Below are races, when RPC client can be created without PiepFS dentries

CPU#0                                   CPU#1
-----------------------------           -----------------------------
rpc_new_client                          rpc_fill_super
rpc_setup_pipedir
mutex_lock(&sn->pipefs_sb_lock)
rpc_get_sb_net == NULL
(no per-net PipeFS superblock)
                                        sn->pipefs_sb = sb;
                                        notifier_call_chain(MOUNT)
                                        (client is not in the list)
rpc_register_client
(client without pipes dentries)

To fix this patch:
1) makes PipeFS mount notification call with pipefs_sb_lock being held.
2) releases pipefs_sb_lock on new SUNRPC client creation only after
registration.

Signed-off-by: Stanislav Kinsbursky <skinsbur...@parallels.com>
Cc: sta...@vger.kernel.org
---
 net/sunrpc/clnt.c     |   24 +++++++++++++-----------
 net/sunrpc/rpc_pipe.c |    3 +++
 2 files changed, 16 insertions(+), 11 deletions(-)

diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c
index 4bf2409..48888ee 100644
--- a/net/sunrpc/clnt.c
+++ b/net/sunrpc/clnt.c
@@ -157,20 +157,15 @@ static struct dentry *rpc_setup_pipedir_sb(struct 
super_block *sb,
 }
 
 static int
-rpc_setup_pipedir(struct rpc_clnt *clnt, const char *dir_name)
+rpc_setup_pipedir(struct rpc_clnt *clnt, const char *dir_name,
+                 struct super_block *pipefs_sb)
 {
-       struct net *net = rpc_net_ns(clnt);
-       struct super_block *pipefs_sb;
        struct dentry *dentry;
 
        clnt->cl_dentry = NULL;
        if (dir_name == NULL)
                return 0;
-       pipefs_sb = rpc_get_sb_net(net);
-       if (!pipefs_sb)
-               return 0;
        dentry = rpc_setup_pipedir_sb(pipefs_sb, clnt, dir_name);
-       rpc_put_sb_net(net);
        if (IS_ERR(dentry))
                return PTR_ERR(dentry);
        clnt->cl_dentry = dentry;
@@ -294,11 +289,16 @@ static int rpc_client_register(const struct 
rpc_create_args *args,
 {
        const struct rpc_program *program = args->program;
        struct rpc_auth *auth;
+       struct net *net = rpc_net_ns(clnt);
+       struct super_block *pipefs_sb;
        int err = 0;
 
-       err = rpc_setup_pipedir(clnt, program->pipe_dir_name);
-       if (err < 0)
-               goto out;
+       pipefs_sb = rpc_get_sb_net(net);
+       if (pipefs_sb) {
+               err = rpc_setup_pipedir(clnt, program->pipe_dir_name, 
pipefs_sb);
+               if (err)
+                       goto out;
+       }
 
        auth = rpcauth_create(args->authflavor, clnt);
        if (IS_ERR(auth)) {
@@ -310,10 +310,12 @@ static int rpc_client_register(const struct 
rpc_create_args *args,
 
        rpc_register_client(clnt);
 out:
+       if (pipefs_sb)
+               rpc_put_sb_net(net);
        return err;
 
 err_auth:
-       rpc_clnt_remove_pipedir(clnt);
+       __rpc_clnt_remove_pipedir(clnt);
        goto out;
 }
 
diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c
index e7ce4b3..c512448 100644
--- a/net/sunrpc/rpc_pipe.c
+++ b/net/sunrpc/rpc_pipe.c
@@ -1126,6 +1126,7 @@ rpc_fill_super(struct super_block *sb, void *data, int 
silent)
                return -ENOMEM;
        dprintk("RPC:       sending pipefs MOUNT notification for net %p%s\n",
                net, NET_NAME(net));
+       mutex_lock(&sn->pipefs_sb_lock);
        sn->pipefs_sb = sb;
        err = blocking_notifier_call_chain(&rpc_pipefs_notifier_list,
                                           RPC_PIPEFS_MOUNT,
@@ -1133,6 +1134,7 @@ rpc_fill_super(struct super_block *sb, void *data, int 
silent)
        if (err)
                goto err_depopulate;
        sb->s_fs_info = get_net(net);
+       mutex_unlock(&sn->pipefs_sb_lock);
        return 0;
 
 err_depopulate:
@@ -1141,6 +1143,7 @@ err_depopulate:
                                           sb);
        sn->pipefs_sb = NULL;
        __rpc_depopulate(root, files, RPCAUTH_lockd, RPCAUTH_RootEOF);
+       mutex_unlock(&sn->pipefs_sb_lock);
        return err;
 }
 

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to