Skip to contentSkip to conversation

FAILED: patch "[PATCH] mm/rmap: use huge_ptep_get() in try_to_unmap_one()" failed to apply to 6.12-stable tree

PATCH New [email protected] 2 participants 3 messages Sep 3 – Sep 4

Subsystems (4)
lore
Share & tools
lore

[email protected]

author maintainer
#0 lore raw

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 <[email protected]>.

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 f5407e9b697c940e78b27ff63c6e14d8d171adc3
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<[email protected]>' --in-reply-to '2026090345-number-strenuous-f36b@gregkh' --subject-prefix 'PATCH 6.12.y' 'HEAD^..'

Possible dependencies:

thanks,

greg k-h

------------------ original commit in Linus's tree ------------------

From f5407e9b697c940e78b27ff63c6e14d8d171adc3 Mon Sep 17 00:00:00 2001
From: Dev Jain <[email protected]>
Date: Fri, 3 Jul 2026 11:41:55 +0000
Subject: [PATCH] mm/rmap: use huge_ptep_get() in try_to_unmap_one()

Patch series "Fix incorrect access of hugetlb pte entries", v3.

There are various places which use ptep_get() to get the pte entry corresponding to a hugetlb folio. Some arches (like s390) have special handling to compute the pteval, so they provide huge_ptep_get(). Use this helper consistently.

Additionally, some code paths may provide huge_ptep_get with an unaligned address. This is a problem on arm64 (I checked other arches and it looks fine for them), which is fixed in patch 1. The fix is made to be
backport-friendly: the cleaner fix would be to perhaps pass the hstate to huge_ptep_get() - that is wider churn and we can do that later.

This patch (of 5):

try_to_unmap_one() handles hugetlb folios when memory failure needs to replace a poisoned hugetlb mapping with a hwpoison entry. In that case page_vma_mapped_walk() returns the pte pointer to the hugetlb folio in pvmw.pte, but the code reads it with ptep_get().

On arches which provide their own huge_ptep_get() to dereference a huge pte pointer, accessing via ptep_get() would cause pte_pfn(), pte_present() etc to misbehave.

It is not clear whether this has a trivially visible effect to userspace.

Just use huge_ptep_get() for dereferencing a huge pte pointer.

Fixes c7ab0d2fdc84 ("mm: convert try_to_unmap_one() to use page_vma_mapped_walk()")
Cc Alistair Popple <[email protected]>
Cc Andi Kleen <[email protected]>
Cc Anshuman Khandual <[email protected]>
Cc Byungchul Park <[email protected]>
Cc Catalin Marinas <[email protected]>
Cc Dave Hansen <[email protected]>
Cc Gregory Price <[email protected]>
Cc Harry Yoo <[email protected]>
Cc "Huang, Ying" <[email protected]>
Cc Jann Horn <[email protected]>
Cc Josh Poimboeuf <[email protected]>
Cc Joshua Hahn <[email protected]>
Cc Jun'ichi "Nick" Nomura <[email protected]>
Cc Kiryl Shutsemau <[email protected]>
Cc Lance Yang <[email protected]>
Cc Liam R. Howlett <[email protected]>
Cc Lorenzo Stoakes <[email protected]>
Cc Matthew Brost <[email protected]>
Cc Mel Gorman <[email protected]>
Cc Naoya Horiguchi <[email protected]>
Cc Oscar Salvador <[email protected]>
Cc Pedro Falcato <[email protected]>
Cc Rakie Kim <[email protected]>
Cc Ralph Campbell <[email protected]>
Cc Rik van Riel <[email protected]>
Cc Ryan Roberts <[email protected]>
Cc Vlastimil Babka <[email protected]>
Cc Will Deacon <[email protected]>
Cc Zi Yan <[email protected]>
include/linux/hugetlb.h +2 -0
index 817b8b4223fa..95b1b6ee1f96 100644
@@ -1270,6 +1270,8 @@ static inline void hugetlb_count_sub(long l, struct mm_struct *mm)
 {
 }
 
