Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

mm: pgtable: introduce pagetable_dtor()

The pagetable_p*_dtor() are exactly the same except for the handling of
ptlock. If we make ptlock_free() handle the case where ptdesc->ptl is
NULL and remove VM_BUG_ON_PAGE() from pmd_ptlock_free(), we can unify
pagetable_p*_dtor() into one function. Let's introduce pagetable_dtor()
to do this.

Later, pagetable_dtor() will be moved to tlb_remove_ptdesc(), so that
ptlock and page table pages can be freed together (regardless of whether
RCU is used). This prevents the use-after-free problem where the ptlock
is freed immediately but the page table pages is freed later via RCU.

Link: https://lkml.kernel.org/r/47f44fff9dc68d9d9e9a0d6c036df275f820598a.1736317725.git.zhengqi.arch@bytedance.com
Signed-off-by: Qi Zheng <zhengqi.arch@bytedance.com>
Originally-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Reviewed-by: Kevin Brodsky <kevin.brodsky@arm.com>
Acked-by: Alexander Gordeev <agordeev@linux.ibm.com> [s390]
Cc: Alexandre Ghiti <alex@ghiti.fr>
Cc: Alexandre Ghiti <alexghiti@rivosinc.com>
Cc: Andreas Larsson <andreas@gaisler.com>
Cc: Aneesh Kumar K.V (Arm) <aneesh.kumar@kernel.org>
Cc: Arnd Bergmann <arnd@arndb.de>
Cc: Dave Hansen <dave.hansen@linux.intel.com>
Cc: David Hildenbrand <david@redhat.com>
Cc: David Rientjes <rientjes@google.com>
Cc: Hugh Dickins <hughd@google.com>
Cc: Jann Horn <jannh@google.com>
Cc: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
Cc: Matthew Wilcox (Oracle) <willy@infradead.org>
Cc: Mike Rapoport (Microsoft) <rppt@kernel.org>
Cc: Muchun Song <muchun.song@linux.dev>
Cc: Nicholas Piggin <npiggin@gmail.com>
Cc: Palmer Dabbelt <palmer@dabbelt.com>
Cc: Ryan Roberts <ryan.roberts@arm.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Vishal Moola (Oracle) <vishal.moola@gmail.com>
Cc: Will Deacon <will@kernel.org>
Cc: Yu Zhao <yuzhao@google.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>

authored by

Qi Zheng and committed by
Andrew Morton
db6b435d b7dcd539

