]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - net/sunrpc/clnt.c
SUNRPC: handle RPC client pipefs dentries by network namespace aware routines
[karo-tx-linux.git] / net / sunrpc / clnt.c
index f0268ea7e71121f3c07f159b6f46732b4074dd73..5ef192c1a57cf3cf26c3a5c6a93833fb83e43bc0 100644 (file)
@@ -93,52 +93,89 @@ static void rpc_unregister_client(struct rpc_clnt *clnt)
        spin_unlock(&rpc_client_lock);
 }
 
-static int
-rpc_setup_pipedir(struct rpc_clnt *clnt, char *dir_name)
+static void __rpc_clnt_remove_pipedir(struct rpc_clnt *clnt)
+{
+       if (clnt->cl_path.dentry)
+               rpc_remove_client_dir(clnt->cl_path.dentry);
+       clnt->cl_path.dentry = NULL;
+}
+
+static void rpc_clnt_remove_pipedir(struct rpc_clnt *clnt)
+{
+       struct super_block *pipefs_sb;
+       int put_mnt = 0;
+
+       pipefs_sb = rpc_get_sb_net(clnt->cl_xprt->xprt_net);
+       if (pipefs_sb) {
+               if (clnt->cl_path.dentry)
+                       put_mnt = 1;
+               __rpc_clnt_remove_pipedir(clnt);
+               rpc_put_sb_net(clnt->cl_xprt->xprt_net);
+       }
+       if (put_mnt)
+               rpc_put_mount();
+}
+
+static struct dentry *rpc_setup_pipedir_sb(struct super_block *sb,
+                                   struct rpc_clnt *clnt, char *dir_name)
 {
        static uint32_t clntid;
-       struct path path, dir;
        char name[15];
        struct qstr q = {
                .name = name,
        };
+       struct dentry *dir, *dentry;
        int error;
 
-       clnt->cl_path.mnt = ERR_PTR(-ENOENT);
-       clnt->cl_path.dentry = ERR_PTR(-ENOENT);
-       if (dir_name == NULL)
-               return 0;
-
-       path.mnt = rpc_get_mount();
-       if (IS_ERR(path.mnt))
-               return PTR_ERR(path.mnt);
-       error = vfs_path_lookup(path.mnt->mnt_root, path.mnt, dir_name, 0, &dir);
-       if (error)
-               goto err;
-
+       dir = rpc_d_lookup_sb(sb, dir_name);
+       if (dir == NULL)
+               return dir;
        for (;;) {
                q.len = snprintf(name, sizeof(name), "clnt%x", (unsigned int)clntid++);
                name[sizeof(name) - 1] = '\0';
                q.hash = full_name_hash(q.name, q.len);
-               path.dentry = rpc_create_client_dir(dir.dentry, &q, clnt);
-               if (!IS_ERR(path.dentry))
+               dentry = rpc_create_client_dir(dir, &q, clnt);
+               if (!IS_ERR(dentry))
                        break;
-               error = PTR_ERR(path.dentry);
+               error = PTR_ERR(dentry);
                if (error != -EEXIST) {
                        printk(KERN_INFO "RPC: Couldn't create pipefs entry"
                                        " %s/%s, error %d\n",
                                        dir_name, name, error);
-                       goto err_path_put;
+                       break;
                }
        }
-       path_put(&dir);
+       dput(dir);
+       return dentry;
+}
+
+static int
+rpc_setup_pipedir(struct rpc_clnt *clnt, char *dir_name)
+{
+       struct super_block *pipefs_sb;
+       struct path path;
+
+       clnt->cl_path.mnt = ERR_PTR(-ENOENT);
+       clnt->cl_path.dentry = NULL;
+       if (dir_name == NULL)
+               return 0;
+
+       path.mnt = rpc_get_mount();
+       if (IS_ERR(path.mnt))
+               return PTR_ERR(path.mnt);
+       pipefs_sb = rpc_get_sb_net(clnt->cl_xprt->xprt_net);
+       if (!pipefs_sb) {
+               rpc_put_mount();
+               return -ENOENT;
+       }
+       path.dentry = rpc_setup_pipedir_sb(pipefs_sb, clnt, dir_name);
+       rpc_put_sb_net(clnt->cl_xprt->xprt_net);
+       if (IS_ERR(path.dentry)) {
+               rpc_put_mount();
+               return PTR_ERR(path.dentry);
+       }
        clnt->cl_path = path;
        return 0;
-err_path_put:
-       path_put(&dir);
-err:
-       rpc_put_mount();
-       return error;
 }
 
 static struct rpc_clnt * rpc_new_client(const struct rpc_create_args *args, struct rpc_xprt *xprt)
@@ -246,10 +283,7 @@ static struct rpc_clnt * rpc_new_client(const struct rpc_create_args *args, stru
        return clnt;
 
 out_no_auth:
-       if (!IS_ERR(clnt->cl_path.dentry)) {
-               rpc_remove_client_dir(clnt->cl_path.dentry);
-               rpc_put_mount();
-       }
+       rpc_clnt_remove_pipedir(clnt);
 out_no_path:
        kfree(clnt->cl_principal);
 out_no_principal:
@@ -474,10 +508,7 @@ rpc_free_client(struct rpc_clnt *clnt)
 {
        dprintk("RPC:       destroying %s client for %s\n",
                        clnt->cl_protname, clnt->cl_server);
-       if (!IS_ERR(clnt->cl_path.dentry)) {
-               rpc_remove_client_dir(clnt->cl_path.dentry);
-               rpc_put_mount();
-       }
+       rpc_clnt_remove_pipedir(clnt);
        if (clnt->cl_parent != clnt) {
                rpc_release_client(clnt->cl_parent);
                goto out_free;