Currently, we have two helpers that check for PMD-sized pages but have different names and slightly different semantics: - has_transparent_hugepage(): the name suggests it checks if THP is enabled, but when CONFIG_TRANSPARENT_HUGEPAGE=y and the architecture implements this helper, it actually checks if the CPU supports PMD-sized pages - thp_disabled_by_hw(): the name suggests it checks if THP is disabled by the hardware, but it just returns a cached value acquired with has_transparent_hugepage() during boot. This helper is used in fast paths A better design would be to separate CONFIG_TRANSPARENT_HUGEPAGE checking, which can be done with the IS_ENABLED() macro, from checking if a CPU supports PMD-sized pages. To this end, this commit introduces a new helper called pgtable_has_pmd_leaves() which offers the following advantages: 1. Well defined and clear semantics: it returns true if the CPU supports PMD-sized pages and false otherwise 2. It always returns a cached value, so it can be used in fast paths 3. It's implemented with a static key: it's a no-op for archs not implemeting it and for archs implementing it the static key is changed only during boot The new helper requires an initialization step which is performed by pgtable_leaf_support_init(). We call pgtable_leaf_support_init() early during boot from mm_core_init(). The next commits will convert users of both has_transparent_hugepage() and thp_disabled_by_hw() to pgtable_has_pmd_leaves() and/or IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE). Signed-off-by: Luiz Capitulino --- include/linux/pgtable.h | 16 ++++++++++++++++ mm/memory.c | 9 +++++++++ mm/mm_init.c | 1 + 3 files changed, 26 insertions(+) diff --git a/include/linux/pgtable.h b/include/linux/pgtable.h index 8c093c119e5a..4c00cf53e183 100644 --- a/include/linux/pgtable.h +++ b/include/linux/pgtable.h @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -2313,6 +2314,21 @@ static inline const char *pgtable_level_to_str(enum pgtable_level level) } } +#ifdef CONFIG_MMU +DECLARE_STATIC_KEY_TRUE(__arch_has_pmd_leaves_key); +static inline bool pgtable_has_pmd_leaves(void) +{ + return static_branch_likely(&__arch_has_pmd_leaves_key); +} +void __init pgtable_leaf_support_init(void); +#else +static inline bool pgtable_has_pmd_leaves(void) +{ + return false; +} +static inline void __init pgtable_leaf_support_init(void) { } +#endif + #endif /* !__ASSEMBLER__ */ #if !defined(MAX_POSSIBLE_PHYSMEM_BITS) && !defined(CONFIG_64BIT) diff --git a/mm/memory.c b/mm/memory.c index bc14cae3c49d..69ab1bb54853 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -164,6 +164,15 @@ __setup("norandmaps", disable_randmaps); unsigned long highest_memmap_pfn __read_mostly; +DEFINE_STATIC_KEY_TRUE(__arch_has_pmd_leaves_key); +EXPORT_SYMBOL(__arch_has_pmd_leaves_key); + +void __init pgtable_leaf_support_init(void) +{ + if (!has_transparent_hugepage()) + static_branch_disable(&__arch_has_pmd_leaves_key); +} + void mm_trace_rss_stat(struct mm_struct *mm, int member) { trace_rss_stat(mm, member); diff --git a/mm/mm_init.c b/mm/mm_init.c index 33ff95141adb..0476d54d0b6f 100644 --- a/mm/mm_init.c +++ b/mm/mm_init.c @@ -2645,6 +2645,7 @@ void __init mm_core_init(void) { arch_mm_preinit(); init_zero_page_pfn(); + pgtable_leaf_support_init(); /* Initializations relying on SMP setup */ BUILD_BUG_ON(MAX_ZONELISTS > 2); -- 2.55.0