Skip to content

Commit 8e141f9

Browse files
Christoph Hellwigaxboe
Christoph Hellwig
authored andcommitted
block: drain file system I/O on del_gendisk
Instead of delaying draining of file system I/O related items like the blk-qos queues, the integrity read workqueue and timeouts only when the request_queue is removed, do that when del_gendisk is called. This is important for SCSI where the upper level drivers that control the gendisk are separate entities, and the disk can be freed much earlier than the request_queue, or can even be unbound without tearing down the queue. Fixes: edb0872 ("block: move the bdi from the request_queue to the gendisk") Reported-by: Ming Lei <[email protected]> Signed-off-by: Christoph Hellwig <[email protected]> Tested-by: Darrick J. Wong <[email protected]> Link: https://lore.kernel.org/r/[email protected] Tested-by: Yi Zhang <[email protected]> Signed-off-by: Jens Axboe <[email protected]>
1 parent a674153 commit 8e141f9

File tree

4 files changed

+35
-15
lines changed

4 files changed

+35
-15
lines changed

block/blk-core.c

Lines changed: 12 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,6 @@
4949
#include "blk-mq.h"
5050
#include "blk-mq-sched.h"
5151
#include "blk-pm.h"
52-
#include "blk-rq-qos.h"
5352

5453
struct dentry *blk_debugfs_root;
5554

@@ -337,23 +336,25 @@ void blk_put_queue(struct request_queue *q)
337336
}
338337
EXPORT_SYMBOL(blk_put_queue);
339338

340-
void blk_set_queue_dying(struct request_queue *q)
339+
void blk_queue_start_drain(struct request_queue *q)
341340
{
342-
blk_queue_flag_set(QUEUE_FLAG_DYING, q);
343-
344341
/*
345342
* When queue DYING flag is set, we need to block new req
346343
* entering queue, so we call blk_freeze_queue_start() to
347344
* prevent I/O from crossing blk_queue_enter().
348345
*/
349346
blk_freeze_queue_start(q);
350-
351347
if (queue_is_mq(q))
352348
blk_mq_wake_waiters(q);
353-
354349
/* Make blk_queue_enter() reexamine the DYING flag. */
355350
wake_up_all(&q->mq_freeze_wq);
356351
}
352+
353+
void blk_set_queue_dying(struct request_queue *q)
354+
{
355+
blk_queue_flag_set(QUEUE_FLAG_DYING, q);
356+
blk_queue_start_drain(q);
357+
}
357358
EXPORT_SYMBOL_GPL(blk_set_queue_dying);
358359

359360
/**
@@ -385,13 +386,8 @@ void blk_cleanup_queue(struct request_queue *q)
385386
*/
386387
blk_freeze_queue(q);
387388

388-
rq_qos_exit(q);
389-
390389
blk_queue_flag_set(QUEUE_FLAG_DEAD, q);
391390

392-
/* for synchronous bio-based driver finish in-flight integrity i/o */
393-
blk_flush_integrity();
394-
395391
blk_sync_queue(q);
396392
if (queue_is_mq(q))
397393
blk_mq_exit_queue(q);
@@ -474,11 +470,12 @@ int blk_queue_enter(struct request_queue *q, blk_mq_req_flags_t flags)
474470

475471
static inline int bio_queue_enter(struct bio *bio)
476472
{
477-
struct request_queue *q = bio->bi_bdev->bd_disk->queue;
473+
struct gendisk *disk = bio->bi_bdev->bd_disk;
474+
struct request_queue *q = disk->queue;
478475

479476
while (!blk_try_enter_queue(q, false)) {
480477
if (bio->bi_opf & REQ_NOWAIT) {
481-
if (blk_queue_dying(q))
478+
if (test_bit(GD_DEAD, &disk->state))
482479
goto dead;
483480
bio_wouldblock_error(bio);
484481
return -EBUSY;
@@ -495,8 +492,8 @@ static inline int bio_queue_enter(struct bio *bio)
495492
wait_event(q->mq_freeze_wq,
496493
(!q->mq_freeze_depth &&
497494
blk_pm_resume_queue(false, q)) ||
498-
blk_queue_dying(q));
499-
if (blk_queue_dying(q))
495+
test_bit(GD_DEAD, &disk->state));
496+
if (test_bit(GD_DEAD, &disk->state))
500497
goto dead;
501498
}
502499

block/blk.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ struct blk_flush_queue *blk_alloc_flush_queue(int node, int cmd_size,
5151
void blk_free_flush_queue(struct blk_flush_queue *q);
5252

5353
void blk_freeze_queue(struct request_queue *q);
54+
void blk_queue_start_drain(struct request_queue *q);
5455

5556
#define BIO_INLINE_VECS 4
5657
struct bio_vec *bvec_alloc(mempool_t *pool, unsigned short *nr_vecs,

block/genhd.c

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include <linux/badblocks.h>
2727

2828
#include "blk.h"
29+
#include "blk-rq-qos.h"
2930

3031
static struct kobject *block_depr;
3132

@@ -559,6 +560,8 @@ EXPORT_SYMBOL(device_add_disk);
559560
*/
560561
void del_gendisk(struct gendisk *disk)
561562
{
563+
struct request_queue *q = disk->queue;
564+
562565
might_sleep();
563566

564567
if (WARN_ON_ONCE(!disk_live(disk) && !(disk->flags & GENHD_FL_HIDDEN)))
@@ -575,8 +578,26 @@ void del_gendisk(struct gendisk *disk)
575578
fsync_bdev(disk->part0);
576579
__invalidate_device(disk->part0, true);
577580

581+
/*
582+
* Fail any new I/O.
583+
*/
584+
set_bit(GD_DEAD, &disk->state);
578585
set_capacity(disk, 0);
579586

587+
/*
588+
* Prevent new I/O from crossing bio_queue_enter().
589+
*/
590+
blk_queue_start_drain(q);
591+
blk_mq_freeze_queue_wait(q);
592+
593+
rq_qos_exit(q);
594+
blk_sync_queue(q);
595+
blk_flush_integrity();
596+
/*
597+
* Allow using passthrough request again after the queue is torn down.
598+
*/
599+
blk_mq_unfreeze_queue(q);
600+
580601
if (!(disk->flags & GENHD_FL_HIDDEN)) {
581602
sysfs_remove_link(&disk_to_dev(disk)->kobj, "bdi");
582603

include/linux/genhd.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,7 @@ struct gendisk {
149149
unsigned long state;
150150
#define GD_NEED_PART_SCAN 0
151151
#define GD_READ_ONLY 1
152+
#define GD_DEAD 2
152153

153154
struct mutex open_mutex; /* open/close mutex */
154155
unsigned open_partitions; /* number of open partitions */

0 commit comments

Comments
 (0)