diff options
Diffstat (limited to 'net/sunrpc/sched.c')
-rw-r--r-- | net/sunrpc/sched.c | 46 |
1 files changed, 42 insertions, 4 deletions
diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c index 86aa897e7b08..29b1c1441f4d 100644 --- a/net/sunrpc/sched.c +++ b/net/sunrpc/sched.c | |||
@@ -40,6 +40,7 @@ static mempool_t *rpc_buffer_mempool __read_mostly; | |||
40 | 40 | ||
41 | static void rpc_async_schedule(struct work_struct *); | 41 | static void rpc_async_schedule(struct work_struct *); |
42 | static void rpc_release_task(struct rpc_task *task); | 42 | static void rpc_release_task(struct rpc_task *task); |
43 | static void __rpc_queue_timer_fn(unsigned long ptr); | ||
43 | 44 | ||
44 | /* | 45 | /* |
45 | * RPC tasks sit here while waiting for conditions to improve. | 46 | * RPC tasks sit here while waiting for conditions to improve. |
@@ -59,8 +60,18 @@ struct workqueue_struct *rpciod_workqueue; | |||
59 | static void | 60 | static void |
60 | __rpc_disable_timer(struct rpc_task *task) | 61 | __rpc_disable_timer(struct rpc_task *task) |
61 | { | 62 | { |
63 | if (task->tk_timeout == 0) | ||
64 | return; | ||
62 | dprintk("RPC: %5u disabling timer\n", task->tk_pid); | 65 | dprintk("RPC: %5u disabling timer\n", task->tk_pid); |
63 | task->tk_timeout = 0; | 66 | task->tk_timeout = 0; |
67 | list_del(&task->u.tk_wait.timer_list); | ||
68 | } | ||
69 | |||
70 | static void | ||
71 | rpc_set_queue_timer(struct rpc_wait_queue *queue, unsigned long expires) | ||
72 | { | ||
73 | queue->timer_list.expires = expires; | ||
74 | mod_timer(&queue->timer_list.timer, expires); | ||
64 | } | 75 | } |
65 | 76 | ||
66 | /* | 77 | /* |
@@ -153,7 +164,6 @@ static void __rpc_remove_wait_queue_priority(struct rpc_task *task) | |||
153 | list_move(&t->u.tk_wait.list, &task->u.tk_wait.list); | 164 | list_move(&t->u.tk_wait.list, &task->u.tk_wait.list); |
154 | list_splice_init(&task->u.tk_wait.links, &t->u.tk_wait.links); | 165 | list_splice_init(&task->u.tk_wait.links, &t->u.tk_wait.links); |
155 | } | 166 | } |
156 | list_del(&task->u.tk_wait.list); | ||
157 | } | 167 | } |
158 | 168 | ||
159 | /* | 169 | /* |
@@ -162,10 +172,10 @@ static void __rpc_remove_wait_queue_priority(struct rpc_task *task) | |||
162 | */ | 172 | */ |
163 | static void __rpc_remove_wait_queue(struct rpc_wait_queue *queue, struct rpc_task *task) | 173 | static void __rpc_remove_wait_queue(struct rpc_wait_queue *queue, struct rpc_task *task) |
164 | { | 174 | { |
175 | __rpc_disable_timer(task); | ||
165 | if (RPC_IS_PRIORITY(queue)) | 176 | if (RPC_IS_PRIORITY(queue)) |
166 | __rpc_remove_wait_queue_priority(task); | 177 | __rpc_remove_wait_queue_priority(task); |
167 | else | 178 | list_del(&task->u.tk_wait.list); |
168 | list_del(&task->u.tk_wait.list); | ||
169 | queue->qlen--; | 179 | queue->qlen--; |
170 | dprintk("RPC: %5u removed from queue %p \"%s\"\n", | 180 | dprintk("RPC: %5u removed from queue %p \"%s\"\n", |
171 | task->tk_pid, queue, rpc_qname(queue)); | 181 | task->tk_pid, queue, rpc_qname(queue)); |
@@ -198,6 +208,9 @@ static void __rpc_init_priority_wait_queue(struct rpc_wait_queue *queue, const c | |||
198 | INIT_LIST_HEAD(&queue->tasks[i]); | 208 | INIT_LIST_HEAD(&queue->tasks[i]); |
199 | queue->maxpriority = nr_queues - 1; | 209 | queue->maxpriority = nr_queues - 1; |
200 | rpc_reset_waitqueue_priority(queue); | 210 | rpc_reset_waitqueue_priority(queue); |
211 | queue->qlen = 0; | ||
212 | setup_timer(&queue->timer_list.timer, __rpc_queue_timer_fn, (unsigned long)queue); | ||
213 | INIT_LIST_HEAD(&queue->timer_list.list); | ||
201 | #ifdef RPC_DEBUG | 214 | #ifdef RPC_DEBUG |
202 | queue->name = qname; | 215 | queue->name = qname; |
203 | #endif | 216 | #endif |
@@ -216,6 +229,7 @@ EXPORT_SYMBOL_GPL(rpc_init_wait_queue); | |||
216 | 229 | ||
217 | void rpc_destroy_wait_queue(struct rpc_wait_queue *queue) | 230 | void rpc_destroy_wait_queue(struct rpc_wait_queue *queue) |
218 | { | 231 | { |
232 | del_timer_sync(&queue->timer_list.timer); | ||
219 | } | 233 | } |
220 | EXPORT_SYMBOL_GPL(rpc_destroy_wait_queue); | 234 | EXPORT_SYMBOL_GPL(rpc_destroy_wait_queue); |
221 | 235 | ||
@@ -369,7 +383,6 @@ static void __rpc_do_wake_up_task(struct rpc_wait_queue *queue, struct rpc_task | |||
369 | return; | 383 | return; |
370 | } | 384 | } |
371 | 385 | ||
372 | __rpc_disable_timer(task); | ||
373 | __rpc_remove_wait_queue(queue, task); | 386 | __rpc_remove_wait_queue(queue, task); |
374 | 387 | ||
375 | rpc_make_runnable(task); | 388 | rpc_make_runnable(task); |
@@ -562,6 +575,31 @@ static void rpc_run_timer(unsigned long ptr) | |||
562 | smp_mb__after_clear_bit(); | 575 | smp_mb__after_clear_bit(); |
563 | } | 576 | } |
564 | 577 | ||
578 | static void __rpc_queue_timer_fn(unsigned long ptr) | ||
579 | { | ||
580 | struct rpc_wait_queue *queue = (struct rpc_wait_queue *)ptr; | ||
581 | struct rpc_task *task, *n; | ||
582 | unsigned long expires, now, timeo; | ||
583 | |||
584 | spin_lock(&queue->lock); | ||
585 | expires = now = jiffies; | ||
586 | list_for_each_entry_safe(task, n, &queue->timer_list.list, u.tk_wait.timer_list) { | ||
587 | timeo = task->u.tk_wait.expires; | ||
588 | if (time_after_eq(now, timeo)) { | ||
589 | list_del_init(&task->u.tk_wait.timer_list); | ||
590 | dprintk("RPC: %5u timeout\n", task->tk_pid); | ||
591 | task->tk_status = -ETIMEDOUT; | ||
592 | rpc_wake_up_task_queue_locked(queue, task); | ||
593 | continue; | ||
594 | } | ||
595 | if (expires == now || time_after(expires, timeo)) | ||
596 | expires = timeo; | ||
597 | } | ||
598 | if (!list_empty(&queue->timer_list.list)) | ||
599 | rpc_set_queue_timer(queue, expires); | ||
600 | spin_unlock(&queue->lock); | ||
601 | } | ||
602 | |||
565 | static void __rpc_atrun(struct rpc_task *task) | 603 | static void __rpc_atrun(struct rpc_task *task) |
566 | { | 604 | { |
567 | task->tk_status = 0; | 605 | task->tk_status = 0; |