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

mm: hugetlb_vmemmap: use walk_page_range_novma() to simplify the code

It is unnecessary to implement a series of dedicated page table walking
helpers since there is already a general one walk_page_range_novma(). So
use it to simplify the code.

Link: https://lkml.kernel.org/r/20231127084645.27017-3-songmuchun@bytedance.com
Signed-off-by: Muchun Song <songmuchun@bytedance.com>
Reviewed-by: Mike Kravetz <mike.kravetz@oracle.com>
Cc: Kefeng Wang <wangkefeng.wang@huawei.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>

authored by

Muchun Song and committed by
Andrew Morton
fb93ed63 b123d093

+43 -113
+43 -113
mm/hugetlb_vmemmap.c
··· 14 14 #include <linux/moduleparam.h> 15 15 #include <linux/bootmem_info.h> 16 16 #include <linux/mmdebug.h> 17 + #include <linux/pagewalk.h> 17 18 #include <asm/pgalloc.h> 18 19 #include <asm/tlbflush.h> 19 20 #include "hugetlb_vmemmap.h" ··· 46 45 unsigned long flags; 47 46 }; 48 47 49 - static int split_vmemmap_huge_pmd(pmd_t *pmd, unsigned long start, bool flush) 48 + static int vmemmap_split_pmd(pmd_t *pmd, struct page *head, unsigned long start, 49 + struct vmemmap_remap_walk *walk) 50 50 { 51 51 pmd_t __pmd; 52 52 int i; 53 53 unsigned long addr = start; 54 - struct page *head; 55 54 pte_t *pgtable; 56 - 57 - spin_lock(&init_mm.page_table_lock); 58 - head = pmd_leaf(*pmd) ? pmd_page(*pmd) : NULL; 59 - spin_unlock(&init_mm.page_table_lock); 60 - 61 - if (!head) 62 - return 0; 63 55 64 56 pgtable = pte_alloc_one_kernel(&init_mm); 65 57 if (!pgtable) ··· 82 88 /* Make pte visible before pmd. See comment in pmd_install(). */ 83 89 smp_wmb(); 84 90 pmd_populate_kernel(&init_mm, pmd, pgtable); 85 - if (flush) 91 + if (!(walk->flags & VMEMMAP_SPLIT_NO_TLB_FLUSH)) 86 92 flush_tlb_kernel_range(start, start + PMD_SIZE); 87 93 } else { 88 94 pte_free_kernel(&init_mm, pgtable); ··· 92 98 return 0; 93 99 } 94 100 95 - static void vmemmap_pte_range(pmd_t *pmd, unsigned long addr, 96 - unsigned long end, 97 - struct vmemmap_remap_walk *walk) 101 + static int vmemmap_pmd_entry(pmd_t *pmd, unsigned long addr, 102 + unsigned long next, struct mm_walk *walk) 98 103 { 99 - pte_t *pte = pte_offset_kernel(pmd, addr); 104 + struct page *head; 105 + struct vmemmap_remap_walk *vmemmap_walk = walk->private; 106 + 107 + /* Only splitting, not remapping the vmemmap pages. */ 108 + if (!vmemmap_walk->remap_pte) 109 + walk->action = ACTION_CONTINUE; 110 + 111 + spin_lock(&init_mm.page_table_lock); 112 + head = pmd_leaf(*pmd) ? pmd_page(*pmd) : NULL; 113 + spin_unlock(&init_mm.page_table_lock); 114 + if (!head) 115 + return 0; 116 + 117 + return vmemmap_split_pmd(pmd, head, addr & PMD_MASK, vmemmap_walk); 118 + } 119 + 120 + static int vmemmap_pte_entry(pte_t *pte, unsigned long addr, 121 + unsigned long next, struct mm_walk *walk) 122 + { 123 + struct vmemmap_remap_walk *vmemmap_walk = walk->private; 100 124 101 125 /* 102 - * The reuse_page is found 'first' in table walk before we start 103 - * remapping (which is calling @walk->remap_pte). 126 + * The reuse_page is found 'first' in page table walking before 127 + * starting remapping. 104 128 */ 105 - if (!walk->reuse_page) { 106 - walk->reuse_page = pte_page(ptep_get(pte)); 107 - /* 108 - * Because the reuse address is part of the range that we are 109 - * walking, skip the reuse address range. 110 - */ 111 - addr += PAGE_SIZE; 112 - pte++; 113 - walk->nr_walked++; 114 - } 115 - 116 - for (; addr != end; addr += PAGE_SIZE, pte++) { 117 - walk->remap_pte(pte, addr, walk); 118 - walk->nr_walked++; 119 - } 120 - } 121 - 122 - static int vmemmap_pmd_range(pud_t *pud, unsigned long addr, 123 - unsigned long end, 124 - struct vmemmap_remap_walk *walk) 125 - { 126 - pmd_t *pmd; 127 - unsigned long next; 128 - 129 - pmd = pmd_offset(pud, addr); 130 - do { 131 - int ret; 132 - 133 - ret = split_vmemmap_huge_pmd(pmd, addr & PMD_MASK, 134 - !(walk->flags & VMEMMAP_SPLIT_NO_TLB_FLUSH)); 135 - if (ret) 136 - return ret; 137 - 138 - next = pmd_addr_end(addr, end); 139 - 140 - /* 141 - * We are only splitting, not remapping the hugetlb vmemmap 142 - * pages. 143 - */ 144 - if (!walk->remap_pte) 145 - continue; 146 - 147 - vmemmap_pte_range(pmd, addr, next, walk); 148 - } while (pmd++, addr = next, addr != end); 129 + if (!vmemmap_walk->reuse_page) 130 + vmemmap_walk->reuse_page = pte_page(ptep_get(pte)); 131 + else 132 + vmemmap_walk->remap_pte(pte, addr, vmemmap_walk); 133 + vmemmap_walk->nr_walked++; 149 134 150 135 return 0; 151 136 } 152 137 153 - static int vmemmap_pud_range(p4d_t *p4d, unsigned long addr, 154 - unsigned long end, 155 - struct vmemmap_remap_walk *walk) 156 - { 157 - pud_t *pud; 158 - unsigned long next; 159 - 160 - pud = pud_offset(p4d, addr); 161 - do { 162 - int ret; 163 - 164 - next = pud_addr_end(addr, end); 165 - ret = vmemmap_pmd_range(pud, addr, next, walk); 166 - if (ret) 167 - return ret; 168 - } while (pud++, addr = next, addr != end); 169 - 170 - return 0; 171 - } 172 - 173 - static int vmemmap_p4d_range(pgd_t *pgd, unsigned long addr, 174 - unsigned long end, 175 - struct vmemmap_remap_walk *walk) 176 - { 177 - p4d_t *p4d; 178 - unsigned long next; 179 - 180 - p4d = p4d_offset(pgd, addr); 181 - do { 182 - int ret; 183 - 184 - next = p4d_addr_end(addr, end); 185 - ret = vmemmap_pud_range(p4d, addr, next, walk); 186 - if (ret) 187 - return ret; 188 - } while (p4d++, addr = next, addr != end); 189 - 190 - return 0; 191 - } 138 + static const struct mm_walk_ops vmemmap_remap_ops = { 139 + .pmd_entry = vmemmap_pmd_entry, 140 + .pte_entry = vmemmap_pte_entry, 141 + }; 192 142 193 143 static int vmemmap_remap_range(unsigned long start, unsigned long end, 194 144 struct vmemmap_remap_walk *walk) 195 145 { 196 - unsigned long addr = start; 197 - unsigned long next; 198 - pgd_t *pgd; 146 + int ret; 199 147 200 - VM_BUG_ON(!PAGE_ALIGNED(start)); 201 - VM_BUG_ON(!PAGE_ALIGNED(end)); 148 + VM_BUG_ON(!PAGE_ALIGNED(start | end)); 202 149 203 - pgd = pgd_offset_k(addr); 204 - do { 205 - int ret; 206 - 207 - next = pgd_addr_end(addr, end); 208 - ret = vmemmap_p4d_range(pgd, addr, next, walk); 209 - if (ret) 210 - return ret; 211 - } while (pgd++, addr = next, addr != end); 150 + ret = walk_page_range_novma(&init_mm, start, end, &vmemmap_remap_ops, 151 + NULL, walk); 152 + if (ret) 153 + return ret; 212 154 213 155 if (walk->remap_pte && !(walk->flags & VMEMMAP_REMAP_NO_TLB_FLUSH)) 214 156 flush_tlb_kernel_range(start, end);