Skip to content

Commit 29e847d

Browse files
ioworker0akpm00
authored andcommitted
mm/rmap: integrate PMD-mapped folio splitting into pagewalk loop
In preparation for supporting try_to_unmap_one() to unmap PMD-mapped folios, start the pagewalk first, then call split_huge_pmd_address() to split the folio. Link: https://lkml.kernel.org/r/[email protected] Signed-off-by: Lance Yang <[email protected]> Suggested-by: David Hildenbrand <[email protected]> Acked-by: David Hildenbrand <[email protected]> Suggested-by: Baolin Wang <[email protected]> Acked-by: Zi Yan <[email protected]> Cc: Bang Li <[email protected]> Cc: Barry Song <[email protected]> Cc: Fangrui Song <[email protected]> Cc: Jeff Xie <[email protected]> Cc: Kefeng Wang <[email protected]> Cc: Matthew Wilcox (Oracle) <[email protected]> Cc: Michal Hocko <[email protected]> Cc: Minchan Kim <[email protected]> Cc: Muchun Song <[email protected]> Cc: Peter Xu <[email protected]> Cc: Ryan Roberts <[email protected]> Cc: SeongJae Park <[email protected]> Cc: Yang Shi <[email protected]> Cc: Yin Fengwei <[email protected]> Cc: Zach O'Keefe <[email protected]> Signed-off-by: Andrew Morton <[email protected]>
1 parent 26d21b1 commit 29e847d

File tree

4 files changed

+67
-26
lines changed

4 files changed

+67
-26
lines changed

include/linux/huge_mm.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -428,6 +428,9 @@ static inline bool thp_migration_supported(void)
428428
return IS_ENABLED(CONFIG_ARCH_ENABLE_THP_MIGRATION);
429429
}
430430

431+
void split_huge_pmd_locked(struct vm_area_struct *vma, unsigned long address,
432+
pmd_t *pmd, bool freeze, struct folio *folio);
433+
431434
#else /* CONFIG_TRANSPARENT_HUGEPAGE */
432435

433436
static inline bool folio_test_pmd_mappable(struct folio *folio)
@@ -490,6 +493,9 @@ static inline void __split_huge_pmd(struct vm_area_struct *vma, pmd_t *pmd,
490493
unsigned long address, bool freeze, struct folio *folio) {}
491494
static inline void split_huge_pmd_address(struct vm_area_struct *vma,
492495
unsigned long address, bool freeze, struct folio *folio) {}
496+
static inline void split_huge_pmd_locked(struct vm_area_struct *vma,
497+
unsigned long address, pmd_t *pmd,
498+
bool freeze, struct folio *folio) {}
493499

494500
#define split_huge_pud(__vma, __pmd, __address) \
495501
do { } while (0)

include/linux/rmap.h

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -703,6 +703,30 @@ static inline void page_vma_mapped_walk_done(struct page_vma_mapped_walk *pvmw)
703703
spin_unlock(pvmw->ptl);
704704
}
705705

706+
/**
707+
* page_vma_mapped_walk_restart - Restart the page table walk.
708+
* @pvmw: Pointer to struct page_vma_mapped_walk.
709+
*
710+
* It restarts the page table walk when changes occur in the page
711+
* table, such as splitting a PMD. Ensures that the PTL held during
712+
* the previous walk is released and resets the state to allow for
713+
* a new walk starting at the current address stored in pvmw->address.
714+
*/
715+
static inline void
716+
page_vma_mapped_walk_restart(struct page_vma_mapped_walk *pvmw)
717+
{
718+
WARN_ON_ONCE(!pvmw->pmd && !pvmw->pte);
719+
720+
if (likely(pvmw->ptl))
721+
spin_unlock(pvmw->ptl);
722+
else
723+
WARN_ON_ONCE(1);
724+
725+
pvmw->ptl = NULL;
726+
pvmw->pmd = NULL;
727+
pvmw->pte = NULL;
728+
}
729+
706730
bool page_vma_mapped_walk(struct page_vma_mapped_walk *pvmw);
707731

