[PATCH] mm/madvise: avoid skipping pages after splitting large folios

From: Yunhui Cui

Date: Wed Aug 05 2026 - 08:54:07 EST


madvise_inject_error() advances through the requested range using the
size of the page returned by get_user_pages_fast(). Saving the size
before error injection is required for hugetlb pages because successful
soft offlining can dissolve the source huge page.

That stride is incorrect for non-hugetlb large folios. The memory
failure handlers split such a folio and handle only the base page for
the supplied PFN. Advancing by the pre-split folio size then skips the
remaining pages in the requested range while madvise() still reports
success.

Advance by PAGE_SIZE for non-hugetlb pages and retain the whole-page
stride for hugetlb pages.

Fixes: 19bfbe22f59a ("mm, hugetlb, soft_offline: save compound page order before page migration")
Cc: stable@xxxxxxxxxxxxxxx
Signed-off-by: Yunhui Cui <cuiyunhui@xxxxxxxxxxxxx>
---
mm/madvise.c | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/mm/madvise.c b/mm/madvise.c
index 07a21ca31bad4..f37abed29445b 100644
--- a/mm/madvise.c
+++ b/mm/madvise.c
@@ -1464,11 +1464,12 @@ static int madvise_inject_error(struct madvise_behavior *madv_behavior)
pfn = page_to_pfn(page);

/*
- * When soft offlining hugepages, after migrating the page
- * we dissolve it, therefore in the second loop "page" will
- * no longer be a compound page.
+ * Non-hugetlb large folios are split and only the addressed
+ * base page is handled. Hugetlb folios are handled as a
+ * whole and may be dissolved, so save their size beforehand.
*/
- size = page_size(compound_head(page));
+ size = PageHuge(page) ?
+ page_size(compound_head(page)) : PAGE_SIZE;

if (madv_behavior->behavior == MADV_SOFT_OFFLINE) {
pr_info("Soft offlining pfn %#lx at process virtual address %#lx\n",
--
2.39.5