FAILED: patch "[PATCH] mm/page_vma_mapped: use huge_ptep_get() for hugetlb" 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 e87df0d5d6962bde50f55f6d02b779daa394f894
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<[email protected]>' --in-reply-to '2026090314-mumps-septum-7049@gregkh' --subject-prefix 'PATCH 6.6.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/6 hugetlb: convert hugetlb_fault() to use struct vm_fault
From: "Vishal Moola (Oracle)" <[email protected]>
[ Upstream commit 9b42fa16195fb471bf3b7849803c0a7d3e7620f2 ]
Patch series "Hugetlb fault path to use struct vm_fault", v2.
This patchset converts the hugetlb fault path to use struct vm_fault. This helps make the code more readable, and alleviates the stack by allowing us to consolidate many fault-related variables into an individual pointer.
This patch (of 3):
Now that hugetlb_fault() has a vm_fault available for fault tracking, use it throughout. This cleans up the code by removing 2 variables, and prepares hugetlb_fault() to take in a struct vm_fault argument.
Stable-dep-of: e87df0d5d696 ("mm/page_vma_mapped: use huge_ptep_get() for hugetlb")
--- mm/hugetlb.c | 104 ++++++++++++++++++++++++++------------------------- 1 file changed, 53 insertions(+), 51 deletions(-)
mm/hugetlb.c +53 -51
@@ -6085,17 +6085,27 @@ 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 folio *folio =NULL ;struct folio *pagecache_folio =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)), +/* TODO: Track hugetlb faults using vm_fault */ + +/* +* Some fields may not be initialized, be careful as it may +* be hard to debug if called functions make assumptions +*/ + };/* TODO: Handle faults under the VMA lock */ if (flags &FAULT_FLAG_VMA_LOCK ) {
@@ -6109,28 +6119,27 @@ 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. */ 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); -if (huge_pte_none_mostly (entry)) { -if (is_pte_marker (entry)) { + vmf.orig_pte =huge_ptep_get (vmf.pte); +if (huge_pte_none_mostly (vmf.orig_pte)) { +if (is_pte_marker (vmf.orig_pte)) {pte_marker marker = -pte_marker_get (pte_to_swp_entry (entry)); +pte_marker_get (pte_to_swp_entry (vmf.orig_pte));if (marker &PTE_MARKER_POISONED ) { ret =VM_FAULT_HWPOISON_LARGE ;
@@ -6144,21 +6153,21 @@ vm_fault_t hugetlb_fault(struct mm_struct *mm, struct vm_area_struct *vma,* 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 (mm, vma, mapping, vmf.pgoff, address, + vmf.pte, vmf.orig_pte, flags); } 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 vmf.orig_pte 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 (unlikely (is_hugetlb_entry_migration (entry))) { +if (!pte_present (vmf.orig_pte)) { +if (unlikely (is_hugetlb_entry_migration (vmf.orig_pte))) {/* * Release the hugetlb fault lock now, but retain * the vma lock, because it is needed to guard the
@@ -6167,9 +6176,9 @@ vm_fault_t hugetlb_fault(struct mm_struct *mm, struct vm_area_struct *vma,* be released there. */ mutex_unlock (&hugetlb_fault_mutex_table[hash]); -migration_entry_wait_huge (vma, ptep); +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))) ret =VM_FAULT_HWPOISON_LARGE |VM_FAULT_SET_HINDEX (hstate_index (h)); goto out_mutex;
@@ -6183,36 +6192,29 @@ 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_folio =filemap_lock_folio (mapping, idx); + pagecache_folio =filemap_lock_folio (mapping, vmf.pgoff);if (IS_ERR (pagecache_folio)) pagecache_folio =NULL ; } - 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_folio) {folio_unlock (pagecache_folio);folio_put (pagecache_folio);
@@ -6223,11 +6225,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_folio, so here we need take the former one * when folio != pagecache_folio or !pagecache_folio. */ - folio =page_folio (pte_page (entry)); + folio =page_folio (pte_page (vmf.orig_pte));if (folio != pagecache_folio)if (!folio_trylock (folio)) { need_wait_lock =1 ;
@@ -6237,24 +6239,24 @@ vm_fault_t hugetlb_fault(struct mm_struct *mm, struct vm_area_struct *vma,folio_get (folio);if (flags & (FAULT_FLAG_WRITE |FAULT_FLAG_UNSHARE )) { -if (!huge_pte_write (entry)) { - ret =hugetlb_wp (mm, vma, address, ptep, flags, - pagecache_folio, ptl); +if (!huge_pte_write (vmf.orig_pte)) { + ret =hugetlb_wp (mm, vma, address, vmf.pte, flags, + pagecache_folio, 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, + 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, haddr, ptep); +update_mmu_cache (vma, vmf.address, vmf.pte); out_put_page:if (folio != pagecache_folio)folio_unlock (folio);folio_put (folio); out_ptl: -spin_unlock (ptl); +spin_unlock (vmf.ptl);if (pagecache_folio) {folio_unlock (pagecache_folio);
Signature · 1 line
2.53.0
Sasha Levin
maintainerPATCH 2/6 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 | 74 +++++++++++++++++++++++++++------------------------- 1 file changed, 38 insertions(+), 36 deletions(-)
mm/hugetlb.c +38 -36
@@ -5848,22 +5848,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 folio *folio;pte_t new_pte; -spinlock_t *ptl; -unsigned long haddr = address &huge_page_mask (h);bool new_folio, new_pagecache_folio = 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
@@ -5882,10 +5879,10 @@ static vm_fault_t hugetlb_no_page(struct mm_struct *mm,* before we get page_table_lock. */ new_folio = false; - folio =filemap_lock_folio (mapping, idx); + folio =filemap_lock_folio (mapping, vmf->pgoff);if (IS_ERR (folio)) { 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)) {
@@ -5906,17 +5903,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 ); } - folio =alloc_hugetlb_folio (vma, haddr,0 ); + folio =alloc_hugetlb_folio (vma, vmf->address,0 );if (IS_ERR (folio)) {/* * Returning error will result in faulting task being
@@ -5930,18 +5928,20 @@ 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 (folio));else ret =0 ; goto out; } -clear_huge_page (&folio->page, address,pages_per_huge_page (h)); +clear_huge_page (&folio->page, vmf->real_address, +pages_per_huge_page (h));__folio_mark_uptodate (folio); new_folio = true;if (vma->vm_flags &VM_MAYSHARE ) { -int err =hugetlb_add_to_page_cache (folio, mapping, idx); +int err =hugetlb_add_to_page_cache (folio, mapping, + vmf->pgoff);if (err) {/* * err can't be -EEXIST which implies someone
@@ -5950,7 +5950,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, folio); +restore_reserve_on_error (h, vma, vmf->address, + folio);folio_put (folio); goto out; }
@@ -5980,12 +5981,13 @@ static vm_fault_t hugetlb_no_page(struct mm_struct *mm,folio_unlock (folio);folio_put (folio);/* 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 ); } }
@@ -5996,23 +5998,23 @@ 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) -hugepage_add_new_anon_rmap (folio, vma, haddr); +hugepage_add_new_anon_rmap (folio, vma, vmf->address);else page_dup_file_rmap (&folio->page, true); new_pte = make_huge_pte(vma, &folio->page, ((vma->vm_flags & VM_WRITE)
@@ -6021,17 +6023,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_mkuffd_wp (new_pte); -set_huge_pte_at (mm, haddr, ptep, new_pte,huge_page_size (h)); +set_huge_pte_at (mm, vmf->address, vmf->pte, new_pte,huge_page_size (h));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, folio, ptl); + ret =hugetlb_wp (mm, vma, vmf->real_address, vmf->pte, + vmf->flags, folio, vmf->ptl); } -spin_unlock (ptl); +spin_unlock (vmf->ptl);/* * Only set hugetlb_migratable in newly allocated pages. Existing pages
@@ -6048,10 +6051,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_folio && !new_pagecache_folio) -restore_reserve_on_error (h, vma, haddr, folio); +restore_reserve_on_error (h, vma, vmf->address, folio);folio_unlock (folio);folio_put (folio);
@@ -6153,8 +6156,7 @@ vm_fault_t hugetlb_fault(struct mm_struct *mm, struct vm_area_struct *vma,* hugetlb_no_page will drop vma lock and hugetlb fault * mutex internally, which make us return immediately. */ -return hugetlb_no_page (mm, vma, mapping, vmf.pgoff, address, - vmf.pte, vmf.orig_pte, flags); +return hugetlb_no_page (mapping, &vmf); } ret =0 ;
Signature · 1 line
2.53.0
Sasha Levin
maintainerPATCH 3/6 hugetlb: convert hugetlb_wp() to use struct vm_fault
In reply to Sasha LevinFrom: "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 | 65 ++++++++++++++++++++++++++-------------------------- 1 file changed, 33 insertions(+), 32 deletions(-)
mm/hugetlb.c +33 -32
@@ -5563,18 +5563,18 @@ 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 folio *pagecache_folio,spinlock_t *ptl) +static vm_fault_t hugetlb_wp (struct folio *pagecache_folio, +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 folio *old_folio;struct folio *new_folio;int outside_reserve =0 ;vm_fault_t ret =0 ; -unsigned long haddr = address &huge_page_mask (h);struct mmu_notifier_range range;/*
@@ -5597,7 +5597,7 @@ static vm_fault_t hugetlb_wp(struct mm_struct *mm, struct vm_area_struct *vma,/* Let's take out MAP_SHARED mappings first. */ if (vma->vm_flags &VM_MAYSHARE ) { -set_huge_ptep_writable (vma, haddr, ptep); +set_huge_ptep_writable (vma, vmf->address, vmf->pte);return 0 ; }
@@ -5614,7 +5614,7 @@ static vm_fault_t hugetlb_wp(struct mm_struct *mm, struct vm_area_struct *vma,if (!PageAnonExclusive (&old_folio->page))page_move_anon_rmap (&old_folio->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 ;
@@ -5641,8 +5641,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_folio =alloc_hugetlb_folio (vma, haddr, outside_reserve); +spin_unlock (vmf->ptl); + new_folio =alloc_hugetlb_folio (vma, vmf->address, outside_reserve);if (IS_ERR (new_folio)) {/*
@@ -5667,19 +5667,21 @@ 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_folio->page, haddr); +unmap_ref_private (mm, vma, &old_folio->page, + vmf->address);mutex_lock (&hugetlb_fault_mutex_table[hash]);hugetlb_vma_lock_read (vma); -spin_lock (ptl); - ptep =hugetlb_walk (vma, haddr,huge_page_size (h)); -if (likely (ptep && -pte_same (huge_ptep_get (ptep), pte))) +spin_lock (vmf->ptl); + vmf->pte =hugetlb_walk (vma, 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
@@ -5702,37 +5704,38 @@ static vm_fault_t hugetlb_wp(struct mm_struct *mm, struct vm_area_struct *vma, goto out_release_all; } -if (copy_user_large_folio (new_folio, old_folio, address, vma)) { +if (copy_user_large_folio (new_folio, old_folio, vmf->real_address, vma)) { ret =VM_FAULT_HWPOISON_LARGE ; goto out_release_all; }__folio_mark_uptodate (new_folio); -mmu_notifier_range_init (&range,MMU_NOTIFY_CLEAR ,0 , mm, haddr, - haddr +huge_page_size (h)); +mmu_notifier_range_init (&range,MMU_NOTIFY_CLEAR ,0 , 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 =hugetlb_walk (vma, haddr,huge_page_size (h)); -if (likely (ptep &&pte_same (huge_ptep_get (ptep), pte))) { +spin_lock (vmf->ptl); + vmf->pte =hugetlb_walk (vma, vmf->address,huge_page_size (h)); +if (likely (vmf->pte &&pte_same (huge_ptep_get (vmf->pte), pte))) {pte_t newpte =make_huge_pte (vma, &new_folio->page, !unshare);/* Break COW or unshare */ -huge_ptep_clear_flush (vma, haddr, ptep); +huge_ptep_clear_flush (vma, vmf->address, vmf->pte);page_remove_rmap (&old_folio->page, vma, true); -hugepage_add_new_anon_rmap (new_folio, vma, haddr); +hugepage_add_new_anon_rmap (new_folio, vma, vmf->address);if (huge_pte_uffd_wp (pte)) newpte =huge_pte_mkuffd_wp (newpte); -set_huge_pte_at (mm, haddr, ptep, newpte,huge_page_size (h)); +set_huge_pte_at (mm, vmf->address, vmf->pte, newpte, +huge_page_size (h));folio_set_hugetlb_migratable (new_folio);/* Make the old page be freed below */ new_folio = old_folio; } -spin_unlock (ptl); +spin_unlock (vmf->ptl);mmu_notifier_invalidate_range_end (&range); out_release_all:/*
@@ -5740,12 +5743,12 @@ static vm_fault_t hugetlb_wp(struct mm_struct *mm, struct vm_area_struct *vma,* unshare) */ if (new_folio != old_folio) -restore_reserve_on_error (h, vma, haddr, new_folio); +restore_reserve_on_error (h, vma, vmf->address, new_folio);folio_put (new_folio); out_release_old:folio_put (old_folio); -spin_lock (ptl);/* Caller expects lock to be held */ +spin_lock (vmf->ptl);/* Caller expects lock to be held */ delayacct_wpcopy_end ();return ret;
@@ -6030,8 +6033,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, folio, vmf->ptl); + ret =hugetlb_wp (folio, vmf); }spin_unlock (vmf->ptl);
@@ -6242,8 +6244,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_folio, vmf.ptl); + ret =hugetlb_wp (pagecache_folio, &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 4/6 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.
Stable-dep-of: e87df0d5d696 ("mm/page_vma_mapped: use huge_ptep_get() for hugetlb")
--- fs/proc/task_mmu.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-)
fs/proc/task_mmu.c +7 -6
@@ -723,19 +723,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 =ptep_get (pte); +pte_t ptent =huge_ptep_get (pte); +struct folio *folio =NULL ;if (pte_present (ptent)) { - page =vm_normal_page (vma, addr, 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 =pfn_swap_entry_folio (swpent); } -if (page) { -if (page_mapcount (page) >=2 ||hugetlb_pmd_shared (pte)) +if (folio) { +if (folio_likely_mapped_shared (folio) || +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 5/6 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().
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/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 | 10 +++--- fs/userfaultfd.c | 2 +- include/asm-generic/hugetlb.h | 2 +- include/linux/swapops.h | 4 +-- mm/damon/vaddr.c | 6 ++-- mm/gup.c | 2 +- mm/hmm.c | 2 +- mm/hugetlb.c | 46 +++++++++++++-------------- mm/memory-failure.c | 2 +- mm/mempolicy.c | 2 +- mm/migrate.c | 4 +-- mm/mincore.c | 2 +- mm/userfaultfd.c | 2 +- 21 files changed, 54 insertions(+), 54 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
@@ -46,7 +46,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
@@ -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 +5 -5
@@ -723,7 +723,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)) {
@@ -732,10 +732,10 @@ static int smaps_hugetlb_range(pte_t *pte, unsigned long hmask,swp_entry_t swpent =pte_to_swp_entry (ptent);if (is_pfn_swap_entry (swpent)) - folio =pfn_swap_entry_folio (swpent); + folio =page_folio (pfn_swap_entry_to_page (swpent)); }if (folio) { -if (folio_likely_mapped_shared (folio) || +if (folio_mapcount (folio) >=2 ||hugetlb_pmd_shared (pte)) mss->shared_hugetlb +=huge_page_size (hstate_vma (vma));else
@@ -1579,7 +1579,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);
@@ -1911,7 +1911,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 +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 +2 -2
@@ -334,7 +334,7 @@ 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 +359,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 (current->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 +23 -23
181 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 +2 -2
@@ -335,14 +335,14 @@ 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 +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 +1 -1
@@ -482,7 +482,7 @@ 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 6/6 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
@@ -97,7 +97,13 @@ static bool map_pte(struct page_vma_mapped_walk *pvmw, spinlock_t **ptlp)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 ) {swp_entry_t entry;
Signature · 1 line
2.53.0