708732
/*

mm/huge_memory.c

Lines changed: 22 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2583,6 +2583,27 @@ static void __split_huge_pmd_locked(struct vm_area_struct *vma, pmd_t *pmd,
25832583
pmd_populate(mm, pmd, pgtable);
25842584
}
25852585

2586+
void split_huge_pmd_locked(struct vm_area_struct *vma, unsigned long address,
2587+
pmd_t *pmd, bool freeze, struct folio *folio)
2588+
{
2589+
VM_WARN_ON_ONCE(folio && !folio_test_pmd_mappable(folio));
2590+
VM_WARN_ON_ONCE(!IS_ALIGNED(address, HPAGE_PMD_SIZE));
2591+
VM_WARN_ON_ONCE(folio && !folio_test_locked(folio));
2592+
VM_BUG_ON(freeze && !folio);
2593+
2594+
/*
2595+
* When the caller requests to set up a migration entry, we
2596+
* require a folio to check the PMD against. Otherwise, there
2597+
* is a risk of replacing the wrong folio.
2598+
*/
2599+
if (pmd_trans_huge(*pmd) || pmd_devmap(*pmd) ||
2600+
is_pmd_migration_entry(*pmd)) {
2601+
if (folio && folio != pmd_folio(*pmd))
2602+
return;
2603+
__split_huge_pmd_locked(vma, pmd, address, freeze);
2604+
}
2605+
}
2606+
25862607
void __split_huge_pmd(struct vm_area_struct *vma, pmd_t *pmd,
25872608
unsigned long address, bool freeze, struct folio *folio)
25882609
{
@@ -2594,26 +2615,7 @@ void __split_huge_pmd(struct vm_area_struct *vma, pmd_t *pmd,
25942615
(address & HPAGE_PMD_MASK) + HPAGE_PMD_SIZE);
25952616
mmu_notifier_invalidate_range_start(&range);
25962617
ptl = pmd_lock(vma->vm_mm, pmd);
2597-
2598-
/*
2599-
* If caller asks to setup a migration entry, we need a folio to check
2600-
* pmd against. Otherwise we can end up replacing wrong folio.
2601-
*/
2602-
VM_BUG_ON(freeze && !folio);
2603-
VM_WARN_ON_ONCE(folio && !folio_test_locked(folio));
2604-
2605-
if (pmd_trans_huge(*pmd) || pmd_devmap(*pmd) ||
2606-
is_pmd_migration_entry(*pmd)) {
2607-
/*
2608-
* It's safe to call pmd_page when folio is set because it's
2609-
* guaranteed that pmd is present.
2610-
*/
2611-
if (folio && folio != pmd_folio(*pmd))
2612-
goto out;
2613-
__split_huge_pmd_locked(vma, pmd, range.start, freeze);
2614-
}
2615-
2616-
out:
2618+
split_huge_pmd_locked(vma, range.start, pmd, freeze, folio);
26172619
spin_unlock(ptl);
26182620
mmu_notifier_invalidate_range_end(&range);
26192621
}

mm/rmap.c

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1642,9 +1642,6 @@ static bool try_to_unmap_one(struct folio *folio, struct vm_area_struct *vma,
16421642
if (flags & TTU_SYNC)
16431643
pvmw.flags = PVMW_SYNC;
16441644

1645-
if (flags & TTU_SPLIT_HUGE_PMD)
1646-
split_huge_pmd_address(vma, address, false, folio);
1647-
16481645
/*
16491646
* For THP, we have to assume the worse case ie pmd for invalidation.
16501647
* For hugetlb, it could be much worse if we need to do pud
@@ -1670,9 +1667,6 @@ static bool try_to_unmap_one(struct folio *folio, struct vm_area_struct *vma,
16701667
mmu_notifier_invalidate_range_start(&range);
16711668

16721669
while (page_vma_mapped_walk(&pvmw)) {
1673-
/* Unexpected PMD-mapped THP? */
1674-
VM_BUG_ON_FOLIO(!pvmw.pte, folio);
1675-
16761670
/*
16771671
* If the folio is in an mlock()d vma, we must not swap it out.
16781672
*/
@@ -1684,6 +1678,21 @@ static bool try_to_unmap_one(struct folio *folio, struct vm_area_struct *vma,
16841678
goto walk_abort;
16851679
}
16861680

1681+
if (!pvmw.pte && (flags & TTU_SPLIT_HUGE_PMD)) {
1682+
/*
1683+
* We temporarily have to drop the PTL and start once
1684+
* again from that now-PTE-mapped page table.
1685+
*/
1686+
split_huge_pmd_locked(vma, pvmw.address, pvmw.pmd,
1687+
false, folio);
1688+
flags &= ~TTU_SPLIT_HUGE_PMD;
1689+
page_vma_mapped_walk_restart(&pvmw);
1690+
continue;
1691+
}
1692+
1693+
/* Unexpected PMD-mapped THP? */
1694+
VM_BUG_ON_FOLIO(!pvmw.pte, folio);
1695+
16871696
pfn = pte_pfn(ptep_get(pvmw.pte));
16881697
subpage = folio_page(folio, pfn - folio_pfn(folio));
16891698
address = pvmw.address;

0 commit comments

Comments
 (0)