[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.