Skip to contentSkip to conversation

Send durable handle v2 contexts when use of persistent handles required

PATCH In review Steve French 2 participants 3 messages Oct 1, 2015 – Oct 4, 2015 2 messages not in the archive

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

PATCH 1/1 Send durable handle v2 contexts when use of persistent handles required

---
 fs/cifs/cifsglob.h |   1 +
 fs/cifs/smb2pdu.c  | 114 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
 fs/cifs/smb2pdu.h  |  30 ++++++++++++++
 3 files changed, 144 insertions(+), 1 deletion(-)
fs/cifs/cifsglob.h +1 -0
index 51353bb..ec31a03 100644
@@ -1022,6 +1022,7 @@ struct cifs_fid {
 	__u64 persistent_fid;	/* persist file id for smb2 */
 	__u64 volatile_fid;	/* volatile file id for smb2 */
 	__u8 lease_key[SMB2_LEASE_KEY_SIZE];	/* lease key for smb2 */
+	__u8 create_guid[16];
 #endif
 	struct cifs_pending_open *pending_open;
 	unsigned int epoch;
fs/cifs/smb2pdu.c +113 -1

132 lines not on this page · raw message

fs/cifs/smb2pdu.h +30 -0
index b26da75..a939526 100644
@@ -590,6 +590,36 @@ struct create_durable {
 	} Data;
 } __packed;
 
