From: Zi Yan <[email protected]>

Preallocated 513 (1 PMD and 512 PTE) page table pages need to be freed
when PUD THP is removed. zap_pud_deposited_table is added to perform the
action.

Signed-off-by: Zi Yan <[email protected]>
---
 mm/huge_memory.c | 48 +++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 45 insertions(+), 3 deletions(-)

diff --git a/mm/huge_memory.c b/mm/huge_memory.c
index ea9fbedcda26..76069affebef 100644
--- a/mm/huge_memory.c
+++ b/mm/huge_memory.c
@@ -2013,11 +2013,27 @@ spinlock_t *__pud_trans_huge_lock(pud_t *pud, struct 
vm_area_struct *vma)
 }
 
 #ifdef CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD
+static inline void zap_pud_deposited_table(struct mm_struct *mm, pud_t *pud)
+{
+       pgtable_t pgtable;
+       int i;
+
+       pgtable = pgtable_trans_huge_pud_withdraw(mm, pud);
+       pmd_free_page_with_ptes(mm, (pmd_t *)page_address(pgtable));
+
+       mm_dec_nr_pmds(mm);
+       for (i = 0; i < (1<<(HPAGE_PUD_ORDER - HPAGE_PMD_ORDER)); i++)
+               mm_dec_nr_ptes(mm);
+}
+
 int zap_huge_pud(struct mmu_gather *tlb, struct vm_area_struct *vma,
                 pud_t *pud, unsigned long addr)
 {
+       pud_t orig_pud;
        spinlock_t *ptl;
 
+       tlb_change_page_size(tlb, HPAGE_PUD_SIZE);
+
        ptl = __pud_trans_huge_lock(pud, vma);
        if (!ptl)
                return 0;
@@ -2027,14 +2043,40 @@ int zap_huge_pud(struct mmu_gather *tlb, struct 
vm_area_struct *vma,
         * pgtable_trans_huge_withdraw after finishing pudp related
         * operations.
         */
-       pudp_huge_get_and_clear_full(tlb->mm, addr, pud, tlb->fullmm);
+       orig_pud = pudp_huge_get_and_clear_full(tlb->mm, addr, pud,
+                       tlb->fullmm);
        tlb_remove_pud_tlb_entry(tlb, pud, addr);
        if (vma_is_special_huge(vma)) {
                spin_unlock(ptl);
                /* No zero page support yet */
+       } else if (is_huge_zero_pud(orig_pud)) {
+               zap_pud_deposited_table(tlb->mm, pud);
+               spin_unlock(ptl);
+               tlb_remove_page_size(tlb, pud_page(orig_pud), HPAGE_PUD_SIZE);
        } else {
-               /* No support for anonymous PUD pages yet */
-               BUG();
+               struct page *page = NULL;
+               int flush_needed = 1;
+
+               if (pud_present(orig_pud)) {
+                       page = pud_page(orig_pud);
+                       page_remove_rmap(page, true);
+                       VM_BUG_ON_PAGE(page_mapcount(page) < 0, page);
+                       VM_BUG_ON_PAGE(!PageHead(page), page);
+               } else
+                       WARN_ONCE(1, "Non present huge pmd without pmd 
migration enabled!");
+
+               if (PageAnon(page)) {
+                       zap_pud_deposited_table(tlb->mm, pud);
+                       add_mm_counter(tlb->mm, MM_ANONPAGES, -HPAGE_PUD_NR);
+               } else {
+                       if (arch_needs_pgtable_deposit())
+                               zap_pud_deposited_table(tlb->mm, pud);
+                       add_mm_counter(tlb->mm, MM_FILEPAGES, -HPAGE_PUD_NR);
+               }
+
+               spin_unlock(ptl);
+               if (flush_needed)
+                       tlb_remove_page_size(tlb, page, HPAGE_PUD_SIZE);
        }
        return 1;
 }
-- 
2.28.0

Reply via email to