[PATCH v3 6/8] md/raid1: skip futile retries on P2PDMA mapping failures

From: Mykola Marzhan

Date: Tue Jul 21 2026 - 13:58:41 EST


A member that cannot DMA-map peer memory fails the leg bio with
BLK_STS_TARGET. The failure is a property of the peer/member
pairing -- retrying the same pages against the same member cannot
succeed, and there is nothing on the medium to repair -- but the
error machinery treats it as a medium error: narrow_write_error()
grinds through hundreds of doomed chunk retries per write,
WantReplacement burns a spare and evicts the healthy member,
fix_read_error()'s host-page probe "succeeds" so mixed host/P2P
reads charge the read-error budget until a healthy member is
kicked (~1s in testing), and FailFast evicts on the first
unroutable I/O.

Flag P2PDMA master bios with a new R1BIO_P2PDMA state bit at
submission. On a BLK_STS_TARGET leg failure for a flagged bio:
retry writes once as a single whole range, recording one bad range
if that also fails (TARGET can be a transient device condition,
e.g. NVME_SC_NS_NOT_READY, so the retry is not skipped outright);
don't set WantReplacement; mark failed read legs IO_BLOCKED without
charging the read-error budget; and don't treat the failure as
FailFast evidence -- the request never reached the wire -- as
commit f7b24c7b41f2 ("md/raid1,raid10: don't fail devices for
invalid IO errors") did for BLK_STS_INVAL.

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 <mykola@xxxxxxxxxxx>
---
drivers/md/raid1.c | 54 ++++++++++++++++++++++++++++++++++------------
drivers/md/raid1.h | 2 ++
2 files changed, 42 insertions(+), 14 deletions(-)

diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
index 16b7465c233a..6334032c4bb8 100644
--- a/drivers/md/raid1.c
+++ b/drivers/md/raid1.c
@@ -483,16 +483,22 @@ static void raid1_end_write_request(struct bio *bio)
* 'one mirror IO has finished' event handler:
*/
if (bio->bi_status && !ignore_error) {
- set_bit(WriteErrorSeen, &rdev->flags);
- if (!test_and_set_bit(WantReplacement, &rdev->flags))
- set_bit(MD_RECOVERY_NEEDED, &
- conf->mddev->recovery);
+ /* Peer/member pairing failure, not member health. */
+ bool p2pdma_unmappable = bio->bi_status == BLK_STS_TARGET &&
+ test_bit(R1BIO_P2PDMA, &r1_bio->state);

- if (test_bit(FailFast, &rdev->flags) &&
- (bio->bi_opf & MD_FAILFAST) &&
- /* We never try FailFast to WriteMostly devices */
- !test_bit(WriteMostly, &rdev->flags)) {
- md_error(r1_bio->mddev, rdev);
+ set_bit(WriteErrorSeen, &rdev->flags);
+ if (!p2pdma_unmappable) {
+ if (!test_and_set_bit(WantReplacement, &rdev->flags))
+ set_bit(MD_RECOVERY_NEEDED,
+ &conf->mddev->recovery);
+
+ if (test_bit(FailFast, &rdev->flags) &&
+ (bio->bi_opf & MD_FAILFAST) &&
+ /* We never try FailFast to WriteMostly devices */
+ !test_bit(WriteMostly, &rdev->flags)) {
+ md_error(r1_bio->mddev, rdev);
+ }
}

/*
@@ -1378,6 +1384,8 @@ static void raid1_read_request(struct mddev *mddev, struct bio *bio,
else
init_r1bio(r1_bio, mddev, bio);
r1_bio->sectors = max_read_sectors;
+ if (md_bio_is_p2pdma(bio))
+ set_bit(R1BIO_P2PDMA, &r1_bio->state);

/*
* make_request() can abort the operation when read-ahead is being
@@ -1557,6 +1565,8 @@ static bool raid1_write_request(struct mddev *mddev, struct bio *bio,

r1_bio = alloc_r1bio(mddev, bio);
r1_bio->sectors = max_sectors;
+ if (md_bio_is_p2pdma(bio))
+ set_bit(R1BIO_P2PDMA, &r1_bio->state);

/* first select target devices under rcu_lock and
* inc refcount on their rdev. Record them by setting
@@ -2522,7 +2532,7 @@ static void fix_read_error(struct r1conf *conf, struct r1bio *r1_bio)
}
}

-static void narrow_write_error(struct r1bio *r1_bio, int i)
+static void narrow_write_error(struct r1bio *r1_bio, int i, bool coarse)
{
struct mddev *mddev = r1_bio->mddev;
struct r1conf *conf = mddev->private;
@@ -2536,6 +2546,9 @@ static void narrow_write_error(struct r1bio *r1_bio, int i)
* It is conceivable that the bio doesn't exactly align with
* blocks. We must handle this somehow.
*
+ * With 'coarse', retry the whole range as one bio: P2PDMA
+ * mapping failures fail every block identically.
+ *
* We currently own a reference on the rdev.
*/

@@ -2550,9 +2563,12 @@ static void narrow_write_error(struct r1bio *r1_bio, int i)
block_sectors = roundup(1 << rdev->badblocks.shift, lbs);

sector = r1_bio->sector;
- sectors = ((sector + block_sectors)
- & ~(sector_t)(block_sectors - 1))
- - sector;
+ if (coarse)
+ sectors = sect_to_write;
+ else
+ sectors = ((sector + block_sectors)
+ & ~(sector_t)(block_sectors - 1))
+ - sector;

while (sect_to_write) {
struct bio *wbio;
@@ -2633,8 +2649,12 @@ static void handle_write_finished(struct r1conf *conf, struct r1bio *r1_bio)
* narrow down and record precise write
* errors.
*/
+ bool coarse = r1_bio->bios[m]->bi_status ==
+ BLK_STS_TARGET &&
+ test_bit(R1BIO_P2PDMA, &r1_bio->state);
+
fail = true;
- narrow_write_error(r1_bio, m);
+ narrow_write_error(r1_bio, m, coarse);
rdev_dec_pending(conf->mirrors[m].rdev,
conf->mddev);
}
@@ -2661,6 +2681,9 @@ static void handle_read_error(struct r1conf *conf, struct r1bio *r1_bio)
{
struct md_rdev *rdev = conf->mirrors[r1_bio->read_disk].rdev;
struct bio *bio = r1_bio->bios[r1_bio->read_disk];
+ /* evaluate before the bio_put() below */
+ bool p2pdma_error = bio->bi_status == BLK_STS_TARGET &&
+ test_bit(R1BIO_P2PDMA, &r1_bio->state);
struct mddev *mddev = conf->mddev;
sector_t sector;

@@ -2680,6 +2703,9 @@ static void handle_read_error(struct r1conf *conf, struct r1bio *r1_bio)
*/
if (mddev->ro) {
r1_bio->bios[r1_bio->read_disk] = IO_BLOCKED;
+ } else if (p2pdma_error) {
+ /* Peer can't reach this member: just redirect the read. */
+ r1_bio->bios[r1_bio->read_disk] = IO_BLOCKED;
} else if (test_bit(FailFast, &rdev->flags)) {
md_error(mddev, rdev);
} else {
diff --git a/drivers/md/raid1.h b/drivers/md/raid1.h
index c98d43a7ae99..61b788a99d14 100644
--- a/drivers/md/raid1.h
+++ b/drivers/md/raid1.h
@@ -184,6 +184,8 @@ enum r1bio_state {
R1BIO_MadeGood,
R1BIO_WriteError,
R1BIO_FailFast,
+/* the master bio carries PCI P2PDMA (peer device memory) pages */
+ R1BIO_P2PDMA,
};

static inline int sector_to_idx(sector_t sector)
--
2.52.0