Linux-mm Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v7 00/14] mm: thp: always enable mTHP support
@ 2026-09-01  3:12 Luiz Capitulino
  2026-09-01  3:12 ` [PATCH v7 01/14] docs: tmpfs: remove implementation detail reference Luiz Capitulino
                   ` (13 more replies)
  0 siblings, 14 replies; 19+ messages in thread
From: Luiz Capitulino @ 2026-09-01  3:12 UTC (permalink / raw)
  To: linux-kernel, linux-mm, david, baolin.wang, ziy, lance.yang
  Cc: corbet, tsbogend, maddy, mpe, agordeev, gerald.schaefer, hca, gor,
	x86, tglx, mingo, bp, hughd, dave.hansen, djbw, vishal.l.verma,
	dave.jiang, akpm, yintirui, dev.jain, usama.arif

[ NOTE: Updated cover letter ]

Introduction
============

Today, if an architecture implements has_transparent_hugepage() and the CPU
lacks support for PMD-sized pages, the THP code disables all THP, including
mTHP.

This happens because the has_transparent_hugepage() helper is overloaded:
its name implies it checks whether THP is enabled, but on some architectures
it actually checks whether the CPU supports PMD-sized pages. In addition,
the THP and shmem code have a big switch on has_transparent_hugepage().

This series solves this by decoupling THP availability checking from
querying CPU support for PMD-sized pages. THP availability can be checked
with IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE). For querying PMD-sized page
support, this series introduces a new helper called pgtable_has_pmd_leaves(),
which is independent of THP, has well defined semantics and can be used
in fast paths.

Core THP code and shmem can use pgtable_has_pmd_leaves() to determine
PMD-sized THP support at page fault time (or folio allocation time for
shmem), leaving THP and shmem always enabled for other THP sizes. For
architectures and CPUs that do support PMD-sized pages there's no
intended change in behavior.

We also convert each user of has_transparent_hugepage(), and the related
helper thp_disabled_by_hw(), to IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE)
and/or pgtable_has_pmd_leaves() according to the call site's check semantics.
On s390, powerpc, mips and x86 the arch has_transparent_hugepage()
implementation is moved out of the CONFIG_TRANSPARENT_HUGEPAGE guard and
renamed to arch_has_pmd_leaves().

Thanks to David Hildenbrand for suggesting this improvement and for
providing initial guidance (all bugs and misconceptions are mine).

This applies to mm-new da6c37ed8beb ("mm/swap, PM: hibernate: atomically
replace hibernation pin").

Reporting availability of PMD-sized pages to user-space
=======================================================

Before this series, not having PMD pages available would shutdown THP support
meaning that /sys/kernel/mm/transparent_hugepage would not be available.
After this series, /sys/kernel/mm/transparent_hugepage and hpage_pmd_size are
always available but hugepages-<PMD-size>kB is only available if PMD-sized
pages are supported.

To me this seems logical, as hugepages-<size>kB is only available if <size>
is supported. If this is correct, then MM kselftests that depend on PMD-sized
pages will need to be updated to check for it as they fail with this series
applied when PMD-sized pages are not available.

The alternative is changing hpage_pmd_size: either don't create the file
when PMD-sized pages are not available or set hpage_pmd_size=0. My concern
is that this could be considered an ABI breakage as this file was never
reported to be optional or report a zero value.

Testing
=======

- Ran MM kselftests on x86_64 with and without PMD-sized pages available
- Tested all mTHP sizes allocation on x86_64 when PMD-sized pages are
  not available
- Tested shmem with within_size w/ mTHP on x86_64 when PMD-sized pages
  are not available
- Performed defconfig build on x86_64, s390, arm64, powerpc, and mips

NOTES:
  1. I'm forcing arch_has_pmd_leaves() off on x86 to simulate not having
     PMD-sized pages available

  2. Running the MM kselftests when PMD pages are not available causes some
     tests that depend on PMD-sized THP pages to fail as noted earlier

Changelog
=========

v7
--
- Applied on top of latest mm-new
- Improved various changelogs including cover-letter
- Changed arch_has_pmd_leaves() default implementation to use IS_ENABLED()
  intead of IS_BUILTIN()

v6
--
- Rebased on top of mm-unstable (required a minor conflict resolution)
- Added more Reviewed-by and Acked-by tags

v5
--
- Moved init_arch_has_pmd_leaves() to mm_core_init() (David)
- Renamed init_arch_has_pmd_leaves() to pgtable_leaf_support_init() (Lance)
- Added new patch changing shmem_getattr() to set blksize according to
  highest supported THP order (Baolin)
- Added new patches to move has_transparent_hugepage() out of
  CONFIG_TRANSPARENT_HUGEPAGE guards (Sashiko)
- shmem_allowable_huge_orders(): rename variable and only disable
  PMD_ORDER (David)
- Added <linux/jmp_label.h> to include/linux/pgtable.h (Sashiko)
- Added new tags and removed Reviewed-by from changed patches

v4
--
- Used static key for pgtable_has_pmd_leaves() API (Lance)
- Moved shmem pgtable_has_pmd_leaves() check to
  shmem_allowable_huge_orders() (Baolin)
- Default pgtable_has_pmd_leaves() implementation to
  IS_ENABLED(CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE) (Zi)
- Dropped patch “mm: thp: x86: cleanup PSE feature bit usage” (Dave)

v3
--
- Rebased on top of latest Linus tree
- Removed i915 patch as driver dropped has_transparent_hugepage() usage
- Moved init_arch_has_pmd_leaves() call in start_kernel() to avoid conflict
  with early_param handlers clearing CPU feature flags
- Fixed build error with CONFIG_MMU=n (kernel test robot)
- Fixed huge_anon_orders_inherit default setting when !pgtable_pmd_leaves() (Baolin)
- Small commit changelog improvements

v2
--
- Added support for always enabling mTHPs for shmem (Baolin)
- Improved commits changelog & added reviewed-by

v1
--
- Call init_arch_has_pmd_leaves() from start_kernel()
- Keep pgtable_has_pmd_leaves() calls tied to CONFIG_TRANSPARENT_HUGEPAGE (David)
- Clear PUD_ORDER when clearing PMD_ORDER (David)
- Small changelog improvements (David)
- Rebased on top of latest mm-new

Luiz Capitulino (14):
  docs: tmpfs: remove implementation detail reference
  mm: shmem: shmem_getattr(): set blksize to highest supported THP order
  mm: introduce pgtable_has_pmd_leaves()
  drivers: dax: use pgtable_has_pmd_leaves()
  drivers: nvdimm: use pgtable_has_pmd_leaves()
  mm: debug_vm_pgtable: use pgtable_has_pmd_leaves()
  mm: shmem: allow THP support determination at folio allocation time
  s390: move has_transparent_hugepage() out of THP guard
  powerpc: move has_transparent_hugepage() out of THP guard
  mips: move has_transparent_hugepage() out of THP guard
  x86: move has_transparent_hugepage() out of THP guard
  treewide: introduce arch_has_pmd_leaves()
  mm: replace thp_disabled_by_hw() with pgtable_has_pmd_leaves()
  mm: thp: always enable mTHP support

 Documentation/filesystems/tmpfs.rst           |  5 ++--
 arch/mips/include/asm/pgtable.h               |  6 ++--
 arch/mips/mm/tlb-r4k.c                        |  8 ++---
 arch/powerpc/include/asm/book3s/64/hash-4k.h  |  2 +-
 arch/powerpc/include/asm/book3s/64/hash-64k.h |  2 +-
 arch/powerpc/include/asm/book3s/64/pgtable.h  | 18 ++++++------
 arch/powerpc/include/asm/book3s/64/radix.h    | 14 ++++-----
 arch/powerpc/mm/book3s64/hash_pgtable.c       |  8 ++---
 arch/s390/include/asm/pgtable.h               |  6 ++--
 arch/x86/include/asm/pgtable.h                | 12 ++++----
 drivers/dax/dax-private.h                     |  2 +-
 drivers/nvdimm/pfn_devs.c                     |  6 ++--
 include/linux/huge_mm.h                       |  7 -----
 include/linux/pgtable.h                       | 20 +++++++++++--
 mm/debug_vm_pgtable.c                         | 20 ++++++-------
 mm/huge_memory.c                              | 27 ++++++++++++-----
 mm/memory.c                                   | 11 ++++++-
 mm/mm_init.c                                  |  1 +
 mm/shmem.c                                    | 29 ++++++++++++-------
 19 files changed, 120 insertions(+), 84 deletions(-)

-- 
2.55.0



^ permalink raw reply	[flat|nested] 19+ messages in thread

* [PATCH v7 01/14] docs: tmpfs: remove implementation detail reference
  2026-09-01  3:12 [PATCH v7 00/14] mm: thp: always enable mTHP support Luiz Capitulino
@ 2026-09-01  3:12 ` Luiz Capitulino
  2026-09-01  3:12 ` [PATCH v7 02/14] mm: shmem: shmem_getattr(): set blksize to highest supported THP order Luiz Capitulino
                   ` (12 subsequent siblings)
  13 siblings, 0 replies; 19+ messages in thread
From: Luiz Capitulino @ 2026-09-01  3:12 UTC (permalink / raw)
  To: linux-kernel, linux-mm, david, baolin.wang, ziy, lance.yang
  Cc: corbet, tsbogend, maddy, mpe, agordeev, gerald.schaefer, hca, gor,
	x86, tglx, mingo, bp, hughd, dave.hansen, djbw, vishal.l.verma,
	dave.jiang, akpm, yintirui, dev.jain, usama.arif

The tmpfs.rst doc references the has_transparent_hugepage() helper, which
is an implementation detail in the kernel and not relevant for users
wishing to properly configure THP support for tmpfs. Remove it.

Acked-by: David Hildenbrand (Red Hat) <david@kernel.org>
Reviewed-by: Baolin Wang <baolin.wang@linux.alibaba.com>
Reviewed-by: Lance Yang <lance.yang@linux.dev>
Reviewed-by: Zi Yan <ziy@nvidia.com>
Reviewed-by: Dev Jain <dev.jain@arm.com>
Signed-off-by: Luiz Capitulino <luizcap@redhat.com>
---
 Documentation/filesystems/tmpfs.rst | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/Documentation/filesystems/tmpfs.rst b/Documentation/filesystems/tmpfs.rst
index d677e0428c3f..46fc986c3388 100644
--- a/Documentation/filesystems/tmpfs.rst
+++ b/Documentation/filesystems/tmpfs.rst
@@ -109,9 +109,8 @@ noswap  Disables swap. Remounts must respect the original settings.
 ======  ===========================================================
 
 tmpfs also supports Transparent Huge Pages which requires a kernel
-configured with CONFIG_TRANSPARENT_HUGEPAGE and with huge supported for
-your system (has_transparent_hugepage(), which is architecture specific).
-The mount options for this are:
+configured with CONFIG_TRANSPARENT_HUGEPAGE and with huge pages
+supported for your system. The mount options for this are:
 
 ================ ==============================================================
 huge=never       Do not allocate huge pages.  This is the default.
-- 
2.55.0



^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH v7 02/14] mm: shmem: shmem_getattr(): set blksize to highest supported THP order
  2026-09-01  3:12 [PATCH v7 00/14] mm: thp: always enable mTHP support Luiz Capitulino
  2026-09-01  3:12 ` [PATCH v7 01/14] docs: tmpfs: remove implementation detail reference Luiz Capitulino
@ 2026-09-01  3:12 ` Luiz Capitulino
  2026-09-01  3:12 ` [PATCH v7 03/14] mm: introduce pgtable_has_pmd_leaves() Luiz Capitulino
                   ` (11 subsequent siblings)
  13 siblings, 0 replies; 19+ messages in thread
From: Luiz Capitulino @ 2026-09-01  3:12 UTC (permalink / raw)
  To: linux-kernel, linux-mm, david, baolin.wang, ziy, lance.yang
  Cc: corbet, tsbogend, maddy, mpe, agordeev, gerald.schaefer, hca, gor,
	x86, tglx, mingo, bp, hughd, dave.hansen, djbw, vishal.l.verma,
	dave.jiang, akpm, yintirui, dev.jain, usama.arif

Today, shmem_getattr() sets stat->blksize to PMD size whenever
shmem_huge_global_enabled() returns non-zero. While this works fine
for the normal THP-enabled case as explained by Baolin in [1], this
has two problems:

 1. Theoretically, when shmem is configured for within_size, this
    could set blksize to PMD size even though the allocation may
    be a smaller mTHP order

 2. A future commit will allow shmem THP support to be enabled
    even when the CPU doesn't support PMD-sized pages. We should
    not allow blksize to be set to PMD size in this case

In order to fix #1 and prepare for #2, this commit sets blksize
to the size of the highest supported order returned by
shmem_huge_global_enabled().

  [1] https://lore.kernel.org/linux-mm/6591a74c-7ef9-4614-9ae9-cb2fbed86ebf@linux.alibaba.com/

Suggested-by: Baolin Wang <baolin.wang@linux.alibaba.com>
Acked-by: Zi Yan <ziy@nvidia.com>
Signed-off-by: Luiz Capitulino <luizcap@redhat.com>
---
 mm/shmem.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/mm/shmem.c b/mm/shmem.c
index eeb9a78c125a..b963f55640a8 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -1506,6 +1506,7 @@ static int shmem_getattr(struct mnt_idmap *idmap,
 {
 	struct inode *inode = path->dentry->d_inode;
 	struct shmem_inode_info *info = SHMEM_I(inode);
+	unsigned int orders;
 
 	/* Fast-path hint; recalc under info->lock corrects any stale read. */
 	if (data_race(info->alloced - info->swapped != inode->i_mapping->nrpages))
@@ -1522,8 +1523,9 @@ static int shmem_getattr(struct mnt_idmap *idmap,
 			STATX_ATTR_NODUMP);
 	generic_fillattr(idmap, request_mask, inode, stat);
 
-	if (shmem_huge_global_enabled(inode, 0, 0, false, NULL, 0))
-		stat->blksize = HPAGE_PMD_SIZE;
+	orders = shmem_huge_global_enabled(inode, 0, 0, false, NULL, 0);
+	if (orders)
+		stat->blksize = PAGE_SIZE << highest_order(orders);
 
 	if (request_mask & STATX_BTIME) {
 		stat->result_mask |= STATX_BTIME;
-- 
2.55.0



^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH v7 03/14] mm: introduce pgtable_has_pmd_leaves()
  2026-09-01  3:12 [PATCH v7 00/14] mm: thp: always enable mTHP support Luiz Capitulino
  2026-09-01  3:12 ` [PATCH v7 01/14] docs: tmpfs: remove implementation detail reference Luiz Capitulino
  2026-09-01  3:12 ` [PATCH v7 02/14] mm: shmem: shmem_getattr(): set blksize to highest supported THP order Luiz Capitulino
@ 2026-09-01  3:12 ` Luiz Capitulino
  2026-09-01  3:12 ` [PATCH v7 04/14] drivers: dax: use pgtable_has_pmd_leaves() Luiz Capitulino
                   ` (10 subsequent siblings)
  13 siblings, 0 replies; 19+ messages in thread
From: Luiz Capitulino @ 2026-09-01  3:12 UTC (permalink / raw)
  To: linux-kernel, linux-mm, david, baolin.wang, ziy, lance.yang
  Cc: corbet, tsbogend, maddy, mpe, agordeev, gerald.schaefer, hca, gor,
	x86, tglx, mingo, bp, hughd, dave.hansen, djbw, vishal.l.verma,
	dave.jiang, akpm, yintirui, dev.jain, usama.arif

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 <luizcap@redhat.com>
---
 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 <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>
 
@@ -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



^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH v7 04/14] drivers: dax: use pgtable_has_pmd_leaves()
  2026-09-01  3:12 [PATCH v7 00/14] mm: thp: always enable mTHP support Luiz Capitulino
                   ` (2 preceding siblings ...)
  2026-09-01  3:12 ` [PATCH v7 03/14] mm: introduce pgtable_has_pmd_leaves() Luiz Capitulino
