From: Trond Myklebust Date: Thu, 19 Apr 2007 09:55:44 -0400 RPC: Fix the TCP resend semantics for NFSv4 Fix a regression due to the patch "NFS: disconnect before retrying NFSv4 requests over TCP" The assumption made in xprt_transmit() that the condition "req->rq_bytes_sent == 0 and request is on the receive list" should imply that we're dealing with a retransmission is false. Firstly, it may simply happen that the socket send queue was full at the time the request was initially sent through xprt_transmit(). Secondly, doing this for each request that was retransmitted implies that we disconnect and reconnect for _every_ request that happened to be retransmitted irrespective of whether or not a disconnection has already occurred. Fix is to move this logic into the call_status request timeout handler. Signed-off-by: Trond Myklebust --- net/sunrpc/clnt.c | 4 ++++ net/sunrpc/xprt.c | 10 ---------- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index 6d7221f..396cdbe 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -1046,6 +1046,8 @@ call_status(struct rpc_task *task) rpc_delay(task, 3*HZ); case -ETIMEDOUT: task->tk_action = call_timeout; + if (task->tk_client->cl_discrtry) + xprt_disconnect(task->tk_xprt); break; case -ECONNREFUSED: case -ENOTCONN: @@ -1169,6 +1171,8 @@ call_decode(struct rpc_task *task) out_retry: req->rq_received = req->rq_private_buf.len = 0; task->tk_status = 0; + if (task->tk_client->cl_discrtry) + xprt_disconnect(task->tk_xprt); } /* diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index ee6ffa0..456a145 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c @@ -735,16 +735,6 @@ void xprt_transmit(struct rpc_task *task) xprt_reset_majortimeo(req); /* Turn off autodisconnect */ del_singleshot_timer_sync(&xprt->timer); - } else { - /* If all request bytes have been sent, - * then we must be retransmitting this one */ - if (!req->rq_bytes_sent) { - if (task->tk_client->cl_discrtry) { - xprt_disconnect(xprt); - task->tk_status = -ENOTCONN; - return; - } - } } } else if (!req->rq_bytes_sent) return;