+/* Flags */
+#define SMB2_DHANDLE_FLAG_PERSISTENT	0x00000002
+struct durable_context_v2 {
+	__le32 Timeout;
+	__le32 Flags;
+	__u64 Reserved;
+	__u8 CreateGuid[16];
+} __packed;
+
+struct create_durable_v2 {
+	struct create_context ccontext;
+	__u8   Name[8];
+	struct durable_context_v2 dcontext;
+} __packed;
+
+struct durable_reconnect_context_v2 {
+	struct {
+		__u64 PersistentFileId;
+		__u64 VolatileFileId;
+	} Fid;
+	__u8 CreateGuid[16];
+	__le32 Flags; /* see above DHANDLE_FLAG_PERSISTENT */
+} __packed;
+
+struct create_durable_handle_reconnect_v2 {
+	struct create_context ccontext;
+	__u8   Name[8];
+	struct durable_reconnect_context_v2 dcontext;
+} __packed;
+
 #define COPY_CHUNK_RES_KEY_SIZE	24
 struct resume_key_req {
 	char ResumeKey[COPY_CHUNK_RES_KEY_SIZE];
Signature · 1 line
1.9.1

A message that is not in the archive (sent off-list or not yet received): 1443723435-32484-1-git-send-email-smfrench-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org

#2 lore raw

2015-10-01 21:17 GMT+03:00 Steve French <[email protected]>:

Quoted 145 lines
---
 fs/cifs/cifsglob.h |   1 +
 fs/cifs/smb2pdu.c  | 114 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
 fs/cifs/smb2pdu.h  |  30 ++++++++++++++
 3 files changed, 144 insertions(+), 1 deletion(-)
fs/cifs/cifsglob.h +1 -0
index 51353bb..ec31a03 100644
@@ -1022,6 +1022,7 @@ struct cifs_fid {
        __u64 persistent_fid;   /* persist file id for smb2 */
        __u64 volatile_fid;     /* volatile file id for smb2 */
        __u8 lease_key[SMB2_LEASE_KEY_SIZE];    /* lease key for smb2 */
+       __u8 create_guid[16];
 #endif
        struct cifs_pending_open *pending_open;
        unsigned int epoch;
fs/cifs/smb2pdu.c +104 -0
index c744b57..6b899bf 100644
@@ -1100,6 +1100,68 @@ create_reconnect_durable_buf(struct cifs_fid *fid)
        return buf;
 }
 
+static struct create_durable_v2 *
+create_durable_v2_buf(struct cifs_fid *pfid)
+{
+       struct create_durable_v2 *buf;
+
+       buf = kzalloc(sizeof(struct create_durable), GFP_KERNEL);
+       if (!buf)
+               return NULL;
+
+       buf->ccontext.DataOffset = cpu_to_le16(offsetof
+                                       (struct create_durable_v2, dcontext));
+       buf->ccontext.DataLength = cpu_to_le32(sizeof(struct durable_context_v2));
+       buf->ccontext.NameOffset = cpu_to_le16(offsetof
+                               (struct create_durable_v2, Name));
+       buf->ccontext.NameLength = cpu_to_le16(4);
+
+       buf->dcontext.Timeout = 0; /* Should this be configurable by workload */
+       buf->dcontext.Flags = cpu_to_le32(SMB2_DHANDLE_FLAG_PERSISTENT);
+       get_random_bytes(buf->dcontext.CreateGuid, 16);
+       memcpy(pfid->create_guid, buf->dcontext.CreateGuid, 16);
+
+       /* SMB2_CREATE_DURABLE_HANDLE_REQUEST is "DH2Q" */
+       buf->Name[0] = 'D';
+       buf->Name[1] = 'H';
+       buf->Name[2] = '2';
+       buf->Name[3] = 'Q';
+       return buf;
+}
+
+static struct create_durable_handle_reconnect_v2 *
+create_reconnect_durable_v2_buf(struct cifs_fid *fid)
+{
+       struct create_durable_handle_reconnect_v2 *buf;
+
+       buf = kzalloc(sizeof(struct create_durable_handle_reconnect_v2),
+                       GFP_KERNEL);
+       if (!buf)
+               return NULL;
+
+       buf->ccontext.DataOffset =
+               cpu_to_le16(offsetof(struct create_durable_handle_reconnect_v2,
+                                    dcontext));
+       buf->ccontext.DataLength =
+               cpu_to_le32(sizeof(struct durable_reconnect_context_v2));
+       buf->ccontext.NameOffset =
+               cpu_to_le16(offsetof(struct create_durable_handle_reconnect_v2,
+                           Name));
+       buf->ccontext.NameLength = cpu_to_le16(4);
+
+       buf->dcontext.Fid.PersistentFileId = fid->persistent_fid;
+       buf->dcontext.Fid.VolatileFileId = fid->volatile_fid;
+       buf->dcontext.Flags = cpu_to_le32(SMB2_DHANDLE_FLAG_PERSISTENT);
+       memcpy(buf->dcontext.CreateGuid, fid->create_guid, 16);
+
+       /* SMB2_CREATE_DURABLE_HANDLE_RECONNECT_V2 is "DH2C" */
+       buf->Name[0] = 'D';
+       buf->Name[1] = 'H';
+       buf->Name[2] = '2';
+       buf->Name[3] = 'C';
+       return buf;
+}
+
 static __u8
 parse_lease_state(struct TCP_Server_Info *server, struct smb2_create_rsp *rsp,
                  unsigned int *epoch)
@@ -1174,6 +1236,48 @@ add_durable_context(struct kvec *iov, unsigned int *num_iovec,
        return 0;
 }
 
+static int
+add_durable_v2_context(struct kvec *iov, unsigned int *num_iovec,
+                   struct cifs_open_parms *oparms)
+{
+       struct smb2_create_req *req = iov[0].iov_base;
+       unsigned int num = *num_iovec;
+
+       iov[num].iov_base = create_durable_v2_buf(oparms->fid);
+       if (iov[num].iov_base == NULL)
+               return -ENOMEM;
+       iov[num].iov_len = sizeof(struct create_durable_v2);
+       if (!req->CreateContextsOffset)
+               req->CreateContextsOffset =
+                       cpu_to_le32(sizeof(struct smb2_create_req) - 4 +
+                                                               iov[1].iov_len);
+       le32_add_cpu(&req->CreateContextsLength, sizeof(struct create_durable_v2));
+       inc_rfc1001_len(&req->hdr, sizeof(struct create_durable_v2));
+       *num_iovec = num + 1;
+       return 0;
+}
+
+static int
+add_durable_reconnect_v2_context(struct kvec *iov, unsigned int *num_iovec,
+                   struct cifs_open_parms *oparms)
+{
+       struct smb2_create_req *req = iov[0].iov_base;
+       unsigned int num = *num_iovec;
+
+       iov[num].iov_base = create_reconnect_durable_v2_buf(oparms->fid);
+       if (iov[num].iov_base == NULL)
+               return -ENOMEM;
+       iov[num].iov_len = sizeof(struct create_durable_handle_reconnect_v2);
+       if (!req->CreateContextsOffset)
+               req->CreateContextsOffset =
+                       cpu_to_le32(sizeof(struct smb2_create_req) - 4 +
+                                                               iov[1].iov_len);
+       le32_add_cpu(&req->CreateContextsLength, sizeof(struct create_durable_handle_reconnect_v2));
+       inc_rfc1001_len(&req->hdr, sizeof(struct create_durable_handle_reconnect_v2));
+       *num_iovec = num + 1;
+       return 0;
+}
+
 int
 SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path,
          __u8 *oplock, struct smb2_file_all_info *buf,
@@ -1272,7 +1376,15 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path,
                        ccontext->Next =
                                cpu_to_le32(server->vals->create_lease_size);
                }

