summaryrefslogtreecommitdiff
path: root/block
diff options
context:
space:
mode:
authorMing Lei <ming.lei@redhat.com>2026-03-05 11:15:50 +0800
committerJens Axboe <axboe@kernel.dk>2026-03-05 04:01:42 -0700
commitce8ee8583ed83122405eabaa8fb351be4d9dc65c (patch)
tree86439944b7169805737e33b20c125e79eed23fba /block
parentd90c470b0eca9d2d77a23a1cd7d6ac7fb02d7cb8 (diff)
block: use trylock to avoid lockdep circular dependency in sysfs
Use trylock instead of blocking lock acquisition for update_nr_hwq_lock in queue_requests_store() and elv_iosched_store() to avoid circular lock dependency with kernfs active reference during concurrent disk deletion: update_nr_hwq_lock -> kn->active (via del_gendisk -> kobject_del) kn->active -> update_nr_hwq_lock (via sysfs write path) Return -EBUSY when the lock is not immediately available. Reported-and-tested-by: Yi Zhang <yi.zhang@redhat.com> Closes: https://lore.kernel.org/linux-block/CAHj4cs-em-4acsHabMdT=jJhXkCzjnprD-aQH1OgrZo4nTnmMw@mail.gmail.com/ Fixes: 626ff4f8ebcb ("blk-mq: convert to serialize updating nr_requests with update_nr_hwq_lock") Signed-off-by: Ming Lei <ming.lei@redhat.com> Tested-by: Yi Zhang <yi.zhang@redhat.com> Signed-off-by: Jens Axboe <axboe@kernel.dk>
Diffstat (limited to 'block')
-rw-r--r--block/blk-sysfs.c8
-rw-r--r--block/elevator.c12
2 files changed, 18 insertions, 2 deletions
diff --git a/block/blk-sysfs.c b/block/blk-sysfs.c
index f3b1968c80ce..55a1bbfef7d4 100644
--- a/block/blk-sysfs.c
+++ b/block/blk-sysfs.c
@@ -78,8 +78,14 @@ queue_requests_store(struct gendisk *disk, const char *page, size_t count)
/*
* Serialize updating nr_requests with concurrent queue_requests_store()
* and switching elevator.
+ *
+ * Use trylock to avoid circular lock dependency with kernfs active
+ * reference during concurrent disk deletion:
+ * update_nr_hwq_lock -> kn->active (via del_gendisk -> kobject_del)
+ * kn->active -> update_nr_hwq_lock (via this sysfs write path)
*/
- down_write(&set->update_nr_hwq_lock);
+ if (!down_write_trylock(&set->update_nr_hwq_lock))
+ return -EBUSY;
if (nr == q->nr_requests)
goto unlock;
diff --git a/block/elevator.c b/block/elevator.c
index ebe2a1fcf011..3bcd37c2aa34 100644
--- a/block/elevator.c
+++ b/block/elevator.c
@@ -807,7 +807,16 @@ ssize_t elv_iosched_store(struct gendisk *disk, const char *buf,
elv_iosched_load_module(ctx.name);
ctx.type = elevator_find_get(ctx.name);
- down_read(&set->update_nr_hwq_lock);
+ /*
+ * Use trylock to avoid circular lock dependency with kernfs active
+ * reference during concurrent disk deletion:
+ * update_nr_hwq_lock -> kn->active (via del_gendisk -> kobject_del)
+ * kn->active -> update_nr_hwq_lock (via this sysfs write path)
+ */
+ if (!down_read_trylock(&set->update_nr_hwq_lock)) {
+ ret = -EBUSY;
+ goto out;
+ }
if (!blk_queue_no_elv_switch(q)) {
ret = elevator_change(q, &ctx);
if (!ret)
@@ -817,6 +826,7 @@ ssize_t elv_iosched_store(struct gendisk *disk, const char *buf,
}
up_read(&set->update_nr_hwq_lock);
+out:
if (ctx.type)
elevator_put(ctx.type);
return ret;