diff options
-rw-r--r-- | fs/nfs/direct.c | 1 | ||||
-rw-r--r-- | include/linux/sunrpc/sched.h | 21 | ||||
-rw-r--r-- | net/sunrpc/sched.c | 78 |
3 files changed, 78 insertions, 22 deletions
diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c index a834423942c7..ae2be0744191 100644 --- a/fs/nfs/direct.c +++ b/fs/nfs/direct.c | |||
@@ -268,7 +268,6 @@ static void nfs_direct_read_schedule(struct nfs_direct_req *dreq, | |||
268 | NFS_PROTO(inode)->read_setup(data); | 268 | NFS_PROTO(inode)->read_setup(data); |
269 | 269 | ||
270 | data->task.tk_cookie = (unsigned long) inode; | 270 | data->task.tk_cookie = (unsigned long) inode; |
271 | data->task.tk_calldata = data; | ||
272 | data->complete = nfs_direct_read_result; | 271 | data->complete = nfs_direct_read_result; |
273 | 272 | ||
274 | lock_kernel(); | 273 | lock_kernel(); |
diff --git a/include/linux/sunrpc/sched.h b/include/linux/sunrpc/sched.h index ac1326fc3e1a..94b0afa4ab05 100644 --- a/include/linux/sunrpc/sched.h +++ b/include/linux/sunrpc/sched.h | |||
@@ -42,6 +42,7 @@ struct rpc_task { | |||
42 | #ifdef RPC_DEBUG | 42 | #ifdef RPC_DEBUG |
43 | unsigned long tk_magic; /* 0xf00baa */ | 43 | unsigned long tk_magic; /* 0xf00baa */ |
44 | #endif | 44 | #endif |
45 | atomic_t tk_count; /* Reference count */ | ||
45 | struct list_head tk_task; /* global list of tasks */ | 46 | struct list_head tk_task; /* global list of tasks */ |
46 | struct rpc_clnt * tk_client; /* RPC client */ | 47 | struct rpc_clnt * tk_client; /* RPC client */ |
47 | struct rpc_rqst * tk_rqstp; /* RPC request */ | 48 | struct rpc_rqst * tk_rqstp; /* RPC request */ |
@@ -78,7 +79,6 @@ struct rpc_task { | |||
78 | struct timer_list tk_timer; /* kernel timer */ | 79 | struct timer_list tk_timer; /* kernel timer */ |
79 | unsigned long tk_timeout; /* timeout for rpc_sleep() */ | 80 | unsigned long tk_timeout; /* timeout for rpc_sleep() */ |
80 | unsigned short tk_flags; /* misc flags */ | 81 | unsigned short tk_flags; /* misc flags */ |
81 | unsigned char tk_active : 1;/* Task has been activated */ | ||
82 | unsigned char tk_priority : 2;/* Task priority */ | 82 | unsigned char tk_priority : 2;/* Task priority */ |
83 | unsigned long tk_runstate; /* Task run status */ | 83 | unsigned long tk_runstate; /* Task run status */ |
84 | struct workqueue_struct *tk_workqueue; /* Normally rpciod, but could | 84 | struct workqueue_struct *tk_workqueue; /* Normally rpciod, but could |
@@ -136,7 +136,6 @@ struct rpc_call_ops { | |||
136 | #define RPC_IS_SWAPPER(t) ((t)->tk_flags & RPC_TASK_SWAPPER) | 136 | #define RPC_IS_SWAPPER(t) ((t)->tk_flags & RPC_TASK_SWAPPER) |
137 | #define RPC_DO_ROOTOVERRIDE(t) ((t)->tk_flags & RPC_TASK_ROOTCREDS) | 137 | #define RPC_DO_ROOTOVERRIDE(t) ((t)->tk_flags & RPC_TASK_ROOTCREDS) |
138 | #define RPC_ASSASSINATED(t) ((t)->tk_flags & RPC_TASK_KILLED) | 138 | #define RPC_ASSASSINATED(t) ((t)->tk_flags & RPC_TASK_KILLED) |
139 | #define RPC_IS_ACTIVATED(t) ((t)->tk_active) | ||
140 | #define RPC_DO_CALLBACK(t) ((t)->tk_callback != NULL) | 139 | #define RPC_DO_CALLBACK(t) ((t)->tk_callback != NULL) |
141 | #define RPC_IS_SOFT(t) ((t)->tk_flags & RPC_TASK_SOFT) | 140 | #define RPC_IS_SOFT(t) ((t)->tk_flags & RPC_TASK_SOFT) |
142 | #define RPC_TASK_UNINTERRUPTIBLE(t) ((t)->tk_flags & RPC_TASK_NOINTR) | 141 | #define RPC_TASK_UNINTERRUPTIBLE(t) ((t)->tk_flags & RPC_TASK_NOINTR) |
@@ -145,6 +144,7 @@ struct rpc_call_ops { | |||
145 | #define RPC_TASK_QUEUED 1 | 144 | #define RPC_TASK_QUEUED 1 |
146 | #define RPC_TASK_WAKEUP 2 | 145 | #define RPC_TASK_WAKEUP 2 |
147 | #define RPC_TASK_HAS_TIMER 3 | 146 | #define RPC_TASK_HAS_TIMER 3 |
147 | #define RPC_TASK_ACTIVE 4 | ||
148 | 148 | ||
149 | #define RPC_IS_RUNNING(t) (test_bit(RPC_TASK_RUNNING, &(t)->tk_runstate)) | 149 | #define RPC_IS_RUNNING(t) (test_bit(RPC_TASK_RUNNING, &(t)->tk_runstate)) |
150 | #define rpc_set_running(t) (set_bit(RPC_TASK_RUNNING, &(t)->tk_runstate)) | 150 | #define rpc_set_running(t) (set_bit(RPC_TASK_RUNNING, &(t)->tk_runstate)) |
@@ -175,6 +175,15 @@ struct rpc_call_ops { | |||
175 | smp_mb__after_clear_bit(); \ | 175 | smp_mb__after_clear_bit(); \ |
176 | } while (0) | 176 | } while (0) |
177 | 177 | ||
178 | #define RPC_IS_ACTIVATED(t) (test_bit(RPC_TASK_ACTIVE, &(t)->tk_runstate)) | ||
179 | #define rpc_set_active(t) (set_bit(RPC_TASK_ACTIVE, &(t)->tk_runstate)) | ||
180 | #define rpc_clear_active(t) \ | ||
181 | do { \ | ||
182 | smp_mb__before_clear_bit(); \ | ||
183 | clear_bit(RPC_TASK_ACTIVE, &(t)->tk_runstate); \ | ||
184 | smp_mb__after_clear_bit(); \ | ||
185 | } while(0) | ||
186 | |||
178 | /* | 187 | /* |
179 | * Task priorities. | 188 | * Task priorities. |
180 | * Note: if you change these, you must also change | 189 | * Note: if you change these, you must also change |
@@ -237,6 +246,8 @@ struct rpc_wait_queue { | |||
237 | */ | 246 | */ |
238 | struct rpc_task *rpc_new_task(struct rpc_clnt *, int flags, | 247 | struct rpc_task *rpc_new_task(struct rpc_clnt *, int flags, |
239 | const struct rpc_call_ops *ops, void *data); | 248 | const struct rpc_call_ops *ops, void *data); |
249 | struct rpc_task *rpc_run_task(struct rpc_clnt *clnt, int flags, | ||
250 | const struct rpc_call_ops *ops, void *data); | ||
240 | struct rpc_task *rpc_new_child(struct rpc_clnt *, struct rpc_task *parent); | 251 | struct rpc_task *rpc_new_child(struct rpc_clnt *, struct rpc_task *parent); |
241 | void rpc_init_task(struct rpc_task *task, struct rpc_clnt *clnt, | 252 | void rpc_init_task(struct rpc_task *task, struct rpc_clnt *clnt, |
242 | int flags, const struct rpc_call_ops *ops, | 253 | int flags, const struct rpc_call_ops *ops, |
@@ -260,6 +271,7 @@ void * rpc_malloc(struct rpc_task *, size_t); | |||
260 | int rpciod_up(void); | 271 | int rpciod_up(void); |
261 | void rpciod_down(void); | 272 | void rpciod_down(void); |
262 | void rpciod_wake_up(void); | 273 | void rpciod_wake_up(void); |
274 | int __rpc_wait_for_completion_task(struct rpc_task *task, int (*)(void *)); | ||
263 | #ifdef RPC_DEBUG | 275 | #ifdef RPC_DEBUG |
264 | void rpc_show_tasks(void); | 276 | void rpc_show_tasks(void); |
265 | #endif | 277 | #endif |
@@ -272,6 +284,11 @@ static inline void rpc_exit(struct rpc_task *task, int status) | |||
272 | task->tk_action = rpc_exit_task; | 284 | task->tk_action = rpc_exit_task; |
273 | } | 285 | } |
274 | 286 | ||
287 | static inline int rpc_wait_for_completion_task(struct rpc_task *task) | ||
288 | { | ||
289 | return __rpc_wait_for_completion_task(task, NULL); | ||
290 | } | ||
291 | |||
275 | #ifdef RPC_DEBUG | 292 | #ifdef RPC_DEBUG |
276 | static inline const char * rpc_qname(struct rpc_wait_queue *q) | 293 | static inline const char * rpc_qname(struct rpc_wait_queue *q) |
277 | { | 294 | { |
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 | * |