@ 2026-09-01  3:12 ` Luiz Capitulino
  2026-09-01  3:12 ` [PATCH v7 05/14] drivers: nvdimm: " Luiz Capitulino
                   ` (9 subsequent siblings)
  13 siblings, 0 replies; 19+ messages in thread
From: Luiz Capitulino @ 2026-09-01  3:12 UTC (permalink / raw)
  To: linux-kernel, linux-mm, david, baolin.wang, ziy, lance.yang
  Cc: corbet, tsbogend, maddy, mpe, agordeev, gerald.schaefer, hca, gor,
	x86, tglx, mingo, bp, hughd, dave.hansen, djbw, vishal.l.verma,
	dave.jiang, akpm, yintirui, dev.jain, usama.arif

dax_align_valid() uses has_transparent_hugepage() to check if PMD-sized
pages are supported, use pgtable_has_pmd_leaves() instead.

Acked-by: David Hildenbrand (Red Hat) <david@kernel.org>
Signed-off-by: Luiz Capitulino <luizcap@redhat.com>
---
 drivers/dax/dax-private.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/dax/dax-private.h b/drivers/dax/dax-private.h
index 607a53a91f58..18a6295aa766 100644
--- a/drivers/dax/dax-private.h
+++ b/drivers/dax/dax-private.h
@@ -121,7 +121,7 @@ static inline bool dax_align_valid(unsigned long align)
 {
 	if (align == PUD_SIZE && IS_ENABLED(CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD))
 		return true;
-	if (align == PMD_SIZE && has_transparent_hugepage())
+	if (align == PMD_SIZE && pgtable_has_pmd_leaves())
 		return true;
 	if (align == PAGE_SIZE)
 		return true;
-- 
2.55.0



^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH v7 05/14] drivers: nvdimm: use pgtable_has_pmd_leaves()
  2026-09-01  3:12 [PATCH v7 00/14] mm: thp: always enable mTHP support Luiz Capitulino
                   ` (3 preceding siblings ...)
  2026-09-01  3:12 ` [PATCH v7 04/14] drivers: dax: use pgtable_has_pmd_leaves() Luiz Capitulino
@ 2026-09-01  3:12 ` Luiz Capitulino
  2026-09-01  3:12 ` [PATCH v7 06/14] mm: debug_vm_pgtable: " Luiz Capitulino
                   ` (8 subsequent siblings)
  13 siblings, 0 replies; 19+ messages in thread
From: Luiz Capitulino @ 2026-09-01  3:12 UTC (permalink / raw)
  To: linux-kernel, linux-mm, david, baolin.wang, ziy, lance.yang
  Cc: corbet, tsbogend, maddy, mpe, agordeev, gerald.schaefer, hca, gor,
	x86, tglx, mingo, bp, hughd, dave.hansen, djbw, vishal.l.verma,
	dave.jiang, akpm, yintirui, dev.jain, usama.arif

nd_pfn_supported_alignments() and nd_pfn_default_alignment() use
has_transparent_hugepage() to check if THP is supported with PMD-sized
pages. Use pgtable_has_pmd_leaves() instead. Also, check for
IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE) to preserve the current
implementation semantics.

Acked-by: Zi Yan <ziy@nvidia.com>
Signed-off-by: Luiz Capitulino <luizcap@redhat.com>
---
 drivers/nvdimm/pfn_devs.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/drivers/nvdimm/pfn_devs.c b/drivers/nvdimm/pfn_devs.c
index 8fa9c16aba7e..457eb54e7ab6 100644
--- a/drivers/nvdimm/pfn_devs.c
+++ b/drivers/nvdimm/pfn_devs.c
@@ -94,7 +94,8 @@ static unsigned long *nd_pfn_supported_alignments(unsigned long *alignments)
 
 	alignments[0] = PAGE_SIZE;
 
-	if (has_transparent_hugepage()) {
+	if (IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE) &&
+	    pgtable_has_pmd_leaves()) {
 		alignments[1] = HPAGE_PMD_SIZE;
 		if (has_transparent_pud_hugepage())
 			alignments[2] = HPAGE_PUD_SIZE;
@@ -109,7 +110,8 @@ static unsigned long *nd_pfn_supported_alignments(unsigned long *alignments)
 static unsigned long nd_pfn_default_alignment(void)
 {
 
-	if (has_transparent_hugepage())
+	if (IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE) &&
+	    pgtable_has_pmd_leaves())
 		return HPAGE_PMD_SIZE;
 	return PAGE_SIZE;
 }
-- 
2.55.0



^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH v7 06/14] mm: debug_vm_pgtable: use pgtable_has_pmd_leaves()
  2026-09-01  3:12 [PATCH v7 00/14] mm: thp: always enable mTHP support Luiz Capitulino
                   ` (4 preceding siblings ...)
  2026-09-01  3:12 ` [PATCH v7 05/14] drivers: nvdimm: " Luiz Capitulino
@ 2026-09-01  3:12 ` Luiz Capitulino
  2026-09-01  3:12 ` [PATCH v7 07/14] mm: shmem: allow THP support determination at folio allocation time Luiz Capitulino
                   ` (7 subsequent siblings)
  13 siblings, 0 replies; 19+ messages in thread
From: Luiz Capitulino @ 2026-09-01  3:12 UTC (permalink / raw)
  To: linux-kernel, linux-mm, david, baolin.wang, ziy, lance.yang
  Cc: corbet, tsbogend, maddy, mpe, agordeev, gerald.schaefer, hca, gor,
	x86, tglx, mingo, bp, hughd, dave.hansen, djbw, vishal.l.verma,
	dave.jiang, akpm, yintirui, dev.jain, usama.arif

debug_vm_pgtable calls has_transparent_hugepage() in multiple places to
check if PMD-sized pages are supported, use pgtable_has_pmd_leaves()
instead.

Reviewed-by: Lance Yang <lance.yang@linux.dev>
Reviewed-by: Zi Yan <ziy@nvidia.com>
Signed-off-by: Luiz Capitulino <luizcap@redhat.com>
---
 mm/debug_vm_pgtable.c | 20 ++++++++++----------
 1 file changed, 10 insertions(+), 10 deletions(-)

diff --git a/mm/debug_vm_pgtable.c b/mm/debug_vm_pgtable.c
index 2875fd22d7bb..25038b74c7bc 100644
--- a/mm/debug_vm_pgtable.c
+++ b/mm/debug_vm_pgtable.c
@@ -177,7 +177,7 @@ static void __init pmd_basic_tests(struct pgtable_debug_args *args, int idx)
 	unsigned long val = idx, *ptr = &val;
 	pmd_t pmd;
 
-	if (!has_transparent_hugepage())
+	if (!pgtable_has_pmd_leaves())
 		return;
 
 	pr_debug("Validating PMD basic (%pGv)\n", ptr);
@@ -222,7 +222,7 @@ static void __init pmd_advanced_tests(struct pgtable_debug_args *args)
 	pmd_t pmd;
 	unsigned long vaddr = args->vaddr;
 
-	if (!has_transparent_hugepage())
+	if (!pgtable_has_pmd_leaves())
 		return;
 
 	page = (args->pmd_pfn != ULONG_MAX) ? pfn_to_page(args->pmd_pfn) : NULL;
@@ -283,7 +283,7 @@ static void __init pmd_leaf_tests(struct pgtable_debug_args *args)
 {
 	pmd_t pmd;
 
-	if (!has_transparent_hugepage())
+	if (!pgtable_has_pmd_leaves())
 		return;
 
 	pr_debug("Validating PMD leaf\n");
@@ -688,7 +688,7 @@ static void __init pmd_protnone_tests(struct pgtable_debug_args *args)
 	if (!IS_ENABLED(CONFIG_ARCH_HAS_PTE_PROTNONE))
 		return;
 
-	if (!has_transparent_hugepage())
+	if (!pgtable_has_pmd_leaves())
 		return;
 
 	pr_debug("Validating PMD protnone\n");
@@ -737,7 +737,7 @@ static void __init pmd_soft_dirty_tests(struct pgtable_debug_args *args)
 	if (!pgtable_supports_soft_dirty())
 		return;
 
-	if (!has_transparent_hugepage())
+	if (!pgtable_has_pmd_leaves())
 		return;
 
 	pr_debug("Validating PMD soft dirty\n");
@@ -754,7 +754,7 @@ static void __init pmd_leaf_soft_dirty_tests(struct pgtable_debug_args *args)
 	    !IS_ENABLED(CONFIG_ARCH_HAS_PMD_SOFTLEAVES))
 		return;
 
-	if (!has_transparent_hugepage())
+	if (!pgtable_has_pmd_leaves())
 		return;
 
 	pr_debug("Validating PMD swap soft dirty\n");
@@ -825,7 +825,7 @@ static void __init pmd_softleaf_tests(struct pgtable_debug_args *args)
 	swp_entry_t arch_entry;
 	pmd_t pmd1, pmd2;
 
-	if (!has_transparent_hugepage())
+	if (!pgtable_has_pmd_leaves())
 		return;
 
 	pr_debug("Validating PMD swap\n");
@@ -906,7 +906,7 @@ static void __init pmd_thp_tests(struct pgtable_debug_args *args)
 {
 	pmd_t pmd;
 
-	if (!has_transparent_hugepage())
+	if (!pgtable_has_pmd_leaves())
 		return;
 
 	pr_debug("Validating PMD based THP\n");
@@ -997,7 +997,7 @@ static void __init destroy_args(struct pgtable_debug_args *args)
 	}
 
 	if (IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE) &&
-	    has_transparent_hugepage() &&
+	    pgtable_has_pmd_leaves() &&
 	    args->pmd_pfn != ULONG_MAX) {
 		debug_vm_pgtable_free_huge_page(args, args->pmd_pfn, HPAGE_PMD_ORDER);
 		args->pmd_pfn = ULONG_MAX;
@@ -1249,7 +1249,7 @@ static int __init init_args(struct pgtable_debug_args *args)
 	}
 
 	if (IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE) &&
-	    has_transparent_hugepage()) {
+	    pgtable_has_pmd_leaves()) {
 		page = debug_vm_pgtable_alloc_huge_page(args, HPAGE_PMD_ORDER);
 		if (page) {
 			args->pmd_pfn = page_to_pfn(page);
-- 
2.55.0



^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH v7 07/14] mm: shmem: allow THP support determination at folio allocation time
  2026-09-01  3:12 [PATCH v7 00/14] mm: thp: always enable mTHP support Luiz Capitulino
                   ` (5 preceding siblings ...)
  2026-09-01  3:12 ` [PATCH v7 06/14] mm: debug_vm_pgtable: " Luiz Capitulino
@ 2026-09-01  3:12 ` Luiz Capitulino
  2026-09-01  3:12 ` [PATCH v7 08/14] s390: move has_transparent_hugepage() out of THP guard Luiz Capitulino
                   ` (6 subsequent siblings)
  13 siblings, 0 replies; 19+ messages in thread
