summary refs log tree commit diff
path: root/net
diff options
context:
space:
mode:
authorTrond Myklebust <trond.myklebust@fys.uio.no>2005-11-09 21:45:24 -0500
committerLinus Torvalds <torvalds@g5.osdl.org>2005-11-09 19:31:33 -0800
commit940e3318c36394939d805e797d7be39ddaaa7911 (patch)
treeaa0bab66b2bde96f01150504909d3ef5de41a7d1 /net
parente4d76e1c0b15590f2ad9bba89426c2520cd22ca6 (diff)
downloadlinux-940e3318c36394939d805e797d7be39ddaaa7911.tar.gz
[PATCH] SUNRPC: don't reencode when looping in call transmit.
If the call to xprt_transmit() fails due to socket buffer space
exhaustion, we do not need to re-encode the RPC message when we
loop back through call_transmit.

Re-encoding can actually end up triggering the WARN_ON() in
call_decode() if we re-encode something like a read() request and
auth->au_rslack has changed.
It can also cause us to increment the RPCSEC_GSS sequence number
beyond the limits of the allowed window.

Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'net')
-rw-r--r--net/sunrpc/clnt.c32
1 files changed, 29 insertions, 3 deletions
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c
index 702ede309b06..61c3abeaccae 100644
--- a/net/sunrpc/clnt.c
+++ b/net/sunrpc/clnt.c
@@ -55,6 +55,7 @@ static void	call_bind(struct rpc_task *task);
 static void	call_bind_status(struct rpc_task *task);
 static void	call_transmit(struct rpc_task *task);
 static void	call_status(struct rpc_task *task);
+static void	call_transmit_status(struct rpc_task *task);
 static void	call_refresh(struct rpc_task *task);
 static void	call_refreshresult(struct rpc_task *task);
 static void	call_timeout(struct rpc_task *task);
@@ -672,6 +673,18 @@ call_allocate(struct rpc_task *task)
 	rpc_exit(task, -ERESTARTSYS);
 }
 
+static inline int
+rpc_task_need_encode(struct rpc_task *task)
+{
+	return task->tk_rqstp->rq_snd_buf.len == 0;
+}
+
+static inline void
+rpc_task_force_reencode(struct rpc_task *task)
+{
+	task->tk_rqstp->rq_snd_buf.len = 0;
+}
+
 /*
  * 3.	Encode arguments of an RPC call
  */
@@ -867,12 +880,14 @@ call_transmit(struct rpc_task *task)
 	if (task->tk_status != 0)
 		return;
 	/* Encode here so that rpcsec_gss can use correct sequence number. */
-	if (task->tk_rqstp->rq_bytes_sent == 0) {
+	if (rpc_task_need_encode(task)) {
+		task->tk_rqstp->rq_bytes_sent = 0;
 		call_encode(task);
 		/* Did the encode result in an error condition? */
 		if (task->tk_status != 0)
 			goto out_nosend;
 	}
+	task->tk_action = call_transmit_status;
 	xprt_transmit(task);
 	if (task->tk_status < 0)
 		return;
@@ -884,6 +899,7 @@ call_transmit(struct rpc_task *task)
 out_nosend:
 	/* release socket write lock before attempting to handle error */
 	xprt_abort_transmit(task);
+	rpc_task_force_reencode(task);
 }
 
 /*
@@ -915,7 +931,6 @@ call_status(struct rpc_task *task)
 		break;
 	case -ECONNREFUSED:
 	case -ENOTCONN:
-		req->rq_bytes_sent = 0;
 		if (clnt->cl_autobind)
 			clnt->cl_port = 0;
 		task->tk_action = call_bind;
@@ -937,7 +952,18 @@ call_status(struct rpc_task *task)
 }
 
 /*
- * 6a.	Handle RPC timeout
+ * 6a.	Handle transmission errors.
+ */
+static void
+call_transmit_status(struct rpc_task *task)
+{
+	if (task->tk_status != -EAGAIN)
+		rpc_task_force_reencode(task);
+	call_status(task);
+}
+
+/*
+ * 6b.	Handle RPC timeout
  * 	We do not release the request slot, so we keep using the
  *	same XID for all retransmits.
  */