FAILED: patch "[PATCH] mm/page_vma_mapped: use huge_ptep_get() for hugetlb" failed to apply to 5.10-stable tree
Subsystems (3)
[email protected]
maintainerThe patch below does not apply to the 5.10-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-5.10.y
git checkout FETCH_HEAD
git cherry-pick -x e87df0d5d6962bde50f55f6d02b779daa394f894
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<[email protected]>' --in-reply-to '2026090327-numerous-array-4fc1@gregkh' --subject-prefix 'PATCH 5.10.y' 'HEAD^..'
Possible dependencies:
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From e87df0d5d6962bde50f55f6d02b779daa394f894 Mon Sep 17 00:00:00 2001
From: Dev Jain <[email protected]>
Date: Fri, 3 Jul 2026 11:41:58 +0000
Subject: [PATCH] mm/page_vma_mapped: use huge_ptep_get() for hugetlb
check_pte() is the final validation step in page_vma_mapped_walk(). It reads pvmw->pte with ptep_get() to decide whether the entry maps the PFN range being walked. For hugetlb VMAs, that pointer refers to a hugetlb entry.
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/page_vma_mapped.c +7 -1
@@ -107,7 +107,13 @@ static bool map_pte(struct page_vma_mapped_walk *pvmw, pmd_t *pmdvalp,static bool check_pte (struct page_vma_mapped_walk *pvmw,unsigned long pte_nr) {unsigned long pfn; -pte_t ptent =ptep_get (pvmw->pte); +pte_t ptent; + +if (is_vm_hugetlb_page (pvmw->vma)) + ptent =huge_ptep_get (pvmw->vma->vm_mm, pvmw->address, + pvmw->pte); +else + ptent =ptep_get (pvmw->pte);if (pvmw->flags &PVMW_MIGRATION ) {const softleaf_t entry =softleaf_from_pte (ptent);
Sasha Levin
maintainerPATCH 1/2 mm: provide mm_struct and address to huge_ptep_get()
From: Christophe Leroy <[email protected]>
[ Upstream commit e6c0c03245b14d6c205814aee67128257d0bea84 ]
On powerpc 8xx huge_ptep_get() will need to know whether the given ptep is a PTE entry or a PMD entry. This cannot be known with the PMD entry itself because there is no easy way to know it from the content of the entry.
So huge_ptep_get() will need to know either the size of the page or get the pmd.
In order to be consistent with huge_ptep_get_and_clear(), give mm and address to huge_ptep_get().
[ sashal: Reduced backport -- upstream e6c0c03245b14 touches 21 file(s), this
backport carries 14. Not backported here:
arch/arm64/include/asm/hugetlb.h arch/riscv/include/asm/hugetlb.h
arch/riscv/mm/hugetlbpage.c
fs/hugetlbfs/inode.c
include/linux/swapops.h
mm/damon/vaddr.c
mm/memory-failure.c
mm/migrate.c
This note is generated from the file lists only; see the resolution record for the reasoning. ]
Stable-dep-of: e87df0d5d696 ("mm/page_vma_mapped: use huge_ptep_get() for hugetlb")
--- arch/arm/include/asm/hugetlb-3level.h | 5 ++-- arch/arm64/mm/hugetlbpage.c | 15 ++++++---- arch/s390/include/asm/hugetlb.h | 4 +-- arch/s390/mm/hugetlbpage.c | 4 +-- fs/proc/task_mmu.c | 4 +-- fs/userfaultfd.c | 2 +- include/asm-generic/hugetlb.h | 3 +- mm/gup.c | 2 +- mm/hmm.c | 2 +- mm/hugetlb.c | 40 ++++++++++++++------------- mm/mempolicy.c | 2 +- mm/mincore.c | 3 +- mm/page_vma_mapped.c | 13 +++++---- mm/userfaultfd.c | 2 +- 14 files changed, 55 insertions(+), 46 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/mm/hugetlbpage.c +9 -6
@@ -159,7 +159,7 @@ static pte_t get_clear_flush(struct mm_struct *mm, unsigned long pgsize, unsigned long ncontig) { -pte_t orig_pte =huge_ptep_get (ptep); +pte_t orig_pte =huge_ptep_get (mm, addr, ptep);bool valid =pte_valid (orig_pte);unsigned long i, saddr = addr;
@@ -373,7 +373,7 @@ pte_t huge_ptep_get_and_clear(struct mm_struct *mm, {int ncontig;size_t pgsize; -pte_t orig_pte =huge_ptep_get (ptep); +pte_t orig_pte =huge_ptep_get (mm, addr, ptep);if (!pte_cont (orig_pte))return ptep_get_and_clear (mm, addr, ptep);
@@ -392,15 +392,17 @@ pte_t huge_ptep_get_and_clear(struct mm_struct *mm,* all the contiguous ptes we need to check whether or not there is a * discrepancy between dirty or young. */ -static int __cont_access_flags_changed (pte_t *ptep,pte_t pte,int ncontig) +static int __cont_access_flags_changed (struct mm_struct *mm, +unsigned long addr,pte_t *ptep, +pte_t pte,int ncontig) {int i; -if (pte_write (pte) !=pte_write (huge_ptep_get (ptep))) +if (pte_write (pte) !=pte_write (huge_ptep_get (mm, addr, ptep)))return 1 ;for (i =0 ; i < ncontig; i++) { -pte_t orig_pte =huge_ptep_get (ptep + i); +pte_t orig_pte =huge_ptep_get (mm, addr, ptep + i);if (pte_dirty (pte) !=pte_dirty (orig_pte))return 1 ;
@@ -428,7 +430,8 @@ int huge_ptep_set_access_flags(struct vm_area_struct *vma, ncontig =find_num_contig (vma->vm_mm, addr, ptep, &pgsize); dpfn = pgsize >>PAGE_SHIFT ; -if (!__cont_access_flags_changed (ptep, pte, ncontig)) +if (!__cont_access_flags_changed (vma->vm_mm, addr, ptep, pte, + ncontig))return 0 ; orig_pte =get_clear_flush (vma->vm_mm, addr, ptep, pgsize, ncontig);
arch/s390/include/asm/hugetlb.h +2 -2
@@ -17,7 +17,7 @@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);
@@ -62,7 +62,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
@@ -170,7 +170,7 @@ void set_huge_pte_at(struct mm_struct *mm, unsigned long addr,pte_val (*ptep) = rste; } -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)); }
@@ -178,7 +178,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/proc/task_mmu.c +2 -2
@@ -1529,7 +1529,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);
@@ -1847,7 +1847,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
@@ -243,7 +243,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 (mm, address, ptep);/* * Lockless access: we're in a wait_event so it's ok if it
include/asm-generic/hugetlb.h +2 -1
@@ -120,7 +120,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); }
mm/gup.c +1 -1
@@ -2371,7 +2371,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 (current->mm, addr, ptep);if (!pte_access_permitted (pte, flags &FOLL_WRITE ))return 0 ;
mm/hmm.c +1 -1
@@ -484,7 +484,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, start, pte); i = (start - range->start) >>PAGE_SHIFT ; pfn_req_flags = range->hmm_pfns[i];
mm/hugetlb.c +21 -19
@@ -3793,7 +3793,8 @@ static void set_huge_ptep_writable(struct vm_area_struct *vma, {pte_t entry; - entry =huge_pte_mkwrite (huge_pte_mkdirty (huge_ptep_get (ptep))); + entry =huge_pte_mkwrite (huge_pte_mkdirty ( +huge_ptep_get (vma->vm_mm, address, ptep)));if (huge_ptep_set_access_flags (vma, address, ptep, entry,1 ))update_mmu_cache (vma, address, ptep); }
@@ -3874,7 +3875,7 @@ int copy_hugetlb_page_range(struct mm_struct *dst, struct mm_struct *src, dst_ptl =huge_pte_lock (h, dst, dst_pte); src_ptl =huge_pte_lockptr (h, src, src_pte);spin_lock_nested (src_ptl,SINGLE_DEPTH_NESTING ); - entry =huge_ptep_get (src_pte); + entry =huge_ptep_get (src, addr, src_pte);if (huge_pte_none (entry)) {/* * Skip if src entry none.
@@ -3906,7 +3907,7 @@ int copy_hugetlb_page_range(struct mm_struct *dst, struct mm_struct *src,*/ huge_ptep_set_wrprotect (src, addr, src_pte); } - entry =huge_ptep_get (src_pte); + entry =huge_ptep_get (src, addr, src_pte); ptepage =pte_page (entry);get_page (ptepage);page_dup_rmap (ptepage, true);
@@ -3969,7 +3970,7 @@ void __unmap_hugepage_range(struct mmu_gather *tlb, struct vm_area_struct *vma,continue ; } - pte =huge_ptep_get (ptep); + pte =huge_ptep_get (mm, address, ptep);if (huge_pte_none (pte)) {spin_unlock (ptl);continue ;
@@ -4143,7 +4144,7 @@ static vm_fault_t hugetlb_cow(struct mm_struct *mm, struct vm_area_struct *vma,unsigned long haddr = address &huge_page_mask (h);struct mmu_notifier_range range; - pte =huge_ptep_get (ptep); + pte =huge_ptep_get (mm, address, ptep); old_page =pte_page (pte); retry_avoidcopy:
@@ -4213,7 +4214,7 @@ static vm_fault_t hugetlb_cow(struct mm_struct *mm, struct vm_area_struct *vma,spin_lock (ptl); ptep =huge_pte_offset (mm, haddr,huge_page_size (h));if (likely (ptep && -pte_same (huge_ptep_get (ptep), pte))) +pte_same (huge_ptep_get (mm, haddr, ptep), pte))) goto retry_avoidcopy;/* * race occurs while re-acquiring page table
@@ -4249,7 +4250,8 @@ static vm_fault_t hugetlb_cow(struct mm_struct *mm, struct vm_area_struct *vma,*/ spin_lock (ptl); ptep =huge_pte_offset (mm, haddr,huge_page_size (h)); -if (likely (ptep &&pte_same (huge_ptep_get (ptep), pte))) { +if (likely (ptep && +pte_same (huge_ptep_get (mm, haddr, ptep), pte))) {ClearPagePrivate (new_page);/* Break COW */
@@ -4413,7 +4415,7 @@ static vm_fault_t hugetlb_no_page(struct mm_struct *mm,* sure there really is no pte entry. */ ptl =huge_pte_lock (h, mm, ptep); -if (!huge_pte_none (huge_ptep_get (ptep))) { +if (!huge_pte_none (huge_ptep_get (mm, haddr, ptep))) { ret =0 ;spin_unlock (ptl); goto out;
@@ -4472,7 +4474,7 @@ static vm_fault_t hugetlb_no_page(struct mm_struct *mm, ptl =huge_pte_lock (h, mm, ptep); ret =0 ; -if (!huge_pte_none (huge_ptep_get (ptep))) +if (!huge_pte_none (huge_ptep_get (mm, haddr, ptep))) goto backout;if (anon_rmap) {
@@ -4561,7 +4563,7 @@ vm_fault_t hugetlb_fault(struct mm_struct *mm, struct vm_area_struct *vma,* OK as we are only making decisions based on content and * not actually modifying content here. */ - entry =huge_ptep_get (ptep); + entry =huge_ptep_get (mm, haddr, ptep);if (unlikely (is_hugetlb_entry_migration (entry))) {migration_entry_wait_huge (vma, mm, ptep);return 0 ;
@@ -4598,7 +4600,7 @@ vm_fault_t hugetlb_fault(struct mm_struct *mm, struct vm_area_struct *vma, hash =hugetlb_fault_mutex_hash (mapping, idx);mutex_lock (&hugetlb_fault_mutex_table[hash]); - entry =huge_ptep_get (ptep); + entry =huge_ptep_get (mm, haddr, ptep);if (huge_pte_none (entry))/* * hugetlb_no_page will drop vma lock and hugetlb fault
@@ -4642,7 +4644,7 @@ vm_fault_t hugetlb_fault(struct mm_struct *mm, struct vm_area_struct *vma, ptl =huge_pte_lock (h, mm, ptep);/* Check for a racing update before calling hugetlb_cow */ -if (unlikely (!pte_same (entry,huge_ptep_get (ptep)))) +if (unlikely (!pte_same (entry,huge_ptep_get (mm, haddr, ptep)))) goto out_ptl;/*
@@ -4798,7 +4800,7 @@ int hugetlb_mcopy_atomic_pte(struct mm_struct *dst_mm, goto out_release_unlock; ret = -EEXIST ; -if (!huge_pte_none (huge_ptep_get (dst_pte))) +if (!huge_pte_none (huge_ptep_get (dst_mm, dst_addr, dst_pte))) goto out_release_unlock;if (vm_shared) {
@@ -4875,7 +4877,7 @@ long follow_hugetlb_page(struct mm_struct *mm, struct vm_area_struct *vma, huge_page_size(h));if (pte) ptl =huge_pte_lock (h, mm, pte); - absent = !pte ||huge_pte_none (huge_ptep_get (pte)); + absent = !pte ||huge_pte_none (huge_ptep_get (mm, vaddr, pte));/* * When coredumping, it suits get_dump_page if we just return
@@ -4902,9 +4904,9 @@ long follow_hugetlb_page(struct mm_struct *mm, struct vm_area_struct *vma,* both cases, and because we can't follow correct pages * directly from any kind of swap entries. */ -if (absent ||is_swap_pte (huge_ptep_get (pte)) || +if (absent ||is_swap_pte (huge_ptep_get (mm, vaddr, pte)) || ((flags &FOLL_WRITE ) && - !huge_pte_write (huge_ptep_get (pte)))) { + !huge_pte_write (huge_ptep_get (mm, vaddr, pte)))) {vm_fault_t ret;unsigned int fault_flags =0 ;
@@ -4951,7 +4953,7 @@ long follow_hugetlb_page(struct mm_struct *mm, struct vm_area_struct *vma, } pfn_offset = (vaddr & ~huge_page_mask (h)) >>PAGE_SHIFT ; - page =pte_page (huge_ptep_get (pte)); + page =pte_page (huge_ptep_get (mm, vaddr, pte));/* * If subpage information not requested, update counters
@@ -5062,7 +5064,7 @@ unsigned long hugetlb_change_protection(struct vm_area_struct *vma,spin_unlock (ptl);continue ; } - pte =huge_ptep_get (ptep); + pte =huge_ptep_get (mm, address, ptep);if (unlikely (is_hugetlb_entry_hwpoisoned (pte))) {spin_unlock (ptl);continue ;
@@ -5635,7 +5637,7 @@ follow_huge_pmd_pte(struct vm_area_struct *vma, unsigned long address, int flagsreturn NULL ; ptl =huge_pte_lock (h, mm, ptep); - pte =huge_ptep_get (ptep); + pte =huge_ptep_get (mm, address, ptep);if (pte_present (pte)) { page =pte_page (pte) + ((address & ~huge_page_mask (h)) >>PAGE_SHIFT );
mm/mempolicy.c +1 -1
@@ -593,7 +593,7 @@ static int queue_pages_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)) goto unlock; page =pte_page (entry);
mm/mincore.c +2 -1
@@ -32,7 +32,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 (huge_ptep_get (pte)); + present = pte && + !huge_pte_none (huge_ptep_get (walk->mm, addr, pte));for (; addr != end; vec++, addr +=PAGE_SIZE ) *vec = present; walk->private = vec;
mm/page_vma_mapped.c +7 -6
@@ -85,31 +85,32 @@ static inline bool pfn_is_match(struct page *page, unsigned long pfn)static bool check_pte (struct page_vma_mapped_walk *pvmw) {unsigned long pfn; +pte_t ptent =ptep_get (pvmw->pte);if (pvmw->flags &PVMW_MIGRATION ) {swp_entry_t entry; -if (!is_swap_pte (*pvmw->pte)) +if (!is_swap_pte (ptent))return false; - entry =pte_to_swp_entry (*pvmw->pte); + entry =pte_to_swp_entry (ptent);if (!is_migration_entry (entry))return false; pfn =migration_entry_to_pfn (entry); - }else if (is_swap_pte (*pvmw->pte)) { + }else if (is_swap_pte (ptent)) {swp_entry_t entry;/* Handle un-addressable ZONE_DEVICE memory */ - entry =pte_to_swp_entry (*pvmw->pte); + entry =pte_to_swp_entry (ptent);if (!is_device_private_entry (entry))return false; pfn =device_private_entry_to_pfn (entry); }else { -if (!pte_present (*pvmw->pte)) +if (!pte_present (ptent))return false; - pfn =pte_pfn (*pvmw->pte); + pfn =pte_pfn (ptent); }return pfn_is_match (pvmw->page, pfn);
mm/userfaultfd.c +1 -1
@@ -301,7 +301,7 @@ static __always_inline ssize_t __mcopy_atomic_hugetlb(struct mm_struct *dst_mm, } err = -EEXIST ; - dst_pteval =huge_ptep_get (dst_pte); + dst_pteval =huge_ptep_get (dst_mm, dst_addr, dst_pte);if (!huge_pte_none (dst_pteval)) {mutex_unlock (&hugetlb_fault_mutex_table[hash]);i_mmap_unlock_read (mapping);
Signature · 1 line
2.53.0
Sasha Levin
maintainerPATCH 2/2 mm/page_vma_mapped: use huge_ptep_get() for hugetlb
From: Dev Jain <[email protected]>
[ Upstream commit e87df0d5d6962bde50f55f6d02b779daa394f894 ]
check_pte() is the final validation step in page_vma_mapped_walk(). It reads pvmw->pte with ptep_get() to decide whether the entry maps the PFN range being walked. For hugetlb VMAs, that pointer refers to a hugetlb entry.
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/page_vma_mapped.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)
mm/page_vma_mapped.c +7 -1
@@ -85,7 +85,13 @@ static inline bool pfn_is_match(struct page *page, unsigned long pfn)static bool check_pte (struct page_vma_mapped_walk *pvmw) {unsigned long pfn; -pte_t ptent =ptep_get (pvmw->pte); +pte_t ptent; + +if (is_vm_hugetlb_page (pvmw->vma)) + ptent =huge_ptep_get (pvmw->vma->vm_mm, pvmw->address, + pvmw->pte); +else + ptent =ptep_get (pvmw->pte);if (pvmw->flags &PVMW_MIGRATION ) {swp_entry_t entry;
Signature · 1 line
2.53.0