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

collapse_order_mixed_sources faults its region as order-2 folios and
collapses them to the -o target, covering collapse of sources that are
already large folios of an order below the target. But it only ever tests
one source order, and order 2 sits below the contpte threshold on both
arm64 page-size configs -- so a source-side contpte unfold is never
exercised deterministically by this suite.

Let -s name the source order when combined with -o (it was rejected
before): the mixed-source case then faults at order @anon_order instead of
the fixed order 2, keeping order 2 as the default when -s is absent. -s
stays constrained to a supported mTHP order strictly below the target; the
other order-parameterized cases keep their order-0 sources (the source
order is enabled locally, not globally), so -s under -o is a knob on the
mixed-source case alone.

This makes e.g. -s 5 -o 7 on arm64/64K collapse contpte-mapped sources
into a larger mTHP, covering the source-unfold path directly.

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

diff --git a/tools/testing/selftests/mm/khugepaged.c 
b/tools/testing/selftests/mm/khugepaged.c
index b074b005b62f..21a8fb24dc43 100644
--- a/tools/testing/selftests/mm/khugepaged.c
+++ b/tools/testing/selftests/mm/khugepaged.c
@@ -1363,28 +1363,32 @@ static void collapse_order_mixed_sources(struct 
collapse_context *c,
                                         struct mem_ops *ops)
 {
        struct thp_settings settings = *thp_current_settings();
+       int source_order = anon_order ? anon_order : MIN_MTHP_ORDER;
        void *p;
 
-       if (anon_target_order <= MIN_MTHP_ORDER) {
+       /* Sources must be a supported mTHP order strictly below the target. */
+       if (source_order >= anon_target_order ||
+           !(thp_supported_orders() & (1UL << source_order))) {
                ksft_test_result_skip("%s: no source order below target\n",
                                      __func__);
                return;
        }
 
-       /* Fault the whole region as order-MIN_MTHP_ORDER folios. */
-       settings.hugepages[MIN_MTHP_ORDER].enabled = THP_ALWAYS;
+       /* Fault the whole region as order-@source_order folios. */
+       settings.hugepages[source_order].enabled = THP_ALWAYS;
        thp_push_settings(&settings);
        p = ops->setup_area(1);
        ops->fault(p, 0, hpage_pmd_size);
        thp_pop_settings();
 
-       if (!is_range_backed_by_folio_orders(p, hpage_pmd_size, MIN_MTHP_ORDER,
+       if (!is_range_backed_by_folio_orders(p, hpage_pmd_size, source_order,
                                             pagemap_fd, kpageflags_fd))
                ksft_exit_fail_msg("Region not backed by order-%d folios after 
fault\n",
-                                  MIN_MTHP_ORDER);
+                                  source_order);
 
        madvise(p, hpage_pmd_size, MADV_HUGEPAGE);
-       ksft_print_msg("Collapse region backed by smaller large folios...");
+       ksft_print_msg("Collapse region backed by order-%d sources...",
+                      source_order);
        if (!khugepaged_wait_full_pass())
                fail("Timeout");
        else if (range_collapsed(p, hpage_pmd_size))
@@ -1414,7 +1418,9 @@ static void usage(void)
        fprintf(stderr, "\t\t    Defaults to 0. Use this size for anon or shmem 
allocations.\n");
        fprintf(stderr, "\t\t-o: collapse target order for khugepaged:anon.\n");
        fprintf(stderr, "\t\t    Runs the order-parameterized collapse cases 
instead\n");
-       fprintf(stderr, "\t\t    of the PMD cases. Cannot be combined with 
-s.\n");
+       fprintf(stderr, "\t\t    of the PMD cases.\n");
+       fprintf(stderr, "\t\t    With -s, -s names the mTHP source order for 
the\n");
+       fprintf(stderr, "\t\t    mixed-source case (source order below the 
target).\n");
        exit(1);
 }
 
@@ -1438,7 +1444,15 @@ static void parse_test_type(int argc, char **argv)
                }
        }
 
-       if (anon_target_order && anon_order)
+       /*
+        * -s and -o compose: -s then names the mTHP source order for the
+        * mixed-source case, which needs a source strictly below the
+        * target (and at or above the smallest mTHP order). Alone, -s is
+        * the source order for the default PMD suite; alone, -o is the
+        * collapse target for the order-parameterized suite.
+        */
+       if (anon_target_order && anon_order &&
+           (anon_order < MIN_MTHP_ORDER || anon_order >= anon_target_order))
                usage();
 
        argv += optind;
@@ -1573,9 +1587,17 @@ int main(int argc, char **argv)
        default_settings.khugepaged.max_ptes_shared = hpage_pmd_nr / 2;
        default_settings.khugepaged.pages_to_scan = hpage_pmd_nr * 8;
        default_settings.hugepages[hpage_pmd_order].enabled = THP_INHERIT;
-       default_settings.hugepages[anon_order].enabled = THP_ALWAYS;
        default_settings.shmem_hugepages[hpage_pmd_order].enabled = 
SHMEM_INHERIT;
-       default_settings.shmem_hugepages[anon_order].enabled = SHMEM_ALWAYS;
+       /*
+        * Under -o the order-parameterized cases want order-0 sources by
+        * default; the mixed-source case enables its own (possibly -s
+        * selected) source order locally. Enabling it globally here would
+        * make every case fault that order.
+        */
+       if (!anon_target_order) {
+               default_settings.hugepages[anon_order].enabled = THP_ALWAYS;
+               default_settings.shmem_hugepages[anon_order].enabled = 
SHMEM_ALWAYS;
+       }
 
        if (anon_target_order) {
                /*
-- 
2.54.0


Reply via email to