diff options
-rw-r--r-- | block/blk-core.c | 57 | ||||
-rw-r--r-- | block/blk-sysfs.c | 1 | ||||
-rw-r--r-- | block/blk-throttle.c | 50 | ||||
-rw-r--r-- | block/blk.h | 6 | ||||
-rw-r--r-- | block/elevator.c | 2 |
5 files changed, 87 insertions, 29 deletions
diff --git a/block/blk-core.c b/block/blk-core.c index 034cbb2024f0..7e1523521c70 100644 --- a/block/blk-core.c +++ b/block/blk-core.c | |||
@@ -349,11 +349,13 @@ EXPORT_SYMBOL(blk_put_queue); | |||
349 | /** | 349 | /** |
350 | * blk_drain_queue - drain requests from request_queue | 350 | * blk_drain_queue - drain requests from request_queue |
351 | * @q: queue to drain | 351 | * @q: queue to drain |
352 | * @drain_all: whether to drain all requests or only the ones w/ ELVPRIV | ||
352 | * | 353 | * |
353 | * Drain ELV_PRIV requests from @q. The caller is responsible for ensuring | 354 | * Drain requests from @q. If @drain_all is set, all requests are drained. |
354 | * that no new requests which need to be drained are queued. | 355 | * If not, only ELVPRIV requests are drained. The caller is responsible |
356 | * for ensuring that no new requests which need to be drained are queued. | ||
355 | */ | 357 | */ |
356 | void blk_drain_queue(struct request_queue *q) | 358 | void blk_drain_queue(struct request_queue *q, bool drain_all) |
357 | { | 359 | { |
358 | while (true) { | 360 | while (true) { |
359 | int nr_rqs; | 361 | int nr_rqs; |
@@ -361,9 +363,15 @@ void blk_drain_queue(struct request_queue *q) | |||
361 | spin_lock_irq(q->queue_lock); | 363 | spin_lock_irq(q->queue_lock); |
362 | 364 | ||
363 | elv_drain_elevator(q); | 365 | elv_drain_elevator(q); |
366 | if (drain_all) | ||
367 | blk_throtl_drain(q); | ||
364 | 368 | ||
365 | __blk_run_queue(q); | 369 | __blk_run_queue(q); |
366 | nr_rqs = q->rq.elvpriv; | 370 | |
371 | if (drain_all) | ||
372 | nr_rqs = q->rq.count[0] + q->rq.count[1]; | ||
373 | else | ||
374 | nr_rqs = q->rq.elvpriv; | ||
367 | 375 | ||
368 | spin_unlock_irq(q->queue_lock); | 376 | spin_unlock_irq(q->queue_lock); |
369 | 377 | ||
@@ -373,30 +381,40 @@ void blk_drain_queue(struct request_queue *q) | |||
373 | } | 381 | } |
374 | } | 382 | } |
375 | 383 | ||
376 | /* | 384 | /** |
377 | * Note: If a driver supplied the queue lock, it is disconnected | 385 | * blk_cleanup_queue - shutdown a request queue |
378 | * by this function. The actual state of the lock doesn't matter | 386 | * @q: request queue to shutdown |
379 | * here as the request_queue isn't accessible after this point | 387 | * |
380 | * (QUEUE_FLAG_DEAD is set) and no other requests will be queued. | 388 | * Mark @q DEAD, drain all pending requests, destroy and put it. All |
389 | * future requests will be failed immediately with -ENODEV. | ||
381 | */ | 390 | */ |
382 | void blk_cleanup_queue(struct request_queue *q) | 391 | void blk_cleanup_queue(struct request_queue *q) |
383 | { | 392 | { |
384 | /* | 393 | spinlock_t *lock = q->queue_lock; |
385 | * We know we have process context here, so we can be a little | ||
386 | * cautious and ensure that pending block actions on this device | ||
387 | * are done before moving on. Going into this function, we should | ||
388 | * not have processes doing IO to this device. | ||
389 | */ | ||
390 | blk_sync_queue(q); | ||
391 | 394 | ||
392 | del_timer_sync(&q->backing_dev_info.laptop_mode_wb_timer); | 395 | /* mark @q DEAD, no new request or merges will be allowed afterwards */ |
393 | mutex_lock(&q->sysfs_lock); | 396 | mutex_lock(&q->sysfs_lock); |
394 | queue_flag_set_unlocked(QUEUE_FLAG_DEAD, q); | 397 | queue_flag_set_unlocked(QUEUE_FLAG_DEAD, q); |
395 | mutex_unlock(&q->sysfs_lock); | 398 | |
399 | spin_lock_irq(lock); | ||
400 | queue_flag_set(QUEUE_FLAG_NOMERGES, q); | ||
401 | queue_flag_set(QUEUE_FLAG_NOXMERGES, q); | ||
402 | queue_flag_set(QUEUE_FLAG_DEAD, q); | ||
396 | 403 | ||
397 | if (q->queue_lock != &q->__queue_lock) | 404 | if (q->queue_lock != &q->__queue_lock) |
398 | q->queue_lock = &q->__queue_lock; | 405 | q->queue_lock = &q->__queue_lock; |
399 | 406 | ||
407 | spin_unlock_irq(lock); | ||
408 | mutex_unlock(&q->sysfs_lock); | ||
409 | |||
410 | /* drain all requests queued before DEAD marking */ | ||
411 | blk_drain_queue(q, true); | ||
412 | |||
413 | /* @q won't process any more request, flush async actions */ | ||
414 | del_timer_sync(&q->backing_dev_info.laptop_mode_wb_timer); | ||
415 | blk_sync_queue(q); | ||
416 | |||
417 | /* @q is and will stay empty, shutdown and put */ | ||
400 | blk_put_queue(q); | 418 | blk_put_queue(q); |
401 | } | 419 | } |
402 | EXPORT_SYMBOL(blk_cleanup_queue); | 420 | EXPORT_SYMBOL(blk_cleanup_queue); |
@@ -1509,9 +1527,6 @@ generic_make_request_checks(struct bio *bio) | |||
1509 | goto end_io; | 1527 | goto end_io; |
1510 | } | 1528 | } |
1511 | 1529 | ||
1512 | if (unlikely(test_bit(QUEUE_FLAG_DEAD, &q->queue_flags))) | ||
1513 | goto end_io; | ||
1514 | |||
1515 | part = bio->bi_bdev->bd_part; | 1530 | part = bio->bi_bdev->bd_part; |
1516 | if (should_fail_request(part, bio->bi_size) || | 1531 | if (should_fail_request(part, bio->bi_size) || |
1517 | should_fail_request(&part_to_disk(part)->part0, | 1532 | should_fail_request(&part_to_disk(part)->part0, |
diff --git a/block/blk-sysfs.c b/block/blk-sysfs.c index a8eff5f8b9c5..e7f9f657f105 100644 --- a/block/blk-sysfs.c +++ b/block/blk-sysfs.c | |||
@@ -490,6 +490,7 @@ static void blk_release_queue(struct kobject *kobj) | |||
490 | if (q->queue_tags) | 490 | if (q->queue_tags) |
491 | __blk_queue_free_tags(q); | 491 | __blk_queue_free_tags(q); |
492 | 492 | ||
493 | blk_throtl_release(q); | ||
493 | blk_trace_shutdown(q); | 494 | blk_trace_shutdown(q); |
494 | 495 | ||
495 | bdi_destroy(&q->backing_dev_info); | 496 | bdi_destroy(&q->backing_dev_info); |
diff --git a/block/blk-throttle.c b/block/blk-throttle.c index 900a0c98745b..8edb9499b509 100644 --- a/block/blk-throttle.c +++ b/block/blk-throttle.c | |||
@@ -309,6 +309,10 @@ static struct throtl_grp * throtl_get_tg(struct throtl_data *td) | |||
309 | struct blkio_cgroup *blkcg; | 309 | struct blkio_cgroup *blkcg; |
310 | struct request_queue *q = td->queue; | 310 | struct request_queue *q = td->queue; |
311 | 311 | ||
312 | /* no throttling for dead queue */ | ||
313 | if (unlikely(test_bit(QUEUE_FLAG_DEAD, &q->queue_flags))) | ||
314 | return NULL; | ||
315 | |||
312 | rcu_read_lock(); | 316 | rcu_read_lock(); |
313 | blkcg = task_blkio_cgroup(current); | 317 | blkcg = task_blkio_cgroup(current); |
314 | tg = throtl_find_tg(td, blkcg); | 318 | tg = throtl_find_tg(td, blkcg); |
@@ -1001,11 +1005,6 @@ static void throtl_release_tgs(struct throtl_data *td) | |||
1001 | } | 1005 | } |
1002 | } | 1006 | } |
1003 | 1007 | ||
1004 | static void throtl_td_free(struct throtl_data *td) | ||
1005 | { | ||
1006 | kfree(td); | ||
1007 | } | ||
1008 | |||
1009 | /* | 1008 | /* |
1010 | * Blk cgroup controller notification saying that blkio_group object is being | 1009 | * Blk cgroup controller notification saying that blkio_group object is being |
1011 | * delinked as associated cgroup object is going away. That also means that | 1010 | * delinked as associated cgroup object is going away. That also means that |
@@ -1204,6 +1203,41 @@ out: | |||
1204 | return throttled; | 1203 | return throttled; |
1205 | } | 1204 | } |
1206 | 1205 | ||
1206 | /** | ||
1207 | * blk_throtl_drain - drain throttled bios | ||
1208 | * @q: request_queue to drain throttled bios for | ||
1209 | * | ||
1210 | * Dispatch all currently throttled bios on @q through ->make_request_fn(). | ||
1211 | */ | ||
1212 | void blk_throtl_drain(struct request_queue *q) | ||
1213 | __releases(q->queue_lock) __acquires(q->queue_lock) | ||
1214 | { | ||
1215 | struct throtl_data *td = q->td; | ||
1216 | struct throtl_rb_root *st = &td->tg_service_tree; | ||
1217 | struct throtl_grp *tg; | ||
1218 | struct bio_list bl; | ||
1219 | struct bio *bio; | ||
1220 | |||
1221 | lockdep_is_held(q->queue_lock); | ||
1222 | |||
1223 | bio_list_init(&bl); | ||
1224 | |||
1225 | while ((tg = throtl_rb_first(st))) { | ||
1226 | throtl_dequeue_tg(td, tg); | ||
1227 | |||
1228 | while ((bio = bio_list_peek(&tg->bio_lists[READ]))) | ||
1229 | tg_dispatch_one_bio(td, tg, bio_data_dir(bio), &bl); | ||
1230 | while ((bio = bio_list_peek(&tg->bio_lists[WRITE]))) | ||
1231 | tg_dispatch_one_bio(td, tg, bio_data_dir(bio), &bl); | ||
1232 | } | ||
1233 | spin_unlock_irq(q->queue_lock); | ||
1234 | |||
1235 | while ((bio = bio_list_pop(&bl))) | ||
1236 | generic_make_request(bio); | ||
1237 | |||
1238 | spin_lock_irq(q->queue_lock); | ||
1239 | } | ||
1240 | |||
1207 | int blk_throtl_init(struct request_queue *q) | 1241 | int blk_throtl_init(struct request_queue *q) |
1208 | { | 1242 | { |
1209 | struct throtl_data *td; | 1243 | struct throtl_data *td; |
@@ -1276,7 +1310,11 @@ void blk_throtl_exit(struct request_queue *q) | |||
1276 | * it. | 1310 | * it. |
1277 | */ | 1311 | */ |
1278 | throtl_shutdown_wq(q); | 1312 | throtl_shutdown_wq(q); |
1279 | throtl_td_free(td); | 1313 | } |
1314 | |||
1315 | void blk_throtl_release(struct request_queue *q) | ||
1316 | { | ||
1317 | kfree(q->td); | ||
1280 | } | 1318 | } |
1281 | 1319 | ||
1282 | static int __init throtl_init(void) | 1320 | static int __init throtl_init(void) |
diff --git a/block/blk.h b/block/blk.h index c018dba4e335..3f6551b3c92d 100644 --- a/block/blk.h +++ b/block/blk.h | |||
@@ -15,7 +15,7 @@ void blk_rq_bio_prep(struct request_queue *q, struct request *rq, | |||
15 | struct bio *bio); | 15 | struct bio *bio); |
16 | int blk_rq_append_bio(struct request_queue *q, struct request *rq, | 16 | int blk_rq_append_bio(struct request_queue *q, struct request *rq, |
17 | struct bio *bio); | 17 | struct bio *bio); |
18 | void blk_drain_queue(struct request_queue *q); | 18 | void blk_drain_queue(struct request_queue *q, bool drain_all); |
19 | void blk_dequeue_request(struct request *rq); | 19 | void blk_dequeue_request(struct request *rq); |
20 | void __blk_queue_free_tags(struct request_queue *q); | 20 | void __blk_queue_free_tags(struct request_queue *q); |
21 | bool __blk_end_bidi_request(struct request *rq, int error, | 21 | bool __blk_end_bidi_request(struct request *rq, int error, |
@@ -191,15 +191,19 @@ static inline int blk_do_io_stat(struct request *rq) | |||
191 | 191 | ||
192 | #ifdef CONFIG_BLK_DEV_THROTTLING | 192 | #ifdef CONFIG_BLK_DEV_THROTTLING |
193 | extern bool blk_throtl_bio(struct request_queue *q, struct bio *bio); | 193 | extern bool blk_throtl_bio(struct request_queue *q, struct bio *bio); |
194 | extern void blk_throtl_drain(struct request_queue *q); | ||
194 | extern int blk_throtl_init(struct request_queue *q); | 195 | extern int blk_throtl_init(struct request_queue *q); |
195 | extern void blk_throtl_exit(struct request_queue *q); | 196 | extern void blk_throtl_exit(struct request_queue *q); |
197 | extern void blk_throtl_release(struct request_queue *q); | ||
196 | #else /* CONFIG_BLK_DEV_THROTTLING */ | 198 | #else /* CONFIG_BLK_DEV_THROTTLING */ |
197 | static inline bool blk_throtl_bio(struct request_queue *q, struct bio *bio) | 199 | static inline bool blk_throtl_bio(struct request_queue *q, struct bio *bio) |
198 | { | 200 | { |
199 | return false; | 201 | return false; |
200 | } | 202 | } |
203 | static inline void blk_throtl_drain(struct request_queue *q) { } | ||
201 | static inline int blk_throtl_init(struct request_queue *q) { return 0; } | 204 | static inline int blk_throtl_init(struct request_queue *q) { return 0; } |
202 | static inline void blk_throtl_exit(struct request_queue *q) { } | 205 | static inline void blk_throtl_exit(struct request_queue *q) { } |
206 | static inline void blk_throtl_release(struct request_queue *q) { } | ||
203 | #endif /* CONFIG_BLK_DEV_THROTTLING */ | 207 | #endif /* CONFIG_BLK_DEV_THROTTLING */ |
204 | 208 | ||
205 | #endif /* BLK_INTERNAL_H */ | 209 | #endif /* BLK_INTERNAL_H */ |
diff --git a/block/elevator.c b/block/elevator.c index 74a277ffed39..66343d6917d0 100644 --- a/block/elevator.c +++ b/block/elevator.c | |||
@@ -626,7 +626,7 @@ void elv_quiesce_start(struct request_queue *q) | |||
626 | queue_flag_set(QUEUE_FLAG_ELVSWITCH, q); | 626 | queue_flag_set(QUEUE_FLAG_ELVSWITCH, q); |
627 | spin_unlock_irq(q->queue_lock); | 627 | spin_unlock_irq(q->queue_lock); |
628 | 628 | ||
629 | blk_drain_queue(q); | 629 | blk_drain_queue(q, false); |
630 | } | 630 | } |
631 | 631 | ||
632 | void elv_quiesce_end(struct request_queue *q) | 632 | void elv_quiesce_end(struct request_queue *q) |