[PATCH 3/3] blk-zoned: Do not lock zwplug->lock recursively

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



If zoned block devices are stacked and if a lower driver reports an I/O
error, this triggers nested locking of spinlocks. Rework the zoned block
device code such that this doesn't happen anymore. This patch fixes the
following kernel warning:

WARNING: possible recursive locking detected
--------------------------------------------
kworker/6:1H/203 is trying to acquire lock:
ffffff8881697130 (&zwplug->lock){-...}-{2:2}, at: blk_zone_write_plug_bio_endio+0x144/0x290

but task is already holding lock:
ffffff884e99d930 (&zwplug->lock){-...}-{2:2}, at: blk_zone_wplug_bio_work+0x30/0x250

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/6:1H/203:
 #0: ffffff88128ed358 ((wq_completion)sde_zwplugs){+.+.}-{0:0}, at: process_one_work+0x1bc/0x65c
 #1: ffffffc088343d70 ((work_completion)(&zwplug->bio_work)){+.+.}-{0:0}, at: process_one_work+0x1e4/0x65c
 #2: ffffff884e99d930 (&zwplug->lock){-...}-{2:2}, at: blk_zone_wplug_bio_work+0x30/0x250

stack backtrace:
Workqueue: sde_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+0x144/0x290
 bio_endio+0x9c/0x240
 __dm_io_complete+0x210/0x27c
 clone_endio+0xe8/0x214
 bio_endio+0x218/0x240
 blk_crypto_fallback_encrypt_endio+0x78/0x94
 bio_endio+0x218/0x240
 blk_zone_wplug_bio_work+0xa8/0x250
 process_one_work+0x26c/0x65c
 worker_thread+0x33c/0x498
 kthread+0x110/0x134
 ret_from_fork+0x10/0x20

Signed-off-by: Bart Van Assche <bvanassche@xxxxxxx>
---
 block/blk-zoned.c | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/block/blk-zoned.c b/block/blk-zoned.c
index ce5604c92fea..4bff76a06204 100644
--- a/block/blk-zoned.c
+++ b/block/blk-zoned.c
@@ -614,12 +614,11 @@ static void disk_zone_wplug_abort(struct blk_zone_wplug *zwplug)
 	pr_warn_ratelimited("%s: zone %u: Aborting plugged BIOs\n",
 			    zwplug->disk->disk_name, zwplug->zone_no);
 	for (;;) {
-		scoped_guard(spinlock_irqsave, &zwplug->lock) {
+		scoped_guard(spinlock_irqsave, &zwplug->lock)
 			bio = bio_list_pop(&zwplug->bio_list);
-			if (!bio)
-				break;
-			blk_zone_wplug_bio_io_error(zwplug, bio);
-		}
+		if (!bio)
+			break;
+		blk_zone_wplug_bio_io_error(zwplug, bio);
 	}
 }
 
@@ -1236,8 +1235,9 @@ void blk_zone_write_plug_bio_endio(struct bio *bio)
 	 * needing a write pointer update.
 	 */
 	if (bio->bi_status != BLK_STS_OK) {
-		spin_lock_irqsave(&zwplug->lock, flags);
 		disk_zone_wplug_abort(zwplug);
+
+		spin_lock_irqsave(&zwplug->lock, flags);
 		zwplug->flags |= BLK_ZONE_WPLUG_NEED_WP_UPDATE;
 		spin_unlock_irqrestore(&zwplug->lock, flags);
 	}
@@ -1288,13 +1288,12 @@ static void blk_zone_wplug_bio_work(struct work_struct *work)
 	unsigned long flags;
 	struct bio *bio;
 
+again:
 	/*
 	 * Submit the next plugged BIO. If we do not have any, clear
 	 * the plugged flag.
 	 */
 	spin_lock_irqsave(&zwplug->lock, flags);
-
-again:
 	bio = bio_list_pop(&zwplug->bio_list);
 	if (!bio) {
 		zwplug->flags &= ~BLK_ZONE_WPLUG_PLUGGED;
@@ -1303,6 +1302,7 @@ static void blk_zone_wplug_bio_work(struct work_struct *work)
 	}
 
 	if (!blk_zone_wplug_prepare_bio(zwplug, bio)) {
+		spin_unlock_irqrestore(&zwplug->lock, flags);
 		blk_zone_wplug_bio_io_error(zwplug, bio);
 		goto again;
 	}




[Index of Archives]     [Linux RAID]     [Linux SCSI]     [Linux ATA RAID]     [IDE]     [Linux Wireless]     [Linux Kernel]     [ATH6KL]     [Linux Bluetooth]     [Linux Netdev]     [Kernel Newbies]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Device Mapper]

  Powered by Linux