Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > 27922b4260f65d317aabda37e42bbbff > files > 3123

kernel-2.6.18-238.el5.src.rpm

From: Steve Dickson <SteveD@redhat.com>
Date: Mon, 10 Dec 2007 10:50:49 -0500
Subject: [net] sunrpc: lockd recovery is broken
Message-id: 475D6059.7040309@RedHat.com
O-Subject: [RHEL5.2] [PATCH] lockd recovery is broken
Bugzilla: 240976

The following patch restores lock recover in RHEL5.2 kernel.

The problem is UDP listeners of the in-kernel lockd process are no longer
being created by default. Unfortunately, rpc.statd (the userlevel process
that notifies the kernel to recover its locks) can only use UPD sockets.
So the callback into the kernel fails because there is no UPD listener.

The first part of this patch removes the one line that stop
UPS listeners from always being started.

In debugging this problem, Jeff noticed that lockd fails instead of
retrying when the portmapper is down. This is wrong. Lockd needs to retry
(forever) when the portmapper is down. The patch is a backport of:

commit da45828e2835057045150b318c4fbe9bb91f18dd
Author: Trond Myklebust <Trond.Myklebust@netapp.com>
Date:	Thu Aug 31 15:44:52 2006 -0400

    SUNRPC: Clean up soft task error handling

    - Ensure that the task aborts the RPC call only when it has actually timed
out.
     - Ensure that req->rq_majortimeo is initialised correctly.

    Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>

the bzs are:
https://bugzilla.redhat.com/show_bug.cgi?id=240976
https://bugzilla.redhat.com/show_bug.cgi?id=369561

steved.

Acked-by: Jeff Layton <jlayton@redhat.com>

diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c
index e19f096..928721f 100644
--- a/fs/lockd/svc.c
+++ b/fs/lockd/svc.c
@@ -234,9 +234,13 @@ static int make_socks(struct svc_serv *serv, int proto)
 	 * options, make those sockets unconditionally
 	 */
 	int err = 0;
-	if (proto == IPPROTO_UDP || nlm_udpport)
-		if (!find_socket(serv, IPPROTO_UDP))
-			err = svc_makesock(serv, IPPROTO_UDP, nlm_udpport);
+	
+	/*
+	 * Note: a UDP socket needs to always exist for statd
+	 * to make callback on.
+	 */
+	if (!find_socket(serv, IPPROTO_UDP))
+		err = svc_makesock(serv, IPPROTO_UDP, nlm_udpport);
 	if (err)
 		return err;
 	if (proto == IPPROTO_TCP || nlm_tcpport)
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c
index cd41838..2086f11 100644
--- a/net/sunrpc/clnt.c
+++ b/net/sunrpc/clnt.c
@@ -836,15 +836,11 @@ call_bind_status(struct rpc_task *task)
 		dprintk("RPC: %4d remote rpcbind: RPC program/version unavailable\n",
 				task->tk_pid);
 		rpc_delay(task, 3*HZ);
-		goto retry_bind;
+		goto retry_timeout;
 	case -ETIMEDOUT:
 		dprintk("RPC: %4d rpcbind request timed out\n",
 				task->tk_pid);
-		if (RPC_IS_SOFT(task)) {
-			status = -EIO;
-			break;
-		}
-		goto retry_bind;
+		goto retry_timeout;
 	case -EPFNOSUPPORT:
 		dprintk("RPC: %4d remote rpcbind service unavailable\n",
 				task->tk_pid);
@@ -857,16 +853,13 @@ call_bind_status(struct rpc_task *task)
 		dprintk("RPC: %4d unrecognized rpcbind error (%d)\n",
 				task->tk_pid, -task->tk_status);
 		status = -EIO;
-		break;
 	}
 
 	rpc_exit(task, status);
 	return;
 
-retry_bind:
-	task->tk_status = 0;
-	task->tk_action = call_bind;
-	return;
+retry_timeout:
+	task->tk_action = call_timeout;
 }
 
 /*
@@ -914,14 +907,16 @@ call_connect_status(struct rpc_task *task)
 
 	switch (status) {
 	case -ENOTCONN:
-	case -ETIMEDOUT:
 	case -EAGAIN:
 		task->tk_action = call_bind;
-		break;
-	default:
-		rpc_exit(task, -EIO);
-		break;
+		if (!RPC_IS_SOFT(task))
+			return;
+		/* if soft mounted, test if we've timed out */
+	case -ETIMEDOUT:
+		task->tk_action = call_timeout;
+		return;
 	}
+	rpc_exit(task, -EIO);
 }
 
 /*
@@ -1022,7 +1017,6 @@ call_status(struct rpc_task *task)
 		printk("%s: RPC call returned error %d\n",
 			       clnt->cl_protname, -status);
 		rpc_exit(task, status);
-		break;
 	}
 }
 
@@ -1090,10 +1084,10 @@ call_decode(struct rpc_task *task)
 			clnt->cl_stats->rpcretrans++;
 			goto out_retry;
 		}
-		printk(KERN_WARNING "%s: too small RPC reply size (%d bytes)\n",
+		dprintk("%s: too small RPC reply size (%d bytes)\n",
 			clnt->cl_protname, task->tk_status);
-		rpc_exit(task, -EIO);
-		return;
+		task->tk_action = call_timeout;
+		goto out_retry;
 	}
 
 	/*
diff --git a/net/sunrpc/pmap_clnt.c b/net/sunrpc/pmap_clnt.c
index 623180f..fab1f97 100644
--- a/net/sunrpc/pmap_clnt.c
+++ b/net/sunrpc/pmap_clnt.c
@@ -144,11 +144,9 @@ pmap_getport_done(struct rpc_task *task)
 
 	xprt->ops->set_port(xprt, 0);
 	if (task->tk_status < 0) {
-		/* Make the calling task exit with an error */
-		task->tk_action = rpc_exit_task;
+		clnt->cl_port = 0;
 	} else if (clnt->cl_port == 0) {
-		/* Program not registered */
-		rpc_exit(task, -EACCES);
+		task->tk_status = -EACCES;
 	} else {
 		xprt->ops->set_port(xprt, clnt->cl_port);
 		clnt->cl_port = htons(clnt->cl_port);
diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c
index decb4fd..40dbb96 100644
--- a/net/sunrpc/xprt.c
+++ b/net/sunrpc/xprt.c
@@ -585,13 +585,6 @@ static void xprt_connect_status(struct rpc_task *task)
 				task->tk_pid, -task->tk_status, task->tk_client->cl_server);
 		xprt_release_write(xprt, task);
 		task->tk_status = -EIO;
-		return;
-	}
-
-	/* if soft mounted, just cause this RPC to fail */
-	if (RPC_IS_SOFT(task)) {
-		xprt_release_write(xprt, task);
-		task->tk_status = -EIO;
 	}
 }
 
@@ -829,6 +822,7 @@ static void xprt_request_init(struct rpc_task *task, struct rpc_xprt *xprt)
 	req->rq_bufsize = 0;
 	req->rq_xid     = xprt_alloc_xid(xprt);
 	req->rq_release_snd_buf = NULL;
+	xprt_reset_majortimeo(req);
 	dprintk("RPC: %4d reserved req %p xid %08x\n", task->tk_pid,
 			req, ntohl(req->rq_xid));
 }