]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
[PATCH] SUNRPC: Give cloned RPC clients their own rpc_pipefs directory
authorTrond Myklebust <Trond.Myklebust@netapp.com>
Thu, 25 Jan 2007 04:13:46 +0000 (20:13 -0800)
committerChris Wright <chrisw@sous-sol.org>
Mon, 5 Feb 2007 16:31:45 +0000 (08:31 -0800)
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>
include/linux/sunrpc/clnt.h
net/sunrpc/clnt.c

index f6d1d646ce05c1039437ff7af52155df9afbe353..a1be89deb3af7cb0f5d592b5bbfcdb82e216ccd0 100644 (file)
@@ -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];
 };
 
index 78696f2dc7d6d402ef200f140f897388ce383db1..898d5411fdd5e05c2f8e23eb8b636b5b9ec8b22c 100644 (file)
@@ -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: