mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH v5 00/10] block,md,nvme: correct handling of unsupported P2PDMA transfers
@ 2026-07-23 20:41 Mykola Marzhan
  2026-07-23 20:41 ` [PATCH v5 01/10] block: add BLK_STS_P2PDMA for unsupported peer-to-peer transfers Mykola Marzhan
                   ` (10 more replies)
  0 siblings, 11 replies; 15+ messages in thread
From: Mykola Marzhan @ 2026-07-23 20:41 UTC (permalink / raw)
  To: Jens Axboe, Song Liu, Yu Kuai, Keith Busch, Christoph Hellwig,
	Sagi Grimberg, linux-block, linux-raid, linux-nvme
  Cc: Li Nan, Xiao Ni, Guoqing Jiang, Leon Romanovsky, Jason Gunthorpe,
	Kiran Kumar Modukuri, Chaitanya Kulkarni, Logan Gunthorpe,
	Bjorn Helgaas, Shivaji Kant, Pranjal Shrivastava,
	Henrique Carvalho, stable, linux-kernel, linux-rdma, linux-pci

md treats an unsupported P2PDMA transfer to a member as success, and
nvme-rdma retries one forever.  Whether peer memory can be DMA-mapped
depends on the PCIe topology between the two devices, and since v6.17
the failure completes as BLK_STS_INVAL: retryable for multipath and
deliberately ignored by md for member failures, so mirrors silently
diverge.

v1-v3 restored BLK_STS_TARGET for these failures and tagged P2PDMA
bios in md.  Logan Gunthorpe proposed a dedicated BLK_STS_P2PDMA
instead, so no consumer needs to know whether an I/O was P2P, and
wrote the core patches; v5 is built on them.  Patches 1 and 5 are
his and keep his authorship.

  1  block: add BLK_STS_P2PDMA (stable, v6.17)
  2  md: ensure REQ_NOMERGE is set on P2PDMA bios
  3  md/raid1: serialize non-write-behind writes on CollisionCheck
     rdevs (pre-existing bug patch 4 would widen; stable)
  4  md/raid1: no write-behind for P2PDMA bios
  5  md/raid1,raid10: factor out raid1_write_error() helper
  6  md/raid1,raid10: keep REQ_NOMERGE on narrow_write_error()
     retry clones
  7  md/raid1,raid10: skip futile retries on P2PDMA mapping
     failures
  8  md/raid1,raid10: set IO_BLOCKED in case of BLK_STS_P2PDMA
  9  nvme-rdma: use ib_dma_map_sgtable_attrs() (stable, v7.1;
     dependency of patch 10)
 10  nvme-rdma: return BLK_STS_P2PDMA (stable, v7.1; needs patches
     1 and 9)

Routing: patch 1 block, 2-8 md, 9-10 nvme; 7, 8 and 10 use the new
status.  Patch 1 alone stops the divergence and the dm-multipath
requeue loop; the nvme-rdma loop also needs 9-10; everything else
refines the fallout, so the series bisects safely.  The md patches
fix a v7.2-rc1 regression (02666132403a), except 3 (older bug,
stable) and 5 (refactor).

Tested with the QEMU raid1/raid10 error matrix and a ConnectX-4 Lx.
After patch 1, block-layer error injection accepts status=P2PDMA, so
the md completion paths can be exercised on any member with no P2P
hardware.  The patches were developed with AI assistance (see the
Assisted-by trailers); all code was human-reviewed and tested.

