Skip to content

Commit

Permalink
[SMB3] Send durable handle v2 contexts when use of persistent handles…
Browse files Browse the repository at this point in the history
… 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 <[email protected]>
Reviewed-by: Pavel Shilovsky <[email protected]>
Signed-off-by: Steve French <[email protected]>
  • Loading branch information
smfrench committed Nov 3, 2015
1 parent f16dfa7 commit b56eae4
Show file tree
Hide file tree
Showing 4 changed files with 168 additions and 3 deletions.
1 change: 1 addition & 0 deletions fs/cifs/cifsglob.h
Original file line number Diff line number Diff line change
Expand Up @@ -1018,6 +1018,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;
Expand Down
123 changes: 121 additions & 2 deletions fs/cifs/smb2pdu.c
Original file line number Diff line number Diff line change
Expand Up @@ -1151,13 +1151,130 @@ add_lease_context(struct TCP_Server_Info *server, struct kvec *iov,
return 0;
}

static struct create_durable_v2 *
create_durable_v2_buf(struct cifs_fid *pfid)
{
struct create_durable_v2 *buf;

buf = kzalloc(sizeof(struct create_durable_v2), 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 int
add_durable_context(struct kvec *iov, unsigned int *num_iovec,
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;

/* indicate that we don't need to relock the file */
oparms->reconnect = false;

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;
}

static int
add_durable_context(struct kvec *iov, unsigned int *num_iovec,
struct cifs_open_parms *oparms, bool use_persistent)
{
struct smb2_create_req *req = iov[0].iov_base;
unsigned int num = *num_iovec;

if (use_persistent) {
if (oparms->reconnect)
return add_durable_reconnect_v2_context(iov, num_iovec,
oparms);
else
return add_durable_v2_context(iov, num_iovec, oparms);
}

if (oparms->reconnect) {
iov[num].iov_base = create_reconnect_durable_buf(oparms->fid);
/* indicate that we don't need to relock the file */
Expand Down Expand Up @@ -1275,7 +1392,9 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path,
ccontext->Next =
cpu_to_le32(server->vals->create_lease_size);
}
rc = add_durable_context(iov, &num_iovecs, oparms);

rc = add_durable_context(iov, &num_iovecs, oparms,
tcon->use_persistent);
if (rc) {
cifs_small_buf_release(req);
kfree(copy_path);
Expand Down
45 changes: 45 additions & 0 deletions fs/cifs/smb2pdu.h
Original file line number Diff line number Diff line change
Expand Up @@ -590,6 +590,44 @@ struct create_durable {
} Data;
} __packed;

/* See MS-SMB2 2.2.13.2.11 */
/* 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;

/* See MS-SMB2 2.2.13.2.12 */
struct durable_reconnect_context_v2 {
struct {
__u64 PersistentFileId;
__u64 VolatileFileId;
} Fid;
__u8 CreateGuid[16];
__le32 Flags; /* see above DHANDLE_FLAG_PERSISTENT */
} __packed;

/* See MS-SMB2 2.2.14.2.12 */
struct durable_reconnect_context_v2_rsp {
__le32 Timeout;
__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];
Expand Down Expand Up @@ -643,6 +681,13 @@ struct fsctl_get_integrity_information_rsp {
/* Integrity flags for above */
#define FSCTL_INTEGRITY_FLAG_CHECKSUM_ENFORCEMENT_OFF 0x00000001

/* See MS-SMB2 2.2.31.3 */
struct network_resiliency_req {
__le32 Timeout;
__le32 Reserved;
} __packed;
/* There is no buffer for the response ie no struct network_resiliency_rsp */


struct validate_negotiate_info_req {
__le32 Capabilities;
Expand Down
2 changes: 1 addition & 1 deletion fs/cifs/smbfsctl.h
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@
#define FSCTL_SRV_ENUMERATE_SNAPSHOTS 0x00144064
/* Retrieve an opaque file reference for server-side data movement ie copy */
#define FSCTL_SRV_REQUEST_RESUME_KEY 0x00140078
#define FSCTL_LMR_REQUEST_RESILIENCY 0x001401D4 /* BB add struct */
#define FSCTL_LMR_REQUEST_RESILIENCY 0x001401D4
#define FSCTL_LMR_GET_LINK_TRACK_INF 0x001400E8 /* BB add struct */
#define FSCTL_LMR_SET_LINK_TRACK_INF 0x001400EC /* BB add struct */
#define FSCTL_VALIDATE_NEGOTIATE_INFO 0x00140204
Expand Down

0 comments on commit b56eae4

Please sign in to comment.