]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
block: use trylock to avoid lockdep circular dependency in sysfs
authorMing Lei <ming.lei@redhat.com>
Thu, 5 Mar 2026 03:15:50 +0000 (11:15 +0800)
committerJens Axboe <axboe@kernel.dk>
Thu, 5 Mar 2026 11:01:42 +0000 (04:01 -0700)
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>
block/blk-sysfs.c
block/elevator.c

index f3b1968c80ced8820b127a2086bd57e7c8a96476..55a1bbfef7d453e59d9b62bbcc6030747070d820 100644 (file)
@@ -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;
index ebe2a1fcf011f9f1e573f73062b40ee24c4df96a..3bcd37c2aa34012c9c60ef0167c56fe9b82d7a2c 100644 (file)
@@ -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;