Against v7.2-rc4 (Logan's base).

Changes in v5:
 - patches 7, 8: From: is now Mykola (Logan's request)
   Logan keeps Signed-off-by on both, Co-developed-by on 8
 - patch 8: raid10 declares bio up front and bi_status sits in a
   blk_status_t local in both files.
 - old patch 9 split: 9 is the mechanical sgtable conversion,
   10 the -EREMOTEIO -> BLK_STS_P2PDMA translation; both stable
   since 10 needs 9

Changes in v4:
 - new BLK_STS_P2PDMA (Logan) replaces restoring BLK_STS_TARGET; the
   R1BIO_P2PDMA/R10BIO_P2PDMA state bits are gone and the md changes
   shrink to completion-time status tests
 - blk_dma_map_iter_start() gets the explicit
   PCI_P2PDMA_MAP_NOT_SUPPORTED case (Logan's patch; v3 kept
   default: only)
 - write completions record the whole failed range as bad blocks
   instead of narrow_write_error()'s per-block retries; v3's coarse
   retry is gone -- the new status is deterministic, nothing to
   re-attempt
 - read path: bi_status is evaluated before bio_put()

Link: https://lore.kernel.org/linux-raid/20260718162547.448892-1-mykola@meshstor.io/ [v1]
Link: https://lore.kernel.org/linux-raid/20260719105327.864949-1-mykola@meshstor.io/ [v2]
Link: https://lore.kernel.org/linux-raid/20260721174502.111503-1-mykola@meshstor.io/ [v3]
Link: https://lore.kernel.org/linux-raid/20260722185841.449934-1-mykola@meshstor.io/ [v4]
Link: https://lore.kernel.org/linux-raid/9f846c85-f427-433a-b87d-8e9e3a4406e7@deltatee.com/ [Logan's proposal]

Logan Gunthorpe (2):
  block: add BLK_STS_P2PDMA for unsupported peer-to-peer transfers
  md/raid1,raid10: factor out raid1_write_error() helper

Mykola Marzhan (8):
  md: ensure REQ_NOMERGE is set on P2PDMA bios
  md/raid1: serialize non-write-behind writes on CollisionCheck rdevs
  md/raid1: don't use write-behind for P2PDMA bios
  md/raid1,raid10: keep REQ_NOMERGE on narrow_write_error() retry clones
  md/raid1,raid10: skip futile retries on P2PDMA mapping failures
  md/raid1,raid10: set IO_BLOCKED in case of BLK_STS_P2PDMA
  nvme-rdma: use ib_dma_map_sgtable_attrs()
  nvme-rdma: return BLK_STS_P2PDMA for unsupported P2P transfers

 block/blk-core.c          |  3 +++
 block/blk-mq-dma.c        |  3 ++-
 drivers/md/md.c           | 10 +++++++--
 drivers/md/md.h           | 15 +++++++++++++
 drivers/md/raid1-10.c     | 16 +++++++++++++
 drivers/md/raid1.c        | 47 +++++++++++++++++++++++----------------
 drivers/md/raid10.c       | 27 +++++++++++-----------
 drivers/nvme/host/rdma.c  | 38 ++++++++++++++++++-------------
 include/linux/blk_types.h | 10 +++++++++
 9 files changed, 118 insertions(+), 51 deletions(-)


base-commit: 1590cf0329716306e948a8fc29f1d3ee87d3989f
-- 
2.52.0


^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH v5 01/10] block: add BLK_STS_P2PDMA for unsupported peer-to-peer transfers
  2026-07-23 20:41 [PATCH v5 00/10] block,md,nvme: correct handling of unsupported P2PDMA transfers Mykola Marzhan
@ 2026-07-23 20:41 ` Mykola Marzhan
  2026-07-23 20:41 ` [PATCH v5 02/10] md: ensure REQ_NOMERGE is set on P2PDMA bios Mykola Marzhan
                   ` (9 subsequent siblings)
  10 siblings, 0 replies; 15+ messages in thread
From: Mykola Marzhan @ 2026-07-23 20:41 UTC (permalink / raw)
  To: Jens Axboe, Song Liu, Yu Kuai, Keith Busch, Christoph Hellwig,
	Sagi Grimberg, linux-block, linux-raid, linux-nvme
  Cc: Li Nan, Xiao Ni, Guoqing Jiang, Leon Romanovsky, Jason Gunthorpe,
	Kiran Kumar Modukuri, Chaitanya Kulkarni, Logan Gunthorpe,
	Bjorn Helgaas, Shivaji Kant, Pranjal Shrivastava,
	Henrique Carvalho, stable, linux-kernel, linux-rdma, linux-pci

From: Logan Gunthorpe <logang@deltatee.com>

blk_dma_map_iter_start() reports BLK_STS_INVAL when a P2PDMA transfer
is attempted between two devices whose PCIe topology cannot route it.
blk_path_error() treats INVAL as retryable, so multipath requeues the
I/O forever, and callers cannot tell it apart from an invalid request.
md also ignores it for member failures, so a mirror silently diverges.

Restoring the old BLK_STS_TARGET would stay ambiguous -- nvme maps
NS_NOT_READY, LBA_RANGE and CMD_INTERRUPTED to it too.  Add a dedicated
BLK_STS_P2PDMA, non-retryable in blk_path_error(), and return it from
blk_dma_map_iter_start().

Fixes: 858299dc6160 ("block: add scatterlist-less DMA mapping helpers")
Fixes: 7ce3c1dd78fc ("nvme-pci: convert the data mapping to blk_rq_dma_map")
Cc: stable@vger.kernel.org # v6.17
Signed-off-by: Logan Gunthorpe <logang@deltatee.com>
Signed-off-by: Mykola Marzhan <mykola@meshstor.io>
---
 block/blk-core.c          |  3 +++
 block/blk-mq-dma.c        |  3 ++-
 include/linux/blk_types.h | 10 ++++++++++
 3 files changed, 15 insertions(+), 1 deletion(-)

diff --git a/block/blk-core.c b/block/blk-core.c
index 365641266c9e..83cb5464265f 100644
--- a/block/blk-core.c
+++ b/block/blk-core.c
@@ -177,6 +177,9 @@ static const struct {
 
 	/* Command duration limit device-side timeout */
 	ENT(DURATION_LIMIT,	-ETIME,		"duration limit exceeded"),
+
+	/* no PCIe P2PDMA route between initiator and target */
+	ENT(P2PDMA,		-EREMOTEIO,	"peer-to-peer transfer unroutable"),
 	ENT(INVAL,		-EINVAL,	"invalid"),
 
 	/* everything else not covered above: */
diff --git a/block/blk-mq-dma.c b/block/blk-mq-dma.c
index bfdb9ed70741..e88d6b3524e6 100644
--- a/block/blk-mq-dma.c
+++ b/block/blk-mq-dma.c
@@ -189,8 +189,9 @@ static bool blk_dma_map_iter_start(struct request *req, struct device *dma_dev,
 		 */
 	case PCI_P2PDMA_MAP_NONE:
 		break;
+	case PCI_P2PDMA_MAP_NOT_SUPPORTED:
 	default:
-		iter->status = BLK_STS_INVAL;
+		iter->status = BLK_STS_P2PDMA;
 		return false;
 	}
 
diff --git a/include/linux/blk_types.h b/include/linux/blk_types.h
index 8808ee76e73c..c8de7809320a 100644
--- a/include/linux/blk_types.h
+++ b/include/linux/blk_types.h
@@ -165,6 +165,15 @@ typedef u16 blk_short_t;
  */
 #define BLK_STS_DURATION_LIMIT	((__force blk_status_t)17)
 
+/*
+ * BLK_STS_P2PDMA is returned when a peer-to-peer DMA transfer cannot be
+ * mapped (typically because there is no route between the initiator and the
+ * target that the platform's PCIe topology and ACS settings allow). This
+ * is a property of the initiator/target pair, not of the target device's
+ * health. This error should never be retried.
+ */
+#define BLK_STS_P2PDMA	((__force blk_status_t)18)
+
 /*
  * Invalid size or alignment.
  */
@@ -188,6 +197,7 @@ static inline bool blk_path_error(blk_status_t error)
 	case BLK_STS_NOTSUPP:
 	case BLK_STS_NOSPC:
 	case BLK_STS_TARGET:
+	case BLK_STS_P2PDMA:
 	case BLK_STS_RESV_CONFLICT:
 	case BLK_STS_MEDIUM:
 	case BLK_STS_PROTECTION:
-- 
2.52.0


^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH v5 02/10] md: ensure REQ_NOMERGE is set on P2PDMA bios
  2026-07-23 20:41 [PATCH v5 00/10] block,md,nvme: correct handling of unsupported P2PDMA transfers Mykola Marzhan
  2026-07-23 20:41 ` [PATCH v5 01/10] block: add BLK_STS_P2PDMA for unsupported peer-to-peer transfers Mykola Marzhan
@ 2026-07-23 20:41 ` Mykola Marzhan
  2026-07-23 20:41 ` [PATCH v5 03/10] md/raid1: serialize non-write-behind writes on CollisionCheck rdevs Mykola Marzhan
                   ` (8 subsequent siblings)
  10 siblings, 0 replies; 15+ messages in thread
From: Mykola Marzhan @ 2026-07-23 20:41 UTC (permalink / raw)
  To: Jens Axboe, Song Liu, Yu Kuai, Keith Busch, Christoph Hellwig,
	Sagi Grimberg, linux-block, linux-raid, linux-nvme
  Cc: Li Nan, Xiao Ni, Guoqing Jiang, Leon Romanovsky, Jason Gunthorpe,
	Kiran Kumar Modukuri, Chaitanya Kulkarni, Logan Gunthorpe,
	Bjorn Helgaas, Shivaji Kant, Pranjal Shrivastava,
	Henrique Carvalho, stable, linux-kernel, linux-rdma, linux-pci

md_submit_bio() strips REQ_NOMERGE from every bio.  For P2PDMA bios
the flag is what keeps requests single-provider (see
__bio_add_page()): merging a P2PDMA bio with one over a different
pgmap, or over host memory, maps the merged request with the wrong
bus address.  Set the flag on P2PDMA bios -- bios built via
bio_iov_bvec_set() arrive without it -- and keep stripping it
otherwise.

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@meshstor.io>
Reviewed-by: Logan Gunthorpe <logang@deltatee.com>
---
 drivers/md/md.c | 10 ++++++++--
 drivers/md/md.h | 15 +++++++++++++++
 2 files changed, 23 insertions(+), 2 deletions(-)

diff --git a/drivers/md/md.c b/drivers/md/md.c
index d1465bcd86c8..3770bdb4d4b2 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -451,8 +451,14 @@ static void md_submit_bio(struct bio *bio)
 		return;
 	}
 
-	/* bio could be mergeable after passing to underlayer */
-	bio->bi_opf &= ~REQ_NOMERGE;
+	/*
+	 * A bio md split may merge again below md -- except P2PDMA bios,
+	 * which must stay single-provider (see __bio_add_page()).
+	 */
+	if (md_bio_is_p2pdma(bio))
+		bio->bi_opf |= REQ_NOMERGE;
+	else
+		bio->bi_opf &= ~REQ_NOMERGE;
 
 	md_handle_request(mddev, bio);
 }
diff --git a/drivers/md/md.h b/drivers/md/md.h
index d8daf0f75cbb..73df1a6eccd8 100644
--- a/drivers/md/md.h
+++ b/drivers/md/md.h
@@ -11,8 +11,10 @@
 #include <linux/blkdev.h>
 #include <linux/backing-dev.h>
 #include <linux/badblocks.h>
+#include <linux/bio.h>
 #include <linux/kobject.h>
 #include <linux/list.h>
+#include <linux/memremap.h>
 #include <linux/mm.h>
 #include <linux/mutex.h>
 #include <linux/timer.h>
@@ -22,6 +24,19 @@
 #include <trace/events/block.h>
 
 #define MaxSector (~(sector_t)0)
+
+/*
+ * P2P and host pages never mix within a bio, so the first bvec is
+ * representative.  Read bi_io_vec directly: bio_first_bvec_all()
+ * WARNs on the split clones md handles, and data-less bios have no
+ * bi_io_vec.  Not valid after the bio's iterator is consumed.
+ */
+static inline bool md_bio_is_p2pdma(struct bio *bio)
+{
+	return bio_has_data(bio) && bio->bi_io_vec &&
+	       is_pci_p2pdma_page(bio->bi_io_vec->bv_page);
+}
+
 /*
  * Number of guaranteed raid bios in case of extreme VM load:
  */
-- 
2.52.0


^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH v5 03/10] md/raid1: serialize non-write-behind writes on CollisionCheck rdevs
  2026-07-23 20:41 [PATCH v5 00/10] block,md,nvme: correct handling of unsupported P2PDMA transfers Mykola Marzhan
  2026-07-23 20:41 ` [PATCH v5 01/10] block: add BLK_STS_P2PDMA for unsupported peer-to-peer transfers Mykola Marzhan
  2026-07-23 20:41 ` [PATCH v5 02/10] md: ensure REQ_NOMERGE is set on P2PDMA bios Mykola Marzhan
@ 2026-07-23 20:41 ` Mykola Marzhan
  2026-07-23 20:42 ` [PATCH v5 04/10] md/raid1: don't use write-behind for P2PDMA bios Mykola Marzhan
                   ` (7 subsequent siblings)
  10 siblings, 0 replies; 15+ messages in thread
From: Mykola Marzhan @ 2026-07-23 20:41 UTC (permalink / raw)
  To: Jens Axboe, Song Liu, Yu Kuai, Keith Busch, Christoph Hellwig,
	Sagi Grimberg, linux-block, linux-raid, linux-nvme
  Cc: Li Nan, Xiao Ni, Guoqing Jiang, Leon Romanovsky, Jason Gunthorpe,
	Kiran Kumar Modukuri, Chaitanya Kulkarni, Logan Gunthorpe,
	Bjorn Helgaas, Shivaji Kant, Pranjal Shrivastava,
	Henrique Carvalho, stable, linux-kernel, linux-rdma, linux-pci

A write that skips write-behind (full behind queue, a waiting
reader, failed behind-bio allocation) races the in-flight behind
write it overlaps: nothing orders the two on the write-mostly
member, and if the older behind data lands last the member keeps
stale data for sectors already acknowledged as rewritten.

Serialize on CollisionCheck, which marks exactly the rdevs owning a
serial tree: serialize_policy rdevs plus write-mostly members when
write-behind arms serialization -- the case the MD_SERIALIZE_POLICY
test misses.  remove_serial() under the same condition.  This also
avoids the old gate's latent NULL deref for rdevs hot-added under
serialize_policy (they never get a serial tree).

Fixes: 69df9cfc7042 ("raid1: serialize the overlap write")
Cc: stable@vger.kernel.org
Assisted-by: Claude:claude-fable-5
Signed-off-by: Mykola Marzhan <mykola@meshstor.io>
---
 drivers/md/raid1.c | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
index afe2ca96ad8c..997f79c05db7 100644
--- a/drivers/md/raid1.c
+++ b/drivers/md/raid1.c
@@ -564,7 +564,7 @@ static void raid1_end_write_request(struct bio *bio)
 				call_bio_endio(r1_bio);
 			}
 		}
