[PATCH] md/raid10: honor REQ_NOWAIT in wait_blocked_dev()

[email protected] Wed, 22 Jul 2026 15:26:45 +0800
Newsgroups org.kernel.vger.linux-raid
Message-ID <[email protected]>
From: liyouhong <[email protected]>

raid10_write_request() already respects REQ_NOWAIT for barrier and reshape
waits, but wait_blocked_dev() still always sleeps in
md_wait_for_blocked_rdev() when a member is Blocked / BlockedBadBlocks.
A NOWAIT write can therefore block in the submit path despite the flag.

Mirror raid1's wait_blocked_rdev(): if nowait is set and an rdev is
blocked, return false without waiting. The write path releases the
barrier, frees r10_bio, and completes the bio with wouldblock.

Discard still calls wait_blocked_dev(..., false). REQ_NOWAIT for discard is
already handled at wait_barrier(); honoring it again in wait_blocked_dev()
is a separate, harder-to-hit path (e.g. io_uring discard) and is left for
a follow-up to keep this fix focused on the reproduced write hang.

Fixes: c9aa889b035f ("md: raid10 add nowait support")
Signed-off-by: liyouhong <[email protected]>
---
 drivers/md/raid10.c | 17 ++++++++++++++---
 1 file changed, 14 insertions(+), 3 deletions(-)

diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
index 0a3cfdd3f5df..2ccca42e0702 100644
--- a/drivers/md/raid10.c
+++ b/drivers/md/raid10.c
@@ -1293,7 +1293,8 @@ static void raid10_write_one_disk(struct mddev *mddev, struct r10bio *r10_bio,
 	}
 }
 
-static void wait_blocked_dev(struct mddev *mddev, struct r10bio *r10_bio)
+static bool wait_blocked_dev(struct mddev *mddev, struct r10bio *r10_bio,
+			     bool nowait)
 {
 	struct r10conf *conf = mddev->private;
 	struct md_rdev *blocked_rdev;
@@ -1323,6 +1324,8 @@ static void wait_blocked_dev(struct mddev *mddev, struct r10bio *r10_bio)
 				set_bit(BlockedBadBlocks, &rdev->flags);
 
 			if (rdev_blocked(rdev)) {
+				if (nowait)
+					return false;
 				blocked_rdev = rdev;
 				atomic_inc(&rdev->nr_pending);
 				break;
@@ -1331,6 +1334,8 @@ static void wait_blocked_dev(struct mddev *mddev, struct r10bio *r10_bio)
 
 		rrdev = conf->mirrors[i].replacement;
 		if (rrdev && rdev_blocked(rrdev)) {
+			if (nowait)
+				return false;
 			atomic_inc(&rrdev->nr_pending);
 			blocked_rdev = rrdev;
 			break;
@@ -1347,6 +1352,7 @@ static void wait_blocked_dev(struct mddev *mddev, struct r10bio *r10_bio)
 		wait_barrier(conf, false);
 		goto retry_wait;
 	}
+	return true;
 }
 
 static bool raid10_write_request(struct mddev *mddev, struct bio *bio,
@@ -1421,7 +1427,12 @@ static bool raid10_write_request(struct mddev *mddev, struct bio *bio,
 	r10_bio->read_slot = -1; /* make sure repl_bio gets freed */
 	raid10_find_phys(conf, r10_bio);
 
-	wait_blocked_dev(mddev, r10_bio);
+	if (!wait_blocked_dev(mddev, r10_bio, bio->bi_opf & REQ_NOWAIT)) {
+		allow_barrier(conf);
+		free_r10bio(r10_bio);
+		bio_wouldblock_error(bio);
+		return false;
+	}
 
 	max_sectors = r10_bio->sectors;
 
@@ -1748,7 +1759,7 @@ static int raid10_handle_discard(struct mddev *mddev, struct bio *bio)
 	r10_bio->sectors = 0;
 	r10_bio->read_slot = -1;
 	memset(r10_bio->devs, 0, sizeof(r10_bio->devs[0]) * geo->raid_disks);
-	wait_blocked_dev(mddev, r10_bio);
+	wait_blocked_dev(mddev, r10_bio, false);
 
 	/*
 	 * For far layout it needs more than one r10bio to cover all regions.