* [PATCH v6 00/12] block,md,nvme: correct handling of unsupported P2PDMA transfers
@ 2026-07-26 11:32 Mykola Marzhan
2026-07-26 11:32 ` [PATCH v6 01/12] block: add BLK_STS_P2PDMA for unsupported peer-to-peer transfers Mykola Marzhan
` (11 more replies)
0 siblings, 12 replies; 25+ messages in thread
From: Mykola Marzhan @ 2026-07-26 11:32 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,
Thorsten Leemhuis, Martin Wilck
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; v4 onward 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)
11 nvme-rdma: ratelimit the map-failure error message (cleanup)
12 nvme-rdma: factor out the scatterlist DMA mapping helper
(cleanup)
Routing: patch 1 block, 2-8 md, 9-12 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). 11 and 12 are cleanup only and can be
deferred if you would rather not carry them at -rc.
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 v6:
- patches 7, 9, 10: picked up Logan's Reviewed-by; on 7 it replaces
his now-stale Signed-off-by, as he asked
- patch 10: the map-failure ratelimit conversion moves out to its
own patch 11 (Logan); the stable note now names both prerequisites
- new patch 12: the data and the metadata mapping share a helper
(Logan's suggestion on patch 9). Kept out of 9 so the
stable-tagged fix stays minimal
Changes in v5:
- patch 7: From: is now Mykola, at Logan's request; patch 8 follows
for consistency. 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
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/20260723204206.76930-1-mykola@meshstor.io/ [v5]
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 (10):
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
nvme-rdma: ratelimit the map-failure error message
nvme-rdma: factor out the scatterlist DMA mapping helper
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 | 54 +++++++++++++++++++++++++++------------
include/linux/blk_types.h | 10 ++++++++
9 files changed, 134 insertions(+), 51 deletions(-)
base-commit: 1590cf0329716306e948a8fc29f1d3ee87d3989f
--
2.52.0
^ permalink raw reply [flat|nested] 25+ messages in thread
* [PATCH v6 01/12] block: add BLK_STS_P2PDMA for unsupported peer-to-peer transfers
2026-07-26 11:32 [PATCH v6 00/12] block,md,nvme: correct handling of unsupported P2PDMA transfers Mykola Marzhan
@ 2026-07-26 11:32 ` Mykola Marzhan
2026-07-26 12:06 ` sashiko-bot
2026-07-26 11:32 ` [PATCH v6 02/12] md: ensure REQ_NOMERGE is set on P2PDMA bios Mykola Marzhan
` (10 subsequent siblings)
11 siblings, 1 reply; 25+ messages in thread
From: Mykola Marzhan @ 2026-07-26 11:32 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,
Thorsten Leemhuis, Martin Wilck
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 related [flat|nested] 25+ messages in thread
* [PATCH v6 02/12] md: ensure REQ_NOMERGE is set on P2PDMA bios
2026-07-26 11:32 [PATCH v6 00/12] block,md,nvme: correct handling of unsupported P2PDMA transfers Mykola Marzhan
2026-07-26 11:32 ` [PATCH v6 01/12] block: add BLK_STS_P2PDMA for unsupported peer-to-peer transfers Mykola Marzhan
@ 2026-07-26 11:32 ` Mykola Marzhan
2026-07-26 11:59 ` sashiko-bot
2026-07-26 11:32 ` [PATCH v6 03/12] md/raid1: serialize non-write-behind writes on CollisionCheck rdevs Mykola Marzhan
` (9 subsequent siblings)
11 siblings, 1 reply; 25+ messages in thread
From: Mykola Marzhan @ 2026-07-26 11:32 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,
Thorsten Leemhuis, Martin Wilck
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 related [flat|nested] 25+ messages in thread
* [PATCH v6 03/12] md/raid1: serialize non-write-behind writes on CollisionCheck rdevs
2026-07-26 11:32 [PATCH v6 00/12] block,md,nvme: correct handling of unsupported P2PDMA transfers Mykola Marzhan
2026-07-26 11:32 ` [PATCH v6 01/12] block: add BLK_STS_P2PDMA for unsupported peer-to-peer transfers Mykola Marzhan
2026-07-26 11:32 ` [PATCH v6 02/12] md: ensure REQ_NOMERGE is set on P2PDMA bios Mykola Marzhan
@ 2026-07-26 11:32 ` Mykola Marzhan
2026-07-26 12:10 ` sashiko-bot
2026-07-26 11:32 ` [PATCH v6 04/12] md/raid1: don't use write-behind for P2PDMA bios Mykola Marzhan
` (8 subsequent siblings)
11 siblings, 1 reply; 25+ messages in thread
From: Mykola Marzhan @ 2026-07-26 11:32 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,
Thorsten Leemhuis, Martin Wilck
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.
An rdev hot-added under serialize_policy gets no serial tree at all,
because mddev_create_serial_pool() skips one that is not write-behind
eligible: the old gate dereferences NULL there, this one skips
serialization instead. Martin Wilck's fix repairs that case at the
source, after which CollisionCheck is a strict superset of
MD_SERIALIZE_POLICY.
Link: https://lore.kernel.org/linux-raid/20260723112741.1206836-1-mwilck@suse.com/
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 related [flat|nested] 25+ messages in thread
* [PATCH v6 04/12] md/raid1: don't use write-behind for P2PDMA bios
2026-07-26 11:32 [PATCH v6 00/12] block,md,nvme: correct handling of unsupported P2PDMA transfers Mykola Marzhan
` (2 preceding siblings ...)
2026-07-26 11:32 ` [PATCH v6 03/12] md/raid1: serialize non-write-behind writes on CollisionCheck rdevs Mykola Marzhan
@ 2026-07-26 11:32 ` Mykola Marzhan
2026-07-26 12:01 ` sashiko-bot
2026-07-26 11:32 ` [PATCH v6 05/12] md/raid1,raid10: factor out raid1_write_error() helper Mykola Marzhan
` (7 subsequent siblings)
11 siblings, 1 reply; 25+ messages in thread
From: Mykola Marzhan @ 2026-07-26 11:32 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,
Thorsten Leemhuis, Martin Wilck
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 related [flat|nested] 25+ messages in thread
* [PATCH v6 05/12] md/raid1,raid10: factor out raid1_write_error() helper
2026-07-26 11:32 [PATCH v6 00/12] block,md,nvme: correct handling of unsupported P2PDMA transfers Mykola Marzhan
` (3 preceding siblings ...)
2026-07-26 11:32 ` [PATCH v6 04/12] md/raid1: don't use write-behind for P2PDMA bios Mykola Marzhan
@ 2026-07-26 11:32 ` Mykola Marzhan
2026-07-26 11:57 ` sashiko-bot
2026-07-26 11:32 ` [PATCH v6 06/12] md/raid1,raid10: keep REQ_NOMERGE on narrow_write_error() retry clones Mykola Marzhan
` (6 subsequent siblings)
11 siblings, 1 reply; 25+ messages in thread
From: Mykola Marzhan @ 2026-07-26 11:32 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,
Thorsten Leemhuis, Martin Wilck
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 related [flat|nested] 25+ messages in thread
* [PATCH v6 06/12] md/raid1,raid10: keep REQ_NOMERGE on narrow_write_error() retry clones
2026-07-26 11:32 [PATCH v6 00/12] block,md,nvme: correct handling of unsupported P2PDMA transfers Mykola Marzhan
` (4 preceding siblings ...)
2026-07-26 11:32 ` [PATCH v6 05/12] md/raid1,raid10: factor out raid1_write_error() helper Mykola Marzhan
@ 2026-07-26 11:32 ` Mykola Marzhan
2026-07-26 12:09 ` sashiko-bot
2026-07-26 11:32 ` [PATCH v6 07/12] md/raid1,raid10: skip futile retries on P2PDMA mapping failures Mykola Marzhan
` (5 subsequent siblings)
11 siblings, 1 reply; 25+ messages in thread
From: Mykola Marzhan @ 2026-07-26 11:32 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,
Thorsten Leemhuis, Martin Wilck
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 related [flat|nested] 25+ messages in thread
* [PATCH v6 07/12] md/raid1,raid10: skip futile retries on P2PDMA mapping failures
2026-07-26 11:32 [PATCH v6 00/12] block,md,nvme: correct handling of unsupported P2PDMA transfers Mykola Marzhan
` (5 preceding siblings ...)
2026-07-26 11:32 ` [PATCH v6 06/12] md/raid1,raid10: keep REQ_NOMERGE on narrow_write_error() retry clones Mykola Marzhan
@ 2026-07-26 11:32 ` Mykola Marzhan
2026-07-26 12:03 ` sashiko-bot
2026-07-26 11:32 ` [PATCH v6 08/12] md/raid1,raid10: set IO_BLOCKED in case of BLK_STS_P2PDMA Mykola Marzhan
` (4 subsequent siblings)
11 siblings, 1 reply; 25+ messages in thread
From: Mykola Marzhan @ 2026-07-26 11:32 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,
Thorsten Leemhuis, Martin Wilck
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. raid10
replacement legs are unchanged: a write error there fails the
replacement, whatever the status.
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: Mykola Marzhan <mykola@meshstor.io>
Reviewed-by: Logan Gunthorpe <logang@deltatee.com>
---
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 related [flat|nested] 25+ messages in thread
* [PATCH v6 08/12] md/raid1,raid10: set IO_BLOCKED in case of BLK_STS_P2PDMA
2026-07-26 11:32 [PATCH v6 00/12] block,md,nvme: correct handling of unsupported P2PDMA transfers Mykola Marzhan
` (6 preceding siblings ...)
2026-07-26 11:32 ` [PATCH v6 07/12] md/raid1,raid10: skip futile retries on P2PDMA mapping failures Mykola Marzhan
@ 2026-07-26 11:32 ` Mykola Marzhan
2026-07-26 12:06 ` sashiko-bot
2026-07-26 11:32 ` [PATCH v6 09/12] nvme-rdma: use ib_dma_map_sgtable_attrs() Mykola Marzhan
` (3 subsequent siblings)
11 siblings, 1 reply; 25+ messages in thread
From: Mykola Marzhan @ 2026-07-26 11:32 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,
Thorsten Leemhuis, Martin Wilck
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 related [flat|nested] 25+ messages in thread
* [PATCH v6 09/12] nvme-rdma: use ib_dma_map_sgtable_attrs()
2026-07-26 11:32 [PATCH v6 00/12] block,md,nvme: correct handling of unsupported P2PDMA transfers Mykola Marzhan
` (7 preceding siblings ...)
2026-07-26 11:32 ` [PATCH v6 08/12] md/raid1,raid10: set IO_BLOCKED in case of BLK_STS_P2PDMA Mykola Marzhan
@ 2026-07-26 11:32 ` Mykola Marzhan
2026-07-26 12:01 ` sashiko-bot
2026-07-26 11:32 ` [PATCH v6 10/12] nvme-rdma: return BLK_STS_P2PDMA for unsupported P2P transfers Mykola Marzhan
` (2 subsequent siblings)
11 siblings, 1 reply; 25+ messages in thread
From: Mykola Marzhan @ 2026-07-26 11:32 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,
Thorsten Leemhuis, Martin Wilck
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>
Reviewed-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;
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 related [flat|nested] 25+ messages in thread
* [PATCH v6 10/12] nvme-rdma: return BLK_STS_P2PDMA for unsupported P2P transfers
2026-07-26 11:32 [PATCH v6 00/12] block,md,nvme: correct handling of unsupported P2PDMA transfers Mykola Marzhan
` (8 preceding siblings ...)
2026-07-26 11:32 ` [PATCH v6 09/12] nvme-rdma: use ib_dma_map_sgtable_attrs() Mykola Marzhan
@ 2026-07-26 11:32 ` Mykola Marzhan
2026-07-26 12:10 ` sashiko-bot
2026-07-26 11:32 ` [PATCH v6 11/12] nvme-rdma: ratelimit the map-failure error message Mykola Marzhan
2026-07-26 11:32 ` [PATCH v6 12/12] nvme-rdma: factor out the scatterlist DMA mapping helper Mykola Marzhan
11 siblings, 1 reply; 25+ messages in thread
From: Mykola Marzhan @ 2026-07-26 11:32 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,
Thorsten Leemhuis, Martin Wilck
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.
Start the request only after the mapping succeeds, as nvme-pci and
nvme-tcp do. A hard status from ->queue_rq is completed by blk-mq
itself, skipping nvme_mpath_end_request(), so the multipath I/O
accounting leaks -- today for -EINVAL, and now for BLK_STS_P2PDMA.
Fixes: 23528aa3320a ("nvme: enable PCI P2PDMA support for RDMA transport")
Cc: stable@vger.kernel.org # v7.1: requires BLK_STS_P2PDMA and the ib_dma_map_sgtable_attrs() conversion
Assisted-by: Claude:claude-fable-5
Signed-off-by: Mykola Marzhan <mykola@meshstor.io>
Reviewed-by: Logan Gunthorpe <logang@deltatee.com>
---
drivers/nvme/host/rdma.c | 15 +++++++--------
1 file changed, 7 insertions(+), 8 deletions(-)
diff --git a/drivers/nvme/host/rdma.c b/drivers/nvme/host/rdma.c
index 63830334c73e..c38d949502b7 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 ||
@@ -2051,6 +2045,8 @@ static blk_status_t nvme_rdma_queue_rq(struct blk_mq_hw_ctx *hctx,
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 related [flat|nested] 25+ messages in thread
* [PATCH v6 11/12] nvme-rdma: ratelimit the map-failure error message
2026-07-26 11:32 [PATCH v6 00/12] block,md,nvme: correct handling of unsupported P2PDMA transfers Mykola Marzhan
` (9 preceding siblings ...)
2026-07-26 11:32 ` [PATCH v6 10/12] nvme-rdma: return BLK_STS_P2PDMA for unsupported P2P transfers Mykola Marzhan
@ 2026-07-26 11:32 ` Mykola Marzhan
2026-07-26 11:53 ` sashiko-bot
2026-07-26 11:32 ` [PATCH v6 12/12] nvme-rdma: factor out the scatterlist DMA mapping helper Mykola Marzhan
11 siblings, 1 reply; 25+ messages in thread
From: Mykola Marzhan @ 2026-07-26 11:32 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,
Thorsten Leemhuis, Martin Wilck
A mapping failure is per-request and, for an unroutable P2P transfer,
deterministic: a workload that keeps issuing one turns this into a
log line per I/O. Ratelimit it, as nvme's per-I/O error logging
(nvme_log_error()) already is.
Assisted-by: Claude:claude-fable-5
Signed-off-by: Mykola Marzhan <mykola@meshstor.io>
---
drivers/nvme/host/rdma.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/nvme/host/rdma.c b/drivers/nvme/host/rdma.c
index c38d949502b7..2f50509a7a61 100644
--- a/drivers/nvme/host/rdma.c
+++ b/drivers/nvme/host/rdma.c
@@ -2040,8 +2040,8 @@ 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;
}
--
2.52.0
^ permalink raw reply related [flat|nested] 25+ messages in thread
* [PATCH v6 12/12] nvme-rdma: factor out the scatterlist DMA mapping helper
2026-07-26 11:32 [PATCH v6 00/12] block,md,nvme: correct handling of unsupported P2PDMA transfers Mykola Marzhan
` (10 preceding siblings ...)
2026-07-26 11:32 ` [PATCH v6 11/12] nvme-rdma: ratelimit the map-failure error message Mykola Marzhan
@ 2026-07-26 11:32 ` Mykola Marzhan
2026-07-26 12:02 ` sashiko-bot
11 siblings, 1 reply; 25+ messages in thread
From: Mykola Marzhan @ 2026-07-26 11:32 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,
Thorsten Leemhuis, Martin Wilck
The data and the metadata mapping do the same thing: describe the
segments blk_rq_map_sg() produced in a local sg_table -- the embedded
one's orig_nents is the allocated size, not the valid-segment count --
map that, and hand back the DMA-mapped count. Fold both into a
helper.
No functional change.
Suggested-by: Logan Gunthorpe <logang@deltatee.com>
Assisted-by: Claude:claude-fable-5
Signed-off-by: Mykola Marzhan <mykola@meshstor.io>
---
drivers/nvme/host/rdma.c | 42 +++++++++++++++++++++++++++-------------
1 file changed, 29 insertions(+), 13 deletions(-)
diff --git a/drivers/nvme/host/rdma.c b/drivers/nvme/host/rdma.c
index 2f50509a7a61..525e5aea65a1 100644
--- a/drivers/nvme/host/rdma.c
+++ b/drivers/nvme/host/rdma.c
@@ -1465,11 +1465,33 @@ static int nvme_rdma_map_sg_pi(struct nvme_rdma_queue *queue,
return -EINVAL;
}
+/*
+ * Map the segments blk_rq_map_sg() produced. They are described by a local
+ * sg_table because the embedded one's orig_nents is the allocated size, not
+ * the number of valid segments; rdma_rw_ctx_init() does the same.
+ */
+static int nvme_rdma_dma_map_sgl(struct ib_device *ibdev,
+ struct scatterlist *sgl, int nents,
+ enum dma_data_direction dir, int *count)
+{
+ struct sg_table sgt = {
+ .sgl = sgl,
+ .orig_nents = nents,
+ };
+ int ret;
+
+ ret = ib_dma_map_sgtable_attrs(ibdev, &sgt, dir, 0);
+ if (unlikely(ret))
+ return ret;
+
+ *count = sgt.nents;
+ return 0;
+}
+
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);
@@ -1481,14 +1503,10 @@ 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);
- 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);
+ ret = nvme_rdma_dma_map_sgl(ibdev, req->data_sgl.sg_table.sgl,
+ req->data_sgl.nents, rq_dma_dir(rq), count);
if (unlikely(ret))
goto out_free_table;
- *count = sgt.nents;
if (blk_integrity_rq(rq)) {
req->metadata_sgl->sg_table.sgl =
@@ -1504,14 +1522,12 @@ 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);
- 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);
+ ret = nvme_rdma_dma_map_sgl(ibdev,
+ req->metadata_sgl->sg_table.sgl,
+ req->metadata_sgl->nents,
+ rq_dma_dir(rq), pi_count);
if (unlikely(ret))
goto out_free_pi_table;
- *pi_count = sgt.nents;
}
return 0;
--
2.52.0
^ permalink raw reply related [flat|nested] 25+ messages in thread
* Re: [PATCH v6 11/12] nvme-rdma: ratelimit the map-failure error message
2026-07-26 11:32 ` [PATCH v6 11/12] nvme-rdma: ratelimit the map-failure error message Mykola Marzhan
@ 2026-07-26 11:53 ` sashiko-bot
0 siblings, 0 replies; 25+ messages in thread
From: sashiko-bot @ 2026-07-26 11:53 UTC (permalink / raw)
To: Mykola Marzhan; +Cc: yukuai, linux-pci, linux-raid
> A mapping failure is per-request and, for an unroutable P2P transfer,
> deterministic: a workload that keeps issuing one turns this into a
> log line per I/O. Ratelimit it, as nvme's per-I/O error logging
> (nvme_log_error()) already is.
>
> Assisted-by: Claude:claude-fable-5
> Signed-off-by: Mykola Marzhan <mykola@meshstor.io>
Sashiko has reviewed this patch and found no issues. It looks great!
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260726113229.2154269-1-mykola@meshstor.io?part=11
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH v6 05/12] md/raid1,raid10: factor out raid1_write_error() helper
2026-07-26 11:32 ` [PATCH v6 05/12] md/raid1,raid10: factor out raid1_write_error() helper Mykola Marzhan
@ 2026-07-26 11:57 ` sashiko-bot
0 siblings, 0 replies; 25+ messages in thread
From: sashiko-bot @ 2026-07-26 11:57 UTC (permalink / raw)
To: Mykola Marzhan; +Cc: linux-pci, linux-raid, yukuai
> 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>
Sashiko has reviewed this patch and found no issues. It looks great!
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260726113229.2154269-1-mykola@meshstor.io?part=5
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH v6 02/12] md: ensure REQ_NOMERGE is set on P2PDMA bios
2026-07-26 11:32 ` [PATCH v6 02/12] md: ensure REQ_NOMERGE is set on P2PDMA bios Mykola Marzhan
@ 2026-07-26 11:59 ` sashiko-bot
0 siblings, 0 replies; 25+ messages in thread
From: sashiko-bot @ 2026-07-26 11:59 UTC (permalink / raw)
To: Mykola Marzhan; +Cc: linux-raid, linux-pci, yukuai
> 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>
Sashiko has reviewed this patch and found no issues. It looks great!
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260726113229.2154269-1-mykola@meshstor.io?part=2
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH v6 04/12] md/raid1: don't use write-behind for P2PDMA bios
2026-07-26 11:32 ` [PATCH v6 04/12] md/raid1: don't use write-behind for P2PDMA bios Mykola Marzhan
@ 2026-07-26 12:01 ` sashiko-bot
0 siblings, 0 replies; 25+ messages in thread
From: sashiko-bot @ 2026-07-26 12:01 UTC (permalink / raw)
To: Mykola Marzhan; +Cc: linux-raid, yukuai, 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>
Sashiko has reviewed this patch and found no issues. It looks great!
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260726113229.2154269-1-mykola@meshstor.io?part=4
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH v6 09/12] nvme-rdma: use ib_dma_map_sgtable_attrs()
2026-07-26 11:32 ` [PATCH v6 09/12] nvme-rdma: use ib_dma_map_sgtable_attrs() Mykola Marzhan
@ 2026-07-26 12:01 ` sashiko-bot
0 siblings, 0 replies; 25+ messages in thread
From: sashiko-bot @ 2026-07-26 12:01 UTC (permalink / raw)
To: Mykola Marzhan; +Cc: linux-pci, linux-raid, yukuai
> 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>
Sashiko has reviewed this patch and found no issues. It looks great!
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260726113229.2154269-1-mykola@meshstor.io?part=9
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH v6 12/12] nvme-rdma: factor out the scatterlist DMA mapping helper
2026-07-26 11:32 ` [PATCH v6 12/12] nvme-rdma: factor out the scatterlist DMA mapping helper Mykola Marzhan
@ 2026-07-26 12:02 ` sashiko-bot
0 siblings, 0 replies; 25+ messages in thread
From: sashiko-bot @ 2026-07-26 12:02 UTC (permalink / raw)
To: Mykola Marzhan; +Cc: linux-raid, yukuai, linux-pci
> The data and the metadata mapping do the same thing: describe the
> segments blk_rq_map_sg() produced in a local sg_table -- the embedded
> one's orig_nents is the allocated size, not the valid-segment count --
> map that, and hand back the DMA-mapped count. Fold both into a
> helper.
>
> No functional change.
>
> Suggested-by: Logan Gunthorpe <logang@deltatee.com>
> Assisted-by: Claude:claude-fable-5
> Signed-off-by: Mykola Marzhan <mykola@meshstor.io>
Sashiko has reviewed this patch and found no issues. It looks great!
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260726113229.2154269-1-mykola@meshstor.io?part=12
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH v6 07/12] md/raid1,raid10: skip futile retries on P2PDMA mapping failures
2026-07-26 11:32 ` [PATCH v6 07/12] md/raid1,raid10: skip futile retries on P2PDMA mapping failures Mykola Marzhan
@ 2026-07-26 12:03 ` sashiko-bot
0 siblings, 0 replies; 25+ messages in thread
From: sashiko-bot @ 2026-07-26 12:03 UTC (permalink / raw)
To: Mykola Marzhan; +Cc: yukuai, linux-pci, linux-raid
> 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. raid10
> replacement legs are unchanged: a write error there fails the
> replacement, whatever the status.
>
> 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: Mykola Marzhan <mykola@meshstor.io>
Sashiko has reviewed this patch and found no issues. It looks great!
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260726113229.2154269-1-mykola@meshstor.io?part=7
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH v6 01/12] block: add BLK_STS_P2PDMA for unsupported peer-to-peer transfers
2026-07-26 11:32 ` [PATCH v6 01/12] block: add BLK_STS_P2PDMA for unsupported peer-to-peer transfers Mykola Marzhan
@ 2026-07-26 12:06 ` sashiko-bot
0 siblings, 0 replies; 25+ messages in thread
From: sashiko-bot @ 2026-07-26 12:06 UTC (permalink / raw)
To: Mykola Marzhan; +Cc: linux-pci, yukuai, linux-raid
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
Pre-existing issues:
- [High] BLK_STS_INVAL is omitted from the non-retryable list in blk_path_error(), causing genuine invalid requests to trigger infinite path-flapping loops in dm-mpath.
--
--- Patch [1]: [PATCH v6 01/12] block: add BLK_STS_P2PDMA for unsupported peer-to-peer transfers ---
commit d0a7b922115b23f3d33b00adcd1560732559cd9f
Author: Logan Gunthorpe <logang@deltatee.com>
block: add BLK_STS_P2PDMA for unsupported peer-to-peer transfers
This commit introduces BLK_STS_P2PDMA to handle unsupported peer-to-peer DMA
transfers that cannot be routed by the PCIe topology. It returns this new
status from blk_dma_map_iter_start() instead of BLK_STS_INVAL to distinguish
it from standard invalid requests. It also adds BLK_STS_P2PDMA to
blk_path_error() so multipath does not infinitely retry these failures.
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
> diff --git a/include/linux/blk_types.h b/include/linux/blk_types.h
> index 8808ee76e73c0..c8de7809320ad 100644
> --- a/include/linux/blk_types.h
> +++ b/include/linux/blk_types.h
[ ... ]
> @@ -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:
[Severity: High]
This is a pre-existing issue, but should BLK_STS_INVAL also be included in
this non-retryable list?
Currently, because BLK_STS_INVAL is omitted from blk_path_error(), it falls
through to the default case and returns true (treating it as a retryable
path failure).
If a user submits an inherently invalid I/O request (such as an atomic write
exceeding hardware limits via RWF_ATOMIC), the block layer correctly rejects
it and returns BLK_STS_INVAL.
However, dm-mpath will incorrectly treat this user error as a path failure,
fail the active path, and requeue the I/O. Since the request is genuinely
invalid, it fails on all paths, causing an infinite path-flapping loop as
the path checker periodically reinstates them.
Could this lead to a Denial of Service for all legitimate I/O on the
affected multipath device?
> return false;
> }
>
> /* Anything else could be a path failure, so should be retried */
> return true;
> }
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260726113229.2154269-1-mykola@meshstor.io?part=1
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH v6 08/12] md/raid1,raid10: set IO_BLOCKED in case of BLK_STS_P2PDMA
2026-07-26 11:32 ` [PATCH v6 08/12] md/raid1,raid10: set IO_BLOCKED in case of BLK_STS_P2PDMA Mykola Marzhan
@ 2026-07-26 12:06 ` sashiko-bot
0 siblings, 0 replies; 25+ messages in thread
From: sashiko-bot @ 2026-07-26 12:06 UTC (permalink / raw)
To: Mykola Marzhan; +Cc: linux-raid, linux-pci, yukuai
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
Pre-existing issues:
- [High] A pre-existing ABBA deadlock can occur if a read error is processed by `raid1d` or `raid10d` concurrently with a management thread calling `freeze_array(conf, 0)`.
--
--- Patch [8]: [PATCH v6 08/12] md/raid1,raid10: set IO_BLOCKED in case of BLK_STS_P2PDMA ---
commit f4692375c384d52b343af556c8a63ea0e3e48c0f
Author: Mykola Marzhan <mykola@meshstor.io>
md/raid1,raid10: set IO_BLOCKED in case of BLK_STS_P2PDMA
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.
This skips the read-error machinery to avoid evicting a healthy member
under a P2P workload.
> diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
> index 83ebf40237d57..16a47568679f0 100644
> --- a/drivers/md/raid1.c
> +++ b/drivers/md/raid1.c
[ ... ]
> @@ -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) {
[Severity: High]
This isn't a bug introduced by this patch, but does extending this condition
expose a pre-existing ABBA deadlock to P2PDMA failures?
If a management thread concurrently calls freeze_array(conf, 0) (setting
conf->array_frozen = 1 and waiting for nr_pending to drop to 0), and
raid1d takes this branch, it skips calling freeze_array(conf, 1) and
unfreeze_array(conf).
Later in handle_read_error(), the daemon thread invokes
raid1_read_request(), which blocks on wait_read_barrier() waiting for
conf->array_frozen to be cleared.
The management thread is blocked waiting for the daemon to drop its
nr_pending count, while the daemon is blocked waiting for the management
thread to unfreeze the array. Can this cause both threads to hang
indefinitely?
> 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 77c7d8a599160..462f622556ed0 100644
> --- a/drivers/md/raid10.c
> +++ b/drivers/md/raid10.c
[ ... ]
> @@ -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)
[Severity: High]
This isn't a bug introduced by this patch, but does this branch suffer from
a similar pre-existing deadlock in raid10?
If the daemon thread takes this path, it skips the freeze/unfreeze cycle
and later calls raid10_read_request(). This blocks on wait_barrier(),
waiting for the concurrent management freeze_array(conf, 0) to clear,
creating the same deadlock between the daemon and management thread.
> r10_bio->devs[slot].bio = IO_BLOCKED;
> else if (!test_bit(FailFast, &rdev->flags)) {
> freeze_array(conf, 1);
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260726113229.2154269-1-mykola@meshstor.io?part=8
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH v6 06/12] md/raid1,raid10: keep REQ_NOMERGE on narrow_write_error() retry clones
2026-07-26 11:32 ` [PATCH v6 06/12] md/raid1,raid10: keep REQ_NOMERGE on narrow_write_error() retry clones Mykola Marzhan
@ 2026-07-26 12:09 ` sashiko-bot
0 siblings, 0 replies; 25+ messages in thread
From: sashiko-bot @ 2026-07-26 12:09 UTC (permalink / raw)
To: Mykola Marzhan; +Cc: linux-raid, yukuai, linux-pci
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
Pre-existing issues:
- [High] Unconditional assignment to `wbio->bi_opf` destroys all request flags cloned from the master bio, leading to potential data corruption.
--
--- Patch [6]: [PATCH v6 06/12] md/raid1,raid10: keep REQ_NOMERGE on narrow_write_error() retry clones ---
commit 333e1430f8770afc53cf111be8c36899e6c4c5e3
Author: Mykola Marzhan <mykola@meshstor.io>
md/raid1,raid10: keep REQ_NOMERGE on narrow_write_error() retry clones
This commit restores REQ_NOMERGE on P2PDMA retry clones in
narrow_write_error() to prevent member queues from improperly merging
segments.
> diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
> index f07edeac6e5a3..19c4dec450de0 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;
[Severity: High]
This isn't a bug introduced by this patch, but does this assignment
unintentionally overwrite all request flags?
Since bio_alloc_clone() copies the original bi_opf, setting it directly to
REQ_OP_WRITE zeroes out the upper 24 flag bits, which drops flags like
REQ_FUA and REQ_PREFLUSH.
Could this result in data corruption on power loss if the original write
requested forced unit access?
> + /* 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 5b63175fb3826..428bddddfe71d 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;
[Severity: High]
This is the same pre-existing issue as in raid1.c. Does overwriting bi_opf
drop critical data integrity flags like REQ_FUA cloned from the master bio?
> + /* 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)) {
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260726113229.2154269-1-mykola@meshstor.io?part=6
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH v6 10/12] nvme-rdma: return BLK_STS_P2PDMA for unsupported P2P transfers
2026-07-26 11:32 ` [PATCH v6 10/12] nvme-rdma: return BLK_STS_P2PDMA for unsupported P2P transfers Mykola Marzhan
@ 2026-07-26 12:10 ` sashiko-bot
0 siblings, 0 replies; 25+ messages in thread
From: sashiko-bot @ 2026-07-26 12:10 UTC (permalink / raw)
To: Mykola Marzhan; +Cc: linux-raid, linux-pci, yukuai
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
New issues:
- [High] DMA API violation causing stale PI metadata (Data Corruption).
Pre-existing issues:
- [High] Incomplete fix: multipath I/O accounting leak on nvme_rdma_post_send() failure.
--
--- Patch [10]: [PATCH v6 10/12] nvme-rdma: return BLK_STS_P2PDMA for unsupported P2P transfers ---
commit d3d8febf3662843e41333a6adc3c3ea1d88ff373
Author: Mykola Marzhan <mykola@meshstor.io>
nvme-rdma: return BLK_STS_P2PDMA for unsupported P2P transfers
This commit propagates -EREMOTEIO from ib_dma_map_sgtable_attrs() as BLK_STS_P2PDMA
to prevent infinite multipath requeues. It also delays nvme_start_request() until
after data mapping succeeds to avoid multipath accounting leaks on mapping errors.
Cc: stable@vger.kernel.org # v7.1: requires BLK_STS_P2PDMA and the ib_dma_map_sgtable_attrs() conversion
> diff --git a/drivers/nvme/host/rdma.c b/drivers/nvme/host/rdma.c
> index 63830334c73e2..c38d949502b7c 100644
> --- a/drivers/nvme/host/rdma.c
> +++ b/drivers/nvme/host/rdma.c
> @@ -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 ||
> @@ -2051,6 +2045,8 @@ static blk_status_t nvme_rdma_queue_rq(struct blk_mq_hw_ctx *hctx,
> goto err;
> }
>
> + nvme_start_request(rq);
> +
[Severity: High]
Does moving nvme_start_request() after nvme_rdma_map_data() violate the DMA API?
nvme_start_request() calls blk_mq_start_request(), which invokes
blk_integrity_prepare(). This modifies the PI metadata buffers in CPU memory
to update reference tags.
Because nvme_rdma_map_data() has already mapped these buffers for DMA
(DMA_TO_DEVICE), could CPU writes happening after the map operation remain
unsynced on non-coherent architectures or when bounce buffers are used?
This might cause the device to read stale PI metadata, leading to PI
verification failures or data corruption.
> 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;
[Severity: High]
This is a pre-existing issue, but I noticed a potential multipath I/O
accounting leak if nvme_rdma_post_send() fails.
The commit message notes that starting the request before a failure causes
multipath accounting leaks when blk-mq hard-completes the request directly.
If nvme_rdma_post_send() fails (e.g., returns -EINVAL), execution jumps to
err_unmap and falls through to the err: block, returning a hard error status
like BLK_STS_IOERR:
err = nvme_rdma_post_send(queue, sqe, ...);
if (unlikely(err))
goto err_unmap;
...
err:
...
else
ret = BLK_STS_IOERR;
Since nvme_start_request() was already called, will blk-mq hard-complete the
request directly, bypassing the driver's nvme_mpath_end_request() and leaking
multipath accounting like bd_stats->in_flight and nr_active?
This could permanently block block device teardown.
> nvme_cleanup_cmd(rq);
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260726113229.2154269-1-mykola@meshstor.io?part=10
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH v6 03/12] md/raid1: serialize non-write-behind writes on CollisionCheck rdevs
2026-07-26 11:32 ` [PATCH v6 03/12] md/raid1: serialize non-write-behind writes on CollisionCheck rdevs Mykola Marzhan
@ 2026-07-26 12:10 ` sashiko-bot
0 siblings, 0 replies; 25+ messages in thread
From: sashiko-bot @ 2026-07-26 12:10 UTC (permalink / raw)
To: Mykola Marzhan; +Cc: yukuai, linux-pci, linux-raid
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
Pre-existing issues:
- [High] A Time-of-Check to Time-of-Use (TOCTOU) race condition exists during concurrent device removal, leading to a NULL pointer dereference in both the read and write I/O submission paths.
--
--- Patch [3]: [PATCH v6 03/12] md/raid1: serialize non-write-behind writes on CollisionCheck rdevs ---
commit c5339979d08defedb52fda8881d721fd1180c172
Author: Mykola Marzhan <mykola@meshstor.io>
md/raid1: serialize non-write-behind writes on CollisionCheck rdevs
This commit serializes non-write-behind writes on CollisionCheck rdevs
to prevent older behind data from landing last and leaving stale data.
It replaces the previous MD_SERIALIZE_POLICY check with CollisionCheck,
which properly accounts for write-mostly members.
Link: https://lore.kernel.org/linux-raid/20260723112741.1206836-1-mwilck@suse.com/
> diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
> index afe2ca96ad8c2..997f79c05db7b 100644
> --- a/drivers/md/raid1.c
> +++ b/drivers/md/raid1.c
[ ... ]
> @@ -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);
>
[Severity: High]
This is a pre-existing issue, but can this second loop in
raid1_write_request() encounter a NULL pointer dereference during
concurrent device removal?
The loop re-fetches rdev from conf->mirrors[i].rdev which might have
been set to NULL by a concurrent raid1_remove_conf(). If
raid1_remove_conf() executes after the first loop incremented
nr_pending on the old pointer, re-fetching it here and accessing
rdev->bdev in bio_alloc_clone() could trigger a kernel panic.
A similar issue appears to exist in the read path where
update_read_sectors() implicitly re-fetches info->rdev after an active
disk is selected in choose_best_rdev(), potentially crashing on
atomic_inc(&info->rdev->nr_pending).
> - 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);
> }
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260726113229.2154269-1-mykola@meshstor.io?part=3
^ permalink raw reply [flat|nested] 25+ messages in thread
end of thread, other threads:[~2026-07-26 12:10 UTC | newest]
Thread overview: 25+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-26 11:32 [PATCH v6 00/12] block,md,nvme: correct handling of unsupported P2PDMA transfers Mykola Marzhan
2026-07-26 11:32 ` [PATCH v6 01/12] block: add BLK_STS_P2PDMA for unsupported peer-to-peer transfers Mykola Marzhan
2026-07-26 12:06 ` sashiko-bot
2026-07-26 11:32 ` [PATCH v6 02/12] md: ensure REQ_NOMERGE is set on P2PDMA bios Mykola Marzhan
2026-07-26 11:59 ` sashiko-bot
2026-07-26 11:32 ` [PATCH v6 03/12] md/raid1: serialize non-write-behind writes on CollisionCheck rdevs Mykola Marzhan
2026-07-26 12:10 ` sashiko-bot
2026-07-26 11:32 ` [PATCH v6 04/12] md/raid1: don't use write-behind for P2PDMA bios Mykola Marzhan
2026-07-26 12:01 ` sashiko-bot
2026-07-26 11:32 ` [PATCH v6 05/12] md/raid1,raid10: factor out raid1_write_error() helper Mykola Marzhan
2026-07-26 11:57 ` sashiko-bot
2026-07-26 11:32 ` [PATCH v6 06/12] md/raid1,raid10: keep REQ_NOMERGE on narrow_write_error() retry clones Mykola Marzhan
2026-07-26 12:09 ` sashiko-bot
2026-07-26 11:32 ` [PATCH v6 07/12] md/raid1,raid10: skip futile retries on P2PDMA mapping failures Mykola Marzhan
2026-07-26 12:03 ` sashiko-bot
2026-07-26 11:32 ` [PATCH v6 08/12] md/raid1,raid10: set IO_BLOCKED in case of BLK_STS_P2PDMA Mykola Marzhan
2026-07-26 12:06 ` sashiko-bot
2026-07-26 11:32 ` [PATCH v6 09/12] nvme-rdma: use ib_dma_map_sgtable_attrs() Mykola Marzhan
2026-07-26 12:01 ` sashiko-bot
2026-07-26 11:32 ` [PATCH v6 10/12] nvme-rdma: return BLK_STS_P2PDMA for unsupported P2P transfers Mykola Marzhan
2026-07-26 12:10 ` sashiko-bot
2026-07-26 11:32 ` [PATCH v6 11/12] nvme-rdma: ratelimit the map-failure error message Mykola Marzhan
2026-07-26 11:53 ` sashiko-bot
2026-07-26 11:32 ` [PATCH v6 12/12] nvme-rdma: factor out the scatterlist DMA mapping helper Mykola Marzhan
2026-07-26 12:02 ` sashiko-bot
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox