NFS pnfs data server multipath session trunking
authorAndy Adamson <andros@netapp.com>
Fri, 9 Sep 2016 13:22:29 +0000 (09:22 -0400)
committerAnna Schumaker <Anna.Schumaker@Netapp.com>
Mon, 19 Sep 2016 17:08:37 +0000 (13:08 -0400)
Try all multipath addresses for a data server. The first address that
successfully connects and creates a session is the DS mount address.
All subsequent addresses are tested for session trunking and
added as aliases.

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

index 74935a19e4bfc678767dcc7fde3fcef16d7872e2..fd82bed39ed4b6a9334d1b289f8df9fb8a75e86a 100644 (file)
@@ -572,6 +572,9 @@ extern int nfs40_walk_client_list(struct nfs_client *clp,
 extern int nfs41_walk_client_list(struct nfs_client *clp,
                                struct nfs_client **result,
                                struct rpc_cred *cred);
+extern int nfs4_test_session_trunk(struct rpc_clnt *,
+                               struct rpc_xprt *,
+                               void *);
 
 static inline struct inode *nfs_igrab_and_active(struct inode *inode)
 {
index cf744aa0fa74f76f19eff134159ac07b23472dd3..804113421337f41e1f347aac1f0174eb2bc4ab8e 100644 (file)
@@ -59,6 +59,7 @@ struct nfs4_minor_version_ops {
                        struct nfs4_lock_state *);
        struct nfs_seqid *
                (*alloc_seqid)(struct nfs_seqid_counter *, gfp_t);
+       int     (*session_trunk)(struct rpc_clnt *, struct rpc_xprt *, void *);
        const struct rpc_call_ops *call_sync_ops;
        const struct nfs4_state_recovery_ops *reboot_recovery_ops;
        const struct nfs4_state_recovery_ops *nograce_recovery_ops;
@@ -203,6 +204,11 @@ struct nfs4_state_recovery_ops {
                struct rpc_cred *);
 };
 
+struct nfs4_add_xprt_data {
+       struct nfs_client       *clp;
+       struct rpc_cred         *cred;
+};
+
 struct nfs4_state_maintenance_ops {
        int (*sched_state_renewal)(struct nfs_client *, struct rpc_cred *, unsigned);
        struct rpc_cred * (*get_state_renewal_cred_locked)(struct nfs_client *);
index a70a972eb06f1537fd052703ac379d8ca097e5d8..cfdf45a14cc334373905549c26e27549c046d194 100644 (file)
@@ -7353,6 +7353,37 @@ int nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred)
        return _nfs4_proc_exchange_id(clp, cred, SP4_NONE, NULL);
 }
 
