diff options
author | Stanislav Kinsbursky <skinsbursky@parallels.com> | 2013-06-24 03:52:38 -0400 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2013-06-28 15:41:18 -0400 |
commit | 384816051ca9125cd54750e59c780c2a2655fa4f (patch) | |
tree | b7ef1f57a54d747f750c2ad8c8974b236ff9febf /net/sunrpc/clnt.c | |
parent | 52fcac988ae6d5a902e9c1d79fc11ba5ec9361e7 (diff) |
SUNRPC: fix races on PipeFS MOUNT notifications
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>
Cc: stable@vger.kernel.org
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'net/sunrpc/clnt.c')
-rw-r--r-- | net/sunrpc/clnt.c | 26 |
1 files changed, 15 insertions, 11 deletions
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index 5a750b9c3640..b827a4b91975 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, | |||
157 | } | 157 | } |
158 | 158 | ||
159 | static int | 159 | static int |
160 | rpc_setup_pipedir(struct rpc_clnt *clnt, const char *dir_name) | 160 | rpc_setup_pipedir(struct rpc_clnt *clnt, const char *dir_name, |
161 | struct super_block *pipefs_sb) | ||
161 | { | 162 | { |
162 | struct net *net = rpc_net_ns(clnt); | ||
163 | struct super_block *pipefs_sb; | ||
164 | struct dentry *dentry; | 163 | struct dentry *dentry; |
165 | 164 | ||
166 | clnt->cl_dentry = NULL; | 165 | clnt->cl_dentry = NULL; |
167 | if (dir_name == NULL) | 166 | if (dir_name == NULL) |
168 | return 0; | 167 | return 0; |
169 | pipefs_sb = rpc_get_sb_net(net); | ||
170 | if (!pipefs_sb) | ||
171 | return 0; | ||
172 | dentry = rpc_setup_pipedir_sb(pipefs_sb, clnt, dir_name); | 168 | dentry = rpc_setup_pipedir_sb(pipefs_sb, clnt, dir_name); |
173 | rpc_put_sb_net(net); | ||
174 | if (IS_ERR(dentry)) | 169 | if (IS_ERR(dentry)) |
175 | return PTR_ERR(dentry); | 170 | return PTR_ERR(dentry); |
176 | clnt->cl_dentry = dentry; | 171 | clnt->cl_dentry = dentry; |
@@ -296,6 +291,7 @@ static struct rpc_clnt * rpc_new_client(const struct rpc_create_args *args, stru | |||
296 | struct rpc_clnt *clnt = NULL; | 291 | struct rpc_clnt *clnt = NULL; |
297 | struct rpc_auth *auth; | 292 | struct rpc_auth *auth; |
298 | int err; | 293 | int err; |
294 | struct super_block *pipefs_sb; | ||
299 | 295 | ||
300 | /* sanity check the name before trying to print it */ | 296 | /* sanity check the name before trying to print it */ |
301 | dprintk("RPC: creating %s client for %s (xprt %p)\n", | 297 | dprintk("RPC: creating %s client for %s (xprt %p)\n", |
@@ -354,9 +350,12 @@ static struct rpc_clnt * rpc_new_client(const struct rpc_create_args *args, stru | |||
354 | 350 | ||
355 | atomic_set(&clnt->cl_count, 1); | 351 | atomic_set(&clnt->cl_count, 1); |
356 | 352 | ||
357 | err = rpc_setup_pipedir(clnt, program->pipe_dir_name); | 353 | pipefs_sb = rpc_get_sb_net(rpc_net_ns(clnt)); |
358 | if (err < 0) | 354 | if (pipefs_sb) { |
359 | goto out_no_path; | 355 | err = rpc_setup_pipedir(clnt, program->pipe_dir_name, pipefs_sb); |
356 | if (err) | ||
357 | goto out_no_path; | ||
358 | } | ||
360 | 359 | ||
361 | auth = rpcauth_create(args->authflavor, clnt); | 360 | auth = rpcauth_create(args->authflavor, clnt); |
362 | if (IS_ERR(auth)) { | 361 | if (IS_ERR(auth)) { |
@@ -369,11 +368,16 @@ static struct rpc_clnt * rpc_new_client(const struct rpc_create_args *args, stru | |||
369 | /* save the nodename */ | 368 | /* save the nodename */ |
370 | rpc_clnt_set_nodename(clnt, utsname()->nodename); | 369 | rpc_clnt_set_nodename(clnt, utsname()->nodename); |
371 | rpc_register_client(clnt); | 370 | rpc_register_client(clnt); |
371 | if (pipefs_sb) | ||
372 | rpc_put_sb_net(rpc_net_ns(clnt)); | ||
372 | return clnt; | 373 | return clnt; |
373 | 374 | ||
374 | out_no_auth: | 375 | out_no_auth: |
375 | rpc_clnt_remove_pipedir(clnt); | 376 | if (pipefs_sb) |
377 | __rpc_clnt_remove_pipedir(clnt); | ||
376 | out_no_path: | 378 | out_no_path: |
379 | if (pipefs_sb) | ||
380 | rpc_put_sb_net(rpc_net_ns(clnt)); | ||
377 | kfree(clnt->cl_principal); | 381 | kfree(clnt->cl_principal); |
378 | out_no_principal: | 382 | out_no_principal: |
379 | rpc_free_iostats(clnt->cl_metrics); | 383 | rpc_free_iostats(clnt->cl_metrics); |