Add parsing for new mount option controlling persistent handles
Subsystems (2)
PATCH 1/4 Add parsing for new mount option controlling persistent handles
"nopersistenthandles" and "persistenthandles" mount options added. The former will not request persistent handles on open even when SMB3 negotiated and Continuous Availability share. The latter will request persistent handles (as long as server notes the capability in protocol negotiation) even if share is not Continuous Availability share.
--- fs/cifs/cifsglob.h | 4 +++- fs/cifs/connect.c | 19 +++++++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-)
fs/cifs/cifsglob.h +3 -1
@@ -493,7 +493,9 @@ struct smb_vol { bool mfsymlinks:1; /* use Minshall+French Symlinks */ bool multiuser:1; bool rwpidforward:1; /* pid forward for read/write operations */ -bool nosharesock; + bool nosharesock:1; + bool persistent:1; + bool nopersistent:1;unsigned int rsize;unsigned int wsize; bool sockopt_tcp_nodelay:1;
fs/cifs/connect.c +19 -0
@@ -87,6 +87,7 @@ enum { Opt_sign, Opt_seal, Opt_noac, Opt_fsc, Opt_mfsymlinks, Opt_multiuser, Opt_sloppy, Opt_nosharesock, + Opt_persistent, Opt_nopersistent,/* Mount options which take numeric value */ Opt_backupuid, Opt_backupgid, Opt_uid,
@@ -169,6 +170,8 @@ static const match_table_t cifs_mount_option_tokens = { { Opt_multiuser, "multiuser" }, { Opt_sloppy, "sloppy" }, { Opt_nosharesock, "nosharesock" }, + { Opt_persistent, "persistenthandles"}, + { Opt_nopersistent, "nopersistenthandles"}, { Opt_backupuid, "backupuid=%s" }, { Opt_backupgid, "backupgid=%s" },
@@ -1497,6 +1500,22 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,case Opt_nosharesock: vol->nosharesock = true;break ; +case Opt_nopersistent: + vol->nopersistent = true; +if (vol->persistent) { +cifs_dbg (VFS , +"persistenthandles mount options conflict\n" ); + goto cifs_parse_mount_err; + } +break ; +case Opt_persistent: + vol->persistent = true; +if (vol->nopersistent) { +cifs_dbg (VFS , +"persistenthandles mount options conflict\n" ); + goto cifs_parse_mount_err; + } +break ;/* Numeric Values */ case Opt_backupuid:
Signature · 1 line
1.9.1
A message that is not in the archive (sent off-list or not yet received): 1443916442-42466-1-git-send-email-smfrench-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org
PATCH 2/4 Enable checking for continuous availability and persistent handle support
Validate "persistenthandles" and "nopersistenthandles" mount options against the support the server claims in negotiate and tree connect SMB3 responses.
--- fs/cifs/cifsglob.h | 1 + fs/cifs/connect.c | 30 ++++++++++++++++++++++++++++++ fs/cifs/smb2ops.c | 6 +++--- 3 files changed, 34 insertions(+), 3 deletions(-)
fs/cifs/cifsglob.h +1 -0
@@ -901,6 +901,7 @@ struct cifs_tcon {bool broken_posix_open;/* e.g. Samba server versions < 3.3.2, 3.2.9 */ bool broken_sparse_sup;/* if server or share does not support sparse */ bool need_reconnect:1; /* connection reset, tid now invalid */ + bool use_persistent:1; /* use persistent instead of durable handles */#ifdef CONFIG_CIFS_SMB2 bool print:1; /* set if connection to printer share */ bool bad_network_name:1; /* set if ret status STATUS_BAD_NETWORK_NAME */
fs/cifs/connect.c +30 -0
@@ -2673,6 +2673,30 @@ cifs_get_tcon(struct cifs_ses *ses, struct smb_vol *volume_info)cifs_dbg (FYI ,"DFS disabled (%d)\n" , tcon->Flags); } tcon->seal = volume_info->seal; + tcon->use_persistent = false; +/* check if SMB2 or later, CIFS does not support persistent handles */ +if (volume_info->persistent) { +if (ses->server->vals->protocol_id ==0 ) { +cifs_dbg (VFS , +"SMB3 or later required for persistent handles\n" ); + rc = -EOPNOTSUPP ; + goto out_fail; + }else if (ses->server->capabilities & +SMB2_GLOBAL_CAP_PERSISTENT_HANDLES ) + tcon->use_persistent = true; +else /* persistent handles requested but not supported */ { +cifs_dbg (VFS , +"Persistent handles not supported on share\n" ); + rc = -EOPNOTSUPP ; + goto out_fail; + } + }else if ((tcon->capabilities &SMB2_SHARE_CAP_CONTINUOUS_AVAILABILITY ) + && (ses->server->capabilities &SMB2_GLOBAL_CAP_PERSISTENT_HANDLES ) + && (volume_info->nopersistent == false)) { +cifs_dbg (FYI ,"enabling persistent handles\n" ); + tcon->use_persistent = true; + } +/* * We can have only one retry value for a connection to a share so for * resources mounted more than once to the same server share the last
@@ -3521,6 +3545,12 @@ try_mount_again: goto mount_fail_check; } +if ((volume_info->persistent == true) && ((ses->server->capabilities & +SMB2_GLOBAL_CAP_PERSISTENT_HANDLES ) ==0 )) { +cifs_dbg (VFS ,"persistent handles not supported by server\n" ); + rc = -EOPNOTSUPP ; + goto mount_fail_check; + }/* search for existing tcon to this server share */ tcon =cifs_get_tcon (ses, volume_info);if (IS_ERR (tcon)) {
fs/cifs/smb2ops.c +3 -3
@@ -1843,7 +1843,7 @@ struct smb_version_values smb21_values = {struct smb_version_values smb30_values = { .version_string =SMB30_VERSION_STRING , .protocol_id =SMB30_PROT_ID , - .req_capabilities =SMB2_GLOBAL_CAP_DFS |SMB2_GLOBAL_CAP_LEASING |SMB2_GLOBAL_CAP_LARGE_MTU |SMB2_GLOBAL_CAP_ENCRYPTION , + .req_capabilities =SMB2_GLOBAL_CAP_DFS |SMB2_GLOBAL_CAP_LEASING |SMB2_GLOBAL_CAP_LARGE_MTU |SMB2_GLOBAL_CAP_ENCRYPTION |SMB2_GLOBAL_CAP_PERSISTENT_HANDLES , .large_lock_type =0 , .exclusive_lock_type =SMB2_LOCKFLAG_EXCLUSIVE_LOCK , .shared_lock_type =SMB2_LOCKFLAG_SHARED_LOCK ,
@@ -1863,7 +1863,7 @@ struct smb_version_values smb30_values = {struct smb_version_values smb302_values = { .version_string =SMB302_VERSION_STRING , .protocol_id =SMB302_PROT_ID , - .req_capabilities =SMB2_GLOBAL_CAP_DFS |SMB2_GLOBAL_CAP_LEASING |SMB2_GLOBAL_CAP_LARGE_MTU , + .req_capabilities =SMB2_GLOBAL_CAP_DFS |SMB2_GLOBAL_CAP_LEASING |SMB2_GLOBAL_CAP_LARGE_MTU |SMB2_GLOBAL_CAP_PERSISTENT_HANDLES , .large_lock_type =0 , .exclusive_lock_type =SMB2_LOCKFLAG_EXCLUSIVE_LOCK , .shared_lock_type =SMB2_LOCKFLAG_SHARED_LOCK ,
@@ -1884,7 +1884,7 @@ struct smb_version_values smb302_values = {struct smb_version_values smb311_values = { .version_string =SMB311_VERSION_STRING , .protocol_id =SMB311_PROT_ID , - .req_capabilities =SMB2_GLOBAL_CAP_DFS |SMB2_GLOBAL_CAP_LEASING |SMB2_GLOBAL_CAP_LARGE_MTU , + .req_capabilities =SMB2_GLOBAL_CAP_DFS |SMB2_GLOBAL_CAP_LEASING |SMB2_GLOBAL_CAP_LARGE_MTU |SMB2_GLOBAL_CAP_PERSISTENT_HANDLES , .large_lock_type =0 , .exclusive_lock_type =SMB2_LOCKFLAG_EXCLUSIVE_LOCK , .shared_lock_type =SMB2_LOCKFLAG_SHARED_LOCK ,
Signature · 1 line
1.9.1
PATCH 3/4 Display persistenthandles in /proc/mounts for SMB3 shares if enabled
In reply to a message not in the archive--- fs/cifs/cifsfs.c | 2 ++ 1 file changed, 2 insertions(+)
fs/cifs/cifsfs.c +2 -0
@@ -454,6 +454,8 @@ cifs_show_options(struct seq_file *s, struct dentry *root)seq_puts (s,",nocase" );if (tcon->retry)seq_puts (s,",hard" ); +if (tcon->use_persistent) +seq_puts (s,",persistenthandles" );if (tcon->unix_ext)seq_puts (s,",unix" );else
Signature · 1 line
1.9.1
PATCH 4/4 Send durable handle v2 contexts when use of persistent handles required
In reply to a message not in the archive--- fs/cifs/cifsglob.h | 1 + fs/cifs/smb2pdu.c | 123 ++++++++++++++++++++++++++++++++++++++++++++++++++++- fs/cifs/smb2pdu.h | 45 ++++++++++++++++++++ fs/cifs/smbfsctl.h | 2 +- 4 files changed, 168 insertions(+), 3 deletions(-)
fs/cifs/cifsglob.h +1 -0
@@ -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 +121 -2
141 lines not on this page · raw message
fs/cifs/smb2pdu.h +45 -0
57 lines not on this page · raw message
fs/cifs/smbfsctl.h +1 -1
@@ -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
Signature · 1 line
1.9.1
A message that is not in the archive (sent off-list or not yet received): 1443916442-42466-4-git-send-email-smfrench-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org
Pavel Shilovsky
Reviewed-byRe: [PATCH 4/4] [SMB3] Send durable handle v2 contexts when use of persistent handles required
2015-10-04 2:54 GMT+03:00 Steve French <[email protected]>:
Quoted 245 lines
CC Pavel Shilovsky <[email protected]>--- fs/cifs/cifsglob.h | 1 + fs/cifs/smb2pdu.c | 123 ++++++++++++++++++++++++++++++++++++++++++++++++++++- fs/cifs/smb2pdu.h | 45 ++++++++++++++++++++ fs/cifs/smbfsctl.h | 2 +- 4 files changed, 168 insertions(+), 3 deletions(-)fs/cifs/cifsglob.h +1
-0@@ -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 +121
-2@@ -1148,13 +1148,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 ),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 */ @@ -1272,7 +1389,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);fs/cifs/smb2pdu.h +45
-0@@ -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 24struct resume_key_req {char ResumeKey[COPY_CHUNK_RES_KEY_SIZE ];@@ -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;fs/cifs/smbfsctl.h +1
-2@@ -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 --
Quoted 1 line
1.9.1
The whole series looks good to me. You can add my
tag to each of 4 patches.
Signature · 2 lines
Best regards, Pavel Shilovsky.