+/**
+ * nfs4_test_session_trunk
+ *
+ * This is an add_xprt_test() test function called from
+ * rpc_clnt_setup_test_and_add_xprt.
+ *
+ * The rpc_xprt_switch is referrenced by rpc_clnt_setup_test_and_add_xprt
+ * and is dereferrenced in nfs4_exchange_id_release
+ *
+ * Upon success, add the new transport to the rpc_clnt
+ *
+ * @clnt: struct rpc_clnt to get new transport
+ * @xprt: the rpc_xprt to test
+ * @data: call data for _nfs4_proc_exchange_id.
+ */
+int nfs4_test_session_trunk(struct rpc_clnt *clnt, struct rpc_xprt *xprt,
+                           void *data)
+{
+       struct nfs4_add_xprt_data *adata = (struct nfs4_add_xprt_data *)data;
+       u32 sp4_how;
+
+       dprintk("--> %s try %s\n", __func__,
+               xprt->address_strings[RPC_DISPLAY_ADDR]);
+
+       sp4_how = (adata->clp->cl_sp4_flags == 0 ? SP4_NONE : SP4_MACH_CRED);
+
+       /* Test connection for session trunking. Async exchange_id call */
+       return  _nfs4_proc_exchange_id(adata->clp, adata->cred, sp4_how, xprt);
+}
+EXPORT_SYMBOL_GPL(nfs4_test_session_trunk);
+
 static int _nfs4_proc_destroy_clientid(struct nfs_client *clp,
                struct rpc_cred *cred)
 {
@@ -8944,6 +8975,7 @@ static const struct nfs4_minor_version_ops nfs_v4_1_minor_ops = {
        .find_root_sec = nfs41_find_root_sec,
        .free_lock_state = nfs41_free_lock_state,
        .alloc_seqid = nfs_alloc_no_seqid,
+       .session_trunk = nfs4_test_session_trunk,
        .call_sync_ops = &nfs41_call_sync_ops,
        .reboot_recovery_ops = &nfs41_reboot_recovery_ops,
        .nograce_recovery_ops = &nfs41_nograce_recovery_ops,
@@ -8973,6 +9005,7 @@ static const struct nfs4_minor_version_ops nfs_v4_2_minor_ops = {
        .free_lock_state = nfs41_free_lock_state,
        .call_sync_ops = &nfs41_call_sync_ops,
        .alloc_seqid = nfs_alloc_no_seqid,
+       .session_trunk = nfs4_test_session_trunk,
        .reboot_recovery_ops = &nfs41_reboot_recovery_ops,
        .nograce_recovery_ops = &nfs41_nograce_recovery_ops,
        .state_renewal_ops = &nfs41_state_renewal_ops,
index f3468b57a32a32c71d7aa55fbf835ae064c16bcc..53b4705abcc76144fc7fb9f1f08a23add0f4df86 100644 (file)
@@ -690,13 +690,50 @@ static int _nfs4_pnfs_v4_ds_connect(struct nfs_server *mds_srv,
                dprintk("%s: DS %s: trying address %s\n",
                        __func__, ds->ds_remotestr, da->da_remotestr);
 
-               clp = nfs4_set_ds_client(mds_srv,
-                                       (struct sockaddr *)&da->da_addr,
-                                       da->da_addrlen, IPPROTO_TCP,
-                                       timeo, retrans, minor_version,
-                                       au_flavor);
-               if (!IS_ERR(clp))
-                       break;
+               if (!IS_ERR(clp) && clp->cl_mvops->session_trunk) {
+                       struct xprt_create xprt_args = {
+                               .ident = XPRT_TRANSPORT_TCP,
+                               .net = clp->cl_net,
+                               .dstaddr = (struct sockaddr *)&da->da_addr,
+                               .addrlen = da->da_addrlen,
+                               .servername = clp->cl_hostname,
+                       };
+                       struct nfs4_add_xprt_data xprtdata = {
+                               .clp = clp,
+                               .cred = nfs4_get_clid_cred(clp),
+                       };
+                       struct rpc_add_xprt_test rpcdata = {
+                               .add_xprt_test = clp->cl_mvops->session_trunk,
+                               .data = &xprtdata,
+                       };
+
+                       /**
+                       * Test this address for session trunking and
+                       * add as an alias
+                       */
+                       rpc_clnt_add_xprt(clp->cl_rpcclient, &xprt_args,
+                                         rpc_clnt_setup_test_and_add_xprt,
+                                         &rpcdata);
+                       if (xprtdata.cred)
+                               put_rpccred(xprtdata.cred);
+               } else {
+                       clp = nfs4_set_ds_client(mds_srv,
+                                               (struct sockaddr *)&da->da_addr,
+                                               da->da_addrlen, IPPROTO_TCP,
+                                               timeo, retrans, minor_version,
+                                               au_flavor);
+                       if (IS_ERR(clp))
+                               continue;
+
+                       status = nfs4_init_ds_session(clp,
+                                       mds_srv->nfs_client->cl_lease_time);
+                       if (status) {
+                               nfs_put_client(clp);
+                               clp = ERR_PTR(-EIO);
+                               continue;
+                       }
+
+               }
        }
 
        if (IS_ERR(clp)) {
@@ -704,18 +741,11 @@ static int _nfs4_pnfs_v4_ds_connect(struct nfs_server *mds_srv,
                goto out;
        }
 
-       status = nfs4_init_ds_session(clp, mds_srv->nfs_client->cl_lease_time);
-       if (status)
-               goto out_put;
-
        smp_wmb();
        ds->ds_clp = clp;
        dprintk("%s [new] addr: %s\n", __func__, ds->ds_remotestr);
 out:
        return status;
-out_put:
-       nfs_put_client(clp);
-       goto out;
 }
 
 /*