]> www.infradead.org Git - users/griffoul/linux.git/commitdiff
blk-zoned: Fix a lockdep complaint about recursive locking
authorBart Van Assche <bvanassche@acm.org>
Mon, 25 Aug 2025 18:27:19 +0000 (11:27 -0700)
committerJens Axboe <axboe@kernel.dk>
Tue, 26 Aug 2025 14:27:24 +0000 (08:27 -0600)
If preparing a write bio fails then blk_zone_wplug_bio_work() calls
bio_endio() with zwplug->lock held. If a device mapper driver is stacked
on top of the zoned block device then this results in nested locking of
zwplug->lock. The resulting lockdep complaint is a false positive
because this is nested locking and not recursive locking. Suppress this
false positive by calling blk_zone_wplug_bio_io_error() without holding
zwplug->lock. This is safe because no code in
blk_zone_wplug_bio_io_error() depends on zwplug->lock being held. This
patch suppresses the following lockdep complaint:

WARNING: possible recursive locking detected
--------------------------------------------
kworker/3:0H/46 is trying to acquire lock:
ffffff882968b830 (&zwplug->lock){-...}-{2:2}, at: blk_zone_write_plug_bio_endio+0x64/0x1f0

but task is already holding lock:
ffffff88315bc230 (&zwplug->lock){-...}-{2:2}, at: blk_zone_wplug_bio_work+0x8c/0x48c

other info that might help us debug this:
 Possible unsafe locking scenario:

       CPU0
       ----
  lock(&zwplug->lock);
  lock(&zwplug->lock);

 *** DEADLOCK ***

 May be due to missing lock nesting notation

3 locks held by kworker/3:0H/46:
 #0: ffffff8809486758 ((wq_completion)sdd_zwplugs){+.+.}-{0:0}, at: process_one_work+0x1bc/0x65c
 #1: ffffffc085de3d70 ((work_completion)(&zwplug->bio_work)){+.+.}-{0:0}, at: process_one_work+0x1e4/0x65c
 #2: ffffff88315bc230 (&zwplug->lock){-...}-{2:2}, at: blk_zone_wplug_bio_work+0x8c/0x48c

stack backtrace:
CPU: 3 UID: 0 PID: 46 Comm: kworker/3:0H Tainted: G        W  OE      6.12.38-android16-5-maybe-dirty-4k #1 8b362b6f76e3645a58cd27d86982bce10d150025
Tainted: [W]=WARN, [O]=OOT_MODULE, [E]=UNSIGNED_MODULE
Hardware name: Spacecraft board based on MALIBU (DT)
Workqueue: sdd_zwplugs blk_zone_wplug_bio_work
Call trace:
 dump_backtrace+0xfc/0x17c
 show_stack+0x18/0x28
 dump_stack_lvl+0x40/0xa0
 dump_stack+0x18/0x24
 print_deadlock_bug+0x38c/0x398
 __lock_acquire+0x13e8/0x2e1c
 lock_acquire+0x134/0x2b4
 _raw_spin_lock_irqsave+0x5c/0x80
 blk_zone_write_plug_bio_endio+0x64/0x1f0
 bio_endio+0x9c/0x240
 __dm_io_complete+0x214/0x260
 clone_endio+0xe8/0x214
 bio_endio+0x218/0x240
 blk_zone_wplug_bio_work+0x204/0x48c
 process_one_work+0x26c/0x65c
 worker_thread+0x33c/0x498
 kthread+0x110/0x134
 ret_from_fork+0x10/0x20

Cc: stable@vger.kernel.org
Cc: Damien Le Moal <dlemoal@kernel.org>
Cc: Christoph Hellwig <hch@lst.de>
Fixes: dd291d77cc90 ("block: Introduce zone write plugging")
Signed-off-by: Bart Van Assche <bvanassche@acm.org>
Reviewed-by: Damien Le Moal <dlemoal@kernel.org>
Link: https://lore.kernel.org/r/20250825182720.1697203-1-bvanassche@acm.org
Signed-off-by: Jens Axboe <axboe@kernel.dk>
block/blk-zoned.c

index ef43aaca49f4d9791b799bc8f2f7888181f909bd..5e2a5788dc3b2965b512bc0bafa022a0f97e8f2d 100644 (file)
@@ -1286,14 +1286,14 @@ static void blk_zone_wplug_bio_work(struct work_struct *work)
        struct block_device *bdev;
        unsigned long flags;
        struct bio *bio;
+       bool prepared;
 
        /*
         * Submit the next plugged BIO. If we do not have any, clear
         * the plugged flag.
         */
-       spin_lock_irqsave(&zwplug->lock, flags);
-
 again:
+       spin_lock_irqsave(&zwplug->lock, flags);
        bio = bio_list_pop(&zwplug->bio_list);
        if (!bio) {
                zwplug->flags &= ~BLK_ZONE_WPLUG_PLUGGED;
@@ -1304,13 +1304,14 @@ again:
        trace_blk_zone_wplug_bio(zwplug->disk->queue, zwplug->zone_no,
                                 bio->bi_iter.bi_sector, bio_sectors(bio));
 
-       if (!blk_zone_wplug_prepare_bio(zwplug, bio)) {
+       prepared = blk_zone_wplug_prepare_bio(zwplug, bio);
+       spin_unlock_irqrestore(&zwplug->lock, flags);
+
+       if (!prepared) {
                blk_zone_wplug_bio_io_error(zwplug, bio);
                goto again;
        }
 
-       spin_unlock_irqrestore(&zwplug->lock, flags);
-
        bdev = bio->bi_bdev;
 
        /*