From: Olga Kornievskaia <kolga@xxxxxxxxxx> For only offline transports, attempt to check connectivity via a NULL call and, if that succeeds, call a provided session trunking detection function. Signed-off-by: Olga Kornievskaia <kolga@xxxxxxxxxx> --- fs/nfs/nfs4proc.c | 2 +- include/linux/sunrpc/clnt.h | 3 ++- net/sunrpc/clnt.c | 47 +++++++++++++++++++++++++++++++++---- net/sunrpc/debugfs.c | 3 ++- net/sunrpc/stats.c | 2 +- 5 files changed, 48 insertions(+), 9 deletions(-) diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 152da2bc5100..00778f351283 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -8533,7 +8533,7 @@ int nfs4_proc_bind_conn_to_session(struct nfs_client *clp, const struct cred *cr .cred = cred, }; return rpc_clnt_iterate_for_each_xprt(clp->cl_rpcclient, NULL, - nfs4_proc_bind_conn_to_session_callback, &data); + nfs4_proc_bind_conn_to_session_callback, &data, false); } /* diff --git a/include/linux/sunrpc/clnt.h b/include/linux/sunrpc/clnt.h index ac1024da86c5..a0160b83d4a4 100644 --- a/include/linux/sunrpc/clnt.h +++ b/include/linux/sunrpc/clnt.h @@ -215,7 +215,7 @@ int rpc_localaddr(struct rpc_clnt *, struct sockaddr *, size_t); int rpc_clnt_iterate_for_each_xprt(struct rpc_clnt *clnt, int (*setup)(struct rpc_clnt *, struct rpc_xprt_iter *), int (*fn)(struct rpc_clnt *, struct rpc_xprt *, void *), - void *data); + void *data, bool do_rewind); int rpc_clnt_test_and_add_xprt(struct rpc_clnt *clnt, struct rpc_xprt_switch *xps, @@ -236,6 +236,7 @@ int rpc_clnt_setup_test_and_add_xprt(struct rpc_clnt *, struct rpc_xprt *, void *); void rpc_clnt_manage_trunked_xprts(struct rpc_clnt *, void *); +void rpc_probe_trunked_xprts(struct rpc_clnt *, void *); const char *rpc_proc_name(const struct rpc_task *task); diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index 6b04b29bf842..348d0772c91d 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -830,7 +830,7 @@ int rpc_clnt_xprt_iter_offline_init(struct rpc_clnt *clnt, int rpc_clnt_iterate_for_each_xprt(struct rpc_clnt *clnt, int (*setup)(struct rpc_clnt *, struct rpc_xprt_iter *), int (*fn)(struct rpc_clnt *, struct rpc_xprt *, void *), - void *data) + void *data, bool do_rewind) { struct rpc_xprt_iter xpi; int ret; @@ -850,6 +850,9 @@ int rpc_clnt_iterate_for_each_xprt(struct rpc_clnt *clnt, xprt_put(xprt); if (ret < 0) break; + + if (do_rewind) + xprt_iter_rewind(&xpi); } xprt_iter_destroy(&xpi); return ret; @@ -3032,6 +3035,40 @@ int rpc_clnt_add_xprt(struct rpc_clnt *clnt, } EXPORT_SYMBOL_GPL(rpc_clnt_add_xprt); +static int rpc_xprt_probe_trunked(struct rpc_clnt *clnt, + struct rpc_xprt *xprt, + void *data) +{ + struct rpc_xprt_switch *xps; + struct rpc_xprt *main_xprt; + int status = 0; + + xprt_get(xprt); + + rcu_read_lock(); + main_xprt = xprt_get(rcu_dereference(clnt->cl_xprt)); + xps = xprt_switch_get(rcu_dereference(clnt->cl_xpi.xpi_xpswitch)); + status = rpc_cmp_addr_port((struct sockaddr *)&xprt->addr, + (struct sockaddr *)&main_xprt->addr); + rcu_read_unlock(); + xprt_put(main_xprt); + if (status || !test_bit(XPRT_OFFLINE, &xprt->state)) + goto out; + + status = rpc_clnt_add_xprt_helper(clnt, xprt, data); +out: + xprt_put(xprt); + xprt_switch_put(xps); + return status; +} + +void rpc_probe_trunked_xprts(struct rpc_clnt *clnt, void *data) +{ + rpc_clnt_iterate_for_each_xprt(clnt, rpc_clnt_xprt_iter_offline_init, + rpc_xprt_probe_trunked, data, true); +} +EXPORT_SYMBOL_GPL(rpc_probe_trunked_xprts); + static int rpc_xprt_offline_destroy(struct rpc_clnt *clnt, struct rpc_xprt *xprt, void *data) @@ -3071,7 +3108,7 @@ static int rpc_xprt_offline_destroy(struct rpc_clnt *clnt, void rpc_clnt_manage_trunked_xprts(struct rpc_clnt *clnt, void *data) { rpc_clnt_iterate_for_each_xprt(clnt, NULL, rpc_xprt_offline_destroy, - data); + data, false); } EXPORT_SYMBOL_GPL(rpc_clnt_manage_trunked_xprts); @@ -3105,7 +3142,7 @@ rpc_set_connect_timeout(struct rpc_clnt *clnt, }; rpc_clnt_iterate_for_each_xprt(clnt, NULL, rpc_xprt_set_connect_timeout, - &timeout); + &timeout, false); } EXPORT_SYMBOL_GPL(rpc_set_connect_timeout); @@ -3228,7 +3265,7 @@ rpc_clnt_swap_activate(struct rpc_clnt *clnt) clnt = clnt->cl_parent; if (atomic_inc_return(&clnt->cl_swapper) == 1) return rpc_clnt_iterate_for_each_xprt(clnt, NULL, - rpc_clnt_swap_activate_callback, NULL); + rpc_clnt_swap_activate_callback, NULL, false); return 0; } EXPORT_SYMBOL_GPL(rpc_clnt_swap_activate); @@ -3247,7 +3284,7 @@ rpc_clnt_swap_deactivate(struct rpc_clnt *clnt) { if (atomic_dec_if_positive(&clnt->cl_swapper) == 0) rpc_clnt_iterate_for_each_xprt(clnt, NULL, - rpc_clnt_swap_deactivate_callback, NULL); + rpc_clnt_swap_deactivate_callback, NULL, false); } EXPORT_SYMBOL_GPL(rpc_clnt_swap_deactivate); #endif /* CONFIG_SUNRPC_SWAP */ diff --git a/net/sunrpc/debugfs.c b/net/sunrpc/debugfs.c index ab60b4d3deb2..9c700bad1ec5 100644 --- a/net/sunrpc/debugfs.c +++ b/net/sunrpc/debugfs.c @@ -160,7 +160,8 @@ rpc_clnt_debugfs_register(struct rpc_clnt *clnt) debugfs_create_file("tasks", S_IFREG | 0400, clnt->cl_debugfs, clnt, &tasks_fops); - rpc_clnt_iterate_for_each_xprt(clnt, NULL, do_xprt_debugfs, &xprtnum); + rpc_clnt_iterate_for_each_xprt(clnt, NULL, do_xprt_debugfs, &xprtnum, + false); } void diff --git a/net/sunrpc/stats.c b/net/sunrpc/stats.c index e50f73a4aca5..60e2d738a8f1 100644 --- a/net/sunrpc/stats.c +++ b/net/sunrpc/stats.c @@ -258,7 +258,7 @@ void rpc_clnt_show_stats(struct seq_file *seq, struct rpc_clnt *clnt) seq_printf(seq, "p/v: %u/%u (%s)\n", clnt->cl_prog, clnt->cl_vers, clnt->cl_program->name); - rpc_clnt_iterate_for_each_xprt(clnt, NULL, do_print_stats, seq); + rpc_clnt_iterate_for_each_xprt(clnt, NULL, do_print_stats, seq, false); seq_printf(seq, "\tper-op statistics\n"); for (op = 0; op < maxproc; op++) { -- 2.27.0