Skip to content

Commit 21eed79

Browse files
Ming Leiaxboe
authored andcommitted
block: add new helper for disabling elevator switch when deleting disk
Add new helper disable_elv_switch() and new flag QUEUE_FLAG_NO_ELV_SWITCH for disabling elevator switch before deleting disk: - originally flag QUEUE_FLAG_REGISTERED is added for preventing elevator switch during removing disk, but this flag has been used widely for other purposes, so add one new flag for disabling elevator switch only - for avoiding deadlock risk, we have to move elevator queue register/unregister out of elevator lock and queue freeze, which will be done in next patch. However, this way adds small race window between elevator switch and deleting ->queue_kobj, in which elevator queue register/unregister could be run concurrently. The added helper will be used for avoiding the race in the following patch. - drain in-progress elevator switch before deleting disk Suggested-by: Nilay Shroff <[email protected]> Reviewed-by: Christoph Hellwig <[email protected]> Reviewed-by: Hannes Reinecke <[email protected]> Signed-off-by: Ming Lei <[email protected]> Reviewed-by: Nilay Shroff <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Jens Axboe <[email protected]>
1 parent 5c3d858 commit 21eed79

File tree

4 files changed

+27
-3
lines changed

4 files changed

+27
-3
lines changed

block/blk-mq-debugfs.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ static const char *const blk_queue_flag_name[] = {
9494
QUEUE_FLAG_NAME(HCTX_ACTIVE),
9595
QUEUE_FLAG_NAME(SQ_SCHED),
9696
QUEUE_FLAG_NAME(DISABLE_WBT_DEF),
97+
QUEUE_FLAG_NAME(NO_ELV_SWITCH),
9798
};
9899
#undef QUEUE_FLAG_NAME
99100

block/elevator.c

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -680,6 +680,9 @@ void elevator_set_default(struct request_queue *q)
680680
};
681681
int err = 0;
682682

683+
/* now we allow to switch elevator */
684+
blk_queue_flag_clear(QUEUE_FLAG_NO_ELV_SWITCH, q);
685+
683686
if (q->tag_set->flags & BLK_MQ_F_NO_SCHED_BY_DEFAULT)
684687
return;
685688

@@ -744,9 +747,13 @@ ssize_t elv_iosched_store(struct gendisk *disk, const char *buf,
744747
elv_iosched_load_module(ctx.name);
745748

746749
down_read(&set->update_nr_hwq_lock);
747-
ret = elevator_change(q, &ctx);
748-
if (!ret)
749-
ret = count;
750+
if (!blk_queue_no_elv_switch(q)) {
751+
ret = elevator_change(q, &ctx);
752+
if (!ret)
753+
ret = count;
754+
} else {
755+
ret = -ENOENT;
756+
}
750757
up_read(&set->update_nr_hwq_lock);
751758
return ret;
752759
}

block/genhd.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -764,6 +764,16 @@ static void __del_gendisk(struct gendisk *disk)
764764
blk_unfreeze_release_lock(q);
765765
}
766766

767+
static void disable_elv_switch(struct request_queue *q)
768+
{
769+
struct blk_mq_tag_set *set = q->tag_set;
770+
WARN_ON_ONCE(!queue_is_mq(q));
771+
772+
down_write(&set->update_nr_hwq_lock);
773+
blk_queue_flag_set(QUEUE_FLAG_NO_ELV_SWITCH, q);
774+
up_write(&set->update_nr_hwq_lock);
775+
}
776+
767777
/**
768778
* del_gendisk - remove the gendisk
769779
* @disk: the struct gendisk to remove
@@ -792,6 +802,9 @@ void del_gendisk(struct gendisk *disk)
792802
__del_gendisk(disk);
793803
} else {
794804
set = disk->queue->tag_set;
805+
806+
disable_elv_switch(disk->queue);
807+
795808
memflags = memalloc_noio_save();
796809
down_read(&set->update_nr_hwq_lock);
797810
__del_gendisk(disk);

include/linux/blkdev.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -642,6 +642,7 @@ enum {
642642
QUEUE_FLAG_HCTX_ACTIVE, /* at least one blk-mq hctx is active */
643643
QUEUE_FLAG_SQ_SCHED, /* single queue style io dispatch */
644644
QUEUE_FLAG_DISABLE_WBT_DEF, /* for sched to disable/enable wbt */
645+
QUEUE_FLAG_NO_ELV_SWITCH, /* can't switch elevator any more */
645646
QUEUE_FLAG_MAX
646647
};
647648

@@ -679,6 +680,8 @@ void blk_queue_flag_clear(unsigned int flag, struct request_queue *q);
679680
((q)->limits.features & BLK_FEAT_SKIP_TAGSET_QUIESCE)
680681
#define blk_queue_disable_wbt(q) \
681682
test_bit(QUEUE_FLAG_DISABLE_WBT_DEF, &(q)->queue_flags)
683+
#define blk_queue_no_elv_switch(q) \
684+
test_bit(QUEUE_FLAG_NO_ELV_SWITCH, &(q)->queue_flags)
682685

683686
extern void blk_set_pm_only(struct request_queue *q);
684687
extern void blk_clear_pm_only(struct request_queue *q);

0 commit comments

Comments
 (0)