-	} else if (test_bit(MD_SERIALIZE_POLICY, &rdev->mddev->flags))
+	} else if (test_bit(CollisionCheck, &rdev->flags))
 		remove_serial(rdev, lo, hi);
 	if (r1_bio->bios[mirror] == NULL)
 		rdev_dec_pending(rdev, conf->mddev);
@@ -1677,7 +1677,11 @@ static bool raid1_write_request(struct mddev *mddev, struct bio *bio,
 			mbio = bio_alloc_clone(rdev->bdev, bio, GFP_NOIO,
 					       &mddev->bio_set);
 
-			if (test_bit(MD_SERIALIZE_POLICY, &mddev->flags))
+			/*
+			 * CollisionCheck marks every rdev with a serial
+			 * tree; order against in-flight write-behind I/O.
+			 */
+			if (test_bit(CollisionCheck, &rdev->flags))
 				wait_for_serialization(rdev, r1_bio);
 		}
 
-- 
2.52.0


^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH v5 04/10] md/raid1: don't use write-behind for P2PDMA bios
  2026-07-23 20:41 [PATCH v5 00/10] block,md,nvme: correct handling of unsupported P2PDMA transfers Mykola Marzhan
                   ` (2 preceding siblings ...)
  2026-07-23 20:41 ` [PATCH v5 03/10] md/raid1: serialize non-write-behind writes on CollisionCheck rdevs Mykola Marzhan
@ 2026-07-23 20:42 ` Mykola Marzhan
  2026-07-23 20:42 ` [PATCH v5 05/10] md/raid1,raid10: factor out raid1_write_error() helper Mykola Marzhan
                   ` (6 subsequent siblings)
  10 siblings, 0 replies; 15+ messages in thread
From: Mykola Marzhan @ 2026-07-23 20:42 UTC (permalink / raw)
  To: Jens Axboe, Song Liu, Yu Kuai, Keith Busch, Christoph Hellwig,
	Sagi Grimberg, linux-block, linux-raid, linux-nvme
  Cc: Li Nan, Xiao Ni, Guoqing Jiang, Leon Romanovsky, Jason Gunthorpe,
	Kiran Kumar Modukuri, Chaitanya Kulkarni, Logan Gunthorpe,
	Bjorn Helgaas, Shivaji Kant, Pranjal Shrivastava,
	Henrique Carvalho, stable, linux-kernel, linux-rdma, linux-pci

alloc_behind_master_bio() copies the bio's data with bio_copy_data(),
a CPU copy. P2PDMA pages are peer device (BAR) memory; generic code
must not assume CPU load/store access to them is safe or fast on
every architecture, and bouncing peer memory through the CPU defeats
the point of a peer-to-peer transfer.

Skip write-behind for P2PDMA bios: they are written directly to all
members, including write-mostly ones.  Ordering against write-behind
I/O in flight to overlapping sectors is preserved: the non-behind
clone path serializes on CollisionCheck rdevs (see the preceding
fix), which covers these bios like any other write that bypasses
write-behind.

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@meshstor.io>
Reviewed-by: Logan Gunthorpe <logang@deltatee.com>
---
 drivers/md/raid1.c | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
index 997f79c05db7..7d769b6460ca 100644
--- a/drivers/md/raid1.c
+++ b/drivers/md/raid1.c
@@ -1523,6 +1523,7 @@ static bool raid1_write_request(struct mddev *mddev, struct bio *bio,
 	bool write_behind = false;
 	bool nowait = bio->bi_opf & REQ_NOWAIT;
 	bool is_discard = op_is_discard(bio->bi_opf);
+	bool is_p2pdma = md_bio_is_p2pdma(bio);
 	sector_t sector = bio->bi_iter.bi_sector;
 
 	if (mddev_is_clustered(mddev) &&
@@ -1575,9 +1576,12 @@ static bool raid1_write_request(struct mddev *mddev, struct bio *bio,
 		/*
 		 * The write-behind io is only attempted on drives marked as
 		 * write-mostly, which means we could allocate write behind
-		 * bio later.
+		 * bio later. P2PDMA bios are excluded: write-behind copies
+		 * the data with bio_copy_data(), a CPU copy that cannot be
+		 * assumed safe or fast on P2PDMA (device BAR) pages.
 		 */
-		if (!is_discard && rdev && test_bit(WriteMostly, &rdev->flags))
+		if (!is_discard && !is_p2pdma && rdev &&
+		    test_bit(WriteMostly, &rdev->flags))
 			write_behind = true;
 
 		r1_bio->bios[i] = NULL;
-- 
2.52.0


^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH v5 05/10] md/raid1,raid10: factor out raid1_write_error() helper
  2026-07-23 20:41 [PATCH v5 00/10] block,md,nvme: correct handling of unsupported P2PDMA transfers Mykola Marzhan
                   ` (3 preceding siblings ...)
  2026-07-23 20:42 ` [PATCH v5 04/10] md/raid1: don't use write-behind for P2PDMA bios Mykola Marzhan
@ 2026-07-23 20:42 ` Mykola Marzhan
  2026-07-23 20:42 ` [PATCH v5 06/10] md/raid1,raid10: keep REQ_NOMERGE on narrow_write_error() retry clones Mykola Marzhan
                   ` (5 subsequent siblings)
  10 siblings, 0 replies; 15+ messages in thread
From: Mykola Marzhan @ 2026-07-23 20:42 UTC (permalink / raw)
  To: Jens Axboe, Song Liu, Yu Kuai, Keith Busch, Christoph Hellwig,
	Sagi Grimberg, linux-block, linux-raid, linux-nvme
  Cc: Li Nan, Xiao Ni, Guoqing Jiang, Leon Romanovsky, Jason Gunthorpe,
	Kiran Kumar Modukuri, Chaitanya Kulkarni, Logan Gunthorpe,
	Bjorn Helgaas, Shivaji Kant, Pranjal Shrivastava,
	Henrique Carvalho, stable, linux-kernel, linux-rdma, linux-pci

From: Logan Gunthorpe <logang@deltatee.com>

Factor out a common raid1_write_error() helper from raid1.c and
raid10.c.

This will help reduce code duplication in subsequent patches.

Signed-off-by: Logan Gunthorpe <logang@deltatee.com>
Signed-off-by: Mykola Marzhan <mykola@meshstor.io>
---
 drivers/md/raid1-10.c | 13 +++++++++++++
 drivers/md/raid1.c    | 13 ++-----------
 drivers/md/raid10.c   | 10 +---------
 3 files changed, 16 insertions(+), 20 deletions(-)

