diff options
Diffstat (limited to 'net/sunrpc')
-rw-r--r-- | net/sunrpc/clnt.c | 6 | ||||
-rw-r--r-- | net/sunrpc/xprt.c | 29 | ||||
-rw-r--r-- | net/sunrpc/xprtsock.c | 2 |
3 files changed, 35 insertions, 2 deletions
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index 3ae560464513..8773b4342c92 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c | |||
@@ -1120,7 +1120,8 @@ call_status(struct rpc_task *task) | |||
1120 | case -ETIMEDOUT: | 1120 | case -ETIMEDOUT: |
1121 | task->tk_action = call_timeout; | 1121 | task->tk_action = call_timeout; |
1122 | if (task->tk_client->cl_discrtry) | 1122 | if (task->tk_client->cl_discrtry) |
1123 | xprt_force_disconnect(task->tk_xprt); | 1123 | xprt_conditional_disconnect(task->tk_xprt, |
1124 | req->rq_connect_cookie); | ||
1124 | break; | 1125 | break; |
1125 | case -ECONNREFUSED: | 1126 | case -ECONNREFUSED: |
1126 | case -ENOTCONN: | 1127 | case -ENOTCONN: |
@@ -1245,7 +1246,8 @@ out_retry: | |||
1245 | if (task->tk_rqstp == req) { | 1246 | if (task->tk_rqstp == req) { |
1246 | req->rq_received = req->rq_rcv_buf.len = 0; | 1247 | req->rq_received = req->rq_rcv_buf.len = 0; |
1247 | if (task->tk_client->cl_discrtry) | 1248 | if (task->tk_client->cl_discrtry) |
1248 | xprt_force_disconnect(task->tk_xprt); | 1249 | xprt_conditional_disconnect(task->tk_xprt, |
1250 | req->rq_connect_cookie); | ||
1249 | } | 1251 | } |
1250 | } | 1252 | } |
1251 | 1253 | ||
diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index a0646a3b4a39..75d748eee0eb 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c | |||
@@ -606,6 +606,34 @@ void xprt_force_disconnect(struct rpc_xprt *xprt) | |||
606 | spin_unlock_bh(&xprt->transport_lock); | 606 | spin_unlock_bh(&xprt->transport_lock); |
607 | } | 607 | } |
608 | 608 | ||
609 | /** | ||
610 | * xprt_conditional_disconnect - force a transport to disconnect | ||
611 | * @xprt: transport to disconnect | ||
612 | * @cookie: 'connection cookie' | ||
613 | * | ||
614 | * This attempts to break the connection if and only if 'cookie' matches | ||
615 | * the current transport 'connection cookie'. It ensures that we don't | ||
616 | * try to break the connection more than once when we need to retransmit | ||
617 | * a batch of RPC requests. | ||
618 | * | ||
619 | */ | ||
620 | void xprt_conditional_disconnect(struct rpc_xprt *xprt, unsigned int cookie) | ||
621 | { | ||
622 | /* Don't race with the test_bit() in xprt_clear_locked() */ | ||
623 | spin_lock_bh(&xprt->transport_lock); | ||
624 | if (cookie != xprt->connect_cookie) | ||
625 | goto out; | ||
626 | if (test_bit(XPRT_CLOSING, &xprt->state) || !xprt_connected(xprt)) | ||
627 | goto out; | ||
628 | set_bit(XPRT_CLOSE_WAIT, &xprt->state); | ||
629 | /* Try to schedule an autoclose RPC call */ | ||
630 | if (test_and_set_bit(XPRT_LOCKED, &xprt->state) == 0) | ||
631 | queue_work(rpciod_workqueue, &xprt->task_cleanup); | ||
632 | xprt_wake_pending_tasks(xprt, -ENOTCONN); | ||
633 | out: | ||
634 | spin_unlock_bh(&xprt->transport_lock); | ||
635 | } | ||
636 | |||
609 | static void | 637 | static void |
610 | xprt_init_autodisconnect(unsigned long data) | 638 | xprt_init_autodisconnect(unsigned long data) |
611 | { | 639 | { |
@@ -849,6 +877,7 @@ void xprt_transmit(struct rpc_task *task) | |||
849 | } else if (!req->rq_bytes_sent) | 877 | } else if (!req->rq_bytes_sent) |
850 | return; | 878 | return; |
851 | 879 | ||
880 | req->rq_connect_cookie = xprt->connect_cookie; | ||
852 | status = xprt->ops->send_request(task); | 881 | status = xprt->ops->send_request(task); |
853 | if (status == 0) { | 882 | if (status == 0) { |
854 | dprintk("RPC: %5u xmit complete\n", task->tk_pid); | 883 | dprintk("RPC: %5u xmit complete\n", task->tk_pid); |
diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index 4a567a93e6ad..63d79e347c00 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c | |||
@@ -1142,6 +1142,7 @@ static void xs_tcp_state_change(struct sock *sk) | |||
1142 | break; | 1142 | break; |
1143 | case TCP_FIN_WAIT1: | 1143 | case TCP_FIN_WAIT1: |
1144 | /* The client initiated a shutdown of the socket */ | 1144 | /* The client initiated a shutdown of the socket */ |
1145 | xprt->connect_cookie++; | ||
1145 | xprt->reestablish_timeout = 0; | 1146 | xprt->reestablish_timeout = 0; |
1146 | set_bit(XPRT_CLOSING, &xprt->state); | 1147 | set_bit(XPRT_CLOSING, &xprt->state); |
1147 | smp_mb__before_clear_bit(); | 1148 | smp_mb__before_clear_bit(); |
@@ -1154,6 +1155,7 @@ static void xs_tcp_state_change(struct sock *sk) | |||
1154 | set_bit(XPRT_CLOSING, &xprt->state); | 1155 | set_bit(XPRT_CLOSING, &xprt->state); |
1155 | xprt_force_disconnect(xprt); | 1156 | xprt_force_disconnect(xprt); |
1156 | case TCP_SYN_SENT: | 1157 | case TCP_SYN_SENT: |
1158 | xprt->connect_cookie++; | ||
1157 | case TCP_CLOSING: | 1159 | case TCP_CLOSING: |
1158 | /* | 1160 | /* |
1159 | * If the server closed down the connection, make sure that | 1161 | * If the server closed down the connection, make sure that |