]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
Add resilienthandles mount parm
authorSteve French <smfrench@gmail.com>
Tue, 6 Oct 2015 04:17:27 +0000 (23:17 -0500)
committerSteve French <smfrench@gmail.com>
Sun, 1 Nov 2015 03:44:53 +0000 (22:44 -0500)
Since many servers (Windows clients, and non-clustered servers) do not
support persistent handles but do support resilient handles, allow
the user to specify a mount option "resilienthandles" in order
to get more reliable connections and less chance of data loss
(at least when SMB2.1 or later).  Default resilient handle
timeout (120 seconds to recent Windows server) is used.

Reviewed-by: Pavel Shilovsky <pshilovsky@samba.org>
Signed-off-by: Steve French <steve.french@primarydata.com>
fs/cifs/cifsfs.c
fs/cifs/cifsglob.h
fs/cifs/connect.c
fs/cifs/smb2file.c

index 13302e94fee3d1ede7d2a646cace52aded1cec0d..f578ef9bc1f4dbc039ffce2081d64e5049de041d 100644 (file)
@@ -456,6 +456,8 @@ cifs_show_options(struct seq_file *s, struct dentry *root)
                seq_puts(s, ",hard");
        if (tcon->use_persistent)
                seq_puts(s, ",persistenthandles");
+       else if (tcon->use_resilient)
+               seq_puts(s, ",resilienthandles");
        if (tcon->unix_ext)
                seq_puts(s, ",unix");
        else
index ec31a0337baf00f63abf2fe6a9c67147108230fa..472daeb513d70d2ba34bea9536333b83e142a035 100644 (file)
@@ -496,6 +496,7 @@ struct smb_vol {
        bool nosharesock:1;
        bool persistent:1;
        bool nopersistent:1;
+       bool resilient:1; /* noresilient not required since not fored for CA */
        unsigned int rsize;
        unsigned int wsize;
        bool sockopt_tcp_nodelay:1;
@@ -901,6 +902,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_resilient:1; /* use resilient instead of durable handles */
        bool use_persistent:1; /* use persistent instead of durable handles */
 #ifdef CONFIG_CIFS_SMB2
        bool print:1;           /* set if connection to printer share */
index 9e445324fe0b104567aa48f700fd443386654821..1e7840a19a35f656ba8aea0945b7aab31b3cfe4e 100644 (file)
@@ -88,6 +88,7 @@ enum {
        Opt_fsc, Opt_mfsymlinks,
        Opt_multiuser, Opt_sloppy, Opt_nosharesock,
        Opt_persistent, Opt_nopersistent,
+       Opt_resilient, Opt_noresilient,
 
        /* Mount options which take numeric value */
        Opt_backupuid, Opt_backupgid, Opt_uid,
@@ -172,6 +173,8 @@ static const match_table_t cifs_mount_option_tokens = {
        { Opt_nosharesock, "nosharesock" },
        { Opt_persistent, "persistenthandles"},
        { Opt_nopersistent, "nopersistenthandles"},
+       { Opt_resilient, "resilienthandles"},
+       { Opt_noresilient, "noresilienthandles"},
 
        { Opt_backupuid, "backupuid=%s" },
        { Opt_backupgid, "backupgid=%s" },
@@ -1510,12 +1513,23 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
                        break;
                case Opt_persistent:
                        vol->persistent = true;
-                       if (vol->nopersistent) {
+                       if ((vol->nopersistent) || (vol->resilient)) {
                                cifs_dbg(VFS,
                                  "persistenthandles mount options conflict\n");
                                goto cifs_parse_mount_err;
                        }
                        break;
+               case Opt_resilient:
+                       vol->resilient = true;
+                       if (vol->persistent) {
+                               cifs_dbg(VFS,
+                                 "persistenthandles mount options conflict\n");
+                               goto cifs_parse_mount_err;
+                       }
+                       break;
+               case Opt_noresilient:
+                       vol->resilient = false; /* this is already the default */
+                       break;
 
                /* Numeric Values */
                case Opt_backupuid:
@@ -2695,6 +2709,14 @@ cifs_get_tcon(struct cifs_ses *ses, struct smb_vol *volume_info)
             && (volume_info->nopersistent == false)) {
                cifs_dbg(FYI, "enabling persistent handles\n");
                tcon->use_persistent = true;
+       } else if (volume_info->resilient) {
+               if (ses->server->vals->protocol_id == 0) {
+                       cifs_dbg(VFS,
+                            "SMB2.1 or later required for resilient handles\n");
+                       rc = -EOPNOTSUPP;
+                       goto out_fail;
+               }
+               tcon->use_resilient = true;
        }
 
        /*
index 2ab297dae5a7b2b4e544e3f35abc5f09b9fa7b1d..f9e766f464beec408b628146c4e0d4e04010e0f2 100644 (file)
@@ -43,6 +43,7 @@ smb2_open_file(const unsigned int xid, struct cifs_open_parms *oparms,
        struct smb2_file_all_info *smb2_data = NULL;
        __u8 smb2_oplock[17];
        struct cifs_fid *fid = oparms->fid;
+       struct network_resiliency_req nr_ioctl_req;
 
        smb2_path = cifs_convert_path_to_utf16(oparms->path, oparms->cifs_sb);
        if (smb2_path == NULL) {
@@ -67,6 +68,24 @@ smb2_open_file(const unsigned int xid, struct cifs_open_parms *oparms,
        if (rc)
                goto out;
 
+
+        if (oparms->tcon->use_resilient) {
+               nr_ioctl_req.Timeout = 0; /* use server default (120 seconds) */
+               nr_ioctl_req.Reserved = 0;
+               rc = SMB2_ioctl(xid, oparms->tcon, fid->persistent_fid,
+                       fid->volatile_fid, FSCTL_LMR_REQUEST_RESILIENCY, true,
+                       (char *)&nr_ioctl_req, sizeof(nr_ioctl_req),
+                       NULL, NULL /* no return info */);
+               if (rc == -EOPNOTSUPP) {
+                       cifs_dbg(VFS,
+                            "resiliency not supported by server, disabling\n");
+                       oparms->tcon->use_resilient = false;
+               } else if (rc)
+                       cifs_dbg(FYI, "error %d setting resiliency\n", rc);
+
+               rc = 0;
+       }
+
        if (buf) {
                /* open response does not have IndexNumber field - get it */
                rc = SMB2_get_srv_num(xid, oparms->tcon, fid->persistent_fid,