[PATCH] mm/thp: support mTHP in thp_underused()

From: Ye Liu

Date: Wed Jul 15 2026 - 02:22:15 EST


From: Ye Liu <liuye@xxxxxxxxxx>

When khugepaged_max_ptes_none is configured to a non-default value,
scale it for non-PMD-mappable folios to match the logic in
collapse_max_ptes_none(), so mTHP can be classified as underused
instead of being silently skipped due to unscaled PMD-sized thresholds.

Signed-off-by: Ye Liu <liuye@xxxxxxxxxx>
---
mm/huge_memory.c | 21 +++++++++++++--------
1 file changed, 13 insertions(+), 8 deletions(-)

diff --git a/mm/huge_memory.c b/mm/huge_memory.c
index 25612af72dca..c642bec967fa 100644
--- a/mm/huge_memory.c
+++ b/mm/huge_memory.c
@@ -4489,24 +4489,29 @@ static unsigned long deferred_split_count(struct shrinker *shrink,
static bool thp_underused(struct folio *folio)
{
int num_zero_pages = 0, num_filled_pages = 0;
+ unsigned int max_ptes_none = khugepaged_max_ptes_none;
+ unsigned int folio_nr = folio_nr_pages(folio);
int i;

- if (khugepaged_max_ptes_none == HPAGE_PMD_NR - 1)
+ if (!folio_test_pmd_mappable(folio)) {
+ if (max_ptes_none == HPAGE_PMD_NR - 1)
+ max_ptes_none = folio_nr - 1;
+ else if (max_ptes_none)
+ return false;
+ }
+
+ if (max_ptes_none == folio_nr - 1)
return false;

if (folio_contain_hwpoisoned_page(folio))
return false;

- for (i = 0; i < folio_nr_pages(folio); i++) {
+ for (i = 0; i < folio_nr; i++) {
if (pages_identical(folio_page(folio, i), ZERO_PAGE(0))) {
- if (++num_zero_pages > khugepaged_max_ptes_none)
+ if (++num_zero_pages > max_ptes_none)
return true;
} else {
- /*
- * Another path for early exit once the number
- * of non-zero filled pages exceeds threshold.
- */
- if (++num_filled_pages >= HPAGE_PMD_NR - khugepaged_max_ptes_none)
+ if (++num_filled_pages >= folio_nr - max_ptes_none)
return false;
}
}
--
2.43.0