Skip to content

Commit 91962d0

Browse files
committed
Merge tag '5.3-smb3-fixes' of git://git.samba.org/sfrench/cifs-2.6
Pull cifs fixes from Steve French: "Two fixes for stable, one that had dependency on earlier patch in this merge window and can now go in, and a perf improvement in SMB3 open" * tag '5.3-smb3-fixes' of git://git.samba.org/sfrench/cifs-2.6: cifs: update internal module number cifs: flush before set-info if we have writeable handles smb3: optimize open to not send query file internal info cifs: copy_file_range needs to strip setuid bits and update timestamps CIFS: fix deadlock in cached root handling
2 parents 8cf6650 + 2a957ac commit 91962d0

File tree

8 files changed

+126
-31
lines changed

8 files changed

+126
-31
lines changed

fs/cifs/cifsfs.c

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1104,6 +1104,10 @@ ssize_t cifs_file_copychunk_range(unsigned int xid,
11041104
goto out;
11051105
}
11061106

1107+
rc = -EOPNOTSUPP;
1108+
if (!target_tcon->ses->server->ops->copychunk_range)
1109+
goto out;
1110+
11071111
/*
11081112
* Note: cifs case is easier than btrfs since server responsible for
11091113
* checks for proper open modes and file type and if it wants
@@ -1115,11 +1119,12 @@ ssize_t cifs_file_copychunk_range(unsigned int xid,
11151119
/* should we flush first and last page first */
11161120
truncate_inode_pages(&target_inode->i_data, 0);
11171121

1118-
if (target_tcon->ses->server->ops->copychunk_range)
1122+
rc = file_modified(dst_file);
1123+
if (!rc)
11191124
rc = target_tcon->ses->server->ops->copychunk_range(xid,
11201125
smb_file_src, smb_file_target, off, len, destoff);
1121-
else
1122-
rc = -EOPNOTSUPP;
1126+
1127+
file_accessed(src_file);
11231128

11241129
/* force revalidate of size and timestamps of target file now
11251130
* that target is updated on the server

fs/cifs/cifsfs.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,5 +152,5 @@ extern long cifs_ioctl(struct file *filep, unsigned int cmd, unsigned long arg);
152152
extern const struct export_operations cifs_export_ops;
153153
#endif /* CONFIG_CIFS_NFSD_EXPORT */
154154

155-
#define CIFS_VERSION "2.20"
155+
#define CIFS_VERSION "2.21"
156156
#endif /* _CIFSFS_H */

fs/cifs/inode.c

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2406,6 +2406,8 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)
24062406
struct inode *inode = d_inode(direntry);
24072407
struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
24082408
struct cifsInodeInfo *cifsInode = CIFS_I(inode);
2409+
struct cifsFileInfo *wfile;
2410+
struct cifs_tcon *tcon;
24092411
char *full_path = NULL;
24102412
int rc = -EACCES;
24112413
__u32 dosattr = 0;
@@ -2452,6 +2454,20 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)
24522454
mapping_set_error(inode->i_mapping, rc);
24532455
rc = 0;
24542456

