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

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
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -33,6 +33,8 @@ struct rpc_wait_queue;
struct rpc_wait {
	struct list_head	list;		/* wait queue links */
	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 {
#define RPC_PRIORITY_HIGH	(1)
#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
 */
@@ -203,6 +211,7 @@ struct rpc_wait_queue {
	unsigned char		count;			/* # task groups remaining serviced so far */
	unsigned char		nr;			/* # tasks remaining for cookie */
	unsigned short		qlen;			/* total # tasks waiting in queue */
	struct rpc_timer	timer_list;
#ifdef RPC_DEBUG
	const char *		name;
#endif
+42 −4
Original line number Diff line number Diff line
@@ -40,6 +40,7 @@ static mempool_t *rpc_buffer_mempool __read_mostly;

static void			rpc_async_schedule(struct work_struct *);
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.
@@ -59,8 +60,18 @@ struct workqueue_struct *rpciod_workqueue;
static void
__rpc_disable_timer(struct rpc_task *task)
{
	if (task->tk_timeout == 0)
		return;
	dprintk("RPC: %5u disabling timer\n", task->tk_pid);
	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)
		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_del(&task->u.tk_wait.list);
}

/*
@@ -162,9 +172,9 @@ 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)
{
	__rpc_disable_timer(task);
	if (RPC_IS_PRIORITY(queue))
		__rpc_remove_wait_queue_priority(task);
	else
	list_del(&task->u.tk_wait.list);
	queue->qlen--;
	dprintk("RPC: %5u removed from queue %p \"%s\"\n",
@@ -198,6 +208,9 @@ static void __rpc_init_priority_wait_queue(struct rpc_wait_queue *queue, const c
		INIT_LIST_HEAD(&queue->tasks[i]);
	queue->maxpriority = nr_queues - 1;
	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
	queue->name = qname;
#endif
@@ -216,6 +229,7 @@ EXPORT_SYMBOL_GPL(rpc_init_wait_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);

@@ -369,7 +383,6 @@ static void __rpc_do_wake_up_task(struct rpc_wait_queue *queue, struct rpc_task
		return;
	}

	__rpc_disable_timer(task);
	__rpc_remove_wait_queue(queue, task);

	rpc_make_runnable(task);
@@ -562,6 +575,31 @@ static void rpc_run_timer(unsigned long ptr)
	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)
{
	task->tk_status = 0;