瀏覽代碼

[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>
Trond Myklebust 19 年之前
父節點
當前提交
940e3318c3
共有 1 個文件被更改,包括 29 次插入3 次删除
  1. 29 3
      net/sunrpc/clnt.c

+ 29 - 3
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_bind_status(struct rpc_task *task);
 static void	call_transmit(struct rpc_task *task);
 static void	call_transmit(struct rpc_task *task);
 static void	call_status(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_refresh(struct rpc_task *task);
 static void	call_refreshresult(struct rpc_task *task);
 static void	call_refreshresult(struct rpc_task *task);
 static void	call_timeout(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);
 	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
  * 3.	Encode arguments of an RPC call
  */
  */
@@ -867,12 +880,14 @@ call_transmit(struct rpc_task *task)
 	if (task->tk_status != 0)
 	if (task->tk_status != 0)
 		return;
 		return;
 	/* Encode here so that rpcsec_gss can use correct sequence number. */
 	/* 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);
 		call_encode(task);
 		/* Did the encode result in an error condition? */
 		/* Did the encode result in an error condition? */
 		if (task->tk_status != 0)
 		if (task->tk_status != 0)
 			goto out_nosend;
 			goto out_nosend;
 	}
 	}
+	task->tk_action = call_transmit_status;
 	xprt_transmit(task);
 	xprt_transmit(task);
 	if (task->tk_status < 0)
 	if (task->tk_status < 0)
 		return;
 		return;
@@ -884,6 +899,7 @@ call_transmit(struct rpc_task *task)
 out_nosend:
 out_nosend:
 	/* release socket write lock before attempting to handle error */
 	/* release socket write lock before attempting to handle error */
 	xprt_abort_transmit(task);
 	xprt_abort_transmit(task);
+	rpc_task_force_reencode(task);
 }
 }
 
 
 /*
 /*
@@ -915,7 +931,6 @@ call_status(struct rpc_task *task)
 		break;
 		break;
 	case -ECONNREFUSED:
 	case -ECONNREFUSED:
 	case -ENOTCONN:
 	case -ENOTCONN:
-		req->rq_bytes_sent = 0;
 		if (clnt->cl_autobind)
 		if (clnt->cl_autobind)
 			clnt->cl_port = 0;
 			clnt->cl_port = 0;
 		task->tk_action = call_bind;
 		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
  * 	We do not release the request slot, so we keep using the
  *	same XID for all retransmits.
  *	same XID for all retransmits.
  */
  */