NFS test session trunking with exchange id
authorAndy Adamson <andros@netapp.com>
Fri, 9 Sep 2016 13:22:28 +0000 (09:22 -0400)
committerAnna Schumaker <Anna.Schumaker@Netapp.com>
Mon, 19 Sep 2016 17:08:36 +0000 (13:08 -0400)
Use an async exchange id call to test for session trunking

To conform with RFC 5661 section 18.35.4, the Non-Update on
Existing Clientid case, save the exchange id verifier in
cl_confirm and use it for the session trunking exhange id test.

Signed-off-by: Andy Adamson <andros@netapp.com>
Signed-off-by: Anna Schumaker <Anna.Schumaker@Netapp.com>
fs/nfs/nfs4client.c
fs/nfs/nfs4proc.c

index 6914d4b176aef6adb2181a603979dacfbc343ff5..a2c9654d018f3c115ce3b821576aea9cd850faeb 100644 (file)
@@ -637,9 +637,10 @@ out_scope_mismatch:
 }
 
 /**
- * nfs4_detect_session_trunking - Checks for session trunking called
- * after a successful EXCHANGE_ID testing a multi-addr connection to be
- * potentially added as a session trunk
+ * nfs4_detect_session_trunking - Checks for session trunking.
+ *
+ * Called after a successful EXCHANGE_ID on a multi-addr connection.
+ * Upon success, add the transport.
  *
  * @clp:    original mount nfs_client
  * @res:    result structure from an exchange_id using the original mount
@@ -673,6 +674,9 @@ int nfs4_detect_session_trunking(struct nfs_client *clp,
        if (!nfs4_check_server_scope(clp->cl_serverscope, res->server_scope))
                goto out_err;
 
+       /* Session trunking passed, add the xprt */
+       rpc_clnt_xprt_switch_add_xprt(clp->cl_rpcclient, xprt);
+
        pr_info("NFS:  %s: Session trunking succeeded for %s\n",
                clp->cl_hostname,
                xprt->address_strings[RPC_DISPLAY_ADDR]);
index 05b90a756fb561562c838af3cbb7057710cd94df..a70a972eb06f1537fd052703ac379d8ca097e5d8 100644 (file)
@@ -7107,6 +7107,7 @@ static int nfs4_sp4_select_mode(struct nfs_client *clp,
 struct nfs41_exchange_id_data {
        struct nfs41_exchange_id_res res;
        struct nfs41_exchange_id_args args;
+       struct rpc_xprt *xprt;
        int rpc_status;
 };
 
@@ -7121,6 +7122,13 @@ static void nfs4_exchange_id_done(struct rpc_task *task, void *data)
 
        if (status == 0)
                status = nfs4_check_cl_exchange_flags(cdata->res.flags);
+
+       if (cdata->xprt && status == 0) {
+               status = nfs4_detect_session_trunking(clp, &cdata->res,
+                                                     cdata->xprt);
+               goto out;
+       }
+
        if (status  == 0)
                status = nfs4_sp4_select_mode(clp, &cdata->res.state_protect);
 
@@ -7157,8 +7165,13 @@ static void nfs4_exchange_id_done(struct rpc_task *task, void *data)
                        clp->cl_serverscope = cdata->res.server_scope;
                        cdata->res.server_scope = NULL;
                }
+               /* Save the EXCHANGE_ID verifier session trunk tests */
+               memcpy(clp->cl_confirm.data, cdata->args.verifier->data,
+                      sizeof(clp->cl_confirm.data));
        }
+out:
        cdata->rpc_status = status;
+       return;
 }
 
 static void nfs4_exchange_id_release(void *data)
@@ -7167,6 +7180,10 @@ static void nfs4_exchange_id_release(void *data)
                                        (struct nfs41_exchange_id_data *)data;
 
        nfs_put_client(cdata->args.client);
+       if (cdata->xprt) {
+               xprt_put(cdata->xprt);
+               rpc_clnt_xprt_switch_put(cdata->args.client->cl_rpcclient);
+       }
        kfree(cdata->res.impl_id);
        kfree(cdata->res.server_scope);
        kfree(cdata->res.server_owner);
@@ -7184,7 +7201,7 @@ static const struct rpc_call_ops nfs4_exchange_id_call_ops = {
  * Wrapper for EXCHANGE_ID operation.
  */
 static int _nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred,
-       u32 sp4_how)
+                       u32 sp4_how, struct rpc_xprt *xprt)
 {
        nfs4_verifier verifier;
        struct rpc_message msg = {
@@ -7209,7 +7226,8 @@ static int _nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred,
        if (!calldata)
                goto out;
 
-       nfs4_init_boot_verifier(clp, &verifier);
+       if (!xprt)
+               nfs4_init_boot_verifier(clp, &verifier);
 
        status = nfs4_init_uniform_client_string(clp);
        if (status)
@@ -7249,8 +7267,15 @@ static int _nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred,
                status = -EINVAL;
                goto out_impl_id;
        }
-
-       calldata->args.verifier = &verifier;
+       if (xprt) {
+               calldata->xprt = xprt;
+               task_setup_data.rpc_xprt = xprt;
+               task_setup_data.flags =
+                               RPC_TASK_SOFT|RPC_TASK_SOFTCONN|RPC_TASK_ASYNC;
+               calldata->args.verifier = &clp->cl_confirm;
+       } else {
+               calldata->args.verifier = &verifier;
+       }
        calldata->args.client = clp;
 #ifdef CONFIG_NFS_V4_1_MIGRATION
        calldata->args.flags = EXCHGID4_FLAG_SUPP_MOVED_REFER |
@@ -7270,9 +7295,13 @@ static int _nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred,
                goto out_impl_id;
        }
 
-       status = rpc_wait_for_completion_task(task);
-       if (!status)
+       if (!xprt) {
+               status = rpc_wait_for_completion_task(task);
+               if (!status)
+                       status = calldata->rpc_status;
+       } else  /* session trunking test */
                status = calldata->rpc_status;
+
        rpc_put_task(task);
 out:
        if (clp->cl_implid != NULL)
@@ -7315,13 +7344,13 @@ int nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred)
        /* try SP4_MACH_CRED if krb5i/p */
        if (authflavor == RPC_AUTH_GSS_KRB5I ||
            authflavor == RPC_AUTH_GSS_KRB5P) {
-               status = _nfs4_proc_exchange_id(clp, cred, SP4_MACH_CRED);
+               status = _nfs4_proc_exchange_id(clp, cred, SP4_MACH_CRED, NULL);
                if (!status)
                        return 0;
        }
 
        /* try SP4_NONE */
-       return _nfs4_proc_exchange_id(clp, cred, SP4_NONE);
+       return _nfs4_proc_exchange_id(clp, cred, SP4_NONE, NULL);
 }
 
 static int _nfs4_proc_destroy_clientid(struct nfs_client *clp,