Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c2dea2d1 authored by Vasily Tarasov's avatar Vasily Tarasov Committed by Jens Axboe
Browse files

cfq: async queue allocation per priority



If we have two processes with different ioprio_class, but the same
ioprio_data, their async requests will fall into the same queue. I guess
such behavior is not expected, because it's not right to put real-time
requests and best-effort requests in the same queue.

The attached patch fixes the problem by introducing additional *cfqq
fields on cfqd, pointing to per-(class,priority) async queues.

Signed-off-by: default avatarJens Axboe <jens.axboe@oracle.com>
parent 9a79b227
Loading
Loading
Loading
Loading
+44 −12
Original line number Diff line number Diff line
@@ -92,7 +92,11 @@ struct cfq_data {
	struct cfq_queue *active_queue;
	struct cfq_io_context *active_cic;

	struct cfq_queue *async_cfqq[IOPRIO_BE_NR];
	/*
	 * async queue for each priority case
	 */
	struct cfq_queue *async_cfqq[2][IOPRIO_BE_NR];
	struct cfq_queue *async_idle_cfqq;

	struct timer_list idle_class_timer;

@@ -1414,24 +1418,44 @@ cfq_find_alloc_queue(struct cfq_data *cfqd, int is_sync,
	return cfqq;
}

static struct cfq_queue **
cfq_async_queue_prio(struct cfq_data *cfqd, int ioprio_class, int ioprio)
{
	switch(ioprio_class) {
	case IOPRIO_CLASS_RT:
		return &cfqd->async_cfqq[0][ioprio];
	case IOPRIO_CLASS_BE:
		return &cfqd->async_cfqq[1][ioprio];
	case IOPRIO_CLASS_IDLE:
		return &cfqd->async_idle_cfqq;
	default:
		BUG();
	}
}

static struct cfq_queue *
cfq_get_queue(struct cfq_data *cfqd, int is_sync, struct task_struct *tsk,
	      gfp_t gfp_mask)
{
	const int ioprio = task_ioprio(tsk);
	const int ioprio_class = task_ioprio_class(tsk);
	struct cfq_queue **async_cfqq = NULL;
	struct cfq_queue *cfqq = NULL;

	if (!is_sync)
		cfqq = cfqd->async_cfqq[ioprio];
	if (!is_sync) {
		async_cfqq = cfq_async_queue_prio(cfqd, ioprio_class, ioprio);
		cfqq = *async_cfqq;
	}

	if (!cfqq)
		cfqq = cfq_find_alloc_queue(cfqd, is_sync, tsk, gfp_mask);

	/*
	 * pin the queue now that it's allocated, scheduler exit will prune it
	 */
	if (!is_sync && !cfqd->async_cfqq[ioprio]) {
	if (!is_sync && !(*async_cfqq)) {
		atomic_inc(&cfqq->ref);
		cfqd->async_cfqq[ioprio] = cfqq;
		*async_cfqq = cfqq;
	}

	atomic_inc(&cfqq->ref);
@@ -2042,11 +2066,24 @@ static void cfq_shutdown_timer_wq(struct cfq_data *cfqd)
	blk_sync_queue(cfqd->queue);
}

static void cfq_put_async_queues(struct cfq_data *cfqd)
{
	int i;

	for (i = 0; i < IOPRIO_BE_NR; i++) {
		if (cfqd->async_cfqq[0][i])
			cfq_put_queue(cfqd->async_cfqq[0][i]);
		if (cfqd->async_cfqq[1][i])
			cfq_put_queue(cfqd->async_cfqq[1][i]);
		if (cfqd->async_idle_cfqq)
			cfq_put_queue(cfqd->async_idle_cfqq);
	}
}

static void cfq_exit_queue(elevator_t *e)
{
	struct cfq_data *cfqd = e->elevator_data;
	request_queue_t *q = cfqd->queue;
	int i;

	cfq_shutdown_timer_wq(cfqd);

@@ -2063,12 +2100,7 @@ static void cfq_exit_queue(elevator_t *e)
		__cfq_exit_single_io_context(cfqd, cic);
	}

	/*
	 * Put the async queues
	 */
	for (i = 0; i < IOPRIO_BE_NR; i++)
		if (cfqd->async_cfqq[i])	
			cfq_put_queue(cfqd->async_cfqq[i]);
	cfq_put_async_queues(cfqd);

	spin_unlock_irq(q->queue_lock);

+8 −0
Original line number Diff line number Diff line
@@ -53,6 +53,14 @@ static inline int task_ioprio(struct task_struct *task)
	return IOPRIO_NORM;
}

static inline int task_ioprio_class(struct task_struct *task)
{
	if (ioprio_valid(task->ioprio))
		return IOPRIO_PRIO_CLASS(task->ioprio);

	return IOPRIO_CLASS_BE;
}

static inline int task_nice_ioprio(struct task_struct *task)
{
	return (task_nice(task) + 20) / 5;