2457+
if (attrs->ia_valid & ATTR_MTIME) {
2458+
rc = cifs_get_writable_file(cifsInode, false, &wfile);
2459+
if (!rc) {
2460+
tcon = tlink_tcon(wfile->tlink);
2461+
rc = tcon->ses->server->ops->flush(xid, tcon, &wfile->fid);
2462+
cifsFileInfo_put(wfile);
2463+
if (rc)
2464+
return rc;
2465+
} else if (rc != -EBADF)
2466+
return rc;
2467+
else
2468+
rc = 0;
2469+
}
2470+
24552471
if (attrs->ia_valid & ATTR_SIZE) {
24562472
rc = cifs_set_file_size(inode, attrs, xid, full_path);
24572473
if (rc != 0)

fs/cifs/smb2file.c

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -88,14 +88,20 @@ smb2_open_file(const unsigned int xid, struct cifs_open_parms *oparms,
8888
}
8989

9090
if (buf) {
91-
/* open response does not have IndexNumber field - get it */
92-
rc = SMB2_get_srv_num(xid, oparms->tcon, fid->persistent_fid,
91+
/* if open response does not have IndexNumber field - get it */
92+
if (smb2_data->IndexNumber == 0) {
93+
rc = SMB2_get_srv_num(xid, oparms->tcon,
94+
fid->persistent_fid,
9395
fid->volatile_fid,
9496
&smb2_data->IndexNumber);
95-
if (rc) {
96-
/* let get_inode_info disable server inode numbers */
97-
smb2_data->IndexNumber = 0;
98-
rc = 0;
97+
if (rc) {
98+
/*
99+
* let get_inode_info disable server inode
100+
* numbers
101+
*/
102+
smb2_data->IndexNumber = 0;
103+
rc = 0;
104+
}
99105
}
100106
move_smb2_info_to_cifs(buf, smb2_data);
101107
}

fs/cifs/smb2ops.c

Lines changed: 49 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -694,8 +694,51 @@ int open_shroot(unsigned int xid, struct cifs_tcon *tcon, struct cifs_fid *pfid)
694694

695695
smb2_set_related(&rqst[1]);
696696

697+
/*
698+
* We do not hold the lock for the open because in case
699+
* SMB2_open needs to reconnect, it will end up calling
700+
* cifs_mark_open_files_invalid() which takes the lock again
701+
* thus causing a deadlock
702+
*/
703+
704+
mutex_unlock(&tcon->crfid.fid_mutex);
697705
rc = compound_send_recv(xid, ses, flags, 2, rqst,
698706
resp_buftype, rsp_iov);
707+
mutex_lock(&tcon->crfid.fid_mutex);
708+
709+
/*
710+
* Now we need to check again as the cached root might have
711+
* been successfully re-opened from a concurrent process
712+
*/
713+
714+
if (tcon->crfid.is_valid) {
715+
/* work was already done */
716+
717+
/* stash fids for close() later */
718+
struct cifs_fid fid = {
719+
.persistent_fid = pfid->persistent_fid,
720+
.volatile_fid = pfid->volatile_fid,
721+
};
722+
723+
/*
724+
* caller expects this func to set pfid to a valid
725+
* cached root, so we copy the existing one and get a
726+
* reference.
727+
*/
728+
memcpy(pfid, tcon->crfid.fid, sizeof(*pfid));
729+
kref_get(&tcon->crfid.refcount);
730+
731+
mutex_unlock(&tcon->crfid.fid_mutex);
732+
733+
if (rc == 0) {
734+
/* close extra handle outside of crit sec */
735+
SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid);
736+
}
737+
goto oshr_free;
738+
}
739+
740+
/* Cached root is still invalid, continue normaly */
741+
699742
if (rc)
700743
goto oshr_exit;
701744

@@ -711,11 +754,12 @@ int open_shroot(unsigned int xid, struct cifs_tcon *tcon, struct cifs_fid *pfid)
711754
tcon->crfid.is_valid = true;
712755
kref_init(&tcon->crfid.refcount);
713756

757+
/* BB TBD check to see if oplock level check can be removed below */
714758
if (o_rsp->OplockLevel == SMB2_OPLOCK_LEVEL_LEASE) {
715759
kref_get(&tcon->crfid.refcount);
716-
oplock = smb2_parse_lease_state(server, o_rsp,
717-
&oparms.fid->epoch,
718-
oparms.fid->lease_key);
760+
smb2_parse_contexts(server, o_rsp,
761+
&oparms.fid->epoch,
762+
oparms.fid->lease_key, &oplock, NULL);
719763
} else
720764
goto oshr_exit;
721765

@@ -729,8 +773,9 @@ int open_shroot(unsigned int xid, struct cifs_tcon *tcon, struct cifs_fid *pfid)
729773
(char *)&tcon->crfid.file_all_info))
730774
tcon->crfid.file_all_info_is_valid = 1;
731775

732-
oshr_exit:
776+
oshr_exit:
733777
mutex_unlock(&tcon->crfid.fid_mutex);
778+
oshr_free:
734779
SMB2_open_free(&rqst[0]);
735780
SMB2_query_info_free(&rqst[1]);
736781
free_rsp_buf(resp_buftype[0], rsp_iov[0].iov_base);

fs/cifs/smb2pdu.c

Lines changed: 33 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1873,26 +1873,46 @@ create_reconnect_durable_buf(struct cifs_fid *fid)
18731873
return buf;
18741874
}
18751875