fs/cifs/smb2pdu.c SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path, · line 1387

Quoted 10 lines
fs/cifs/smb2pdu.c +9 -1
-               rc = add_durable_context(iov, &num_iovecs, oparms);
+               if (tcon->use_persistent) {
+                       if (oparms->reconnect)
+                               rc = add_durable_reconnect_v2_context(iov,
+                                                       &num_iovecs, oparms);
+                       else
+                               rc = add_durable_v2_context(iov, &num_iovecs,
+                                                       oparms);
+               } else
+                       rc = add_durable_context(iov, &num_iovecs, oparms);

I think it will be better to incapsulate this if statements into add_durable_context() function to leave SMB2_open() code more generic.

Quoted 47 lines
fs/cifs/smb2pdu.c +0 -0
                if (rc) {
                        cifs_small_buf_release(req);
                        kfree(copy_path);
fs/cifs/smb2pdu.h +30 -1
index b26da75..a939526 100644
@@ -590,6 +590,36 @@ struct create_durable {
        } Data;
 } __packed;
 
+/* Flags */
+#define SMB2_DHANDLE_FLAG_PERSISTENT   0x00000002
+struct durable_context_v2 {
+       __le32 Timeout;
+       __le32 Flags;
+       __u64 Reserved;
+       __u8 CreateGuid[16];
+} __packed;
+
+struct create_durable_v2 {
+       struct create_context ccontext;
+       __u8   Name[8];
+       struct durable_context_v2 dcontext;
+} __packed;
+
+struct durable_reconnect_context_v2 {
+       struct {
+               __u64 PersistentFileId;
+               __u64 VolatileFileId;
+       } Fid;
+       __u8 CreateGuid[16];
+       __le32 Flags; /* see above DHANDLE_FLAG_PERSISTENT */
+} __packed;
+
+struct create_durable_handle_reconnect_v2 {
+       struct create_context ccontext;
+       __u8   Name[8];
+       struct durable_reconnect_context_v2 dcontext;
+} __packed;
+
 #define COPY_CHUNK_RES_KEY_SIZE        24
 struct resume_key_req {
        char ResumeKey[COPY_CHUNK_RES_KEY_SIZE];
--

1.9.1

Quoted 4 lines

--
To unsubscribe from this list: send the line "unsubscribe linux-cifs" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html

Other than the note above the patch looks good.

Signature · 2 lines
Best regards,
Pavel Shilovsky.

A message that is not in the archive (sent off-list or not yet received): CAKywueTcLJ0__8mSaD5LGG6rVp2PiNnJhC0br1NcyHc6rTQrwQ-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org

#4 lore raw

Updated and resent the 4 patch series onto linux-cifs and also pushed to cifs-2.6.git experimental branch.

I don't know if channel sequence number in the SMB3 request would also need to be incremented on disconnect though (the documentation is confusing on that in MS-SMB2) in the case where we only have one channel.

Also wondering if I should add a mount option for resilient handles to allow us to force better reliability of connections to non-clustered servers (and presumably could work even to Windows 8 and 8.1 and Windows 10 servers) when the application would prefer that (to the less strict guarantees of durable handles)

Quoted 217 lines · Pavel Shilovsky

2015-10-01 21:17 GMT+03:00 Steve French <[email protected]>:

Quoted 145 lines
---
 fs/cifs/cifsglob.h |   1 +
 fs/cifs/smb2pdu.c  | 114 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
 fs/cifs/smb2pdu.h  |  30 ++++++++++++++
 3 files changed, 144 insertions(+), 1 deletion(-)
fs/cifs/cifsglob.h +1 -0
index 51353bb..ec31a03 100644
@@ -1022,6 +1022,7 @@ struct cifs_fid {
        __u64 persistent_fid;   /* persist file id for smb2 */
        __u64 volatile_fid;     /* volatile file id for smb2 */
        __u8 lease_key[SMB2_LEASE_KEY_SIZE];    /* lease key for smb2 */
+       __u8 create_guid[16];
 #endif
        struct cifs_pending_open *pending_open;
        unsigned int epoch;
fs/cifs/smb2pdu.c +104 -0
index c744b57..6b899bf 100644
@@ -1100,6 +1100,68 @@ create_reconnect_durable_buf(struct cifs_fid *fid)
        return buf;
 }
 
+static struct create_durable_v2 *
+create_durable_v2_buf(struct cifs_fid *pfid)
+{
+       struct create_durable_v2 *buf;
+
+       buf = kzalloc(sizeof(struct create_durable), GFP_KERNEL);
+       if (!buf)
+               return NULL;
+
+       buf->ccontext.DataOffset = cpu_to_le16(offsetof
+                                       (struct create_durable_v2, dcontext));
+       buf->ccontext.DataLength = cpu_to_le32(sizeof(struct durable_context_v2));
+       buf->ccontext.NameOffset = cpu_to_le16(offsetof
+                               (struct create_durable_v2, Name));
+       buf->ccontext.NameLength = cpu_to_le16(4);
+
+       buf->dcontext.Timeout = 0; /* Should this be configurable by workload */
+       buf->dcontext.Flags = cpu_to_le32(SMB2_DHANDLE_FLAG_PERSISTENT);
+       get_random_bytes(buf->dcontext.CreateGuid, 16);
+       memcpy(pfid->create_guid, buf->dcontext.CreateGuid, 16);
+
+       /* SMB2_CREATE_DURABLE_HANDLE_REQUEST is "DH2Q" */
+       buf->Name[0] = 'D';
+       buf->Name[1] = 'H';
+       buf->Name[2] = '2';
+       buf->Name[3] = 'Q';
+       return buf;
+}
+
+static struct create_durable_handle_reconnect_v2 *
+create_reconnect_durable_v2_buf(struct cifs_fid *fid)
+{
+       struct create_durable_handle_reconnect_v2 *buf;
+
+       buf = kzalloc(sizeof(struct create_durable_handle_reconnect_v2),
+                       GFP_KERNEL);
+       if (!buf)
+               return NULL;
+
+       buf->ccontext.DataOffset =
+               cpu_to_le16(offsetof(struct create_durable_handle_reconnect_v2,
+                                    dcontext));
+       buf->ccontext.DataLength =
+               cpu_to_le32(sizeof(struct durable_reconnect_context_v2));
+       buf->ccontext.NameOffset =
+               cpu_to_le16(offsetof(struct create_durable_handle_reconnect_v2,
+                           Name));
+       buf->ccontext.NameLength = cpu_to_le16(4);
+
+       buf->dcontext.Fid.PersistentFileId = fid->persistent_fid;
+       buf->dcontext.Fid.VolatileFileId = fid->volatile_fid;
+       buf->dcontext.Flags = cpu_to_le32(SMB2_DHANDLE_FLAG_PERSISTENT);
+       memcpy(buf->dcontext.CreateGuid, fid->create_guid, 16);
+
+       /* SMB2_CREATE_DURABLE_HANDLE_RECONNECT_V2 is "DH2C" */
+       buf->Name[0] = 'D';
+       buf->Name[1] = 'H';
+       buf->Name[2] = '2';
+       buf->Name[3] = 'C';
+       return buf;
+}
+
 static __u8
 parse_lease_state(struct TCP_Server_Info *server, struct smb2_create_rsp *rsp,
                  unsigned int *epoch)
@@ -1174,6 +1236,48 @@ add_durable_context(struct kvec *iov, unsigned int *num_iovec,
        return 0;
 }
 
+static int
+add_durable_v2_context(struct kvec *iov, unsigned int *num_iovec,
+                   struct cifs_open_parms *oparms)
+{
+       struct smb2_create_req *req = iov[0].iov_base;
+       unsigned int num = *num_iovec;
+
+       iov[num].iov_base = create_durable_v2_buf(oparms->fid);
+       if (iov[num].iov_base == NULL)
+               return -ENOMEM;
+       iov[num].iov_len = sizeof(struct create_durable_v2);
+       if (!req->CreateContextsOffset)
+               req->CreateContextsOffset =
+                       cpu_to_le32(sizeof(struct smb2_create_req) - 4 +
+                                                               iov[1].iov_len);
+       le32_add_cpu(&req->CreateContextsLength, sizeof(struct create_durable_v2));
+       inc_rfc1001_len(&req->hdr, sizeof(struct create_durable_v2));
+       *num_iovec = num + 1;
+       return 0;
+}
+
+static int
+add_durable_reconnect_v2_context(struct kvec *iov, unsigned int *num_iovec,
+                   struct cifs_open_parms *oparms)
+{
+       struct smb2_create_req *req = iov[0].iov_base;
+       unsigned int num = *num_iovec;
+
+       iov[num].iov_base = create_reconnect_durable_v2_buf(oparms->fid);
+       if (iov[num].iov_base == NULL)
+               return -ENOMEM;
+       iov[num].iov_len = sizeof(struct create_durable_handle_reconnect_v2);
+       if (!req->CreateContextsOffset)
+               req->CreateContextsOffset =
+                       cpu_to_le32(sizeof(struct smb2_create_req) - 4 +
+                                                               iov[1].iov_len);
+       le32_add_cpu(&req->CreateContextsLength, sizeof(struct create_durable_handle_reconnect_v2));
+       inc_rfc1001_len(&req->hdr, sizeof(struct create_durable_handle_reconnect_v2));
+       *num_iovec = num + 1;
+       return 0;
+}
+
 int
 SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path,
          __u8 *oplock, struct smb2_file_all_info *buf,
@@ -1272,7 +1376,15 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path,
                        ccontext->Next =
                                cpu_to_le32(server->vals->create_lease_size);
                }

