FAILED: patch "[PATCH] mm/page_vma_mapped: use huge_ptep_get() for hugetlb" failed to apply to 6.1-stable tree
Subsystems (3)
[email protected]
maintainerThe patch below does not apply to the 6.1-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.1.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 '2026090326-freestyle-gratify-7686@gregkh' --subject-prefix 'PATCH 6.1.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/5 hugetlb: convert hugetlb_no_page() to use struct vm_fault
From: "Vishal Moola (Oracle)" <[email protected]>
[ Upstream commit 7b6ec181de372a243e3ef285ae1a48f32d5c71ba ]
hugetlb_no_page() can use the struct vm_fault passed in from hugetlb_fault(). This alleviates the stack by consolidating 7 variables into a single struct.
Stable-dep-of: e87df0d5d696 ("mm/page_vma_mapped: use huge_ptep_get() for hugetlb")
--- mm/hugetlb.c | 176 +++++++++++++++++++++---------------------- mm/page_vma_mapped.c | 13 ++-- 2 files changed, 94 insertions(+), 95 deletions(-)
mm/hugetlb.c +87 -89
@@ -5829,22 +5829,19 @@ static bool hugetlb_pte_stable(struct hstate *h, struct mm_struct *mm,return same; } -static vm_fault_t hugetlb_no_page (struct mm_struct *mm, -struct vm_area_struct *vma, -struct address_space *mapping,pgoff_t idx, -unsigned long address,pte_t *ptep, -pte_t old_pte,unsigned int flags) +static vm_fault_t hugetlb_no_page (struct address_space *mapping, +struct vm_fault *vmf) { +struct vm_area_struct *vma = vmf->vma; +struct mm_struct *mm = vma->vm_mm;struct hstate *h =hstate_vma (vma);vm_fault_t ret =VM_FAULT_SIGBUS ;int anon_rmap =0 ;unsigned long size;struct page *page;pte_t new_pte; -spinlock_t *ptl; -unsigned long haddr = address &huge_page_mask (h);bool new_page, new_pagecache_page = false; -u32 hash =hugetlb_fault_mutex_hash (mapping, idx); +u32 hash =hugetlb_fault_mutex_hash (mapping, vmf->pgoff);/* * Currently, we are forced to kill the process in the event the
@@ -5863,10 +5860,10 @@ static vm_fault_t hugetlb_no_page(struct mm_struct *mm,* before we get page_table_lock. */ new_page = false; - page =find_lock_page (mapping, idx); + page =find_lock_page (mapping, vmf->pgoff);if (!page) { size =i_size_read (mapping->host) >>huge_page_shift (h); -if (idx >= size) +if (vmf->pgoff >= size) goto out;/* Check for page in userfault range */ if (userfaultfd_missing (vma)) {
@@ -5887,17 +5884,18 @@ static vm_fault_t hugetlb_no_page(struct mm_struct *mm,* never happen on the page after UFFDIO_COPY has * correctly installed the page and returned. */ -if (!hugetlb_pte_stable (h, mm, ptep, old_pte)) { +if (!hugetlb_pte_stable (h, mm, vmf->pte, vmf->orig_pte)) { ret =0 ; goto out; } -return hugetlb_handle_userfault (vma, mapping, idx, flags, - haddr, address, +return hugetlb_handle_userfault (vma, mapping, vmf->pgoff, + vmf->flags, vmf->address, + vmf->real_address,VM_UFFD_MISSING ); } - page =alloc_huge_page (vma, haddr,0 ); + page =alloc_huge_page (vma, vmf->address,0 );if (IS_ERR (page)) {/* * Returning error will result in faulting task being
@@ -5911,18 +5909,19 @@ static vm_fault_t hugetlb_no_page(struct mm_struct *mm,* here. Before returning error, get ptl and make * sure there really is no pte entry. */ -if (hugetlb_pte_stable (h, mm, ptep, old_pte)) +if (hugetlb_pte_stable (h, mm, vmf->pte, vmf->orig_pte)) ret =vmf_error (PTR_ERR (page));else ret =0 ; goto out; } -clear_huge_page (page, address,pages_per_huge_page (h)); +clear_huge_page (page, vmf->real_address,pages_per_huge_page (h));__SetPageUptodate (page); new_page = true;if (vma->vm_flags &VM_MAYSHARE ) { -int err =hugetlb_add_to_page_cache (page, mapping, idx); +int err =hugetlb_add_to_page_cache (page, mapping, + vmf->pgoff);if (err) {/* * err can't be -EEXIST which implies someone
@@ -5931,7 +5930,8 @@ static vm_fault_t hugetlb_no_page(struct mm_struct *mm,* to the page cache. So it's safe to call * restore_reserve_on_error() here. */ -restore_reserve_on_error (h, vma, haddr, page); +restore_reserve_on_error (h, vma, vmf->address, + page);put_page (page); goto out; }
@@ -5961,12 +5961,13 @@ static vm_fault_t hugetlb_no_page(struct mm_struct *mm,unlock_page (page);put_page (page);/* See comment in userfaultfd_missing() block above */ -if (!hugetlb_pte_stable (h, mm, ptep, old_pte)) { +if (!hugetlb_pte_stable (h, mm, vmf->pte, vmf->orig_pte)) { ret =0 ; goto out; } -return hugetlb_handle_userfault (vma, mapping, idx, flags, - haddr, address, +return hugetlb_handle_userfault (vma, mapping, vmf->pgoff, + vmf->flags, vmf->address, + vmf->real_address,VM_UFFD_MINOR ); } }
@@ -5977,24 +5978,24 @@ static vm_fault_t hugetlb_no_page(struct mm_struct *mm,* any allocations necessary to record that reservation occur outside * the spinlock. */ -if ((flags &FAULT_FLAG_WRITE ) && !(vma->vm_flags &VM_SHARED )) { -if (vma_needs_reservation (h, vma, haddr) <0 ) { +if ((vmf->flags &FAULT_FLAG_WRITE ) && !(vma->vm_flags &VM_SHARED )) { +if (vma_needs_reservation (h, vma, vmf->address) <0 ) { ret =VM_FAULT_OOM ; goto backout_unlocked; }/* Just decrements count, does not deallocate */ -vma_end_reservation (h, vma, haddr); +vma_end_reservation (h, vma, vmf->address); } - ptl =huge_pte_lock (h, mm, ptep); + vmf->ptl =huge_pte_lock (h, mm, vmf->pte); ret =0 ;/* If pte changed from under us, retry */ -if (!pte_same (huge_ptep_get (ptep), old_pte)) +if (!pte_same (huge_ptep_get (vmf->pte), vmf->orig_pte)) goto backout;if (anon_rmap) {ClearHPageRestoreReserve (page); -hugepage_add_new_anon_rmap (page, vma, haddr); +hugepage_add_new_anon_rmap (page, vma, vmf->address); }else page_dup_file_rmap (page, true); new_pte = make_huge_pte(vma, page, ((vma->vm_flags & VM_WRITE)
@@ -6003,17 +6004,18 @@ static vm_fault_t hugetlb_no_page(struct mm_struct *mm,* If this pte was previously wr-protected, keep it wr-protected even * if populated. */ -if (unlikely (pte_marker_uffd_wp (old_pte))) +if (unlikely (pte_marker_uffd_wp (vmf->orig_pte))) new_pte =huge_pte_wrprotect (huge_pte_mkuffd_wp (new_pte)); -set_huge_pte_at (mm, haddr, ptep, new_pte); +set_huge_pte_at (mm, vmf->address, vmf->pte, new_pte);hugetlb_count_add (pages_per_huge_page (h), mm); -if ((flags &FAULT_FLAG_WRITE ) && !(vma->vm_flags &VM_SHARED )) { +if ((vmf->flags &FAULT_FLAG_WRITE ) && !(vma->vm_flags &VM_SHARED )) {/* Optimization, do the COW without a second fault */ - ret =hugetlb_wp (mm, vma, address, ptep, flags, page, ptl); + ret =hugetlb_wp (mm, vma, vmf->real_address, vmf->pte, + vmf->flags, page, vmf->ptl); } -spin_unlock (ptl); +spin_unlock (vmf->ptl);/* * Only set HPageMigratable in newly allocated pages. Existing pages
@@ -6030,10 +6032,10 @@ static vm_fault_t hugetlb_no_page(struct mm_struct *mm,return ret; backout: -spin_unlock (ptl); +spin_unlock (vmf->ptl); backout_unlocked:if (new_page && !new_pagecache_page) -restore_reserve_on_error (h, vma, haddr, page); +restore_reserve_on_error (h, vma, vmf->address, page);unlock_page (page);put_page (page);
@@ -6067,30 +6069,34 @@ u32 hugetlb_fault_mutex_hash(struct address_space *mapping, pgoff_t idx)vm_fault_t hugetlb_fault (struct mm_struct *mm,struct vm_area_struct *vma,unsigned long address,unsigned int flags) { -pte_t *ptep, entry; -spinlock_t *ptl;vm_fault_t ret;u32 hash; -pgoff_t idx;struct page *page =NULL ;struct page *pagecache_page =NULL ;struct hstate *h =hstate_vma (vma);struct address_space *mapping;int need_wait_lock =0 ; -unsigned long haddr = address &huge_page_mask (h); +struct vm_fault vmf = { + .vma = vma, + .address = address &huge_page_mask (h), + .real_address = address, + .flags = flags, + .pgoff =vma_hugecache_offset (h, vma, + address &huge_page_mask (h)), + }; - ptep =huge_pte_offset (mm, haddr,huge_page_size (h)); -if (ptep) { + vmf.pte =huge_pte_offset (mm, vmf.address,huge_page_size (h)); +if (vmf.pte) {/* -* Since we hold no locks, ptep could be stale. That is +* Since we hold no locks, vmf.pte could be stale. That is * OK as we are only making decisions based on content and * not actually modifying content here. */ - entry =huge_ptep_get (ptep); -if (unlikely (is_hugetlb_entry_migration (entry))) { -migration_entry_wait_huge (vma, ptep); + vmf.orig_pte =huge_ptep_get (vmf.pte); +if (unlikely (is_hugetlb_entry_migration (vmf.orig_pte))) { +migration_entry_wait_huge (vma, vmf.pte);return 0 ; - }else if (unlikely (is_hugetlb_entry_hwpoisoned (entry))) + }else if (unlikely (is_hugetlb_entry_hwpoisoned (vmf.orig_pte)))return VM_FAULT_HWPOISON_LARGE |VM_FAULT_SET_HINDEX (hstate_index (h)); }
@@ -6101,47 +6107,45 @@ vm_fault_t hugetlb_fault(struct mm_struct *mm, struct vm_area_struct *vma,* the same page in the page cache. */ mapping = vma->vm_file->f_mapping; - idx =vma_hugecache_offset (h, vma, haddr); - hash =hugetlb_fault_mutex_hash (mapping, idx); + hash =hugetlb_fault_mutex_hash (mapping, vmf.pgoff);mutex_lock (&hugetlb_fault_mutex_table[hash]);/* * Acquire vma lock before calling huge_pte_alloc and hold -* until finished with ptep. This prevents huge_pmd_unshare from -* being called elsewhere and making the ptep no longer valid. +* until finished with vmf.pte. This prevents huge_pmd_unshare from +* being called elsewhere and making the vmf.pte no longer valid. * -* ptep could have already be assigned via huge_pte_offset. That +* vmf.pte could have already be assigned via huge_pte_offset. That * is OK, as huge_pte_alloc will return the same value unless * something has changed. */ hugetlb_vma_lock_read (vma); - ptep =huge_pte_alloc (mm, vma, haddr,huge_page_size (h)); -if (!ptep) { + vmf.pte =huge_pte_alloc (mm, vma, vmf.address,huge_page_size (h)); +if (!vmf.pte) {hugetlb_vma_unlock_read (vma);mutex_unlock (&hugetlb_fault_mutex_table[hash]);return VM_FAULT_OOM ; } - entry =huge_ptep_get (ptep); + vmf.orig_pte =huge_ptep_get (vmf.pte);/* PTE markers should be handled the same way as none pte */ -if (huge_pte_none_mostly (entry)) +if (huge_pte_none_mostly (vmf.orig_pte))/* * hugetlb_no_page will drop vma lock and hugetlb fault * mutex internally, which make us return immediately. */ -return hugetlb_no_page (mm, vma, mapping, idx, address, ptep, - entry, flags); +return hugetlb_no_page (mapping, &vmf); ret =0 ;/* -* entry could be a migration/hwpoison entry at this point, so this -* check prevents the kernel from going below assuming that we have -* an active hugepage in pagecache. This goto expects the 2nd page -* fault, and is_hugetlb_entry_(migration|hwpoisoned) check will -* properly handle it. +* vmf.orig_pte could be a migration/hwpoison entry at this point, so +* this check prevents the kernel from going below assuming that we +* have an active hugepage in pagecache. This goto expects the 2nd page +* fault, and is_hugetlb_entry_(migration|hwpoisoned) check will properly +* handle it. */ -if (!pte_present (entry)) +if (!pte_present (vmf.orig_pte)) goto out_mutex;/*
@@ -6152,34 +6156,28 @@ vm_fault_t hugetlb_fault(struct mm_struct *mm, struct vm_area_struct *vma,* determine if a reservation has been consumed. */ if ((flags & (FAULT_FLAG_WRITE |FAULT_FLAG_UNSHARE )) && - !(vma->vm_flags &VM_MAYSHARE ) && !huge_pte_write (entry)) { -if (vma_needs_reservation (h, vma, haddr) <0 ) { + !(vma->vm_flags &VM_MAYSHARE ) && + !huge_pte_write (vmf.orig_pte)) { +if (vma_needs_reservation (h, vma, vmf.address) <0 ) { ret =VM_FAULT_OOM ; goto out_mutex; }/* Just decrements count, does not deallocate */ -vma_end_reservation (h, vma, haddr); +vma_end_reservation (h, vma, vmf.address); - pagecache_page =find_lock_page (mapping, idx); + pagecache_page =find_lock_page (mapping, vmf.pgoff); } - ptl =huge_pte_lock (h, mm, ptep); + vmf.ptl =huge_pte_lock (h, mm, vmf.pte);/* Check for a racing update before calling hugetlb_wp() */ -if (unlikely (!pte_same (entry,huge_ptep_get (ptep)))) +if (unlikely (!pte_same (vmf.orig_pte,huge_ptep_get (vmf.pte)))) goto out_ptl;/* Handle userfault-wp first, before trying to lock more pages */ -if (userfaultfd_wp (vma) &&huge_pte_uffd_wp (huge_ptep_get (ptep)) && - (flags &FAULT_FLAG_WRITE ) && !huge_pte_write (entry)) { -struct vm_fault vmf = { - .vma = vma, - .address = haddr, - .real_address = address, - .flags = flags, - }; - -spin_unlock (ptl); +if (userfaultfd_wp (vma) &&huge_pte_uffd_wp (huge_ptep_get (vmf.pte)) && + (flags &FAULT_FLAG_WRITE ) && !huge_pte_write (vmf.orig_pte)) { +spin_unlock (vmf.ptl);if (pagecache_page) {unlock_page (pagecache_page);put_page (pagecache_page);
@@ -6190,11 +6188,11 @@ vm_fault_t hugetlb_fault(struct mm_struct *mm, struct vm_area_struct *vma, }/* -* hugetlb_wp() requires page locks of pte_page(entry) and +* hugetlb_wp() requires page locks of pte_page(vmf.orig_pte) and * pagecache_page, so here we need take the former one * when page != pagecache_page or !pagecache_page. */ - page =pte_page (entry); + page =pte_page (vmf.orig_pte);if (page != pagecache_page)if (!trylock_page (page)) { need_wait_lock =1 ;
@@ -6204,24 +6202,24 @@ vm_fault_t hugetlb_fault(struct mm_struct *mm, struct vm_area_struct *vma,get_page (page);if (flags & (FAULT_FLAG_WRITE |FAULT_FLAG_UNSHARE )) { -if (!huge_pte_write (entry)) { - ret =hugetlb_wp (mm, vma, address, ptep, flags, - pagecache_page, ptl); +if (!huge_pte_write (vmf.orig_pte)) { + ret =hugetlb_wp (mm, vma, address, vmf.pte, flags, + pagecache_page, vmf.ptl); goto out_put_page; }else if (likely (flags &FAULT_FLAG_WRITE )) { - entry =huge_pte_mkdirty (entry); + vmf.orig_pte =huge_pte_mkdirty (vmf.orig_pte); } } - entry =pte_mkyoung (entry); -if (huge_ptep_set_access_flags (vma, haddr, ptep, entry, - flags &FAULT_FLAG_WRITE )) -update_mmu_cache (vma, haddr, ptep); + vmf.orig_pte =pte_mkyoung (vmf.orig_pte); +if (huge_ptep_set_access_flags (vma, vmf.address, vmf.pte, vmf.orig_pte, + flags &FAULT_FLAG_WRITE )) +update_mmu_cache (vma, vmf.address, vmf.pte); out_put_page:if (page != pagecache_page)unlock_page (page);put_page (page); out_ptl: -spin_unlock (ptl); +spin_unlock (vmf.ptl);if (pagecache_page) {unlock_page (pagecache_page);
mm/page_vma_mapped.c +7 -6
@@ -75,33 +75,34 @@ static bool map_pte(struct page_vma_mapped_walk *pvmw)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) && !is_device_exclusive_entry (entry))return false; pfn =swp_offset_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) && !is_device_exclusive_entry (entry))return false; pfn =swp_offset_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 - pvmw->pfn) < pvmw->nr_pages;
Signature · 1 line
2.53.0
Sasha Levin
maintainerPATCH 2/5 hugetlb: convert hugetlb_wp() to use struct vm_fault
From: "Vishal Moola (Oracle)" <[email protected]>
[ Upstream commit bd722058e34de4857bc554e786b7f41c747ad894 ]
hugetlb_wp() can use the struct vm_fault passed in from hugetlb_fault(). This alleviates the stack by consolidating 5 variables into a single struct.
Stable-dep-of: e87df0d5d696 ("mm/page_vma_mapped: use huge_ptep_get() for hugetlb")
--- mm/hugetlb.c | 68 ++++++++++++++++++++++++++-------------------------- 1 file changed, 34 insertions(+), 34 deletions(-)
mm/hugetlb.c +34 -34
@@ -5538,21 +5538,21 @@ static void unmap_ref_private(struct mm_struct *mm, struct vm_area_struct *vma,* cannot race with other handlers or page migration. * Keep the pte_same checks anyway to make transition from the mutex easier. */ -static vm_fault_t hugetlb_wp (struct mm_struct *mm,struct vm_area_struct *vma, -unsigned long address,pte_t *ptep,unsigned int flags, -struct page *pagecache_page,spinlock_t *ptl) +static vm_fault_t hugetlb_wp (struct page *pagecache_page, +struct vm_fault *vmf) { -const bool unshare = flags &FAULT_FLAG_UNSHARE ; -pte_t pte =huge_ptep_get (ptep); +struct vm_area_struct *vma = vmf->vma; +struct mm_struct *mm = vma->vm_mm; +const bool unshare = vmf->flags &FAULT_FLAG_UNSHARE ; +pte_t pte =huge_ptep_get (vmf->pte);struct hstate *h =hstate_vma (vma);struct page *old_page, *new_page;int outside_reserve =0 ;vm_fault_t ret =0 ; -unsigned long haddr = address &huge_page_mask (h);struct mmu_notifier_range range; -VM_BUG_ON (unshare && (flags &FOLL_WRITE )); -VM_BUG_ON (!unshare && !(flags &FOLL_WRITE )); +VM_BUG_ON (unshare && (vmf->flags &FOLL_WRITE )); +VM_BUG_ON (!unshare && !(vmf->flags &FOLL_WRITE ));/* * Never handle CoW for uffd-wp protected pages. It should be only
@@ -5576,7 +5576,7 @@ static vm_fault_t hugetlb_wp(struct mm_struct *mm, struct vm_area_struct *vma,if (vma->vm_flags &VM_MAYSHARE ) {if (unlikely (unshare))return 0 ; -set_huge_ptep_writable (vma, haddr, ptep); +set_huge_ptep_writable (vma, vmf->address, vmf->pte);return 0 ; }
@@ -5593,7 +5593,7 @@ static vm_fault_t hugetlb_wp(struct mm_struct *mm, struct vm_area_struct *vma,if (!PageAnonExclusive (old_page))page_move_anon_rmap (old_page, vma);if (likely (!unshare)) -set_huge_ptep_writable (vma, haddr, ptep); +set_huge_ptep_writable (vma, vmf->address, vmf->pte);delayacct_wpcopy_end ();return 0 ;
@@ -5620,8 +5620,8 @@ static vm_fault_t hugetlb_wp(struct mm_struct *mm, struct vm_area_struct *vma,* Drop page table lock as buddy allocator may be called. It will * be acquired again before returning to the caller, as expected. */ -spin_unlock (ptl); - new_page =alloc_huge_page (vma, haddr, outside_reserve); +spin_unlock (vmf->ptl); + new_page =alloc_huge_page (vma, vmf->address, outside_reserve);if (IS_ERR (new_page)) {/*
@@ -5646,19 +5646,20 @@ static vm_fault_t hugetlb_wp(struct mm_struct *mm, struct vm_area_struct *vma,* * Reacquire both after unmap operation. */ - idx =vma_hugecache_offset (h, vma, haddr); + idx =vma_hugecache_offset (h, vma, vmf->address); hash =hugetlb_fault_mutex_hash (mapping, idx);hugetlb_vma_unlock_read (vma);mutex_unlock (&hugetlb_fault_mutex_table[hash]); -unmap_ref_private (mm, vma, old_page, haddr); +unmap_ref_private (mm, vma, old_page, vmf->address);mutex_lock (&hugetlb_fault_mutex_table[hash]);hugetlb_vma_lock_read (vma); -spin_lock (ptl); - ptep =huge_pte_offset (mm, haddr,huge_page_size (h)); -if (likely (ptep && -pte_same (huge_ptep_get (ptep), pte))) +spin_lock (vmf->ptl); + vmf->pte =huge_pte_offset (mm, vmf->address, +huge_page_size (h)); +if (likely (vmf->pte && +pte_same (huge_ptep_get (vmf->pte), pte))) goto retry_avoidcopy;/* * race occurs while re-acquiring page table
@@ -5681,35 +5682,36 @@ static vm_fault_t hugetlb_wp(struct mm_struct *mm, struct vm_area_struct *vma, goto out_release_all; } -copy_user_huge_page (new_page, old_page, address, vma, +copy_user_huge_page (new_page, old_page, vmf->real_address, vma,pages_per_huge_page (h));__SetPageUptodate (new_page); -mmu_notifier_range_init (&range,MMU_NOTIFY_CLEAR ,0 , vma, mm, haddr, - haddr +huge_page_size (h)); +mmu_notifier_range_init (&range,MMU_NOTIFY_CLEAR ,0 , vma, mm, + vmf->address, + vmf->address +huge_page_size (h));mmu_notifier_invalidate_range_start (&range);/* * Retake the page table lock to check for racing updates * before the page tables are altered */ -spin_lock (ptl); - ptep =huge_pte_offset (mm, haddr,huge_page_size (h)); -if (likely (ptep &&pte_same (huge_ptep_get (ptep), pte))) { +spin_lock (vmf->ptl); + vmf->pte =huge_pte_offset (mm, vmf->address,huge_page_size (h)); +if (likely (vmf->pte &&pte_same (huge_ptep_get (vmf->pte), pte))) {ClearHPageRestoreReserve (new_page);/* Break COW or unshare */ -huge_ptep_clear_flush (vma, haddr, ptep); +huge_ptep_clear_flush (vma, vmf->address, vmf->pte);mmu_notifier_invalidate_range (mm, range.start, range.end);page_remove_rmap (old_page, vma, true); -hugepage_add_new_anon_rmap (new_page, vma, haddr); -set_huge_pte_at (mm, haddr, ptep, +hugepage_add_new_anon_rmap (new_page, vma, vmf->address); +set_huge_pte_at (mm, vmf->address, vmf->pte,make_huge_pte (vma, new_page, !unshare));SetHPageMigratable (new_page);/* Make the old page be freed below */ new_page = old_page; } -spin_unlock (ptl); +spin_unlock (vmf->ptl);mmu_notifier_invalidate_range_end (&range); out_release_all:/*
@@ -5717,12 +5719,12 @@ static vm_fault_t hugetlb_wp(struct mm_struct *mm, struct vm_area_struct *vma,* unshare) */ if (new_page != old_page) -restore_reserve_on_error (h, vma, haddr, new_page); +restore_reserve_on_error (h, vma, vmf->address, new_page);put_page (new_page); out_release_old:put_page (old_page); -spin_lock (ptl);/* Caller expects lock to be held */ +spin_lock (vmf->ptl);/* Caller expects lock to be held */ delayacct_wpcopy_end ();return ret;
@@ -6011,8 +6013,7 @@ static vm_fault_t hugetlb_no_page(struct address_space *mapping,hugetlb_count_add (pages_per_huge_page (h), mm);if ((vmf->flags &FAULT_FLAG_WRITE ) && !(vma->vm_flags &VM_SHARED )) {/* Optimization, do the COW without a second fault */ - ret =hugetlb_wp (mm, vma, vmf->real_address, vmf->pte, - vmf->flags, page, vmf->ptl); + ret =hugetlb_wp (page, vmf); }spin_unlock (vmf->ptl);
@@ -6203,8 +6204,7 @@ vm_fault_t hugetlb_fault(struct mm_struct *mm, struct vm_area_struct *vma,if (flags & (FAULT_FLAG_WRITE |FAULT_FLAG_UNSHARE )) {if (!huge_pte_write (vmf.orig_pte)) { - ret =hugetlb_wp (mm, vma, address, vmf.pte, flags, - pagecache_page, vmf.ptl); + ret =hugetlb_wp (pagecache_page, &vmf); goto out_put_page; }else if (likely (flags &FAULT_FLAG_WRITE )) { vmf.orig_pte =huge_pte_mkdirty (vmf.orig_pte);
Signature · 1 line
2.53.0
Sasha Levin
maintainerPATCH 3/5 fs/proc/task_mmu: convert smaps_hugetlb_range() to work on folios
In reply to Sasha LevinFrom: David Hildenbrand <[email protected]>
[ Upstream commit 6401a2e6900843a77a27873c0529dea68f61193d ]
Let's get rid of another page_mapcount() check and simply use folio_likely_mapped_shared(), which is precise for hugetlb folios.
While at it, use huge_ptep_get() + pte_page() instead of ptep_get() + vm_normal_page(), just like we do in pagemap_hugetlb_range().
No functional change intended.
On this stable tree, use folio_estimated_sharers() and wrap pfn_swap_entry_to_page() with page_folio(). These are the equivalent APIs available before folio_likely_mapped_shared() and pfn_swap_entry_folio() were introduced.
Stable-dep-of: e87df0d5d696 ("mm/page_vma_mapped: use huge_ptep_get() for hugetlb")
--- fs/proc/task_mmu.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-)
fs/proc/task_mmu.c +10 -8
@@ -726,18 +726,20 @@ static int smaps_hugetlb_range(pte_t *pte, unsigned long hmask, {struct mem_size_stats *mss = walk->private;struct vm_area_struct *vma = walk->vma; -struct page *page =NULL ; +pte_t ptent =huge_ptep_get (pte); +struct folio *folio =NULL ; -if (pte_present (*pte)) { - page =vm_normal_page (vma, addr, *pte); - }else if (is_swap_pte (*pte)) { -swp_entry_t swpent =pte_to_swp_entry (*pte); +if (pte_present (ptent)) { + folio =page_folio (pte_page (ptent)); + }else if (is_swap_pte (ptent)) { +swp_entry_t swpent =pte_to_swp_entry (ptent);if (is_pfn_swap_entry (swpent)) - page =pfn_swap_entry_to_page (swpent); + folio =page_folio (pfn_swap_entry_to_page (swpent)); } -if (page) { -if (page_mapcount (page) >=2 ||hugetlb_pmd_shared (pte)) +if (folio) { +if (folio_estimated_sharers (folio) >=2 || +hugetlb_pmd_shared (pte)) mss->shared_hugetlb +=huge_page_size (hstate_vma (vma));else mss->private_hugetlb +=huge_page_size (hstate_vma (vma));
Signature · 1 line
2.53.0
Sasha Levin
maintainerPATCH 4/5 mm: provide mm_struct and address to huge_ptep_get()
In reply to Sasha LevinFrom: 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 19. Not backported here:
arch/riscv/include/asm/hugetlb.h
arch/riscv/mm/hugetlbpage.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 | 4 +- arch/arm64/include/asm/hugetlb.h | 2 +- arch/arm64/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 | 6 +-- fs/userfaultfd.c | 2 +- include/asm-generic/hugetlb.h | 2 +- include/linux/swapops.h | 12 +++-- mm/damon/vaddr.c | 6 +-- mm/gup.c | 2 +- mm/hmm.c | 2 +- mm/hugetlb.c | 75 ++++++++++++++++----------- mm/memory-failure.c | 2 +- mm/mempolicy.c | 2 +- mm/migrate.c | 10 ++-- mm/mincore.c | 2 +- mm/userfaultfd.c | 3 +- 19 files changed, 82 insertions(+), 62 deletions(-)
arch/arm/include/asm/hugetlb-3level.h +2 -2
@@ -13,12 +13,12 @@/* * 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 +1 -1
@@ -45,7 +45,7 @@ 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
@@ -148,7 +148,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/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
@@ -163,7 +163,7 @@ void set_huge_pte_at(struct mm_struct *mm, unsigned long addr,set_pte (ptep,__pte (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)); }
@@ -171,7 +171,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
@@ -405,7 +405,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 +3 -3
@@ -726,7 +726,7 @@ static int smaps_hugetlb_range(pte_t *pte, unsigned long hmask, {struct mem_size_stats *mss = walk->private;struct vm_area_struct *vma = walk->vma; -pte_t ptent =huge_ptep_get (pte); +pte_t ptent =huge_ptep_get (walk->mm, addr, pte);struct folio *folio =NULL ;if (pte_present (ptent)) {
@@ -1576,7 +1576,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);
@@ -1900,7 +1900,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
@@ -264,7 +264,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, address, ptep);/* * Lockless access: we're in a wait_event so it's ok if it
include/asm-generic/hugetlb.h +1 -1
@@ -144,7 +144,7 @@ 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 +8 -4
@@ -347,8 +347,10 @@ extern void __migration_entry_wait(struct mm_struct *mm, pte_t *ptep,extern void migration_entry_wait (struct mm_struct *mm,pmd_t *pmd,unsigned long address);#ifdef CONFIG_HUGETLB_PAGE -extern void __migration_entry_wait_huge (pte_t *ptep,spinlock_t *ptl); -extern void migration_entry_wait_huge (struct vm_area_struct *vma,pte_t *pte); +extern void __migration_entry_wait_huge (struct mm_struct *mm, +unsigned long address,pte_t *ptep,spinlock_t *ptl); +extern void migration_entry_wait_huge (struct vm_area_struct *vma, +unsigned long address,pte_t *pte);#endif /* CONFIG_HUGETLB_PAGE */ #else /* CONFIG_MIGRATION */ static inline swp_entry_t make_readable_migration_entry (pgoff_t offset)
@@ -376,8 +378,10 @@ static inline void __migration_entry_wait(struct mm_struct *mm, pte_t *ptep,static inline void migration_entry_wait (struct mm_struct *mm,pmd_t *pmd,unsigned long address) { }#ifdef CONFIG_HUGETLB_PAGE -static inline void __migration_entry_wait_huge (pte_t *ptep,spinlock_t *ptl) { } -static inline void migration_entry_wait_huge (struct vm_area_struct *vma,pte_t *pte) { } +static inline void __migration_entry_wait_huge (struct mm_struct *mm, +unsigned long address,pte_t *ptep,spinlock_t *ptl) { } +static inline void migration_entry_wait_huge (struct vm_area_struct *vma, +unsigned long address,pte_t *pte) { }#endif /* CONFIG_HUGETLB_PAGE */ static inline int is_writable_migration_entry (swp_entry_t entry) {
mm/damon/vaddr.c +3 -3
@@ -336,7 +336,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 page *page =pte_page (entry);get_page (page);
@@ -369,7 +369,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;
@@ -497,7 +497,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
@@ -2662,7 +2662,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, addr, pte); i = (start - range->start) >>PAGE_SHIFT ; pfn_req_flags = range->hmm_pfns[i];
mm/hugetlb.c +44 -31
241 lines not on this page · raw message
mm/memory-failure.c +1 -1
@@ -721,7 +721,7 @@ static int hwpoison_hugetlb_range(pte_t *ptep, unsigned long hmask, struct mm_walk *walk) {struct hwp_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
@@ -567,7 +567,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/migrate.c +6 -4
@@ -322,12 +322,13 @@ void migration_entry_wait(struct mm_struct *mm, pmd_t *pmd, }#ifdef CONFIG_HUGETLB_PAGE -void __migration_entry_wait_huge (pte_t *ptep,spinlock_t *ptl) +void __migration_entry_wait_huge (struct mm_struct *mm, +unsigned long address,pte_t *ptep,spinlock_t *ptl) {pte_t pte;spin_lock (ptl); - pte =huge_ptep_get (ptep); + pte =huge_ptep_get (mm, address, ptep);if (unlikely (!is_hugetlb_entry_migration (pte)))spin_unlock (ptl);
@@ -335,11 +336,12 @@ void __migration_entry_wait_huge(pte_t *ptep, spinlock_t *ptl) migration_entry_wait_on_locked(pte_to_swp_entry(pte), NULL, ptl); } -void migration_entry_wait_huge (struct vm_area_struct *vma,pte_t *pte) +void migration_entry_wait_huge (struct vm_area_struct *vma, +unsigned long address,pte_t *pte) {spinlock_t *ptl =huge_pte_lockptr (hstate_vma (vma), vma->vm_mm, pte); -__migration_entry_wait_huge (pte, ptl); +__migration_entry_wait_huge (vma->vm_mm, address, pte, ptl); }#endif
mm/mincore.c +1 -1
@@ -33,7 +33,7 @@ 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
@@ -417,7 +417,8 @@ static __always_inline ssize_t __mcopy_atomic_hugetlb(struct mm_struct *dst_mm, }if (mode !=MCOPY_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 5/5 mm/page_vma_mapped: use huge_ptep_get() for hugetlb
In reply to Sasha LevinFrom: 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
@@ -75,7 +75,13 @@ static bool map_pte(struct page_vma_mapped_walk *pvmw)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