aboutsummaryrefslogtreecommitdiffstats
path: root/net/sunrpc/clnt.c
diff options
context:
space:
mode:
authorTrond Myklebust <Trond.Myklebust@netapp.com>2010-09-12 19:55:25 -0400
committerTrond Myklebust <Trond.Myklebust@netapp.com>2010-09-12 19:55:25 -0400
commit006abe887c5e637d059c44310de6c92f36aded3b (patch)
tree542ab0f1d56b4d9681c8d61fbf77c9a46062e661 /net/sunrpc/clnt.c
parent5a67657a2e90c9e4a48518f95d4ba7777aa20fbb (diff)
SUNRPC: Fix a race in rpc_info_open
There is a race between rpc_info_open and rpc_release_client() in that nothing stops a process from opening the file after the clnt->cl_kref goes to zero. Fix this by using atomic_inc_unless_zero()... Reported-by: J. Bruce Fields <bfields@redhat.com> Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com> Cc: stable@kernel.org
Diffstat (limited to 'net/sunrpc/clnt.c')
-rw-r--r--net/sunrpc/clnt.c26
1 files changed, 12 insertions, 14 deletions
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c
index 657aac630fc9..3a8f53e7ba07 100644
--- a/net/sunrpc/clnt.c
+++ b/net/sunrpc/clnt.c
@@ -226,7 +226,7 @@ static struct rpc_clnt * rpc_new_client(const struct rpc_create_args *args, stru
226 goto out_no_principal; 226 goto out_no_principal;
227 } 227 }
228 228
229 kref_init(&clnt->cl_kref); 229 atomic_set(&clnt->cl_count, 1);
230 230
231 err = rpc_setup_pipedir(clnt, program->pipe_dir_name); 231 err = rpc_setup_pipedir(clnt, program->pipe_dir_name);
232 if (err < 0) 232 if (err < 0)
@@ -390,14 +390,14 @@ rpc_clone_client(struct rpc_clnt *clnt)
390 if (new->cl_principal == NULL) 390 if (new->cl_principal == NULL)
391 goto out_no_principal; 391 goto out_no_principal;
392 } 392 }
393 kref_init(&new->cl_kref); 393 atomic_set(&new->cl_count, 1);
394 err = rpc_setup_pipedir(new, clnt->cl_program->pipe_dir_name); 394 err = rpc_setup_pipedir(new, clnt->cl_program->pipe_dir_name);
395 if (err != 0) 395 if (err != 0)
396 goto out_no_path; 396 goto out_no_path;
397 if (new->cl_auth) 397 if (new->cl_auth)
398 atomic_inc(&new->cl_auth->au_count); 398 atomic_inc(&new->cl_auth->au_count);
399 xprt_get(clnt->cl_xprt); 399 xprt_get(clnt->cl_xprt);
400 kref_get(&clnt->cl_kref); 400 atomic_inc(&clnt->cl_count);
401 rpc_register_client(new); 401 rpc_register_client(new);
402 rpciod_up(); 402 rpciod_up();
403 return new; 403 return new;
@@ -465,10 +465,8 @@ EXPORT_SYMBOL_GPL(rpc_shutdown_client);
465 * Free an RPC client 465 * Free an RPC client
466 */ 466 */
467static void 467static void
468rpc_free_client(struct kref *kref) 468rpc_free_client(struct rpc_clnt *clnt)
469{ 469{
470 struct rpc_clnt *clnt = container_of(kref, struct rpc_clnt, cl_kref);
471
472 dprintk("RPC: destroying %s client for %s\n", 470 dprintk("RPC: destroying %s client for %s\n",
473 clnt->cl_protname, clnt->cl_server); 471 clnt->cl_protname, clnt->cl_server);
474 if (!IS_ERR(clnt->cl_path.dentry)) { 472 if (!IS_ERR(clnt->cl_path.dentry)) {
@@ -495,12 +493,10 @@ out_free:
495 * Free an RPC client 493 * Free an RPC client
496 */ 494 */
497static void 495static void
498rpc_free_auth(struct kref *kref) 496rpc_free_auth(struct rpc_clnt *clnt)
499{ 497{
500 struct rpc_clnt *clnt = container_of(kref, struct rpc_clnt, cl_kref);
501
502 if (clnt->cl_auth == NULL) { 498 if (clnt->cl_auth == NULL) {
503 rpc_free_client(kref); 499 rpc_free_client(clnt);
504 return; 500 return;
505 } 501 }
506 502
@@ -509,10 +505,11 @@ rpc_free_auth(struct kref *kref)
509 * release remaining GSS contexts. This mechanism ensures 505 * release remaining GSS contexts. This mechanism ensures
510 * that it can do so safely. 506 * that it can do so safely.
511 */ 507 */
512 kref_init(kref); 508 atomic_inc(&clnt->cl_count);
513 rpcauth_release(clnt->cl_auth); 509 rpcauth_release(clnt->cl_auth);
514 clnt->cl_auth = NULL; 510 clnt->cl_auth = NULL;
515 kref_put(kref, rpc_free_client); 511 if (atomic_dec_and_test(&clnt->cl_count))
512 rpc_free_client(clnt);
516} 513}
517 514
518/* 515/*
@@ -525,7 +522,8 @@ rpc_release_client(struct rpc_clnt *clnt)
525 522
526 if (list_empty(&clnt->cl_tasks)) 523 if (list_empty(&clnt->cl_tasks))
527 wake_up(&destroy_wait); 524 wake_up(&destroy_wait);
528 kref_put(&clnt->cl_kref, rpc_free_auth); 525 if (atomic_dec_and_test(&clnt->cl_count))
526 rpc_free_auth(clnt);
529} 527}
530 528
531/** 529/**
@@ -588,7 +586,7 @@ void rpc_task_set_client(struct rpc_task *task, struct rpc_clnt *clnt)
588 if (clnt != NULL) { 586 if (clnt != NULL) {
589 rpc_task_release_client(task); 587 rpc_task_release_client(task);
590 task->tk_client = clnt; 588 task->tk_client = clnt;
591 kref_get(&clnt->cl_kref); 589 atomic_inc(&clnt->cl_count);
592 if (clnt->cl_softrtry) 590 if (clnt->cl_softrtry)
593 task->tk_flags |= RPC_TASK_SOFT; 591 task->tk_flags |= RPC_TASK_SOFT;
594 /* Add to the client's list of all tasks */ 592 /* Add to the client's list of all tasks */