aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/sunrpc/xprt.h8
-rw-r--r--net/sunrpc/clnt.c6
-rw-r--r--net/sunrpc/xprt.c29
-rw-r--r--net/sunrpc/xprtsock.c2
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);
241void xprt_release_rqst_cong(struct rpc_task *task); 248void xprt_release_rqst_cong(struct rpc_task *task);
242void xprt_disconnect_done(struct rpc_xprt *xprt); 249void xprt_disconnect_done(struct rpc_xprt *xprt);
243void xprt_force_disconnect(struct rpc_xprt *xprt); 250void xprt_force_disconnect(struct rpc_xprt *xprt);
251void 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 */
620void 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);
633out:
634 spin_unlock_bh(&xprt->transport_lock);
635}
636
609static void 637static void
610xprt_init_autodisconnect(unsigned long data) 638xprt_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