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

mm: thp: kill __transhuge_page_enabled()

The page fault path checks THP eligibility with __transhuge_page_enabled()
which does the similar thing as hugepage_vma_check(), so use
hugepage_vma_check() instead.

However page fault allows DAX and !anon_vma cases, so added a new flag,
in_pf, to hugepage_vma_check() to make page fault work correctly.

The in_pf flag is also used to skip shmem and file THP for page fault
since shmem handles THP in its own shmem_fault() and file THP allocation
on fault is not supported yet.

Also remove hugepage_vma_enabled() since hugepage_vma_check() is the only
caller now, it is not necessary to have a helper function.

Link: https://lkml.kernel.org/r/20220616174840.1202070-6-shy828301@gmail.com
Signed-off-by: Yang Shi <shy828301@gmail.com>
Reviewed-by: Zach O'Keefe <zokeefe@google.com>
Cc: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
Cc: Matthew Wilcox <willy@infradead.org>
Cc: Miaohe Lin <linmiaohe@huawei.com>
Cc: Vlastimil Babka <vbabka@suse.cz>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>

authored by

Yang Shi and committed by
akpm
7da4e2cb 9fec5168

+53 -74
+1 -1
fs/proc/task_mmu.c
··· 863 863 __show_smap(m, &mss, false); 864 864 865 865 seq_printf(m, "THPeligible: %d\n", 866 - hugepage_vma_check(vma, vma->vm_flags, true)); 866 + hugepage_vma_check(vma, vma->vm_flags, true, false)); 867 867 868 868 if (arch_pkeys_enabled()) 869 869 seq_printf(m, "ProtectionKey: %8u\n", vma_pkey(vma));
+2 -55
include/linux/huge_mm.h
··· 146 146 return true; 147 147 } 148 148 149 - static inline bool transhuge_vma_enabled(struct vm_area_struct *vma, 150 - unsigned long vm_flags) 151 - { 152 - /* Explicitly disabled through madvise. */ 153 - if ((vm_flags & VM_NOHUGEPAGE) || 154 - test_bit(MMF_DISABLE_THP, &vma->vm_mm->flags)) 155 - return false; 156 - return true; 157 - } 158 - 159 - /* 160 - * to be used on vmas which are known to support THP. 161 - * Use transparent_hugepage_active otherwise 162 - */ 163 - static inline bool __transparent_hugepage_enabled(struct vm_area_struct *vma) 164 - { 165 - 166 - /* 167 - * If the hardware/firmware marked hugepage support disabled. 168 - */ 169 - if (transparent_hugepage_flags & (1 << TRANSPARENT_HUGEPAGE_NEVER_DAX)) 170 - return false; 171 - 172 - if (!transhuge_vma_enabled(vma, vma->vm_flags)) 173 - return false; 174 - 175 - if (vma_is_temporary_stack(vma)) 176 - return false; 177 - 178 - if (transparent_hugepage_flags & (1 << TRANSPARENT_HUGEPAGE_FLAG)) 179 - return true; 180 - 181 - if (vma_is_dax(vma)) 182 - return true; 183 - 184 - if (transparent_hugepage_flags & 185 - (1 << TRANSPARENT_HUGEPAGE_REQ_MADV_FLAG)) 186 - return !!(vma->vm_flags & VM_HUGEPAGE); 187 - 188 - return false; 189 - } 190 - 191 149 static inline bool file_thp_enabled(struct vm_area_struct *vma) 192 150 { 193 151 struct inode *inode; ··· 162 204 163 205 bool hugepage_vma_check(struct vm_area_struct *vma, 164 206 unsigned long vm_flags, 165 - bool smaps); 207 + bool smaps, bool in_pf); 166 208 167 209 #define transparent_hugepage_use_zero_page() \ 168 210 (transparent_hugepage_flags & \ ··· 306 348 return false; 307 349 } 308 350 309 - static inline bool __transparent_hugepage_enabled(struct vm_area_struct *vma) 310 - { 311 - return false; 312 - } 313 - 314 351 static inline bool transhuge_vma_suitable(struct vm_area_struct *vma, 315 352 unsigned long addr) 316 353 { 317 354 return false; 318 355 } 319 356 320 - static inline bool transhuge_vma_enabled(struct vm_area_struct *vma, 321 - unsigned long vm_flags) 322 - { 323 - return false; 324 - } 325 - 326 357 static inline bool hugepage_vma_check(struct vm_area_struct *vma, 327 358 unsigned long vm_flags, 328 - bool smaps) 359 + bool smaps, bool in_pf) 329 360 { 330 361 return false; 331 362 }
+41 -12
mm/huge_memory.c
··· 71 71 72 72 bool hugepage_vma_check(struct vm_area_struct *vma, 73 73 unsigned long vm_flags, 74 - bool smaps) 74 + bool smaps, bool in_pf) 75 75 { 76 76 if (!vma->vm_mm) /* vdso */ 77 77 return false; 78 78 79 - if (!transhuge_vma_enabled(vma, vm_flags)) 79 + /* 80 + * Explicitly disabled through madvise or prctl, or some 81 + * architectures may disable THP for some mappings, for 82 + * example, s390 kvm. 83 + * */ 84 + if ((vm_flags & VM_NOHUGEPAGE) || 85 + test_bit(MMF_DISABLE_THP, &vma->vm_mm->flags)) 86 + return false; 87 + /* 88 + * If the hardware/firmware marked hugepage support disabled. 89 + */ 90 + if (transparent_hugepage_flags & (1 << TRANSPARENT_HUGEPAGE_NEVER_DAX)) 80 91 return false; 81 92 93 + /* khugepaged doesn't collapse DAX vma, but page fault is fine. */ 94 + if (vma_is_dax(vma)) 95 + return in_pf; 96 + 97 + /* 98 + * Special VMA and hugetlb VMA. 99 + * Must be checked after dax since some dax mappings may have 100 + * VM_MIXEDMAP set. 101 + */ 82 102 if (vm_flags & VM_NO_KHUGEPAGED) 83 103 return false; 84 104 85 - /* Don't run khugepaged against DAX vma */ 86 - if (vma_is_dax(vma)) 105 + /* 106 + * Check alignment for file vma and size for both file and anon vma. 107 + * 108 + * Skip the check for page fault. Huge fault does the check in fault 109 + * handlers. And this check is not suitable for huge PUD fault. 110 + */ 111 + if (!in_pf && 112 + !transhuge_vma_suitable(vma, (vma->vm_end - HPAGE_PMD_SIZE))) 87 113 return false; 88 114 89 - /* Check alignment for file vma and size for both file and anon vma */ 90 - if (!transhuge_vma_suitable(vma, (vma->vm_end - HPAGE_PMD_SIZE))) 91 - return false; 92 - 93 - /* Enabled via shmem mount options or sysfs settings. */ 94 - if (shmem_file(vma->vm_file)) 115 + /* 116 + * Enabled via shmem mount options or sysfs settings. 117 + * Must be done before hugepage flags check since shmem has its 118 + * own flags. 119 + */ 120 + if (!in_pf && shmem_file(vma->vm_file)) 95 121 return shmem_huge_enabled(vma); 96 122 97 123 if (!khugepaged_enabled()) ··· 128 102 return false; 129 103 130 104 /* Only regular file is valid */ 131 - if (file_thp_enabled(vma)) 105 + if (!in_pf && file_thp_enabled(vma)) 132 106 return true; 133 107 134 108 if (!vma_is_anonymous(vma)) ··· 140 114 /* 141 115 * THPeligible bit of smaps should show 1 for proper VMAs even 142 116 * though anon_vma is not initialized yet. 117 + * 118 + * Allow page fault since anon_vma may be not initialized until 119 + * the first page fault. 143 120 */ 144 121 if (!vma->anon_vma) 145 - return smaps; 122 + return (smaps || in_pf); 146 123 147 124 return true; 148 125 }
+4 -4
mm/khugepaged.c
··· 466 466 { 467 467 if (!test_bit(MMF_VM_HUGEPAGE, &vma->vm_mm->flags) && 468 468 khugepaged_enabled()) { 469 - if (hugepage_vma_check(vma, vm_flags, false)) 469 + if (hugepage_vma_check(vma, vm_flags, false, false)) 470 470 __khugepaged_enter(vma->vm_mm); 471 471 } 472 472 } ··· 916 916 917 917 if (!transhuge_vma_suitable(vma, address)) 918 918 return SCAN_ADDRESS_RANGE; 919 - if (!hugepage_vma_check(vma, vma->vm_flags, false)) 919 + if (!hugepage_vma_check(vma, vma->vm_flags, false, false)) 920 920 return SCAN_VMA_CHECK; 921 921 /* 922 922 * Anon VMA expected, the address may be unmapped then ··· 1401 1401 * the valid THP. Add extra VM_HUGEPAGE so hugepage_vma_check() 1402 1402 * will not fail the vma for missing VM_HUGEPAGE 1403 1403 */ 1404 - if (!hugepage_vma_check(vma, vma->vm_flags | VM_HUGEPAGE, false)) 1404 + if (!hugepage_vma_check(vma, vma->vm_flags | VM_HUGEPAGE, false, false)) 1405 1405 return; 1406 1406 1407 1407 /* Keep pmd pgtable for uffd-wp; see comment in retract_page_tables() */ ··· 2091 2091 progress++; 2092 2092 break; 2093 2093 } 2094 - if (!hugepage_vma_check(vma, vma->vm_flags, false)) { 2094 + if (!hugepage_vma_check(vma, vma->vm_flags, false, false)) { 2095 2095 skip: 2096 2096 progress++; 2097 2097 continue;
+5 -2
mm/memory.c
··· 4970 4970 .gfp_mask = __get_fault_gfp_mask(vma), 4971 4971 }; 4972 4972 struct mm_struct *mm = vma->vm_mm; 4973 + unsigned long vm_flags = vma->vm_flags; 4973 4974 pgd_t *pgd; 4974 4975 p4d_t *p4d; 4975 4976 vm_fault_t ret; ··· 4984 4983 if (!vmf.pud) 4985 4984 return VM_FAULT_OOM; 4986 4985 retry_pud: 4987 - if (pud_none(*vmf.pud) && __transparent_hugepage_enabled(vma)) { 4986 + if (pud_none(*vmf.pud) && 4987 + hugepage_vma_check(vma, vm_flags, false, true)) { 4988 4988 ret = create_huge_pud(&vmf); 4989 4989 if (!(ret & VM_FAULT_FALLBACK)) 4990 4990 return ret; ··· 5018 5016 if (pud_trans_unstable(vmf.pud)) 5019 5017 goto retry_pud; 5020 5018 5021 - if (pmd_none(*vmf.pmd) && __transparent_hugepage_enabled(vma)) { 5019 + if (pmd_none(*vmf.pmd) && 5020 + hugepage_vma_check(vma, vm_flags, false, true)) { 5022 5021 ret = create_huge_pmd(&vmf); 5023 5022 if (!(ret & VM_FAULT_FALLBACK)) 5024 5023 return ret;