From: Luiz Capitulino @ 2026-09-01  3:12 UTC (permalink / raw)
  To: linux-kernel, linux-mm, david, baolin.wang, ziy, lance.yang
  Cc: corbet, tsbogend, maddy, mpe, agordeev, gerald.schaefer, hca, gor,
	x86, tglx, mingo, bp, hughd, dave.hansen, djbw, vishal.l.verma,
	dave.jiang, akpm, yintirui, dev.jain, usama.arif

In order to enable THP support in shmem today, besides the user
configuration required, the CPU must support PMD-sized pages. This
is the case because of the following has_transparent_hugepage()
usage:

- shmem_parse_one() and shmem_parse_huge(): Check if THP is built-in and
  if the CPU supports PMD-sized pages

- shmem_init(): Since the CONFIG_TRANSPARENT_HUGEPAGE guard is outside
  the code block calling has_transparent_hugepage(), the
  has_transparent_hugepage() call is exclusively checking if the CPU
  supports PMD-sized pages

While it's necessary to check if CONFIG_TRANSPARENT_HUGEPAGE is enabled
in all cases, shmem can determine THP size support at folio allocation
time. Therefore, drop the has_transparent_hugepage() usage listed above
while keeping the CONFIG_TRANSPARENT_HUGEPAGE checks.

Additionally, we need to check if PMD size order is supported in
shmem_getattr(). Use pgtable_has_pmd_leaves() for that.

Reviewed-by: Baolin Wang <baolin.wang@linux.alibaba.com>
Signed-off-by: Luiz Capitulino <luizcap@redhat.com>
---
 mm/shmem.c | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/mm/shmem.c b/mm/shmem.c
index b963f55640a8..c285cb7fd32e 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -690,7 +690,7 @@ static int shmem_parse_huge(const char *str)
 	else
 		return -EINVAL;
 
-	if (!has_transparent_hugepage() &&
+	if (!IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE) &&
 	    huge != SHMEM_HUGE_NEVER && huge != SHMEM_HUGE_DENY)
 		return -EINVAL;
 
@@ -1524,6 +1524,8 @@ static int shmem_getattr(struct mnt_idmap *idmap,
 	generic_fillattr(idmap, request_mask, inode, stat);
 
 	orders = shmem_huge_global_enabled(inode, 0, 0, false, NULL, 0);
+	if (!pgtable_has_pmd_leaves())
+		orders &= ~BIT(PMD_ORDER);
 	if (orders)
 		stat->blksize = PAGE_SIZE << highest_order(orders);
 
@@ -4810,8 +4812,7 @@ static int shmem_parse_one(struct fs_context *fc, struct fs_parameter *param)
 	case Opt_huge:
 		ctx->huge = result.uint_32;
 		if (ctx->huge != SHMEM_HUGE_NEVER &&
-		    !(IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE) &&
-		      has_transparent_hugepage()))
+		    !IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE))
 			goto unsupported_parameter;
 		ctx->seen |= SHMEM_SEEN_HUGE;
 		break;
@@ -5616,7 +5617,7 @@ void __init shmem_init(void)
 #endif
 
 #ifdef CONFIG_TRANSPARENT_HUGEPAGE
-	if (has_transparent_hugepage() && shmem_huge > SHMEM_HUGE_DENY)
+	if (shmem_huge > SHMEM_HUGE_DENY)
 		SHMEM_SB(shm_mnt->mnt_sb)->huge = shmem_huge;
 	else
 		shmem_huge = SHMEM_HUGE_NEVER; /* just in case it was patched */
-- 
2.55.0



^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH v7 08/14] s390: move has_transparent_hugepage() out of THP guard
  2026-09-01  3:12 [PATCH v7 00/14] mm: thp: always enable mTHP support Luiz Capitulino
                   ` (6 preceding siblings ...)
  2026-09-01  3:12 ` [PATCH v7 07/14] mm: shmem: allow THP support determination at folio allocation time Luiz Capitulino
@ 2026-09-01  3:12 ` Luiz Capitulino
  2026-09-01  3:12 ` [PATCH v7 09/14] powerpc: " Luiz Capitulino
                   ` (5 subsequent siblings)
  13 siblings, 0 replies; 19+ messages in thread
From: Luiz Capitulino @ 2026-09-01  3:12 UTC (permalink / raw)
  To: linux-kernel, linux-mm, david, baolin.wang, ziy, lance.yang
  Cc: corbet, tsbogend, maddy, mpe, agordeev, gerald.schaefer, hca, gor,
	x86, tglx, mingo, bp, hughd, dave.hansen, djbw, vishal.l.verma,
	dave.jiang, akpm, yintirui, dev.jain, usama.arif

A future commit will introduce a kernel API to allow for checking if the
CPU supports PMD-sized pages. This API will be based on the
has_transparent_hugepage() implementation but will be orthogonal to THP
and therefore must work when CONFIG_TRANSPARENT_HUGEPAGE=n.

Move its definition out of the THP guard.

Signed-off-by: Luiz Capitulino <luizcap@redhat.com>
---
 arch/s390/include/asm/pgtable.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/s390/include/asm/pgtable.h b/arch/s390/include/asm/pgtable.h
index e882663a58e7..5aa8f621df04 100644
--- a/arch/s390/include/asm/pgtable.h
+++ b/arch/s390/include/asm/pgtable.h
@@ -1825,13 +1825,13 @@ static inline int pmd_trans_huge(pmd_t pmd)
 {
 	return pmd_leaf(pmd);
 }
+#endif /* CONFIG_TRANSPARENT_HUGEPAGE */
 
 #define has_transparent_hugepage has_transparent_hugepage
 static inline int has_transparent_hugepage(void)
 {
 	return cpu_has_edat1() ? 1 : 0;
 }
-#endif /* CONFIG_TRANSPARENT_HUGEPAGE */
 
 #ifdef CONFIG_PAGE_TABLE_CHECK
 static inline bool pte_user_accessible_page(struct mm_struct *mm, unsigned long addr, pte_t pte)
-- 
2.55.0



^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH v7 09/14] powerpc: move has_transparent_hugepage() out of THP guard
  2026-09-01  3:12 [PATCH v7 00/14] mm: thp: always enable mTHP support Luiz Capitulino
                   ` (7 preceding siblings ...)
  2026-09-01  3:12 ` [PATCH v7 08/14] s390: move has_transparent_hugepage() out of THP guard Luiz Capitulino
@ 2026-09-01  3:12 ` Luiz Capitulino
  2026-09-01  3:12 ` [PATCH v7 10/14] mips: " Luiz Capitulino
                   ` (4 subsequent siblings)
  13 siblings, 0 replies; 19+ messages in thread
From: Luiz Capitulino @ 2026-09-01  3:12 UTC (permalink / raw)
  To: linux-kernel, linux-mm, david, baolin.wang, ziy, lance.yang
  Cc: corbet, tsbogend, maddy, mpe, agordeev, gerald.schaefer, hca, gor,
	x86, tglx, mingo, bp, hughd, dave.hansen, djbw, vishal.l.verma,
	dave.jiang, akpm, yintirui, dev.jain, usama.arif

A future commit will introduce a kernel API to allow for checking if the
CPU supports PMD-sized pages. This API will be based on the
has_transparent_hugepage() implementation but will be orthogonal to THP
and therefore must work when CONFIG_TRANSPARENT_HUGEPAGE=n.

Move its definition out of the THP guard.

Signed-off-by: Luiz Capitulino <luizcap@redhat.com>
---
 arch/powerpc/include/asm/book3s/64/hash-4k.h  |  2 +-
 arch/powerpc/include/asm/book3s/64/hash-64k.h |  2 +-
 arch/powerpc/include/asm/book3s/64/pgtable.h  | 18 +++++++++---------
 arch/powerpc/include/asm/book3s/64/radix.h    | 14 +++++++-------
 arch/powerpc/mm/book3s64/hash_pgtable.c       |  4 ++--
 5 files changed, 20 insertions(+), 20 deletions(-)

