aboutsummaryrefslogtreecommitdiffstats
path: root/net
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 /net
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>
Diffstat (limited to 'net')
-rw-r--r--net/sunrpc/clnt.c6
-rw-r--r--net/sunrpc/xprt.c29
-rw-r--r--net/sunrpc/xprtsock.c2
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 */
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