Commit b029195d authored by Jens Axboe's avatar Jens Axboe

cfq-iosched: don't let idling interfere with plugging

When CFQ is waiting for a new request from a process, currently it'll
immediately restart queuing when it sees such a request. This doesn't
work very well with streamed IO, since we then end up splitting IO
that would otherwise have been merged nicely. For a simple dd test,
this causes 10x as many requests to be issued as we should have.
Normally this goes unnoticed due to the low overhead of requests
at the device side, but some hardware is very sensitive to request
sizes and there it can cause big slow downs.
Signed-off-by: default avatarJens Axboe <jens.axboe@oracle.com>
parent 23853277
...@@ -177,6 +177,7 @@ struct cfq_queue { ...@@ -177,6 +177,7 @@ struct cfq_queue {
enum cfqq_state_flags { enum cfqq_state_flags {
CFQ_CFQQ_FLAG_on_rr = 0, /* on round-robin busy list */ CFQ_CFQQ_FLAG_on_rr = 0, /* on round-robin busy list */
CFQ_CFQQ_FLAG_wait_request, /* waiting for a request */ CFQ_CFQQ_FLAG_wait_request, /* waiting for a request */
CFQ_CFQQ_FLAG_must_dispatch, /* must be allowed a dispatch */
CFQ_CFQQ_FLAG_must_alloc, /* must be allowed rq alloc */ CFQ_CFQQ_FLAG_must_alloc, /* must be allowed rq alloc */
CFQ_CFQQ_FLAG_must_alloc_slice, /* per-slice must_alloc flag */ CFQ_CFQQ_FLAG_must_alloc_slice, /* per-slice must_alloc flag */
CFQ_CFQQ_FLAG_fifo_expire, /* FIFO checked in this slice */ CFQ_CFQQ_FLAG_fifo_expire, /* FIFO checked in this slice */
...@@ -202,6 +203,7 @@ static inline int cfq_cfqq_##name(const struct cfq_queue *cfqq) \ ...@@ -202,6 +203,7 @@ static inline int cfq_cfqq_##name(const struct cfq_queue *cfqq) \
CFQ_CFQQ_FNS(on_rr); CFQ_CFQQ_FNS(on_rr);
CFQ_CFQQ_FNS(wait_request); CFQ_CFQQ_FNS(wait_request);
CFQ_CFQQ_FNS(must_dispatch);
CFQ_CFQQ_FNS(must_alloc); CFQ_CFQQ_FNS(must_alloc);
CFQ_CFQQ_FNS(must_alloc_slice); CFQ_CFQQ_FNS(must_alloc_slice);
CFQ_CFQQ_FNS(fifo_expire); CFQ_CFQQ_FNS(fifo_expire);
...@@ -774,6 +776,7 @@ static void __cfq_set_active_queue(struct cfq_data *cfqd, ...@@ -774,6 +776,7 @@ static void __cfq_set_active_queue(struct cfq_data *cfqd,
cfqq->slice_dispatch = 0; cfqq->slice_dispatch = 0;
cfq_clear_cfqq_wait_request(cfqq); cfq_clear_cfqq_wait_request(cfqq);
cfq_clear_cfqq_must_dispatch(cfqq);
cfq_clear_cfqq_must_alloc_slice(cfqq); cfq_clear_cfqq_must_alloc_slice(cfqq);
cfq_clear_cfqq_fifo_expire(cfqq); cfq_clear_cfqq_fifo_expire(cfqq);
cfq_mark_cfqq_slice_new(cfqq); cfq_mark_cfqq_slice_new(cfqq);
...@@ -1009,7 +1012,7 @@ static struct cfq_queue *cfq_select_queue(struct cfq_data *cfqd) ...@@ -1009,7 +1012,7 @@ static struct cfq_queue *cfq_select_queue(struct cfq_data *cfqd)
/* /*
* The active queue has run out of time, expire it and select new. * The active queue has run out of time, expire it and select new.
*/ */
if (cfq_slice_used(cfqq)) if (cfq_slice_used(cfqq) && !cfq_cfqq_must_dispatch(cfqq))
goto expire; goto expire;
/* /*
...@@ -1173,6 +1176,7 @@ static int cfq_dispatch_requests(struct request_queue *q, int force) ...@@ -1173,6 +1176,7 @@ static int cfq_dispatch_requests(struct request_queue *q, int force)
*/ */
cfq_dispatch_request(cfqd, cfqq); cfq_dispatch_request(cfqd, cfqq);
cfqq->slice_dispatch++; cfqq->slice_dispatch++;
cfq_clear_cfqq_must_dispatch(cfqq);
/* /*
* expire an async queue immediately if it has used up its slice. idle * expire an async queue immediately if it has used up its slice. idle
...@@ -1898,14 +1902,13 @@ cfq_rq_enqueued(struct cfq_data *cfqd, struct cfq_queue *cfqq, ...@@ -1898,14 +1902,13 @@ cfq_rq_enqueued(struct cfq_data *cfqd, struct cfq_queue *cfqq,
if (cfqq == cfqd->active_queue) { if (cfqq == cfqd->active_queue) {
/* /*
* if we are waiting for a request for this queue, let it rip * Remember that we saw a request from this process, but
* immediately and flag that we must not expire this queue * don't start queuing just yet. Otherwise we risk seeing lots
* just now * of tiny requests, because we disrupt the normal plugging
* and merging.
*/ */
if (cfq_cfqq_wait_request(cfqq)) { if (cfq_cfqq_wait_request(cfqq))
del_timer(&cfqd->idle_slice_timer); cfq_mark_cfqq_must_dispatch(cfqq);
blk_start_queueing(cfqd->queue);
}
} else if (cfq_should_preempt(cfqd, cfqq, rq)) { } else if (cfq_should_preempt(cfqd, cfqq, rq)) {
/* /*
* not the active queue - expire current slice if it is * not the active queue - expire current slice if it is
...@@ -2174,6 +2177,12 @@ static void cfq_idle_slice_timer(unsigned long data) ...@@ -2174,6 +2177,12 @@ static void cfq_idle_slice_timer(unsigned long data)
if (cfqq) { if (cfqq) {
timed_out = 0; timed_out = 0;
/*
* We saw a request before the queue expired, let it through
*/
if (cfq_cfqq_must_dispatch(cfqq))
goto out_kick;
/* /*
* expired * expired
*/ */
......
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