+62 -95
+2 -2
Documentation/mm/split_page_table_lock.rst
··· 62 62 =================================================== 63 63 64 64 There's no need in special enabling of PTE split page table lock: everything 65 - required is done by pagetable_pte_ctor() and pagetable_pte_dtor(), which 65 + required is done by pagetable_pte_ctor() and pagetable_dtor(), which 66 66 must be called on PTE table allocation / freeing. 67 67 68 68 Make sure the architecture doesn't use slab allocator for page table ··· 73 73 levels. 74 74 75 75 PMD split lock enabling requires pagetable_pmd_ctor() call on PMD table 76 - allocation and pagetable_pmd_dtor() on freeing. 76 + allocation and pagetable_dtor() on freeing. 77 77 78 78 Allocation usually happens in pmd_alloc_one(), freeing in pmd_free() and 79 79 pmd_free_tlb(), but make sure you cover all PMD table allocation / freeing
+2 -2
arch/arm/include/asm/tlb.h
··· 41 41 { 42 42 struct ptdesc *ptdesc = page_ptdesc(pte); 43 43 44 - pagetable_pte_dtor(ptdesc); 44 + pagetable_dtor(ptdesc); 45 45 46 46 #ifndef CONFIG_ARM_LPAE 47 47 /* ··· 61 61 #ifdef CONFIG_ARM_LPAE 62 62 struct ptdesc *ptdesc = virt_to_ptdesc(pmdp); 63 63 64 - pagetable_pmd_dtor(ptdesc); 64 + pagetable_dtor(ptdesc); 65 65 tlb_remove_ptdesc(tlb, ptdesc); 66 66 #endif 67 67 }
+4 -4
arch/arm64/include/asm/tlb.h
··· 82 82 { 83 83 struct ptdesc *ptdesc = page_ptdesc(pte); 84 84 85 - pagetable_pte_dtor(ptdesc); 85 + pagetable_dtor(ptdesc); 86 86 tlb_remove_ptdesc(tlb, ptdesc); 87 87 } 88 88 ··· 92 92 { 93 93 struct ptdesc *ptdesc = virt_to_ptdesc(pmdp); 94 94 95 - pagetable_pmd_dtor(ptdesc); 95 + pagetable_dtor(ptdesc); 96 96 tlb_remove_ptdesc(tlb, ptdesc); 97 97 } 98 98 #endif ··· 106 106 if (!pgtable_l4_enabled()) 107 107 return; 108 108 109 - pagetable_pud_dtor(ptdesc); 109 + pagetable_dtor(ptdesc); 110 110 tlb_remove_ptdesc(tlb, ptdesc); 111 111 } 112 112 #endif ··· 120 120 if (!pgtable_l5_enabled()) 121 121 return; 122 122 123 - pagetable_p4d_dtor(ptdesc); 123 + pagetable_dtor(ptdesc); 124 124 tlb_remove_ptdesc(tlb, ptdesc); 125 125 } 126 126 #endif
+1 -1
arch/csky/include/asm/pgalloc.h
··· 63 63 64 64 #define __pte_free_tlb(tlb, pte, address) \ 65 65 do { \ 66 - pagetable_pte_dtor(page_ptdesc(pte)); \ 66 + pagetable_dtor(page_ptdesc(pte)); \ 67 67 tlb_remove_page_ptdesc(tlb, page_ptdesc(pte)); \ 68 68 } while (0) 69 69
+1 -1
arch/hexagon/include/asm/pgalloc.h
··· 89 89 90 90 #define __pte_free_tlb(tlb, pte, addr) \ 91 91 do { \ 92 - pagetable_pte_dtor((page_ptdesc(pte))); \ 92 + pagetable_dtor((page_ptdesc(pte))); \ 93 93 tlb_remove_page_ptdesc((tlb), (page_ptdesc(pte))); \ 94 94 } while (0) 95 95
+1 -1
arch/loongarch/include/asm/pgalloc.h
··· 57 57 58 58 #define __pte_free_tlb(tlb, pte, address) \ 59 59 do { \ 60 - pagetable_pte_dtor(page_ptdesc(pte)); \ 60 + pagetable_dtor(page_ptdesc(pte)); \ 61 61 tlb_remove_page_ptdesc((tlb), page_ptdesc(pte)); \ 62 62 } while (0) 63 63
+2 -2
arch/m68k/include/asm/mcf_pgalloc.h
··· 37 37 { 38 38 struct ptdesc *ptdesc = virt_to_ptdesc(pgtable); 39 39 40 - pagetable_pte_dtor(ptdesc); 40 + pagetable_dtor(ptdesc); 41 41 pagetable_free(ptdesc); 42 42 } 43 43 ··· 61 61 { 62 62 struct ptdesc *ptdesc = virt_to_ptdesc(pgtable); 63 63 64 - pagetable_pte_dtor(ptdesc); 64 + pagetable_dtor(ptdesc); 65 65 pagetable_free(ptdesc); 66 66 } 67 67
+1 -1
arch/m68k/include/asm/sun3_pgalloc.h
··· 19 19 20 20 #define __pte_free_tlb(tlb, pte, addr) \ 21 21 do { \ 22 - pagetable_pte_dtor(page_ptdesc(pte)); \ 22 + pagetable_dtor(page_ptdesc(pte)); \ 23 23 tlb_remove_page_ptdesc((tlb), page_ptdesc(pte)); \ 24 24 } while (0) 25 25
+1 -1
arch/m68k/mm/motorola.c
··· 201 201 list_del(dp); 202 202 mmu_page_dtor((void *)page); 203 203 if (type == TABLE_PTE) 204 - pagetable_pte_dtor(virt_to_ptdesc((void *)page)); 204 + pagetable_dtor(virt_to_ptdesc((void *)page)); 205 205 free_page (page); 206 206 return 1; 207 207 } else if (ptable_list[type].next != dp) {
+1 -1
arch/mips/include/asm/pgalloc.h
··· 56 56 57 57 #define __pte_free_tlb(tlb, pte, address) \ 58 58 do { \ 59 - pagetable_pte_dtor(page_ptdesc(pte)); \ 59 + pagetable_dtor(page_ptdesc(pte)); \ 60 60 tlb_remove_page_ptdesc((tlb), page_ptdesc(pte)); \ 61 61 } while (0) 62 62
+1 -1
arch/nios2/include/asm/pgalloc.h
··· 30 30 31 31 #define __pte_free_tlb(tlb, pte, addr) \ 32 32 do { \ 33 - pagetable_pte_dtor(page_ptdesc(pte)); \ 33 + pagetable_dtor(page_ptdesc(pte)); \ 34 34 tlb_remove_page_ptdesc((tlb), (page_ptdesc(pte))); \ 35 35 } while (0) 36 36
+1 -1
arch/openrisc/include/asm/pgalloc.h
··· 68 68 69 69 #define __pte_free_tlb(tlb, pte, addr) \ 70 70 do { \ 71 - pagetable_pte_dtor(page_ptdesc(pte)); \ 71 + pagetable_dtor(page_ptdesc(pte)); \ 72 72 tlb_remove_page_ptdesc((tlb), (page_ptdesc(pte))); \ 73 73 } while (0) 74 74
+1 -1
arch/powerpc/mm/book3s64/mmu_context.c
··· 253 253 count = ((unsigned long)pmd_frag & ~PAGE_MASK) >> PMD_FRAG_SIZE_SHIFT; 254 254 /* We allow PTE_FRAG_NR fragments from a PTE page */ 255 255 if (atomic_sub_and_test(PMD_FRAG_NR - count, &ptdesc->pt_frag_refcount)) { 256 - pagetable_pmd_dtor(ptdesc); 256 + pagetable_dtor(ptdesc); 257 257 pagetable_free(ptdesc); 258 258 } 259 259 }
+1 -1
arch/powerpc/mm/book3s64/pgtable.c
··· 477 477 478 478 BUG_ON(atomic_read(&ptdesc->pt_frag_refcount) <= 0); 479 479 if (atomic_dec_and_test(&ptdesc->pt_frag_refcount)) { 480 - pagetable_pmd_dtor(ptdesc); 480 + pagetable_dtor(ptdesc); 481 481 pagetable_free(ptdesc); 482 482 } 483 483 }
+2 -2
arch/powerpc/mm/pgtable-frag.c
··· 25 25 count = ((unsigned long)pte_frag & ~PAGE_MASK) >> PTE_FRAG_SIZE_SHIFT; 26 26 /* We allow PTE_FRAG_NR fragments from a PTE page */ 27 27 if (atomic_sub_and_test(PTE_FRAG_NR - count, &ptdesc->pt_frag_refcount)) { 28 - pagetable_pte_dtor(ptdesc); 28 + pagetable_dtor(ptdesc); 29 29 pagetable_free(ptdesc); 30 30 } 31 31 } ··· 111 111 struct ptdesc *ptdesc; 112 112 113 113 ptdesc = container_of(head, struct ptdesc, pt_rcu_head); 114 - pagetable_pte_dtor(ptdesc); 114 + pagetable_dtor(ptdesc); 115 115 pagetable_free(ptdesc); 116 116 } 117 117
+4 -4
arch/riscv/include/asm/pgalloc.h
··· 100 100 if (pgtable_l4_enabled) { 101 101 struct ptdesc *ptdesc = virt_to_ptdesc(pud); 102 102 103 - pagetable_pud_dtor(ptdesc); 103 + pagetable_dtor(ptdesc); 104 104 riscv_tlb_remove_ptdesc(tlb, ptdesc); 105 105 } 106 106 } ··· 111 111 if (pgtable_l5_enabled) { 112 112 struct ptdesc *ptdesc = virt_to_ptdesc(p4d); 113 113 114 - pagetable_p4d_dtor(ptdesc); 114 + pagetable_dtor(ptdesc); 115 115 riscv_tlb_remove_ptdesc(tlb, virt_to_ptdesc(p4d)); 116 116 } 117 117 } ··· 144 144 { 145 145 struct ptdesc *ptdesc = virt_to_ptdesc(pmd); 146 146 147 - pagetable_pmd_dtor(ptdesc); 147 + pagetable_dtor(ptdesc); 148 148 riscv_tlb_remove_ptdesc(tlb, ptdesc); 149 149 } 150 150 ··· 155 155 { 156 156 struct ptdesc *ptdesc = page_ptdesc(pte); 157 157 158 - pagetable_pte_dtor(ptdesc); 158 + pagetable_dtor(ptdesc); 159 159 riscv_tlb_remove_ptdesc(tlb, ptdesc); 160 160 } 161 161 #endif /* CONFIG_MMU */
+2 -2
arch/riscv/mm/init.c
··· 1558 1558 return; 1559 1559 } 1560 1560 1561 - pagetable_pte_dtor(ptdesc); 1561 + pagetable_dtor(ptdesc); 1562 1562 if (PageReserved(page)) 1563 1563 free_reserved_page(page); 1564 1564 else ··· 1580 1580 } 1581 1581 1582 1582 if (!is_vmemmap) 1583 - pagetable_pmd_dtor(ptdesc); 1583 + pagetable_dtor(ptdesc); 1584 1584 if (PageReserved(page)) 1585 1585 free_reserved_page(page); 1586 1586 else
+3 -3
arch/s390/include/asm/pgalloc.h
··· 66 66 if (mm_p4d_folded(mm)) 67 67 return; 68 68 69 - pagetable_p4d_dtor(virt_to_ptdesc(p4d)); 69 + pagetable_dtor(virt_to_ptdesc(p4d)); 70 70 crst_table_free(mm, (unsigned long *) p4d); 71 71 } 72 72 ··· 87 87 if (mm_pud_folded(mm)) 88 88 return; 89 89 90 - pagetable_pud_dtor(virt_to_ptdesc(pud)); 90 + pagetable_dtor(virt_to_ptdesc(pud)); 91 91 crst_table_free(mm, (unsigned long *) pud); 92 92 } 93 93 ··· 109 109 { 110 110 if (mm_pmd_folded(mm)) 111 111 return; 112 - pagetable_pmd_dtor(virt_to_ptdesc(pmd)); 112 + pagetable_dtor(virt_to_ptdesc(pmd)); 113 113 crst_table_free(mm, (unsigned long *) pmd); 114 114 } 115 115
+3 -3
arch/s390/include/asm/tlb.h
··· 102 102 { 103 103 if (mm_pmd_folded(tlb->mm)) 104 104 return; 105 - pagetable_pmd_dtor(virt_to_ptdesc(pmd)); 105 + pagetable_dtor(virt_to_ptdesc(pmd)); 106 106 __tlb_adjust_range(tlb, address, PAGE_SIZE); 107 107 tlb->mm->context.flush_mm = 1; 108 108 tlb->freed_tables = 1; ··· 122 122 { 123 123 if (mm_p4d_folded(tlb->mm)) 124 124 return; 125 - pagetable_p4d_dtor(virt_to_ptdesc(p4d)); 125 + pagetable_dtor(virt_to_ptdesc(p4d)); 126 126 __tlb_adjust_range(tlb, address, PAGE_SIZE); 127 127 tlb->mm->context.flush_mm = 1; 128 128 tlb->freed_tables = 1; ··· 141 141 { 142 142 if (mm_pud_folded(tlb->mm)) 143 143 return; 144 - pagetable_pud_dtor(virt_to_ptdesc(pud)); 144 + pagetable_dtor(virt_to_ptdesc(pud)); 145 145 tlb->mm->context.flush_mm = 1; 146 146 tlb->freed_tables = 1; 147 147 tlb->cleared_p4ds = 1;
+1 -1
arch/s390/mm/pgalloc.c
··· 182 182 183 183 static void pagetable_pte_dtor_free(struct ptdesc *ptdesc) 184 184 { 185 - pagetable_pte_dtor(ptdesc); 185 + pagetable_dtor(ptdesc); 186 186 pagetable_free(ptdesc); 187 187 } 188 188
+1 -1
arch/sh/include/asm/pgalloc.h
··· 34 34 35 35 #define __pte_free_tlb(tlb, pte, addr) \ 36 36 do { \ 37 - pagetable_pte_dtor(page_ptdesc(pte)); \ 37 + pagetable_dtor(page_ptdesc(pte)); \ 38 38 tlb_remove_page_ptdesc((tlb), (page_ptdesc(pte))); \ 39 39 } while (0) 40 40
+1 -1
arch/sparc/mm/init_64.c
··· 2915 2915 { 2916 2916 struct ptdesc *ptdesc = virt_to_ptdesc(pte); 2917 2917 2918 - pagetable_pte_dtor(ptdesc); 2918 + pagetable_dtor(ptdesc); 2919 2919 pagetable_free(ptdesc); 2920 2920 } 2921 2921
+1 -1
arch/sparc/mm/srmmu.c
··· 372 372 page = pfn_to_page(__nocache_pa((unsigned long)ptep) >> PAGE_SHIFT); 373 373 spin_lock(&mm->page_table_lock); 374 374 if (page_ref_dec_return(page) == 1) 375 - pagetable_pte_dtor(page_ptdesc(page)); 375 + pagetable_dtor(page_ptdesc(page)); 376 376 spin_unlock(&mm->page_table_lock); 377 377 378 378 srmmu_free_nocache(ptep, SRMMU_PTE_TABLE_SIZE);
+3 -3
arch/um/include/asm/pgalloc.h
··· 27 27 28 28 #define __pte_free_tlb(tlb, pte, address) \ 29 29 do { \ 30 - pagetable_pte_dtor(page_ptdesc(pte)); \ 30 + pagetable_dtor(page_ptdesc(pte)); \ 31 31 tlb_remove_page_ptdesc((tlb), (page_ptdesc(pte))); \ 32 32 } while (0) 33 33 ··· 35 35 36 36 #define __pmd_free_tlb(tlb, pmd, address) \ 37 37 do { \ 38 - pagetable_pmd_dtor(virt_to_ptdesc(pmd)); \ 38 + pagetable_dtor(virt_to_ptdesc(pmd)); \ 39 39 tlb_remove_page_ptdesc((tlb), virt_to_ptdesc(pmd)); \ 40 40 } while (0) 41 41 ··· 43 43 44 44 #define __pud_free_tlb(tlb, pud, address) \ 45 45 do { \ 46 - pagetable_pud_dtor(virt_to_ptdesc(pud)); \ 46 + pagetable_dtor(virt_to_ptdesc(pud)); \ 47 47 tlb_remove_page_ptdesc((tlb), virt_to_ptdesc(pud)); \ 48 48 } while (0) 49 49
+6 -6
arch/x86/mm/pgtable.c
··· 60 60 61 61 void ___pte_free_tlb(struct mmu_gather *tlb, struct page *pte) 62 62 { 63 - pagetable_pte_dtor(page_ptdesc(pte)); 63 + pagetable_dtor(page_ptdesc(pte)); 64 64 paravirt_release_pte(page_to_pfn(pte)); 65 65 paravirt_tlb_remove_table(tlb, pte); 66 66 } ··· 77 77 #ifdef CONFIG_X86_PAE 78 78 tlb->need_flush_all = 1; 79 79 #endif 80 - pagetable_pmd_dtor(ptdesc); 80 + pagetable_dtor(ptdesc); 81 81 paravirt_tlb_remove_table(tlb, ptdesc_page(ptdesc)); 82 82 } 83 83 ··· 86 86 { 87 87 struct ptdesc *ptdesc = virt_to_ptdesc(pud); 88 88 89 - pagetable_pud_dtor(ptdesc); 89 + pagetable_dtor(ptdesc); 90 90 paravirt_release_pud(__pa(pud) >> PAGE_SHIFT); 91 91 paravirt_tlb_remove_table(tlb, virt_to_page(pud)); 92 92 } ··· 96 96 { 97 97 struct ptdesc *ptdesc = virt_to_ptdesc(p4d); 98 98 99 - pagetable_p4d_dtor(ptdesc); 99 + pagetable_dtor(ptdesc); 100 100 paravirt_release_p4d(__pa(p4d) >> PAGE_SHIFT); 101 101 paravirt_tlb_remove_table(tlb, virt_to_page(p4d)); 102 102 } ··· 233 233 if (pmds[i]) { 234 234 ptdesc = virt_to_ptdesc(pmds[i]); 235 235 236 - pagetable_pmd_dtor(ptdesc); 236 + pagetable_dtor(ptdesc); 237 237 pagetable_free(ptdesc); 238 238 mm_dec_nr_pmds(mm); 239 239 } ··· 867 867 868 868 free_page((unsigned long)pmd_sv); 869 869 870 - pagetable_pmd_dtor(virt_to_ptdesc(pmd)); 870 + pagetable_dtor(virt_to_ptdesc(pmd)); 871 871 free_page((unsigned long)pmd); 872 872 873 873 return 1;
+4 -4
include/asm-generic/pgalloc.h
··· 109 109 { 110 110 struct ptdesc *ptdesc = page_ptdesc(pte_page); 111 111 112 - pagetable_pte_dtor(ptdesc); 112 + pagetable_dtor(ptdesc); 113 113 pagetable_free(ptdesc); 114 114 } 115 115 ··· 153 153 struct ptdesc *ptdesc = virt_to_ptdesc(pmd); 154 154 155 155 BUG_ON((unsigned long)pmd & (PAGE_SIZE-1)); 156 - pagetable_pmd_dtor(ptdesc); 156 + pagetable_dtor(ptdesc); 157 157 pagetable_free(ptdesc); 158 158 } 159 159 #endif ··· 202 202 struct ptdesc *ptdesc = virt_to_ptdesc(pud); 203 203 204 204 BUG_ON((unsigned long)pud & (PAGE_SIZE-1)); 205 - pagetable_pud_dtor(ptdesc); 205 + pagetable_dtor(ptdesc); 206 206 pagetable_free(ptdesc); 207 207 } 208 208 ··· 248 248 struct ptdesc *ptdesc = virt_to_ptdesc(p4d); 249 249 250 250 BUG_ON((unsigned long)p4d & (PAGE_SIZE-1)); 251 - pagetable_p4d_dtor(ptdesc); 251 + pagetable_dtor(ptdesc); 252 252 pagetable_free(ptdesc); 253 253 } 254 254
+9 -43
include/linux/mm.h
··· 2992 2992 static inline void ptlock_free(struct ptdesc *ptdesc) {} 2993 2993 #endif /* defined(CONFIG_SPLIT_PTE_PTLOCKS) */ 2994 2994 2995 + static inline void pagetable_dtor(struct ptdesc *ptdesc) 2996 + { 2997 + struct folio *folio = ptdesc_folio(ptdesc); 2998 + 2999 + ptlock_free(ptdesc); 3000 + __folio_clear_pgtable(folio); 3001 + lruvec_stat_sub_folio(folio, NR_PAGETABLE); 3002 + } 3003 + 2995 3004 static inline bool pagetable_pte_ctor(struct ptdesc *ptdesc) 2996 3005 { 2997 3006 struct folio *folio = ptdesc_folio(ptdesc); ··· 3010 3001 __folio_set_pgtable(folio); 3011 3002 lruvec_stat_add_folio(folio, NR_PAGETABLE); 3012 3003 return true; 3013 - } 3014 - 3015 - static inline void pagetable_pte_dtor(struct ptdesc *ptdesc) 3016 - { 3017 - struct folio *folio = ptdesc_folio(ptdesc); 3018 - 3019 - ptlock_free(ptdesc); 3020 - __folio_clear_pgtable(folio); 3021 - lruvec_stat_sub_folio(folio, NR_PAGETABLE); 3022 3004 } 3023 3005 3024 3006 pte_t *___pte_offset_map(pmd_t *pmd, unsigned long addr, pmd_t *pmdvalp); ··· 3088 3088 return ptlock_init(ptdesc); 3089 3089 } 3090 3090 3091 - static inline void pmd_ptlock_free(struct ptdesc *ptdesc) 3092 - { 3093 - #ifdef CONFIG_TRANSPARENT_HUGEPAGE 3094 - VM_BUG_ON_PAGE(ptdesc->pmd_huge_pte, ptdesc_page(ptdesc)); 3095 - #endif 3096 - ptlock_free(ptdesc); 3097 - } 3098 - 3099 3091 #define pmd_huge_pte(mm, pmd) (pmd_ptdesc(pmd)->pmd_huge_pte) 3100 3092 3101 3093 #else ··· 3098 3106 } 3099 3107 3100 3108 static inline bool pmd_ptlock_init(struct ptdesc *ptdesc) { return true; } 3101 - static inline void pmd_ptlock_free(struct ptdesc *ptdesc) {} 3102 3109 3103 3110 #define pmd_huge_pte(mm, pmd) ((mm)->pmd_huge_pte) 3104 3111 ··· 3120 3129 ptdesc_pmd_pts_init(ptdesc); 3121 3130 lruvec_stat_add_folio(folio, NR_PAGETABLE); 3122 3131 return true; 3123 - } 3124 - 3125 - static inline void pagetable_pmd_dtor(struct ptdesc *ptdesc) 3126 - { 3127 - struct folio *folio = ptdesc_folio(ptdesc); 3128 - 3129 - pmd_ptlock_free(ptdesc); 3130 - __folio_clear_pgtable(folio); 3131 - lruvec_stat_sub_folio(folio, NR_PAGETABLE); 3132 3132 } 3133 3133 3134 3134 /* ··· 3149 3167 lruvec_stat_add_folio(folio, NR_PAGETABLE); 3150 3168 } 3151 3169 3152 - static inline void pagetable_pud_dtor(struct ptdesc *ptdesc) 3153 - { 3154 - struct folio *folio = ptdesc_folio(ptdesc); 3155 - 3156 - __folio_clear_pgtable(folio); 3157 - lruvec_stat_sub_folio(folio, NR_PAGETABLE); 3158 - } 3159 - 3160 3170 static inline void pagetable_p4d_ctor(struct ptdesc *ptdesc) 3161 3171 { 3162 3172 struct folio *folio = ptdesc_folio(ptdesc); 3163 3173 3164 3174 __folio_set_pgtable(folio); 3165 3175 lruvec_stat_add_folio(folio, NR_PAGETABLE); 3166 - } 3167 - 3168 - static inline void pagetable_p4d_dtor(struct ptdesc *ptdesc) 3169 - { 3170 - struct folio *folio = ptdesc_folio(ptdesc); 3171 - 3172 - __folio_clear_pgtable(folio); 3173 - lruvec_stat_sub_folio(folio, NR_PAGETABLE); 3174 3176 } 3175 3177 3176 3178 extern void __init pagecache_init(void);
+2 -1
mm/memory.c
··· 7031 7031 7032 7032 void ptlock_free(struct ptdesc *ptdesc) 7033 7033 { 7034 - kmem_cache_free(page_ptl_cachep, ptdesc->ptl); 7034 + if (ptdesc->ptl) 7035 + kmem_cache_free(page_ptl_cachep, ptdesc->ptl); 7035 7036 } 7036 7037 #endif 7037 7038