diff options
author | Trond Myklebust <trond.myklebust@hammerspace.com> | 2019-03-04 22:19:31 +0300 |
---|---|---|
committer | Trond Myklebust <trond.myklebust@hammerspace.com> | 2019-03-08 00:45:19 +0300 |
commit | ed7dc973bd91da234d93aff6d033a5206a6c9885 (patch) | |
tree | e5927d8cbd2999455e0331e5b9ba57b36b9d1ad8 | |
parent | 0d1bf3407c4ae887a464d136aaa5e9ef609834f0 (diff) | |
download | linux-ed7dc973bd91da234d93aff6d033a5206a6c9885.tar.xz |
SUNRPC: Prevent thundering herd when the socket is not connected
If the socket is not connected, then we want to initiate a reconnect
rather that trying to transmit requests. If there is a large number
of requests queued and waiting for the lock in call_transmit(),
then it can take a while for one of the to loop back and retake
the lock in call_connect.
Fixes: 89f90fe1ad8b ("SUNRPC: Allow calls to xprt_transmit() to drain...")
Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
-rw-r--r-- | net/sunrpc/clnt.c | 21 |
1 files changed, 17 insertions, 4 deletions
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index 241e8423fd0c..7ab4da342ab5 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -1807,7 +1807,12 @@ call_encode(struct rpc_task *task) xprt_request_enqueue_receive(task); xprt_request_enqueue_transmit(task); out: - task->tk_action = call_bind; + task->tk_action = call_transmit; + /* Check that the connection is OK */ + if (!xprt_bound(task->tk_xprt)) + task->tk_action = call_bind; + else if (!xprt_connected(task->tk_xprt)) + task->tk_action = call_connect; } /* @@ -1999,13 +2004,19 @@ call_transmit(struct rpc_task *task) { dprint_status(task); - task->tk_status = 0; + task->tk_action = call_transmit_status; if (test_bit(RPC_TASK_NEED_XMIT, &task->tk_runstate)) { if (!xprt_prepare_transmit(task)) return; - xprt_transmit(task); + task->tk_status = 0; + if (test_bit(RPC_TASK_NEED_XMIT, &task->tk_runstate)) { + if (!xprt_connected(task->tk_xprt)) { + task->tk_status = -ENOTCONN; + return; + } + xprt_transmit(task); + } } - task->tk_action = call_transmit_status; xprt_end_transmit(task); } @@ -2067,6 +2078,8 @@ call_transmit_status(struct rpc_task *task) case -EADDRINUSE: case -ENOTCONN: case -EPIPE: + task->tk_action = call_bind; + task->tk_status = 0; break; } } |