aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorTrond Myklebust <Trond.Myklebust@netapp.com>2006-11-11 22:18:03 -0500
committerTrond Myklebust <Trond.Myklebust@netapp.com>2006-12-06 10:46:25 -0500
commite6b3c4db6fbcd0d33720696f37790d6b8be12313 (patch)
tree24ad4a93b00ba7236b9a2d896fd6cb59a1dc2334 /net
parentcc4dc59e5580d6c0de1685a25b74d32175f43434 (diff)
Fix a second potential rpc_wakeup race...
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'net')
-rw-r--r--net/sunrpc/clnt.c19
-rw-r--r--net/sunrpc/pmap_clnt.c2
-rw-r--r--net/sunrpc/sched.c80
-rw-r--r--net/sunrpc/sunrpc_syms.c1
4 files changed, 58 insertions, 44 deletions
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c
index dfeea4fea95a..a323abc7ea85 100644
--- a/net/sunrpc/clnt.c
+++ b/net/sunrpc/clnt.c
@@ -466,10 +466,9 @@ int rpc_call_sync(struct rpc_clnt *clnt, struct rpc_message *msg, int flags)
466 466
467 BUG_ON(flags & RPC_TASK_ASYNC); 467 BUG_ON(flags & RPC_TASK_ASYNC);
468 468
469 status = -ENOMEM;
470 task = rpc_new_task(clnt, flags, &rpc_default_ops, NULL); 469 task = rpc_new_task(clnt, flags, &rpc_default_ops, NULL);
471 if (task == NULL) 470 if (task == NULL)
472 goto out; 471 return -ENOMEM;
473 472
474 /* Mask signals on RPC calls _and_ GSS_AUTH upcalls */ 473 /* Mask signals on RPC calls _and_ GSS_AUTH upcalls */
475 rpc_task_sigmask(task, &oldset); 474 rpc_task_sigmask(task, &oldset);
@@ -478,15 +477,17 @@ int rpc_call_sync(struct rpc_clnt *clnt, struct rpc_message *msg, int flags)
478 477
479 /* Set up the call info struct and execute the task */ 478 /* Set up the call info struct and execute the task */
480 status = task->tk_status; 479 status = task->tk_status;
481 if (status == 0) { 480 if (status != 0) {
482 atomic_inc(&task->tk_count); 481 rpc_release_task(task);
483 status = rpc_execute(task); 482 goto out;
484 if (status == 0)
485 status = task->tk_status;
486 } 483 }
487 rpc_restore_sigmask(&oldset); 484 atomic_inc(&task->tk_count);
488 rpc_release_task(task); 485 status = rpc_execute(task);
486 if (status == 0)
487 status = task->tk_status;
488 rpc_put_task(task);
489out: 489out:
490 rpc_restore_sigmask(&oldset);
490 return status; 491 return status;
491} 492}
492 493
diff --git a/net/sunrpc/pmap_clnt.c b/net/sunrpc/pmap_clnt.c
index e52afab413de..8d2e10fc3df9 100644
--- a/net/sunrpc/pmap_clnt.c
+++ b/net/sunrpc/pmap_clnt.c
@@ -134,7 +134,7 @@ void rpc_getport(struct rpc_task *task)
134 child = rpc_run_task(pmap_clnt, RPC_TASK_ASYNC, &pmap_getport_ops, map); 134 child = rpc_run_task(pmap_clnt, RPC_TASK_ASYNC, &pmap_getport_ops, map);
135 if (IS_ERR(child)) 135 if (IS_ERR(child))
136 goto bailout; 136 goto bailout;
137 rpc_release_task(child); 137 rpc_put_task(child);
138 138
139 task->tk_xprt->stat.bind_count++; 139 task->tk_xprt->stat.bind_count++;
140 return; 140 return;
diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c
index b57d4062d429..66d01365f3a5 100644
--- a/net/sunrpc/sched.c
+++ b/net/sunrpc/sched.c
@@ -266,12 +266,28 @@ static int rpc_wait_bit_interruptible(void *word)
266 return 0; 266 return 0;
267} 267}
268 268
269static void rpc_set_active(struct rpc_task *task)
270{
271 if (test_and_set_bit(RPC_TASK_ACTIVE, &task->tk_runstate) != 0)
272 return;
273 spin_lock(&rpc_sched_lock);
274#ifdef RPC_DEBUG
275 task->tk_magic = RPC_TASK_MAGIC_ID;
276 task->tk_pid = rpc_task_id++;
277#endif
278 /* Add to global list of all tasks */
279 list_add_tail(&task->tk_task, &all_tasks);
280 spin_unlock(&rpc_sched_lock);
281}
282
269/* 283/*
270 * Mark an RPC call as having completed by clearing the 'active' bit 284 * Mark an RPC call as having completed by clearing the 'active' bit
271 */ 285 */
272static inline void rpc_mark_complete_task(struct rpc_task *task) 286static void rpc_mark_complete_task(struct rpc_task *task)
273{ 287{
274 rpc_clear_active(task); 288 smp_mb__before_clear_bit();
289 clear_bit(RPC_TASK_ACTIVE, &task->tk_runstate);
290 smp_mb__after_clear_bit();
275 wake_up_bit(&task->tk_runstate, RPC_TASK_ACTIVE); 291 wake_up_bit(&task->tk_runstate, RPC_TASK_ACTIVE);
276} 292}
277 293
@@ -335,9 +351,6 @@ static void __rpc_sleep_on(struct rpc_wait_queue *q, struct rpc_task *task,
335 return; 351 return;
336 } 352 }
337 353
338 /* Mark the task as being activated if so needed */
339 rpc_set_active(task);
340
341 __rpc_add_wait_queue(q, task); 354 __rpc_add_wait_queue(q, task);
342 355
343 BUG_ON(task->tk_callback != NULL); 356 BUG_ON(task->tk_callback != NULL);
@@ -348,6 +361,9 @@ static void __rpc_sleep_on(struct rpc_wait_queue *q, struct rpc_task *task,
348void rpc_sleep_on(struct rpc_wait_queue *q, struct rpc_task *task, 361void rpc_sleep_on(struct rpc_wait_queue *q, struct rpc_task *task,
349 rpc_action action, rpc_action timer) 362 rpc_action action, rpc_action timer)
350{ 363{
364 /* Mark the task as being activated if so needed */
365 rpc_set_active(task);
366
351 /* 367 /*
352 * Protect the queue operations. 368 * Protect the queue operations.
353 */ 369 */
@@ -673,8 +689,6 @@ static int __rpc_execute(struct rpc_task *task)
673 } 689 }
674 690
675 dprintk("RPC: %4d, return %d, status %d\n", task->tk_pid, status, task->tk_status); 691 dprintk("RPC: %4d, return %d, status %d\n", task->tk_pid, status, task->tk_status);
676 /* Wake up anyone who is waiting for task completion */
677 rpc_mark_complete_task(task);
678 /* Release all resources associated with the task */ 692 /* Release all resources associated with the task */
679 rpc_release_task(task); 693 rpc_release_task(task);
680 return status; 694 return status;
@@ -788,15 +802,6 @@ void rpc_init_task(struct rpc_task *task, struct rpc_clnt *clnt, int flags, cons
788 task->tk_flags |= RPC_TASK_NOINTR; 802 task->tk_flags |= RPC_TASK_NOINTR;
789 } 803 }
790 804
791#ifdef RPC_DEBUG
792 task->tk_magic = RPC_TASK_MAGIC_ID;
793 task->tk_pid = rpc_task_id++;
794#endif
795 /* Add to global list of all tasks */
796 spin_lock(&rpc_sched_lock);
797 list_add_tail(&task->tk_task, &all_tasks);
798 spin_unlock(&rpc_sched_lock);
799
800 BUG_ON(task->tk_ops == NULL); 805 BUG_ON(task->tk_ops == NULL);
801 806
802 /* starting timestamp */ 807 /* starting timestamp */
@@ -849,16 +854,35 @@ cleanup:
849 goto out; 854 goto out;
850} 855}
851 856
852void rpc_release_task(struct rpc_task *task) 857
858void rpc_put_task(struct rpc_task *task)
853{ 859{
854 const struct rpc_call_ops *tk_ops = task->tk_ops; 860 const struct rpc_call_ops *tk_ops = task->tk_ops;
855 void *calldata = task->tk_calldata; 861 void *calldata = task->tk_calldata;
856 862
863 if (!atomic_dec_and_test(&task->tk_count))
864 return;
865 /* Release resources */
866 if (task->tk_rqstp)
867 xprt_release(task);
868 if (task->tk_msg.rpc_cred)
869 rpcauth_unbindcred(task);
870 if (task->tk_client) {
871 rpc_release_client(task->tk_client);
872 task->tk_client = NULL;
873 }
874 if (task->tk_flags & RPC_TASK_DYNAMIC)
875 rpc_free_task(task);
876 if (tk_ops->rpc_release)
877 tk_ops->rpc_release(calldata);
878}
879EXPORT_SYMBOL(rpc_put_task);
880
881void rpc_release_task(struct rpc_task *task)
882{
857#ifdef RPC_DEBUG 883#ifdef RPC_DEBUG
858 BUG_ON(task->tk_magic != RPC_TASK_MAGIC_ID); 884 BUG_ON(task->tk_magic != RPC_TASK_MAGIC_ID);
859#endif 885#endif
860 if (!atomic_dec_and_test(&task->tk_count))
861 return;
862 dprintk("RPC: %4d release task\n", task->tk_pid); 886 dprintk("RPC: %4d release task\n", task->tk_pid);
863 887
864 /* Remove from global task list */ 888 /* Remove from global task list */
@@ -871,23 +895,13 @@ void rpc_release_task(struct rpc_task *task)
871 /* Synchronously delete any running timer */ 895 /* Synchronously delete any running timer */
872 rpc_delete_timer(task); 896 rpc_delete_timer(task);
873 897
874 /* Release resources */
875 if (task->tk_rqstp)
876 xprt_release(task);
877 if (task->tk_msg.rpc_cred)
878 rpcauth_unbindcred(task);
879 if (task->tk_client) {
880 rpc_release_client(task->tk_client);
881 task->tk_client = NULL;
882 }
883
884#ifdef RPC_DEBUG 898#ifdef RPC_DEBUG
885 task->tk_magic = 0; 899 task->tk_magic = 0;
886#endif 900#endif
887 if (task->tk_flags & RPC_TASK_DYNAMIC) 901 /* Wake up anyone who is waiting for task completion */
888 rpc_free_task(task); 902 rpc_mark_complete_task(task);
889 if (tk_ops->rpc_release) 903
890 tk_ops->rpc_release(calldata); 904 rpc_put_task(task);
891} 905}
892 906
893/** 907/**
diff --git a/net/sunrpc/sunrpc_syms.c b/net/sunrpc/sunrpc_syms.c
index 192dff5dabcb..faaf81e97720 100644
--- a/net/sunrpc/sunrpc_syms.c
+++ b/net/sunrpc/sunrpc_syms.c
@@ -33,7 +33,6 @@ EXPORT_SYMBOL(rpciod_down);
33EXPORT_SYMBOL(rpciod_up); 33EXPORT_SYMBOL(rpciod_up);
34EXPORT_SYMBOL(rpc_new_task); 34EXPORT_SYMBOL(rpc_new_task);
35EXPORT_SYMBOL(rpc_wake_up_status); 35EXPORT_SYMBOL(rpc_wake_up_status);
36EXPORT_SYMBOL(rpc_release_task);
37 36
38/* RPC client functions */ 37/* RPC client functions */
39EXPORT_SYMBOL(rpc_clone_client); 38EXPORT_SYMBOL(rpc_clone_client);