diff options
author | Ronnie Sahlberg <lsahlber@redhat.com> | 2018-10-16 15:47:58 -0400 |
---|---|---|
committer | Steve French <stfrench@microsoft.com> | 2018-10-23 22:16:05 -0400 |
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: | |||
1120 | 1120 | ||
1121 | static int | 1121 | static int |
1122 | smb2_ioctl_query_info(const unsigned int xid, | 1122 | smb2_ioctl_query_info(const unsigned int xid, |
1123 | struct cifsFileInfo *file, | 1123 | struct cifs_tcon *tcon, |
1124 | __le16 *path, int is_dir, | ||
1124 | unsigned long p) | 1125 | unsigned long p) |
1125 | { | 1126 | { |
1126 | struct cifs_tcon *tcon = tlink_tcon(file->tlink); | ||
1127 | struct cifs_ses *ses = tcon->ses; | 1127 | struct cifs_ses *ses = tcon->ses; |
1128 | char __user *arg = (char __user *)p; | 1128 | char __user *arg = (char __user *)p; |
1129 | struct smb_query_info qi; | 1129 | struct smb_query_info qi; |
1130 | struct smb_query_info __user *pqi; | 1130 | struct smb_query_info __user *pqi; |
1131 | int rc = 0; | 1131 | int rc = 0; |
1132 | int flags = 0; | 1132 | int flags = 0; |
1133 | struct smb_rqst rqst; | ||
1134 | struct kvec iov[1]; | ||
1135 | struct kvec rsp_iov; | ||
1136 | int resp_buftype = CIFS_NO_BUFFER; | ||
1137 | struct smb2_query_info_rsp *rsp = NULL; | 1133 | struct smb2_query_info_rsp *rsp = NULL; |
1138 | void *buffer; | 1134 | void *buffer = NULL; |
1135 | struct smb_rqst rqst[3]; | ||
1136 | int resp_buftype[3]; | ||
1137 | struct kvec rsp_iov[3]; | ||
1138 | struct kvec open_iov[SMB2_CREATE_IOV_SIZE]; | ||
1139 | struct cifs_open_parms oparms; | ||
1140 | u8 oplock = SMB2_OPLOCK_LEVEL_NONE; | ||
1141 | struct cifs_fid fid; | ||
1142 | struct kvec qi_iov[1]; | ||
1143 | struct kvec close_iov[1]; | ||
1144 | |||
1145 | memset(rqst, 0, sizeof(rqst)); | ||
1146 | resp_buftype[0] = resp_buftype[1] = resp_buftype[2] = CIFS_NO_BUFFER; | ||
1147 | memset(rsp_iov, 0, sizeof(rsp_iov)); | ||
1139 | 1148 | ||
1140 | if (copy_from_user(&qi, arg, sizeof(struct smb_query_info))) | 1149 | if (copy_from_user(&qi, arg, sizeof(struct smb_query_info))) |
1141 | return -EFAULT; | 1150 | return -EFAULT; |
@@ -1155,31 +1164,62 @@ smb2_ioctl_query_info(const unsigned int xid, | |||
1155 | 1164 | ||
1156 | if (copy_from_user(buffer, arg + sizeof(struct smb_query_info), | 1165 | if (copy_from_user(buffer, arg + sizeof(struct smb_query_info), |
1157 | qi.output_buffer_length)) { | 1166 | qi.output_buffer_length)) { |
1158 | kfree(buffer); | 1167 | rc = -EFAULT; |
1159 | return -EFAULT; | 1168 | goto iqinf_exit; |
1160 | } | 1169 | } |
1161 | 1170 | ||
1162 | memset(&rqst, 0, sizeof(struct smb_rqst)); | 1171 | /* Open */ |
1163 | memset(&iov, 0, sizeof(iov)); | 1172 | memset(&open_iov, 0, sizeof(open_iov)); |
1164 | rqst.rq_iov = iov; | 1173 | rqst[0].rq_iov = open_iov; |
1165 | rqst.rq_nvec = 1; | 1174 | rqst[0].rq_nvec = SMB2_CREATE_IOV_SIZE; |
1175 | |||
1176 | memset(&oparms, 0, sizeof(oparms)); | ||
1177 | oparms.tcon = tcon; | ||
1178 | oparms.desired_access = FILE_READ_ATTRIBUTES | READ_CONTROL; | ||
1179 | oparms.disposition = FILE_OPEN; | ||
1180 | if (is_dir) | ||
1181 | oparms.create_options = CREATE_NOT_FILE; | ||
1182 | else | ||
1183 | oparms.create_options = CREATE_NOT_DIR; | ||
1184 | oparms.fid = &fid; | ||
1185 | oparms.reconnect = false; | ||
1186 | |||
1187 | rc = SMB2_open_init(tcon, &rqst[0], &oplock, &oparms, path); | ||
1188 | if (rc) | ||
1189 | goto iqinf_exit; | ||
1190 | smb2_set_next_command(ses->server, &rqst[0]); | ||
1166 | 1191 | ||
1167 | rc = SMB2_query_info_init(tcon, &rqst, file->fid.persistent_fid, | 1192 | /* Query */ |
1168 | file->fid.volatile_fid, | 1193 | memset(&qi_iov, 0, sizeof(qi_iov)); |
1194 | rqst[1].rq_iov = qi_iov; | ||
1195 | rqst[1].rq_nvec = 1; | ||
1196 | |||
1197 | rc = SMB2_query_info_init(tcon, &rqst[1], COMPOUND_FID, COMPOUND_FID, | ||
1169 | qi.file_info_class, qi.info_type, | 1198 | qi.file_info_class, qi.info_type, |
1170 | qi.additional_information, | 1199 | qi.additional_information, |
1171 | qi.input_buffer_length, | 1200 | qi.input_buffer_length, |
1172 | qi.output_buffer_length, buffer); | 1201 | qi.output_buffer_length, buffer); |
1173 | kfree(buffer); | ||
1174 | if (rc) | 1202 | if (rc) |
1175 | goto iqinf_exit; | 1203 | goto iqinf_exit; |
1204 | smb2_set_next_command(ses->server, &rqst[1]); | ||
1205 | smb2_set_related(&rqst[1]); | ||
1176 | 1206 | ||
1177 | rc = cifs_send_recv(xid, ses, &rqst, &resp_buftype, flags, &rsp_iov); | 1207 | /* Close */ |
1178 | rsp = (struct smb2_query_info_rsp *)rsp_iov.iov_base; | 1208 | memset(&close_iov, 0, sizeof(close_iov)); |
1209 | rqst[2].rq_iov = close_iov; | ||
1210 | rqst[2].rq_nvec = 1; | ||
1211 | |||
1212 | rc = SMB2_close_init(tcon, &rqst[2], COMPOUND_FID, COMPOUND_FID); | ||
1179 | if (rc) | 1213 | if (rc) |
1180 | goto iqinf_exit; | 1214 | goto iqinf_exit; |
1215 | smb2_set_related(&rqst[2]); | ||
1181 | 1216 | ||
1217 | rc = compound_send_recv(xid, ses, flags, 3, rqst, | ||
1218 | resp_buftype, rsp_iov); | ||
1219 | if (rc) | ||
1220 | goto iqinf_exit; | ||
1182 | pqi = (struct smb_query_info __user *)arg; | 1221 | pqi = (struct smb_query_info __user *)arg; |
1222 | rsp = (struct smb2_query_info_rsp *)rsp_iov[1].iov_base; | ||
1183 | if (le32_to_cpu(rsp->OutputBufferLength) < qi.input_buffer_length) | 1223 | if (le32_to_cpu(rsp->OutputBufferLength) < qi.input_buffer_length) |
1184 | qi.input_buffer_length = le32_to_cpu(rsp->OutputBufferLength); | 1224 | qi.input_buffer_length = le32_to_cpu(rsp->OutputBufferLength); |
1185 | if (copy_to_user(&pqi->input_buffer_length, &qi.input_buffer_length, | 1225 | if (copy_to_user(&pqi->input_buffer_length, &qi.input_buffer_length, |
@@ -1193,8 +1233,13 @@ smb2_ioctl_query_info(const unsigned int xid, | |||
1193 | } | 1233 | } |
1194 | 1234 | ||
1195 | iqinf_exit: | 1235 | iqinf_exit: |
1196 | SMB2_query_info_free(&rqst); | 1236 | kfree(buffer); |
1197 | free_rsp_buf(resp_buftype, rsp); | 1237 | SMB2_open_free(&rqst[0]); |
1238 | SMB2_query_info_free(&rqst[1]); | ||
1239 | SMB2_close_free(&rqst[2]); | ||
1240 | free_rsp_buf(resp_buftype[0], rsp_iov[0].iov_base); | ||
1241 | free_rsp_buf(resp_buftype[1], rsp_iov[1].iov_base); | ||
1242 | free_rsp_buf(resp_buftype[2], rsp_iov[2].iov_base); | ||
1198 | return rc; | 1243 | return rc; |
1199 | } | 1244 | } |
1200 | 1245 | ||