1876-
__u8
1877-
smb2_parse_lease_state(struct TCP_Server_Info *server,
1876+
static void
1877+
parse_query_id_ctxt(struct create_context *cc, struct smb2_file_all_info *buf)
1878+
{
1879+
struct create_on_disk_id *pdisk_id = (struct create_on_disk_id *)cc;
1880+
1881+
cifs_dbg(FYI, "parse query id context 0x%llx 0x%llx\n",
1882+
pdisk_id->DiskFileId, pdisk_id->VolumeId);
1883+
buf->IndexNumber = pdisk_id->DiskFileId;
1884+
}
1885+
1886+
void
1887+
smb2_parse_contexts(struct TCP_Server_Info *server,
18781888
struct smb2_create_rsp *rsp,
1879-
unsigned int *epoch, char *lease_key)
1889+
unsigned int *epoch, char *lease_key, __u8 *oplock,
1890+
struct smb2_file_all_info *buf)
18801891
{
18811892
char *data_offset;
18821893
struct create_context *cc;
18831894
unsigned int next;
18841895
unsigned int remaining;
18851896
char *name;
18861897

1898+
*oplock = 0;
18871899
data_offset = (char *)rsp + le32_to_cpu(rsp->CreateContextsOffset);
18881900
remaining = le32_to_cpu(rsp->CreateContextsLength);
18891901
cc = (struct create_context *)data_offset;
1902+
1903+
/* Initialize inode number to 0 in case no valid data in qfid context */
1904+
if (buf)
1905+
buf->IndexNumber = 0;
1906+
18901907
while (remaining >= sizeof(struct create_context)) {
18911908
name = le16_to_cpu(cc->NameOffset) + (char *)cc;
18921909
if (le16_to_cpu(cc->NameLength) == 4 &&
1893-
strncmp(name, "RqLs", 4) == 0)
1894-
return server->ops->parse_lease_buf(cc, epoch,
1895-
lease_key);
1910+
strncmp(name, SMB2_CREATE_REQUEST_LEASE, 4) == 0)
1911+
*oplock = server->ops->parse_lease_buf(cc, epoch,
1912+
lease_key);
1913+
else if (buf && (le16_to_cpu(cc->NameLength) == 4) &&
1914+
strncmp(name, SMB2_CREATE_QUERY_ON_DISK_ID, 4) == 0)
1915+
parse_query_id_ctxt(cc, buf);
18961916

18971917
next = le32_to_cpu(cc->Next);
18981918
if (!next)
@@ -1901,7 +1921,10 @@ smb2_parse_lease_state(struct TCP_Server_Info *server,
19011921
cc = (struct create_context *)((char *)cc + next);
19021922
}
19031923

1904-
return 0;
1924+
if (rsp->OplockLevel != SMB2_OPLOCK_LEVEL_LEASE)
1925+
*oplock = rsp->OplockLevel;
1926+
1927+
return;
19051928
}
19061929

19071930
static int
@@ -2588,12 +2611,9 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path,
25882611
buf->DeletePending = 0;
25892612
}
25902613

2591-
if (rsp->OplockLevel == SMB2_OPLOCK_LEVEL_LEASE)
2592-
*oplock = smb2_parse_lease_state(server, rsp,
2593-
&oparms->fid->epoch,
2594-
oparms->fid->lease_key);
2595-
else
2596-
*oplock = rsp->OplockLevel;
2614+
2615+
smb2_parse_contexts(server, rsp, &oparms->fid->epoch,
2616+
oparms->fid->lease_key, oplock, buf);
25972617
creat_exit:
25982618
SMB2_open_free(&rqst);
25992619
free_rsp_buf(resp_buftype, rsp);

fs/cifs/smb2pdu.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -818,7 +818,9 @@ struct durable_reconnect_context_v2 {
818818
} __packed;
819819

820820
/* See MS-SMB2 2.2.14.2.9 */
821-
struct on_disk_id {
821+
struct create_on_disk_id {
822+
struct create_context ccontext;
823+
__u8 Name[8];
822824
__le64 DiskFileId;
823825
__le64 VolumeId;
824826
__u32 Reserved[4];

fs/cifs/smb2proto.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -228,9 +228,10 @@ extern int smb3_validate_negotiate(const unsigned int, struct cifs_tcon *);
228228

229229
extern enum securityEnum smb2_select_sectype(struct TCP_Server_Info *,
230230
enum securityEnum);
231-
extern __u8 smb2_parse_lease_state(struct TCP_Server_Info *server,
232-
struct smb2_create_rsp *rsp,
233-
unsigned int *epoch, char *lease_key);
231+
extern void smb2_parse_contexts(struct TCP_Server_Info *server,
232+
struct smb2_create_rsp *rsp,
233+
unsigned int *epoch, char *lease_key,
234+
__u8 *oplock, struct smb2_file_all_info *buf);
234235
extern int smb3_encryption_required(const struct cifs_tcon *tcon);
235236
extern int smb2_validate_iov(unsigned int offset, unsigned int buffer_length,
236237
struct kvec *iov, unsigned int min_buf_size);

0 commit comments

Comments
 (0)