SUNRPC: Fix a 'Busy inodes' error in rpc_pipefs
authorTrond Myklebust <Trond.Myklebust@netapp.com>
Mon, 20 Mar 2006 18:44:49 +0000 (13:44 -0500)
committerTrond Myklebust <Trond.Myklebust@netapp.com>
Mon, 20 Mar 2006 18:44:49 +0000 (13:44 -0500)
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
include/linux/sunrpc/clnt.h
include/linux/sunrpc/rpc_pipe_fs.h
net/sunrpc/clnt.c
net/sunrpc/rpc_pipe.c

index e37c06128e5197a06bae01691721a11f75891f7e..8fe9f35eba31f2a1593c19f361ac9d3a29cbc4f4 100644 (file)
@@ -60,6 +60,7 @@ struct rpc_clnt {
        int                     cl_nodelen;     /* nodename length */
        char                    cl_nodename[UNX_MAXNODENAME];
        char                    cl_pathname[30];/* Path in rpc_pipe_fs */
+       struct vfsmount *       cl_vfsmnt;
        struct dentry *         cl_dentry;      /* inode */
        struct rpc_clnt *       cl_parent;      /* Points to parent of clones */
        struct rpc_rtt          cl_rtt_default;
index 63929349571fe643eecfd1636636daabb6aac2a4..2c2189cb30aab2012e4ab2082247aba3a9f5f5b7 100644 (file)
@@ -45,6 +45,8 @@ extern struct dentry *rpc_mkdir(char *, struct rpc_clnt *);
 extern int rpc_rmdir(char *);
 extern struct dentry *rpc_mkpipe(char *, void *, struct rpc_pipe_ops *, int flags);
 extern int rpc_unlink(char *);
+extern struct vfsmount *rpc_get_mount(void);
+extern void rpc_put_mount(void);
 
 #endif
 #endif
index 0bb23e8e9d0c0714766dbd0ab46eb0e785076813..9f775302d1dff946969f366ca74f39416c703d35 100644 (file)
@@ -70,8 +70,15 @@ rpc_setup_pipedir(struct rpc_clnt *clnt, char *dir_name)
        static uint32_t clntid;
        int error;
 
+       clnt->cl_vfsmnt = ERR_PTR(-ENOENT);
+       clnt->cl_dentry = ERR_PTR(-ENOENT);
        if (dir_name == NULL)
                return 0;
+
+       clnt->cl_vfsmnt = rpc_get_mount();
+       if (IS_ERR(clnt->cl_vfsmnt))
+               return PTR_ERR(clnt->cl_vfsmnt);
+
        for (;;) {
                snprintf(clnt->cl_pathname, sizeof(clnt->cl_pathname),
                                "%s/clnt%x", dir_name,
@@ -84,6 +91,7 @@ rpc_setup_pipedir(struct rpc_clnt *clnt, char *dir_name)
                if (error != -EEXIST) {
                        printk(KERN_INFO "RPC: Couldn't create pipefs entry %s, error %d\n",
                                        clnt->cl_pathname, error);
+                       rpc_put_mount();
                        return error;
                }
        }
@@ -175,7 +183,11 @@ rpc_new_client(struct rpc_xprt *xprt, char *servname,
        return clnt;
 
 out_no_auth:
-       rpc_rmdir(clnt->cl_pathname);
+       if (!IS_ERR(clnt->cl_dentry)) {
+               rpc_rmdir(clnt->cl_pathname);
+               dput(clnt->cl_dentry);
+               rpc_put_mount();
+       }
 out_no_path:
        if (clnt->cl_server != clnt->cl_inline_name)
                kfree(clnt->cl_server);
@@ -240,13 +252,15 @@ rpc_clone_client(struct rpc_clnt *clnt)
        new->cl_autobind = 0;
        new->cl_oneshot = 0;
        new->cl_dead = 0;
-       dget(new->cl_dentry);
+       if (!IS_ERR(new->cl_dentry)) {
+               dget(new->cl_dentry);
+               rpc_get_mount();
+       }
        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_pmap            = &new->cl_pmap_default;
        new->cl_metrics         = rpc_alloc_iostats(clnt);
-       rpc_init_wait_queue(&new->cl_pmap_default.pm_bindwait, "bindwait");
        return new;
 out_no_clnt:
        printk(KERN_INFO "RPC: out of memory in %s\n", __FUNCTION__);
@@ -318,8 +332,10 @@ rpc_destroy_client(struct rpc_clnt *clnt)
 out_free:
        rpc_free_iostats(clnt->cl_metrics);
        clnt->cl_metrics = NULL;
-       if (clnt->cl_dentry)
+       if (!IS_ERR(clnt->cl_dentry)) {
                dput(clnt->cl_dentry);
+               rpc_put_mount();
+       }
        kfree(clnt);
        return 0;
 }
index 72b22172f0aff0f66e9c635a2b7600eddb47b104..391d2bfc71aa3cd0eb23025ff615d4b5bd72d641 100644 (file)
@@ -435,14 +435,17 @@ static struct rpc_filelist authfiles[] = {
        },
 };
 
-static int
-rpc_get_mount(void)
+struct vfsmount *rpc_get_mount(void)
 {
-       return simple_pin_fs("rpc_pipefs", &rpc_mount, &rpc_mount_count);
+       int err;
+
+       err = simple_pin_fs("rpc_pipefs", &rpc_mount, &rpc_mount_count);
+       if (err != 0)
+               return ERR_PTR(err);
+       return rpc_mount;
 }
 
-static void
-rpc_put_mount(void)
+void rpc_put_mount(void)
 {
        simple_release_fs(&rpc_mount, &rpc_mount_count);
 }
@@ -452,12 +455,13 @@ rpc_lookup_parent(char *path, struct nameidata *nd)
 {
        if (path[0] == '\0')
                return -ENOENT;
-       if (rpc_get_mount()) {
+       nd->mnt = rpc_get_mount();
+       if (IS_ERR(nd->mnt)) {
                printk(KERN_WARNING "%s: %s failed to mount "
                               "pseudofilesystem \n", __FILE__, __FUNCTION__);
-               return -ENODEV;
+               return PTR_ERR(nd->mnt);
        }
-       nd->mnt = mntget(rpc_mount);
+       mntget(nd->mnt);
        nd->dentry = dget(rpc_mount->mnt_root);
        nd->last_type = LAST_ROOT;
        nd->flags = LOOKUP_PARENT;
@@ -594,7 +598,6 @@ __rpc_mkdir(struct inode *dir, struct dentry *dentry)
        d_instantiate(dentry, inode);
        dir->i_nlink++;
        inode_dir_notify(dir, DN_CREATE);
-       rpc_get_mount();
        return 0;
 out_err:
        printk(KERN_WARNING "%s: %s failed to allocate inode for dentry %s\n",
@@ -615,7 +618,6 @@ __rpc_rmdir(struct inode *dir, struct dentry *dentry)
        if (!error) {
                inode_dir_notify(dir, DN_DELETE);
                d_drop(dentry);
-               rpc_put_mount();
        }
        return 0;
 }