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

arch: fix has_transparent_hugepage()

I've just discovered that the useful-sounding has_transparent_hugepage()
is actually an architecture-dependent minefield: on some arches it only
builds if CONFIG_TRANSPARENT_HUGEPAGE=y, on others it's also there when
not, but on some of those (arm and arm64) it then gives the wrong
answer; and on mips alone it's marked __init, which would crash if
called later (but so far it has not been called later).

Straighten this out: make it available to all configs, with a sensible
default in asm-generic/pgtable.h, removing its definitions from those
arches (arc, arm, arm64, sparc, tile) which are served by the default,
adding #define has_transparent_hugepage has_transparent_hugepage to
those (mips, powerpc, s390, x86) which need to override the default at
runtime, and removing the __init from mips (but maybe that kind of code
should be avoided after init: set a static variable the first time it's
called).

Signed-off-by: Hugh Dickins <hughd@google.com>
Cc: "Kirill A. Shutemov" <kirill.shutemov@linux.intel.com>
Cc: Andrea Arcangeli <aarcange@redhat.com>
Cc: Andres Lagar-Cavilla <andreslc@google.com>
Cc: Yang Shi <yang.shi@linaro.org>
Cc: Ning Qu <quning@gmail.com>
Cc: Mel Gorman <mgorman@techsingularity.net>
Cc: Konstantin Khlebnikov <koct9i@gmail.com>
Acked-by: David S. Miller <davem@davemloft.net>
Acked-by: Vineet Gupta <vgupta@synopsys.com> [arch/arc]
Acked-by: Gerald Schaefer <gerald.schaefer@de.ibm.com> [arch/s390]
Acked-by: Ingo Molnar <mingo@kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Hugh Dickins and committed by
Linus Torvalds
fd8cfd30 1d069b7d

