[PATCH v5 03/14] mm: introduce pgtable_has_pmd_leaves()
From: Luiz Capitulino
Date: Fri May 29 2026 - 11:11:41 EST
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(). This helper is used in fast paths
This commit introduces a new helper called pgtable_has_pmd_leaves()
which is intended to replace both has_transparent_hugepage() and
thp_disabled_by_hw(). pgtable_has_pmd_leaves() has very clear semantics:
it returns true if the CPU supports PMD-sized pages and false otherwise.
It always returns a cached value, so it can be used in fast paths.
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().
Signed-off-by: Luiz Capitulino <luizcap@xxxxxxxxxx>
---
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 cdd68ed3ae1a..d7899b95d3f1 100644
--- a/include/linux/pgtable.h
+++ b/include/linux/pgtable.h
@@ -14,6 +14,7 @@
#include <linux/mm_types.h>
#include <linux/bug.h>
#include <linux/errno.h>
+#include <linux/jump_label.h>
#include <asm-generic/pgtable_uffd.h>
#include <linux/page_table_check.h>
@@ -2243,6 +2244,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 /* !__ASSEMBLY__ */
#if !defined(MAX_POSSIBLE_PHYSMEM_BITS) && !defined(CONFIG_64BIT)
diff --git a/mm/memory.c b/mm/memory.c
index 86a973119bd4..2f2bf7950daf 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 f9f8e1af921c..913d35fd67a0 100644
--- a/mm/mm_init.c
+++ b/mm/mm_init.c
@@ -2697,6 +2697,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.54.0