FAILED: patch "[PATCH] mm/migrate: use huge_ptep_get() in remove_migration_pte()" failed to apply to 6.6-stable tree
Subsystems (3)
[email protected]
maintainerThe patch below does not apply to the 6.6-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.6.y
git checkout FETCH_HEAD
git cherry-pick -x ac1ec50d71b953524100ddc09057ee61a3dfaff3
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<[email protected]>' --in-reply-to '2026090332-posh-plaster-8398@gregkh' --subject-prefix 'PATCH 6.6.y' 'HEAD^..'
Possible dependencies:
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From ac1ec50d71b953524100ddc09057ee61a3dfaff3 Mon Sep 17 00:00:00 2001
From: Dev Jain <[email protected]>
Date: Fri, 3 Jul 2026 11:41:57 +0000
Subject: [PATCH] mm/migrate: use huge_ptep_get() in remove_migration_pte()
remove_migration_pte() converts migration entries back to present PTEs after folio migration completes. For hugetlb folios, 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.
Use huge_ptep_get() to dereference a huge pte pointer.
mm/migrate.c +5 -1
@@ -372,7 +372,11 @@ static bool remove_migration_pte(struct folio *folio, continue; }#endif - old_pte =ptep_get (pvmw.pte); +if (folio_test_hugetlb (folio)) + old_pte =huge_ptep_get (vma->vm_mm, pvmw.address, + pvmw.pte); +else + old_pte =ptep_get (pvmw.pte);if (rmap_walk_arg->map_unused_to_zeropage &&try_to_map_unused_to_zeropage (&pvmw, folio, old_pte, idx))continue ;
Sasha Levin
maintainerPATCH 1/2 mm/rmap: integrate PMD-mapped folio splitting into pagewalk loop
From: Lance Yang <[email protected]>
[ Upstream commit 29e847d2ade3cdff36afe095fdbeb9b5f71a197a ]
In preparation for supporting try_to_unmap_one() to unmap PMD-mapped folios, start the pagewalk first, then call split_huge_pmd_address() to split the folio.
Stable-dependency-note: Drop the unrelated PMD split and provide the migration-walk/API compatibility required by the target
[ sashal: Reduced backport -- upstream 29e847d2ade3c touches 4 file(s), this
backport carries 21. Not backported here:
include/linux/huge_mm.h
include/linux/rmap.h
mm/huge_memory.c
mm/rmap.c
This note is generated from the file lists only; see the resolution record for the reasoning. ]
Stable-dep-of: ac1ec50d71b9 ("mm/migrate: use huge_ptep_get() in remove_migration_pte()")
--- arch/arm/include/asm/hugetlb-3level.h | 5 +-- arch/arm64/include/asm/hugetlb.h | 3 +- arch/arm64/mm/hugetlbpage.c | 2 +- arch/riscv/include/asm/hugetlb.h | 2 +- arch/riscv/mm/hugetlbpage.c | 2 +- arch/s390/include/asm/hugetlb.h | 4 +-- arch/s390/mm/hugetlbpage.c | 4 +-- fs/hugetlbfs/inode.c | 2 +- fs/proc/task_mmu.c | 4 +-- fs/userfaultfd.c | 2 +- include/asm-generic/hugetlb.h | 3 +- include/linux/swapops.h | 5 +-- mm/damon/vaddr.c | 6 ++-- mm/gup.c | 2 +- mm/hmm.c | 2 +- mm/hugetlb.c | 50 +++++++++++++++------------ mm/memory-failure.c | 2 +- mm/mempolicy.c | 2 +- mm/migrate.c | 33 ++++++++++++++---- mm/mincore.c | 3 +- mm/userfaultfd.c | 3 +- 21 files changed, 86 insertions(+), 55 deletions(-)
arch/arm/include/asm/hugetlb-3level.h +3 -2
@@ -13,12 +13,13 @@/* * If our huge pte is non-zero then mark the valid bit. -* This allows pte_present(huge_ptep_get(ptep)) to return true for non-zero +* This allows pte_present(huge_ptep_get(mm, addr, ptep)) to return true for non-zero * ptes. * (The valid bit is automatically cleared by set_pte_at for PROT_NONE ptes). */ #define __HAVE_ARCH_HUGE_PTEP_GET -static inline pte_t huge_ptep_get (pte_t *ptep) +static inline pte_t huge_ptep_get (struct mm_struct *mm,unsigned long addr, +pte_t *ptep) {pte_t retval = *ptep;if (pte_val (retval))
arch/arm64/include/asm/hugetlb.h +2 -1
@@ -46,7 +46,8 @@ extern pte_t huge_ptep_clear_flush(struct vm_area_struct *vma,extern void huge_pte_clear (struct mm_struct *mm,unsigned long addr,pte_t *ptep,unsigned long sz);#define __HAVE_ARCH_HUGE_PTEP_GET -extern pte_t huge_ptep_get (pte_t *ptep); +extern pte_t huge_ptep_get (struct mm_struct *mm,unsigned long addr, +pte_t *ptep);void __init arm64_hugetlb_cma_reserve (void );
arch/arm64/mm/hugetlbpage.c +1 -1
@@ -141,7 +141,7 @@ static inline int num_contig_ptes(unsigned long size, size_t *pgsize)return contig_ptes; } -pte_t huge_ptep_get (pte_t *ptep) +pte_t huge_ptep_get (struct mm_struct *mm,unsigned long addr,pte_t *ptep) {int ncontig, i;size_t pgsize;
arch/riscv/include/asm/hugetlb.h +1 -1
@@ -45,7 +45,7 @@ int huge_ptep_set_access_flags(struct vm_area_struct *vma, pte_t pte, int dirty);#define __HAVE_ARCH_HUGE_PTEP_GET -pte_t huge_ptep_get (pte_t *ptep); +pte_t huge_ptep_get (struct mm_struct *mm,unsigned long addr,pte_t *ptep);pte_t arch_make_huge_pte (pte_t entry,unsigned int shift,vm_flags_t flags);#define arch_make_huge_pte arch_make_huge_pte
arch/riscv/mm/hugetlbpage.c +1 -1
@@ -3,7 +3,7 @@#include <linux/err.h> #ifdef CONFIG_RISCV_ISA_SVNAPOT -pte_t huge_ptep_get (pte_t *ptep) +pte_t huge_ptep_get (struct mm_struct *mm,unsigned long addr,pte_t *ptep) {unsigned long pte_num;int i;
arch/s390/include/asm/hugetlb.h +2 -2
@@ -19,7 +19,7 @@ void set_huge_pte_at(struct mm_struct *mm, unsigned long addr, pte_t *ptep, pte_t pte, unsigned long sz);void __set_huge_pte_at (struct mm_struct *mm,unsigned long addr,pte_t *ptep,pte_t pte); -pte_t huge_ptep_get (pte_t *ptep); +pte_t huge_ptep_get (struct mm_struct *mm,unsigned long addr,pte_t *ptep);pte_t __huge_ptep_get_and_clear (struct mm_struct *mm,unsigned long addr,pte_t *ptep);
@@ -71,7 +71,7 @@ static inline int huge_ptep_set_access_flags(struct vm_area_struct *vma, unsigned long addr, pte_t *ptep, pte_t pte, int dirty) { - int changed = !pte_same(huge_ptep_get(ptep), pte); + int changed = !pte_same(huge_ptep_get(vma->vm_mm, addr, ptep), pte);if (changed) {__huge_ptep_get_and_clear (vma->vm_mm, addr, ptep);__set_huge_pte_at (vma->vm_mm, addr, ptep, pte);
arch/s390/mm/hugetlbpage.c +2 -2
@@ -169,7 +169,7 @@ void set_huge_pte_at(struct mm_struct *mm, unsigned long addr,__set_huge_pte_at (mm, addr, ptep, pte); } -pte_t huge_ptep_get (pte_t *ptep) +pte_t huge_ptep_get (struct mm_struct *mm,unsigned long addr,pte_t *ptep) {return __rste_to_pte (pte_val (*ptep)); }
@@ -177,7 +177,7 @@ pte_t huge_ptep_get(pte_t *ptep)pte_t __huge_ptep_get_and_clear (struct mm_struct *mm,unsigned long addr,pte_t *ptep) { -pte_t pte =huge_ptep_get (ptep); +pte_t pte =huge_ptep_get (mm, addr, ptep);pmd_t *pmdp = (pmd_t *) ptep;pud_t *pudp = (pud_t *) ptep;
fs/hugetlbfs/inode.c +1 -1
@@ -448,7 +448,7 @@ static bool hugetlb_vma_maps_page(struct vm_area_struct *vma,if (!ptep)return false; - pte =huge_ptep_get (ptep); + pte =huge_ptep_get (vma->vm_mm, addr, ptep);if (huge_pte_none (pte) || !pte_present (pte))return false;
fs/proc/task_mmu.c +2 -2
@@ -1578,7 +1578,7 @@ static int pagemap_hugetlb_range(pte_t *ptep, unsigned long hmask,if (vma->vm_flags &VM_SOFTDIRTY ) flags |=PM_SOFT_DIRTY ; - pte =huge_ptep_get (ptep); + pte =huge_ptep_get (walk->mm, addr, ptep);if (pte_present (pte)) {struct page *page =pte_page (pte);
@@ -1910,7 +1910,7 @@ static int gather_pte_stats(pmd_t *pmd, unsigned long addr,static int gather_hugetlb_stats (pte_t *pte,unsigned long hmask,unsigned long addr,unsigned long end,struct mm_walk *walk) { -pte_t huge_pte =huge_ptep_get (pte); +pte_t huge_pte =huge_ptep_get (walk->mm, addr, pte);struct numa_maps *md;struct page *page;
fs/userfaultfd.c +1 -1
@@ -291,7 +291,7 @@ static inline bool userfaultfd_huge_must_wait(struct userfaultfd_ctx *ctx, goto out; ret = false; - pte =huge_ptep_get (ptep); + pte =huge_ptep_get (vma->vm_mm, vmf->address, ptep);/* * Lockless access: we're in a wait_event so it's ok if it
include/asm-generic/hugetlb.h +2 -1
@@ -144,7 +144,8 @@ static inline int huge_ptep_set_access_flags(struct vm_area_struct *vma,#endif #ifndef __HAVE_ARCH_HUGE_PTEP_GET -static inline pte_t huge_ptep_get (pte_t *ptep) +static inline pte_t huge_ptep_get (struct mm_struct *mm,unsigned long addr, +pte_t *ptep) {return ptep_get (ptep); }
include/linux/swapops.h +3 -2
@@ -334,7 +334,8 @@ static inline bool is_migration_entry_dirty(swp_entry_t entry)extern void migration_entry_wait (struct mm_struct *mm,pmd_t *pmd,unsigned long address); -extern void migration_entry_wait_huge (struct vm_area_struct *vma,pte_t *pte); +extern void migration_entry_wait_huge (struct vm_area_struct *vma, +unsigned long addr,pte_t *pte);#else /* CONFIG_MIGRATION */ static inline swp_entry_t make_readable_migration_entry (pgoff_t offset) {
@@ -359,7 +360,7 @@ static inline int is_migration_entry(swp_entry_t swp)static inline void migration_entry_wait (struct mm_struct *mm,pmd_t *pmd,unsigned long address) { }static inline void migration_entry_wait_huge (struct vm_area_struct *vma, -pte_t *pte) { } +unsigned long addr,pte_t *pte) { }static inline int is_writable_migration_entry (swp_entry_t entry) {return 0 ;
mm/damon/vaddr.c +3 -3
@@ -339,7 +339,7 @@ static void damon_hugetlb_mkold(pte_t *pte, struct mm_struct *mm, struct vm_area_struct *vma, unsigned long addr) { bool referenced = false; -pte_t entry =huge_ptep_get (pte); +pte_t entry =huge_ptep_get (mm, addr, pte);struct folio *folio =pfn_folio (pte_pfn (entry));unsigned long psize =huge_page_size (hstate_vma (vma));
@@ -373,7 +373,7 @@ static int damon_mkold_hugetlb_entry(pte_t *pte, unsigned long hmask,pte_t entry; ptl =huge_pte_lock (h, walk->mm, pte); - entry =huge_ptep_get (pte); + entry =huge_ptep_get (walk->mm, addr, pte);if (!pte_present (entry)) goto out;
@@ -507,7 +507,7 @@ static int damon_young_hugetlb_entry(pte_t *pte, unsigned long hmask,pte_t entry; ptl =huge_pte_lock (h, walk->mm, pte); - entry =huge_ptep_get (pte); + entry =huge_ptep_get (walk->mm, addr, pte);if (!pte_present (entry)) goto out;
mm/gup.c +1 -1
@@ -2812,7 +2812,7 @@ static int gup_hugepte(pte_t *ptep, unsigned long sz, unsigned long addr,if (pte_end < end) end = pte_end; - pte =huge_ptep_get (ptep); + pte =huge_ptep_get (vma->vm_mm, addr, ptep);if (!pte_access_permitted (pte, flags &FOLL_WRITE ))return 0 ;
mm/hmm.c +1 -1
@@ -485,7 +485,7 @@ static int hmm_vma_walk_hugetlb_entry(pte_t *pte, unsigned long hmask,pte_t entry; ptl =huge_pte_lock (hstate_vma (vma), walk->mm, pte); - entry =huge_ptep_get (pte); + entry =huge_ptep_get (walk->mm, addr, pte); i = (start - range->start) >>PAGE_SHIFT ; pfn_req_flags = range->hmm_pfns[i];
mm/hugetlb.c +27 -23
184 lines not on this page · raw message
mm/memory-failure.c +1 -1
@@ -825,7 +825,7 @@ static int hwpoison_hugetlb_range(pte_t *ptep, unsigned long hmask, struct mm_walk *walk) {struct hwpoison_walk *hwp = walk->private; -pte_t pte =huge_ptep_get (ptep); +pte_t pte =huge_ptep_get (walk->mm, addr, ptep);struct hstate *h =hstate_vma (walk->vma); return check_hwpoisoned_entry(pte, addr, huge_page_shift(h),
mm/mempolicy.c +1 -1
@@ -584,7 +584,7 @@ static int queue_folios_hugetlb(pte_t *pte, unsigned long hmask,pte_t entry; ptl =huge_pte_lock (hstate_vma (walk->vma), walk->mm, pte); - entry =huge_ptep_get (pte); + entry =huge_ptep_get (walk->mm, addr, pte);if (!pte_present (entry)) {if (unlikely (is_hugetlb_entry_migration (entry))) qp->nr_failed++;
mm/migrate.c +27 -6
@@ -177,13 +177,27 @@ void putback_movable_pages(struct list_head *l) } } +/* +* This tree predates remapping unused THP subpages to the shared zeropage. +* Retain the newer rmap walk argument shape so fixes to this walk can be +* applied without pulling in that feature. +*/ +struct rmap_walk_arg { +struct folio *folio; +bool map_unused_to_zeropage; +}; + +#define try_to_map_unused_to_zeropage (pvmw, folio, old_pte, idx) false +/* * Restore a potential migration pte to a working pte entry */ static bool remove_migration_pte (struct folio *folio, -struct vm_area_struct *vma,unsigned long addr,void *old) +struct vm_area_struct *vma,unsigned long addr,void *arg) { -DEFINE_FOLIO_VMA_WALK (pvmw, old, vma, addr,PVMW_SYNC |PVMW_MIGRATION ); +struct rmap_walk_arg *rmap_walk_arg = arg; +DEFINE_FOLIO_VMA_WALK (pvmw, rmap_walk_arg->folio, vma, addr, +PVMW_SYNC |PVMW_MIGRATION );while (page_vma_mapped_walk (&pvmw)) {rmap_t rmap_flags =RMAP_NONE ;
@@ -207,10 +221,13 @@ static bool remove_migration_pte(struct folio *folio, continue; }#endif + old_pte =ptep_get (pvmw.pte); +if (rmap_walk_arg->map_unused_to_zeropage && +try_to_map_unused_to_zeropage (&pvmw, folio, old_pte, idx)) +continue ;folio_get (folio); pte =mk_pte (new,READ_ONCE (vma->vm_page_prot)); - old_pte =ptep_get (pvmw.pte);if (pte_swp_soft_dirty (old_pte)) pte =pte_mksoft_dirty (pte);
@@ -284,9 +301,12 @@ static bool remove_migration_pte(struct folio *folio,*/ void remove_migration_ptes (struct folio *src,struct folio *dst,bool locked) { +struct rmap_walk_arg rmap_walk_arg = { + .folio = src, + };struct rmap_walk_control rwc = { .rmap_one = remove_migration_pte, - .arg = src, + .arg = &rmap_walk_arg, };if (locked)
@@ -335,14 +355,15 @@ void migration_entry_wait(struct mm_struct *mm, pmd_t *pmd,* * This function will release the vma lock before returning. */ -void migration_entry_wait_huge (struct vm_area_struct *vma,pte_t *ptep) +void migration_entry_wait_huge (struct vm_area_struct *vma,unsigned long addr, +pte_t *ptep) {spinlock_t *ptl =huge_pte_lockptr (hstate_vma (vma), vma->vm_mm, ptep);pte_t pte;hugetlb_vma_assert_locked (vma);spin_lock (ptl); - pte =huge_ptep_get (ptep); + pte =huge_ptep_get (vma->vm_mm, addr, ptep);if (unlikely (!is_hugetlb_entry_migration (pte))) {spin_unlock (ptl);
mm/mincore.c +2 -1
@@ -33,7 +33,8 @@ static int mincore_hugetlb(pte_t *pte, unsigned long hmask, unsigned long addr,* Hugepages under user process are always in RAM and never * swapped out, but theoretically it needs to be checked. */ - present = pte && !huge_pte_none_mostly (huge_ptep_get (pte)); + present = pte && + !huge_pte_none_mostly (huge_ptep_get (walk->mm, addr, pte));for (; addr != end; vec++, addr +=PAGE_SIZE ) *vec = present; walk->private = vec;
mm/userfaultfd.c +2 -1
@@ -482,7 +482,8 @@ static __always_inline ssize_t mfill_atomic_hugetlb( }if (!uffd_flags_mode_is (flags,MFILL_ATOMIC_CONTINUE ) && - !huge_pte_none_mostly (huge_ptep_get (dst_pte))) { + !huge_pte_none_mostly (huge_ptep_get (dst_mm, dst_addr, + dst_pte))) { err = -EEXIST ;hugetlb_vma_unlock_read (dst_vma);mutex_unlock (&hugetlb_fault_mutex_table[hash]);
Signature · 1 line
2.53.0
Sasha Levin
maintainerPATCH 2/2 mm/migrate: use huge_ptep_get() in remove_migration_pte()
From: Dev Jain <[email protected]>
[ Upstream commit ac1ec50d71b953524100ddc09057ee61a3dfaff3 ]
remove_migration_pte() converts migration entries back to present PTEs after folio migration completes. For hugetlb folios, 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.
Use huge_ptep_get() to dereference a huge pte pointer.
--- mm/migrate.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
mm/migrate.c +5 -1
@@ -221,7 +221,11 @@ static bool remove_migration_pte(struct folio *folio, continue; }#endif - old_pte =ptep_get (pvmw.pte); +if (folio_test_hugetlb (folio)) + old_pte =huge_ptep_get (vma->vm_mm, pvmw.address, + pvmw.pte); +else + old_pte =ptep_get (pvmw.pte);if (rmap_walk_arg->map_unused_to_zeropage &&try_to_map_unused_to_zeropage (&pvmw, folio, old_pte, idx))continue ;
Signature · 1 line
2.53.0