aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTrond Myklebust <Trond.Myklebust@netapp.com>2008-04-17 16:52:57 -0400
committerTrond Myklebust <Trond.Myklebust@netapp.com>2008-04-19 16:55:12 -0400
commit7c1d71cf56feebfb5b98219b9d11dfc3a2feca62 (patch)
tree5a073d987ec79900b2aff217a226c8c78e94b579
parent636ac43318ce6939c1698fb67e714d421314ed71 (diff)
SUNRPC: Don't disconnect more than once if retransmitting NFSv4 requests
NFSv4 requires us to ensure that we break the TCP connection before we're allowed to retransmit a request. However in the case where we're retransmitting several requests that have been sent on the same connection, we need to ensure that we don't interfere with the attempt to reconnect and/or break the connection again once it has been established. We therefore introduce a 'connection' cookie that is bumped every time a connection is broken. This allows requests to track if they need to force a disconnection. Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
-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