Same handling as the preceding raid1 commit: flag P2PDMA master bios with R10BIO_P2PDMA at submission; on a BLK_STS_TARGET leg failure retry writes once as a whole range, don't set WantReplacement, block the leg for reads without charging the read-error budget, don't trip FailFast. Replacement legs keep the stock fail-on-write-error policy: badblocks are never recorded on a replacement, so failing it is the only outcome that cannot leave a silent hole in a rebuild. Fixes: 02666132403a ("md: propagate BLK_FEAT_PCI_P2PDMA from member devices to RAID device") Assisted-by: Claude:claude-opus-4-8 Signed-off-by: Mykola Marzhan --- drivers/md/raid10.c | 63 ++++++++++++++++++++++++++++++++++----------- drivers/md/raid10.h | 2 ++ 2 files changed, 50 insertions(+), 15 deletions(-) diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index f7ef903a3d4e..4c3da50250a5 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -482,15 +482,23 @@ static void raid10_end_write_request(struct bio *bio) */ md_error(rdev->mddev, rdev); else { - set_bit(WriteErrorSeen, &rdev->flags); - if (!test_and_set_bit(WantReplacement, &rdev->flags)) - set_bit(MD_RECOVERY_NEEDED, - &rdev->mddev->recovery); + /* Peer/member pairing failure, not member health. */ + bool p2pdma_unmappable = + bio->bi_status == BLK_STS_TARGET && + test_bit(R10BIO_P2PDMA, &r10_bio->state); + set_bit(WriteErrorSeen, &rdev->flags); dec_rdev = 0; - if (test_bit(FailFast, &rdev->flags) && - (bio->bi_opf & MD_FAILFAST)) { - md_error(rdev->mddev, rdev); + if (!p2pdma_unmappable) { + if (!test_and_set_bit(WantReplacement, + &rdev->flags)) + set_bit(MD_RECOVERY_NEEDED, + &rdev->mddev->recovery); + + if (test_bit(FailFast, &rdev->flags) && + (bio->bi_opf & MD_FAILFAST)) { + md_error(rdev->mddev, rdev); + } } /* @@ -1170,6 +1178,9 @@ static void raid10_read_request(struct mddev *mddev, struct bio *bio, */ gfp_t gfp = err_path ? (GFP_NOIO | __GFP_HIGH) : GFP_NOIO; + if (md_bio_is_p2pdma(bio)) + set_bit(R10BIO_P2PDMA, &r10_bio->state); + if (slot >= 0 && r10_bio->devs[slot].rdev) { /* * This is an error retry, but we cannot @@ -1357,6 +1368,9 @@ static bool raid10_write_request(struct mddev *mddev, struct bio *bio, sector_t sectors; int max_sectors; + if (md_bio_is_p2pdma(bio)) + set_bit(R10BIO_P2PDMA, &r10_bio->state); + if ((mddev_is_clustered(mddev) && mddev->cluster_ops->area_resyncing(mddev, WRITE, bio->bi_iter.bi_sector, @@ -2786,7 +2800,7 @@ static void fix_read_error(struct r10conf *conf, struct mddev *mddev, struct r10 } } -static void narrow_write_error(struct r10bio *r10_bio, int i) +static void narrow_write_error(struct r10bio *r10_bio, int i, bool coarse) { struct bio *bio = r10_bio->master_bio; struct mddev *mddev = r10_bio->mddev; @@ -2800,6 +2814,9 @@ static void narrow_write_error(struct r10bio *r10_bio, int i) * It is conceivable that the bio doesn't exactly align with * blocks. We must handle this. * + * With 'coarse', retry the whole range as one bio: P2PDMA + * mapping failures fail every block identically. + * * We currently own a reference to the rdev. */ @@ -2814,9 +2831,12 @@ static void narrow_write_error(struct r10bio *r10_bio, int i) block_sectors = roundup(1 << rdev->badblocks.shift, lbs); sector = r10_bio->sector; - sectors = ((r10_bio->sector + block_sectors) - & ~(sector_t)(block_sectors - 1)) - - sector; + if (coarse) + sectors = sect_to_write; + else + sectors = ((r10_bio->sector + block_sectors) + & ~(sector_t)(block_sectors - 1)) + - sector; while (sect_to_write) { struct bio *wbio; @@ -2856,6 +2876,7 @@ static void handle_read_error(struct mddev *mddev, struct r10bio *r10_bio) { int slot = r10_bio->read_slot; struct bio *bio; + bool p2pdma_error; struct r10conf *conf = mddev->private; struct md_rdev *rdev = r10_bio->devs[slot].rdev; @@ -2868,17 +2889,24 @@ static void handle_read_error(struct mddev *mddev, struct r10bio *r10_bio) * frozen. */ bio = r10_bio->devs[slot].bio; + /* evaluate before the bio_put() below */ + p2pdma_error = bio->bi_status == BLK_STS_TARGET && + test_bit(R10BIO_P2PDMA, &r10_bio->state); bio_put(bio); r10_bio->devs[slot].bio = NULL; if (mddev->ro) r10_bio->devs[slot].bio = IO_BLOCKED; - else if (!test_bit(FailFast, &rdev->flags)) { + else if (p2pdma_error) { + /* Peer can't reach this member: just redirect the read. */ + r10_bio->devs[slot].bio = IO_BLOCKED; + } else if (test_bit(FailFast, &rdev->flags)) { + md_error(mddev, rdev); + } else { freeze_array(conf, 1); fix_read_error(conf, mddev, r10_bio); unfreeze_array(conf); - } else - md_error(mddev, rdev); + } rdev_dec_pending(rdev, mddev); r10_bio->state = 0; @@ -2947,8 +2975,13 @@ static void handle_write_completed(struct r10conf *conf, struct r10bio *r10_bio) r10_bio->sectors, 0); rdev_dec_pending(rdev, conf->mddev); } else if (bio != NULL && bio->bi_status) { + bool coarse = bio->bi_status == + BLK_STS_TARGET && + test_bit(R10BIO_P2PDMA, + &r10_bio->state); + fail = true; - narrow_write_error(r10_bio, m); + narrow_write_error(r10_bio, m, coarse); rdev_dec_pending(rdev, conf->mddev); } bio = r10_bio->devs[m].repl_bio; diff --git a/drivers/md/raid10.h b/drivers/md/raid10.h index ec79d87fb92f..a2e1554f77db 100644 --- a/drivers/md/raid10.h +++ b/drivers/md/raid10.h @@ -174,6 +174,8 @@ enum r10bio_state { R10BIO_Previous, /* failfast devices did receive failfast requests. */ R10BIO_FailFast, +/* the master bio carries PCI P2PDMA (peer device memory) pages */ + R10BIO_P2PDMA, R10BIO_Discard, }; #endif -- 2.52.0