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

