From: Trond Myklebust Date: Thu, 23 Oct 2008 19:14:55 -0400 SUNRPC: Fix the setting of xprt->reestablish_timeout when reconnecting If the server aborts an established connection, then we should retry connecting immediately. Since xprt->reestablish_timeout is not reset unless we go through a TCP_FIN_WAIT1 state, we may end up waiting unnecessarily. The fix is to reset xprt->reestablish_timeout in TCP_ESTABLISHED, and then rely on the fact that we set it to non-zero values in all other cases when the server closes the connection. Also fix a race between xs_connect() and xs_tcp_state_change(). The value of xprt->reestablish_timeout should be updated before we actually attempt the connection. Signed-off-by: Trond Myklebust --- net/sunrpc/xprtsock.c | 10 ++++++---- 1 files changed, 6 insertions(+), 4 deletions(-) diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index 0a50361..ac2aa52 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -1144,6 +1144,8 @@ static void xs_tcp_state_change(struct sock *sk) struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt); + xprt->reestablish_timeout = 0; + /* Reset TCP record info */ transport->tcp_offset = 0; transport->tcp_reclen = 0; @@ -1158,7 +1160,6 @@ static void xs_tcp_state_change(struct sock *sk) case TCP_FIN_WAIT1: /* The client initiated a shutdown of the socket */ xprt->connect_cookie++; - xprt->reestablish_timeout = 0; set_bit(XPRT_CLOSING, &xprt->state); smp_mb__before_clear_bit(); clear_bit(XPRT_CONNECTED, &xprt->state); @@ -1793,6 +1794,7 @@ static void xs_connect(struct rpc_task *task) { struct rpc_xprt *xprt = task->tk_xprt; struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt); + unsigned long timeout; if (xprt_test_and_set_connecting(xprt)) return; @@ -1801,12 +1803,12 @@ static void xs_connect(struct rpc_task *task) dprintk("RPC: xs_connect delayed xprt %p for %lu " "seconds\n", xprt, xprt->reestablish_timeout / HZ); - queue_delayed_work(rpciod_workqueue, - &transport->connect_worker, - xprt->reestablish_timeout); + timeout = xprt->reestablish_timeout; xprt->reestablish_timeout <<= 1; if (xprt->reestablish_timeout > XS_TCP_MAX_REEST_TO) xprt->reestablish_timeout = XS_TCP_MAX_REEST_TO; + queue_delayed_work(rpciod_workqueue, + &transport->connect_worker, timeout); } else { dprintk("RPC: xs_connect scheduled xprt %p\n", xprt); queue_delayed_work(rpciod_workqueue,