fs/cifs/smb2pdu.c SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path, · line 1387

Quoted 10 lines
fs/cifs/smb2pdu.c +9 -1
-               rc = add_durable_context(iov, &num_iovecs, oparms);
+               if (tcon->use_persistent) {
+                       if (oparms->reconnect)
+                               rc = add_durable_reconnect_v2_context(iov,
+                                                       &num_iovecs, oparms);
+                       else
+                               rc = add_durable_v2_context(iov, &num_iovecs,
+                                                       oparms);
+               } else
+                       rc = add_durable_context(iov, &num_iovecs, oparms);

I think it will be better to incapsulate this if statements into add_durable_context() function to leave SMB2_open() code more generic.

Quoted 47 lines
fs/cifs/smb2pdu.c +0 -0
                if (rc) {
                        cifs_small_buf_release(req);
                        kfree(copy_path);
fs/cifs/smb2pdu.h +30 -1
index b26da75..a939526 100644
@@ -590,6 +590,36 @@ struct create_durable {
        } Data;
 } __packed;
 
+/* Flags */
+#define SMB2_DHANDLE_FLAG_PERSISTENT   0x00000002
+struct durable_context_v2 {
+       __le32 Timeout;
+       __le32 Flags;
+       __u64 Reserved;
+       __u8 CreateGuid[16];
+} __packed;
+
+struct create_durable_v2 {
+       struct create_context ccontext;
+       __u8   Name[8];
+       struct durable_context_v2 dcontext;
+} __packed;
+
+struct durable_reconnect_context_v2 {
+       struct {
+               __u64 PersistentFileId;
+               __u64 VolatileFileId;
+       } Fid;
+       __u8 CreateGuid[16];
+       __le32 Flags; /* see above DHANDLE_FLAG_PERSISTENT */
+} __packed;
+
+struct create_durable_handle_reconnect_v2 {
+       struct create_context ccontext;
+       __u8   Name[8];
+       struct durable_reconnect_context_v2 dcontext;
+} __packed;
+
 #define COPY_CHUNK_RES_KEY_SIZE        24
 struct resume_key_req {
        char ResumeKey[COPY_CHUNK_RES_KEY_SIZE];
--

1.9.1

Quoted 4 lines

--
To unsubscribe from this list: send the line "unsubscribe linux-cifs" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html

Other than the note above the patch looks good.

--
Best regards,
Pavel Shilovsky.

Signature · 3 lines
Thanks,

Steve