From: "Kiryl Shutsemau (Meta)" <[email protected]>

The page cache caps folio order at MAX_PAGECACHE_ORDER, which sits below
the PMD order where a PMD is 512M -- arm64 with 64K base pages.  A
PMD-sized page cache folio is then impossible, so MADV_COLLAPSE answers
-EINVAL and khugepaged passes over the range.  The shmem cases ask for one
anyway, so four of them fail and the run bails out in the middle.

The cap is one global, so it rules out every file mapping, not just shmem:
shmem_huge_global_enabled() drops the PMD order from what it allows, and
file_thp_enabled() refuses a regular file whose mapping cannot hold a PMD
folio.  Skip both mem types when the PMD order has no per-order
shmem_enabled control, which is the readable form of the cap: that control
is created for the orders in THP_ORDERS_ALL_FILE_DEFAULT.  A run left with
nothing to collapse into skips outright.

Anonymous collapse is unaffected: its orders are not capped this way.

Assisted-by: Claude-Code:claude-opus-5
Tested-by: Muhammad Usama Anjum <[email protected]>
Signed-off-by: Kiryl Shutsemau (Meta) <[email protected]>
---
 tools/testing/selftests/mm/khugepaged.c | 31 +++++++++++++++++++++++++
 1 file changed, 31 insertions(+)

diff --git a/tools/testing/selftests/mm/khugepaged.c 
b/tools/testing/selftests/mm/khugepaged.c
index a5ada78d90ee..c049ac997def 100644
--- a/tools/testing/selftests/mm/khugepaged.c
+++ b/tools/testing/selftests/mm/khugepaged.c
@@ -1391,6 +1391,37 @@ int main(int argc, char **argv)
 
        setbuf(stdout, NULL);
 
+       /*
+        * The page cache caps folio order at MAX_PAGECACHE_ORDER, which
+        * xas_split_alloc() puts below the PMD order on arm64 with 64K pages.
+        * A PMD-sized page cache folio is then impossible, so the kernel
+        * refuses these collapses by design and there is nothing to test.
+        *
+        * The cap is one global, so it rules out every file mapping, not just
+        * shmem: shmem_huge_global_enabled() drops the PMD order from what it
+        * allows, and file_thp_enabled() refuses a regular file whose mapping
+        * cannot hold a PMD folio.
+        *
+        * The per-order shmem_enabled control below is what makes the cap
+        * readable: it is created for the orders in 
THP_ORDERS_ALL_FILE_DEFAULT,
+        * which is the cap and nothing else, so whether the PMD order has one
+        * answers for a regular file as much as for shmem.
+        */
+       if (!(thp_shmem_supported_orders() & (1UL << hpage_pmd_order))) {
+               if (shmem_ops) {
+                       ksft_print_msg("no PMD-order page cache folio: skipping 
shmem\n");
+                       shmem_ops = NULL;
+               }
+               if (read_only_file_ops) {
+                       ksft_print_msg("no PMD-order page cache folio: skipping 
file\n");
+                       read_only_file_ops = NULL;
+                       read_write_file_read_ops = NULL;
+                       read_write_file_write_ops = NULL;
+               }
+               if (!anon_ops && !shmem_ops && !read_only_file_ops)
+                       ksft_exit_skip("Nothing left to collapse into\n");
+       }
+
        default_settings.khugepaged.max_ptes_none = hpage_pmd_nr - 1;
        default_settings.khugepaged.max_ptes_swap = hpage_pmd_nr / 8;
        default_settings.khugepaged.max_ptes_shared = hpage_pmd_nr / 2;
-- 
2.54.0


Reply via email to