+pte_t huge_ptep_get(struct mm_struct *mm, unsigned long addr, pte_t *ptep);
+
 static inline pte_t huge_ptep_clear_flush(struct vm_area_struct *vma,
 					  unsigned long addr, pte_t *ptep)
 {
mm/rmap.c +10 -6
index 408e542649b5..e0d7b33ceee4 100644
@@ -2095,14 +2095,19 @@ static bool try_to_unmap_one(struct folio *folio, struct vm_area_struct *vma,
 		/* Unexpected PMD-mapped THP? */
 		VM_BUG_ON_FOLIO(!pvmw.pte, folio);
 
-		/*
-		 * Handle PFN swap PTEs, such as device-exclusive ones, that
-		 * actually map pages.
-		 */
-		pteval = ptep_get(pvmw.pte);
+		address = pvmw.address;
+		if (folio_test_hugetlb(folio)) {
+			pteval = huge_ptep_get(mm, address, pvmw.pte);
+		} else {
+			pteval = ptep_get(pvmw.pte);
+		}
 		if (likely(pte_present(pteval))) {
 			pfn = pte_pfn(pteval);
 		} else {
+			/*
+			 * Handle PFN swap PTEs, such as device-exclusive ones,
+			 * that actually map pages.
+			 */
 			const softleaf_t entry = softleaf_from_pte(pteval);
 
 			pfn = softleaf_to_pfn(entry);
@@ -2110,7 +2115,6 @@ static bool try_to_unmap_one(struct folio *folio, struct vm_area_struct *vma,
 		}
 
 		subpage = folio_page(folio, pfn - folio_pfn(folio));
-		address = pvmw.address;
 		anon_exclusive = folio_test_anon(folio) &&
 				 PageAnonExclusive(subpage);
 
maintainer
#1 lore raw

PATCH 1/2 mm: avoid unnecessary use of is_swap_pmd()

From: Lorenzo Stoakes <[email protected]>

[ Upstream commit aa62204cb680d8ff32497181fc9e0dac4956f7e5 ]

PMD 'non-swap' swap entries are currently used for PMD-level migration entries and device private entries.

To add to the confusion in this terminology we use is_swap_pmd() in an inconsistent way similar to how is_swap_pte() was being used - sometimes adopting the convention that !pmd_none(), !pmd_present() implies PMD 'swap' entry, sometimes not.

This patch handles the low-hanging fruit of cases where we can simply substitute other predicates for is_swap_pmd().

No functional change intended.

Cc Alexander Gordeev <[email protected]>
Cc Alistair Popple <[email protected]>
Cc Al Viro <[email protected]>
Cc Arnd Bergmann <[email protected]>
Cc Axel Rasmussen <[email protected]>
Cc Baolin Wang <[email protected]>
Cc Baoquan He <[email protected]>
Cc Barry Song <[email protected]>
Cc Byungchul Park <[email protected]>
Cc Chengming Zhou <[email protected]>
Cc Chris Li <[email protected]>
Cc Christian Borntraeger <[email protected]>
Cc Christian Brauner <[email protected]>
Cc Claudio Imbrenda <[email protected]>
Cc David Hildenbrand <[email protected]>
Cc Dev Jain <[email protected]>
Cc Gerald Schaefer <[email protected]>
Cc Gregory Price <[email protected]>
Cc Heiko Carstens <[email protected]>
Cc "Huang, Ying" <[email protected]>
Cc Hugh Dickins <[email protected]>
Cc Jan Kara <[email protected]>
Cc Jann Horn <[email protected]>
Cc Janosch Frank <[email protected]>
Cc Jason Gunthorpe <[email protected]>
Cc Joshua Hahn <[email protected]>
Cc Kairui Song <[email protected]>
Cc Kemeng Shi <[email protected]>
Cc Lance Yang <[email protected]>
Cc Leon Romanovsky <[email protected]>
Cc Liam Howlett <[email protected]>
Cc Mathew Brost <[email protected]>
Cc Matthew Wilcox (Oracle) <[email protected]>
Cc Miaohe Lin <[email protected]>
Cc Michal Hocko <[email protected]>
Cc Mike Rapoport <[email protected]>
Cc Muchun Song <[email protected]>
Cc Naoya Horiguchi <[email protected]>
Cc Nhat Pham <[email protected]>
Cc Nico Pache <[email protected]>
Cc Oscar Salvador <[email protected]>
Cc Pasha Tatashin <[email protected]>
Cc Peter Xu <[email protected]>
Cc Rakie Kim <[email protected]>
Cc Rik van Riel <[email protected]>
Cc Ryan Roberts <[email protected]>
Cc SeongJae Park <[email protected]>
Cc Suren Baghdasaryan <[email protected]>
Cc Sven Schnelle <[email protected]>
Cc Vasily Gorbik <[email protected]>
Cc Vlastimil Babka <[email protected]>
Cc Wei Xu <[email protected]>
Cc xu xin <[email protected]>
Cc Yuanchu Xie <[email protected]>
Cc Zi Yan <[email protected]>

Stable-dep-of: f5407e9b697c ("mm/rmap: use huge_ptep_get() in try_to_unmap_one()")

---
 fs/proc/task_mmu.c       | 15 ++++++++---
 include/linux/mm_types.h |  3 +++
 include/linux/swapops.h  | 12 ++++++++-
 mm/huge_memory.c         |  4 ++-
 mm/memory.c              | 49 ++++++++++++++++++++----------------
 mm/page_table_check.c    | 12 ++++++---
 mm/rmap.c                | 54 ++++++++++++++++++++++++++++++----------
 7 files changed, 105 insertions(+), 44 deletions(-)
fs/proc/task_mmu.c +12 -3
index 44dc442b4f0e7..cfcf0daa1e626 100644
@@ -860,10 +860,12 @@ static void smaps_pmd_entry(pmd_t *pmd, unsigned long addr,
 	bool present = false;
 	struct folio *folio;
 
+	if (pmd_none(*pmd))
+		return;
 	if (pmd_present(*pmd)) {
 		page = vm_normal_page_pmd(vma, addr, *pmd);
 		present = true;
-	} else if (unlikely(thp_migration_supported() && is_swap_pmd(*pmd))) {
+	} else if (unlikely(thp_migration_supported())) {
 		swp_entry_t entry = pmd_to_swp_entry(*pmd);
 
 		if (is_pfn_swap_entry(entry))
@@ -1786,6 +1788,9 @@ static int pagemap_pmd_range(pmd_t *pmdp, unsigned long addr, unsigned long end,
 		if (vma->vm_flags & VM_SOFTDIRTY)
 			flags |= PM_SOFT_DIRTY;
 
+		if (pmd_none(pmd))
+			goto populate_pagemap;
+
 		if (pmd_present(pmd)) {
 			page = pmd_page(pmd);
 
@@ -1798,7 +1803,7 @@ static int pagemap_pmd_range(pmd_t *pmdp, unsigned long addr, unsigned long end,
 				frame = pmd_pfn(pmd) + idx;
 		}
 #ifdef CONFIG_ARCH_ENABLE_THP_MIGRATION
-		else if (is_swap_pmd(pmd)) {
+		else {
 			swp_entry_t entry = pmd_to_swp_entry(pmd);
 			unsigned long offset;
 
@@ -1826,6 +1831,7 @@ static int pagemap_pmd_range(pmd_t *pmdp, unsigned long addr, unsigned long end,
 				flags |= PM_FILE;
 		}
 
+populate_pagemap:
 		for (; addr != end; addr += PAGE_SIZE, idx++) {
 			u64 cur_flags = flags;
 			pagemap_entry_t pme;
@@ -2172,6 +2178,9 @@ static unsigned long pagemap_thp_category(struct pagemap_scan_private *p,
 {
 	unsigned long categories = PAGE_IS_HUGE;
 
+	if (pmd_none(pmd))
+		return categories;
+
 	if (pmd_present(pmd)) {
 		struct page *page;
 
@@ -2189,7 +2198,7 @@ static unsigned long pagemap_thp_category(struct pagemap_scan_private *p,
 			categories |= PAGE_IS_PFNZERO;
 		if (pmd_soft_dirty(pmd))
 			categories |= PAGE_IS_SOFT_DIRTY;
-	} else if (is_swap_pmd(pmd)) {
+	} else {
 		swp_entry_t swp;
 
 		categories |= PAGE_IS_SWAPPED;
include/linux/mm_types.h +3 -0
index 2113f7da182c6..ca4e4a1c2d0b9 100644
@@ -283,6 +283,9 @@ typedef struct {
 	unsigned long val;
 } swp_entry_t;
 
+/* Transitional name used by newer MM fixes. */
+typedef swp_entry_t softleaf_t;
+
 /**
  * struct folio - Represents a contiguous set of bytes.
  * @flags: Identical to the page flags.
include/linux/swapops.h +11 -1
index d988ce9516510..d06bda5be5768 100644
@@ -139,6 +139,10 @@ static inline swp_entry_t pte_to_swp_entry(pte_t pte)
 	return swp_entry(__swp_type(arch_entry), __swp_offset(arch_entry));
 }
 
+/* Transitional softleaf spellings for the equivalent swap entry helpers. */
+#define softleaf_from_pte(pte) pte_to_swp_entry(pte)
+#define softleaf_to_pfn(entry) swp_offset_pfn(entry)
+
 /*
  * Convert the arch-independent representation of a swp_entry_t into the
  * arch-dependent pte representation.
@@ -569,7 +573,13 @@ static inline pmd_t swp_entry_to_pmd(swp_entry_t entry)
 
 static inline int is_pmd_migration_entry(pmd_t pmd)
 {
-	return is_swap_pmd(pmd) && is_migration_entry(pmd_to_swp_entry(pmd));
+	swp_entry_t entry;
+
+	if (pmd_present(pmd))
+		return 0;
+
+	entry = pmd_to_swp_entry(pmd);
+	return is_migration_entry(entry);
 }
 #else  /* CONFIG_ARCH_ENABLE_THP_MIGRATION */
 static inline int set_pmd_migration_entry(struct page_vma_mapped_walk *pvmw,
mm/huge_memory.c +3 -1
index 29cbe43b60a4f..6fc4e1fb88ae6 100644
@@ -2149,9 +2149,11 @@ static pmd_t move_soft_dirty_pmd(pmd_t pmd)
 
 static pmd_t clear_uffd_wp_pmd(pmd_t pmd)
 {
+	if (pmd_none(pmd))
+		return pmd;
 	if (pmd_present(pmd))
 		pmd = pmd_clear_uffd_wp(pmd);
-	else if (is_swap_pmd(pmd))
+	else
 		pmd = pmd_swp_clear_uffd_wp(pmd);
 
 	return pmd;
mm/memory.c +27 -22

61 lines not on this page · raw message

mm/page_table_check.c +8 -4
index 509c6ef8de400..ee52927e9e66b 100644
@@ -228,10 +228,14 @@ EXPORT_SYMBOL(__page_table_check_ptes_set);
 
 static inline void page_table_check_pmd_flags(pmd_t pmd)
 {
-	if (pmd_present(pmd) && pmd_uffd_wp(pmd))
-		WARN_ON_ONCE(pmd_write(pmd));
-	else if (is_swap_pmd(pmd) && pmd_swp_uffd_wp(pmd))
-		WARN_ON_ONCE(swap_cached_writable(pmd_to_swp_entry(pmd)));
+	if (pmd_present(pmd)) {
+		if (pmd_uffd_wp(pmd))
+			WARN_ON_ONCE(pmd_write(pmd));
+	} else if (pmd_swp_uffd_wp(pmd)) {
+		swp_entry_t entry = pmd_to_swp_entry(pmd);
+
+		WARN_ON_ONCE(swap_cached_writable(entry));
+	}
 }
 
 void __page_table_check_pmd_set(struct mm_struct *mm, pmd_t *pmdp, pmd_t pmd)
mm/rmap.c +41 -13

104 lines not on this page · raw message

Signature · 1 line
2.53.0
maintainer
#2 lore raw

PATCH 2/2 mm/rmap: use huge_ptep_get() in try_to_unmap_one()

From: Dev Jain <[email protected]>

[ Upstream commit f5407e9b697c940e78b27ff63c6e14d8d171adc3 ]

Patch series "Fix incorrect access of hugetlb pte entries", v3.

There are various places which use ptep_get() to get the pte entry corresponding to a hugetlb folio. Some arches (like s390) have special handling to compute the pteval, so they provide huge_ptep_get(). Use this helper consistently.

Additionally, some code paths may provide huge_ptep_get with an unaligned address. This is a problem on arm64 (I checked other arches and it looks fine for them), which is fixed in patch 1. The fix is made to be
backport-friendly: the cleaner fix would be to perhaps pass the hstate to huge_ptep_get() - that is wider churn and we can do that later.

This patch (of 5):

try_to_unmap_one() handles hugetlb folios when memory failure needs to replace a poisoned hugetlb mapping with a hwpoison entry. In that case page_vma_mapped_walk() returns the pte pointer to the hugetlb folio in pvmw.pte, but the code reads it with ptep_get().

On arches which provide their own huge_ptep_get() to dereference a huge pte pointer, accessing via ptep_get() would cause pte_pfn(), pte_present() etc to misbehave.

It is not clear whether this has a trivially visible effect to userspace.

Just use huge_ptep_get() for dereferencing a huge pte pointer.

Fixes c7ab0d2fdc84 ("mm: convert try_to_unmap_one() to use page_vma_mapped_walk()")
Cc Alistair Popple <[email protected]>
Cc Andi Kleen <[email protected]>
Cc Anshuman Khandual <[email protected]>
Cc Byungchul Park <[email protected]>
Cc Catalin Marinas <[email protected]>
Cc Dave Hansen <[email protected]>
Cc Gregory Price <[email protected]>
Cc Harry Yoo <[email protected]>
Cc "Huang, Ying" <[email protected]>
Cc Jann Horn <[email protected]>
Cc Josh Poimboeuf <[email protected]>
Cc Joshua Hahn <[email protected]>
Cc Jun'ichi "Nick" Nomura <[email protected]>
Cc Kiryl Shutsemau <[email protected]>
Cc Lance Yang <[email protected]>
Cc Liam R. Howlett <[email protected]>
Cc Lorenzo Stoakes <[email protected]>
Cc Matthew Brost <[email protected]>
Cc Mel Gorman <[email protected]>
Cc Naoya Horiguchi <[email protected]>
Cc Oscar Salvador <[email protected]>
Cc Pedro Falcato <[email protected]>
Cc Rakie Kim <[email protected]>
Cc Ralph Campbell <[email protected]>
Cc Rik van Riel <[email protected]>
Cc Ryan Roberts <[email protected]>
Cc Vlastimil Babka <[email protected]>
Cc Will Deacon <[email protected]>
Cc Zi Yan <[email protected]>
---
 include/linux/hugetlb.h |  2 ++
 mm/rmap.c               | 16 ++++++++++------
 2 files changed, 12 insertions(+), 6 deletions(-)
include/linux/hugetlb.h +2 -0
index 739bc71c33fd1..dfea039a1dc89 100644
@@ -1235,6 +1235,8 @@ static inline void hugetlb_count_sub(long l, struct mm_struct *mm)
 {
 }
 
+pte_t huge_ptep_get(struct mm_struct *mm, unsigned long addr, pte_t *ptep);
+
 static inline pte_t huge_ptep_clear_flush(struct vm_area_struct *vma,
 					  unsigned long addr, pte_t *ptep)
 {
mm/rmap.c +10 -6
index b7907fa14dc98..c051651de6f9a 100644
@@ -1711,14 +1711,19 @@ static bool try_to_unmap_one(struct folio *folio, struct vm_area_struct *vma,
 		/* Unexpected PMD-mapped THP? */
 		VM_BUG_ON_FOLIO(!pvmw.pte, folio);
 
-		/*
-		 * Handle PFN swap PTEs, such as device-exclusive ones, that
-		 * actually map pages.
-		 */
-		pteval = ptep_get(pvmw.pte);
+		address = pvmw.address;
+		if (folio_test_hugetlb(folio)) {
+			pteval = huge_ptep_get(mm, address, pvmw.pte);
+		} else {
+			pteval = ptep_get(pvmw.pte);
+		}
 		if (likely(pte_present(pteval))) {
 			pfn = pte_pfn(pteval);
 		} else {
+			/*
+			 * Handle PFN swap PTEs, such as device-exclusive ones,
+			 * that actually map pages.
+			 */
 			const softleaf_t entry = softleaf_from_pte(pteval);
 
 			pfn = softleaf_to_pfn(entry);
@@ -1726,7 +1731,6 @@ static bool try_to_unmap_one(struct folio *folio, struct vm_area_struct *vma,
 		}
 
 		subpage = folio_page(folio, pfn - folio_pfn(folio));
-		address = pvmw.address;
 		anon_exclusive = folio_test_anon(folio) &&
 				 PageAnonExclusive(subpage);
 
Signature · 1 line
2.53.0