diff options
author | Ronnie Sahlberg <lsahlber@redhat.com> | 2018-10-17 05:47:58 +1000 |
---|---|---|
committer | Steve French <stfrench@microsoft.com> | 2018-10-23 21:16:05 -0500 |
commit | 8d8b26e58432cb2840048b9f8aea286be6f75de5 (patch) | |
tree | 0434bc93a5769be50353d7407a68c9d85dff0588 /fs/cifs/smb2ops.c | |
parent | 3b7960caceafdfc2cdfe2850487f8d091eb41144 (diff) |
cifs: add support for ioctl on directories
We do not call cifs_open_file() for directories and thus we do not have a
pSMBFile we can extract the FIDs from.
Solve this by instead always using a compounded open/query/close for
the passthrough ioctl.
Signed-off-by: Ronnie Sahlberg <lsahlber@redhat.com>
Signed-off-by: Steve French <stfrench@microsoft.com>
Diffstat (limited to 'fs/cifs/smb2ops.c')
-rw-r--r-- | fs/cifs/smb2ops.c | 85 |
1 files changed, 65 insertions, 20 deletions
diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c index 8472cb0ae06c..e35a753eca20 100644 --- a/fs/cifs/smb2ops.c +++ b/fs/cifs/smb2ops.c @@ -1120,22 +1120,31 @@ req_res_key_exit: static int smb2_ioctl_query_info(const unsigned int xid, - struct cifsFileInfo *file, + struct cifs_tcon *tcon, + __le16 *path, int is_dir, unsigned long p) { - struct cifs_tcon *tcon = tlink_tcon(file->tlink); struct cifs_ses *ses = tcon->ses; char __user *arg = (char __user *)p; struct smb_query_info qi; struct smb_query_info __user *pqi; int rc = 0; int flags = 0; - struct smb_rqst rqst; - struct kvec iov[1]; - struct kvec rsp_iov; - int resp_buftype = CIFS_NO_BUFFER; struct smb2_query_info_rsp *rsp = NULL; - void *buffer; + void *buffer = NULL; + struct smb_rqst rqst[3]; + int resp_buftype[3]; + struct kvec rsp_iov[3]; + struct kvec open_iov[SMB2_CREATE_IOV_SIZE]; + struct cifs_open_parms oparms; + u8 oplock = SMB2_OPLOCK_LEVEL_NONE; + struct cifs_fid fid; + struct kvec qi_iov[1]; + struct kvec close_iov[1]; + + memset(rqst, 0, sizeof(rqst)); + resp_buftype[0] = resp_buftype[1] = resp_buftype[2] = CIFS_NO_BUFFER; + memset(rsp_iov, 0, sizeof(rsp_iov)); if (copy_from_user(&qi, arg, sizeof(struct smb_query_info))) return -EFAULT; @@ -1155,31 +1164,62 @@ smb2_ioctl_query_info(const unsigned int xid, if (copy_from_user(buffer, arg + sizeof(struct smb_query_info), qi.output_buffer_length)) { - kfree(buffer); - return -EFAULT; + rc = -EFAULT; + goto iqinf_exit; } - memset(&rqst, 0, sizeof(struct smb_rqst)); - memset(&iov, 0, sizeof(iov)); - rqst.rq_iov = iov; - rqst.rq_nvec = 1; + /* Open */ + memset(&open_iov, 0, sizeof(open_iov)); + rqst[0].rq_iov = open_iov; + rqst[0].rq_nvec = SMB2_CREATE_IOV_SIZE; + + memset(&oparms, 0, sizeof(oparms)); + oparms.tcon = tcon; + oparms.desired_access = FILE_READ_ATTRIBUTES | READ_CONTROL; + oparms.disposition = FILE_OPEN; + if (is_dir) + oparms.create_options = CREATE_NOT_FILE; + else + oparms.create_options = CREATE_NOT_DIR; + oparms.fid = &fid; + oparms.reconnect = false; + + rc = SMB2_open_init(tcon, &rqst[0], &oplock, &oparms, path); + if (rc) + goto iqinf_exit; + smb2_set_next_command(ses->server, &rqst[0]); - rc = SMB2_query_info_init(tcon, &rqst, file->fid.persistent_fid, - file->fid.volatile_fid, + /* Query */ + memset(&qi_iov, 0, sizeof(qi_iov)); + rqst[1].rq_iov = qi_iov; + rqst[1].rq_nvec = 1; + + rc = SMB2_query_info_init(tcon, &rqst[1], COMPOUND_FID, COMPOUND_FID, qi.file_info_class, qi.info_type, qi.additional_information, qi.input_buffer_length, qi.output_buffer_length, buffer); - kfree(buffer); if (rc) goto iqinf_exit; + smb2_set_next_command(ses->server, &rqst[1]); + smb2_set_related(&rqst[1]); - rc = cifs_send_recv(xid, ses, &rqst, &resp_buftype, flags, &rsp_iov); - rsp = (struct smb2_query_info_rsp *)rsp_iov.iov_base; + /* Close */ + memset(&close_iov, 0, sizeof(close_iov)); + rqst[2].rq_iov = close_iov; + rqst[2].rq_nvec = 1; + + rc = SMB2_close_init(tcon, &rqst[2], COMPOUND_FID, COMPOUND_FID); if (rc) goto iqinf_exit; + smb2_set_related(&rqst[2]); + rc = compound_send_recv(xid, ses, flags, 3, rqst, + resp_buftype, rsp_iov); + if (rc) + goto iqinf_exit; pqi = (struct smb_query_info __user *)arg; + rsp = (struct smb2_query_info_rsp *)rsp_iov[1].iov_base; if (le32_to_cpu(rsp->OutputBufferLength) < qi.input_buffer_length) qi.input_buffer_length = le32_to_cpu(rsp->OutputBufferLength); if (copy_to_user(&pqi->input_buffer_length, &qi.input_buffer_length, @@ -1193,8 +1233,13 @@ smb2_ioctl_query_info(const unsigned int xid, } iqinf_exit: - SMB2_query_info_free(&rqst); - free_rsp_buf(resp_buftype, rsp); + kfree(buffer); + SMB2_open_free(&rqst[0]); + SMB2_query_info_free(&rqst[1]); + SMB2_close_free(&rqst[2]); + free_rsp_buf(resp_buftype[0], rsp_iov[0].iov_base); + free_rsp_buf(resp_buftype[1], rsp_iov[1].iov_base); + free_rsp_buf(resp_buftype[2], rsp_iov[2].iov_base); return rc; } |