Commit 04fa2c6b authored by Andy Adamson's avatar Andy Adamson Committed by Anna Schumaker

NFS pnfs data server multipath session trunking

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: default avatarAndy Adamson <andros@netapp.com>
Signed-off-by: default avatarAnna Schumaker <Anna.Schumaker@Netapp.com>
parent ad0849a7
...@@ -572,6 +572,9 @@ extern int nfs40_walk_client_list(struct nfs_client *clp, ...@@ -572,6 +572,9 @@ extern int nfs40_walk_client_list(struct nfs_client *clp,
extern int nfs41_walk_client_list(struct nfs_client *clp, extern int nfs41_walk_client_list(struct nfs_client *clp,
struct nfs_client **result, struct nfs_client **result,
struct rpc_cred *cred); 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) static inline struct inode *nfs_igrab_and_active(struct inode *inode)
{ {
......
...@@ -59,6 +59,7 @@ struct nfs4_minor_version_ops { ...@@ -59,6 +59,7 @@ struct nfs4_minor_version_ops {
struct nfs4_lock_state *); struct nfs4_lock_state *);
struct nfs_seqid * struct nfs_seqid *
(*alloc_seqid)(struct nfs_seqid_counter *, gfp_t); (*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 rpc_call_ops *call_sync_ops;
const struct nfs4_state_recovery_ops *reboot_recovery_ops; const struct nfs4_state_recovery_ops *reboot_recovery_ops;
const struct nfs4_state_recovery_ops *nograce_recovery_ops; const struct nfs4_state_recovery_ops *nograce_recovery_ops;
...@@ -203,6 +204,11 @@ struct nfs4_state_recovery_ops { ...@@ -203,6 +204,11 @@ struct nfs4_state_recovery_ops {
struct rpc_cred *); struct rpc_cred *);
}; };
struct nfs4_add_xprt_data {
struct nfs_client *clp;
struct rpc_cred *cred;
};
struct nfs4_state_maintenance_ops { struct nfs4_state_maintenance_ops {
int (*sched_state_renewal)(struct nfs_client *, struct rpc_cred *, unsigned); int (*sched_state_renewal)(struct nfs_client *, struct rpc_cred *, unsigned);
struct rpc_cred * (*get_state_renewal_cred_locked)(struct nfs_client *); struct rpc_cred * (*get_state_renewal_cred_locked)(struct nfs_client *);
......
...@@ -7353,6 +7353,37 @@ int nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred) ...@@ -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); 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, static int _nfs4_proc_destroy_clientid(struct nfs_client *clp,
struct rpc_cred *cred) struct rpc_cred *cred)
{ {
...@@ -8944,6 +8975,7 @@ static const struct nfs4_minor_version_ops nfs_v4_1_minor_ops = { ...@@ -8944,6 +8975,7 @@ static const struct nfs4_minor_version_ops nfs_v4_1_minor_ops = {
.find_root_sec = nfs41_find_root_sec, .find_root_sec = nfs41_find_root_sec,
.free_lock_state = nfs41_free_lock_state, .free_lock_state = nfs41_free_lock_state,
.alloc_seqid = nfs_alloc_no_seqid, .alloc_seqid = nfs_alloc_no_seqid,
.session_trunk = nfs4_test_session_trunk,
.call_sync_ops = &nfs41_call_sync_ops, .call_sync_ops = &nfs41_call_sync_ops,
.reboot_recovery_ops = &nfs41_reboot_recovery_ops, .reboot_recovery_ops = &nfs41_reboot_recovery_ops,
.nograce_recovery_ops = &nfs41_nograce_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 = { ...@@ -8973,6 +9005,7 @@ static const struct nfs4_minor_version_ops nfs_v4_2_minor_ops = {
.free_lock_state = nfs41_free_lock_state, .free_lock_state = nfs41_free_lock_state,
.call_sync_ops = &nfs41_call_sync_ops, .call_sync_ops = &nfs41_call_sync_ops,
.alloc_seqid = nfs_alloc_no_seqid, .alloc_seqid = nfs_alloc_no_seqid,
.session_trunk = nfs4_test_session_trunk,
.reboot_recovery_ops = &nfs41_reboot_recovery_ops, .reboot_recovery_ops = &nfs41_reboot_recovery_ops,
.nograce_recovery_ops = &nfs41_nograce_recovery_ops, .nograce_recovery_ops = &nfs41_nograce_recovery_ops,
.state_renewal_ops = &nfs41_state_renewal_ops, .state_renewal_ops = &nfs41_state_renewal_ops,
......
...@@ -690,13 +690,50 @@ static int _nfs4_pnfs_v4_ds_connect(struct nfs_server *mds_srv, ...@@ -690,13 +690,50 @@ static int _nfs4_pnfs_v4_ds_connect(struct nfs_server *mds_srv,
dprintk("%s: DS %s: trying address %s\n", dprintk("%s: DS %s: trying address %s\n",
__func__, ds->ds_remotestr, da->da_remotestr); __func__, ds->ds_remotestr, da->da_remotestr);
clp = nfs4_set_ds_client(mds_srv, if (!IS_ERR(clp) && clp->cl_mvops->session_trunk) {
(struct sockaddr *)&da->da_addr, struct xprt_create xprt_args = {
da->da_addrlen, IPPROTO_TCP, .ident = XPRT_TRANSPORT_TCP,
timeo, retrans, minor_version, .net = clp->cl_net,
au_flavor); .dstaddr = (struct sockaddr *)&da->da_addr,
if (!IS_ERR(clp)) .addrlen = da->da_addrlen,
break; .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)) { if (IS_ERR(clp)) {
...@@ -704,18 +741,11 @@ static int _nfs4_pnfs_v4_ds_connect(struct nfs_server *mds_srv, ...@@ -704,18 +741,11 @@ static int _nfs4_pnfs_v4_ds_connect(struct nfs_server *mds_srv,
goto out; goto out;
} }
status = nfs4_init_ds_session(clp, mds_srv->nfs_client->cl_lease_time);
if (status)
goto out_put;
smp_wmb(); smp_wmb();
ds->ds_clp = clp; ds->ds_clp = clp;
dprintk("%s [new] addr: %s\n", __func__, ds->ds_remotestr); dprintk("%s [new] addr: %s\n", __func__, ds->ds_remotestr);
out: out:
return status; return status;
out_put:
nfs_put_client(clp);
goto out;
} }
/* /*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment