diff options
author | Trond Myklebust <trond.myklebust@hammerspace.com> | 2019-03-04 22:19:31 +0300 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2019-03-23 22:11:41 +0300 |
commit | aed54941cf9e67876456513b490fdf72e0367aed (patch) | |
tree | 8fe2633431ed6a857defe0b2b2cdec1cd87837a3 | |
parent | 1b2f5d715bbc21c548c834647084c4ad7952696f (diff) | |
download | linux-aed54941cf9e67876456513b490fdf72e0367aed.tar.xz |
SUNRPC: Prevent thundering herd when the socket is not connected
commit ed7dc973bd91da234d93aff6d033a5206a6c9885 upstream.
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>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-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 d7ec6132c046..47d664ce64ba 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -1786,7 +1786,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; } /* @@ -1978,13 +1983,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); } @@ -2046,6 +2057,8 @@ call_transmit_status(struct rpc_task *task) case -EADDRINUSE: case -ENOTCONN: case -EPIPE: + task->tk_action = call_bind; + task->tk_status = 0; break; } } |