These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / fs / cifs / connect.c
index 8383d5e..3c194ff 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" },
@@ -280,6 +286,11 @@ static const match_table_t cifs_smb_version_tokens = {
        { Smb_21, SMB21_VERSION_STRING },
        { Smb_30, SMB30_VERSION_STRING },
        { Smb_302, SMB302_VERSION_STRING },
+#ifdef CONFIG_CIFS_SMB311
+       { Smb_311, SMB311_VERSION_STRING },
+       { Smb_311, ALT_SMB311_VERSION_STRING },
+#endif /* SMB311 */
+       { Smb_version_err, NULL }
 };
 
 static int ip_connect(struct TCP_Server_Info *server);
@@ -357,7 +368,6 @@ cifs_reconnect(struct TCP_Server_Info *server)
        server->session_key.response = NULL;
        server->session_key.len = 0;
        server->lstrp = jiffies;
-       mutex_unlock(&server->srv_mutex);
 
        /* mark submitted MIDs for retry and issue callback */
        INIT_LIST_HEAD(&retry_list);
@@ -370,6 +380,7 @@ cifs_reconnect(struct TCP_Server_Info *server)
                list_move(&mid_entry->qhead, &retry_list);
        }
        spin_unlock(&GlobalMid_Lock);
+       mutex_unlock(&server->srv_mutex);
 
        cifs_dbg(FYI, "%s: issuing mid callbacks\n", __func__);
        list_for_each_safe(tmp, tmp2, &retry_list) {
@@ -1133,6 +1144,12 @@ cifs_parse_smb_version(char *value, struct smb_vol *vol)
                vol->ops = &smb30_operations; /* currently identical with 3.0 */
                vol->vals = &smb302_values;
                break;
+#ifdef CONFIG_CIFS_SMB311
+       case Smb_311:
+               vol->ops = &smb311_operations;
+               vol->vals = &smb311_values;
+               break;
+#endif /* SMB311 */
 #endif
        default:
                cifs_dbg(VFS, "Unknown vers= option specified: %s\n", value);
@@ -1486,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:
@@ -2314,13 +2358,14 @@ static int
 cifs_set_cifscreds(struct smb_vol *vol, struct cifs_ses *ses)
 {
        int rc = 0;
-       char *desc, *delim, *payload;
+       const char *delim, *payload;
+       char *desc;
        ssize_t len;
        struct key *key;
        struct TCP_Server_Info *server = ses->server;
        struct sockaddr_in *sa;
        struct sockaddr_in6 *sa6;
-       struct user_key_payload *upayload;
+       const struct user_key_payload *upayload;
 
        desc = kmalloc(CIFSCREDS_DESC_SIZE, GFP_KERNEL);
        if (!desc)
@@ -2363,14 +2408,14 @@ cifs_set_cifscreds(struct smb_vol *vol, struct cifs_ses *ses)
        }
 
        down_read(&key->sem);
-       upayload = key->payload.data;
+       upayload = user_key_payload(key);
        if (IS_ERR_OR_NULL(upayload)) {
                rc = upayload ? PTR_ERR(upayload) : -EINVAL;
                goto out_key_put;
        }
 
        /* find first : in payload */
-       payload = (char *)upayload->data;
+       payload = upayload->data;
        delim = strnchr(payload, upayload->datalen, ':');
        cifs_dbg(FYI, "payload=%s\n", payload);
        if (!delim) {
@@ -2643,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
@@ -3461,6 +3542,8 @@ try_mount_again:
                else if (ses)
                        cifs_put_smb_ses(ses);
 
+               cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_POSIX_PATHS;
+
                free_xid(xid);
        }
 #endif
@@ -3489,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)) {