diff options
Diffstat (limited to 'net/sunrpc')
-rw-r--r-- | net/sunrpc/sched.c | 78 |
1 files changed, 59 insertions, 19 deletions
diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c index 2d74a1672028..82d158dad16d 100644 --- a/net/sunrpc/sched.c +++ b/net/sunrpc/sched.c | |||
@@ -264,6 +264,35 @@ void rpc_init_wait_queue(struct rpc_wait_queue *queue, const char *qname) | |||
264 | } | 264 | } |
265 | EXPORT_SYMBOL(rpc_init_wait_queue); | 265 | EXPORT_SYMBOL(rpc_init_wait_queue); |
266 | 266 | ||
267 | static int rpc_wait_bit_interruptible(void *word) | ||
268 | { | ||
269 | if (signal_pending(current)) | ||
270 | return -ERESTARTSYS; | ||
271 | schedule(); | ||
272 | return 0; | ||
273 | } | ||
274 | |||
275 | /* | ||
276 | * Mark an RPC call as having completed by clearing the 'active' bit | ||
277 | */ | ||
278 | static inline void rpc_mark_complete_task(struct rpc_task *task) | ||
279 | { | ||
280 | rpc_clear_active(task); | ||
281 | wake_up_bit(&task->tk_runstate, RPC_TASK_ACTIVE); | ||
282 | } | ||
283 | |||
284 | /* | ||
285 | * Allow callers to wait for completion of an RPC call | ||
286 | */ | ||
287 | int __rpc_wait_for_completion_task(struct rpc_task *task, int (*action)(void *)) | ||
288 | { | ||
289 | if (action == NULL) | ||
290 | action = rpc_wait_bit_interruptible; | ||
291 | return wait_on_bit(&task->tk_runstate, RPC_TASK_ACTIVE, | ||
292 | action, TASK_INTERRUPTIBLE); | ||
293 | } | ||
294 | EXPORT_SYMBOL(__rpc_wait_for_completion_task); | ||
295 | |||
267 | /* | 296 | /* |
268 | * Make an RPC task runnable. | 297 | * Make an RPC task runnable. |
269 | * | 298 | * |
@@ -299,10 +328,7 @@ static void rpc_make_runnable(struct rpc_task *task) | |||
299 | static inline void | 328 | static inline void |
300 | rpc_schedule_run(struct rpc_task *task) | 329 | rpc_schedule_run(struct rpc_task *task) |
301 | { | 330 | { |
302 | /* Don't run a child twice! */ | 331 | rpc_set_active(task); |
303 | if (RPC_IS_ACTIVATED(task)) | ||
304 | return; | ||
305 | task->tk_active = 1; | ||
306 | rpc_make_runnable(task); | 332 | rpc_make_runnable(task); |
307 | } | 333 | } |
308 | 334 | ||
@@ -324,8 +350,7 @@ static void __rpc_sleep_on(struct rpc_wait_queue *q, struct rpc_task *task, | |||
324 | } | 350 | } |
325 | 351 | ||
326 | /* Mark the task as being activated if so needed */ | 352 | /* Mark the task as being activated if so needed */ |
327 | if (!RPC_IS_ACTIVATED(task)) | 353 | rpc_set_active(task); |
328 | task->tk_active = 1; | ||
329 | 354 | ||
330 | __rpc_add_wait_queue(q, task); | 355 | __rpc_add_wait_queue(q, task); |
331 | 356 | ||
@@ -580,14 +605,6 @@ void rpc_exit_task(struct rpc_task *task) | |||
580 | } | 605 | } |
581 | EXPORT_SYMBOL(rpc_exit_task); | 606 | EXPORT_SYMBOL(rpc_exit_task); |
582 | 607 | ||
583 | static int rpc_wait_bit_interruptible(void *word) | ||
584 | { | ||
585 | if (signal_pending(current)) | ||
586 | return -ERESTARTSYS; | ||
587 | schedule(); | ||
588 | return 0; | ||
589 | } | ||
590 | |||
591 | /* | 608 | /* |
592 | * This is the RPC `scheduler' (or rather, the finite state machine). | 609 | * This is the RPC `scheduler' (or rather, the finite state machine). |
593 | */ | 610 | */ |
@@ -680,6 +697,8 @@ static int __rpc_execute(struct rpc_task *task) | |||
680 | dprintk("RPC: %4d exit() = %d\n", task->tk_pid, task->tk_status); | 697 | dprintk("RPC: %4d exit() = %d\n", task->tk_pid, task->tk_status); |
681 | status = task->tk_status; | 698 | status = task->tk_status; |
682 | 699 | ||
700 | /* Wake up anyone who is waiting for task completion */ | ||
701 | rpc_mark_complete_task(task); | ||
683 | /* Release all resources associated with the task */ | 702 | /* Release all resources associated with the task */ |
684 | rpc_release_task(task); | 703 | rpc_release_task(task); |
685 | return status; | 704 | return status; |
@@ -697,9 +716,7 @@ static int __rpc_execute(struct rpc_task *task) | |||
697 | int | 716 | int |
698 | rpc_execute(struct rpc_task *task) | 717 | rpc_execute(struct rpc_task *task) |
699 | { | 718 | { |
700 | BUG_ON(task->tk_active); | 719 | rpc_set_active(task); |
701 | |||
702 | task->tk_active = 1; | ||
703 | rpc_set_running(task); | 720 | rpc_set_running(task); |
704 | return __rpc_execute(task); | 721 | return __rpc_execute(task); |
705 | } | 722 | } |
@@ -761,6 +778,7 @@ void rpc_init_task(struct rpc_task *task, struct rpc_clnt *clnt, int flags, cons | |||
761 | init_timer(&task->tk_timer); | 778 | init_timer(&task->tk_timer); |
762 | task->tk_timer.data = (unsigned long) task; | 779 | task->tk_timer.data = (unsigned long) task; |
763 | task->tk_timer.function = (void (*)(unsigned long)) rpc_run_timer; | 780 | task->tk_timer.function = (void (*)(unsigned long)) rpc_run_timer; |
781 | atomic_set(&task->tk_count, 1); | ||
764 | task->tk_client = clnt; | 782 | task->tk_client = clnt; |
765 | task->tk_flags = flags; | 783 | task->tk_flags = flags; |
766 | task->tk_ops = tk_ops; | 784 | task->tk_ops = tk_ops; |
@@ -848,11 +866,13 @@ void rpc_release_task(struct rpc_task *task) | |||
848 | { | 866 | { |
849 | const struct rpc_call_ops *tk_ops = task->tk_ops; | 867 | const struct rpc_call_ops *tk_ops = task->tk_ops; |
850 | void *calldata = task->tk_calldata; | 868 | void *calldata = task->tk_calldata; |
851 | dprintk("RPC: %4d release task\n", task->tk_pid); | ||
852 | 869 | ||
853 | #ifdef RPC_DEBUG | 870 | #ifdef RPC_DEBUG |
854 | BUG_ON(task->tk_magic != RPC_TASK_MAGIC_ID); | 871 | BUG_ON(task->tk_magic != RPC_TASK_MAGIC_ID); |
855 | #endif | 872 | #endif |
873 | if (!atomic_dec_and_test(&task->tk_count)) | ||
874 | return; | ||
875 | dprintk("RPC: %4d release task\n", task->tk_pid); | ||
856 | 876 | ||
857 | /* Remove from global task list */ | 877 | /* Remove from global task list */ |
858 | spin_lock(&rpc_sched_lock); | 878 | spin_lock(&rpc_sched_lock); |
@@ -860,7 +880,6 @@ void rpc_release_task(struct rpc_task *task) | |||
860 | spin_unlock(&rpc_sched_lock); | 880 | spin_unlock(&rpc_sched_lock); |
861 | 881 | ||
862 | BUG_ON (RPC_IS_QUEUED(task)); | 882 | BUG_ON (RPC_IS_QUEUED(task)); |
863 | task->tk_active = 0; | ||
864 | 883 | ||
865 | /* Synchronously delete any running timer */ | 884 | /* Synchronously delete any running timer */ |
866 | rpc_delete_timer(task); | 885 | rpc_delete_timer(task); |
@@ -886,6 +905,27 @@ void rpc_release_task(struct rpc_task *task) | |||
886 | } | 905 | } |
887 | 906 | ||
888 | /** | 907 | /** |
908 | * rpc_run_task - Allocate a new RPC task, then run rpc_execute against it | ||
909 | * @clnt - pointer to RPC client | ||
910 | * @flags - RPC flags | ||
911 | * @ops - RPC call ops | ||
912 | * @data - user call data | ||
913 | */ | ||
914 | struct rpc_task *rpc_run_task(struct rpc_clnt *clnt, int flags, | ||
915 | const struct rpc_call_ops *ops, | ||
916 | void *data) | ||
917 | { | ||
918 | struct rpc_task *task; | ||
919 | task = rpc_new_task(clnt, flags, ops, data); | ||
920 | if (task == NULL) | ||
921 | return ERR_PTR(-ENOMEM); | ||
922 | atomic_inc(&task->tk_count); | ||
923 | rpc_execute(task); | ||
924 | return task; | ||
925 | } | ||
926 | EXPORT_SYMBOL(rpc_run_task); | ||
927 | |||
928 | /** | ||
889 | * rpc_find_parent - find the parent of a child task. | 929 | * rpc_find_parent - find the parent of a child task. |
890 | * @child: child task | 930 | * @child: child task |
891 | * | 931 | * |