The PMD callback still maps and unmaps the PTE table, drives split retries and handles rescheduling after dispatching huge PMDs. This leaves PTE lock ownership mixed with the page-walk callback.
Move that lifecycle into madvise_lru_pte_range(). Its outer loop drops the lock before splitting or yielding and resumes at the current address, leaving the PMD callback to select the huge-PMD or PTE path. No functional change intended. Assisted-by: LLM Signed-off-by: Gregory Price (Meta) <[email protected]> --- mm/madvise.c | 94 ++++++++++++++++++++++++++-------------------------- 1 file changed, 47 insertions(+), 47 deletions(-) diff --git a/mm/madvise.c b/mm/madvise.c index e3c3acfcd9b66..88a4a03dee04c 100644 --- a/mm/madvise.c +++ b/mm/madvise.c @@ -553,66 +553,66 @@ madvise_lru_pte_range_locked(pte_t *pte, unsigned long *addr, return NULL; } -static int madvise_lru_pmd_entry(pmd_t *pmd, unsigned long addr, - unsigned long end, struct mm_walk *walk) +static void madvise_lru_pte_range(pmd_t *pmd, unsigned long addr, + unsigned long end, struct mm_walk *walk, + bool pageout_anon_only) { - struct madvise_walk_private *private = walk->private; - struct mmu_gather *tlb = private->tlb; - bool pageout = private->pageout; - struct mm_struct *mm = tlb->mm; - struct vm_area_struct *vma = walk->vma; + const struct madvise_walk_private *private = walk->private; + struct mm_struct *mm = private->tlb->mm; + LIST_HEAD(folio_list); pte_t *start_pte, *pte; spinlock_t *ptl; - struct folio *folio = NULL; - LIST_HEAD(folio_list); + struct folio *folio; unsigned int batch_count = 0; - bool pageout_anon_only; int nr; - if (fatal_signal_pending(current)) - return -EINTR; - pageout_anon_only = pageout && !vma_is_anonymous(vma) && - !can_do_file_pageout(vma); + tlb_change_page_size(private->tlb, PAGE_SIZE); + while (addr < end) { + start_pte = pte_offset_map_lock(mm, pmd, addr, &ptl); + if (!start_pte) + break; + pte = start_pte; + flush_tlb_batched_pending(mm); + lazy_mmu_mode_enable(); + folio = madvise_lru_pte_range_locked(pte, &addr, end, walk, + &folio_list, pageout_anon_only, &nr, &batch_count); - if (pmd_trans_huge(*pmd) && - madvise_lru_huge_pmd(pmd, addr, end, walk, pageout_anon_only)) - return 0; - tlb_change_page_size(tlb, PAGE_SIZE); -restart: - start_pte = pte = pte_offset_map_lock(vma->vm_mm, pmd, addr, &ptl); - if (!start_pte) - goto out; - flush_tlb_batched_pending(mm); - lazy_mmu_mode_enable(); - folio = madvise_lru_pte_range_locked(pte, &addr, end, walk, - &folio_list, pageout_anon_only, &nr, &batch_count); - if (!folio && addr < end) { lazy_mmu_mode_disable(); pte_unmap_unlock(start_pte, ptl); - cond_resched(); - goto restart; - } - if (!folio) - goto out; - lazy_mmu_mode_disable(); - pte_unmap_unlock(start_pte, ptl); - start_pte = NULL; - if (!split_folio(folio)) - nr = 0; - folio_unlock(folio); - folio_put(folio); - addr += nr * PAGE_SIZE; - goto restart; - -out: - if (start_pte) { - lazy_mmu_mode_disable(); - pte_unmap_unlock(start_pte, ptl); + if (!folio && addr < end) { + cond_resched(); + continue; + } + if (folio) { + if (!split_folio(folio)) + nr = 0; + folio_unlock(folio); + folio_put(folio); + addr += nr * PAGE_SIZE; + } } - if (pageout) + if (private->pageout) reclaim_pages(&folio_list); cond_resched(); +} + +static int madvise_lru_pmd_entry(pmd_t *pmd, unsigned long addr, + unsigned long next, struct mm_walk *walk) +{ + const struct madvise_walk_private *private = walk->private; + struct vm_area_struct *vma = walk->vma; + bool pageout_anon_only; + + if (fatal_signal_pending(current)) + return -EINTR; + pageout_anon_only = private->pageout && !vma_is_anonymous(vma) && + !can_do_file_pageout(vma); + + if (pmd_trans_huge(*pmd) && + madvise_lru_huge_pmd(pmd, addr, next, walk, pageout_anon_only)) + return 0; + madvise_lru_pte_range(pmd, addr, next, walk, pageout_anon_only); return 0; } -- 2.53.0-Meta

