Commit 54281548 authored by Trond Myklebust's avatar Trond Myklebust

SUNRPC: Fix a 'Busy inodes' error in rpc_pipefs

Signed-off-by: default avatarTrond Myklebust <Trond.Myklebust@netapp.com>
parent a9a80178
...@@ -60,6 +60,7 @@ struct rpc_clnt { ...@@ -60,6 +60,7 @@ struct rpc_clnt {
int cl_nodelen; /* nodename length */ int cl_nodelen; /* nodename length */
char cl_nodename[UNX_MAXNODENAME]; char cl_nodename[UNX_MAXNODENAME];
char cl_pathname[30];/* Path in rpc_pipe_fs */ char cl_pathname[30];/* Path in rpc_pipe_fs */
struct vfsmount * cl_vfsmnt;
struct dentry * cl_dentry; /* inode */ struct dentry * cl_dentry; /* inode */
struct rpc_clnt * cl_parent; /* Points to parent of clones */ struct rpc_clnt * cl_parent; /* Points to parent of clones */
struct rpc_rtt cl_rtt_default; struct rpc_rtt cl_rtt_default;
......
...@@ -45,6 +45,8 @@ extern struct dentry *rpc_mkdir(char *, struct rpc_clnt *); ...@@ -45,6 +45,8 @@ extern struct dentry *rpc_mkdir(char *, struct rpc_clnt *);
extern int rpc_rmdir(char *); extern int rpc_rmdir(char *);
extern struct dentry *rpc_mkpipe(char *, void *, struct rpc_pipe_ops *, int flags); extern struct dentry *rpc_mkpipe(char *, void *, struct rpc_pipe_ops *, int flags);
extern int rpc_unlink(char *); extern int rpc_unlink(char *);
extern struct vfsmount *rpc_get_mount(void);
extern void rpc_put_mount(void);
#endif #endif
#endif #endif
...@@ -70,8 +70,15 @@ rpc_setup_pipedir(struct rpc_clnt *clnt, char *dir_name) ...@@ -70,8 +70,15 @@ rpc_setup_pipedir(struct rpc_clnt *clnt, char *dir_name)
static uint32_t clntid; static uint32_t clntid;
int error; int error;
clnt->cl_vfsmnt = ERR_PTR(-ENOENT);
clnt->cl_dentry = ERR_PTR(-ENOENT);
if (dir_name == NULL) if (dir_name == NULL)
return 0; return 0;
clnt->cl_vfsmnt = rpc_get_mount();
if (IS_ERR(clnt->cl_vfsmnt))
return PTR_ERR(clnt->cl_vfsmnt);
for (;;) { for (;;) {
snprintf(clnt->cl_pathname, sizeof(clnt->cl_pathname), snprintf(clnt->cl_pathname, sizeof(clnt->cl_pathname),
"%s/clnt%x", dir_name, "%s/clnt%x", dir_name,
...@@ -84,6 +91,7 @@ rpc_setup_pipedir(struct rpc_clnt *clnt, char *dir_name) ...@@ -84,6 +91,7 @@ rpc_setup_pipedir(struct rpc_clnt *clnt, char *dir_name)
if (error != -EEXIST) { if (error != -EEXIST) {
printk(KERN_INFO "RPC: Couldn't create pipefs entry %s, error %d\n", printk(KERN_INFO "RPC: Couldn't create pipefs entry %s, error %d\n",
clnt->cl_pathname, error); clnt->cl_pathname, error);
rpc_put_mount();
return error; return error;
} }
} }
...@@ -175,7 +183,11 @@ rpc_new_client(struct rpc_xprt *xprt, char *servname, ...@@ -175,7 +183,11 @@ rpc_new_client(struct rpc_xprt *xprt, char *servname,
return clnt; return clnt;
out_no_auth: out_no_auth:
if (!IS_ERR(clnt->cl_dentry)) {
rpc_rmdir(clnt->cl_pathname); rpc_rmdir(clnt->cl_pathname);
dput(clnt->cl_dentry);
rpc_put_mount();
}
out_no_path: out_no_path:
if (clnt->cl_server != clnt->cl_inline_name) if (clnt->cl_server != clnt->cl_inline_name)
kfree(clnt->cl_server); kfree(clnt->cl_server);
...@@ -240,13 +252,15 @@ rpc_clone_client(struct rpc_clnt *clnt) ...@@ -240,13 +252,15 @@ rpc_clone_client(struct rpc_clnt *clnt)
new->cl_autobind = 0; new->cl_autobind = 0;
new->cl_oneshot = 0; new->cl_oneshot = 0;
new->cl_dead = 0; new->cl_dead = 0;
if (!IS_ERR(new->cl_dentry)) {
dget(new->cl_dentry); dget(new->cl_dentry);
rpc_get_mount();
}
rpc_init_rtt(&new->cl_rtt_default, clnt->cl_xprt->timeout.to_initval); rpc_init_rtt(&new->cl_rtt_default, clnt->cl_xprt->timeout.to_initval);
if (new->cl_auth) if (new->cl_auth)
atomic_inc(&new->cl_auth->au_count); atomic_inc(&new->cl_auth->au_count);
new->cl_pmap = &new->cl_pmap_default; new->cl_pmap = &new->cl_pmap_default;
new->cl_metrics = rpc_alloc_iostats(clnt); new->cl_metrics = rpc_alloc_iostats(clnt);
rpc_init_wait_queue(&new->cl_pmap_default.pm_bindwait, "bindwait");
return new; return new;
out_no_clnt: out_no_clnt:
printk(KERN_INFO "RPC: out of memory in %s\n", __FUNCTION__); printk(KERN_INFO "RPC: out of memory in %s\n", __FUNCTION__);
...@@ -318,8 +332,10 @@ rpc_destroy_client(struct rpc_clnt *clnt) ...@@ -318,8 +332,10 @@ rpc_destroy_client(struct rpc_clnt *clnt)
out_free: out_free:
rpc_free_iostats(clnt->cl_metrics); rpc_free_iostats(clnt->cl_metrics);
clnt->cl_metrics = NULL; clnt->cl_metrics = NULL;
if (clnt->cl_dentry) if (!IS_ERR(clnt->cl_dentry)) {
dput(clnt->cl_dentry); dput(clnt->cl_dentry);
rpc_put_mount();
}
kfree(clnt); kfree(clnt);
return 0; return 0;
} }
......
...@@ -435,14 +435,17 @@ static struct rpc_filelist authfiles[] = { ...@@ -435,14 +435,17 @@ static struct rpc_filelist authfiles[] = {
}, },
}; };
static int struct vfsmount *rpc_get_mount(void)
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 void rpc_put_mount(void)
rpc_put_mount(void)
{ {
simple_release_fs(&rpc_mount, &rpc_mount_count); simple_release_fs(&rpc_mount, &rpc_mount_count);
} }
...@@ -452,12 +455,13 @@ rpc_lookup_parent(char *path, struct nameidata *nd) ...@@ -452,12 +455,13 @@ rpc_lookup_parent(char *path, struct nameidata *nd)
{ {
if (path[0] == '\0') if (path[0] == '\0')
return -ENOENT; return -ENOENT;
if (rpc_get_mount()) { nd->mnt = rpc_get_mount();
if (IS_ERR(nd->mnt)) {
printk(KERN_WARNING "%s: %s failed to mount " printk(KERN_WARNING "%s: %s failed to mount "
"pseudofilesystem \n", __FILE__, __FUNCTION__); "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->dentry = dget(rpc_mount->mnt_root);
nd->last_type = LAST_ROOT; nd->last_type = LAST_ROOT;
nd->flags = LOOKUP_PARENT; nd->flags = LOOKUP_PARENT;
...@@ -594,7 +598,6 @@ __rpc_mkdir(struct inode *dir, struct dentry *dentry) ...@@ -594,7 +598,6 @@ __rpc_mkdir(struct inode *dir, struct dentry *dentry)
d_instantiate(dentry, inode); d_instantiate(dentry, inode);
dir->i_nlink++; dir->i_nlink++;
inode_dir_notify(dir, DN_CREATE); inode_dir_notify(dir, DN_CREATE);
rpc_get_mount();
return 0; return 0;
out_err: out_err:
printk(KERN_WARNING "%s: %s failed to allocate inode for dentry %s\n", 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) ...@@ -615,7 +618,6 @@ __rpc_rmdir(struct inode *dir, struct dentry *dentry)
if (!error) { if (!error) {
inode_dir_notify(dir, DN_DELETE); inode_dir_notify(dir, DN_DELETE);
d_drop(dentry); d_drop(dentry);
rpc_put_mount();
} }
return 0; return 0;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment