Commit 1b5ed5e1 authored by Tejun Heo's avatar Tejun Heo Committed by Jens Axboe

[BLOCK] cfq-iosched: cfq forced dispatching fix

cfq forced dispatching might not return all requests on the queue.
This bug can hang elevator switchinig and corrupt request ordering
during flush sequence.
Signed-off-by: default avatarTejun Heo <htejun@gmail.com>
Signed-off-by: default avatarJens Axboe <axboe@suse.de>
parent 407df2aa
...@@ -999,7 +999,7 @@ cfq_prio_to_maxrq(struct cfq_data *cfqd, struct cfq_queue *cfqq) ...@@ -999,7 +999,7 @@ cfq_prio_to_maxrq(struct cfq_data *cfqd, struct cfq_queue *cfqq)
/* /*
* get next queue for service * get next queue for service
*/ */
static struct cfq_queue *cfq_select_queue(struct cfq_data *cfqd, int force) static struct cfq_queue *cfq_select_queue(struct cfq_data *cfqd)
{ {
unsigned long now = jiffies; unsigned long now = jiffies;
struct cfq_queue *cfqq; struct cfq_queue *cfqq;
...@@ -1023,7 +1023,7 @@ static struct cfq_queue *cfq_select_queue(struct cfq_data *cfqd, int force) ...@@ -1023,7 +1023,7 @@ static struct cfq_queue *cfq_select_queue(struct cfq_data *cfqd, int force)
*/ */
if (!RB_EMPTY(&cfqq->sort_list)) if (!RB_EMPTY(&cfqq->sort_list))
goto keep_queue; goto keep_queue;
else if (!force && cfq_cfqq_class_sync(cfqq) && else if (cfq_cfqq_class_sync(cfqq) &&
time_before(now, cfqq->slice_end)) { time_before(now, cfqq->slice_end)) {
if (cfq_arm_slice_timer(cfqd, cfqq)) if (cfq_arm_slice_timer(cfqd, cfqq))
return NULL; return NULL;
...@@ -1091,6 +1091,42 @@ __cfq_dispatch_requests(struct cfq_data *cfqd, struct cfq_queue *cfqq, ...@@ -1091,6 +1091,42 @@ __cfq_dispatch_requests(struct cfq_data *cfqd, struct cfq_queue *cfqq,
return dispatched; return dispatched;
} }
static int
cfq_forced_dispatch_cfqqs(struct list_head *list)
{
int dispatched = 0;
struct cfq_queue *cfqq, *next;
struct cfq_rq *crq;
list_for_each_entry_safe(cfqq, next, list, cfq_list) {
while ((crq = cfqq->next_crq)) {
cfq_dispatch_insert(cfqq->cfqd->queue, crq);
dispatched++;
}
BUG_ON(!list_empty(&cfqq->fifo));
}
return dispatched;
}
static int
cfq_forced_dispatch(struct cfq_data *cfqd)
{
int i, dispatched = 0;
for (i = 0; i < CFQ_PRIO_LISTS; i++)
dispatched += cfq_forced_dispatch_cfqqs(&cfqd->rr_list[i]);
dispatched += cfq_forced_dispatch_cfqqs(&cfqd->busy_rr);
dispatched += cfq_forced_dispatch_cfqqs(&cfqd->cur_rr);
dispatched += cfq_forced_dispatch_cfqqs(&cfqd->idle_rr);
cfq_slice_expired(cfqd, 0);
BUG_ON(cfqd->busy_queues);
return dispatched;
}
static int static int
cfq_dispatch_requests(request_queue_t *q, int force) cfq_dispatch_requests(request_queue_t *q, int force)
{ {
...@@ -1100,7 +1136,10 @@ cfq_dispatch_requests(request_queue_t *q, int force) ...@@ -1100,7 +1136,10 @@ cfq_dispatch_requests(request_queue_t *q, int force)
if (!cfqd->busy_queues) if (!cfqd->busy_queues)
return 0; return 0;
cfqq = cfq_select_queue(cfqd, force); if (unlikely(force))
return cfq_forced_dispatch(cfqd);
cfqq = cfq_select_queue(cfqd);
if (cfqq) { if (cfqq) {
int max_dispatch; int max_dispatch;
...@@ -1115,12 +1154,9 @@ cfq_dispatch_requests(request_queue_t *q, int force) ...@@ -1115,12 +1154,9 @@ cfq_dispatch_requests(request_queue_t *q, int force)
cfq_clear_cfqq_wait_request(cfqq); cfq_clear_cfqq_wait_request(cfqq);
del_timer(&cfqd->idle_slice_timer); del_timer(&cfqd->idle_slice_timer);
if (!force) {
max_dispatch = cfqd->cfq_quantum; max_dispatch = cfqd->cfq_quantum;
if (cfq_class_idle(cfqq)) if (cfq_class_idle(cfqq))
max_dispatch = 1; max_dispatch = 1;
} else
max_dispatch = INT_MAX;
return __cfq_dispatch_requests(cfqd, cfqq, max_dispatch); return __cfq_dispatch_requests(cfqd, cfqq, max_dispatch);
} }
......
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