diff options
author | Trond Myklebust <Trond.Myklebust@netapp.com> | 2006-11-11 22:18:03 -0500 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2006-12-06 10:46:25 -0500 |
commit | e6b3c4db6fbcd0d33720696f37790d6b8be12313 (patch) | |
tree | 24ad4a93b00ba7236b9a2d896fd6cb59a1dc2334 /net/sunrpc/sched.c | |
parent | cc4dc59e5580d6c0de1685a25b74d32175f43434 (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.c | 80 |
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 | ||
269 | static 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 | */ |
272 | static inline void rpc_mark_complete_task(struct rpc_task *task) | 286 | static 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, | |||
348 | void rpc_sleep_on(struct rpc_wait_queue *q, struct rpc_task *task, | 361 | void 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 | ||
852 | void rpc_release_task(struct rpc_task *task) | 857 | |
858 | void 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 | } | ||
879 | EXPORT_SYMBOL(rpc_put_task); | ||
880 | |||
881 | void 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 | /** |