diff options
author | Steve French <smfrench@gmail.com> | 2015-11-03 10:26:27 -0500 |
---|---|---|
committer | Steve French <smfrench@gmail.com> | 2015-11-03 10:26:27 -0500 |
commit | b56eae4df9ef922d5785ec4a15d54d9527cedb13 (patch) | |
tree | 04a31bc533656e79e36ea5d9eed8fed0d7b28b4b | |
parent | f16dfa7cd1b588e5d7ef4b5a19ee579f11b7a41f (diff) |
[SMB3] Send durable handle v2 contexts when use of persistent handles required
Version 2 of the patch. Thanks to Dan Carpenter and the smatch
tool for finding a problem in the first version of this patch.
CC: Dan Carpenter <dan.carpenter@oracle.com>
Reviewed-by: Pavel Shilovsky <pshilovsky@samba.org>
Signed-off-by: Steve French <steve.french@primarydata.com>
-rw-r--r-- | fs/cifs/cifsglob.h | 1 | ||||
-rw-r--r-- | fs/cifs/smb2pdu.c | 123 | ||||
-rw-r--r-- | fs/cifs/smb2pdu.h | 45 | ||||
-rw-r--r-- | fs/cifs/smbfsctl.h | 2 |
4 files changed, 168 insertions, 3 deletions
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 28bd477f6e57..81273fea898f 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h | |||
@@ -1018,6 +1018,7 @@ struct cifs_fid { | |||
1018 | __u64 persistent_fid; /* persist file id for smb2 */ | 1018 | __u64 persistent_fid; /* persist file id for smb2 */ |
1019 | __u64 volatile_fid; /* volatile file id for smb2 */ | 1019 | __u64 volatile_fid; /* volatile file id for smb2 */ |
1020 | __u8 lease_key[SMB2_LEASE_KEY_SIZE]; /* lease key for smb2 */ | 1020 | __u8 lease_key[SMB2_LEASE_KEY_SIZE]; /* lease key for smb2 */ |
1021 | __u8 create_guid[16]; | ||
1021 | #endif | 1022 | #endif |
1022 | struct cifs_pending_open *pending_open; | 1023 | struct cifs_pending_open *pending_open; |
1023 | unsigned int epoch; | 1024 | unsigned int epoch; |
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index 597a417ba94d..2520ed5ded48 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c | |||
@@ -1151,13 +1151,130 @@ add_lease_context(struct TCP_Server_Info *server, struct kvec *iov, | |||
1151 | return 0; | 1151 | return 0; |
1152 | } | 1152 | } |
1153 | 1153 | ||
1154 | static struct create_durable_v2 * | ||
1155 | create_durable_v2_buf(struct cifs_fid *pfid) | ||
1156 | { | ||
1157 | struct create_durable_v2 *buf; | ||
1158 | |||
1159 | buf = kzalloc(sizeof(struct create_durable_v2), GFP_KERNEL); | ||
1160 | if (!buf) | ||
1161 | return NULL; | ||
1162 | |||
1163 | buf->ccontext.DataOffset = cpu_to_le16(offsetof | ||
1164 | (struct create_durable_v2, dcontext)); | ||
1165 | buf->ccontext.DataLength = cpu_to_le32(sizeof(struct durable_context_v2)); | ||
1166 | buf->ccontext.NameOffset = cpu_to_le16(offsetof | ||
1167 | (struct create_durable_v2, Name)); | ||
1168 | buf->ccontext.NameLength = cpu_to_le16(4); | ||
1169 | |||
1170 | buf->dcontext.Timeout = 0; /* Should this be configurable by workload */ | ||
1171 | buf->dcontext.Flags = cpu_to_le32(SMB2_DHANDLE_FLAG_PERSISTENT); | ||
1172 | get_random_bytes(buf->dcontext.CreateGuid, 16); | ||
1173 | memcpy(pfid->create_guid, buf->dcontext.CreateGuid, 16); | ||
1174 | |||
1175 | /* SMB2_CREATE_DURABLE_HANDLE_REQUEST is "DH2Q" */ | ||
1176 | buf->Name[0] = 'D'; | ||
1177 | buf->Name[1] = 'H'; | ||
1178 | buf->Name[2] = '2'; | ||
1179 | buf->Name[3] = 'Q'; | ||
1180 | return buf; | ||
1181 | } | ||
1182 | |||
1183 | static struct create_durable_handle_reconnect_v2 * | ||
1184 | create_reconnect_durable_v2_buf(struct cifs_fid *fid) | ||
1185 | { | ||
1186 | struct create_durable_handle_reconnect_v2 *buf; | ||
1187 | |||
1188 | buf = kzalloc(sizeof(struct create_durable_handle_reconnect_v2), | ||
1189 | GFP_KERNEL); | ||
1190 | if (!buf) | ||
1191 | return NULL; | ||
1192 | |||
1193 | buf->ccontext.DataOffset = | ||
1194 | cpu_to_le16(offsetof(struct create_durable_handle_reconnect_v2, | ||
1195 | dcontext)); | ||
1196 | buf->ccontext.DataLength = | ||
1197 | cpu_to_le32(sizeof(struct durable_reconnect_context_v2)); | ||
1198 | buf->ccontext.NameOffset = | ||
1199 | cpu_to_le16(offsetof(struct create_durable_handle_reconnect_v2, | ||
1200 | Name)); | ||
1201 | buf->ccontext.NameLength = cpu_to_le16(4); | ||
1202 | |||
1203 | buf->dcontext.Fid.PersistentFileId = fid->persistent_fid; | ||
1204 | buf->dcontext.Fid.VolatileFileId = fid->volatile_fid; | ||
1205 | buf->dcontext.Flags = cpu_to_le32(SMB2_DHANDLE_FLAG_PERSISTENT); | ||
1206 | memcpy(buf->dcontext.CreateGuid, fid->create_guid, 16); | ||
1207 | |||
1208 | /* SMB2_CREATE_DURABLE_HANDLE_RECONNECT_V2 is "DH2C" */ | ||
1209 | buf->Name[0] = 'D'; | ||
1210 | buf->Name[1] = 'H'; | ||
1211 | buf->Name[2] = '2'; | ||
1212 | buf->Name[3] = 'C'; | ||
1213 | return buf; | ||
1214 | } | ||
1215 | |||
1154 | static int | 1216 | static int |
1155 | add_durable_context(struct kvec *iov, unsigned int *num_iovec, | 1217 | add_durable_v2_context(struct kvec *iov, unsigned int *num_iovec, |
1156 | struct cifs_open_parms *oparms) | 1218 | struct cifs_open_parms *oparms) |
1157 | { | 1219 | { |
1158 | struct smb2_create_req *req = iov[0].iov_base; | 1220 | struct smb2_create_req *req = iov[0].iov_base; |
1159 | unsigned int num = *num_iovec; | 1221 | unsigned int num = *num_iovec; |
1160 | 1222 | ||
1223 | iov[num].iov_base = create_durable_v2_buf(oparms->fid); | ||
1224 | if (iov[num].iov_base == NULL) | ||
1225 | return -ENOMEM; | ||
1226 | iov[num].iov_len = sizeof(struct create_durable_v2); | ||
1227 | if (!req->CreateContextsOffset) | ||
1228 | req->CreateContextsOffset = | ||
1229 | cpu_to_le32(sizeof(struct smb2_create_req) - 4 + | ||
1230 | iov[1].iov_len); | ||
1231 | le32_add_cpu(&req->CreateContextsLength, sizeof(struct create_durable_v2)); | ||
1232 | inc_rfc1001_len(&req->hdr, sizeof(struct create_durable_v2)); | ||
1233 | *num_iovec = num + 1; | ||
1234 | return 0; | ||
1235 | } | ||
1236 | |||
1237 | static int | ||
1238 | add_durable_reconnect_v2_context(struct kvec *iov, unsigned int *num_iovec, | ||
1239 | struct cifs_open_parms *oparms) | ||
1240 | { | ||
1241 | struct smb2_create_req *req = iov[0].iov_base; | ||
1242 | unsigned int num = *num_iovec; | ||
1243 | |||
1244 | /* indicate that we don't need to relock the file */ | ||
1245 | oparms->reconnect = false; | ||
1246 | |||
1247 | iov[num].iov_base = create_reconnect_durable_v2_buf(oparms->fid); | ||
1248 | if (iov[num].iov_base == NULL) | ||
1249 | return -ENOMEM; | ||
1250 | iov[num].iov_len = sizeof(struct create_durable_handle_reconnect_v2); | ||
1251 | if (!req->CreateContextsOffset) | ||
1252 | req->CreateContextsOffset = | ||
1253 | cpu_to_le32(sizeof(struct smb2_create_req) - 4 + | ||
1254 | iov[1].iov_len); | ||
1255 | le32_add_cpu(&req->CreateContextsLength, | ||
1256 | sizeof(struct create_durable_handle_reconnect_v2)); | ||
1257 | inc_rfc1001_len(&req->hdr, | ||
1258 | sizeof(struct create_durable_handle_reconnect_v2)); | ||
1259 | *num_iovec = num + 1; | ||
1260 | return 0; | ||
1261 | } | ||
1262 | |||
1263 | static int | ||
1264 | add_durable_context(struct kvec *iov, unsigned int *num_iovec, | ||
1265 | struct cifs_open_parms *oparms, bool use_persistent) | ||
1266 | { | ||
1267 | struct smb2_create_req *req = iov[0].iov_base; | ||
1268 | unsigned int num = *num_iovec; | ||
1269 | |||
1270 | if (use_persistent) { | ||
1271 | if (oparms->reconnect) | ||
1272 | return add_durable_reconnect_v2_context(iov, num_iovec, | ||
1273 | oparms); | ||
1274 | else | ||
1275 | return add_durable_v2_context(iov, num_iovec, oparms); | ||
1276 | } | ||
1277 | |||
1161 | if (oparms->reconnect) { | 1278 | if (oparms->reconnect) { |
1162 | iov[num].iov_base = create_reconnect_durable_buf(oparms->fid); | 1279 | iov[num].iov_base = create_reconnect_durable_buf(oparms->fid); |
1163 | /* indicate that we don't need to relock the file */ | 1280 | /* indicate that we don't need to relock the file */ |
@@ -1275,7 +1392,9 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path, | |||
1275 | ccontext->Next = | 1392 | ccontext->Next = |
1276 | cpu_to_le32(server->vals->create_lease_size); | 1393 | cpu_to_le32(server->vals->create_lease_size); |
1277 | } | 1394 | } |
1278 | rc = add_durable_context(iov, &num_iovecs, oparms); | 1395 | |
1396 | rc = add_durable_context(iov, &num_iovecs, oparms, | ||
1397 | tcon->use_persistent); | ||
1279 | if (rc) { | 1398 | if (rc) { |
1280 | cifs_small_buf_release(req); | 1399 | cifs_small_buf_release(req); |
1281 | kfree(copy_path); | 1400 | kfree(copy_path); |
diff --git a/fs/cifs/smb2pdu.h b/fs/cifs/smb2pdu.h index 451108284a2f..4af52780ec35 100644 --- a/fs/cifs/smb2pdu.h +++ b/fs/cifs/smb2pdu.h | |||
@@ -590,6 +590,44 @@ struct create_durable { | |||
590 | } Data; | 590 | } Data; |
591 | } __packed; | 591 | } __packed; |
592 | 592 | ||
593 | /* See MS-SMB2 2.2.13.2.11 */ | ||
594 | /* Flags */ | ||
595 | #define SMB2_DHANDLE_FLAG_PERSISTENT 0x00000002 | ||
596 | struct durable_context_v2 { | ||
597 | __le32 Timeout; | ||
598 | __le32 Flags; | ||
599 | __u64 Reserved; | ||
600 | __u8 CreateGuid[16]; | ||
601 | } __packed; | ||
602 | |||
603 | struct create_durable_v2 { | ||
604 | struct create_context ccontext; | ||
605 | __u8 Name[8]; | ||
606 | struct durable_context_v2 dcontext; | ||
607 | } __packed; | ||
608 | |||
609 | /* See MS-SMB2 2.2.13.2.12 */ | ||
610 | struct durable_reconnect_context_v2 { | ||
611 | struct { | ||
612 | __u64 PersistentFileId; | ||
613 | __u64 VolatileFileId; | ||
614 | } Fid; | ||
615 | __u8 CreateGuid[16]; | ||
616 | __le32 Flags; /* see above DHANDLE_FLAG_PERSISTENT */ | ||
617 | } __packed; | ||
618 | |||
619 | /* See MS-SMB2 2.2.14.2.12 */ | ||
620 | struct durable_reconnect_context_v2_rsp { | ||
621 | __le32 Timeout; | ||
622 | __le32 Flags; /* see above DHANDLE_FLAG_PERSISTENT */ | ||
623 | } __packed; | ||
624 | |||
625 | struct create_durable_handle_reconnect_v2 { | ||
626 | struct create_context ccontext; | ||
627 | __u8 Name[8]; | ||
628 | struct durable_reconnect_context_v2 dcontext; | ||
629 | } __packed; | ||
630 | |||
593 | #define COPY_CHUNK_RES_KEY_SIZE 24 | 631 | #define COPY_CHUNK_RES_KEY_SIZE 24 |
594 | struct resume_key_req { | 632 | struct resume_key_req { |
595 | char ResumeKey[COPY_CHUNK_RES_KEY_SIZE]; | 633 | char ResumeKey[COPY_CHUNK_RES_KEY_SIZE]; |
@@ -643,6 +681,13 @@ struct fsctl_get_integrity_information_rsp { | |||
643 | /* Integrity flags for above */ | 681 | /* Integrity flags for above */ |
644 | #define FSCTL_INTEGRITY_FLAG_CHECKSUM_ENFORCEMENT_OFF 0x00000001 | 682 | #define FSCTL_INTEGRITY_FLAG_CHECKSUM_ENFORCEMENT_OFF 0x00000001 |
645 | 683 | ||
684 | /* See MS-SMB2 2.2.31.3 */ | ||
685 | struct network_resiliency_req { | ||
686 | __le32 Timeout; | ||
687 | __le32 Reserved; | ||
688 | } __packed; | ||
689 | /* There is no buffer for the response ie no struct network_resiliency_rsp */ | ||
690 | |||
646 | 691 | ||
647 | struct validate_negotiate_info_req { | 692 | struct validate_negotiate_info_req { |
648 | __le32 Capabilities; | 693 | __le32 Capabilities; |
diff --git a/fs/cifs/smbfsctl.h b/fs/cifs/smbfsctl.h index a639d0dab453..f996daeea271 100644 --- a/fs/cifs/smbfsctl.h +++ b/fs/cifs/smbfsctl.h | |||
@@ -90,7 +90,7 @@ | |||
90 | #define FSCTL_SRV_ENUMERATE_SNAPSHOTS 0x00144064 | 90 | #define FSCTL_SRV_ENUMERATE_SNAPSHOTS 0x00144064 |
91 | /* Retrieve an opaque file reference for server-side data movement ie copy */ | 91 | /* Retrieve an opaque file reference for server-side data movement ie copy */ |
92 | #define FSCTL_SRV_REQUEST_RESUME_KEY 0x00140078 | 92 | #define FSCTL_SRV_REQUEST_RESUME_KEY 0x00140078 |
93 | #define FSCTL_LMR_REQUEST_RESILIENCY 0x001401D4 /* BB add struct */ | 93 | #define FSCTL_LMR_REQUEST_RESILIENCY 0x001401D4 |
94 | #define FSCTL_LMR_GET_LINK_TRACK_INF 0x001400E8 /* BB add struct */ | 94 | #define FSCTL_LMR_GET_LINK_TRACK_INF 0x001400E8 /* BB add struct */ |
95 | #define FSCTL_LMR_SET_LINK_TRACK_INF 0x001400EC /* BB add struct */ | 95 | #define FSCTL_LMR_SET_LINK_TRACK_INF 0x001400EC /* BB add struct */ |
96 | #define FSCTL_VALIDATE_NEGOTIATE_INFO 0x00140204 | 96 | #define FSCTL_VALIDATE_NEGOTIATE_INFO 0x00140204 |