diff options
-rw-r--r-- | include/linux/sunrpc/xprt.h | 8 | ||||
-rw-r--r-- | net/sunrpc/clnt.c | 6 | ||||
-rw-r--r-- | net/sunrpc/xprt.c | 29 | ||||
-rw-r--r-- | net/sunrpc/xprtsock.c | 2 |
4 files changed, 43 insertions, 2 deletions
diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h index 8a0629abb86a..4d80a118d538 100644 --- a/include/linux/sunrpc/xprt.h +++ b/include/linux/sunrpc/xprt.h | |||
@@ -86,6 +86,10 @@ struct rpc_rqst { | |||
86 | unsigned long rq_majortimeo; /* major timeout alarm */ | 86 | unsigned long rq_majortimeo; /* major timeout alarm */ |
87 | unsigned long rq_timeout; /* Current timeout value */ | 87 | unsigned long rq_timeout; /* Current timeout value */ |
88 | unsigned int rq_retries; /* # of retries */ | 88 | unsigned int rq_retries; /* # of retries */ |
89 | unsigned int rq_connect_cookie; | ||
90 | /* A cookie used to track the | ||
91 | state of the transport | ||
92 | connection */ | ||
89 | 93 | ||
90 | /* | 94 | /* |
91 | * Partial send handling | 95 | * Partial send handling |
@@ -152,6 +156,9 @@ struct rpc_xprt { | |||
152 | unsigned long connect_timeout, | 156 | unsigned long connect_timeout, |
153 | bind_timeout, | 157 | bind_timeout, |
154 | reestablish_timeout; | 158 | reestablish_timeout; |
159 | unsigned int connect_cookie; /* A cookie that gets bumped | ||
160 | every time the transport | ||
161 | is reconnected */ | ||
155 | 162 | ||
156 | /* | 163 | /* |
157 | * Disconnection of idle transports | 164 | * Disconnection of idle transports |
@@ -241,6 +248,7 @@ void xprt_complete_rqst(struct rpc_task *task, int copied); | |||
241 | void xprt_release_rqst_cong(struct rpc_task *task); | 248 | void xprt_release_rqst_cong(struct rpc_task *task); |
242 | void xprt_disconnect_done(struct rpc_xprt *xprt); | 249 | void xprt_disconnect_done(struct rpc_xprt *xprt); |
243 | void xprt_force_disconnect(struct rpc_xprt *xprt); | 250 | void xprt_force_disconnect(struct rpc_xprt *xprt); |
251 | void xprt_conditional_disconnect(struct rpc_xprt *xprt, unsigned int cookie); | ||
244 | 252 | ||
245 | /* | 253 | /* |
246 | * Reserved bit positions in xprt->state | 254 | * Reserved bit positions in xprt->state |
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 |