Commit 36df9aae authored by Trond Myklebust's avatar Trond Myklebust

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: default avatarTrond Myklebust <Trond.Myklebust@netapp.com>
parent f6a1cc89
...@@ -33,6 +33,8 @@ struct rpc_wait_queue; ...@@ -33,6 +33,8 @@ struct rpc_wait_queue;
struct rpc_wait { struct rpc_wait {
struct list_head list; /* wait queue links */ struct list_head list; /* wait queue links */
struct list_head links; /* Links to related tasks */ struct list_head links; /* Links to related tasks */
struct list_head timer_list; /* Timer list */
unsigned long expires;
}; };
/* /*
...@@ -191,6 +193,12 @@ struct rpc_task_setup { ...@@ -191,6 +193,12 @@ struct rpc_task_setup {
#define RPC_PRIORITY_HIGH (1) #define RPC_PRIORITY_HIGH (1)
#define RPC_NR_PRIORITY (1 + RPC_PRIORITY_HIGH - RPC_PRIORITY_LOW) #define RPC_NR_PRIORITY (1 + RPC_PRIORITY_HIGH - RPC_PRIORITY_LOW)
struct rpc_timer {
struct timer_list timer;
struct list_head list;
unsigned long expires;
};
/* /*
* RPC synchronization objects * RPC synchronization objects
*/ */
...@@ -203,6 +211,7 @@ struct rpc_wait_queue { ...@@ -203,6 +211,7 @@ struct rpc_wait_queue {
unsigned char count; /* # task groups remaining serviced so far */ unsigned char count; /* # task groups remaining serviced so far */
unsigned char nr; /* # tasks remaining for cookie */ unsigned char nr; /* # tasks remaining for cookie */
unsigned short qlen; /* total # tasks waiting in queue */ unsigned short qlen; /* total # tasks waiting in queue */
struct rpc_timer timer_list;
#ifdef RPC_DEBUG #ifdef RPC_DEBUG
const char * name; const char * name;
#endif #endif
......
...@@ -40,6 +40,7 @@ static mempool_t *rpc_buffer_mempool __read_mostly; ...@@ -40,6 +40,7 @@ static mempool_t *rpc_buffer_mempool __read_mostly;
static void rpc_async_schedule(struct work_struct *); static void rpc_async_schedule(struct work_struct *);
static void rpc_release_task(struct rpc_task *task); static void rpc_release_task(struct rpc_task *task);
static void __rpc_queue_timer_fn(unsigned long ptr);
/* /*
* RPC tasks sit here while waiting for conditions to improve. * RPC tasks sit here while waiting for conditions to improve.
...@@ -59,8 +60,18 @@ struct workqueue_struct *rpciod_workqueue; ...@@ -59,8 +60,18 @@ struct workqueue_struct *rpciod_workqueue;
static void static void
__rpc_disable_timer(struct rpc_task *task) __rpc_disable_timer(struct rpc_task *task)
{ {
if (task->tk_timeout == 0)
return;
dprintk("RPC: %5u disabling timer\n", task->tk_pid); dprintk("RPC: %5u disabling timer\n", task->tk_pid);
task->tk_timeout = 0; task->tk_timeout = 0;
list_del(&task->u.tk_wait.timer_list);
}
static void
rpc_set_queue_timer(struct rpc_wait_queue *queue, unsigned long expires)
{
queue->timer_list.expires = expires;
mod_timer(&queue->timer_list.timer, expires);
} }
/* /*
...@@ -153,7 +164,6 @@ static void __rpc_remove_wait_queue_priority(struct rpc_task *task) ...@@ -153,7 +164,6 @@ static void __rpc_remove_wait_queue_priority(struct rpc_task *task)
list_move(&t->u.tk_wait.list, &task->u.tk_wait.list); list_move(&t->u.tk_wait.list, &task->u.tk_wait.list);
list_splice_init(&task->u.tk_wait.links, &t->u.tk_wait.links); list_splice_init(&task->u.tk_wait.links, &t->u.tk_wait.links);
} }
list_del(&task->u.tk_wait.list);
} }
/* /*
...@@ -162,10 +172,10 @@ static void __rpc_remove_wait_queue_priority(struct rpc_task *task) ...@@ -162,10 +172,10 @@ static void __rpc_remove_wait_queue_priority(struct rpc_task *task)
*/ */
static void __rpc_remove_wait_queue(struct rpc_wait_queue *queue, struct rpc_task *task) static void __rpc_remove_wait_queue(struct rpc_wait_queue *queue, struct rpc_task *task)
{ {
__rpc_disable_timer(task);
if (RPC_IS_PRIORITY(queue)) if (RPC_IS_PRIORITY(queue))
__rpc_remove_wait_queue_priority(task); __rpc_remove_wait_queue_priority(task);
else list_del(&task->u.tk_wait.list);
list_del(&task->u.tk_wait.list);
queue->qlen--; queue->qlen--;
dprintk("RPC: %5u removed from queue %p \"%s\"\n", dprintk("RPC: %5u removed from queue %p \"%s\"\n",
task->tk_pid, queue, rpc_qname(queue)); 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,6 +208,9 @@ static void __rpc_init_priority_wait_queue(struct rpc_wait_queue *queue, const c
INIT_LIST_HEAD(&queue->tasks[i]); INIT_LIST_HEAD(&queue->tasks[i]);
queue->maxpriority = nr_queues - 1; queue->maxpriority = nr_queues - 1;
rpc_reset_waitqueue_priority(queue); rpc_reset_waitqueue_priority(queue);
queue->qlen = 0;
setup_timer(&queue->timer_list.timer, __rpc_queue_timer_fn, (unsigned long)queue);
INIT_LIST_HEAD(&queue->timer_list.list);
#ifdef RPC_DEBUG #ifdef RPC_DEBUG
queue->name = qname; queue->name = qname;
#endif #endif
...@@ -216,6 +229,7 @@ EXPORT_SYMBOL_GPL(rpc_init_wait_queue); ...@@ -216,6 +229,7 @@ EXPORT_SYMBOL_GPL(rpc_init_wait_queue);
void rpc_destroy_wait_queue(struct rpc_wait_queue *queue) void rpc_destroy_wait_queue(struct rpc_wait_queue *queue)
{ {
del_timer_sync(&queue->timer_list.timer);
} }
EXPORT_SYMBOL_GPL(rpc_destroy_wait_queue); EXPORT_SYMBOL_GPL(rpc_destroy_wait_queue);
...@@ -369,7 +383,6 @@ static void __rpc_do_wake_up_task(struct rpc_wait_queue *queue, struct rpc_task ...@@ -369,7 +383,6 @@ static void __rpc_do_wake_up_task(struct rpc_wait_queue *queue, struct rpc_task
return; return;
} }
__rpc_disable_timer(task);
__rpc_remove_wait_queue(queue, task); __rpc_remove_wait_queue(queue, task);
rpc_make_runnable(task); rpc_make_runnable(task);
...@@ -562,6 +575,31 @@ static void rpc_run_timer(unsigned long ptr) ...@@ -562,6 +575,31 @@ static void rpc_run_timer(unsigned long ptr)
smp_mb__after_clear_bit(); smp_mb__after_clear_bit();
} }
static void __rpc_queue_timer_fn(unsigned long ptr)
{
struct rpc_wait_queue *queue = (struct rpc_wait_queue *)ptr;
struct rpc_task *task, *n;
unsigned long expires, now, timeo;
spin_lock(&queue->lock);
expires = now = jiffies;
list_for_each_entry_safe(task, n, &queue->timer_list.list, u.tk_wait.timer_list) {
timeo = task->u.tk_wait.expires;
if (time_after_eq(now, timeo)) {
list_del_init(&task->u.tk_wait.timer_list);
dprintk("RPC: %5u timeout\n", task->tk_pid);
task->tk_status = -ETIMEDOUT;
rpc_wake_up_task_queue_locked(queue, task);
continue;
}
if (expires == now || time_after(expires, timeo))
expires = timeo;
}
if (!list_empty(&queue->timer_list.list))
rpc_set_queue_timer(queue, expires);
spin_unlock(&queue->lock);
}
static void __rpc_atrun(struct rpc_task *task) static void __rpc_atrun(struct rpc_task *task)
{ {
task->tk_status = 0; task->tk_status = 0;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment