]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - fs/cifs/connect.c
Merge remote-tracking branch 'security/next'
[karo-tx-linux.git] / fs / cifs / connect.c
index 3f2228570d441840b7e6d11c10a3b814a2b60962..ecb0803bdb0e50479f50b0e874a4e87cb064e2d0 100644 (file)
@@ -87,6 +87,8 @@ enum {
        Opt_sign, Opt_seal, Opt_noac,
        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,
@@ -169,6 +171,10 @@ 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_resilient, "resilienthandles"},
+       { Opt_noresilient, "noresilienthandles"},
 
        { Opt_backupuid, "backupuid=%s" },
        { Opt_backupgid, "backupgid=%s" },
@@ -1497,6 +1503,33 @@ 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) || (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; /* already the default */
+                       break;
 
                /* Numeric Values */
                case Opt_backupuid:
@@ -2655,6 +2688,42 @@ 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;
+#ifdef CONFIG_CIFS_SMB2
+               } 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;
+#endif /* CONFIG_CIFS_SMB2 */
+               }
+#ifdef CONFIG_CIFS_SMB2
+       } 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;
+#endif /* CONFIG_CIFS_SMB2 */
+       } 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;
+       }
+
        /*
         * 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
@@ -3503,6 +3572,15 @@ try_mount_again:
                goto mount_fail_check;
        }
 
+#ifdef CONFIG_CIFS_SMB2
+       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;
+       }
+#endif /* CONFIG_CIFS_SMB2*/
+
        /* search for existing tcon to this server share */
        tcon = cifs_get_tcon(ses, volume_info);
        if (IS_ERR(tcon)) {