diff options
Diffstat (limited to 'net/sunrpc/xprtsock.c')
-rw-r--r-- | net/sunrpc/xprtsock.c | 37 |
1 files changed, 34 insertions, 3 deletions
diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index 8f9295da9b34..a28330410b0c 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -748,6 +748,9 @@ out_release: * * This is used when all requests are complete; ie, no DRC state remains * on the server we want to save. + * + * The caller _must_ be holding XPRT_LOCKED in order to avoid issues with + * xs_reset_transport() zeroing the socket from underneath a writer. */ static void xs_close(struct rpc_xprt *xprt) { @@ -781,6 +784,14 @@ clear_close_wait: xprt_disconnect_done(xprt); } +static void xs_tcp_close(struct rpc_xprt *xprt) +{ + if (test_and_clear_bit(XPRT_CONNECTION_CLOSE, &xprt->state)) + xs_close(xprt); + else + xs_tcp_shutdown(xprt); +} + /** * xs_destroy - prepare to shutdown a transport * @xprt: doomed transport @@ -1676,11 +1687,21 @@ static void xs_tcp_connect_worker4(struct work_struct *work) goto out_clear; case -ECONNREFUSED: case -ECONNRESET: + case -ENETUNREACH: /* retry with existing socket, after a delay */ - break; + goto out_clear; default: /* get rid of existing socket, and retry */ xs_tcp_shutdown(xprt); + printk("%s: connect returned unhandled error %d\n", + __func__, status); + case -EADDRNOTAVAIL: + /* We're probably in TIME_WAIT. Get rid of existing socket, + * and retry + */ + set_bit(XPRT_CONNECTION_CLOSE, &xprt->state); + xprt_force_disconnect(xprt); + status = -EAGAIN; } } out: @@ -1735,11 +1756,21 @@ static void xs_tcp_connect_worker6(struct work_struct *work) goto out_clear; case -ECONNREFUSED: case -ECONNRESET: + case -ENETUNREACH: /* retry with existing socket, after a delay */ - break; + goto out_clear; default: /* get rid of existing socket, and retry */ xs_tcp_shutdown(xprt); + printk("%s: connect returned unhandled error %d\n", + __func__, status); + case -EADDRNOTAVAIL: + /* We're probably in TIME_WAIT. Get rid of existing socket, + * and retry + */ + set_bit(XPRT_CONNECTION_CLOSE, &xprt->state); + xprt_force_disconnect(xprt); + status = -EAGAIN; } } out: @@ -1871,7 +1902,7 @@ static struct rpc_xprt_ops xs_tcp_ops = { .buf_free = rpc_free, .send_request = xs_tcp_send_request, .set_retrans_timeout = xprt_set_retrans_timeout_def, - .close = xs_tcp_shutdown, + .close = xs_tcp_close, .destroy = xs_destroy, .print_stats = xs_tcp_print_stats, }; |