Multipathing: In case of NFSv3, rpc_clnt_test_and_add_xprt() adds
the xprt to xprt switch (i.e. xps) if rpc_call_null_helper() returns
success. But in case of NFSv4.1, it needs to do EXCHANGEID to verify
the path along with check for session trunking.
Add the xprt in nfs4_test_session_trunk() only when
nfs4_detect_session_trunking() returns success. Also release refcount
hold by rpc_clnt_setup_test_and_add_xprt().
Signed-off-by: Santosh kumar pradhan <[email protected]>
Tested-by: Suresh Jayaraman <[email protected]>
Reported-by: Aditya Agnihotri <[email protected]>
---
fs/nfs/internal.h | 6 +++---
fs/nfs/nfs4_fs.h | 3 ++-
fs/nfs/nfs4proc.c | 8 +++++---
include/linux/sunrpc/clnt.h | 4 ++--
net/sunrpc/clnt.c | 3 +++
5 files changed, 15 insertions(+), 9 deletions(-)
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h
index 8357ff69962f..ecd02f9531ba 100644
--- a/fs/nfs/internal.h
+++ b/fs/nfs/internal.h
@@ -569,9 +569,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 *);
+extern void nfs4_test_session_trunk(struct rpc_clnt *clnt,
+ struct rpc_xprt *xprt,
+ void *data);
static inline struct inode *nfs_igrab_and_active(struct inode *inode)
{
diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h
index 1b994b527518..240cbb9bafce 100644
--- a/fs/nfs/nfs4_fs.h
+++ b/fs/nfs/nfs4_fs.h
@@ -65,7 +65,8 @@ struct nfs4_minor_version_ops {
nfs4_stateid *, struct rpc_cred *);
struct nfs_seqid *
(*alloc_seqid)(struct nfs_seqid_counter *, gfp_t);
- int (*session_trunk)(struct rpc_clnt *, struct rpc_xprt *, void *);
+ void (*session_trunk)(struct rpc_clnt *clnt,
+ struct rpc_xprt *xprt, void *data);
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;
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 867457d6dfbe..20668276cb66 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -8088,7 +8088,7 @@ int nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred)
* @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 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;
@@ -8105,15 +8105,17 @@ int nfs4_test_session_trunk(struct rpc_clnt *clnt, struct rpc_xprt *xprt,
/* Test connection for session trunking. Async exchange_id call */
task = nfs4_run_exchange_id(adata->clp, adata->cred, sp4_how, xprt);
if (IS_ERR(task))
- return PTR_ERR(task);
+ return;
status = task->tk_status;
if (status == 0)
status = nfs4_detect_session_trunking(adata->clp,
task->tk_msg.rpc_resp, xprt);
+ if (status == 0)
+ rpc_clnt_xprt_switch_add_xprt(clnt, xprt);
+
rpc_put_task(task);
- return status;
}
EXPORT_SYMBOL_GPL(nfs4_test_session_trunk);
diff --git a/include/linux/sunrpc/clnt.h b/include/linux/sunrpc/clnt.h
index 73d5c4a870fa..2564e42bce0e 100644
--- a/include/linux/sunrpc/clnt.h
+++ b/include/linux/sunrpc/clnt.h
@@ -127,8 +127,8 @@ struct rpc_create_args {
};
struct rpc_add_xprt_test {
- int (*add_xprt_test)(struct rpc_clnt *,
- struct rpc_xprt *,
+ void (*add_xprt_test)(struct rpc_clnt *clnt,
+ struct rpc_xprt *xprt,
void *calldata);
void *data;
};
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c
index c6782aa47525..509886ed9ce5 100644
--- a/net/sunrpc/clnt.c
+++ b/net/sunrpc/clnt.c
@@ -2666,6 +2666,9 @@ int rpc_clnt_setup_test_and_add_xprt(struct rpc_clnt *clnt,
/* rpc_xprt_switch and rpc_xprt are deferrenced by add_xprt_test() */
xtest->add_xprt_test(clnt, xprt, xtest->data);
+ xprt_put(xprt);
+ xprt_switch_put(xps);
+
/* so that rpc_clnt_add_xprt does not call rpc_xprt_switch_add_xprt */
return 1;
out_err:
--
2.20.1