aboutsummaryrefslogtreecommitdiffstats
path: root/net/sunrpc/sched.c
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/sunrpc/sched.c
parentcc4dc59e5580d6c0de1685a25b74d32175f43434 (diff)
Fix a second potential rpc_wakeup race...
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'net/sunrpc/sched.c')
-rw-r--r--net/sunrpc/sched.c80
1 files changed, 47 insertions, 33 deletions
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/**