+++ /dev/null
-From 384816051ca9125cd54750e59c780c2a2655fa4f Mon Sep 17 00:00:00 2001
-From: Stanislav Kinsbursky <skinsbursky@parallels.com>
-Date: Mon, 24 Jun 2013 11:52:38 +0400
-Subject: SUNRPC: fix races on PipeFS MOUNT notifications
-
-From: Stanislav Kinsbursky <skinsbursky@parallels.com>
-
-commit 384816051ca9125cd54750e59c780c2a2655fa4f upstream.
-
-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 <skinsbursky@parallels.com>
-Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
-Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-
----
- net/sunrpc/clnt.c | 26 +++++++++++++++-----------
- net/sunrpc/rpc_pipe.c | 3 +++
- 2 files changed, 18 insertions(+), 11 deletions(-)
-
---- a/net/sunrpc/clnt.c
-+++ b/net/sunrpc/clnt.c
-@@ -157,20 +157,15 @@ static struct dentry *rpc_setup_pipedir_
- }
-
- 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;
-@@ -296,6 +291,7 @@ static struct rpc_clnt * rpc_new_client(
- struct rpc_clnt *clnt = NULL;
- struct rpc_auth *auth;
- int err;
-+ struct super_block *pipefs_sb;
-
- /* sanity check the name before trying to print it */
- dprintk("RPC: creating %s client for %s (xprt %p)\n",
-@@ -354,9 +350,12 @@ static struct rpc_clnt * rpc_new_client(
-
- atomic_set(&clnt->cl_count, 1);
-
-- err = rpc_setup_pipedir(clnt, program->pipe_dir_name);
-- if (err < 0)
-- goto out_no_path;
-+ pipefs_sb = rpc_get_sb_net(rpc_net_ns(clnt));
-+ if (pipefs_sb) {
-+ err = rpc_setup_pipedir(clnt, program->pipe_dir_name, pipefs_sb);
-+ if (err)
-+ goto out_no_path;
-+ }
-
- auth = rpcauth_create(args->authflavor, clnt);
- if (IS_ERR(auth)) {
-@@ -369,11 +368,16 @@ static struct rpc_clnt * rpc_new_client(
- /* save the nodename */
- rpc_clnt_set_nodename(clnt, utsname()->nodename);
- rpc_register_client(clnt);
-+ if (pipefs_sb)
-+ rpc_put_sb_net(rpc_net_ns(clnt));
- return clnt;
-
- out_no_auth:
-- rpc_clnt_remove_pipedir(clnt);
-+ if (pipefs_sb)
-+ __rpc_clnt_remove_pipedir(clnt);
- out_no_path:
-+ if (pipefs_sb)
-+ rpc_put_sb_net(rpc_net_ns(clnt));
- kfree(clnt->cl_principal);
- out_no_principal:
- rpc_free_iostats(clnt->cl_metrics);
---- a/net/sunrpc/rpc_pipe.c
-+++ b/net/sunrpc/rpc_pipe.c
-@@ -1126,6 +1126,7 @@ rpc_fill_super(struct super_block *sb, v
- 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, v
- 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;
- }
-
+++ /dev/null
-From adb6fa7ffe9031857ec14b8aab75c9ab65556cbc Mon Sep 17 00:00:00 2001
-From: Stanislav Kinsbursky <skinsbursky@parallels.com>
-Date: Wed, 26 Jun 2013 10:15:14 +0400
-Subject: SUNRPC: fix races on PipeFS UMOUNT notifications
-
-From: Stanislav Kinsbursky <skinsbursky@parallels.com>
-
-commit adb6fa7ffe9031857ec14b8aab75c9ab65556cbc upstream.
-
-CPU#0 CPU#1
------------------------------ -----------------------------
-rpc_kill_sb
-sn->pipefs_sb = NULL rpc_release_client
-(UMOUNT_EVENT) rpc_free_auth
-rpc_pipefs_event
-rpc_get_client_for_event
-!atomic_inc_not_zero(cl_count)
-<skip the client>
- atomic_inc(cl_count)
- rpc_free_client
- rpc_clnt_remove_pipedir
- <skip client dir removing>
-
-To fix this, this patch does the following:
-
-1) Calls RPC_PIPEFS_UMOUNT notification with sn->pipefs_sb_lock being held.
-2) Removes SUNRPC client from the list AFTER pipes destroying.
-3) Doesn't hold RPC client on notification: if client in the list, then it
-can't be destroyed while sn->pipefs_sb_lock in hold by notification caller.
-
-Signed-off-by: Stanislav Kinsbursky <skinsbursky@parallels.com>
-Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
-Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-
----
- net/sunrpc/clnt.c | 5 +----
- net/sunrpc/rpc_pipe.c | 2 +-
- 2 files changed, 2 insertions(+), 5 deletions(-)
-
---- a/net/sunrpc/clnt.c
-+++ b/net/sunrpc/clnt.c
-@@ -236,8 +236,6 @@ static struct rpc_clnt *rpc_get_client_f
- continue;
- if (rpc_clnt_skip_event(clnt, event))
- continue;
-- if (atomic_inc_not_zero(&clnt->cl_count) == 0)
-- continue;
- spin_unlock(&sn->rpc_client_lock);
- return clnt;
- }
-@@ -254,7 +252,6 @@ static int rpc_pipefs_event(struct notif
-
- while ((clnt = rpc_get_client_for_event(sb->s_fs_info, event))) {
- error = __rpc_pipefs_event(clnt, event, sb);
-- rpc_release_client(clnt);
- if (error)
- break;
- }
-@@ -641,8 +638,8 @@ rpc_free_client(struct rpc_clnt *clnt)
- rcu_dereference(clnt->cl_xprt)->servername);
- if (clnt->cl_parent != clnt)
- rpc_release_client(clnt->cl_parent);
-- rpc_unregister_client(clnt);
- rpc_clnt_remove_pipedir(clnt);
-+ rpc_unregister_client(clnt);
- rpc_free_iostats(clnt->cl_metrics);
- kfree(clnt->cl_principal);
- clnt->cl_metrics = NULL;
---- a/net/sunrpc/rpc_pipe.c
-+++ b/net/sunrpc/rpc_pipe.c
-@@ -1165,12 +1165,12 @@ static void rpc_kill_sb(struct super_blo
- goto out;
- }
- sn->pipefs_sb = NULL;
-- mutex_unlock(&sn->pipefs_sb_lock);
- dprintk("RPC: sending pipefs UMOUNT notification for net %p%s\n",
- net, NET_NAME(net));
- blocking_notifier_call_chain(&rpc_pipefs_notifier_list,
- RPC_PIPEFS_UMOUNT,
- sb);
-+ mutex_unlock(&sn->pipefs_sb_lock);
- put_net(net);
- out:
- kill_litter_super(sb);