SMB3 fixes: 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
-----BEGIN PGP SIGNATURE----- iQGzBAABCgAdFiEE6fsu8pdIjtWE/DpLiiy9cAdyT1EFAl0zg9YACgkQiiy9cAdy T1HEtQv/Vn2vb9jPoqbCc5QfSUDL13dNYyxhqt3xPdbb3m49a7XNHLoBByM/pnMu TF10QdOPkPS5eP5OTDpR7iwS9iNX9+8KGtlqlbzX7z+bwQmGbBQXg3VoYahSeeGU soJE8VgqoeoOkPV9Sl8tojOIVk6B+BAv4iRPpswt8iPD8Y8IPRg3ONZNoomybzfG GlQBFabhxJU8VLkJIb4NVB+E4AlgMDueD7HpCXD2zh6xsEULgRs2wwxfEopZlyzh prjNY6OZliXMuTMNLw2D07xlya3ZqaXOt+hHEuvSB//YxooTVxBme70ycLF47N3q Gvmaw8QB6scl110PHud9luqpHhdJsEvKOKr0Amv2ND2Atb098D0kZ+VITRP3QHt5 LZcHtKNRXDpAvkHphgN0W5O0ngdFDFo197BaWdwPmi9rARPhuQPq61vkFpsrPwN2 AxkG7IQANNJh4bII6/+xBpSjmtInm0BQhxuojpHIYGiZvdHNYMrJfwFcAoVWfVvl b9MtG9Qz =rP0b -----END PGP SIGNATURE----- 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
This commit is contained in:
commit
91962d0f79
|
@ -1104,6 +1104,10 @@ ssize_t cifs_file_copychunk_range(unsigned int xid,
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rc = -EOPNOTSUPP;
|
||||||
|
if (!target_tcon->ses->server->ops->copychunk_range)
|
||||||
|
goto out;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Note: cifs case is easier than btrfs since server responsible for
|
* Note: cifs case is easier than btrfs since server responsible for
|
||||||
* checks for proper open modes and file type and if it wants
|
* 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,
|
||||||
/* should we flush first and last page first */
|
/* should we flush first and last page first */
|
||||||
truncate_inode_pages(&target_inode->i_data, 0);
|
truncate_inode_pages(&target_inode->i_data, 0);
|
||||||
|
|
||||||
if (target_tcon->ses->server->ops->copychunk_range)
|
rc = file_modified(dst_file);
|
||||||
|
if (!rc)
|
||||||
rc = target_tcon->ses->server->ops->copychunk_range(xid,
|
rc = target_tcon->ses->server->ops->copychunk_range(xid,
|
||||||
smb_file_src, smb_file_target, off, len, destoff);
|
smb_file_src, smb_file_target, off, len, destoff);
|
||||||
else
|
|
||||||
rc = -EOPNOTSUPP;
|
file_accessed(src_file);
|
||||||
|
|
||||||
/* force revalidate of size and timestamps of target file now
|
/* force revalidate of size and timestamps of target file now
|
||||||
* that target is updated on the server
|
* that target is updated on the server
|
||||||
|
|
|
@ -152,5 +152,5 @@ extern long cifs_ioctl(struct file *filep, unsigned int cmd, unsigned long arg);
|
||||||
extern const struct export_operations cifs_export_ops;
|
extern const struct export_operations cifs_export_ops;
|
||||||
#endif /* CONFIG_CIFS_NFSD_EXPORT */
|
#endif /* CONFIG_CIFS_NFSD_EXPORT */
|
||||||
|
|
||||||
#define CIFS_VERSION "2.20"
|
#define CIFS_VERSION "2.21"
|
||||||
#endif /* _CIFSFS_H */
|
#endif /* _CIFSFS_H */
|
||||||
|
|
|
@ -2406,6 +2406,8 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)
|
||||||
struct inode *inode = d_inode(direntry);
|
struct inode *inode = d_inode(direntry);
|
||||||
struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
|
struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
|
||||||
struct cifsInodeInfo *cifsInode = CIFS_I(inode);
|
struct cifsInodeInfo *cifsInode = CIFS_I(inode);
|
||||||
|
struct cifsFileInfo *wfile;
|
||||||
|
struct cifs_tcon *tcon;
|
||||||
char *full_path = NULL;
|
char *full_path = NULL;
|
||||||
int rc = -EACCES;
|
int rc = -EACCES;
|
||||||
__u32 dosattr = 0;
|
__u32 dosattr = 0;
|
||||||
|
@ -2452,6 +2454,20 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)
|
||||||
mapping_set_error(inode->i_mapping, rc);
|
mapping_set_error(inode->i_mapping, rc);
|
||||||
rc = 0;
|
rc = 0;
|
||||||
|
|
||||||
|
if (attrs->ia_valid & ATTR_MTIME) {
|
||||||
|
rc = cifs_get_writable_file(cifsInode, false, &wfile);
|
||||||
|
if (!rc) {
|
||||||
|
tcon = tlink_tcon(wfile->tlink);
|
||||||
|
rc = tcon->ses->server->ops->flush(xid, tcon, &wfile->fid);
|
||||||
|
cifsFileInfo_put(wfile);
|
||||||
|
if (rc)
|
||||||
|
return rc;
|
||||||
|
} else if (rc != -EBADF)
|
||||||
|
return rc;
|
||||||
|
else
|
||||||
|
rc = 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (attrs->ia_valid & ATTR_SIZE) {
|
if (attrs->ia_valid & ATTR_SIZE) {
|
||||||
rc = cifs_set_file_size(inode, attrs, xid, full_path);
|
rc = cifs_set_file_size(inode, attrs, xid, full_path);
|
||||||
if (rc != 0)
|
if (rc != 0)
|
||||||
|
|
|
@ -88,14 +88,20 @@ smb2_open_file(const unsigned int xid, struct cifs_open_parms *oparms,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (buf) {
|
if (buf) {
|
||||||
/* open response does not have IndexNumber field - get it */
|
/* if open response does not have IndexNumber field - get it */
|
||||||
rc = SMB2_get_srv_num(xid, oparms->tcon, fid->persistent_fid,
|
if (smb2_data->IndexNumber == 0) {
|
||||||
|
rc = SMB2_get_srv_num(xid, oparms->tcon,
|
||||||
|
fid->persistent_fid,
|
||||||
fid->volatile_fid,
|
fid->volatile_fid,
|
||||||
&smb2_data->IndexNumber);
|
&smb2_data->IndexNumber);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
/* let get_inode_info disable server inode numbers */
|
/*
|
||||||
smb2_data->IndexNumber = 0;
|
* let get_inode_info disable server inode
|
||||||
rc = 0;
|
* numbers
|
||||||
|
*/
|
||||||
|
smb2_data->IndexNumber = 0;
|
||||||
|
rc = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
move_smb2_info_to_cifs(buf, smb2_data);
|
move_smb2_info_to_cifs(buf, smb2_data);
|
||||||
}
|
}
|
||||||
|
|
|
@ -694,8 +694,51 @@ int open_shroot(unsigned int xid, struct cifs_tcon *tcon, struct cifs_fid *pfid)
|
||||||
|
|
||||||
smb2_set_related(&rqst[1]);
|
smb2_set_related(&rqst[1]);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We do not hold the lock for the open because in case
|
||||||
|
* SMB2_open needs to reconnect, it will end up calling
|
||||||
|
* cifs_mark_open_files_invalid() which takes the lock again
|
||||||
|
* thus causing a deadlock
|
||||||
|
*/
|
||||||
|
|
||||||
|
mutex_unlock(&tcon->crfid.fid_mutex);
|
||||||
rc = compound_send_recv(xid, ses, flags, 2, rqst,
|
rc = compound_send_recv(xid, ses, flags, 2, rqst,
|
||||||
resp_buftype, rsp_iov);
|
resp_buftype, rsp_iov);
|
||||||
|
mutex_lock(&tcon->crfid.fid_mutex);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Now we need to check again as the cached root might have
|
||||||
|
* been successfully re-opened from a concurrent process
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (tcon->crfid.is_valid) {
|
||||||
|
/* work was already done */
|
||||||
|
|
||||||
|
/* stash fids for close() later */
|
||||||
|
struct cifs_fid fid = {
|
||||||
|
.persistent_fid = pfid->persistent_fid,
|
||||||
|
.volatile_fid = pfid->volatile_fid,
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* caller expects this func to set pfid to a valid
|
||||||
|
* cached root, so we copy the existing one and get a
|
||||||
|
* reference.
|
||||||
|
*/
|
||||||
|
memcpy(pfid, tcon->crfid.fid, sizeof(*pfid));
|
||||||
|
kref_get(&tcon->crfid.refcount);
|
||||||
|
|
||||||
|
mutex_unlock(&tcon->crfid.fid_mutex);
|
||||||
|
|
||||||
|
if (rc == 0) {
|
||||||
|
/* close extra handle outside of crit sec */
|
||||||
|
SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid);
|
||||||
|
}
|
||||||
|
goto oshr_free;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Cached root is still invalid, continue normaly */
|
||||||
|
|
||||||
if (rc)
|
if (rc)
|
||||||
goto oshr_exit;
|
goto oshr_exit;
|
||||||
|
|
||||||
|
@ -711,11 +754,12 @@ int open_shroot(unsigned int xid, struct cifs_tcon *tcon, struct cifs_fid *pfid)
|
||||||
tcon->crfid.is_valid = true;
|
tcon->crfid.is_valid = true;
|
||||||
kref_init(&tcon->crfid.refcount);
|
kref_init(&tcon->crfid.refcount);
|
||||||
|
|
||||||
|
/* BB TBD check to see if oplock level check can be removed below */
|
||||||
if (o_rsp->OplockLevel == SMB2_OPLOCK_LEVEL_LEASE) {
|
if (o_rsp->OplockLevel == SMB2_OPLOCK_LEVEL_LEASE) {
|
||||||
kref_get(&tcon->crfid.refcount);
|
kref_get(&tcon->crfid.refcount);
|
||||||
oplock = smb2_parse_lease_state(server, o_rsp,
|
smb2_parse_contexts(server, o_rsp,
|
||||||
&oparms.fid->epoch,
|
&oparms.fid->epoch,
|
||||||
oparms.fid->lease_key);
|
oparms.fid->lease_key, &oplock, NULL);
|
||||||
} else
|
} else
|
||||||
goto oshr_exit;
|
goto oshr_exit;
|
||||||
|
|
||||||
|
@ -729,8 +773,9 @@ int open_shroot(unsigned int xid, struct cifs_tcon *tcon, struct cifs_fid *pfid)
|
||||||
(char *)&tcon->crfid.file_all_info))
|
(char *)&tcon->crfid.file_all_info))
|
||||||
tcon->crfid.file_all_info_is_valid = 1;
|
tcon->crfid.file_all_info_is_valid = 1;
|
||||||
|
|
||||||
oshr_exit:
|
oshr_exit:
|
||||||
mutex_unlock(&tcon->crfid.fid_mutex);
|
mutex_unlock(&tcon->crfid.fid_mutex);
|
||||||
|
oshr_free:
|
||||||
SMB2_open_free(&rqst[0]);
|
SMB2_open_free(&rqst[0]);
|
||||||
SMB2_query_info_free(&rqst[1]);
|
SMB2_query_info_free(&rqst[1]);
|
||||||
free_rsp_buf(resp_buftype[0], rsp_iov[0].iov_base);
|
free_rsp_buf(resp_buftype[0], rsp_iov[0].iov_base);
|
||||||
|
|
|
@ -1873,10 +1873,21 @@ create_reconnect_durable_buf(struct cifs_fid *fid)
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
__u8
|
static void
|
||||||
smb2_parse_lease_state(struct TCP_Server_Info *server,
|
parse_query_id_ctxt(struct create_context *cc, struct smb2_file_all_info *buf)
|
||||||
|
{
|
||||||
|
struct create_on_disk_id *pdisk_id = (struct create_on_disk_id *)cc;
|
||||||
|
|
||||||
|
cifs_dbg(FYI, "parse query id context 0x%llx 0x%llx\n",
|
||||||
|
pdisk_id->DiskFileId, pdisk_id->VolumeId);
|
||||||
|
buf->IndexNumber = pdisk_id->DiskFileId;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
smb2_parse_contexts(struct TCP_Server_Info *server,
|
||||||
struct smb2_create_rsp *rsp,
|
struct smb2_create_rsp *rsp,
|
||||||
unsigned int *epoch, char *lease_key)
|
unsigned int *epoch, char *lease_key, __u8 *oplock,
|
||||||
|
struct smb2_file_all_info *buf)
|
||||||
{
|
{
|
||||||
char *data_offset;
|
char *data_offset;
|
||||||
struct create_context *cc;
|
struct create_context *cc;
|
||||||
|
@ -1884,15 +1895,24 @@ smb2_parse_lease_state(struct TCP_Server_Info *server,
|
||||||
unsigned int remaining;
|
unsigned int remaining;
|
||||||
char *name;
|
char *name;
|
||||||
|
|
||||||
|
*oplock = 0;
|
||||||
data_offset = (char *)rsp + le32_to_cpu(rsp->CreateContextsOffset);
|
data_offset = (char *)rsp + le32_to_cpu(rsp->CreateContextsOffset);
|
||||||
remaining = le32_to_cpu(rsp->CreateContextsLength);
|
remaining = le32_to_cpu(rsp->CreateContextsLength);
|
||||||
cc = (struct create_context *)data_offset;
|
cc = (struct create_context *)data_offset;
|
||||||
|
|
||||||
|
/* Initialize inode number to 0 in case no valid data in qfid context */
|
||||||
|
if (buf)
|
||||||
|
buf->IndexNumber = 0;
|
||||||
|
|
||||||
while (remaining >= sizeof(struct create_context)) {
|
while (remaining >= sizeof(struct create_context)) {
|
||||||
name = le16_to_cpu(cc->NameOffset) + (char *)cc;
|
name = le16_to_cpu(cc->NameOffset) + (char *)cc;
|
||||||
if (le16_to_cpu(cc->NameLength) == 4 &&
|
if (le16_to_cpu(cc->NameLength) == 4 &&
|
||||||
strncmp(name, "RqLs", 4) == 0)
|
strncmp(name, SMB2_CREATE_REQUEST_LEASE, 4) == 0)
|
||||||
return server->ops->parse_lease_buf(cc, epoch,
|
*oplock = server->ops->parse_lease_buf(cc, epoch,
|
||||||
lease_key);
|
lease_key);
|
||||||
|
else if (buf && (le16_to_cpu(cc->NameLength) == 4) &&
|
||||||
|
strncmp(name, SMB2_CREATE_QUERY_ON_DISK_ID, 4) == 0)
|
||||||
|
parse_query_id_ctxt(cc, buf);
|
||||||
|
|
||||||
next = le32_to_cpu(cc->Next);
|
next = le32_to_cpu(cc->Next);
|
||||||
if (!next)
|
if (!next)
|
||||||
|
@ -1901,7 +1921,10 @@ smb2_parse_lease_state(struct TCP_Server_Info *server,
|
||||||
cc = (struct create_context *)((char *)cc + next);
|
cc = (struct create_context *)((char *)cc + next);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
if (rsp->OplockLevel != SMB2_OPLOCK_LEVEL_LEASE)
|
||||||
|
*oplock = rsp->OplockLevel;
|
||||||
|
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
@ -2588,12 +2611,9 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path,
|
||||||
buf->DeletePending = 0;
|
buf->DeletePending = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rsp->OplockLevel == SMB2_OPLOCK_LEVEL_LEASE)
|
|
||||||
*oplock = smb2_parse_lease_state(server, rsp,
|
smb2_parse_contexts(server, rsp, &oparms->fid->epoch,
|
||||||
&oparms->fid->epoch,
|
oparms->fid->lease_key, oplock, buf);
|
||||||
oparms->fid->lease_key);
|
|
||||||
else
|
|
||||||
*oplock = rsp->OplockLevel;
|
|
||||||
creat_exit:
|
creat_exit:
|
||||||
SMB2_open_free(&rqst);
|
SMB2_open_free(&rqst);
|
||||||
free_rsp_buf(resp_buftype, rsp);
|
free_rsp_buf(resp_buftype, rsp);
|
||||||
|
|
|
@ -818,7 +818,9 @@ struct durable_reconnect_context_v2 {
|
||||||
} __packed;
|
} __packed;
|
||||||
|
|
||||||
/* See MS-SMB2 2.2.14.2.9 */
|
/* See MS-SMB2 2.2.14.2.9 */
|
||||||
struct on_disk_id {
|
struct create_on_disk_id {
|
||||||
|
struct create_context ccontext;
|
||||||
|
__u8 Name[8];
|
||||||
__le64 DiskFileId;
|
__le64 DiskFileId;
|
||||||
__le64 VolumeId;
|
__le64 VolumeId;
|
||||||
__u32 Reserved[4];
|
__u32 Reserved[4];
|
||||||
|
|
|
@ -228,9 +228,10 @@ extern int smb3_validate_negotiate(const unsigned int, struct cifs_tcon *);
|
||||||
|
|
||||||
extern enum securityEnum smb2_select_sectype(struct TCP_Server_Info *,
|
extern enum securityEnum smb2_select_sectype(struct TCP_Server_Info *,
|
||||||
enum securityEnum);
|
enum securityEnum);
|
||||||
extern __u8 smb2_parse_lease_state(struct TCP_Server_Info *server,
|
extern void smb2_parse_contexts(struct TCP_Server_Info *server,
|
||||||
struct smb2_create_rsp *rsp,
|
struct smb2_create_rsp *rsp,
|
||||||
unsigned int *epoch, char *lease_key);
|
unsigned int *epoch, char *lease_key,
|
||||||
|
__u8 *oplock, struct smb2_file_all_info *buf);
|
||||||
extern int smb3_encryption_required(const struct cifs_tcon *tcon);
|
extern int smb3_encryption_required(const struct cifs_tcon *tcon);
|
||||||
extern int smb2_validate_iov(unsigned int offset, unsigned int buffer_length,
|
extern int smb2_validate_iov(unsigned int offset, unsigned int buffer_length,
|
||||||
struct kvec *iov, unsigned int min_buf_size);
|
struct kvec *iov, unsigned int min_buf_size);
|
||||||
|
|
Loading…
Reference in New Issue