diff options
author | Trond Myklebust <trond.myklebust@hammerspace.com> | 2018-12-17 13:34:59 -0500 |
---|---|---|
committer | Trond Myklebust <trond.myklebust@hammerspace.com> | 2018-12-18 11:03:57 -0500 |
commit | 0445f92c5d537c173a54446b80d2052145de5148 (patch) | |
tree | 23b94aa7599440d464970fe1cd85689446b84580 /net/sunrpc/xprt.c | |
parent | 7566ec393f4161572ba6f11ad5171fd5d59b0fbd (diff) | |
download | linux-0445f92c5d537c173a54446b80d2052145de5148.tar.gz linux-0445f92c5d537c173a54446b80d2052145de5148.tar.bz2 linux-0445f92c5d537c173a54446b80d2052145de5148.zip |
SUNRPC: Fix disconnection races
When the socket is closed, we need to call xprt_disconnect_done() in order
to clean up the XPRT_WRITE_SPACE flag, and wake up the sleeping tasks.
However, we also want to ensure that we don't wake them up before the socket
is closed, since that would cause thundering herd issues with everyone
piling up to retransmit before the TCP shutdown dance has completed.
Only the task that holds XPRT_LOCKED needs to wake up early in order to
allow the close to complete.
Reported-by: Dave Wysochanski <dwysocha@redhat.com>
Reported-by: Scott Mayhew <smayhew@redhat.com>
Cc: Chuck Lever <chuck.lever@oracle.com>
Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
Tested-by: Chuck Lever <chuck.lever@oracle.com>
Diffstat (limited to 'net/sunrpc/xprt.c')
-rw-r--r-- | net/sunrpc/xprt.c | 5 |
1 files changed, 4 insertions, 1 deletions
diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index ce927002862a..3fb001dff670 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c @@ -680,7 +680,9 @@ void xprt_force_disconnect(struct rpc_xprt *xprt) /* Try to schedule an autoclose RPC call */ if (test_and_set_bit(XPRT_LOCKED, &xprt->state) == 0) queue_work(xprtiod_workqueue, &xprt->task_cleanup); - xprt_wake_pending_tasks(xprt, -EAGAIN); + else if (xprt->snd_task) + rpc_wake_up_queued_task_set_status(&xprt->pending, + xprt->snd_task, -ENOTCONN); spin_unlock_bh(&xprt->transport_lock); } EXPORT_SYMBOL_GPL(xprt_force_disconnect); @@ -852,6 +854,7 @@ static void xprt_connect_status(struct rpc_task *task) case -ENETUNREACH: case -EHOSTUNREACH: case -EPIPE: + case -ENOTCONN: case -EAGAIN: dprintk("RPC: %5u xprt_connect_status: retrying\n", task->tk_pid); break; |