Skip to content

Commit c7bb3fb

Browse files
committed
Merge tag '6.0-rc2-smb3-client-fixes' of git://git.samba.org/sfrench/cifs-2.6
Pull cfis fixes from Steve French: - two locking fixes (zero range, punch hole) - DFS 9 fix (padding), affecting some servers - three minor cleanup changes * tag '6.0-rc2-smb3-client-fixes' of git://git.samba.org/sfrench/cifs-2.6: cifs: Add helper function to check smb1+ server cifs: Use help macro to get the mid header size cifs: Use help macro to get the header preamble size cifs: skip extra NULL byte in filenames smb3: missing inode locks in punch hole smb3: missing inode locks in zero range
2 parents 2f23a7c + d291e70 commit c7bb3fb

File tree

6 files changed

+70
-67
lines changed

6 files changed

+70
-67
lines changed

fs/cifs/cifsencrypt.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,9 @@ int __cifs_calc_signature(struct smb_rqst *rqst,
3232
int rc;
3333
struct kvec *iov = rqst->rq_iov;
3434
int n_vec = rqst->rq_nvec;
35-
int is_smb2 = server->vals->header_preamble_size == 0;
3635

3736
/* iov[0] is actual data and not the rfc1002 length for SMB2+ */
38-
if (is_smb2) {
37+
if (!is_smb1(server)) {
3938
if (iov[0].iov_len <= 4)
4039
return -EIO;
4140
i = 0;

fs/cifs/cifsglob.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -557,6 +557,8 @@ struct smb_version_values {
557557

558558
#define HEADER_SIZE(server) (server->vals->header_size)
559559
#define MAX_HEADER_SIZE(server) (server->vals->max_header_size)
560+
#define HEADER_PREAMBLE_SIZE(server) (server->vals->header_preamble_size)
561+
#define MID_HEADER_SIZE(server) (HEADER_SIZE(server) - 1 - HEADER_PREAMBLE_SIZE(server))
560562

561563
/**
562564
* CIFS superblock mount flags (mnt_cifs_flags) to consider when
@@ -750,6 +752,11 @@ struct TCP_Server_Info {
750752
#endif
751753
};
752754

755+
static inline bool is_smb1(struct TCP_Server_Info *server)
756+
{
757+
return HEADER_PREAMBLE_SIZE(server) != 0;
758+
}
759+
753760
static inline void cifs_server_lock(struct TCP_Server_Info *server)
754761
{
755762
unsigned int nofs_flag = memalloc_nofs_save();

fs/cifs/connect.c

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -871,7 +871,7 @@ smb2_get_credits_from_hdr(char *buffer, struct TCP_Server_Info *server)
871871
/*
872872
* SMB1 does not use credits.
873873
*/
874-
if (server->vals->header_preamble_size)
874+
if (is_smb1(server))
875875
return 0;
876876

877877
return le16_to_cpu(shdr->CreditRequest);
@@ -1050,7 +1050,7 @@ standard_receive3(struct TCP_Server_Info *server, struct mid_q_entry *mid)
10501050

10511051
/* make sure this will fit in a large buffer */
10521052
if (pdu_length > CIFSMaxBufSize + MAX_HEADER_SIZE(server) -
1053-
server->vals->header_preamble_size) {
1053+
HEADER_PREAMBLE_SIZE(server)) {
10541054
cifs_server_dbg(VFS, "SMB response too long (%u bytes)\n", pdu_length);
10551055
cifs_reconnect(server, true);
10561056
return -ECONNABORTED;
@@ -1065,8 +1065,7 @@ standard_receive3(struct TCP_Server_Info *server, struct mid_q_entry *mid)
10651065

10661066
/* now read the rest */
10671067
length = cifs_read_from_socket(server, buf + HEADER_SIZE(server) - 1,
1068-
pdu_length - HEADER_SIZE(server) + 1
1069-
+ server->vals->header_preamble_size);
1068+
pdu_length - MID_HEADER_SIZE(server));
10701069

10711070
if (length < 0)
10721071
return length;
@@ -1122,7 +1121,7 @@ smb2_add_credits_from_hdr(char *buffer, struct TCP_Server_Info *server)
11221121
/*
11231122
* SMB1 does not use credits.
11241123
*/
1125-
if (server->vals->header_preamble_size)
1124+
if (is_smb1(server))
11261125
return;
11271126

11281127
if (shdr->CreditRequest) {
@@ -1180,10 +1179,10 @@ cifs_demultiplex_thread(void *p)
11801179
if (length < 0)
11811180
continue;
11821181

1183-
if (server->vals->header_preamble_size == 0)
1184-
server->total_read = 0;
1185-
else
1182+
if (is_smb1(server))
11861183
server->total_read = length;
1184+
else
1185+
server->total_read = 0;
11871186

11881187
/*
11891188
* The right amount was read from socket - 4 bytes,
@@ -1198,8 +1197,7 @@ cifs_demultiplex_thread(void *p)
11981197
server->pdu_size = pdu_length;
11991198

12001199
/* make sure we have enough to get to the MID */
1201-
if (server->pdu_size < HEADER_SIZE(server) - 1 -
1202-
server->vals->header_preamble_size) {
1200+
if (server->pdu_size < MID_HEADER_SIZE(server)) {
12031201
cifs_server_dbg(VFS, "SMB response too short (%u bytes)\n",
12041202
server->pdu_size);
12051203
cifs_reconnect(server, true);
@@ -1208,9 +1206,8 @@ cifs_demultiplex_thread(void *p)
12081206

12091207
/* read down to the MID */
12101208
length = cifs_read_from_socket(server,
1211-
buf + server->vals->header_preamble_size,
1212-
HEADER_SIZE(server) - 1
1213-
- server->vals->header_preamble_size);
1209+
buf + HEADER_PREAMBLE_SIZE(server),
1210+
MID_HEADER_SIZE(server));
12141211
if (length < 0)
12151212
continue;
12161213
server->total_read += length;

fs/cifs/smb2ops.c

Lines changed: 36 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -3307,53 +3307,56 @@ get_smb2_acl(struct cifs_sb_info *cifs_sb,
33073307
return pntsd;
33083308
}
33093309

3310+
static long smb3_zero_data(struct file *file, struct cifs_tcon *tcon,
3311+
loff_t offset, loff_t len, unsigned int xid)
3312+
{
3313+
struct cifsFileInfo *cfile = file->private_data;
3314+
struct file_zero_data_information fsctl_buf;
3315+
3316+
cifs_dbg(FYI, "Offset %lld len %lld\n", offset, len);
3317+
3318+
fsctl_buf.FileOffset = cpu_to_le64(offset);
3319+
fsctl_buf.BeyondFinalZero = cpu_to_le64(offset + len);
3320+
3321+
return SMB2_ioctl(xid, tcon, cfile->fid.persistent_fid,
3322+
cfile->fid.volatile_fid, FSCTL_SET_ZERO_DATA,
3323+
(char *)&fsctl_buf,
3324+
sizeof(struct file_zero_data_information),
3325+
0, NULL, NULL);
3326+
}
3327+
33103328
static long smb3_zero_range(struct file *file, struct cifs_tcon *tcon,
33113329
loff_t offset, loff_t len, bool keep_size)
33123330
{
33133331
struct cifs_ses *ses = tcon->ses;
3314-
struct inode *inode;
3315-
struct cifsInodeInfo *cifsi;
3332+
struct inode *inode = file_inode(file);
3333+
struct cifsInodeInfo *cifsi = CIFS_I(inode);
33163334
struct cifsFileInfo *cfile = file->private_data;
3317-
struct file_zero_data_information fsctl_buf;
33183335
long rc;
33193336
unsigned int xid;
33203337
__le64 eof;
33213338

33223339
xid = get_xid();
33233340

3324-
inode = d_inode(cfile->dentry);
3325-
cifsi = CIFS_I(inode);
3326-
33273341
trace_smb3_zero_enter(xid, cfile->fid.persistent_fid, tcon->tid,
33283342
ses->Suid, offset, len);
33293343

3344+
inode_lock(inode);
3345+
filemap_invalidate_lock(inode->i_mapping);
3346+
33303347
/*
33313348
* We zero the range through ioctl, so we need remove the page caches
33323349
* first, otherwise the data may be inconsistent with the server.
33333350
*/
33343351
truncate_pagecache_range(inode, offset, offset + len - 1);
33353352

33363353
/* if file not oplocked can't be sure whether asking to extend size */
3337-
if (!CIFS_CACHE_READ(cifsi))
3338-
if (keep_size == false) {
3339-
rc = -EOPNOTSUPP;
3340-
trace_smb3_zero_err(xid, cfile->fid.persistent_fid,
3341-
tcon->tid, ses->Suid, offset, len, rc);
3342-
free_xid(xid);
3343-
return rc;
3344-
}
3345-
3346-
cifs_dbg(FYI, "Offset %lld len %lld\n", offset, len);
3347-
3348-
fsctl_buf.FileOffset = cpu_to_le64(offset);
3349-
fsctl_buf.BeyondFinalZero = cpu_to_le64(offset + len);
3354+
rc = -EOPNOTSUPP;
3355+
if (keep_size == false && !CIFS_CACHE_READ(cifsi))
3356+
goto zero_range_exit;
33503357

3351-
rc = SMB2_ioctl(xid, tcon, cfile->fid.persistent_fid,
3352-
cfile->fid.volatile_fid, FSCTL_SET_ZERO_DATA,
3353-
(char *)&fsctl_buf,
3354-
sizeof(struct file_zero_data_information),
3355-
0, NULL, NULL);
3356-
if (rc)
3358+
rc = smb3_zero_data(file, tcon, offset, len, xid);
3359+
if (rc < 0)
33573360
goto zero_range_exit;
33583361

33593362
/*
@@ -3366,6 +3369,8 @@ static long smb3_zero_range(struct file *file, struct cifs_tcon *tcon,
33663369
}
33673370

33683371
zero_range_exit:
3372+
filemap_invalidate_unlock(inode->i_mapping);
3373+
inode_unlock(inode);
33693374
free_xid(xid);
33703375
if (rc)
33713376
trace_smb3_zero_err(xid, cfile->fid.persistent_fid, tcon->tid,
@@ -3379,7 +3384,7 @@ static long smb3_zero_range(struct file *file, struct cifs_tcon *tcon,
33793384
static long smb3_punch_hole(struct file *file, struct cifs_tcon *tcon,
33803385
loff_t offset, loff_t len)
33813386
{
3382-
struct inode *inode;
3387+
struct inode *inode = file_inode(file);
33833388
struct cifsFileInfo *cfile = file->private_data;
33843389
struct file_zero_data_information fsctl_buf;
33853390
long rc;
@@ -3388,14 +3393,12 @@ static long smb3_punch_hole(struct file *file, struct cifs_tcon *tcon,
33883393

33893394
xid = get_xid();
33903395

3391-
inode = d_inode(cfile->dentry);
3392-
3396+
inode_lock(inode);
33933397
/* Need to make file sparse, if not already, before freeing range. */
33943398
/* Consider adding equivalent for compressed since it could also work */
33953399
if (!smb2_set_sparse(xid, tcon, cfile, inode, set_sparse)) {
33963400
rc = -EOPNOTSUPP;
3397-
free_xid(xid);
3398-
return rc;
3401+
goto out;
33993402
}
34003403

34013404
filemap_invalidate_lock(inode->i_mapping);
@@ -3415,8 +3418,10 @@ static long smb3_punch_hole(struct file *file, struct cifs_tcon *tcon,
34153418
(char *)&fsctl_buf,
34163419
sizeof(struct file_zero_data_information),
34173420
CIFSMaxBufSize, NULL, NULL);
3418-
free_xid(xid);
34193421
filemap_invalidate_unlock(inode->i_mapping);
3422+
out:
3423+
inode_unlock(inode);
3424+
free_xid(xid);
34203425
return rc;
34213426
}
34223427

fs/cifs/smb2pdu.c

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2572,19 +2572,15 @@ alloc_path_with_tree_prefix(__le16 **out_path, int *out_size, int *out_len,
25722572

25732573
path_len = UniStrnlen((wchar_t *)path, PATH_MAX);
25742574

2575-
/*
2576-
* make room for one path separator between the treename and
2577-
* path
2578-
*/
2579-
*out_len = treename_len + 1 + path_len;
2575+
/* make room for one path separator only if @path isn't empty */
2576+
*out_len = treename_len + (path[0] ? 1 : 0) + path_len;
25802577

25812578
/*
2582-
* final path needs to be null-terminated UTF16 with a
2583-
* size aligned to 8
2579+
* final path needs to be 8-byte aligned as specified in
2580+
* MS-SMB2 2.2.13 SMB2 CREATE Request.
25842581
*/
2585-
2586-
*out_size = roundup((*out_len+1)*2, 8);
2587-
*out_path = kzalloc(*out_size, GFP_KERNEL);
2582+
*out_size = roundup(*out_len * sizeof(__le16), 8);
2583+
*out_path = kzalloc(*out_size + sizeof(__le16) /* null */, GFP_KERNEL);
25882584
if (!*out_path)
25892585
return -ENOMEM;
25902586

fs/cifs/transport.c

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -261,8 +261,8 @@ smb_rqst_len(struct TCP_Server_Info *server, struct smb_rqst *rqst)
261261
int nvec;
262262
unsigned long buflen = 0;
263263

264-
if (server->vals->header_preamble_size == 0 &&
265-
rqst->rq_nvec >= 2 && rqst->rq_iov[0].iov_len == 4) {
264+
if (!is_smb1(server) && rqst->rq_nvec >= 2 &&
265+
rqst->rq_iov[0].iov_len == 4) {
266266
iov = &rqst->rq_iov[1];
267267
nvec = rqst->rq_nvec - 1;
268268
} else {
@@ -346,7 +346,7 @@ __smb_send_rqst(struct TCP_Server_Info *server, int num_rqst,
346346
sigprocmask(SIG_BLOCK, &mask, &oldmask);
347347

348348
/* Generate a rfc1002 marker for SMB2+ */
349-
if (server->vals->header_preamble_size == 0) {
349+
if (!is_smb1(server)) {
350350
struct kvec hiov = {
351351
.iov_base = &rfc1002_marker,
352352
.iov_len = 4
@@ -1238,7 +1238,7 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses,
12381238
buf = (char *)midQ[i]->resp_buf;
12391239
resp_iov[i].iov_base = buf;
12401240
resp_iov[i].iov_len = midQ[i]->resp_buf_size +
1241-
server->vals->header_preamble_size;
1241+
HEADER_PREAMBLE_SIZE(server);
12421242

12431243
if (midQ[i]->large_buf)
12441244
resp_buf_type[i] = CIFS_LARGE_BUFFER;
@@ -1643,7 +1643,7 @@ int
16431643
cifs_discard_remaining_data(struct TCP_Server_Info *server)
16441644
{
16451645
unsigned int rfclen = server->pdu_size;
1646-
int remaining = rfclen + server->vals->header_preamble_size -
1646+
int remaining = rfclen + HEADER_PREAMBLE_SIZE(server) -
16471647
server->total_read;
16481648

16491649
while (remaining > 0) {
@@ -1689,8 +1689,7 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
16891689
unsigned int data_offset, data_len;
16901690
struct cifs_readdata *rdata = mid->callback_data;
16911691
char *buf = server->smallbuf;
1692-
unsigned int buflen = server->pdu_size +
1693-
server->vals->header_preamble_size;
1692+
unsigned int buflen = server->pdu_size + HEADER_PREAMBLE_SIZE(server);
16941693
bool use_rdma_mr = false;
16951694

16961695
cifs_dbg(FYI, "%s: mid=%llu offset=%llu bytes=%u\n",
@@ -1724,10 +1723,10 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
17241723

17251724
/* set up first two iov for signature check and to get credits */
17261725
rdata->iov[0].iov_base = buf;
1727-
rdata->iov[0].iov_len = server->vals->header_preamble_size;
1728-
rdata->iov[1].iov_base = buf + server->vals->header_preamble_size;
1726+
rdata->iov[0].iov_len = HEADER_PREAMBLE_SIZE(server);
1727+
rdata->iov[1].iov_base = buf + HEADER_PREAMBLE_SIZE(server);
17291728
rdata->iov[1].iov_len =
1730-
server->total_read - server->vals->header_preamble_size;
1729+
server->total_read - HEADER_PREAMBLE_SIZE(server);
17311730
cifs_dbg(FYI, "0: iov_base=%p iov_len=%zu\n",
17321731
rdata->iov[0].iov_base, rdata->iov[0].iov_len);
17331732
cifs_dbg(FYI, "1: iov_base=%p iov_len=%zu\n",
@@ -1752,7 +1751,7 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
17521751
}
17531752

17541753
data_offset = server->ops->read_data_offset(buf) +
1755-
server->vals->header_preamble_size;
1754+
HEADER_PREAMBLE_SIZE(server);
17561755
if (data_offset < server->total_read) {
17571756
/*
17581757
* win2k8 sometimes sends an offset of 0 when the read

0 commit comments

Comments
 (0)