Skip to content

Commit 0445f92

Browse files
author
Trond Myklebust
committed
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 <[email protected]> Reported-by: Scott Mayhew <[email protected]> Cc: Chuck Lever <[email protected]> Signed-off-by: Trond Myklebust <[email protected]> Tested-by: Chuck Lever <[email protected]>
1 parent 7566ec3 commit 0445f92

File tree

3 files changed

+7
-5
lines changed

3 files changed

+7
-5
lines changed

net/sunrpc/clnt.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1952,6 +1952,7 @@ call_connect_status(struct rpc_task *task)
19521952
/* retry with existing socket, after a delay */
19531953
rpc_delay(task, 3*HZ);
19541954
/* fall through */
1955+
case -ENOTCONN:
19551956
case -EAGAIN:
19561957
/* Check for timeouts before looping back to call_bind */
19571958
case -ETIMEDOUT:

net/sunrpc/xprt.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -680,7 +680,9 @@ void xprt_force_disconnect(struct rpc_xprt *xprt)
680680
/* Try to schedule an autoclose RPC call */
681681
if (test_and_set_bit(XPRT_LOCKED, &xprt->state) == 0)
682682
queue_work(xprtiod_workqueue, &xprt->task_cleanup);
683-
xprt_wake_pending_tasks(xprt, -EAGAIN);
683+
else if (xprt->snd_task)
684+
rpc_wake_up_queued_task_set_status(&xprt->pending,
685+
xprt->snd_task, -ENOTCONN);
684686
spin_unlock_bh(&xprt->transport_lock);
685687
}
686688
EXPORT_SYMBOL_GPL(xprt_force_disconnect);
@@ -852,6 +854,7 @@ static void xprt_connect_status(struct rpc_task *task)
852854
case -ENETUNREACH:
853855
case -EHOSTUNREACH:
854856
case -EPIPE:
857+
case -ENOTCONN:
855858
case -EAGAIN:
856859
dprintk("RPC: %5u xprt_connect_status: retrying\n", task->tk_pid);
857860
break;

net/sunrpc/xprtsock.c

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1217,6 +1217,8 @@ static void xs_reset_transport(struct sock_xprt *transport)
12171217

12181218
trace_rpc_socket_close(xprt, sock);
12191219
sock_release(sock);
1220+
1221+
xprt_disconnect_done(xprt);
12201222
}
12211223

12221224
/**
@@ -1237,8 +1239,6 @@ static void xs_close(struct rpc_xprt *xprt)
12371239

12381240
xs_reset_transport(transport);
12391241
xprt->reestablish_timeout = 0;
1240-
1241-
xprt_disconnect_done(xprt);
12421242
}
12431243

12441244
static void xs_inject_disconnect(struct rpc_xprt *xprt)
@@ -1489,8 +1489,6 @@ static void xs_tcp_state_change(struct sock *sk)
14891489
&transport->sock_state))
14901490
xprt_clear_connecting(xprt);
14911491
clear_bit(XPRT_CLOSING, &xprt->state);
1492-
if (sk->sk_err)
1493-
xprt_wake_pending_tasks(xprt, -sk->sk_err);
14941492
/* Trigger the socket release */
14951493
xs_tcp_force_close(xprt);
14961494
}

0 commit comments

Comments
 (0)