Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > fc11cd6e1c513a17304da94a5390f3cd > files > 2665

kernel-2.6.18-194.11.1.el5.src.rpm

From: Steve Dickson <SteveD@redhat.com>
Subject: [PATCH][RHEL5]  Unable to mount more that 1 Secure NFS mount
Date: Mon, 22 Jan 2007 09:57:00 -0500
Bugzilla: 220649
Message-Id: <45B4D0BC.4010300@RedHat.com>
Changelog: nfs: Unable to mount more than 1 Secure NFS mount


This is a late breaking fix that allows more than one Secure NFS
mount to be mounted. There are three upstream patches that are
needed to  fix this problem.

The first patch clones RPC client structures that allow more
that one connection which basically fixes the problem... but...
Unfortunately the cloning code is a bit challenged....

So the second patch, fixes the cloning process by adding
referents counts to xptr structures (structures that are used
for connections) and to stop the freeing of freed memory...
(which is always a good thing... ;-) )

The third patch fixes a BUG_ON() from popping due to a
mis-configured krb5 environment or a selinux denial which
is a very common problem when people start to use secured
mounts

The bz is:
https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=220649

steved.

commit 3e32a5d99a467b9d4d416323c8c292479b4915e5
Author: Trond Myklebust <Trond.Myklebust@netapp.com>

    SUNRPC: Give cloned RPC clients their own rpc_pipefs directory

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

--- linux-2.6.18.i686/include/linux/sunrpc/clnt.h.orig	2006-09-19 23:42:06.000000000 -0400
+++ linux-2.6.18.i686/include/linux/sunrpc/clnt.h	2007-01-17 13:48:10.000000000 -0500
@@ -66,6 +66,7 @@ struct rpc_clnt {
 	struct rpc_rtt		cl_rtt_default;
 	struct rpc_portmap	cl_pmap_default;
 	char			cl_inline_name[32];
+	struct rpc_program *	cl_program;
 };
 #define cl_timeout		cl_xprt->timeout
 #define cl_prog			cl_pmap->pm_prog
