diff options
Diffstat (limited to 'block/cfq-iosched.c')
-rw-r--r-- | block/cfq-iosched.c | 56 |
1 files changed, 36 insertions, 20 deletions
diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c index 70b48ea0e3e9..fce8a749f4be 100644 --- a/block/cfq-iosched.c +++ b/block/cfq-iosched.c | |||
@@ -150,7 +150,7 @@ struct cfq_data { | |||
150 | * idle window management | 150 | * idle window management |
151 | */ | 151 | */ |
152 | struct timer_list idle_slice_timer; | 152 | struct timer_list idle_slice_timer; |
153 | struct work_struct unplug_work; | 153 | struct delayed_work unplug_work; |
154 | 154 | ||
155 | struct cfq_queue *active_queue; | 155 | struct cfq_queue *active_queue; |
156 | struct cfq_io_context *active_cic; | 156 | struct cfq_io_context *active_cic; |
@@ -268,11 +268,13 @@ static inline int cfq_bio_sync(struct bio *bio) | |||
268 | * scheduler run of queue, if there are requests pending and no one in the | 268 | * scheduler run of queue, if there are requests pending and no one in the |
269 | * driver that will restart queueing | 269 | * driver that will restart queueing |
270 | */ | 270 | */ |
271 | static inline void cfq_schedule_dispatch(struct cfq_data *cfqd) | 271 | static inline void cfq_schedule_dispatch(struct cfq_data *cfqd, |
272 | unsigned long delay) | ||
272 | { | 273 | { |
273 | if (cfqd->busy_queues) { | 274 | if (cfqd->busy_queues) { |
274 | cfq_log(cfqd, "schedule dispatch"); | 275 | cfq_log(cfqd, "schedule dispatch"); |
275 | kblockd_schedule_work(cfqd->queue, &cfqd->unplug_work); | 276 | kblockd_schedule_delayed_work(cfqd->queue, &cfqd->unplug_work, |
277 | delay); | ||
276 | } | 278 | } |
277 | } | 279 | } |
278 | 280 | ||
@@ -1316,8 +1318,6 @@ static int cfq_dispatch_requests(struct request_queue *q, int force) | |||
1316 | * Does this cfqq already have too much IO in flight? | 1318 | * Does this cfqq already have too much IO in flight? |
1317 | */ | 1319 | */ |
1318 | if (cfqq->dispatched >= max_dispatch) { | 1320 | if (cfqq->dispatched >= max_dispatch) { |
1319 | unsigned long load_at = cfqd->last_end_sync_rq + cfq_slice_sync; | ||
1320 | |||
1321 | /* | 1321 | /* |
1322 | * idle queue must always only have a single IO in flight | 1322 | * idle queue must always only have a single IO in flight |
1323 | */ | 1323 | */ |
@@ -1331,20 +1331,36 @@ static int cfq_dispatch_requests(struct request_queue *q, int force) | |||
1331 | return 0; | 1331 | return 0; |
1332 | 1332 | ||
1333 | /* | 1333 | /* |
1334 | * If a sync request has completed recently, don't overload | 1334 | * Sole queue user, allow bigger slice |
1335 | * the dispatch queue yet with async requests. | ||
1336 | */ | 1335 | */ |
1337 | if (cfqd->cfq_desktop && !cfq_cfqq_sync(cfqq) | 1336 | max_dispatch *= 4; |
1338 | && time_before(jiffies, load_at)) | 1337 | } |
1339 | return 0; | 1338 | |
1339 | /* | ||
1340 | * Async queues must wait a bit before being allowed dispatch. | ||
1341 | * We also ramp up the dispatch depth gradually for async IO, | ||
1342 | * based on the last sync IO we serviced | ||
1343 | */ | ||
1344 | if (!cfq_cfqq_sync(cfqq) && cfqd->cfq_desktop) { | ||
1345 | unsigned long last_sync = jiffies - cfqd->last_end_sync_rq; | ||
1346 | unsigned int depth; | ||
1340 | 1347 | ||
1341 | /* | 1348 | /* |
1342 | * we are the only queue, allow up to 4 times of 'quantum' | 1349 | * must wait a bit longer |
1343 | */ | 1350 | */ |
1344 | if (cfqq->dispatched >= 4 * max_dispatch) | 1351 | if (last_sync < cfq_slice_sync) { |
1352 | cfq_schedule_dispatch(cfqd, cfq_slice_sync - last_sync); | ||
1345 | return 0; | 1353 | return 0; |
1354 | } | ||
1355 | |||
1356 | depth = last_sync / cfq_slice_sync; | ||
1357 | if (depth < max_dispatch) | ||
1358 | max_dispatch = depth; | ||
1346 | } | 1359 | } |
1347 | 1360 | ||
1361 | if (cfqq->dispatched >= max_dispatch) | ||
1362 | return 0; | ||
1363 | |||
1348 | /* | 1364 | /* |
1349 | * Dispatch a request from this cfqq | 1365 | * Dispatch a request from this cfqq |
1350 | */ | 1366 | */ |
@@ -1389,7 +1405,7 @@ static void cfq_put_queue(struct cfq_queue *cfqq) | |||
1389 | 1405 | ||
1390 | if (unlikely(cfqd->active_queue == cfqq)) { | 1406 | if (unlikely(cfqd->active_queue == cfqq)) { |
1391 | __cfq_slice_expired(cfqd, cfqq, 0); | 1407 | __cfq_slice_expired(cfqd, cfqq, 0); |
1392 | cfq_schedule_dispatch(cfqd); | 1408 | cfq_schedule_dispatch(cfqd, 0); |
1393 | } | 1409 | } |
1394 | 1410 | ||
1395 | kmem_cache_free(cfq_pool, cfqq); | 1411 | kmem_cache_free(cfq_pool, cfqq); |
@@ -1484,7 +1500,7 @@ static void cfq_exit_cfqq(struct cfq_data *cfqd, struct cfq_queue *cfqq) | |||
1484 | { | 1500 | { |
1485 | if (unlikely(cfqq == cfqd->active_queue)) { | 1501 | if (unlikely(cfqq == cfqd->active_queue)) { |
1486 | __cfq_slice_expired(cfqd, cfqq, 0); | 1502 | __cfq_slice_expired(cfqd, cfqq, 0); |
1487 | cfq_schedule_dispatch(cfqd); | 1503 | cfq_schedule_dispatch(cfqd, 0); |
1488 | } | 1504 | } |
1489 | 1505 | ||
1490 | cfq_put_queue(cfqq); | 1506 | cfq_put_queue(cfqq); |
@@ -2201,7 +2217,7 @@ static void cfq_completed_request(struct request_queue *q, struct request *rq) | |||
2201 | } | 2217 | } |
2202 | 2218 | ||
2203 | if (!rq_in_driver(cfqd)) | 2219 | if (!rq_in_driver(cfqd)) |
2204 | cfq_schedule_dispatch(cfqd); | 2220 | cfq_schedule_dispatch(cfqd, 0); |
2205 | } | 2221 | } |
2206 | 2222 | ||
2207 | /* | 2223 | /* |
@@ -2331,7 +2347,7 @@ queue_fail: | |||
2331 | if (cic) | 2347 | if (cic) |
2332 | put_io_context(cic->ioc); | 2348 | put_io_context(cic->ioc); |
2333 | 2349 | ||
2334 | cfq_schedule_dispatch(cfqd); | 2350 | cfq_schedule_dispatch(cfqd, 0); |
2335 | spin_unlock_irqrestore(q->queue_lock, flags); | 2351 | spin_unlock_irqrestore(q->queue_lock, flags); |
2336 | cfq_log(cfqd, "set_request fail"); | 2352 | cfq_log(cfqd, "set_request fail"); |
2337 | return 1; | 2353 | return 1; |
@@ -2340,7 +2356,7 @@ queue_fail: | |||
2340 | static void cfq_kick_queue(struct work_struct *work) | 2356 | static void cfq_kick_queue(struct work_struct *work) |
2341 | { | 2357 | { |
2342 | struct cfq_data *cfqd = | 2358 | struct cfq_data *cfqd = |
2343 | container_of(work, struct cfq_data, unplug_work); | 2359 | container_of(work, struct cfq_data, unplug_work.work); |
2344 | struct request_queue *q = cfqd->queue; | 2360 | struct request_queue *q = cfqd->queue; |
2345 | 2361 | ||
2346 | spin_lock_irq(q->queue_lock); | 2362 | spin_lock_irq(q->queue_lock); |
@@ -2394,7 +2410,7 @@ static void cfq_idle_slice_timer(unsigned long data) | |||
2394 | expire: | 2410 | expire: |
2395 | cfq_slice_expired(cfqd, timed_out); | 2411 | cfq_slice_expired(cfqd, timed_out); |
2396 | out_kick: | 2412 | out_kick: |
2397 | cfq_schedule_dispatch(cfqd); | 2413 | cfq_schedule_dispatch(cfqd, 0); |
2398 | out_cont: | 2414 | out_cont: |
2399 | spin_unlock_irqrestore(cfqd->queue->queue_lock, flags); | 2415 | spin_unlock_irqrestore(cfqd->queue->queue_lock, flags); |
2400 | } | 2416 | } |
@@ -2402,7 +2418,7 @@ out_cont: | |||
2402 | static void cfq_shutdown_timer_wq(struct cfq_data *cfqd) | 2418 | static void cfq_shutdown_timer_wq(struct cfq_data *cfqd) |
2403 | { | 2419 | { |
2404 | del_timer_sync(&cfqd->idle_slice_timer); | 2420 | del_timer_sync(&cfqd->idle_slice_timer); |
2405 | cancel_work_sync(&cfqd->unplug_work); | 2421 | cancel_delayed_work_sync(&cfqd->unplug_work); |
2406 | } | 2422 | } |
2407 | 2423 | ||
2408 | static void cfq_put_async_queues(struct cfq_data *cfqd) | 2424 | static void cfq_put_async_queues(struct cfq_data *cfqd) |
@@ -2484,7 +2500,7 @@ static void *cfq_init_queue(struct request_queue *q) | |||
2484 | cfqd->idle_slice_timer.function = cfq_idle_slice_timer; | 2500 | cfqd->idle_slice_timer.function = cfq_idle_slice_timer; |
2485 | cfqd->idle_slice_timer.data = (unsigned long) cfqd; | 2501 | cfqd->idle_slice_timer.data = (unsigned long) cfqd; |
2486 | 2502 | ||
2487 | INIT_WORK(&cfqd->unplug_work, cfq_kick_queue); | 2503 | INIT_DELAYED_WORK(&cfqd->unplug_work, cfq_kick_queue); |
2488 | 2504 | ||
2489 | cfqd->cfq_quantum = cfq_quantum; | 2505 | cfqd->cfq_quantum = cfq_quantum; |
2490 | cfqd->cfq_fifo_expire[0] = cfq_fifo_expire[0]; | 2506 | cfqd->cfq_fifo_expire[0] = cfq_fifo_expire[0]; |