diff --git a/drivers/md/raid1-10.c b/drivers/md/raid1-10.c
index 56a56a4da4f8..cee21452e066 100644
--- a/drivers/md/raid1-10.c
+++ b/drivers/md/raid1-10.c
@@ -303,3 +303,16 @@ static inline bool raid1_should_handle_error(struct bio *bio)
 	return !(bio->bi_opf & (REQ_RAHEAD | REQ_NOWAIT)) &&
 		bio->bi_status != BLK_STS_INVAL;
 }
+
+static inline void raid1_write_error(struct mddev *mddev, struct md_rdev *rdev,
+				     struct bio *bio, bool allow_failfast)
+{
+	set_bit(WriteErrorSeen, &rdev->flags);
+
+	if (!test_and_set_bit(WantReplacement, &rdev->flags))
+		set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
+
+	if (allow_failfast && test_bit(FailFast, &rdev->flags) &&
+	    (bio->bi_opf & MD_FAILFAST))
+		md_error(mddev, rdev);
+}
diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
index 7d769b6460ca..f07edeac6e5a 100644
--- a/drivers/md/raid1.c
+++ b/drivers/md/raid1.c
@@ -483,17 +483,8 @@ 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);
-
-		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);
-		}
+		raid1_write_error(conf->mddev, rdev, bio,
+				  !test_bit(WriteMostly, &rdev->flags));
 
 		/*
 		 * When the device is faulty, it is not necessary to
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
index 0a3cfdd3f5df..5b63175fb382 100644
--- a/drivers/md/raid10.c
+++ b/drivers/md/raid10.c
@@ -482,16 +482,8 @@ 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);
-
 			dec_rdev = 0;
-			if (test_bit(FailFast, &rdev->flags) &&
-			    (bio->bi_opf & MD_FAILFAST)) {
-				md_error(rdev->mddev, rdev);
-			}
+			raid1_write_error(rdev->mddev, rdev, bio, true);
 
 			/*
 			 * When the device is faulty, it is not necessary to
-- 
2.52.0


^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH v5 06/10] md/raid1,raid10: keep REQ_NOMERGE on narrow_write_error() retry clones
  2026-07-23 20:41 [PATCH v5 00/10] block,md,nvme: correct handling of unsupported P2PDMA transfers Mykola Marzhan
                   ` (4 preceding siblings ...)
  2026-07-23 20:42 ` [PATCH v5 05/10] md/raid1,raid10: factor out raid1_write_error() helper Mykola Marzhan
@ 2026-07-23 20:42 ` Mykola Marzhan
  2026-07-23 20:42 ` [PATCH v5 07/10] md/raid1,raid10: skip futile retries on P2PDMA mapping failures Mykola Marzhan
                   ` (4 subsequent siblings)
  10 siblings, 0 replies; 15+ messages in thread
From: Mykola Marzhan @ 2026-07-23 20:42 UTC (permalink / raw)
  To: Jens Axboe, Song Liu, Yu Kuai, Keith Busch, Christoph Hellwig,
	Sagi Grimberg, linux-block, linux-raid, linux-nvme
  Cc: Li Nan, Xiao Ni, Guoqing Jiang, Leon Romanovsky, Jason Gunthorpe,
	Kiran Kumar Modukuri, Chaitanya Kulkarni, Logan Gunthorpe,
	Bjorn Helgaas, Shivaji Kant, Pranjal Shrivastava,
	Henrique Carvalho, stable, linux-kernel, linux-rdma, linux-pci

narrow_write_error() re-issues a failed write in badblock-granularity
chunks, cloning from the master bio and resetting bi_opf to a bare
REQ_OP_WRITE. For a P2PDMA bio that reset drops REQ_NOMERGE, which is
the only request-level protection against the member queue merging
P2PDMA segments across pgmaps or with host memory (see the preceding
md_submit_bio() fix): the retry path would quietly reopen the hole
the submission path closes. Restore the flag on P2PDMA retry clones.

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@meshstor.io>
Reviewed-by: Logan Gunthorpe <logang@deltatee.com>
---
 drivers/md/raid1.c  | 3 +++
 drivers/md/raid10.c | 3 +++
 2 files changed, 6 insertions(+)

diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
index f07edeac6e5a..19c4dec450de 100644
--- a/drivers/md/raid1.c
+++ b/drivers/md/raid1.c
@@ -2561,6 +2561,9 @@ static void narrow_write_error(struct r1bio *r1_bio, int i)
 		}
 
 		wbio->bi_opf = REQ_OP_WRITE;
+		/* Keep P2PDMA retry bios unmergeable, like the original */
+		if (md_bio_is_p2pdma(wbio))
+			wbio->bi_opf |= REQ_NOMERGE;
 		wbio->bi_iter.bi_sector = r1_bio->sector;
 		wbio->bi_iter.bi_size = r1_bio->sectors << 9;
 
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
index 5b63175fb382..428bddddfe71 100644
--- a/drivers/md/raid10.c
+++ b/drivers/md/raid10.c
@@ -2823,6 +2823,9 @@ static void narrow_write_error(struct r10bio *r10_bio, int i)
 		wbio->bi_iter.bi_sector = wsector +
 				   choose_data_offset(r10_bio, rdev);
 		wbio->bi_opf = REQ_OP_WRITE;
+		/* Keep P2PDMA retry bios unmergeable, like the original */
+		if (md_bio_is_p2pdma(wbio))
+			wbio->bi_opf |= REQ_NOMERGE;
 
 		if (submit_bio_wait(wbio) &&
 		    !rdev_set_badblocks(rdev, wsector, sectors, 0)) {
-- 
2.52.0


^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH v5 07/10] md/raid1,raid10: skip futile retries on P2PDMA mapping failures
  2026-07-23 20:41 [PATCH v5 00/10] block,md,nvme: correct handling of unsupported P2PDMA transfers Mykola Marzhan
                   ` (5 preceding siblings ...)
  2026-07-23 20:42 ` [PATCH v5 06/10] md/raid1,raid10: keep REQ_NOMERGE on narrow_write_error() retry clones Mykola Marzhan
@ 2026-07-23 20:42 ` Mykola Marzhan
  2026-07-24 15:11   ` Logan Gunthorpe
  2026-07-23 20:42 ` [PATCH v5 08/10] md/raid1,raid10: set IO_BLOCKED in case of BLK_STS_P2PDMA Mykola Marzhan
                   ` (3 subsequent siblings)
  10 siblings, 1 reply; 15+ messages in thread
From: Mykola Marzhan @ 2026-07-23 20:42 UTC (permalink / raw)
  To: Jens Axboe, Song Liu, Yu Kuai, Keith Busch, Christoph Hellwig,
	Sagi Grimberg, linux-block, linux-raid, linux-nvme
  Cc: Li Nan, Xiao Ni, Guoqing Jiang, Leon Romanovsky, Jason Gunthorpe,
	Kiran Kumar Modukuri, Chaitanya Kulkarni, Logan Gunthorpe,
	Bjorn Helgaas, Shivaji Kant, Pranjal Shrivastava,
	Henrique Carvalho, stable, linux-kernel, linux-rdma, linux-pci