--- linux-2.6.18.i686/net/sunrpc/clnt.c.orig	2007-01-15 06:13:14.000000000 -0500
+++ linux-2.6.18.i686/net/sunrpc/clnt.c	2007-01-17 13:53:44.000000000 -0500
@@ -154,6 +154,7 @@ rpc_new_client(struct rpc_xprt *xprt, ch
 	clnt->cl_prot     = xprt->prot;
 	clnt->cl_stats    = program->stats;
 	clnt->cl_metrics  = rpc_alloc_iostats(clnt);
+	clnt->cl_program  = program;
 	rpc_init_wait_queue(&clnt->cl_pmap_default.pm_bindwait, "bindwait");
 
 	if (!clnt->cl_port)
@@ -235,6 +236,7 @@ struct rpc_clnt *
 rpc_clone_client(struct rpc_clnt *clnt)
 {
 	struct rpc_clnt *new;
+	int err;
 
 	new = kmalloc(sizeof(*new), GFP_KERNEL);
 	if (!new)
@@ -242,6 +244,11 @@ rpc_clone_client(struct rpc_clnt *clnt)
 	memcpy(new, clnt, sizeof(*new));
 	atomic_set(&new->cl_count, 1);
 	atomic_set(&new->cl_users, 0);
+	err = rpc_setup_pipedir(new, clnt->cl_program->pipe_dir_name);
+	if (err != 0) {
+		kfree(new);
+		return ERR_PTR(err);
+	}
 	new->cl_parent = clnt;
 	atomic_inc(&clnt->cl_count);
 	/* Duplicate portmapper */
@@ -250,8 +257,6 @@ rpc_clone_client(struct rpc_clnt *clnt)
 	new->cl_autobind = 0;
 	new->cl_oneshot = 0;
 	new->cl_dead = 0;
-	if (!IS_ERR(new->cl_dentry))
-		dget(new->cl_dentry);
 	rpc_init_rtt(&new->cl_rtt_default, clnt->cl_xprt->timeout.to_initval);
 	if (new->cl_auth)
 		atomic_inc(&new->cl_auth->au_count);
@@ -313,12 +318,6 @@ rpc_destroy_client(struct rpc_clnt *clnt
 		rpcauth_destroy(clnt->cl_auth);
 		clnt->cl_auth = NULL;
 	}
-	if (clnt->cl_parent != clnt) {
-		if (!IS_ERR(clnt->cl_dentry))
-			dput(clnt->cl_dentry);
-		rpc_destroy_client(clnt->cl_parent);
-		goto out_free;
-	}
 	if (!IS_ERR(clnt->cl_dentry)) {
 		rpc_rmdir(clnt->cl_dentry);
 		rpc_put_mount();
@@ -327,6 +326,10 @@ rpc_destroy_client(struct rpc_clnt *clnt
 		xprt_destroy(clnt->cl_xprt);
 		clnt->cl_xprt = NULL;
 	}
+	if (clnt->cl_parent != clnt) {
+		rpc_destroy_client(clnt->cl_parent);
+		goto out_free;
+	}
 	if (clnt->cl_server != clnt->cl_inline_name)
 		kfree(clnt->cl_server);
 out_free:

commit 6b6ca86b77b62b798cf9ca2599036420abce7796
Author: Trond Myklebust <Trond.Myklebust@netapp.com>

    SUNRPC: Add refcounting to the struct rpc_xprt

    In a subsequent patch, this will allow the portmapper to take a reference
    to the rpc_xprt for which it is updating the port number, fixing an Oops.

    Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
------------------------------------------------------
--- linux-2.6.18.noarch/include/linux/sunrpc/xprt.h.orig	2007-01-20 06:37:30.000000000 -0500
+++ linux-2.6.18.noarch/include/linux/sunrpc/xprt.h	2007-01-20 06:37:59.000000000 -0500
@@ -12,6 +12,7 @@
 #include <linux/uio.h>
 #include <linux/socket.h>
 #include <linux/in.h>
+#include <linux/kref.h>
 #include <linux/sunrpc/sched.h>
 #include <linux/sunrpc/xdr.h>
 
@@ -119,6 +120,7 @@ struct rpc_xprt_ops {
 };
 
 struct rpc_xprt {
+	struct kref		kref;		/* Reference count */
 	struct rpc_xprt_ops *	ops;		/* transport methods */
 	struct socket *		sock;		/* BSD socket layer */
 	struct sock *		inet;		/* INET layer */
@@ -234,7 +236,8 @@ int			xprt_adjust_timeout(struct rpc_rqs
 void			xprt_release_xprt(struct rpc_xprt *xprt, struct rpc_task *task);
 void			xprt_release_xprt_cong(struct rpc_xprt *xprt, struct rpc_task *task);
 void			xprt_release(struct rpc_task *task);
-int			xprt_destroy(struct rpc_xprt *xprt);
+struct rpc_xprt *	xprt_get(struct rpc_xprt *xprt);
+void			xprt_put(struct rpc_xprt *xprt);
 
 static inline u32 *xprt_skip_transport_header(struct rpc_xprt *xprt, u32 *p)
 {
--- linux-2.6.18.noarch/net/sunrpc/clnt.c.orig	2007-01-20 06:35:28.000000000 -0500
+++ linux-2.6.18.noarch/net/sunrpc/clnt.c	2007-01-20 06:40:09.000000000 -0500
@@ -192,7 +192,7 @@ out_no_path:
 		kfree(clnt->cl_server);
 	kfree(clnt);
 out_err:
-	xprt_destroy(xprt);
+	xprt_put(xprt);
 out_no_xprt:
 	return ERR_PTR(err);
 }
@@ -244,11 +244,24 @@ rpc_clone_client(struct rpc_clnt *clnt)
 	memcpy(new, clnt, sizeof(*new));
 	atomic_set(&new->cl_count, 1);
 	atomic_set(&new->cl_users, 0);
+	if (clnt->cl_server != clnt->cl_inline_name) {
+		new->cl_server = kstrdup(clnt->cl_server, GFP_KERNEL);
+		if (new->cl_server == NULL) {
+			kfree(new);
+			return ERR_PTR(-ENOMEM);
+		}
+	} else
+		new->cl_server = new->cl_inline_name;
+
 	err = rpc_setup_pipedir(new, clnt->cl_program->pipe_dir_name);
 	if (err != 0) {
+		if (new->cl_server != new->cl_inline_name)
+			kfree(new->cl_server);
 		kfree(new);
 		return ERR_PTR(err);
 	}
+
+	new->cl_xprt = xprt_get(clnt->cl_xprt);
 	new->cl_parent = clnt;
 	atomic_inc(&clnt->cl_count);
 	/* Duplicate portmapper */
@@ -322,10 +335,6 @@ rpc_destroy_client(struct rpc_clnt *clnt
 		rpc_rmdir(clnt->cl_dentry);
 		rpc_put_mount();
 	}
-	if (clnt->cl_xprt) {
-		xprt_destroy(clnt->cl_xprt);
-		clnt->cl_xprt = NULL;
-	}
 	if (clnt->cl_parent != clnt) {
 		rpc_destroy_client(clnt->cl_parent);
 		goto out_free;
@@ -335,6 +344,7 @@ rpc_destroy_client(struct rpc_clnt *clnt
 out_free:
 	rpc_free_iostats(clnt->cl_metrics);
 	clnt->cl_metrics = NULL;
+	xprt_put(clnt->cl_xprt);
 	kfree(clnt);
 	return 0;
 }
--- linux-2.6.18.noarch/net/sunrpc/xprt.c.orig	2007-01-20 06:37:43.000000000 -0500
+++ linux-2.6.18.noarch/net/sunrpc/xprt.c	2007-01-20 06:37:59.000000000 -0500
@@ -916,6 +916,7 @@ static struct rpc_xprt *xprt_setup(int p
 		return ERR_PTR(result);
 	}
 
+	kref_init(&xprt->kref);
 	spin_lock_init(&xprt->transport_lock);
 	spin_lock_init(&xprt->reserve_lock);
 
@@ -966,16 +967,36 @@ struct rpc_xprt *xprt_create_proto(int p
 
 /**
  * xprt_destroy - destroy an RPC transport, killing off all requests.
- * @xprt: transport to destroy
+ * @kref: kref for the transport to destroy
  *
  */
-int xprt_destroy(struct rpc_xprt *xprt)
+static void xprt_destroy(struct kref *kref)
 {
+	struct rpc_xprt *xprt = container_of(kref, struct rpc_xprt, kref);
+
 	dprintk("RPC:      destroying transport %p\n", xprt);
 	xprt->shutdown = 1;
 	del_timer_sync(&xprt->timer);
 	xprt->ops->destroy(xprt);
 	kfree(xprt);
+}
+/**
+ * xprt_put - release a reference to an RPC transport.
+ * @xprt: pointer to the transport
+ *
+ */
+void xprt_put(struct rpc_xprt *xprt)
+{
+	kref_put(&xprt->kref, xprt_destroy);
+}
 
-	return 0;
+/**
+ * xprt_get - return a reference to an RPC transport.
+ * @xprt: pointer to the transport
+ *
+ */
+struct rpc_xprt *xprt_get(struct rpc_xprt *xprt)
+{
+	kref_get(&xprt->kref);
+	return xprt;
 }

We shouldn't be calling rpc_release_task() for tasks that are not active.

Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
-------------
--- linux-2.6.18.i686/include/linux/sunrpc/sched.h.orig	2007-01-21 05:40:37.000000000 -0500
+++ linux-2.6.18.i686/include/linux/sunrpc/sched.h	2007-01-21 15:06:11.000000000 -0500
@@ -253,7 +253,6 @@ void		rpc_init_task(struct rpc_task *tas
 				int flags, const struct rpc_call_ops *ops,
 				void *data);
 void		rpc_put_task(struct rpc_task *);
-void		rpc_release_task(struct rpc_task *);
 void		rpc_exit_task(struct rpc_task *);
 void		rpc_killall_tasks(struct rpc_clnt *);
 int		rpc_execute(struct rpc_task *);
--- linux-2.6.18.i686/net/sunrpc/clnt.c.orig	2007-01-21 05:40:37.000000000 -0500
+++ linux-2.6.18.i686/net/sunrpc/clnt.c	2007-01-21 15:06:11.000000000 -0500
@@ -479,16 +479,14 @@ int rpc_call_sync(struct rpc_clnt *clnt,
 
 	/* Set up the call info struct and execute the task */
 	status = task->tk_status;
-	if (status != 0) {
-		rpc_release_task(task);
+	if (status != 0)
 		goto out;
-	}
 	atomic_inc(&task->tk_count);
 	status = rpc_execute(task);
 	if (status == 0)
 		status = task->tk_status;
-	rpc_put_task(task);
 out:
+	rpc_put_task(task);
 	rpc_restore_sigmask(&oldset);
 	return status;
 }
@@ -526,7 +524,7 @@ rpc_call_async(struct rpc_clnt *clnt, st
 	if (status == 0)
 		rpc_execute(task);
 	else
-		rpc_release_task(task);
+		rpc_put_task(task);
 
 	rpc_restore_sigmask(&oldset);		
 	return status;
--- linux-2.6.18.i686/net/sunrpc/sched.c.orig	2007-01-21 15:04:14.000000000 -0500
+++ linux-2.6.18.i686/net/sunrpc/sched.c	2007-01-21 15:07:09.000000000 -0500
@@ -43,6 +43,7 @@ static mempool_t	*rpc_buffer_mempool __r
 static void			__rpc_default_timer(struct rpc_task *task);
 static void			rpciod_killall(void);
 static void			rpc_async_schedule(void *);
+static void			 rpc_release_task(struct rpc_task *task);
 
 /*
  * RPC tasks that create another task (e.g. for contacting the portmapper)
@@ -909,7 +910,7 @@ void rpc_put_task(struct rpc_task *task)
 }
 EXPORT_SYMBOL(rpc_put_task);
 
-void rpc_release_task(struct rpc_task *task)
+static void rpc_release_task(struct rpc_task *task)
 {
 #ifdef RPC_DEBUG
 	BUG_ON(task->tk_magic != RPC_TASK_MAGIC_ID);