summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTrond Myklebust <Trond.Myklebust@netapp.com>2007-01-24 20:13:46 -0800
committerChris Wright <chrisw@sous-sol.org>2007-02-05 08:31:45 -0800
commit16a2980e7a2d9afe5b6c68c783d025036edcf70e (patch)
treecb1729babf08ff18c5e7e952ac5447612550c729
parent81a86f15d6f696efcb531620c936d1e7edb96f17 (diff)
[PATCH] SUNRPC: Give cloned RPC clients their own rpc_pipefs directory
This patch fixes a regression in 2.6.19 in which the use of multiple krb5 mounts against the same NFS server may result in an Oops on unmount. The Oops is due to the fact that multiple NFS krb5 clients may end up inadvertently sharing the same rpc_pipefs upcall pipe. The first client to 'umount' will unlink that shared pipe, causing an Oops. The solution is to give each client their own upcall pipe. This fix has been in mainline since 2.6.20-rc1. Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com> [chrisw: backport to 2.6.19.2] Signed-off-by: Chris Wright <chrisw@sous-sol.org>
-rw-r--r--include/linux/sunrpc/clnt.h1
-rw-r--r--net/sunrpc/clnt.c26
2 files changed, 16 insertions, 11 deletions
diff --git a/include/linux/sunrpc/clnt.h b/include/linux/sunrpc/clnt.h
index f6d1d646ce05..a1be89deb3af 100644
--- a/include/linux/sunrpc/clnt.h
+++ b/include/linux/sunrpc/clnt.h
@@ -53,6 +53,7 @@ struct rpc_clnt {
struct dentry * cl_dentry; /* inode */
struct rpc_clnt * cl_parent; /* Points to parent of clones */
struct rpc_rtt cl_rtt_default;
+ struct rpc_program * cl_program;
char cl_inline_name[32];
};
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c
index 78696f2dc7d6..898d5411fdd5 100644
--- a/net/sunrpc/clnt.c
+++ b/net/sunrpc/clnt.c
@@ -141,6 +141,7 @@ static struct rpc_clnt * rpc_new_client(struct rpc_xprt *xprt, char *servname, s
clnt->cl_vers = version->number;
clnt->cl_stats = program->stats;
clnt->cl_metrics = rpc_alloc_iostats(clnt);
+ clnt->cl_program = program;
if (!xprt_bound(clnt->cl_xprt))
clnt->cl_autobind = 1;
@@ -252,6 +253,7 @@ struct rpc_clnt *
rpc_clone_client(struct rpc_clnt *clnt)
{
struct rpc_clnt *new;
+ int err = -ENOMEM;
new = kmalloc(sizeof(*new), GFP_KERNEL);
if (!new)
@@ -259,6 +261,10 @@ rpc_clone_client(struct rpc_clnt *clnt)
memcpy(new, clnt, sizeof(*new));
atomic_set(&new->cl_count, 1);
atomic_set(&new->cl_users, 0);
+ new->cl_metrics = rpc_alloc_iostats(clnt);
+ err = rpc_setup_pipedir(new, clnt->cl_program->pipe_dir_name);
+ if (err != 0)
+ goto out_no_path;
new->cl_parent = clnt;
atomic_inc(&clnt->cl_count);
new->cl_xprt = xprt_get(clnt->cl_xprt);
@@ -266,16 +272,16 @@ 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);
- new->cl_metrics = rpc_alloc_iostats(clnt);
return new;
+out_no_path:
+ rpc_free_iostats(new->cl_metrics);
+ kfree(new);
out_no_clnt:
- printk(KERN_INFO "RPC: out of memory in %s\n", __FUNCTION__);
- return ERR_PTR(-ENOMEM);
+ dprintk("RPC: %s returned error %d\n", __FUNCTION__, err);
+ return ERR_PTR(err);
}
/*
@@ -328,16 +334,14 @@ 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();
}
+ 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: