Patchwork [3.5.y.z,extended,stable] Patch "SUNRPC: Ensure we release the socket write lock if the" has been added to staging queue

mail settings
Submitter Herton Ronaldo Krzesinski
Date Jan. 23, 2013, 4:42 a.m.
Message ID <>
Download mbox | patch
Permalink /patch/214755/
State New
Headers show


Herton Ronaldo Krzesinski - Jan. 23, 2013, 4:42 a.m.
This is a note to let you know that I have just added a patch titled

    SUNRPC: Ensure we release the socket write lock if the

to the linux-3.5.y-queue branch of the 3.5.y.z extended stable tree 
which can be found at:;a=shortlog;h=refs/heads/linux-3.5.y-queue

If you, or anyone else, feels it should not be added to this tree, please 
reply to this email.

For more information about the 3.5.y.z tree, see



From 54b1298470d6b4f2cf4de4a0bf1a7e9ae91e3299 Mon Sep 17 00:00:00 2001
From: Trond Myklebust <>
Date: Mon, 7 Jan 2013 14:30:46 -0500
Subject: [PATCH] SUNRPC: Ensure we release the socket write lock if the
 rpc_task exits early

commit 87ed50036b866db2ec2ba16b2a7aec4a2b0b7c39 upstream.

If the rpc_task exits while holding the socket write lock before it has
allocated an rpc slot, then the usual mechanism for releasing the write
lock in xprt_release() is defeated.

The problem occurs if the call to xprt_lock_write() initially fails, so
that the rpc_task is put on the xprt->sending wait queue. If the task
exits after being assigned the lock by __xprt_lock_write_func, but
before it has retried the call to xprt_lock_and_alloc_slot(), then
it calls xprt_release() while holding the write lock, but will
immediately exit due to the test for task->tk_rqstp != NULL.

Reported-by: Chris Perl <>
Signed-off-by: Trond Myklebust <>
Signed-off-by: Herton Ronaldo Krzesinski <>
 net/sunrpc/sched.c |    3 +--
 net/sunrpc/xprt.c  |   12 ++++++++++--
 2 files changed, 11 insertions(+), 4 deletions(-)



diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c
index fe2cf2f..85b9235 100644
--- a/net/sunrpc/sched.c
+++ b/net/sunrpc/sched.c
@@ -953,8 +953,7 @@  static void rpc_async_release(struct work_struct *work)

 static void rpc_release_resources_task(struct rpc_task *task)
-	if (task->tk_rqstp)
-		xprt_release(task);
+	xprt_release(task);
 	if (task->tk_msg.rpc_cred) {
 		task->tk_msg.rpc_cred = NULL;
diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c
index 2d5b811..6329ff3 100644
--- a/net/sunrpc/xprt.c
+++ b/net/sunrpc/xprt.c
@@ -1139,10 +1139,18 @@  static void xprt_request_init(struct rpc_task *task, struct rpc_xprt *xprt)
 void xprt_release(struct rpc_task *task)
 	struct rpc_xprt	*xprt;
-	struct rpc_rqst	*req;
+	struct rpc_rqst	*req = task->tk_rqstp;

-	if (!(req = task->tk_rqstp))
+	if (req == NULL) {
+		if (task->tk_client) {
+			rcu_read_lock();
+			xprt = rcu_dereference(task->tk_client->cl_xprt);
+			if (xprt->snd_task == task)
+				xprt_release_write(xprt, task);
+			rcu_read_unlock();
+		}
+	}

 	xprt = req->rq_xprt;
 	if (task->tk_ops->rpc_count_stats != NULL)