[PATCH 2/2] block: allow different-pgmap pages as separate bvecs in bio_add_page
From: Naman Jain
Date: Wed Apr 01 2026 - 04:31:07 EST
bio_add_page() and bio_integrity_add_page() reject pages from a
different dev_pagemap entirely, returning 0 even when the page could
be added as a new bvec entry. The pgmap check was intended only to
prevent merging into the same bvec segment, not to block the page
from being added at all.
This causes callers to unnecessarily start a new bio when a buffer
spans pages from two different pgmaps, even though the bio has room
for another bvec.
Fix both functions by moving the zone_device_pages_have_same_pgmap()
check into the merge conditional. Pages from different pgmaps now
skip the merge attempt and fall through to be added as new separate
bvec entries.
This is safe because biovec_phys_mergeable() now also checks for
pgmap mismatches, preventing the downstream merge, DMA mapping, and
request coalescing paths from combining segments across pgmaps.
Fixes: 49580e690755 ("block: add check when merging zone device pages")
Cc: stable@xxxxxxxxxxxxxxx
Signed-off-by: Naman Jain <namjain@xxxxxxxxxxxxxxxxxxx>
---
block/bio-integrity.c | 6 ++----
block/bio.c | 6 ++----
2 files changed, 4 insertions(+), 8 deletions(-)
diff --git a/block/bio-integrity.c b/block/bio-integrity.c
index e79eaf0477943..3462697331890 100644
--- a/block/bio-integrity.c
+++ b/block/bio-integrity.c
@@ -231,10 +231,8 @@ 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))
- 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 77067fa346d35..7715e59e68613 100644
--- a/block/bio.c
+++ b/block/bio.c
@@ -1034,10 +1034,8 @@ 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))
- 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;
}
--
2.43.0