aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTrond Myklebust <Trond.Myklebust@netapp.com>2007-07-18 16:18:52 -0400
committerTrond Myklebust <Trond.Myklebust@netapp.com>2008-02-29 02:21:59 -0500
commit36df9aae3158ce8fc4ede241169dc94ac910d884 (patch)
tree5f6caa22ce9414850fd34eefb54150b120a8f4e7
parentf6a1cc89309f0ae847a9b6fe418d1c4215e5bc55 (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.h9
-rw-r--r--net/sunrpc/sched.c46
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;
33struct rpc_wait { 33struct 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
196struct 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
41static void rpc_async_schedule(struct work_struct *); 41static void rpc_async_schedule(struct work_struct *);
42static void rpc_release_task(struct rpc_task *task); 42static void rpc_release_task(struct rpc_task *task);
43static 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;
59static void 60static 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
70static void
71rpc_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 */
163static void __rpc_remove_wait_queue(struct rpc_wait_queue *queue, struct rpc_task *task) 173static 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
217void rpc_destroy_wait_queue(struct rpc_wait_queue *queue) 230void rpc_destroy_wait_queue(struct rpc_wait_queue *queue)
218{ 231{
232 del_timer_sync(&queue->timer_list.timer);
219} 233}
220EXPORT_SYMBOL_GPL(rpc_destroy_wait_queue); 234EXPORT_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
578static 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
565static void __rpc_atrun(struct rpc_task *task) 603static void __rpc_atrun(struct rpc_task *task)
566{ 604{
567 task->tk_status = 0; 605 task->tk_status = 0;