diff options
author | Trond Myklebust <Trond.Myklebust@netapp.com> | 2007-07-18 16:18:52 -0400 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2008-02-29 02:21:59 -0500 |
commit | 36df9aae3158ce8fc4ede241169dc94ac910d884 (patch) | |
tree | 5f6caa22ce9414850fd34eefb54150b120a8f4e7 | |
parent | f6a1cc89309f0ae847a9b6fe418d1c4215e5bc55 (diff) |
SUNRPC: Add a timer function to wait queues.
This is designed to replace the timeout timer in the individual rpc_tasks.
By putting the timer function in the wait queue, we will eventually be able
to reduce the total number of timers in use by the RPC subsystem.
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
-rw-r--r-- | include/linux/sunrpc/sched.h | 9 | ||||
-rw-r--r-- | net/sunrpc/sched.c | 46 |
2 files changed, 51 insertions, 4 deletions
diff --git a/include/linux/sunrpc/sched.h b/include/linux/sunrpc/sched.h index d39729e2b893..7751d3a05497 100644 --- a/include/linux/sunrpc/sched.h +++ b/include/linux/sunrpc/sched.h | |||
@@ -33,6 +33,8 @@ struct rpc_wait_queue; | |||
33 | struct rpc_wait { | 33 | struct rpc_wait { |
34 | struct list_head list; /* wait queue links */ | 34 | struct list_head list; /* wait queue links */ |
35 | struct list_head links; /* Links to related tasks */ | 35 | struct list_head links; /* Links to related tasks */ |
36 | struct list_head timer_list; /* Timer list */ | ||
37 | unsigned long expires; | ||
36 | }; | 38 | }; |
37 | 39 | ||
38 | /* | 40 | /* |
@@ -191,6 +193,12 @@ struct rpc_task_setup { | |||
191 | #define RPC_PRIORITY_HIGH (1) | 193 | #define RPC_PRIORITY_HIGH (1) |
192 | #define RPC_NR_PRIORITY (1 + RPC_PRIORITY_HIGH - RPC_PRIORITY_LOW) | 194 | #define RPC_NR_PRIORITY (1 + RPC_PRIORITY_HIGH - RPC_PRIORITY_LOW) |
193 | 195 | ||
196 | struct rpc_timer { | ||
197 | struct timer_list timer; | ||
198 | struct list_head list; | ||
199 | unsigned long expires; | ||
200 | }; | ||
201 | |||
194 | /* | 202 | /* |
195 | * RPC synchronization objects | 203 | * RPC synchronization objects |
196 | */ | 204 | */ |
@@ -203,6 +211,7 @@ struct rpc_wait_queue { | |||
203 | unsigned char count; /* # task groups remaining serviced so far */ | 211 | unsigned char count; /* # task groups remaining serviced so far */ |
204 | unsigned char nr; /* # tasks remaining for cookie */ | 212 | unsigned char nr; /* # tasks remaining for cookie */ |
205 | unsigned short qlen; /* total # tasks waiting in queue */ | 213 | unsigned short qlen; /* total # tasks waiting in queue */ |
214 | struct rpc_timer timer_list; | ||
206 | #ifdef RPC_DEBUG | 215 | #ifdef RPC_DEBUG |
207 | const char * name; | 216 | const char * name; |
208 | #endif | 217 | #endif |
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; |