[PATCH] cfq-iosched: use last service point as the fairness criteria
Right now we use slice_start, which gives async queues an unfair advantage. Chance that to service_last, and base the resorter on that. Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
This commit is contained in:
parent
b0b8d74941
commit
99f9628aba
1 changed files with 34 additions and 14 deletions
|
@ -146,9 +146,9 @@ struct cfq_queue {
|
||||||
/* fifo list of requests in sort_list */
|
/* fifo list of requests in sort_list */
|
||||||
struct list_head fifo;
|
struct list_head fifo;
|
||||||
|
|
||||||
unsigned long slice_start;
|
|
||||||
unsigned long slice_end;
|
unsigned long slice_end;
|
||||||
unsigned long slice_left;
|
unsigned long slice_left;
|
||||||
|
unsigned long service_last;
|
||||||
|
|
||||||
/* number of requests that are on the dispatch list */
|
/* number of requests that are on the dispatch list */
|
||||||
int on_dispatch[2];
|
int on_dispatch[2];
|
||||||
|
@ -355,7 +355,8 @@ cfq_find_next_rq(struct cfq_data *cfqd, struct cfq_queue *cfqq,
|
||||||
static void cfq_resort_rr_list(struct cfq_queue *cfqq, int preempted)
|
static void cfq_resort_rr_list(struct cfq_queue *cfqq, int preempted)
|
||||||
{
|
{
|
||||||
struct cfq_data *cfqd = cfqq->cfqd;
|
struct cfq_data *cfqd = cfqq->cfqd;
|
||||||
struct list_head *list;
|
struct list_head *list, *n;
|
||||||
|
struct cfq_queue *__cfqq;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Resorting requires the cfqq to be on the RR list already.
|
* Resorting requires the cfqq to be on the RR list already.
|
||||||
|
@ -383,15 +384,13 @@ static void cfq_resort_rr_list(struct cfq_queue *cfqq, int preempted)
|
||||||
list = &cfqd->rr_list[cfqq->ioprio];
|
list = &cfqd->rr_list[cfqq->ioprio];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* If this queue was preempted or is new (never been serviced), let
|
|
||||||
* it be added first for fairness but beind other new queues.
|
|
||||||
* Otherwise, just add to the back of the list.
|
|
||||||
*/
|
|
||||||
if (preempted || cfq_cfqq_queue_new(cfqq)) {
|
if (preempted || cfq_cfqq_queue_new(cfqq)) {
|
||||||
struct list_head *n = list;
|
/*
|
||||||
struct cfq_queue *__cfqq;
|
* If this queue was preempted or is new (never been serviced),
|
||||||
|
* let it be added first for fairness but beind other new
|
||||||
|
* queues.
|
||||||
|
*/
|
||||||
|
n = list;
|
||||||
while (n->next != list) {
|
while (n->next != list) {
|
||||||
__cfqq = list_entry_cfqq(n->next);
|
__cfqq = list_entry_cfqq(n->next);
|
||||||
if (!cfq_cfqq_queue_new(__cfqq))
|
if (!cfq_cfqq_queue_new(__cfqq))
|
||||||
|
@ -399,11 +398,32 @@ static void cfq_resort_rr_list(struct cfq_queue *cfqq, int preempted)
|
||||||
|
|
||||||
n = n->next;
|
n = n->next;
|
||||||
}
|
}
|
||||||
|
list_add_tail(&cfqq->cfq_list, n);
|
||||||
list = n;
|
} else if (!cfq_cfqq_class_sync(cfqq)) {
|
||||||
}
|
/*
|
||||||
|
* async queue always goes to the end. this wont be overly
|
||||||
|
* unfair to writes, as the sort of the sync queue wont be
|
||||||
|
* allowed to pass the async queue again.
|
||||||
|
*/
|
||||||
list_add_tail(&cfqq->cfq_list, list);
|
list_add_tail(&cfqq->cfq_list, list);
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* sort by last service, but don't cross a new or async
|
||||||
|
* queue. we don't cross a new queue because it hasn't been
|
||||||
|
* service before, and we don't cross an async queue because
|
||||||
|
* it gets added to the end on expire.
|
||||||
|
*/
|
||||||
|
n = list;
|
||||||
|
while ((n = n->prev) != list) {
|
||||||
|
struct cfq_queue *__cfqq = list_entry_cfqq(n);
|
||||||
|
|
||||||
|
if (!cfq_cfqq_class_sync(cfqq) || !__cfqq->service_last)
|
||||||
|
break;
|
||||||
|
if (time_before(__cfqq->service_last, cfqq->service_last))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
list_add(&cfqq->cfq_list, n);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -608,7 +628,6 @@ __cfq_set_active_queue(struct cfq_data *cfqd, struct cfq_queue *cfqq)
|
||||||
*/
|
*/
|
||||||
del_timer(&cfqd->idle_class_timer);
|
del_timer(&cfqd->idle_class_timer);
|
||||||
|
|
||||||
cfqq->slice_start = jiffies;
|
|
||||||
cfqq->slice_end = 0;
|
cfqq->slice_end = 0;
|
||||||
cfqq->slice_left = 0;
|
cfqq->slice_left = 0;
|
||||||
cfq_clear_cfqq_must_alloc_slice(cfqq);
|
cfq_clear_cfqq_must_alloc_slice(cfqq);
|
||||||
|
@ -1688,6 +1707,7 @@ static void cfq_completed_request(request_queue_t *q, struct request *rq)
|
||||||
WARN_ON(!cfqq->on_dispatch[sync]);
|
WARN_ON(!cfqq->on_dispatch[sync]);
|
||||||
cfqd->rq_in_driver--;
|
cfqd->rq_in_driver--;
|
||||||
cfqq->on_dispatch[sync]--;
|
cfqq->on_dispatch[sync]--;
|
||||||
|
cfqq->service_last = now;
|
||||||
|
|
||||||
if (!cfq_class_idle(cfqq))
|
if (!cfq_class_idle(cfqq))
|
||||||
cfqd->last_end_request = now;
|
cfqd->last_end_request = now;
|
||||||
|
|
Loading…
Reference in a new issue