aboutsummaryrefslogtreecommitdiffstats
path: root/net/sunrpc/clnt.c
diff options
context:
space:
mode:
authorJeff Layton <jlayton@poochiereds.net>2015-06-03 16:14:25 -0400
committerTrond Myklebust <trond.myklebust@primarydata.com>2015-06-10 18:26:14 -0400
commit3c87ef6efb40f0e339d705c194b2224f854ec38e (patch)
tree2878ea261637cf6c85ab69b9cbde70a036b1e3a2 /net/sunrpc/clnt.c
parent0d2a970d0ae55086520e1e58e572a7acd519429c (diff)
sunrpc: keep a count of swapfiles associated with the rpc_clnt
Jerome reported seeing a warning pop when working with a swapfile on NFS. The nfs_swap_activate can end up calling sk_set_memalloc while holding the rcu_read_lock and that function can sleep. To fix that, we need to take a reference to the xprt while holding the rcu_read_lock, set the socket up for swapping and then drop that reference. But, xprt_put is not exported and having NFS deal with the underlying xprt is a bit of layering violation anyway. Fix this by adding a set of activate/deactivate functions that take a rpc_clnt pointer instead of an rpc_xprt, and have nfs_swap_activate and nfs_swap_deactivate call those. Also, add a per-rpc_clnt atomic counter to keep track of the number of active swapfiles associated with it. When the counter does a 0->1 transition, we enable swapping on the xprt, when we do a 1->0 transition we disable swapping on it. This also allows us to be a bit more selective with the RPC_TASK_SWAPPER flag. If non-swapper and swapper clnts are sharing a xprt, then we only need to flag the tasks from the swapper clnt with that flag. Acked-by: Mel Gorman <mgorman@suse.de> Reported-by: Jerome Marchand <jmarchan@redhat.com> Signed-off-by: Jeff Layton <jeff.layton@primarydata.com> Reviewed-by: Chuck Lever <chuck.lever@oracle.com> Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
Diffstat (limited to 'net/sunrpc/clnt.c')
-rw-r--r--net/sunrpc/clnt.c67
1 files changed, 58 insertions, 9 deletions
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c
index f6717170480e..0ba65156a62b 100644
--- a/net/sunrpc/clnt.c
+++ b/net/sunrpc/clnt.c
@@ -891,15 +891,8 @@ void rpc_task_set_client(struct rpc_task *task, struct rpc_clnt *clnt)
891 task->tk_flags |= RPC_TASK_SOFT; 891 task->tk_flags |= RPC_TASK_SOFT;
892 if (clnt->cl_noretranstimeo) 892 if (clnt->cl_noretranstimeo)
893 task->tk_flags |= RPC_TASK_NO_RETRANS_TIMEOUT; 893 task->tk_flags |= RPC_TASK_NO_RETRANS_TIMEOUT;
894 if (sk_memalloc_socks()) { 894 if (atomic_read(&clnt->cl_swapper))
895 struct rpc_xprt *xprt; 895 task->tk_flags |= RPC_TASK_SWAPPER;
896
897 rcu_read_lock();
898 xprt = rcu_dereference(clnt->cl_xprt);
899 if (xprt->swapper)
900 task->tk_flags |= RPC_TASK_SWAPPER;
901 rcu_read_unlock();
902 }
903 /* Add to the client's list of all tasks */ 896 /* Add to the client's list of all tasks */
904 spin_lock(&clnt->cl_lock); 897 spin_lock(&clnt->cl_lock);
905 list_add_tail(&task->tk_task, &clnt->cl_tasks); 898 list_add_tail(&task->tk_task, &clnt->cl_tasks);
@@ -2479,3 +2472,59 @@ void rpc_show_tasks(struct net *net)
2479 spin_unlock(&sn->rpc_client_lock); 2472 spin_unlock(&sn->rpc_client_lock);
2480} 2473}
2481#endif 2474#endif
2475
2476#if IS_ENABLED(CONFIG_SUNRPC_SWAP)
2477int
2478rpc_clnt_swap_activate(struct rpc_clnt *clnt)
2479{
2480 int ret = 0;
2481 struct rpc_xprt *xprt;
2482
2483 if (atomic_inc_return(&clnt->cl_swapper) == 1) {
2484retry:
2485 rcu_read_lock();
2486 xprt = xprt_get(rcu_dereference(clnt->cl_xprt));
2487 rcu_read_unlock();
2488 if (!xprt) {
2489 /*
2490 * If we didn't get a reference, then we likely are
2491 * racing with a migration event. Wait for a grace
2492 * period and try again.
2493 */
2494 synchronize_rcu();
2495 goto retry;
2496 }
2497
2498 ret = xs_swapper(xprt, 1);
2499 xprt_put(xprt);
2500 }
2501 return ret;
2502}
2503EXPORT_SYMBOL_GPL(rpc_clnt_swap_activate);
2504
2505void
2506rpc_clnt_swap_deactivate(struct rpc_clnt *clnt)
2507{
2508 struct rpc_xprt *xprt;
2509
2510 if (atomic_dec_if_positive(&clnt->cl_swapper) == 0) {
2511retry:
2512 rcu_read_lock();
2513 xprt = xprt_get(rcu_dereference(clnt->cl_xprt));
2514 rcu_read_unlock();
2515 if (!xprt) {
2516 /*
2517 * If we didn't get a reference, then we likely are
2518 * racing with a migration event. Wait for a grace
2519 * period and try again.
2520 */
2521 synchronize_rcu();
2522 goto retry;
2523 }
2524
2525 xs_swapper(xprt, 0);
2526 xprt_put(xprt);
2527 }
2528}
2529EXPORT_SYMBOL_GPL(rpc_clnt_swap_deactivate);
2530#endif /* CONFIG_SUNRPC_SWAP */