* FAILED: patch "[PATCH] block: relax pgmap check in bio_add_page for compatible zone" failed to apply to 6.12-stable tree
@ 2026-05-01 11:07 gregkh
2026-05-02 23:30 ` [PATCH 6.12.y] block: relax pgmap check in bio_add_page for compatible zone device pages Sasha Levin
0 siblings, 1 reply; 2+ messages in thread
From: gregkh @ 2026-05-01 11:07 UTC (permalink / raw)
To: namjain, axboe, hch; +Cc: stable
The patch below does not apply to the 6.12-stable tree.
If someone wants it applied there, or to any other stable or longterm
tree, then please email the backport, including the original git commit
id to <stable@vger.kernel.org>.
To reproduce the conflict and resubmit, you may use the following commands:
git fetch https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/ linux-6.12.y
git checkout FETCH_HEAD
git cherry-pick -x 41c665aae2b5dbecddddcc8ace344caf630cc7a4
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<stable@vger.kernel.org>' --in-reply-to '2026050149-moonlike-issue-7246@gregkh' --subject-prefix 'PATCH 6.12.y' HEAD^..
Possible dependencies:
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From 41c665aae2b5dbecddddcc8ace344caf630cc7a4 Mon Sep 17 00:00:00 2001
From: Naman Jain <namjain@linux.microsoft.com>
Date: Fri, 10 Apr 2026 15:34:14 +0000
Subject: [PATCH] block: relax pgmap check in bio_add_page for compatible zone
device pages
bio_add_page() and bio_integrity_add_page() reject pages from different
dev_pagemaps entirely, returning 0 even when those pages have compatible
DMA mapping requirements. This forces callers to start a new bio when
buffers span pgmap boundaries, even though the pages could safely coexist
as separate bvec entries.
This matters for guests where memory is registered through
devm_memremap_pages() with MEMORY_DEVICE_GENERIC in multiple calls,
creating separate dev_pagemaps for each chunk. When a direct I/O buffer
spans two such chunks, bio_add_page() rejects the second page, forcing an
unnecessary bio split or I/O failure.
Introduce zone_device_pages_compatible() in blk.h to check whether two
pages can coexist in the same bio as separate bvec entries. The block DMA
iterator (blk_dma_map_iter_start) caches the P2PDMA mapping state from the
first segment and applies it to all others, so P2PDMA pages from different
pgmaps must not be mixed, and neither must P2PDMA and non-P2PDMA pages.
All other combinations (MEMORY_DEVICE_GENERIC pages from different pgmaps,
or MEMORY_DEVICE_GENERIC with normal RAM) use the same dma_map_phys path
and are safe.
Replace the blanket zone_device_pages_have_same_pgmap() rejection with
zone_device_pages_compatible(), while keeping
zone_device_pages_have_same_pgmap() as a merge guard.
Pages from different pgmaps can be added as separate bvec entries but
must not be coalesced into the same segment, as that would make
it impossible to recover the correct pgmap via page_pgmap().
Fixes: 49580e690755 ("block: add check when merging zone device pages")
Cc: stable@vger.kernel.org
Signed-off-by: Naman Jain <namjain@linux.microsoft.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Link: https://patch.msgid.link/20260410153414.4159050-3-namjain@linux.microsoft.com
Signed-off-by: Jens Axboe <axboe@kernel.dk>
diff --git a/block/bio-integrity.c b/block/bio-integrity.c
index e79eaf047794..e54c6e06e1cb 100644
--- a/block/bio-integrity.c
+++ b/block/bio-integrity.c
@@ -231,10 +231,10 @@ int bio_integrity_add_page(struct bio *bio, struct page *page,
if (bip->bip_vcnt > 0) {
struct bio_vec *bv = &bip->bip_vec[bip->bip_vcnt - 1];
- if (!zone_device_pages_have_same_pgmap(bv->bv_page, page))
+ if (!zone_device_pages_compatible(bv->bv_page, page))
return 0;
-
- if (bvec_try_merge_hw_page(q, bv, page, len, offset)) {
+ if (zone_device_pages_have_same_pgmap(bv->bv_page, page) &&
+ bvec_try_merge_hw_page(q, bv, page, len, offset)) {
bip->bip_iter.bi_size += len;
return len;
}
diff --git a/block/bio.c b/block/bio.c
index 641ef0928d73..c52a0bd1e899 100644
--- a/block/bio.c
+++ b/block/bio.c
@@ -1048,10 +1048,10 @@ int bio_add_page(struct bio *bio, struct page *page,
if (bio->bi_vcnt > 0) {
struct bio_vec *bv = &bio->bi_io_vec[bio->bi_vcnt - 1];
- if (!zone_device_pages_have_same_pgmap(bv->bv_page, page))
+ if (!zone_device_pages_compatible(bv->bv_page, page))
return 0;
-
- if (bvec_try_merge_page(bv, page, len, offset)) {
+ if (zone_device_pages_have_same_pgmap(bv->bv_page, page) &&
+ bvec_try_merge_page(bv, page, len, offset)) {
bio->bi_iter.bi_size += len;
return len;
}
diff --git a/block/blk.h b/block/blk.h
index 50a41db03913..b998a7761faf 100644
--- a/block/blk.h
+++ b/block/blk.h
@@ -136,6 +136,25 @@ static inline bool biovec_phys_mergeable(struct request_queue *q,
return true;
}
+/*
+ * Check if two pages from potentially different zone device pgmaps can
+ * coexist as separate bvec entries in the same bio.
+ *
+ * The block DMA iterator (blk_dma_map_iter_start) caches the P2PDMA mapping
+ * state from the first segment and applies it to all subsequent segments, so
+ * P2PDMA pages from different pgmaps must not be mixed in the same bio.
+ *
+ * Other zone device types (FS_DAX, GENERIC) use the same dma_map_phys() path
+ * as normal RAM. PRIVATE and COHERENT pages never appear in bios.
+ */
+static inline bool zone_device_pages_compatible(const struct page *a,
+ const struct page *b)
+{
+ if (is_pci_p2pdma_page(a) || is_pci_p2pdma_page(b))
+ return zone_device_pages_have_same_pgmap(a, b);
+ return true;
+}
+
static inline bool __bvec_gap_to_prev(const struct queue_limits *lim,
struct bio_vec *bprv, unsigned int offset)
{
^ permalink raw reply related [flat|nested] 2+ messages in thread
* [PATCH 6.12.y] block: relax pgmap check in bio_add_page for compatible zone device pages
2026-05-01 11:07 FAILED: patch "[PATCH] block: relax pgmap check in bio_add_page for compatible zone" failed to apply to 6.12-stable tree gregkh
@ 2026-05-02 23:30 ` Sasha Levin
0 siblings, 0 replies; 2+ messages in thread
From: Sasha Levin @ 2026-05-02 23:30 UTC (permalink / raw)
To: stable; +Cc: Naman Jain, Christoph Hellwig, Jens Axboe, Sasha Levin
From: Naman Jain <namjain@linux.microsoft.com>
[ Upstream commit 41c665aae2b5dbecddddcc8ace344caf630cc7a4 ]
bio_add_page() and bio_integrity_add_page() reject pages from different
dev_pagemaps entirely, returning 0 even when those pages have compatible
DMA mapping requirements. This forces callers to start a new bio when
buffers span pgmap boundaries, even though the pages could safely coexist
as separate bvec entries.
This matters for guests where memory is registered through
devm_memremap_pages() with MEMORY_DEVICE_GENERIC in multiple calls,
creating separate dev_pagemaps for each chunk. When a direct I/O buffer
spans two such chunks, bio_add_page() rejects the second page, forcing an
unnecessary bio split or I/O failure.
Introduce zone_device_pages_compatible() in blk.h to check whether two
pages can coexist in the same bio as separate bvec entries. The block DMA
iterator (blk_dma_map_iter_start) caches the P2PDMA mapping state from the
first segment and applies it to all others, so P2PDMA pages from different
pgmaps must not be mixed, and neither must P2PDMA and non-P2PDMA pages.
All other combinations (MEMORY_DEVICE_GENERIC pages from different pgmaps,
or MEMORY_DEVICE_GENERIC with normal RAM) use the same dma_map_phys path
and are safe.
Replace the blanket zone_device_pages_have_same_pgmap() rejection with
zone_device_pages_compatible(), while keeping
zone_device_pages_have_same_pgmap() as a merge guard.
Pages from different pgmaps can be added as separate bvec entries but
must not be coalesced into the same segment, as that would make
it impossible to recover the correct pgmap via page_pgmap().
Fixes: 49580e690755 ("block: add check when merging zone device pages")
Cc: stable@vger.kernel.org
Signed-off-by: Naman Jain <namjain@linux.microsoft.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Link: https://patch.msgid.link/20260410153414.4159050-3-namjain@linux.microsoft.com
Signed-off-by: Jens Axboe <axboe@kernel.dk>
[ restructured combined `if` into explicit `bv` block ]
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
block/bio-integrity.c | 2 ++
block/bio.c | 14 +++++++++-----
block/blk.h | 19 +++++++++++++++++++
3 files changed, 30 insertions(+), 5 deletions(-)
diff --git a/block/bio-integrity.c b/block/bio-integrity.c
index 456026c4a3c96..6641ecbf69678 100644
--- a/block/bio-integrity.c
+++ b/block/bio-integrity.c
@@ -167,6 +167,8 @@ int bio_integrity_add_page(struct bio *bio, struct page *page,
struct bio_vec *bv = &bip->bip_vec[bip->bip_vcnt - 1];
bool same_page = false;
+ if (!zone_device_pages_compatible(bv->bv_page, page))
+ return 0;
if (bvec_try_merge_hw_page(q, bv, page, len, offset,
&same_page)) {
bip->bip_iter.bi_size += len;
diff --git a/block/bio.c b/block/bio.c
index b919f3fa2f2d4..a081e2ddf9cf8 100644
--- a/block/bio.c
+++ b/block/bio.c
@@ -1155,11 +1155,15 @@ int bio_add_page(struct bio *bio, struct page *page,
if (bio->bi_iter.bi_size > UINT_MAX - len)
return 0;
- if (bio->bi_vcnt > 0 &&
- bvec_try_merge_page(&bio->bi_io_vec[bio->bi_vcnt - 1],
- page, len, offset, &same_page)) {
- bio->bi_iter.bi_size += len;
- return len;
+ if (bio->bi_vcnt > 0) {
+ struct bio_vec *bv = &bio->bi_io_vec[bio->bi_vcnt - 1];
+
+ if (!zone_device_pages_compatible(bv->bv_page, page))
+ return 0;
+ if (bvec_try_merge_page(bv, page, len, offset, &same_page)) {
+ bio->bi_iter.bi_size += len;
+ return len;
+ }
}
if (bio->bi_vcnt >= bio->bi_max_vecs)
diff --git a/block/blk.h b/block/blk.h
index e7d7c5c636524..8af4f7101c8a8 100644
--- a/block/blk.h
+++ b/block/blk.h
@@ -124,6 +124,25 @@ static inline bool biovec_phys_mergeable(struct request_queue *q,
return true;
}
+/*
+ * Check if two pages from potentially different zone device pgmaps can
+ * coexist as separate bvec entries in the same bio.
+ *
+ * The block DMA iterator (blk_dma_map_iter_start) caches the P2PDMA mapping
+ * state from the first segment and applies it to all subsequent segments, so
+ * P2PDMA pages from different pgmaps must not be mixed in the same bio.
+ *
+ * Other zone device types (FS_DAX, GENERIC) use the same dma_map_phys() path
+ * as normal RAM. PRIVATE and COHERENT pages never appear in bios.
+ */
+static inline bool zone_device_pages_compatible(const struct page *a,
+ const struct page *b)
+{
+ if (is_pci_p2pdma_page(a) || is_pci_p2pdma_page(b))
+ return zone_device_pages_have_same_pgmap(a, b);
+ return true;
+}
+
static inline bool __bvec_gap_to_prev(const struct queue_limits *lim,
struct bio_vec *bprv, unsigned int offset)
{
--
2.53.0
^ permalink raw reply related [flat|nested] 2+ messages in thread
end of thread, other threads:[~2026-05-02 23:30 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-05-01 11:07 FAILED: patch "[PATCH] block: relax pgmap check in bio_add_page for compatible zone" failed to apply to 6.12-stable tree gregkh
2026-05-02 23:30 ` [PATCH 6.12.y] block: relax pgmap check in bio_add_page for compatible zone device pages Sasha Levin
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox