The PMD callback still owns huge-PMD locking, splitting and reclaim along
with its PTE-table loop. This obscures the transition between the two
paths.

Move huge-PMD lock ownership into a dedicated helper. Return false after a
requested PMD split succeeds so the callback continues at PTE level. Use
the PMD boundary already supplied by walk_pmd_range().

No functional change intended.

Assisted-by: LLM
Signed-off-by: Gregory Price (Meta) <[email protected]>
---
 mm/madvise.c | 85 +++++++++++++++++++++++++++++-----------------------
 1 file changed, 48 insertions(+), 37 deletions(-)

diff --git a/mm/madvise.c b/mm/madvise.c
index 6b518f7f73651..83b27258c9673 100644
--- a/mm/madvise.c
+++ b/mm/madvise.c
@@ -435,6 +435,52 @@ madvise_lru_huge_pmd_locked(pmd_t *pmd, pmd_t orig_pmd,
        madvise_lru_folio(folio, private->pageout, folio_list);
        return NULL;
 }
+
+/* Return false when a requested split requires a PTE walk. */
+static bool madvise_lru_huge_pmd(pmd_t *pmd, unsigned long addr,
+               unsigned long next, struct mm_walk *walk,
+               bool pageout_anon_only)
+{
+       const struct madvise_walk_private *private = walk->private;
+       struct mmu_gather *tlb = private->tlb;
+       bool pageout = private->pageout;
+       LIST_HEAD(folio_list);
+       struct folio *folio = NULL;
+       spinlock_t *ptl;
+       pmd_t orig_pmd;
+
+       tlb_change_page_size(tlb, HPAGE_PMD_SIZE);
+       ptl = pmd_trans_huge_lock(pmd, walk->vma);
+       if (!ptl)
+               return true;
+
+       orig_pmd = *pmd;
+       if (unlikely(!pmd_present(orig_pmd))) {
+               VM_WARN_ON_ONCE(!pmd_is_valid_softleaf(orig_pmd));
+       } else {
+               folio = madvise_lru_huge_pmd_locked(pmd, orig_pmd, addr, next,
+                               walk, &folio_list, pageout_anon_only);
+       }
+       spin_unlock(ptl);
+
+       if (folio) {
+               int err = split_folio(folio);
+
+               folio_unlock(folio);
+               folio_put(folio);
+               return err != 0;
+       }
+       if (pageout)
+               reclaim_pages(&folio_list);
+       return true;
+}
+#else
+static bool madvise_lru_huge_pmd(pmd_t *pmd, unsigned long addr,
+               unsigned long next, struct mm_walk *walk,
+               bool pageout_anon_only)
+{
+       return false;
+}
 #endif
 
 static int madvise_lru_pmd_entry(pmd_t *pmd, unsigned long addr,
@@ -458,44 +504,9 @@ static int madvise_lru_pmd_entry(pmd_t *pmd, unsigned long 
addr,
        pageout_anon_only = pageout && !vma_is_anonymous(vma) &&
                                       !can_do_file_pageout(vma);
 
-#ifdef CONFIG_TRANSPARENT_HUGEPAGE
-       if (pmd_trans_huge(*pmd)) {
-               pmd_t orig_pmd;
-               unsigned long next = pmd_addr_end(addr, end);
-
-               tlb_change_page_size(tlb, HPAGE_PMD_SIZE);
-               ptl = pmd_trans_huge_lock(pmd, vma);
-               if (!ptl)
-                       return 0;
-
-               orig_pmd = *pmd;
-               if (unlikely(!pmd_present(orig_pmd))) {
-                       VM_WARN_ON_ONCE(!pmd_is_valid_softleaf(orig_pmd));
-                       goto huge_unlock;
-               }
-
-               folio = madvise_lru_huge_pmd_locked(pmd, orig_pmd, addr, next,
-                               walk, &folio_list, pageout_anon_only);
-               if (folio) {
-                       int err;
-
-                       spin_unlock(ptl);
-                       err = split_folio(folio);
-                       folio_unlock(folio);
-                       folio_put(folio);
-                       if (!err)
-                               goto regular_folio;
-                       return 0;
-               }
-huge_unlock:
-               spin_unlock(ptl);
-               if (pageout)
-                       reclaim_pages(&folio_list);
+       if (pmd_trans_huge(*pmd) &&
+           madvise_lru_huge_pmd(pmd, addr, end, walk, pageout_anon_only))
                return 0;
-       }
-
-regular_folio:
-#endif
        tlb_change_page_size(tlb, PAGE_SIZE);
 restart:
        start_pte = pte = pte_offset_map_lock(vma->vm_mm, pmd, addr, &ptl);
-- 
2.53.0-Meta


Reply via email to