BLK_STS_P2PDMA reflects the peer/member pairing, not member health:
retrying the same pages on the same member cannot succeed.  Keep
WriteErrorSeen so the range stays fenced, but skip WantReplacement and
FailFast eviction, as commit f7b24c7b41f2 ("md/raid1,raid10: don't fail
devices for invalid IO errors") did for BLK_STS_INVAL.

The failure is whole-range and deterministic, so narrow_write_error()'s
block-by-block submit_bio_wait() retries are pointless.  Record the
whole range as a bad block in the completion handler instead.

Fixes: 02666132403a ("md: propagate BLK_FEAT_PCI_P2PDMA from member devices to RAID device")
Assisted-by: Claude:claude-fable-5
Signed-off-by: Logan Gunthorpe <logang@deltatee.com>
Signed-off-by: Mykola Marzhan <mykola@meshstor.io>
---
 drivers/md/raid1-10.c |  3 +++
 drivers/md/raid1.c    | 11 ++++++++---
 drivers/md/raid10.c   |  7 ++++++-
 3 files changed, 17 insertions(+), 4 deletions(-)

diff --git a/drivers/md/raid1-10.c b/drivers/md/raid1-10.c
index cee21452e066..89daf8558251 100644
--- a/drivers/md/raid1-10.c
+++ b/drivers/md/raid1-10.c
@@ -309,6 +309,9 @@ static inline void raid1_write_error(struct mddev *mddev, struct md_rdev *rdev,
 {
 	set_bit(WriteErrorSeen, &rdev->flags);
 
+	if (bio->bi_status == BLK_STS_P2PDMA)
+		return;
+
 	if (!test_and_set_bit(WantReplacement, &rdev->flags))
 		set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
 
diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
index 19c4dec450de..83ebf40237d5 100644
--- a/drivers/md/raid1.c
+++ b/drivers/md/raid1.c
@@ -2624,10 +2624,15 @@ static void handle_write_finished(struct r1conf *conf, struct r1bio *r1_bio)
 			 * narrow down and record precise write
 			 * errors.
 			 */
+			struct md_rdev *rdev = conf->mirrors[m].rdev;
+
 			fail = true;
-			narrow_write_error(r1_bio, m);
-			rdev_dec_pending(conf->mirrors[m].rdev,
-					 conf->mddev);
+			if (r1_bio->bios[m]->bi_status == BLK_STS_P2PDMA)
+				rdev_set_badblocks(rdev, r1_bio->sector,
+						   r1_bio->sectors, 0);
+			else
+				narrow_write_error(r1_bio, m);
+			rdev_dec_pending(rdev, conf->mddev);
 		}
 	if (fail) {
 		spin_lock_irq(&conf->device_lock);
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
index 428bddddfe71..77c7d8a59916 100644
--- a/drivers/md/raid10.c
+++ b/drivers/md/raid10.c
@@ -2940,7 +2940,12 @@ static void handle_write_completed(struct r10conf *conf, struct r10bio *r10_bio)
 				rdev_dec_pending(rdev, conf->mddev);
 			} else if (bio != NULL && bio->bi_status) {
 				fail = true;
-				narrow_write_error(r10_bio, m);
+				if (bio->bi_status == BLK_STS_P2PDMA)
+					rdev_set_badblocks(rdev,
+							   r10_bio->devs[m].addr,
+							   r10_bio->sectors, 0);
+				else
+					narrow_write_error(r10_bio, m);
 				rdev_dec_pending(rdev, conf->mddev);
 			}
 			bio = r10_bio->devs[m].repl_bio;
-- 
2.52.0


^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH v5 08/10] md/raid1,raid10: set IO_BLOCKED in case of BLK_STS_P2PDMA
  2026-07-23 20:41 [PATCH v5 00/10] block,md,nvme: correct handling of unsupported P2PDMA transfers Mykola Marzhan
                   ` (6 preceding siblings ...)
  2026-07-23 20:42 ` [PATCH v5 07/10] md/raid1,raid10: skip futile retries on P2PDMA mapping failures Mykola Marzhan
@ 2026-07-23 20:42 ` Mykola Marzhan
  2026-07-23 20:42 ` [PATCH v5 09/10] nvme-rdma: use ib_dma_map_sgtable_attrs() Mykola Marzhan
                   ` (2 subsequent siblings)
  10 siblings, 0 replies; 15+ messages in thread
From: Mykola Marzhan @ 2026-07-23 20:42 UTC (permalink / raw)
  To: Jens Axboe, Song Liu, Yu Kuai, Keith Busch, Christoph Hellwig,
	Sagi Grimberg, linux-block, linux-raid, linux-nvme
  Cc: Li Nan, Xiao Ni, Guoqing Jiang, Leon Romanovsky, Jason Gunthorpe,
	Kiran Kumar Modukuri, Chaitanya Kulkarni, Logan Gunthorpe,
	Bjorn Helgaas, Shivaji Kant, Pranjal Shrivastava,
	Henrique Carvalho, stable, linux-kernel, linux-rdma, linux-pci

A read that fails with BLK_STS_P2PDMA cannot succeed against that
member, so mark the leg IO_BLOCKED and let the retry redirect elsewhere.
Skip the read-error machinery: there is nothing on the medium to fix,
fix_read_error()'s probe reads into host pages and would "succeed", and
charging the read-error budget would evict a healthy member under a P2P
read workload.  FailFast eviction is skipped for the same reason -- the
request never reached the wire.

Fixes: 02666132403a ("md: propagate BLK_FEAT_PCI_P2PDMA from member devices to RAID device")
Assisted-by: Claude:claude-fable-5
Co-developed-by: Logan Gunthorpe <logang@deltatee.com>
Signed-off-by: Logan Gunthorpe <logang@deltatee.com>
Signed-off-by: Mykola Marzhan <mykola@meshstor.io>
---
 drivers/md/raid1.c  | 4 +++-
 drivers/md/raid10.c | 7 ++++---
 2 files changed, 7 insertions(+), 4 deletions(-)

diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
index 83ebf40237d5..16a47568679f 100644
--- a/drivers/md/raid1.c
+++ b/drivers/md/raid1.c
@@ -2657,6 +2657,8 @@ 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 */
+	blk_status_t status = bio->bi_status;
 	struct mddev *mddev = conf->mddev;
 	sector_t sector;
 
@@ -2674,7 +2676,7 @@ static void handle_read_error(struct r1conf *conf, struct r1bio *r1_bio)
 	 * read error.  This is all done synchronously while the array is
 	 * frozen.
 	 */
-	if (mddev->ro) {
+	if (mddev->ro || status == BLK_STS_P2PDMA) {
 		r1_bio->bios[r1_bio->read_disk] = IO_BLOCKED;
 	} else if (test_bit(FailFast, &rdev->flags)) {
 		md_error(mddev, rdev);
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
index 77c7d8a59916..462f622556ed 100644
--- a/drivers/md/raid10.c
+++ b/drivers/md/raid10.c
@@ -2847,7 +2847,9 @@ static void narrow_write_error(struct r10bio *r10_bio, int i)
 static void handle_read_error(struct mddev *mddev, struct r10bio *r10_bio)
 {
 	int slot = r10_bio->read_slot;
-	struct bio *bio;
+	struct bio *bio = r10_bio->devs[slot].bio;
+	/* evaluate before the bio_put() below */
+	blk_status_t status = bio->bi_status;
 	struct r10conf *conf = mddev->private;
 	struct md_rdev *rdev = r10_bio->devs[slot].rdev;
 
@@ -2859,11 +2861,10 @@ static void handle_read_error(struct mddev *mddev, struct r10bio *r10_bio)
 	 * This is all done synchronously while the array is
 	 * frozen.
 	 */
-	bio = r10_bio->devs[slot].bio;
 	bio_put(bio);
 	r10_bio->devs[slot].bio = NULL;
 
-	if (mddev->ro)
+	if (mddev->ro || status == BLK_STS_P2PDMA)
 		r10_bio->devs[slot].bio = IO_BLOCKED;
 	else if (!test_bit(FailFast, &rdev->flags)) {
 		freeze_array(conf, 1);
-- 
2.52.0


^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH v5 09/10] nvme-rdma: use ib_dma_map_sgtable_attrs()
  2026-07-23 20:41 [PATCH v5 00/10] block,md,nvme: correct handling of unsupported P2PDMA transfers Mykola Marzhan
                   ` (7 preceding siblings ...)
  2026-07-23 20:42 ` [PATCH v5 08/10] md/raid1,raid10: set IO_BLOCKED in case of BLK_STS_P2PDMA Mykola Marzhan
@ 2026-07-23 20:42 ` Mykola Marzhan
  2026-07-24 18:47   ` Logan Gunthorpe
  2026-07-23 20:42 ` [PATCH v5 10/10] nvme-rdma: return BLK_STS_P2PDMA for unsupported P2P transfers Mykola Marzhan
  2026-07-24 10:21 ` [PATCH v5 00/10] block,md,nvme: correct handling of unsupported P2PDMA transfers Thorsten Leemhuis
  10 siblings, 1 reply; 15+ messages in thread
From: Mykola Marzhan @ 2026-07-23 20:42 UTC (permalink / raw)
  To: Jens Axboe, Song Liu, Yu Kuai, Keith Busch, Christoph Hellwig,
	Sagi Grimberg, linux-block, linux-raid, linux-nvme
  Cc: Li Nan, Xiao Ni, Guoqing Jiang, Leon Romanovsky, Jason Gunthorpe,
	Kiran Kumar Modukuri, Chaitanya Kulkarni, Logan Gunthorpe,
	Bjorn Helgaas, Shivaji Kant, Pranjal Shrivastava,
	Henrique Carvalho, stable, linux-kernel, linux-rdma, linux-pci

ib_dma_map_sg() folds every mapping error into a zero return, losing
the DMA layer's error code.  Switch both scatterlist mappings to
ib_dma_map_sgtable_attrs(), which preserves it for the next patch to
act on.  No behavior change: failures are still reported as -EIO.

A local sg_table is needed: dma_map_sgtable() maps orig_nents
entries, and the embedded table's orig_nents is the allocated count,
not the count blk_rq_map_sg() produced.  rdma_rw_ctx_init() does the
same.

Assisted-by: Claude:claude-fable-5
Cc: stable@vger.kernel.org # v7.1
Signed-off-by: Mykola Marzhan <mykola@meshstor.io>
---
 drivers/nvme/host/rdma.c | 23 +++++++++++++++--------
 1 file changed, 15 insertions(+), 8 deletions(-)

diff --git a/drivers/nvme/host/rdma.c b/drivers/nvme/host/rdma.c
index 6909e3542794..63830334c73e 100644
--- a/drivers/nvme/host/rdma.c
+++ b/drivers/nvme/host/rdma.c
@@ -1469,6 +1469,7 @@ static int nvme_rdma_dma_map_req(struct ib_device *ibdev, struct request *rq,
 		int *count, int *pi_count)
 {
 	struct nvme_rdma_request *req = blk_mq_rq_to_pdu(rq);
+	struct sg_table sgt;
 	int ret;
 
 	req->data_sgl.sg_table.sgl = (struct scatterlist *)(req + 1);
@@ -1480,12 +1481,16 @@ static int nvme_rdma_dma_map_req(struct ib_device *ibdev, struct request *rq,
 
 	req->data_sgl.nents = blk_rq_map_sg(rq, req->data_sgl.sg_table.sgl);
 
-	*count = ib_dma_map_sg(ibdev, req->data_sgl.sg_table.sgl,
-			       req->data_sgl.nents, rq_dma_dir(rq));
-	if (unlikely(*count <= 0)) {
+	sgt = (struct sg_table) {
+		.sgl		= req->data_sgl.sg_table.sgl,
+		.orig_nents	= req->data_sgl.nents,
+	};
+	ret = ib_dma_map_sgtable_attrs(ibdev, &sgt, rq_dma_dir(rq), 0);
+	if (unlikely(ret)) {
 		ret = -EIO;
 		goto out_free_table;
 	}
+	*count = sgt.nents;
 
 	if (blk_integrity_rq(rq)) {
 		req->metadata_sgl->sg_table.sgl =
@@ -1501,14 +1506,16 @@ static int nvme_rdma_dma_map_req(struct ib_device *ibdev, struct request *rq,
 
 		req->metadata_sgl->nents = blk_rq_map_integrity_sg(rq,
 				req->metadata_sgl->sg_table.sgl);
-		*pi_count = ib_dma_map_sg(ibdev,
-					  req->metadata_sgl->sg_table.sgl,
-					  req->metadata_sgl->nents,
-					  rq_dma_dir(rq));
-		if (unlikely(*pi_count <= 0)) {
+		sgt = (struct sg_table) {
+			.sgl		= req->metadata_sgl->sg_table.sgl,
+			.orig_nents	= req->metadata_sgl->nents,
+		};
+		ret = ib_dma_map_sgtable_attrs(ibdev, &sgt, rq_dma_dir(rq), 0);
+		if (unlikely(ret)) {
 			ret = -EIO;
 			goto out_free_pi_table;
 		}
+		*pi_count = sgt.nents;
 	}
 
 	return 0;
-- 
2.52.0


^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH v5 10/10] nvme-rdma: return BLK_STS_P2PDMA for unsupported P2P transfers
  2026-07-23 20:41 [PATCH v5 00/10] block,md,nvme: correct handling of unsupported P2PDMA transfers Mykola Marzhan
                   ` (8 preceding siblings ...)
  2026-07-23 20:42 ` [PATCH v5 09/10] nvme-rdma: use ib_dma_map_sgtable_attrs() Mykola Marzhan
@ 2026-07-23 20:42 ` Mykola Marzhan
  2026-07-24 18:50   ` Logan Gunthorpe
  2026-07-24 10:21 ` [PATCH v5 00/10] block,md,nvme: correct handling of unsupported P2PDMA transfers Thorsten Leemhuis
  10 siblings, 1 reply; 15+ messages in thread
From: Mykola Marzhan @ 2026-07-23 20:42 UTC (permalink / raw)
  To: Jens Axboe, Song Liu, Yu Kuai, Keith Busch, Christoph Hellwig,
	Sagi Grimberg, linux-block, linux-raid, linux-nvme
  Cc: Li Nan, Xiao Ni, Guoqing Jiang, Leon Romanovsky, Jason Gunthorpe,
	Kiran Kumar Modukuri, Chaitanya Kulkarni, Logan Gunthorpe,
	Bjorn Helgaas, Shivaji Kant, Pranjal Shrivastava,
	Henrique Carvalho, stable, linux-kernel, linux-rdma, linux-pci

A P2P transfer the PCIe topology cannot route fails DMA mapping
with -EREMOTEIO.  nvme-rdma folds every mapping error into -EIO, a
retryable host-path error: multipath requeues the I/O forever, a
single path burns its whole retry budget.

Propagate the real error code and return the unroutable case as the
non-retryable BLK_STS_P2PDMA.  As in nvme-pci, -ENOMEM now requeues
(BLK_STS_RESOURCE) and -EINVAL fails (BLK_STS_IOERR); -EIO stays a
retryable host-path error.  While at it, start the request only
after mapping succeeds -- nvme-pci's order -- and ratelimit the
map-failure message.

Fixes: 23528aa3320a ("nvme: enable PCI P2PDMA support for RDMA transport")
Cc: stable@vger.kernel.org # v7.1: requires "nvme-rdma: use ib_dma_map_sgtable_attrs()"
Assisted-by: Claude:claude-fable-5
Signed-off-by: Mykola Marzhan <mykola@meshstor.io>
---
 drivers/nvme/host/rdma.c | 19 +++++++++----------
 1 file changed, 9 insertions(+), 10 deletions(-)

diff --git a/drivers/nvme/host/rdma.c b/drivers/nvme/host/rdma.c
index 63830334c73e..2f50509a7a61 100644
--- a/drivers/nvme/host/rdma.c
+++ b/drivers/nvme/host/rdma.c
@@ -1486,10 +1486,8 @@ static int nvme_rdma_dma_map_req(struct ib_device *ibdev, struct request *rq,
 		.orig_nents	= req->data_sgl.nents,
 	};
 	ret = ib_dma_map_sgtable_attrs(ibdev, &sgt, rq_dma_dir(rq), 0);
-	if (unlikely(ret)) {
-		ret = -EIO;
+	if (unlikely(ret))
 		goto out_free_table;
-	}
 	*count = sgt.nents;
 
 	if (blk_integrity_rq(rq)) {
@@ -1511,10 +1509,8 @@ static int nvme_rdma_dma_map_req(struct ib_device *ibdev, struct request *rq,
 			.orig_nents	= req->metadata_sgl->nents,
 		};
 		ret = ib_dma_map_sgtable_attrs(ibdev, &sgt, rq_dma_dir(rq), 0);
-		if (unlikely(ret)) {
-			ret = -EIO;
+		if (unlikely(ret))
 			goto out_free_pi_table;
-		}
 		*pi_count = sgt.nents;
 	}
 
@@ -2033,8 +2029,6 @@ static blk_status_t nvme_rdma_queue_rq(struct blk_mq_hw_ctx *hctx,
 	if (ret)
 		goto unmap_qe;
 
-	nvme_start_request(rq);
-
 	if (IS_ENABLED(CONFIG_BLK_DEV_INTEGRITY) &&
 	    queue->pi_support &&
 	    (c->common.opcode == nvme_cmd_write ||
@@ -2046,11 +2040,13 @@ static blk_status_t nvme_rdma_queue_rq(struct blk_mq_hw_ctx *hctx,
 
 	err = nvme_rdma_map_data(queue, rq, c);
 	if (unlikely(err < 0)) {
-		dev_err(queue->ctrl->ctrl.device,
-			     "Failed to map data (%d)\n", err);
+		dev_err_ratelimited(queue->ctrl->ctrl.device,
+				    "Failed to map data (%d)\n", err);
 		goto err;
 	}
 
+	nvme_start_request(rq);
+
 	sqe->cqe.done = nvme_rdma_send_done;
 
 	ib_dma_sync_single_for_device(dev, sqe->dma,
@@ -2070,6 +2066,9 @@ static blk_status_t nvme_rdma_queue_rq(struct blk_mq_hw_ctx *hctx,
 		ret = nvme_host_path_error(rq);
 	else if (err == -ENOMEM || err == -EAGAIN)
 		ret = BLK_STS_RESOURCE;
+	/* Peer memory unreachable from this device: don't retry. */
+	else if (err == -EREMOTEIO)
+		ret = BLK_STS_P2PDMA;
 	else
 		ret = BLK_STS_IOERR;
 	nvme_cleanup_cmd(rq);
-- 
2.52.0


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH v5 00/10] block,md,nvme: correct handling of unsupported P2PDMA transfers
  2026-07-23 20:41 [PATCH v5 00/10] block,md,nvme: correct handling of unsupported P2PDMA transfers Mykola Marzhan
                   ` (9 preceding siblings ...)
  2026-07-23 20:42 ` [PATCH v5 10/10] nvme-rdma: return BLK_STS_P2PDMA for unsupported P2P transfers Mykola Marzhan
@ 2026-07-24 10:21 ` Thorsten Leemhuis
  10 siblings, 0 replies; 15+ messages in thread
From: Thorsten Leemhuis @ 2026-07-24 10:21 UTC (permalink / raw)
  To: Mykola Marzhan, Kiran Kumar Modukuri, Chaitanya Kulkarni, Jens Axboe
  Cc: Li Nan, Xiao Ni, Song Liu, linux-block, Christoph Hellwig,
	linux-nvme, Guoqing Jiang, linux-raid, Leon Romanovsky,
	Jason Gunthorpe, Logan Gunthorpe, Bjorn Helgaas, Shivaji Kant,
	Pranjal Shrivastava, Henrique Carvalho, stable, linux-kernel,
	linux-rdma, linux-pci, Sagi Grimberg, Yu Kuai, Keith Busch,
	Linux kernel regressions list

On 7/23/26 22:41, Mykola Marzhan wrote:
> md treats an unsupported P2PDMA transfer to a member as success, and
> nvme-rdma retries one forever.  Whether peer memory can be DMA-mapped
> depends on the PCIe topology between the two devices, and since v6.17
> the failure completes as BLK_STS_INVAL: retryable for multipath and
> deliberately ignored by md for member failures, so mirrors silently
> diverge.
> [...]
> Routing: patch 1 block, 2-8 md, 9-10 nvme; 7, 8 and 10 use the new
> status.  Patch 1 alone stops the divergence and the dm-multipath
> requeue loop; the nvme-rdma loop also needs 9-10; everything else
> refines the fallout, so the series bisects safely.  The md patches
> fix a v7.2-rc1 regression (02666132403a), except 3 (older bug,
> stable) and 5 (refactor).
This landed on my radar due to the word "regression" here. Given the
complexity of this patch-set and that we are at v5 please allow me to ask:

Should 02666132403aec ("md: propagate BLK_FEAT_PCI_P2PDMA from member
devices to RAID device") [v7.2-rc1] maybe be removed for now and
reapplied later once this was sorted out? Or is that for some reason
unneeded? Note, no need for a long explanation needed in the latter
case, a brief statement from long-term developer will suffice.

Ciao, Thorsten

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH v5 07/10] md/raid1,raid10: skip futile retries on P2PDMA mapping failures
  2026-07-23 20:42 ` [PATCH v5 07/10] md/raid1,raid10: skip futile retries on P2PDMA mapping failures Mykola Marzhan
@ 2026-07-24 15:11   ` Logan Gunthorpe
  0 siblings, 0 replies; 15+ messages in thread
From: Logan Gunthorpe @ 2026-07-24 15:11 UTC (permalink / raw)
  To: Mykola Marzhan, Jens Axboe, Song Liu, Yu Kuai, Keith Busch,
	Christoph Hellwig, Sagi Grimberg, linux-block, linux-raid,
	linux-nvme
  Cc: Li Nan, Xiao Ni, Guoqing Jiang, Leon Romanovsky, Jason Gunthorpe,
	Kiran Kumar Modukuri, Chaitanya Kulkarni, Bjorn Helgaas,
	Shivaji Kant, Pranjal Shrivastava, Henrique Carvalho, stable,
	linux-kernel, linux-rdma, linux-pci



On 2026-07-23 2:42 p.m., Mykola Marzhan wrote:
> BLK_STS_P2PDMA reflects the peer/member pairing, not member health:
> retrying the same pages on the same member cannot succeed.  Keep
> WriteErrorSeen so the range stays fenced, but skip WantReplacement and
> FailFast eviction, as commit f7b24c7b41f2 ("md/raid1,raid10: don't fail
> devices for invalid IO errors") did for BLK_STS_INVAL.
> 
> The failure is whole-range and deterministic, so narrow_write_error()'s
> block-by-block submit_bio_wait() retries are pointless.  Record the
> whole range as a bad block in the completion handler instead.
> 
> Fixes: 02666132403a ("md: propagate BLK_FEAT_PCI_P2PDMA from member devices to RAID device")
> Assisted-by: Claude:claude-fable-5
> Signed-off-by: Logan Gunthorpe <logang@deltatee.com>
> Signed-off-by: Mykola Marzhan <mykola@meshstor.io>

Change my no longer correct first Signed-off-by to:

Reviewed-by: Logan Gunthorpe <logang@deltatee.com>

Logan

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH v5 09/10] nvme-rdma: use ib_dma_map_sgtable_attrs()
  2026-07-23 20:42 ` [PATCH v5 09/10] nvme-rdma: use ib_dma_map_sgtable_attrs() Mykola Marzhan
@ 2026-07-24 18:47   ` Logan Gunthorpe
  0 siblings, 0 replies; 15+ messages in thread
From: Logan Gunthorpe @ 2026-07-24 18:47 UTC (permalink / raw)
  To: Mykola Marzhan, Jens Axboe, Song Liu, Yu Kuai, Keith Busch,
	Christoph Hellwig, Sagi Grimberg, linux-block, linux-raid,
	linux-nvme
  Cc: Li Nan, Xiao Ni, Guoqing Jiang, Leon Romanovsky, Jason Gunthorpe,
	Kiran Kumar Modukuri, Chaitanya Kulkarni, Bjorn Helgaas,
	Shivaji Kant, Pranjal Shrivastava, Henrique Carvalho, stable,
	linux-kernel, linux-rdma, linux-pci



On 2026-07-23 2:42 p.m., Mykola Marzhan wrote:
> ib_dma_map_sg() folds every mapping error into a zero return, losing
> the DMA layer's error code.  Switch both scatterlist mappings to
> ib_dma_map_sgtable_attrs(), which preserves it for the next patch to
> act on.  No behavior change: failures are still reported as -EIO.
> 
> A local sg_table is needed: dma_map_sgtable() maps orig_nents
> entries, and the embedded table's orig_nents is the allocated count,
> not the count blk_rq_map_sg() produced.  rdma_rw_ctx_init() does the
> same.
> 
> Assisted-by: Claude:claude-fable-5
> Cc: stable@vger.kernel.org # v7.1
> Signed-off-by: Mykola Marzhan <mykola@meshstor.io>

I don't know. I think this could still use a bit more cleanup (see
thoughts below). But the cleanup is probably too much to ask for this
series. See my thoughts below.

Reviewd-by: Logan Gunthorpe <logang@deltatee.com>

> ---
>  drivers/nvme/host/rdma.c | 23 +++++++++++++++--------
>  1 file changed, 15 insertions(+), 8 deletions(-)
> 
> diff --git a/drivers/nvme/host/rdma.c b/drivers/nvme/host/rdma.c
> index 6909e3542794..63830334c73e 100644
> --- a/drivers/nvme/host/rdma.c
> +++ b/drivers/nvme/host/rdma.c
> @@ -1469,6 +1469,7 @@ static int nvme_rdma_dma_map_req(struct ib_device *ibdev, struct request *rq,
>  		int *count, int *pi_count)
>  {
>  	struct nvme_rdma_request *req = blk_mq_rq_to_pdu(rq);
> +	struct sg_table sgt;
>  	int ret;
>  
>  	req->data_sgl.sg_table.sgl = (struct scatterlist *)(req + 1);
> @@ -1480,12 +1481,16 @@ static int nvme_rdma_dma_map_req(struct ib_device *ibdev, struct request *rq,
>  
>  	req->data_sgl.nents = blk_rq_map_sg(rq, req->data_sgl.sg_table.sgl);
>  
> -	*count = ib_dma_map_sg(ibdev, req->data_sgl.sg_table.sgl,
> -			       req->data_sgl.nents, rq_dma_dir(rq));
> -	if (unlikely(*count <= 0)) {
> +	sgt = (struct sg_table) {
> +		.sgl		= req->data_sgl.sg_table.sgl,
> +		.orig_nents	= req->data_sgl.nents,
> +	};
> +	ret = ib_dma_map_sgtable_attrs(ibdev, &sgt, rq_dma_dir(rq), 0);
> +	if (unlikely(ret)) {
>  		ret = -EIO;
>  		goto out_free_table;
>  	}
> +	*count = sgt.nents;

This really makes these calls really complicated and harder to reason
about just to get an appropriate return code in the next patch. Though I
see the complexity here and I feel like I'm confused by the semantics of
nents and orig_nents all the time. It seems like some cases really need
to track three counts: the number of valid DMA addresses (nents), the
number of valid segments and the number actually allocated. sg_table
only has two fields, and orig_nents ends up doing double duty — the DMA
API reads it as the valid-segment count, while
sg_alloc/free_table_chained() treat it as the allocation size. When
those two differ, as they do here, it creates this complexity.

One cheap thought that might clean up this patch series is to create a
helper that can be used for both the data and the metadata, but that's
only slightly better and I don't know if it is worth the effort.

A better long term option might be to introduce a dma_map_sgtable like
helper that also takes the number of valid segments which would clean
this up pretty nicley. But that would be much more work.

Thanks,

Logan


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH v5 10/10] nvme-rdma: return BLK_STS_P2PDMA for unsupported P2P transfers
  2026-07-23 20:42 ` [PATCH v5 10/10] nvme-rdma: return BLK_STS_P2PDMA for unsupported P2P transfers Mykola Marzhan
@ 2026-07-24 18:50   ` Logan Gunthorpe
  0 siblings, 0 replies; 15+ messages in thread
From: Logan Gunthorpe @ 2026-07-24 18:50 UTC (permalink / raw)
  To: Mykola Marzhan, Jens Axboe, Song Liu, Yu Kuai, Keith Busch,
	Christoph Hellwig, Sagi Grimberg, linux-block, linux-raid,
	linux-nvme
  Cc: Li Nan, Xiao Ni, Guoqing Jiang, Leon Romanovsky, Jason Gunthorpe,
	Kiran Kumar Modukuri, Chaitanya Kulkarni, Bjorn Helgaas,
	Shivaji Kant, Pranjal Shrivastava, Henrique Carvalho, stable,
	linux-kernel, linux-rdma, linux-pci



On 2026-07-23 2:42 p.m., Mykola Marzhan wrote:
> A P2P transfer the PCIe topology cannot route fails DMA mapping
> with -EREMOTEIO.  nvme-rdma folds every mapping error into -EIO, a
> retryable host-path error: multipath requeues the I/O forever, a
> single path burns its whole retry budget.
> 
> Propagate the real error code and return the unroutable case as the
> non-retryable BLK_STS_P2PDMA.  As in nvme-pci, -ENOMEM now requeues
> (BLK_STS_RESOURCE) and -EINVAL fails (BLK_STS_IOERR); -EIO stays a
> retryable host-path error.  While at it, start the request only
> after mapping succeeds -- nvme-pci's order -- and ratelimit the
> map-failure message.
> 
> Fixes: 23528aa3320a ("nvme: enable PCI P2PDMA support for RDMA transport")
> Cc: stable@vger.kernel.org # v7.1: requires "nvme-rdma: use ib_dma_map_sgtable_attrs()"
> Assisted-by: Claude:claude-fable-5
> Signed-off-by: Mykola Marzhan <mykola@meshstor.io>

This is much more understandable now. Thanks. I have one nit below,
other than that:

Reviewed-by: Logan Gunthorpe <logang@deltatee.com>

> ---
>  drivers/nvme/host/rdma.c | 19 +++++++++----------
>  1 file changed, 9 insertions(+), 10 deletions(-)
> 
> diff --git a/drivers/nvme/host/rdma.c b/drivers/nvme/host/rdma.c
> index 63830334c73e..2f50509a7a61 100644
> --- a/drivers/nvme/host/rdma.c
> +++ b/drivers/nvme/host/rdma.c
> @@ -1486,10 +1486,8 @@ static int nvme_rdma_dma_map_req(struct ib_device *ibdev, struct request *rq,
>  		.orig_nents	= req->data_sgl.nents,
>  	};
>  	ret = ib_dma_map_sgtable_attrs(ibdev, &sgt, rq_dma_dir(rq), 0);
> -	if (unlikely(ret)) {
> -		ret = -EIO;
> +	if (unlikely(ret))
>  		goto out_free_table;
> -	}
>  	*count = sgt.nents;
>  
>  	if (blk_integrity_rq(rq)) {
> @@ -1511,10 +1509,8 @@ static int nvme_rdma_dma_map_req(struct ib_device *ibdev, struct request *rq,
>  			.orig_nents	= req->metadata_sgl->nents,
>  		};
>  		ret = ib_dma_map_sgtable_attrs(ibdev, &sgt, rq_dma_dir(rq), 0);
> -		if (unlikely(ret)) {
> -			ret = -EIO;
> +		if (unlikely(ret))
>  			goto out_free_pi_table;
> -		}
>  		*pi_count = sgt.nents;
>  	}
>  
> @@ -2033,8 +2029,6 @@ static blk_status_t nvme_rdma_queue_rq(struct blk_mq_hw_ctx *hctx,
>  	if (ret)
>  		goto unmap_qe;
>  
> -	nvme_start_request(rq);
> -
>  	if (IS_ENABLED(CONFIG_BLK_DEV_INTEGRITY) &&
>  	    queue->pi_support &&
>  	    (c->common.opcode == nvme_cmd_write ||
> @@ -2046,11 +2040,13 @@ static blk_status_t nvme_rdma_queue_rq(struct blk_mq_hw_ctx *hctx,
>  
>  	err = nvme_rdma_map_data(queue, rq, c);
>  	if (unlikely(err < 0)) {
> -		dev_err(queue->ctrl->ctrl.device,
> -			     "Failed to map data (%d)\n", err);
> +		dev_err_ratelimited(queue->ctrl->ctrl.device,
> +				    "Failed to map data (%d)\n", err);

This rate limit change probably doesn't belong in this patch. It's
pretty clear in the commit message with the "while at it" message. Worth
moving to another patch.

Logan

^ permalink raw reply	[flat|nested] 15+ messages in thread

end of thread, other threads:[~2026-07-24 18:51 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-07-23 20:41 [PATCH v5 00/10] block,md,nvme: correct handling of unsupported P2PDMA transfers Mykola Marzhan
2026-07-23 20:41 ` [PATCH v5 01/10] block: add BLK_STS_P2PDMA for unsupported peer-to-peer transfers Mykola Marzhan
2026-07-23 20:41 ` [PATCH v5 02/10] md: ensure REQ_NOMERGE is set on P2PDMA bios Mykola Marzhan
2026-07-23 20:41 ` [PATCH v5 03/10] md/raid1: serialize non-write-behind writes on CollisionCheck rdevs Mykola Marzhan
2026-07-23 20:42 ` [PATCH v5 04/10] md/raid1: don't use write-behind for P2PDMA bios Mykola Marzhan
2026-07-23 20:42 ` [PATCH v5 05/10] md/raid1,raid10: factor out raid1_write_error() helper Mykola Marzhan
2026-07-23 20:42 ` [PATCH v5 06/10] md/raid1,raid10: keep REQ_NOMERGE on narrow_write_error() retry clones Mykola Marzhan
2026-07-23 20:42 ` [PATCH v5 07/10] md/raid1,raid10: skip futile retries on P2PDMA mapping failures Mykola Marzhan
2026-07-24 15:11   ` Logan Gunthorpe
2026-07-23 20:42 ` [PATCH v5 08/10] md/raid1,raid10: set IO_BLOCKED in case of BLK_STS_P2PDMA Mykola Marzhan
2026-07-23 20:42 ` [PATCH v5 09/10] nvme-rdma: use ib_dma_map_sgtable_attrs() Mykola Marzhan
2026-07-24 18:47   ` Logan Gunthorpe
2026-07-23 20:42 ` [PATCH v5 10/10] nvme-rdma: return BLK_STS_P2PDMA for unsupported P2P transfers Mykola Marzhan
2026-07-24 18:50   ` Logan Gunthorpe
2026-07-24 10:21 ` [PATCH v5 00/10] block,md,nvme: correct handling of unsupported P2PDMA transfers Thorsten Leemhuis

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®