[PATCH v2 10/12] selftests/mm: mremap_test: replace validation threshold with sampled checks

From: Sarthak Sharma

Date: Tue Oct 06 2026 - 05:32:00 EST


mremap_test validates only the first 4MB of large mappings by
default. Now since the command line option has been removed,
this threshold is fixed and covers only the beginning of
each mapping.

Remove validation threshold and fully validate mappings that
fit within the 40MB random pattern buffer. For larger mappings,
initialize and validate 10 pages each at the start, middle
and end. This increases coverage without significantly
increasing the test's RSS.

Suggested-by: David Hildenbrand (Arm) <david@xxxxxxxxxx>
Signed-off-by: Sarthak Sharma <sarthak.sharma@xxxxxxx>
---
tools/testing/selftests/mm/mremap_test.c | 85 +++++++++++++-----------
1 file changed, 48 insertions(+), 37 deletions(-)

diff --git a/tools/testing/selftests/mm/mremap_test.c b/tools/testing/selftests/mm/mremap_test.c
index 403c5495e160..955727607d4f 100644
--- a/tools/testing/selftests/mm/mremap_test.c
+++ b/tools/testing/selftests/mm/mremap_test.c
@@ -22,13 +22,7 @@
#define EXPECT_FAILURE 1
#define NON_OVERLAPPING 0
#define OVERLAPPING 1
-#define VALIDATION_DEFAULT_THRESHOLD 4 /* 4MB */
-#define VALIDATION_NO_THRESHOLD 0 /* Verify the entire region */

-#ifndef MIN
-#define MIN(X, Y) ((X) < (Y) ? (X) : (Y))
-#define MAX(X, Y) ((X) > (Y) ? (X) : (Y))
-#endif
#define SIZE_MB(m) ((size_t)m * (1024 * 1024))
#define SIZE_KB(k) ((size_t)k * 1024)

@@ -928,19 +922,49 @@ static void mremap_move_multi_invalid_vmas(FILE *maps_fp, unsigned long page_siz
}
#endif /* __NR_userfaultfd */

-static int remap_region(struct config c, unsigned int threshold_mb,
- char *rand_addr)
+static void populate_test_data(char *addr, size_t size, char *pattern_addr,
+ size_t pattern_size, size_t page_size)
+{
+ size_t mid, end;
+ size_t len = 10 * page_size;
+
+ if (size <= pattern_size) {
+ memcpy(addr, pattern_addr, size);
+ return;
+ }
+
+ end = size - len;
+ mid = end / 2;
+
+ memcpy(addr, pattern_addr, len);
+ memcpy(addr + mid, pattern_addr + len, len);
+ memcpy(addr + end, pattern_addr + 2 * len, len);
+}
+
+static bool validate_test_data(char *addr, size_t size, char *pattern_addr,
+ size_t pattern_size, size_t page_size)
+{
+ size_t mid, end;
+ size_t len = 10 * page_size;
+
+ if (size <= pattern_size)
+ return !memcmp(addr, pattern_addr, size);
+
+ end = size - len;
+ mid = end / 2;
+
+ return !memcmp(addr, pattern_addr, len) &&
+ !memcmp(addr + mid, pattern_addr + len, len) &&
+ !memcmp(addr + end, pattern_addr + 2 * len, len);
+}
+
+static int remap_region(struct config c, char *rand_addr, size_t rand_size,
+ size_t page_size)
{
void *addr, *tmp_addr, *src_addr, *dest_addr, *dest_preamble_addr = NULL;
long long align_mask, offset;
- unsigned long long threshold;
int ret = 0;

- if (threshold_mb == VALIDATION_NO_THRESHOLD)
- threshold = c.region_size;
- else
- threshold = MIN(threshold_mb * _1MB, c.region_size);
-
src_addr = get_source_mapping(c);
if (!src_addr) {
ret = -1;
@@ -948,7 +972,7 @@ static int remap_region(struct config c, unsigned int threshold_mb,
}

/* Set byte pattern for source block. */
- memcpy(src_addr, rand_addr, threshold);
+ populate_test_data(src_addr, c.region_size, rand_addr, rand_size, page_size);

/* Mask to zero out lower bits of address for alignment */
align_mask = ~(c.dest_alignment - 1);
@@ -1002,7 +1026,8 @@ static int remap_region(struct config c, unsigned int threshold_mb,
}

/* Verify byte pattern after remapping */
- if (memcmp(dest_addr, rand_addr, threshold)) {
+ if (!validate_test_data(dest_addr, c.region_size, rand_addr,
+ rand_size, page_size)) {
ksft_print_msg("Data after remap doesn't match\n");
ret = -1;
goto clean_up_dest;
@@ -1100,10 +1125,11 @@ static void mremap_move_1mb_from_start(unsigned int pattern_seed,
}

static void run_mremap_test_case(struct test test_case,
- unsigned int threshold_mb,
- char *rand_addr)
+ char *rand_addr,
+ size_t rand_size,
+ size_t page_size)
{
- int ret = remap_region(test_case.config, threshold_mb, rand_addr);
+ int ret = remap_region(test_case.config, rand_addr, rand_size, page_size);

if (ret < 0) {
if (test_case.expect_failure)
@@ -1124,12 +1150,6 @@ static void run_mremap_test_case(struct test test_case,
int main(void)
{
unsigned int i;
- unsigned int threshold_mb = VALIDATION_DEFAULT_THRESHOLD;
-
- /* hard-coded test configs */
- size_t max_test_variable_region_size = _2GB;
- size_t max_test_constant_region_size = _2MB;
- size_t dest_preamble_size = 10 * _4MB;

unsigned int pattern_seed;
char *rand_addr;
@@ -1148,21 +1168,12 @@ int main(void)
pattern_seed = (unsigned int) time(&t);

ksft_print_msg("Test configs:\n");
- ksft_print_msg("threshold_mb=%u\n", threshold_mb);
ksft_print_msg("pattern_seed=%u\n", pattern_seed);

/*
- * set preallocated random array according to test configs; see the
- * functions for the logic of setting the size
+ * The 40MB destination preamble determines the random buffer size
*/
- if (!threshold_mb)
- rand_size = MAX(max_test_variable_region_size,
- max_test_constant_region_size);
- else
- rand_size = MAX(MIN(threshold_mb * _1MB,
- max_test_variable_region_size),
- max_test_constant_region_size);
- rand_size = MAX(dest_preamble_size, rand_size);
+ rand_size = 10 * _4MB;

rand_addr = (char *)mmap(NULL, rand_size, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
@@ -1229,7 +1240,7 @@ int main(void)
ksft_set_plan(ARRAY_SIZE(test_cases) + num_expand_tests + num_misc_tests);

for (i = 0; i < ARRAY_SIZE(test_cases); i++)
- run_mremap_test_case(test_cases[i], threshold_mb, rand_addr);
+ run_mremap_test_case(test_cases[i], rand_addr, rand_size, page_size);

maps_fp = fopen("/proc/self/maps", "r");

--
2.53.0