[PATCH 11/16] selftests/mm: race-harness variant for permissive hole occupancy

Kiryl Shutsemau <[email protected]>
Newsgroups gmane.linux.kernel,gmane.linux.kernel.mm
Message-ID <[email protected]>
From: "Kiryl Shutsemau (Meta)" <[email protected]>

The race harness runs with max_ptes_none=0: strict occupancy keeps
selection honest under racing MADV_DONTNEED and avoids doomed PMD-sized
allocations on 512M-PMD configs. That regime never exercises collapse of
partially populated windows -- every candidate it emits is fully occupied.

Collapsing a window that contains holes is a different path: the hole is
not copied from anywhere, it is zero-filled into the new folio, and the
slot has to be re-checked under the page table lock at install time
because a racing fault may have filled it in the meantime. None of that is
reached at max_ptes_none=0.

Add -z, which selects the other supported end of the occupancy scale
(HPAGE_PMD_NR - 1, scaled per order): selection then emits hole-heavy
windows and those paths take the brunt of the racing faults and zaps.

Also drop the stale claim that max_ptes_none sits "mid-range" from the
header comment; the harness has always pinned it to an end of the scale.

Assisted-by: Claude-Code:claude-opus-5
Signed-off-by: Kiryl Shutsemau (Meta) <[email protected]>
---
 tools/testing/selftests/mm/khugepaged_race.c | 33 ++++++++++++++------
 tools/testing/selftests/mm/run_vmtests.sh    |  2 ++
 2 files changed, 25 insertions(+), 10 deletions(-)

diff --git a/tools/testing/selftests/mm/khugepaged_race.c b/tools/testing/selftests/mm/khugepaged_race.c
index b586a114e4cd..2e36e242caa7 100644
--- a/tools/testing/selftests/mm/khugepaged_race.c
+++ b/tools/testing/selftests/mm/khugepaged_race.c
@@ -15,8 +15,12 @@
  *   madvise	MADV_COLLAPSE in a loop — the legacy-PMD regression
  *		axis.
  *
- * All anon THP orders are enabled (inherit) and max_ptes_none is set
- * mid-range, so the MADV_DONTNEED holes steer selection across orders.
+ * All anon THP orders are enabled (inherit). max_ptes_none is 0 by
+ * default — racing MADV_DONTNEED then steers selection across orders —
+ * or the permissive limit with -z, which floods the batch engine with
+ * hole and zeropage slots so the population paths (park-time zeropage
+ * clear, zero-filled copy, install-time pte_none() verify and abort)
+ * race the faulters directly.
  *
  * Correctness signals: every racing page must read as its pattern or
  * zero (MADV_DONTNEED), never anything else — checked continuously by
@@ -196,7 +200,8 @@ static unsigned long now_ms(void)
 static void usage(void)
 {
 	fprintf(stderr,
-		"Usage: khugepaged_race [-d seconds] [-m stepped|free|madvise] [-a areas]\n"
+		"Usage: khugepaged_race [-d seconds] [-m stepped|free|madvise] [-z] [-a areas]\n"
+		"\t-z: permissive max_ptes_none (hole-heavy windows)\n"
 		"\t-a: number of shared PMD-sized playground areas (default 3)\n");
 	exit(1);
 }
@@ -219,11 +224,12 @@ int main(int argc, char **argv)
 	int duration_s = 10;
 	unsigned long thread_mask = ~0UL;
 	int nr_areas_arg = 0;
+	bool permissive_none = false;
 	unsigned long i;
 	int steps = 0;
 	int opt;
 
-	while ((opt = getopt(argc, argv, "a:d:m:t:h")) != -1) {
+	while ((opt = getopt(argc, argv, "a:d:m:t:zh")) != -1) {
 		switch (opt) {
 		case 'a':
 			nr_areas_arg = atoi(optarg);
@@ -238,6 +244,9 @@ int main(int argc, char **argv)
 			/* debug: bitmask of racing threads to start */
 			thread_mask = strtoul(optarg, NULL, 0);
 			break;
+		case 'z':
+			permissive_none = true;
+			break;
 		default:
 			usage();
 		}
@@ -274,13 +283,17 @@ int main(int argc, char **argv)
 		strcmp(mode, "free") ? 1000 : 0;
 	settings.khugepaged.alloc_sleep_millisecs = 10;
 	/*
-	 * Strict occupancy: mTHP collapse only supports 0 or
-	 * HPAGE_PMD_NR - 1 and coerces anything else to 0 anyway, and 0
-	 * also keeps khugepaged from burning the whole step in doomed
-	 * PMD-sized allocations on 512M-PMD configs: under racing
-	 * MADV_DONTNEED a fully populated PMD area is rare.
+	 * mTHP collapse only supports the two ends of the occupancy
+	 * scale: 0 or HPAGE_PMD_NR - 1 (anything else coerces to 0).
+	 * Strict is the default — it also keeps khugepaged from burning
+	 * the whole step in doomed PMD-sized allocations on 512M-PMD
+	 * configs, where a fully populated area is rare under racing
+	 * MADV_DONTNEED. -z selects the permissive end: selection then
+	 * emits hole-heavy windows and the engine's population paths
+	 * take the brunt of the racing faults and zaps.
 	 */
-	settings.khugepaged.max_ptes_none = 0;
+	settings.khugepaged.max_ptes_none = permissive_none ?
+		(hpage_pmd_size / page_size) - 1 : 0;
 	settings.khugepaged.pages_to_scan =
 		nr_areas * (hpage_pmd_size / page_size) * 8;
 	for (i = 0; i < NR_ORDERS; i++) {
diff --git a/tools/testing/selftests/mm/run_vmtests.sh b/tools/testing/selftests/mm/run_vmtests.sh
index f61ec76d8e00..83a04b1e2520 100755
--- a/tools/testing/selftests/mm/run_vmtests.sh
+++ b/tools/testing/selftests/mm/run_vmtests.sh
@@ -413,6 +413,8 @@ CATEGORY="thp" run_test ./khugepaged_race -d 5 -m free
 
 CATEGORY="thp" run_test ./khugepaged_race -d 5 -m madvise
 
+CATEGORY="thp" run_test ./khugepaged_race -d 5 -m stepped -z
+
 CATEGORY="thp" run_test ./khugepaged
 
 CATEGORY="thp" run_test ./khugepaged -s 2
-- 
2.54.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.