+23 -26
-2
arch/arc/include/asm/hugepage.h
··· 61 61 extern void update_mmu_cache_pmd(struct vm_area_struct *vma, unsigned long addr, 62 62 pmd_t *pmd); 63 63 64 - #define has_transparent_hugepage() 1 65 - 66 64 /* Generic variants assume pgtable_t is struct page *, hence need for these */ 67 65 #define __HAVE_ARCH_PGTABLE_DEPOSIT 68 66 extern void pgtable_trans_huge_deposit(struct mm_struct *mm, pmd_t *pmdp,
-5
arch/arm/include/asm/pgtable-3level.h
··· 281 281 flush_pmd_entry(pmdp); 282 282 } 283 283 284 - static inline int has_transparent_hugepage(void) 285 - { 286 - return 1; 287 - } 288 - 289 284 #endif /* __ASSEMBLY__ */ 290 285 291 286 #endif /* _ASM_PGTABLE_3LEVEL_H */
-5
arch/arm64/include/asm/pgtable.h
··· 314 314 315 315 #define set_pmd_at(mm, addr, pmdp, pmd) set_pte_at(mm, addr, (pte_t *)pmdp, pmd_pte(pmd)) 316 316 317 - static inline int has_transparent_hugepage(void) 318 - { 319 - return 1; 320 - } 321 - 322 317 #define __pgprot_modify(prot,mask,bits) \ 323 318 __pgprot((pgprot_val(prot) & ~(mask)) | (bits)) 324 319
+1
arch/mips/include/asm/pgtable.h
··· 468 468 469 469 #ifdef CONFIG_TRANSPARENT_HUGEPAGE 470 470 471 + #define has_transparent_hugepage has_transparent_hugepage 471 472 extern int has_transparent_hugepage(void); 472 473 473 474 static inline int pmd_trans_huge(pmd_t pmd)
+11 -10
arch/mips/mm/tlb-r4k.c
··· 400 400 401 401 #ifdef CONFIG_TRANSPARENT_HUGEPAGE 402 402 403 - int __init has_transparent_hugepage(void) 403 + int has_transparent_hugepage(void) 404 404 { 405 - unsigned int mask; 406 - unsigned long flags; 405 + static unsigned int mask = -1; 407 406 408 - local_irq_save(flags); 409 - write_c0_pagemask(PM_HUGE_MASK); 410 - back_to_back_c0_hazard(); 411 - mask = read_c0_pagemask(); 412 - write_c0_pagemask(PM_DEFAULT_MASK); 407 + if (mask == -1) { /* first call comes during __init */ 408 + unsigned long flags; 413 409 414 - local_irq_restore(flags); 415 - 410 + local_irq_save(flags); 411 + write_c0_pagemask(PM_HUGE_MASK); 412 + back_to_back_c0_hazard(); 413 + mask = read_c0_pagemask(); 414 + write_c0_pagemask(PM_DEFAULT_MASK); 415 + local_irq_restore(flags); 416 + } 416 417 return mask == PM_HUGE_MASK; 417 418 } 418 419
+1
arch/powerpc/include/asm/book3s/64/pgtable.h
··· 219 219 pmd_t *pmdp, pmd_t pmd); 220 220 extern void update_mmu_cache_pmd(struct vm_area_struct *vma, unsigned long addr, 221 221 pmd_t *pmd); 222 + #define has_transparent_hugepage has_transparent_hugepage 222 223 extern int has_transparent_hugepage(void); 223 224 #endif /* CONFIG_TRANSPARENT_HUGEPAGE */ 224 225
-1
arch/powerpc/include/asm/pgtable.h
··· 65 65 struct page **pages, int *nr); 66 66 #ifndef CONFIG_TRANSPARENT_HUGEPAGE 67 67 #define pmd_large(pmd) 0 68 - #define has_transparent_hugepage() 0 69 68 #endif 70 69 pte_t *__find_linux_pte_or_hugepte(pgd_t *pgdir, unsigned long ea, 71 70 bool *is_thp, unsigned *shift);
+1
arch/s390/include/asm/pgtable.h
··· 1223 1223 return pmd_val(pmd) & _SEGMENT_ENTRY_LARGE; 1224 1224 } 1225 1225 1226 + #define has_transparent_hugepage has_transparent_hugepage 1226 1227 static inline int has_transparent_hugepage(void) 1227 1228 { 1228 1229 return MACHINE_HAS_HPAGE ? 1 : 0;
-2
arch/sparc/include/asm/pgtable_64.h
··· 681 681 return pte_val(pte) & _PAGE_PMD_HUGE; 682 682 } 683 683 684 - #define has_transparent_hugepage() 1 685 - 686 684 static inline pmd_t pmd_mkold(pmd_t pmd) 687 685 { 688 686 pte_t pte = __pte(pmd_val(pmd));
-1
arch/tile/include/asm/pgtable.h
··· 487 487 } 488 488 489 489 #ifdef CONFIG_TRANSPARENT_HUGEPAGE 490 - #define has_transparent_hugepage() 1 491 490 #define pmd_trans_huge pmd_huge_page 492 491 #endif /* CONFIG_TRANSPARENT_HUGEPAGE */ 493 492
+1
arch/x86/include/asm/pgtable.h
··· 181 181 return (pmd_val(pmd) & (_PAGE_PSE|_PAGE_DEVMAP)) == _PAGE_PSE; 182 182 } 183 183 184 + #define has_transparent_hugepage has_transparent_hugepage 184 185 static inline int has_transparent_hugepage(void) 185 186 { 186 187 return boot_cpu_has(X86_FEATURE_PSE);
+8
include/asm-generic/pgtable.h
··· 806 806 #define io_remap_pfn_range remap_pfn_range 807 807 #endif 808 808 809 + #ifndef has_transparent_hugepage 810 + #ifdef CONFIG_TRANSPARENT_HUGEPAGE 811 + #define has_transparent_hugepage() 1 812 + #else 813 + #define has_transparent_hugepage() 0 814 + #endif 815 + #endif 816 + 809 817 #endif /* _ASM_GENERIC_PGTABLE_H */