Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 940e3318 authored by Trond Myklebust's avatar Trond Myklebust Committed by Linus Torvalds
Browse files

[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: default avatarTrond Myklebust <Trond.Myklebust@netapp.com>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent e4d76e1c
Loading
Loading
Loading
Loading
+29 −3
Original line number Diff line number Diff line
@@ -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.
 */