diff --git a/arch/powerpc/include/asm/book3s/64/hash-4k.h b/arch/powerpc/include/asm/book3s/64/hash-4k.h
index 8e5bd9902bed..79511e6abfca 100644
--- a/arch/powerpc/include/asm/book3s/64/hash-4k.h
+++ b/arch/powerpc/include/asm/book3s/64/hash-4k.h
@@ -165,9 +165,9 @@ extern void hash__pgtable_trans_huge_deposit(struct mm_struct *mm, pmd_t *pmdp,
 extern pgtable_t hash__pgtable_trans_huge_withdraw(struct mm_struct *mm, pmd_t *pmdp);
 extern pmd_t hash__pmdp_huge_get_and_clear(struct mm_struct *mm,
 				       unsigned long addr, pmd_t *pmdp);
-extern int hash__has_transparent_hugepage(void);
 #endif
 
+extern int hash__has_transparent_hugepage(void);
 #endif /* !__ASSEMBLER__ */
 
 #endif /* _ASM_POWERPC_BOOK3S_64_HASH_4K_H */
diff --git a/arch/powerpc/include/asm/book3s/64/hash-64k.h b/arch/powerpc/include/asm/book3s/64/hash-64k.h
index 7deb3a66890b..a4a44a112ff9 100644
--- a/arch/powerpc/include/asm/book3s/64/hash-64k.h
+++ b/arch/powerpc/include/asm/book3s/64/hash-64k.h
@@ -278,9 +278,9 @@ extern void hash__pgtable_trans_huge_deposit(struct mm_struct *mm, pmd_t *pmdp,
 extern pgtable_t hash__pgtable_trans_huge_withdraw(struct mm_struct *mm, pmd_t *pmdp);
 extern pmd_t hash__pmdp_huge_get_and_clear(struct mm_struct *mm,
 				       unsigned long addr, pmd_t *pmdp);
-extern int hash__has_transparent_hugepage(void);
 #endif /*  CONFIG_TRANSPARENT_HUGEPAGE */
 
+extern int hash__has_transparent_hugepage(void);
 #endif	/* __ASSEMBLER__ */
 
 #endif /* _ASM_POWERPC_BOOK3S_64_HASH_64K_H */
diff --git a/arch/powerpc/include/asm/book3s/64/pgtable.h b/arch/powerpc/include/asm/book3s/64/pgtable.h
index f4db7d7fbd5c..2a795f6d9263 100644
--- a/arch/powerpc/include/asm/book3s/64/pgtable.h
+++ b/arch/powerpc/include/asm/book3s/64/pgtable.h
@@ -1121,15 +1121,6 @@ static inline void update_mmu_cache_pud(struct vm_area_struct *vma,
 {
 }
 
-extern int hash__has_transparent_hugepage(void);
-static inline int has_transparent_hugepage(void)
-{
-	if (radix_enabled())
-		return radix__has_transparent_hugepage();
-	return hash__has_transparent_hugepage();
-}
-#define has_transparent_hugepage has_transparent_hugepage
-
 static inline int has_transparent_pud_hugepage(void)
 {
 	if (radix_enabled())
@@ -1441,6 +1432,15 @@ static inline bool arch_needs_pgtable_deposit(void)
 
 #endif /* CONFIG_TRANSPARENT_HUGEPAGE */
 
+extern int hash__has_transparent_hugepage(void);
+static inline int has_transparent_hugepage(void)
+{
+	if (radix_enabled())
+		return radix__has_transparent_hugepage();
+	return hash__has_transparent_hugepage();
+}
+#define has_transparent_hugepage has_transparent_hugepage
+
 #define __HAVE_ARCH_PTEP_MODIFY_PROT_TRANSACTION
 pte_t ptep_modify_prot_start(struct vm_area_struct *, unsigned long, pte_t *);
 void ptep_modify_prot_commit(struct vm_area_struct *, unsigned long,
diff --git a/arch/powerpc/include/asm/book3s/64/radix.h b/arch/powerpc/include/asm/book3s/64/radix.h
index da954e779744..50545cf519bd 100644
--- a/arch/powerpc/include/asm/book3s/64/radix.h
+++ b/arch/powerpc/include/asm/book3s/64/radix.h
@@ -298,22 +298,22 @@ extern pmd_t radix__pmdp_huge_get_and_clear(struct mm_struct *mm,
 pud_t radix__pudp_huge_get_and_clear(struct mm_struct *mm,
 				     unsigned long addr, pud_t *pudp);
 
-static inline int radix__has_transparent_hugepage(void)
+static inline int radix__has_transparent_pud_hugepage(void)
 {
-	/* For radix 2M at PMD level means thp */
-	if (mmu_psize_defs[MMU_PAGE_2M].shift == PMD_SHIFT)
+	/* For radix 1G at PUD level means pud hugepage support */
+	if (mmu_psize_defs[MMU_PAGE_1G].shift == PUD_SHIFT)
 		return 1;
 	return 0;
 }
+#endif
 
-static inline int radix__has_transparent_pud_hugepage(void)
+static inline int radix__has_transparent_hugepage(void)
 {
-	/* For radix 1G at PUD level means pud hugepage support */
-	if (mmu_psize_defs[MMU_PAGE_1G].shift == PUD_SHIFT)
+	/* For radix 2M at PMD level means thp */
+	if (mmu_psize_defs[MMU_PAGE_2M].shift == PMD_SHIFT)
 		return 1;
 	return 0;
 }
-#endif
 
 struct vmem_altmap;
 struct dev_pagemap;
diff --git a/arch/powerpc/mm/book3s64/hash_pgtable.c b/arch/powerpc/mm/book3s64/hash_pgtable.c
index d9b5b751d7b7..50316f3fc5d3 100644
--- a/arch/powerpc/mm/book3s64/hash_pgtable.c
+++ b/arch/powerpc/mm/book3s64/hash_pgtable.c
@@ -391,6 +391,8 @@ pmd_t hash__pmdp_huge_get_and_clear(struct mm_struct *mm,
 	return old_pmd;
 }
 
+#endif /* CONFIG_TRANSPARENT_HUGEPAGE */
+
 int hash__has_transparent_hugepage(void)
 {
 
@@ -422,8 +424,6 @@ int hash__has_transparent_hugepage(void)
 }
 EXPORT_SYMBOL_GPL(hash__has_transparent_hugepage);
 
-#endif /* CONFIG_TRANSPARENT_HUGEPAGE */
-
 #ifdef CONFIG_STRICT_KERNEL_RWX
 
 struct change_memory_parms {
-- 
2.55.0



^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH v7 10/14] mips: move has_transparent_hugepage() out of THP guard
  2026-09-01  3:12 [PATCH v7 00/14] mm: thp: always enable mTHP support Luiz Capitulino
                   ` (8 preceding siblings ...)
  2026-09-01  3:12 ` [PATCH v7 09/14] powerpc: " Luiz Capitulino
@ 2026-09-01  3:12 ` Luiz Capitulino
  2026-09-01 11:42   ` Lance Yang
  2026-09-01  3:12 ` [PATCH v7 11/14] x86: " Luiz Capitulino
                   ` (3 subsequent siblings)
  13 siblings, 1 reply; 19+ messages in thread
From: Luiz Capitulino @ 2026-09-01  3:12 UTC (permalink / raw)
  To: linux-kernel, linux-mm, david, baolin.wang, ziy, lance.yang
  Cc: corbet, tsbogend, maddy, mpe, agordeev, gerald.schaefer, hca, gor,
	x86, tglx, mingo, bp, hughd, dave.hansen, djbw, vishal.l.verma,
	dave.jiang, akpm, yintirui, dev.jain, usama.arif

A future commit will introduce a kernel API to allow for checking if the
CPU supports PMD-sized pages. This API will be based on the
has_transparent_hugepage() implementation but will be orthogonal to THP
and therefore must work when CONFIG_TRANSPARENT_HUGEPAGE=n.

Move its definition out of the THP guard.

Signed-off-by: Luiz Capitulino <luizcap@redhat.com>
---
 arch/mips/include/asm/pgtable.h | 6 +++---
 arch/mips/mm/tlb-r4k.c          | 4 ----
 2 files changed, 3 insertions(+), 7 deletions(-)

diff --git a/arch/mips/include/asm/pgtable.h b/arch/mips/include/asm/pgtable.h
index fa7b935f947c..b038da872ec6 100644
--- a/arch/mips/include/asm/pgtable.h
+++ b/arch/mips/include/asm/pgtable.h
@@ -615,9 +615,6 @@ unsigned long io_remap_pfn_range_pfn(unsigned long pfn, unsigned long size);
 /* We don't have hardware dirty/accessed bits, generic_pmdp_establish is fine.*/
 #define pmdp_establish generic_pmdp_establish
 
-#define has_transparent_hugepage has_transparent_hugepage
-extern int has_transparent_hugepage(void);
-
 static inline int pmd_trans_huge(pmd_t pmd)
 {
 	return !!(pmd_val(pmd) & _PAGE_HUGE);
@@ -743,6 +740,9 @@ static inline pmd_t pmdp_huge_get_and_clear(struct mm_struct *mm,
 
 #endif /* CONFIG_TRANSPARENT_HUGEPAGE */
 
+#define has_transparent_hugepage has_transparent_hugepage
+extern int has_transparent_hugepage(void);
+
 #ifdef _PAGE_HUGE
 #define pmd_leaf(pmd)	((pmd_val(pmd) & _PAGE_HUGE) != 0)
 #define pud_leaf(pud)	((pud_val(pud) & _PAGE_HUGE) != 0)
diff --git a/arch/mips/mm/tlb-r4k.c b/arch/mips/mm/tlb-r4k.c
index 24fe85fa169d..f4e369342a56 100644
--- a/arch/mips/mm/tlb-r4k.c
+++ b/arch/mips/mm/tlb-r4k.c
@@ -432,8 +432,6 @@ void add_wired_entry(unsigned long entrylo0, unsigned long entrylo1,
 #endif
 }
 
-#ifdef CONFIG_TRANSPARENT_HUGEPAGE
-
 int has_transparent_hugepage(void)
 {
 	static unsigned int mask = -1;
@@ -452,8 +450,6 @@ int has_transparent_hugepage(void)
 }
 EXPORT_SYMBOL(has_transparent_hugepage);
 
-#endif /* CONFIG_TRANSPARENT_HUGEPAGE  */
-
 /*
  * Used for loading TLB entries before trap_init() has started, when we
  * don't actually want to add a wired entry which remains throughout the
-- 
2.55.0



^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH v7 11/14] x86: move has_transparent_hugepage() out of THP guard
  2026-09-01  3:12 [PATCH v7 00/14] mm: thp: always enable mTHP support Luiz Capitulino
                   ` (9 preceding siblings ...)
  2026-09-01  3:12 ` [PATCH v7 10/14] mips: " Luiz Capitulino
@ 2026-09-01  3:12 ` Luiz Capitulino
  2026-09-01  3:12 ` [PATCH v7 12/14] treewide: introduce arch_has_pmd_leaves() Luiz Capitulino
                   ` (2 subsequent siblings)
  13 siblings, 0 replies; 19+ messages in thread
From: Luiz Capitulino @ 2026-09-01  3:12 UTC (permalink / raw)
  To: linux-kernel, linux-mm, david, baolin.wang, ziy, lance.yang
  Cc: corbet, tsbogend, maddy, mpe, agordeev, gerald.schaefer, hca, gor,
	x86, tglx, mingo, bp, hughd, dave.hansen, djbw, vishal.l.verma,
	dave.jiang, akpm, yintirui, dev.jain, usama.arif

A future commit will introduce a kernel API to allow for checking if the
CPU supports PMD-sized pages. This API will be based on the
has_transparent_hugepage() implementation but will be orthogonal to THP
and therefore must work when CONFIG_TRANSPARENT_HUGEPAGE=n.

Move its definition out of the THP guard.

Signed-off-by: Luiz Capitulino <luizcap@redhat.com>
---
 arch/x86/include/asm/pgtable.h | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/arch/x86/include/asm/pgtable.h b/arch/x86/include/asm/pgtable.h
index d5f4917c1edc..f207e5268918 100644
--- a/arch/x86/include/asm/pgtable.h
+++ b/arch/x86/include/asm/pgtable.h
@@ -306,12 +306,6 @@ static inline int pud_trans_huge(pud_t pud)
 }
 #endif
 
-#define has_transparent_hugepage has_transparent_hugepage
-static inline int has_transparent_hugepage(void)
-{
-	return boot_cpu_has(X86_FEATURE_PSE);
-}
-
 #ifdef CONFIG_ARCH_SUPPORTS_PMD_PFNMAP
 static inline bool pmd_special(pmd_t pmd)
 {
@@ -337,6 +331,12 @@ static inline pud_t pud_mkspecial(pud_t pud)
 #endif	/* CONFIG_ARCH_SUPPORTS_PUD_PFNMAP */
 #endif /* CONFIG_TRANSPARENT_HUGEPAGE */
 
+#define has_transparent_hugepage has_transparent_hugepage
+static inline int has_transparent_hugepage(void)
+{
+	return boot_cpu_has(X86_FEATURE_PSE);
+}
+
 static inline pte_t pte_set_flags(pte_t pte, pteval_t set)
 {
 	pteval_t v = native_pte_val(pte);
-- 
2.55.0



^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH v7 12/14] treewide: introduce arch_has_pmd_leaves()
  2026-09-01  3:12 [PATCH v7 00/14] mm: thp: always enable mTHP support Luiz Capitulino
                   ` (10 preceding siblings ...)
  2026-09-01  3:12 ` [PATCH v7 11/14] x86: " Luiz Capitulino
@ 2026-09-01  3:12 ` Luiz Capitulino
  2026-09-01  3:12 ` [PATCH v7 13/14] mm: replace thp_disabled_by_hw() with pgtable_has_pmd_leaves() Luiz Capitulino
  2026-09-01  3:12 ` [PATCH v7 14/14] mm: thp: always enable mTHP support Luiz Capitulino
  13 siblings, 0 replies; 19+ messages in thread
From: Luiz Capitulino @ 2026-09-01  3:12 UTC (permalink / raw)
  To: linux-kernel, linux-mm, david, baolin.wang, ziy, lance.yang
  Cc: corbet, tsbogend, maddy, mpe, agordeev, gerald.schaefer, hca, gor,
	x86, tglx, mingo, bp, hughd, dave.hansen, djbw, vishal.l.verma,
	dave.jiang, akpm, yintirui, dev.jain, usama.arif

Now that all the has_transparent_hugepage() callers have been converted
to pgtable_has_pmd_leaves(), this commit does two things:

1. Rename has_transparent_hugepage() arch implementations to
   arch_has_pmd_leaves(), since that's what the helper checks for

2. Introduce the default implementation of arch_has_pmd_leaves() as
   IS_ENABLED(CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE). This means that if
   the arch doesn't implement arch_has_pmd_leaves() we default to checking
   CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE as a way to determine if
   PMD-sized pages are supported

Note that arch_has_pmd_leaves() is supposed to be called only by
pgtable_leaf_support_init(). The remaining exception is hugepage_init()
which will be converted in a future commit.

Signed-off-by: Luiz Capitulino <luizcap@redhat.com>
---
 arch/mips/include/asm/pgtable.h               |  4 ++--
 arch/mips/mm/tlb-r4k.c                        |  4 ++--
 arch/powerpc/include/asm/book3s/64/hash-4k.h  |  2 +-
 arch/powerpc/include/asm/book3s/64/hash-64k.h |  2 +-
 arch/powerpc/include/asm/book3s/64/pgtable.h  | 10 +++++-----
 arch/powerpc/include/asm/book3s/64/radix.h    |  2 +-
 arch/powerpc/mm/book3s64/hash_pgtable.c       |  4 ++--
 arch/s390/include/asm/pgtable.h               |  4 ++--
 arch/x86/include/asm/pgtable.h                |  4 ++--
 include/linux/pgtable.h                       |  4 ++--
 mm/huge_memory.c                              |  2 +-
 mm/memory.c                                   |  2 +-
 12 files changed, 22 insertions(+), 22 deletions(-)

diff --git a/arch/mips/include/asm/pgtable.h b/arch/mips/include/asm/pgtable.h
index b038da872ec6..2a0a7ddf8bee 100644
--- a/arch/mips/include/asm/pgtable.h
+++ b/arch/mips/include/asm/pgtable.h
@@ -740,8 +740,8 @@ static inline pmd_t pmdp_huge_get_and_clear(struct mm_struct *mm,
 
 #endif /* CONFIG_TRANSPARENT_HUGEPAGE */
 
-#define has_transparent_hugepage has_transparent_hugepage
-extern int has_transparent_hugepage(void);
+#define arch_has_pmd_leaves arch_has_pmd_leaves
+extern int arch_has_pmd_leaves(void);
 
 #ifdef _PAGE_HUGE
 #define pmd_leaf(pmd)	((pmd_val(pmd) & _PAGE_HUGE) != 0)
diff --git a/arch/mips/mm/tlb-r4k.c b/arch/mips/mm/tlb-r4k.c
index f4e369342a56..9339ebb0815f 100644
--- a/arch/mips/mm/tlb-r4k.c
+++ b/arch/mips/mm/tlb-r4k.c
@@ -432,7 +432,7 @@ void add_wired_entry(unsigned long entrylo0, unsigned long entrylo1,
 #endif
 }
 
-int has_transparent_hugepage(void)
+int arch_has_pmd_leaves(void)
 {
 	static unsigned int mask = -1;
 
@@ -448,7 +448,7 @@ int has_transparent_hugepage(void)
 	}
 	return mask == PM_HUGE_MASK;
 }
-EXPORT_SYMBOL(has_transparent_hugepage);
+EXPORT_SYMBOL(arch_has_pmd_leaves);
 
 /*
  * Used for loading TLB entries before trap_init() has started, when we
diff --git a/arch/powerpc/include/asm/book3s/64/hash-4k.h b/arch/powerpc/include/asm/book3s/64/hash-4k.h
index 79511e6abfca..d532e3f0dfc3 100644
--- a/arch/powerpc/include/asm/book3s/64/hash-4k.h
+++ b/arch/powerpc/include/asm/book3s/64/hash-4k.h
@@ -167,7 +167,7 @@ extern pmd_t hash__pmdp_huge_get_and_clear(struct mm_struct *mm,
 				       unsigned long addr, pmd_t *pmdp);
 #endif
 
-extern int hash__has_transparent_hugepage(void);
+extern int hash__arch_has_pmd_leaves(void);
 #endif /* !__ASSEMBLER__ */
 
 #endif /* _ASM_POWERPC_BOOK3S_64_HASH_4K_H */
diff --git a/arch/powerpc/include/asm/book3s/64/hash-64k.h b/arch/powerpc/include/asm/book3s/64/hash-64k.h
index a4a44a112ff9..d523c80f44f7 100644
--- a/arch/powerpc/include/asm/book3s/64/hash-64k.h
+++ b/arch/powerpc/include/asm/book3s/64/hash-64k.h
@@ -280,7 +280,7 @@ extern pmd_t hash__pmdp_huge_get_and_clear(struct mm_struct *mm,
 				       unsigned long addr, pmd_t *pmdp);
 #endif /*  CONFIG_TRANSPARENT_HUGEPAGE */
 
-extern int hash__has_transparent_hugepage(void);
+extern int hash__arch_has_pmd_leaves(void);
 #endif	/* __ASSEMBLER__ */
 
 #endif /* _ASM_POWERPC_BOOK3S_64_HASH_64K_H */
diff --git a/arch/powerpc/include/asm/book3s/64/pgtable.h b/arch/powerpc/include/asm/book3s/64/pgtable.h
index 2a795f6d9263..41166d44fa75 100644
--- a/arch/powerpc/include/asm/book3s/64/pgtable.h
+++ b/arch/powerpc/include/asm/book3s/64/pgtable.h
@@ -1432,14 +1432,14 @@ static inline bool arch_needs_pgtable_deposit(void)
 
 #endif /* CONFIG_TRANSPARENT_HUGEPAGE */
 
-extern int hash__has_transparent_hugepage(void);
-static inline int has_transparent_hugepage(void)
+extern int hash__arch_has_pmd_leaves(void);
+static inline int arch_has_pmd_leaves(void)
 {
 	if (radix_enabled())
-		return radix__has_transparent_hugepage();
-	return hash__has_transparent_hugepage();
+		return radix__arch_has_pmd_leaves();
+	return hash__arch_has_pmd_leaves();
 }
-#define has_transparent_hugepage has_transparent_hugepage
+#define arch_has_pmd_leaves arch_has_pmd_leaves
 
 #define __HAVE_ARCH_PTEP_MODIFY_PROT_TRANSACTION
 pte_t ptep_modify_prot_start(struct vm_area_struct *, unsigned long, pte_t *);
diff --git a/arch/powerpc/include/asm/book3s/64/radix.h b/arch/powerpc/include/asm/book3s/64/radix.h
index 50545cf519bd..e8b74528953f 100644
--- a/arch/powerpc/include/asm/book3s/64/radix.h
+++ b/arch/powerpc/include/asm/book3s/64/radix.h
@@ -307,7 +307,7 @@ static inline int radix__has_transparent_pud_hugepage(void)
 }
 #endif
 
-static inline int radix__has_transparent_hugepage(void)
+static inline int radix__arch_has_pmd_leaves(void)
 {
 	/* For radix 2M at PMD level means thp */
 	if (mmu_psize_defs[MMU_PAGE_2M].shift == PMD_SHIFT)
diff --git a/arch/powerpc/mm/book3s64/hash_pgtable.c b/arch/powerpc/mm/book3s64/hash_pgtable.c
index 50316f3fc5d3..a67bc1723404 100644
--- a/arch/powerpc/mm/book3s64/hash_pgtable.c
+++ b/arch/powerpc/mm/book3s64/hash_pgtable.c
@@ -393,7 +393,7 @@ pmd_t hash__pmdp_huge_get_and_clear(struct mm_struct *mm,
 
 #endif /* CONFIG_TRANSPARENT_HUGEPAGE */
 
-int hash__has_transparent_hugepage(void)
+int hash__arch_has_pmd_leaves(void)
 {
 
 	if (!mmu_has_feature(MMU_FTR_16M_PAGE))
@@ -422,7 +422,7 @@ int hash__has_transparent_hugepage(void)
 
 	return 1;
 }
-EXPORT_SYMBOL_GPL(hash__has_transparent_hugepage);
+EXPORT_SYMBOL_GPL(hash__arch_has_pmd_leaves);
 
 #ifdef CONFIG_STRICT_KERNEL_RWX
 
diff --git a/arch/s390/include/asm/pgtable.h b/arch/s390/include/asm/pgtable.h
index 5aa8f621df04..24ee90c7e9bf 100644
--- a/arch/s390/include/asm/pgtable.h
+++ b/arch/s390/include/asm/pgtable.h
@@ -1827,8 +1827,8 @@ static inline int pmd_trans_huge(pmd_t pmd)
 }
 #endif /* CONFIG_TRANSPARENT_HUGEPAGE */
 
-#define has_transparent_hugepage has_transparent_hugepage
-static inline int has_transparent_hugepage(void)
+#define arch_has_pmd_leaves arch_has_pmd_leaves
+static inline int arch_has_pmd_leaves(void)
 {
 	return cpu_has_edat1() ? 1 : 0;
 }
diff --git a/arch/x86/include/asm/pgtable.h b/arch/x86/include/asm/pgtable.h
index f207e5268918..17b060184b1d 100644
--- a/arch/x86/include/asm/pgtable.h
+++ b/arch/x86/include/asm/pgtable.h
@@ -331,8 +331,8 @@ static inline pud_t pud_mkspecial(pud_t pud)
 #endif	/* CONFIG_ARCH_SUPPORTS_PUD_PFNMAP */
 #endif /* CONFIG_TRANSPARENT_HUGEPAGE */
 
-#define has_transparent_hugepage has_transparent_hugepage
-static inline int has_transparent_hugepage(void)
+#define arch_has_pmd_leaves arch_has_pmd_leaves
+static inline int arch_has_pmd_leaves(void)
 {
 	return boot_cpu_has(X86_FEATURE_PSE);
 }
diff --git a/include/linux/pgtable.h b/include/linux/pgtable.h
index 4c00cf53e183..98b0a8759ab1 100644
--- a/include/linux/pgtable.h
+++ b/include/linux/pgtable.h
@@ -2344,8 +2344,8 @@ static inline void __init pgtable_leaf_support_init(void) { }
 #endif
 #endif
 
-#ifndef has_transparent_hugepage
-#define has_transparent_hugepage() IS_BUILTIN(CONFIG_TRANSPARENT_HUGEPAGE)
+#ifndef arch_has_pmd_leaves
+#define arch_has_pmd_leaves() IS_ENABLED(CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE)
 #endif
 
 #ifndef has_transparent_pud_hugepage
diff --git a/mm/huge_memory.c b/mm/huge_memory.c
index 54494c3fa983..469d98e01b5f 100644
--- a/mm/huge_memory.c
+++ b/mm/huge_memory.c
@@ -1095,7 +1095,7 @@ static int __init hugepage_init(void)
 	int err;
 	struct kobject *hugepage_kobj;
 
-	if (!has_transparent_hugepage()) {
+	if (!arch_has_pmd_leaves()) {
 		transparent_hugepage_flags = 1 << TRANSPARENT_HUGEPAGE_UNSUPPORTED;
 		return -EINVAL;
 	}
diff --git a/mm/memory.c b/mm/memory.c
index 69ab1bb54853..ed5029745dfb 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -169,7 +169,7 @@ EXPORT_SYMBOL(__arch_has_pmd_leaves_key);
 
 void __init pgtable_leaf_support_init(void)
 {
-	if (!has_transparent_hugepage())
+	if (!arch_has_pmd_leaves())
 		static_branch_disable(&__arch_has_pmd_leaves_key);
 }
 
-- 
2.55.0



^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH v7 13/14] mm: replace thp_disabled_by_hw() with pgtable_has_pmd_leaves()
  2026-09-01  3:12 [PATCH v7 00/14] mm: thp: always enable mTHP support Luiz Capitulino
                   ` (11 preceding siblings ...)
  2026-09-01  3:12 ` [PATCH v7 12/14] treewide: introduce arch_has_pmd_leaves() Luiz Capitulino
@ 2026-09-01  3:12 ` Luiz Capitulino
  2026-09-01  3:12 ` [PATCH v7 14/14] mm: thp: always enable mTHP support Luiz Capitulino
  13 siblings, 0 replies; 19+ messages in thread
From: Luiz Capitulino @ 2026-09-01  3:12 UTC (permalink / raw)
  To: linux-kernel, linux-mm, david, baolin.wang, ziy, lance.yang
  Cc: corbet, tsbogend, maddy, mpe, agordeev, gerald.schaefer, hca, gor,
	x86, tglx, mingo, bp, hughd, dave.hansen, djbw, vishal.l.verma,
	dave.jiang, akpm, yintirui, dev.jain, usama.arif

Despite its name, thp_disabled_by_hw() just checks whether the
architecture supports PMD-sized pages. It returns true when
TRANSPARENT_HUGEPAGE_UNSUPPORTED is set in transparent_hugepage_flags,
this only occurs if the architecture implements arch_has_pmd_leaves()
and that function returns false.

Since pgtable_has_pmd_leaves() provides the same semantics, use it
instead.

Reviewed-by: Lance Yang <lance.yang@linux.dev>
Reviewed-by: Baolin Wang <baolin.wang@linux.alibaba.com>
Acked-by: Zi Yan <ziy@nvidia.com>
Acked-by: David Hildenbrand (Arm) <david@kernel.org>
Signed-off-by: Luiz Capitulino <luizcap@redhat.com>
---
 include/linux/huge_mm.h | 7 -------
 mm/huge_memory.c        | 6 ++----
 mm/memory.c             | 2 +-
 mm/shmem.c              | 2 +-
 4 files changed, 4 insertions(+), 13 deletions(-)

diff --git a/include/linux/huge_mm.h b/include/linux/huge_mm.h
index c745f7ad2298..525acea2eb59 100644
--- a/include/linux/huge_mm.h
+++ b/include/linux/huge_mm.h
@@ -47,7 +47,6 @@ vm_fault_t vmf_insert_folio_pud(struct vm_fault *vmf, struct folio *folio,
 				bool write);
 
 enum transparent_hugepage_flag {
-	TRANSPARENT_HUGEPAGE_UNSUPPORTED,
 	TRANSPARENT_HUGEPAGE_FLAG,
 	TRANSPARENT_HUGEPAGE_REQ_MADV_FLAG,
 	TRANSPARENT_HUGEPAGE_DEFRAG_DIRECT_FLAG,
@@ -383,12 +382,6 @@ static inline bool vma_thp_disabled(struct vm_area_struct *vma,
 	return mm_flags_test(MMF_DISABLE_THP_EXCEPT_ADVISED, vma->vm_mm);
 }
 
-static inline bool thp_disabled_by_hw(void)
-{
-	/* If the hardware/firmware marked hugepage support disabled. */
-	return transparent_hugepage_flags & (1 << TRANSPARENT_HUGEPAGE_UNSUPPORTED);
-}
-
 unsigned long thp_get_unmapped_area(struct file *filp, unsigned long addr,
 		unsigned long len, unsigned long pgoff, unsigned long flags);
 unsigned long thp_get_unmapped_area_vmaflags(struct file *filp, unsigned long addr,
diff --git a/mm/huge_memory.c b/mm/huge_memory.c
index 469d98e01b5f..d5e65cac6a16 100644
--- a/mm/huge_memory.c
+++ b/mm/huge_memory.c
@@ -204,7 +204,7 @@ unsigned long __thp_vma_allowable_orders(struct vm_area_struct *vma,
 	if (!vma->vm_mm)		/* vdso */
 		return 0;
 
-	if (thp_disabled_by_hw() || vma_thp_disabled(vma, vm_flags, forced_collapse))
+	if (!pgtable_has_pmd_leaves() || vma_thp_disabled(vma, vm_flags, forced_collapse))
 		return 0;
 
 	/* khugepaged doesn't collapse DAX vma, but page fault is fine. */
@@ -1095,10 +1095,8 @@ static int __init hugepage_init(void)
 	int err;
 	struct kobject *hugepage_kobj;
 
-	if (!arch_has_pmd_leaves()) {
-		transparent_hugepage_flags = 1 << TRANSPARENT_HUGEPAGE_UNSUPPORTED;
+	if (!pgtable_has_pmd_leaves())
 		return -EINVAL;
-	}
 
 	/*
 	 * hugepages can't be allocated by the buddy allocator
diff --git a/mm/memory.c b/mm/memory.c
index ed5029745dfb..6be55fc39383 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -5611,7 +5611,7 @@ vm_fault_t do_set_pmd(struct vm_fault *vmf, struct folio *folio, struct page *pa
 	 * PMD mappings if THPs are disabled. As we already have a THP,
 	 * behave as if we are forcing a collapse.
 	 */
-	if (thp_disabled_by_hw() || vma_thp_disabled(vma, vma->vm_flags,
+	if (!pgtable_has_pmd_leaves() || vma_thp_disabled(vma, vma->vm_flags,
 						     /* forced_collapse=*/ true))
 		return ret;
 
diff --git a/mm/shmem.c b/mm/shmem.c
index c285cb7fd32e..73281fa060ed 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -2047,7 +2047,7 @@ unsigned long shmem_allowable_huge_orders(struct inode *inode,
 	vm_flags_t vm_flags = vma ? vma->vm_flags : 0;
 	unsigned int global_orders;
 
-	if (thp_disabled_by_hw() || (vma && vma_thp_disabled(vma, vm_flags, shmem_huge_force)))
+	if (!pgtable_has_pmd_leaves() || (vma && vma_thp_disabled(vma, vm_flags, shmem_huge_force)))
 		return 0;
 
 	global_orders = shmem_huge_global_enabled(inode, index, write_end,
-- 
2.55.0



^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH v7 14/14] mm: thp: always enable mTHP support
  2026-09-01  3:12 [PATCH v7 00/14] mm: thp: always enable mTHP support Luiz Capitulino
                   ` (12 preceding siblings ...)
  2026-09-01  3:12 ` [PATCH v7 13/14] mm: replace thp_disabled_by_hw() with pgtable_has_pmd_leaves() Luiz Capitulino
@ 2026-09-01  3:12 ` Luiz Capitulino
  13 siblings, 0 replies; 19+ messages in thread
From: Luiz Capitulino @ 2026-09-01  3:12 UTC (permalink / raw)
  To: linux-kernel, linux-mm, david, baolin.wang, ziy, lance.yang
  Cc: corbet, tsbogend, maddy, mpe, agordeev, gerald.schaefer, hca, gor,
	x86, tglx, mingo, bp, hughd, dave.hansen, djbw, vishal.l.verma,
	dave.jiang, akpm, yintirui, dev.jain, usama.arif

If PMD-sized pages are not supported on an architecture (ie. the
arch implements arch_has_pmd_leaves() and it returns false) then the
current code disables all THP, including mTHP.

This commit fixes this by allowing mTHP to be always enabled for all
archs. When PMD-sized pages are not supported, its sysfs entry won't be
created and their mapping will be disallowed at page-fault time.

Similarly, this commit implements the following changes for shmem in
shmem_allowable_huge_orders():

 - Drop the pgtable_has_pmd_leaves() check so that mTHP sizes are
   considered
 - Filter out PMD and PUD orders from allowable orders when
   PMD-sized pages are not supported by the CPU

Reviewed-by: Baolin Wang <baolin.wang@linux.alibaba.com>
Signed-off-by: Luiz Capitulino <luizcap@redhat.com>
---
 mm/huge_memory.c | 25 ++++++++++++++++++++-----
 mm/shmem.c       | 14 +++++++++-----
 2 files changed, 29 insertions(+), 10 deletions(-)

diff --git a/mm/huge_memory.c b/mm/huge_memory.c
index d5e65cac6a16..95b2191174fc 100644
--- a/mm/huge_memory.c
+++ b/mm/huge_memory.c
@@ -197,6 +197,15 @@ unsigned long __thp_vma_allowable_orders(struct vm_area_struct *vma,
 	else
 		supported_orders = THP_ORDERS_ALL_FILE_DEFAULT;
 
+	if (!pgtable_has_pmd_leaves()) {
+		/*
+		 * If the CPU does not support PMD leaves, assume for
+		 * now that it does not support PUD leaves and disable
+		 * both folio orders.
+		 */
+		supported_orders &= ~(BIT(PMD_ORDER) | BIT(PUD_ORDER));
+	}
+
 	orders &= supported_orders;
 	if (!orders)
 		return 0;
@@ -204,7 +213,7 @@ unsigned long __thp_vma_allowable_orders(struct vm_area_struct *vma,
 	if (!vma->vm_mm)		/* vdso */
 		return 0;
 
-	if (!pgtable_has_pmd_leaves() || vma_thp_disabled(vma, vm_flags, forced_collapse))
+	if (vma_thp_disabled(vma, vm_flags, forced_collapse))
 		return 0;
 
 	/* khugepaged doesn't collapse DAX vma, but page fault is fine. */
@@ -984,7 +993,7 @@ static int __init hugepage_init_sysfs(struct kobject **hugepage_kobj)
 	 * disable all other sizes. powerpc's PMD_ORDER isn't a compile-time
 	 * constant so we have to do this here.
 	 */
-	if (!anon_orders_configured)
+	if (!anon_orders_configured && pgtable_has_pmd_leaves())
 		huge_anon_orders_inherit = BIT(PMD_ORDER);
 
 	*hugepage_kobj = kobject_create_and_add("transparent_hugepage", mm_kobj);
@@ -1006,6 +1015,15 @@ static int __init hugepage_init_sysfs(struct kobject **hugepage_kobj)
 	}
 
 	orders = THP_ORDERS_ALL_ANON | THP_ORDERS_ALL_FILE_DEFAULT;
+	if (!pgtable_has_pmd_leaves()) {
+		/*
+		 * If the CPU does not support PMD leaves, assume for
+		 * now that it does not support PUD leaves and disable
+		 * both folio orders.
+		 */
+		orders &= ~(BIT(PMD_ORDER) | BIT(PUD_ORDER));
+	}
+
 	order = highest_order(orders);
 	while (orders) {
 		thpsize = thpsize_create(order, *hugepage_kobj);
@@ -1095,9 +1113,6 @@ static int __init hugepage_init(void)
 	int err;
 	struct kobject *hugepage_kobj;
 
-	if (!pgtable_has_pmd_leaves())
-		return -EINVAL;
-
 	/*
 	 * hugepages can't be allocated by the buddy allocator
 	 */
diff --git a/mm/shmem.c b/mm/shmem.c
index 73281fa060ed..163e7dc4b2a8 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -2045,16 +2045,19 @@ unsigned long shmem_allowable_huge_orders(struct inode *inode,
 	unsigned long mask = READ_ONCE(huge_shmem_orders_always);
 	unsigned long within_size_orders = READ_ONCE(huge_shmem_orders_within_size);
 	vm_flags_t vm_flags = vma ? vma->vm_flags : 0;
-	unsigned int global_orders;
+	unsigned int global_orders, disabled_orders = 0;
 
-	if (!pgtable_has_pmd_leaves() || (vma && vma_thp_disabled(vma, vm_flags, shmem_huge_force)))
+	if (vma && vma_thp_disabled(vma, vm_flags, shmem_huge_force))
 		return 0;
 
+	if (!pgtable_has_pmd_leaves())
+		disabled_orders = BIT(PMD_ORDER);
+
 	global_orders = shmem_huge_global_enabled(inode, index, write_end,
 						  shmem_huge_force, vma, vm_flags);
 	/* Tmpfs huge pages allocation */
 	if (!vma || !vma_is_anon_shmem(vma))
-		return global_orders;
+		return global_orders & ~disabled_orders;
 
 	/*
 	 * Following the 'deny' semantics of the top level, force the huge
@@ -2068,7 +2071,7 @@ unsigned long shmem_allowable_huge_orders(struct inode *inode,
 	 * means non-PMD sized THP can not override 'huge' mount option now.
 	 */
 	if (shmem_huge == SHMEM_HUGE_FORCE)
-		return READ_ONCE(huge_shmem_orders_inherit);
+		return READ_ONCE(huge_shmem_orders_inherit) & ~disabled_orders;
 
 	/* Allow mTHP that will be fully within i_size. */
 	mask |= shmem_get_orders_within_size(inode, within_size_orders, index, 0);
@@ -2079,6 +2082,7 @@ unsigned long shmem_allowable_huge_orders(struct inode *inode,
 	if (global_orders > 0)
 		mask |= READ_ONCE(huge_shmem_orders_inherit);
 
+	mask &= ~disabled_orders;
 	return THP_ORDERS_ALL_FILE_DEFAULT & mask;
 }
 
@@ -5626,7 +5630,7 @@ void __init shmem_init(void)
 	 * Default to setting PMD-sized THP to inherit the global setting and
 	 * disable all other multi-size THPs.
 	 */
-	if (!shmem_orders_configured)
+	if (!shmem_orders_configured && pgtable_has_pmd_leaves())
 		huge_shmem_orders_inherit = BIT(HPAGE_PMD_ORDER);
 #endif
 	return;
-- 
2.55.0



^ permalink raw reply related	[flat|nested] 19+ messages in thread

* Re: [PATCH v7 10/14] mips: move has_transparent_hugepage() out of THP guard
  2026-09-01  3:12 ` [PATCH v7 10/14] mips: " Luiz Capitulino
@ 2026-09-01 11:42   ` Lance Yang
  2026-09-01 19:53     ` Luiz Capitulino
  0 siblings, 1 reply; 19+ messages in thread
From: Lance Yang @ 2026-09-01 11:42 UTC (permalink / raw)
  To: Luiz Capitulino
  Cc: corbet, ziy, baolin.wang, tsbogend, maddy, mpe, agordeev,
	gerald.schaefer, david, hca, gor, x86, tglx, mingo, bp, hughd,
	linux-kernel, dave.hansen, djbw, vishal.l.verma, dave.jiang, akpm,
	yintirui, dev.jain, usama.arif, linux-mm



On 2026/9/1 11:12, Luiz Capitulino wrote:
> A future commit will introduce a kernel API to allow for checking if the
> CPU supports PMD-sized pages. This API will be based on the
> has_transparent_hugepage() implementation but will be orthogonal to THP
> and therefore must work when CONFIG_TRANSPARENT_HUGEPAGE=n.
> 
> Move its definition out of the THP guard.
> 
> Signed-off-by: Luiz Capitulino <luizcap@redhat.com>
> ---
>   arch/mips/include/asm/pgtable.h | 6 +++---
>   arch/mips/mm/tlb-r4k.c          | 4 ----
>   2 files changed, 3 insertions(+), 7 deletions(-)
> 
> diff --git a/arch/mips/include/asm/pgtable.h b/arch/mips/include/asm/pgtable.h
> index fa7b935f947c..b038da872ec6 100644
> --- a/arch/mips/include/asm/pgtable.h
> +++ b/arch/mips/include/asm/pgtable.h
> @@ -615,9 +615,6 @@ unsigned long io_remap_pfn_range_pfn(unsigned long pfn, unsigned long size);
>   /* We don't have hardware dirty/accessed bits, generic_pmdp_establish is fine.*/
>   #define pmdp_establish generic_pmdp_establish
>   
> -#define has_transparent_hugepage has_transparent_hugepage
> -extern int has_transparent_hugepage(void);

Assume a decstation_defconfig build. CPU_R3000 selects CPU_R3K_TLB, so the
Makefile builds tlb-r3k.o but not tlb-r4k.o IIUC ...

The only MIPS definition is in tlb-r4k.c, so R3000 would fail to link with
an undefined reference ... no?

Cheers, Lance

> -
>   static inline int pmd_trans_huge(pmd_t pmd)
>   {
>   	return !!(pmd_val(pmd) & _PAGE_HUGE);
> @@ -743,6 +740,9 @@ static inline pmd_t pmdp_huge_get_and_clear(struct mm_struct *mm,
>   
>   #endif /* CONFIG_TRANSPARENT_HUGEPAGE */
>   
> +#define has_transparent_hugepage has_transparent_hugepage
> +extern int has_transparent_hugepage(void);
> +
>   #ifdef _PAGE_HUGE
>   #define pmd_leaf(pmd)	((pmd_val(pmd) & _PAGE_HUGE) != 0)
>   #define pud_leaf(pud)	((pud_val(pud) & _PAGE_HUGE) != 0)
> diff --git a/arch/mips/mm/tlb-r4k.c b/arch/mips/mm/tlb-r4k.c
> index 24fe85fa169d..f4e369342a56 100644
> --- a/arch/mips/mm/tlb-r4k.c
> +++ b/arch/mips/mm/tlb-r4k.c
> @@ -432,8 +432,6 @@ void add_wired_entry(unsigned long entrylo0, unsigned long entrylo1,
>   #endif
>   }
>   
> -#ifdef CONFIG_TRANSPARENT_HUGEPAGE
> -
>   int has_transparent_hugepage(void)
>   {
>   	static unsigned int mask = -1;
> @@ -452,8 +450,6 @@ int has_transparent_hugepage(void)
>   }
>   EXPORT_SYMBOL(has_transparent_hugepage);
>   
> -#endif /* CONFIG_TRANSPARENT_HUGEPAGE  */
> -
>   /*
>    * Used for loading TLB entries before trap_init() has started, when we
>    * don't actually want to add a wired entry which remains throughout the



^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH v7 10/14] mips: move has_transparent_hugepage() out of THP guard
  2026-09-01 11:42   ` Lance Yang
@ 2026-09-01 19:53     ` Luiz Capitulino
  2026-09-01 22:25       ` Thomas Bogendoerfer
  0 siblings, 1 reply; 19+ messages in thread
From: Luiz Capitulino @ 2026-09-01 19:53 UTC (permalink / raw)
  To: Lance Yang
  Cc: corbet, ziy, baolin.wang, tsbogend, maddy, mpe, agordeev,
	gerald.schaefer, david, hca, gor, x86, tglx, mingo, bp, hughd,
	linux-kernel, dave.hansen, djbw, vishal.l.verma, dave.jiang, akpm,
	yintirui, dev.jain, usama.arif, linux-mm

On 2026-09-01 07:42, Lance Yang wrote:
> 
> 
> On 2026/9/1 11:12, Luiz Capitulino wrote:
>> A future commit will introduce a kernel API to allow for checking if the
>> CPU supports PMD-sized pages. This API will be based on the
>> has_transparent_hugepage() implementation but will be orthogonal to THP
>> and therefore must work when CONFIG_TRANSPARENT_HUGEPAGE=n.
>>
>> Move its definition out of the THP guard.
>>
>> Signed-off-by: Luiz Capitulino <luizcap@redhat.com>
>> ---
>>   arch/mips/include/asm/pgtable.h | 6 +++---
>>   arch/mips/mm/tlb-r4k.c          | 4 ----
>>   2 files changed, 3 insertions(+), 7 deletions(-)
>>
>> diff --git a/arch/mips/include/asm/pgtable.h b/arch/mips/include/asm/pgtable.h
>> index fa7b935f947c..b038da872ec6 100644
>> --- a/arch/mips/include/asm/pgtable.h
>> +++ b/arch/mips/include/asm/pgtable.h
>> @@ -615,9 +615,6 @@ unsigned long io_remap_pfn_range_pfn(unsigned long pfn, unsigned long size);
>>   /* We don't have hardware dirty/accessed bits, generic_pmdp_establish is fine.*/
>>   #define pmdp_establish generic_pmdp_establish
>> -#define has_transparent_hugepage has_transparent_hugepage
>> -extern int has_transparent_hugepage(void);
> 
> Assume a decstation_defconfig build. CPU_R3000 selects CPU_R3K_TLB, so the
> Makefile builds tlb-r3k.o but not tlb-r4k.o IIUC ...
> 
> The only MIPS definition is in tlb-r4k.c, so R3000 would fail to link with
> an undefined reference ... no?

Yes, you're right. I can reproduce this. Would the solution below be
acceptable?

diff --git a/arch/mips/include/asm/pgtable.h b/arch/mips/include/asm/pgtable.h
index fa7b935f947c..b038da872ec6 100644
--- a/arch/mips/include/asm/pgtable.h
+++ b/arch/mips/include/asm/pgtable.h
@@ -615,9 +615,6 @@ unsigned long io_remap_pfn_range_pfn(unsigned long pfn, unsigned long size);
  /* We don't have hardware dirty/accessed bits, generic_pmdp_establish is fine.*/
  #define pmdp_establish generic_pmdp_establish
  
-#define has_transparent_hugepage has_transparent_hugepage
-extern int has_transparent_hugepage(void);
-
  static inline int pmd_trans_huge(pmd_t pmd)
  {
  	return !!(pmd_val(pmd) & _PAGE_HUGE);
@@ -743,6 +740,9 @@ static inline pmd_t pmdp_huge_get_and_clear(struct mm_struct *mm,
  
  #endif /* CONFIG_TRANSPARENT_HUGEPAGE */
  
+#define has_transparent_hugepage has_transparent_hugepage
+extern int has_transparent_hugepage(void);
+
  #ifdef _PAGE_HUGE
  #define pmd_leaf(pmd)	((pmd_val(pmd) & _PAGE_HUGE) != 0)
  #define pud_leaf(pud)	((pud_val(pud) & _PAGE_HUGE) != 0)
diff --git a/arch/mips/mm/pgtable.c b/arch/mips/mm/pgtable.c
index 10835414819f..3a5b411493d9 100644
--- a/arch/mips/mm/pgtable.c
+++ b/arch/mips/mm/pgtable.c
@@ -23,3 +23,30 @@ pgd_t *pgd_alloc(struct mm_struct *mm)
  	return ret;
  }
  EXPORT_SYMBOL_GPL(pgd_alloc);
+
+#if defined(CONFIG_CPU_R4K_CACHE_TLB) || \
+    defined(CONFIG_CPU_SB1) || \
+    defined(CONFIG_CPU_CAVIUM_OCTEON)
+int has_transparent_hugepage(void)
+{
+	static unsigned int mask = -1;
+
+	if (mask == -1) {	/* first call comes during __init */
+		unsigned long flags;
+
+		local_irq_save(flags);
+		write_c0_pagemask(PM_HUGE_MASK);
+		back_to_back_c0_hazard();
+		mask = read_c0_pagemask();
+		write_c0_pagemask(PM_DEFAULT_MASK);
+		local_irq_restore(flags);
+	}
+	return mask == PM_HUGE_MASK;
+}
+#else
+int has_transparent_hugepage(void)
+{
+	return 0;
+}
+#endif
+EXPORT_SYMBOL(has_transparent_hugepage);
diff --git a/arch/mips/mm/tlb-r4k.c b/arch/mips/mm/tlb-r4k.c
index 24fe85fa169d..625f1c0dd71e 100644
--- a/arch/mips/mm/tlb-r4k.c
+++ b/arch/mips/mm/tlb-r4k.c
@@ -432,28 +432,6 @@ void add_wired_entry(unsigned long entrylo0, unsigned long entrylo1,
  #endif
  }
  
-#ifdef CONFIG_TRANSPARENT_HUGEPAGE
-
-int has_transparent_hugepage(void)
-{
-	static unsigned int mask = -1;
-
-	if (mask == -1) {	/* first call comes during __init */
-		unsigned long flags;
-
-		local_irq_save(flags);
-		write_c0_pagemask(PM_HUGE_MASK);
-		back_to_back_c0_hazard();
-		mask = read_c0_pagemask();
-		write_c0_pagemask(PM_DEFAULT_MASK);
-		local_irq_restore(flags);
-	}
-	return mask == PM_HUGE_MASK;
-}
-EXPORT_SYMBOL(has_transparent_hugepage);
-
-#endif /* CONFIG_TRANSPARENT_HUGEPAGE  */
-
  /*
   * Used for loading TLB entries before trap_init() has started, when we
   * don't actually want to add a wired entry which remains throughout the
-- 
2.55.0



^ permalink raw reply related	[flat|nested] 19+ messages in thread

* Re: [PATCH v7 10/14] mips: move has_transparent_hugepage() out of THP guard
  2026-09-01 19:53     ` Luiz Capitulino
@ 2026-09-01 22:25       ` Thomas Bogendoerfer
  2026-09-02 15:12         ` Luiz Capitulino
  0 siblings, 1 reply; 19+ messages in thread
From: Thomas Bogendoerfer @ 2026-09-01 22:25 UTC (permalink / raw)
  To: Luiz Capitulino
  Cc: Lance Yang, corbet, ziy, baolin.wang, maddy, mpe, agordeev,
	gerald.schaefer, david, hca, gor, x86, tglx, mingo, bp, hughd,
	linux-kernel, dave.hansen, djbw, vishal.l.verma, dave.jiang, akpm,
	yintirui, dev.jain, usama.arif, linux-mm

On Tue, Sep 01, 2026 at 03:53:18PM -0400, Luiz Capitulino wrote:
> On 2026-09-01 07:42, Lance Yang wrote:
> > 
> > 
> > On 2026/9/1 11:12, Luiz Capitulino wrote:
> > > A future commit will introduce a kernel API to allow for checking if the
> > > CPU supports PMD-sized pages. This API will be based on the
> > > has_transparent_hugepage() implementation but will be orthogonal to THP
> > > and therefore must work when CONFIG_TRANSPARENT_HUGEPAGE=n.
> > > 
> > > Move its definition out of the THP guard.
> > > 
> > > Signed-off-by: Luiz Capitulino <luizcap@redhat.com>
> > > ---
> > >   arch/mips/include/asm/pgtable.h | 6 +++---
> > >   arch/mips/mm/tlb-r4k.c          | 4 ----
> > >   2 files changed, 3 insertions(+), 7 deletions(-)
> > > 
> > > diff --git a/arch/mips/include/asm/pgtable.h b/arch/mips/include/asm/pgtable.h
> > > index fa7b935f947c..b038da872ec6 100644
> > > --- a/arch/mips/include/asm/pgtable.h
> > > +++ b/arch/mips/include/asm/pgtable.h
> > > @@ -615,9 +615,6 @@ unsigned long io_remap_pfn_range_pfn(unsigned long pfn, unsigned long size);
> > >   /* We don't have hardware dirty/accessed bits, generic_pmdp_establish is fine.*/
> > >   #define pmdp_establish generic_pmdp_establish
> > > -#define has_transparent_hugepage has_transparent_hugepage
> > > -extern int has_transparent_hugepage(void);
> > 
> > Assume a decstation_defconfig build. CPU_R3000 selects CPU_R3K_TLB, so the
> > Makefile builds tlb-r3k.o but not tlb-r4k.o IIUC ...
> > 
> > The only MIPS definition is in tlb-r4k.c, so R3000 would fail to link with
> > an undefined reference ... no?
> 
> Yes, you're right. I can reproduce this. Would the solution below be
> acceptable?
> 
> diff --git a/arch/mips/include/asm/pgtable.h b/arch/mips/include/asm/pgtable.h
> index fa7b935f947c..b038da872ec6 100644
> --- a/arch/mips/include/asm/pgtable.h
> +++ b/arch/mips/include/asm/pgtable.h
> @@ -615,9 +615,6 @@ unsigned long io_remap_pfn_range_pfn(unsigned long pfn, unsigned long size);
>  /* We don't have hardware dirty/accessed bits, generic_pmdp_establish is fine.*/
>  #define pmdp_establish generic_pmdp_establish
> -#define has_transparent_hugepage has_transparent_hugepage
> -extern int has_transparent_hugepage(void);
> -
>  static inline int pmd_trans_huge(pmd_t pmd)
>  {
>  	return !!(pmd_val(pmd) & _PAGE_HUGE);
> @@ -743,6 +740,9 @@ static inline pmd_t pmdp_huge_get_and_clear(struct mm_struct *mm,
>  #endif /* CONFIG_TRANSPARENT_HUGEPAGE */
> +#define has_transparent_hugepage has_transparent_hugepage
> +extern int has_transparent_hugepage(void);
> +
>  #ifdef _PAGE_HUGE
>  #define pmd_leaf(pmd)	((pmd_val(pmd) & _PAGE_HUGE) != 0)
>  #define pud_leaf(pud)	((pud_val(pud) & _PAGE_HUGE) != 0)
> diff --git a/arch/mips/mm/pgtable.c b/arch/mips/mm/pgtable.c
> index 10835414819f..3a5b411493d9 100644
> --- a/arch/mips/mm/pgtable.c
> +++ b/arch/mips/mm/pgtable.c
> @@ -23,3 +23,30 @@ pgd_t *pgd_alloc(struct mm_struct *mm)
>  	return ret;
>  }
>  EXPORT_SYMBOL_GPL(pgd_alloc);
> +
> +#if defined(CONFIG_CPU_R4K_CACHE_TLB) || \
> +    defined(CONFIG_CPU_SB1) || \
> +    defined(CONFIG_CPU_CAVIUM_OCTEON)

I guess using CONFIG_CPU_SUPPORTS_HUGEPAGES is a better approach

Thomas.

-- 
Crap can work. Given enough thrust pigs will fly, but it's not necessarily a
good idea.                                                [ RFC1925, 2.3 ]


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH v7 10/14] mips: move has_transparent_hugepage() out of THP guard
  2026-09-01 22:25       ` Thomas Bogendoerfer
@ 2026-09-02 15:12         ` Luiz Capitulino
  0 siblings, 0 replies; 19+ messages in thread
From: Luiz Capitulino @ 2026-09-02 15:12 UTC (permalink / raw)
  To: Thomas Bogendoerfer
  Cc: Lance Yang, corbet, ziy, baolin.wang, maddy, mpe, agordeev,
	gerald.schaefer, david, hca, gor, x86, tglx, mingo, bp, hughd,
	linux-kernel, dave.hansen, djbw, vishal.l.verma, dave.jiang, akpm,
	yintirui, dev.jain, usama.arif, linux-mm

On 2026-09-01 18:25, Thomas Bogendoerfer wrote:
> On Tue, Sep 01, 2026 at 03:53:18PM -0400, Luiz Capitulino wrote:
>> On 2026-09-01 07:42, Lance Yang wrote:
>>>
>>>
>>> On 2026/9/1 11:12, Luiz Capitulino wrote:
>>>> A future commit will introduce a kernel API to allow for checking if the
>>>> CPU supports PMD-sized pages. This API will be based on the
>>>> has_transparent_hugepage() implementation but will be orthogonal to THP
>>>> and therefore must work when CONFIG_TRANSPARENT_HUGEPAGE=n.
>>>>
>>>> Move its definition out of the THP guard.
>>>>
>>>> Signed-off-by: Luiz Capitulino <luizcap@redhat.com>
>>>> ---
>>>>    arch/mips/include/asm/pgtable.h | 6 +++---
>>>>    arch/mips/mm/tlb-r4k.c          | 4 ----
>>>>    2 files changed, 3 insertions(+), 7 deletions(-)
>>>>
>>>> diff --git a/arch/mips/include/asm/pgtable.h b/arch/mips/include/asm/pgtable.h
>>>> index fa7b935f947c..b038da872ec6 100644
>>>> --- a/arch/mips/include/asm/pgtable.h
>>>> +++ b/arch/mips/include/asm/pgtable.h
>>>> @@ -615,9 +615,6 @@ unsigned long io_remap_pfn_range_pfn(unsigned long pfn, unsigned long size);
>>>>    /* We don't have hardware dirty/accessed bits, generic_pmdp_establish is fine.*/
>>>>    #define pmdp_establish generic_pmdp_establish
>>>> -#define has_transparent_hugepage has_transparent_hugepage
>>>> -extern int has_transparent_hugepage(void);
>>>
>>> Assume a decstation_defconfig build. CPU_R3000 selects CPU_R3K_TLB, so the
>>> Makefile builds tlb-r3k.o but not tlb-r4k.o IIUC ...
>>>
>>> The only MIPS definition is in tlb-r4k.c, so R3000 would fail to link with
>>> an undefined reference ... no?
>>
>> Yes, you're right. I can reproduce this. Would the solution below be
>> acceptable?
>>
>> diff --git a/arch/mips/include/asm/pgtable.h b/arch/mips/include/asm/pgtable.h
>> index fa7b935f947c..b038da872ec6 100644
>> --- a/arch/mips/include/asm/pgtable.h
>> +++ b/arch/mips/include/asm/pgtable.h
>> @@ -615,9 +615,6 @@ unsigned long io_remap_pfn_range_pfn(unsigned long pfn, unsigned long size);
>>   /* We don't have hardware dirty/accessed bits, generic_pmdp_establish is fine.*/
>>   #define pmdp_establish generic_pmdp_establish
>> -#define has_transparent_hugepage has_transparent_hugepage
>> -extern int has_transparent_hugepage(void);
>> -
>>   static inline int pmd_trans_huge(pmd_t pmd)
>>   {
>>   	return !!(pmd_val(pmd) & _PAGE_HUGE);
>> @@ -743,6 +740,9 @@ static inline pmd_t pmdp_huge_get_and_clear(struct mm_struct *mm,
>>   #endif /* CONFIG_TRANSPARENT_HUGEPAGE */
>> +#define has_transparent_hugepage has_transparent_hugepage
>> +extern int has_transparent_hugepage(void);
>> +
>>   #ifdef _PAGE_HUGE
>>   #define pmd_leaf(pmd)	((pmd_val(pmd) & _PAGE_HUGE) != 0)
>>   #define pud_leaf(pud)	((pud_val(pud) & _PAGE_HUGE) != 0)
>> diff --git a/arch/mips/mm/pgtable.c b/arch/mips/mm/pgtable.c
>> index 10835414819f..3a5b411493d9 100644
>> --- a/arch/mips/mm/pgtable.c
>> +++ b/arch/mips/mm/pgtable.c
>> @@ -23,3 +23,30 @@ pgd_t *pgd_alloc(struct mm_struct *mm)
>>   	return ret;
>>   }
>>   EXPORT_SYMBOL_GPL(pgd_alloc);
>> +
>> +#if defined(CONFIG_CPU_R4K_CACHE_TLB) || \
>> +    defined(CONFIG_CPU_SB1) || \
>> +    defined(CONFIG_CPU_CAVIUM_OCTEON)
> 
> I guess using CONFIG_CPU_SUPPORTS_HUGEPAGES is a better approach

Makes sense. Updated patch below.

Subject: [PATCH 10/14] mips: move has_transparent_hugepage() out of THP guard

A future commit will introduce a kernel API to allow for checking if the
CPU supports PMD-sized pages. This API will be based on the
has_transparent_hugepage() implementation but will be orthogonal to THP
and therefore must work when CONFIG_TRANSPARENT_HUGEPAGE=n.

This commit moves has_transparent_hugepage() definition to
arch/mips/mm/pgtable.c under CONFIG_CPU_SUPPORTS_HUGEPAGES guard in
order to ensure that it's only used in CPUs that support the register
operations performed.

Signed-off-by: Luiz Capitulino <luizcap@redhat.com>
---
  arch/mips/include/asm/pgtable.h |  6 +++---
  arch/mips/mm/pgtable.c          | 25 +++++++++++++++++++++++++
  arch/mips/mm/tlb-r4k.c          | 22 ----------------------
  3 files changed, 28 insertions(+), 25 deletions(-)

diff --git a/arch/mips/include/asm/pgtable.h b/arch/mips/include/asm/pgtable.h
index fa7b935f947c..b038da872ec6 100644
--- a/arch/mips/include/asm/pgtable.h
+++ b/arch/mips/include/asm/pgtable.h
@@ -615,9 +615,6 @@ unsigned long io_remap_pfn_range_pfn(unsigned long pfn, unsigned long size);
  /* We don't have hardware dirty/accessed bits, generic_pmdp_establish is fine.*/
  #define pmdp_establish generic_pmdp_establish
  
-#define has_transparent_hugepage has_transparent_hugepage
-extern int has_transparent_hugepage(void);
-
  static inline int pmd_trans_huge(pmd_t pmd)
  {
  	return !!(pmd_val(pmd) & _PAGE_HUGE);
@@ -743,6 +740,9 @@ static inline pmd_t pmdp_huge_get_and_clear(struct mm_struct *mm,
  
  #endif /* CONFIG_TRANSPARENT_HUGEPAGE */
  
+#define has_transparent_hugepage has_transparent_hugepage
+extern int has_transparent_hugepage(void);
+
  #ifdef _PAGE_HUGE
  #define pmd_leaf(pmd)	((pmd_val(pmd) & _PAGE_HUGE) != 0)
  #define pud_leaf(pud)	((pud_val(pud) & _PAGE_HUGE) != 0)
diff --git a/arch/mips/mm/pgtable.c b/arch/mips/mm/pgtable.c
index 10835414819f..4515fa42f0b3 100644
--- a/arch/mips/mm/pgtable.c
+++ b/arch/mips/mm/pgtable.c
@@ -23,3 +23,28 @@ pgd_t *pgd_alloc(struct mm_struct *mm)
  	return ret;
  }
  EXPORT_SYMBOL_GPL(pgd_alloc);
+
+#ifdef CONFIG_CPU_SUPPORTS_HUGEPAGES
+int has_transparent_hugepage(void)
+{
+	static unsigned int mask = -1;
+
+	if (mask == -1) {	/* first call comes during __init */
+		unsigned long flags;
+
+		local_irq_save(flags);
+		write_c0_pagemask(PM_HUGE_MASK);
+		back_to_back_c0_hazard();
+		mask = read_c0_pagemask();
+		write_c0_pagemask(PM_DEFAULT_MASK);
+		local_irq_restore(flags);
+	}
+	return mask == PM_HUGE_MASK;
+}
+#else
+int has_transparent_hugepage(void)
+{
+	return 0;
+}
+#endif
+EXPORT_SYMBOL(has_transparent_hugepage);
diff --git a/arch/mips/mm/tlb-r4k.c b/arch/mips/mm/tlb-r4k.c
index 24fe85fa169d..625f1c0dd71e 100644
--- a/arch/mips/mm/tlb-r4k.c
+++ b/arch/mips/mm/tlb-r4k.c
@@ -432,28 +432,6 @@ void add_wired_entry(unsigned long entrylo0, unsigned long entrylo1,
  #endif
  }
  
-#ifdef CONFIG_TRANSPARENT_HUGEPAGE
-
-int has_transparent_hugepage(void)
-{
-	static unsigned int mask = -1;
-
-	if (mask == -1) {	/* first call comes during __init */
-		unsigned long flags;
-
-		local_irq_save(flags);
-		write_c0_pagemask(PM_HUGE_MASK);
-		back_to_back_c0_hazard();
-		mask = read_c0_pagemask();
-		write_c0_pagemask(PM_DEFAULT_MASK);
-		local_irq_restore(flags);
-	}
-	return mask == PM_HUGE_MASK;
-}
-EXPORT_SYMBOL(has_transparent_hugepage);
-
-#endif /* CONFIG_TRANSPARENT_HUGEPAGE  */
-
  /*
   * Used for loading TLB entries before trap_init() has started, when we
   * don't actually want to add a wired entry which remains throughout the
-- 
2.55.0



^ permalink raw reply related	[flat|nested] 19+ messages in thread

end of thread, other threads:[~2026-09-02 15:13 UTC | newest]

Thread overview: 19+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-01  3:12 [PATCH v7 00/14] mm: thp: always enable mTHP support Luiz Capitulino
2026-09-01  3:12 ` [PATCH v7 01/14] docs: tmpfs: remove implementation detail reference Luiz Capitulino
2026-09-01  3:12 ` [PATCH v7 02/14] mm: shmem: shmem_getattr(): set blksize to highest supported THP order Luiz Capitulino
2026-09-01  3:12 ` [PATCH v7 03/14] mm: introduce pgtable_has_pmd_leaves() Luiz Capitulino
2026-09-01  3:12 ` [PATCH v7 04/14] drivers: dax: use pgtable_has_pmd_leaves() Luiz Capitulino
2026-09-01  3:12 ` [PATCH v7 05/14] drivers: nvdimm: " Luiz Capitulino
2026-09-01  3:12 ` [PATCH v7 06/14] mm: debug_vm_pgtable: " Luiz Capitulino
2026-09-01  3:12 ` [PATCH v7 07/14] mm: shmem: allow THP support determination at folio allocation time Luiz Capitulino
2026-09-01  3:12 ` [PATCH v7 08/14] s390: move has_transparent_hugepage() out of THP guard Luiz Capitulino
2026-09-01  3:12 ` [PATCH v7 09/14] powerpc: " Luiz Capitulino
2026-09-01  3:12 ` [PATCH v7 10/14] mips: " Luiz Capitulino
2026-09-01 11:42   ` Lance Yang
2026-09-01 19:53     ` Luiz Capitulino
2026-09-01 22:25       ` Thomas Bogendoerfer
2026-09-02 15:12         ` Luiz Capitulino
2026-09-01  3:12 ` [PATCH v7 11/14] x86: " Luiz Capitulino
2026-09-01  3:12 ` [PATCH v7 12/14] treewide: introduce arch_has_pmd_leaves() Luiz Capitulino
2026-09-01  3:12 ` [PATCH v7 13/14] mm: replace thp_disabled_by_hw() with pgtable_has_pmd_leaves() Luiz Capitulino
2026-09-01  3:12 ` [PATCH v7 14/14] mm: thp: always enable mTHP support Luiz Capitulino

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox