mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH v2 00/12] selftests/mm: improve mremap_test
@ 2026-10-06  9:24 Sarthak Sharma
  2026-10-06  9:25 ` [PATCH v2 01/12] selftests/mm: mremap_test: remove command line options Sarthak Sharma
                   ` (11 more replies)
  0 siblings, 12 replies; 13+ messages in thread
From: Sarthak Sharma @ 2026-10-06  9:24 UTC (permalink / raw)
  To: akpm, david
  Cc: ljs, liam, vbabka, rppt, surenb, mhocko, shuah, jhubbard,
	kaleshsingh, anshuman.khandual, linux-mm, linux-kselftest,
	linux-kernel, Sarthak Sharma

This series fixes correctness issues in mremap_test, simplifies its
test infrastructure and strengthens validation of remapped mappings.

Patches 1-3 remove unused command line handling, unnecessary cleanup
checks and redundant errno handling. Patch 4 converts the test to use
kselftest helpers and removes manual failure tracking.

Patches 5-8 fix handling of unavailable userfaultfd support, unexpected
mremap() successes, data-corruption failures and cleanup after mmap()
failures. Patch 9 removes perf tests and timing infrastructure.

Patches 10 and 11 replace threshold-based random-data validation with
sampled validation and a deterministic data pattern. Patch 12
strengthens multi VMA validation by also checking the mapping state
of holes after remapping.

Changes in v2:
- Add a first patch to remove command-line options
- Add a second patch to remove munmap() checks from cleanup paths
- Add a third patch to simplify errno handling
- Drop the "correct multiple VMA range size" patch
- Add an eighth patch to fix cleanup after target mmap() failures
- Replace fully populating and validating large mappings with
  populating and validating 10 pages each from the start, middle
  and end
- Extend multi VMA strengthening to userfaultfd multi VMA test
- Fix minor formatting issues

Previous versions:
v1: https://lore.kernel.org/all/20260924050009.19974-1-sarthak.sharma@arm.com/

---
Sarthak Sharma (12):
  selftests/mm: mremap_test: remove command line options
  selftests/mm: mremap_test: drop munmap() checks from cleanup paths
  selftests/mm: mremap_test: simplify errno handling
  selftests/mm: mremap_test: use kselftest helpers
  selftests/mm: mremap_test: skip test when userfaultfd is unavailable
  selftests/mm: mremap_test: fail unexpected mremap successes
  selftests/mm: mremap_test: fail on data corruption
  selftests/mm: mremap_test: handle cleanup after mmap failures
  selftests/mm: mremap_test: remove perf tests and timing
  selftests/mm: mremap_test: replace validation threshold with sampled
    checks
  selftests/mm: mremap_test: replace random data with deterministic
    pattern
  selftests/mm: mremap_test: strengthen multi VMA validation

 tools/testing/selftests/mm/mremap_test.c | 701 ++++++++++-------------
 1 file changed, 291 insertions(+), 410 deletions(-)

-- 
2.53.0


^ permalink raw reply	[flat|nested] 13+ messages in thread

* [PATCH v2 01/12] selftests/mm: mremap_test: remove command line options
  2026-10-06  9:24 [PATCH v2 00/12] selftests/mm: improve mremap_test Sarthak Sharma
@ 2026-10-06  9:25 ` Sarthak Sharma
  2026-10-06  9:25 ` [PATCH v2 02/12] selftests/mm: mremap_test: drop munmap() checks from cleanup paths Sarthak Sharma
                   ` (10 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: Sarthak Sharma @ 2026-10-06  9:25 UTC (permalink / raw)
  To: akpm, david
  Cc: ljs, liam, vbabka, rppt, surenb, mhocko, shuah, jhubbard,
	kaleshsingh, anshuman.khandual, linux-mm, linux-kselftest,
	linux-kernel, Sarthak Sharma

mremap_test supports command line options for changing
the validation threshold and random pattern seed.

As part of a larger series to remove validation threshold
and randomization, remove all command line options from
the test. The test is already invoked without any
arguments in run_vmtests.sh, so no runner changes are
required.

Suggested-by: David Hildenbrand (Arm) <david@kernel.org>
Signed-off-by: Sarthak Sharma <sarthak.sharma@arm.com>
---
 tools/testing/selftests/mm/mremap_test.c | 45 +-----------------------
 1 file changed, 1 insertion(+), 44 deletions(-)

diff --git a/tools/testing/selftests/mm/mremap_test.c b/tools/testing/selftests/mm/mremap_test.c
index 97abf4713cc5..41f211c39c83 100644
--- a/tools/testing/selftests/mm/mremap_test.c
+++ b/tools/testing/selftests/mm/mremap_test.c
@@ -1188,49 +1188,9 @@ static void run_mremap_test_case(struct test test_case, int *failures,
 	}
 }
 
-static void usage(const char *cmd)
-{
-	fprintf(stderr,
-		"Usage: %s [[-t <threshold_mb>] [-p <pattern_seed>]]\n"
-		"-t\t only validate threshold_mb of the remapped region\n"
-		"  \t if 0 is supplied no threshold is used; all tests\n"
-		"  \t are run and remapped regions validated fully.\n"
-		"  \t The default threshold used is 4MB.\n"
-		"-p\t provide a seed to generate the random pattern for\n"
-		"  \t validating the remapped region.\n", cmd);
-}
-
-static int parse_args(int argc, char **argv, unsigned int *threshold_mb,
-		      unsigned int *pattern_seed)
-{
-	const char *optstr = "t:p:";
-	int opt;
-
-	while ((opt = getopt(argc, argv, optstr)) != -1) {
-		switch (opt) {
-		case 't':
-			*threshold_mb = atoi(optarg);
-			break;
-		case 'p':
-			*pattern_seed = atoi(optarg);
-			break;
-		default:
-			usage(argv[0]);
-			return -1;
-		}
-	}
-
-	if (optind < argc) {
-		usage(argv[0]);
-		return -1;
-	}
-
-	return 0;
-}
-
 #define MAX_TEST 15
 #define MAX_PERF_TEST 3
-int main(int argc, char **argv)
+int main(void)
 {
 	int failures = 0;
 	unsigned int i;
@@ -1259,9 +1219,6 @@ int main(int argc, char **argv)
 
 	pattern_seed = (unsigned int) time(&t);
 
-	if (parse_args(argc, argv, &threshold_mb, &pattern_seed) < 0)
-		exit(EXIT_FAILURE);
-
 	ksft_print_msg("Test configs:\n");
 	ksft_print_msg("threshold_mb=%u\n", threshold_mb);
 	ksft_print_msg("pattern_seed=%u\n", pattern_seed);
-- 
2.53.0


^ permalink raw reply	[flat|nested] 13+ messages in thread

* [PATCH v2 02/12] selftests/mm: mremap_test: drop munmap() checks from cleanup paths
  2026-10-06  9:24 [PATCH v2 00/12] selftests/mm: improve mremap_test Sarthak Sharma
  2026-10-06  9:25 ` [PATCH v2 01/12] selftests/mm: mremap_test: remove command line options Sarthak Sharma
@ 2026-10-06  9:25 ` Sarthak Sharma
  2026-10-06  9:25 ` [PATCH v2 03/12] selftests/mm: mremap_test: simplify errno handling Sarthak Sharma
                   ` (9 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: Sarthak Sharma @ 2026-10-06  9:25 UTC (permalink / raw)
  To: akpm, david
  Cc: ljs, liam, vbabka, rppt, surenb, mhocko, shuah, jhubbard,
	kaleshsingh, anshuman.khandual, linux-mm, linux-kselftest,
	linux-kernel, Sarthak Sharma

mremap_test checks the return value of munmap() on some cleanup
paths and prints an error when it fails. These failures do not
affect the test result and there is nothing useful we can do
about them during cleanup.

Stop checking munmap() return value on cleanup paths.

Suggested-by: David Hildenbrand (Arm) <david@kernel.org>
Signed-off-by: Sarthak Sharma <sarthak.sharma@arm.com>
---
 tools/testing/selftests/mm/mremap_test.c | 35 +++++++++---------------
 1 file changed, 13 insertions(+), 22 deletions(-)

diff --git a/tools/testing/selftests/mm/mremap_test.c b/tools/testing/selftests/mm/mremap_test.c
index 41f211c39c83..95ce6563289c 100644
--- a/tools/testing/selftests/mm/mremap_test.c
+++ b/tools/testing/selftests/mm/mremap_test.c
@@ -364,8 +364,7 @@ static void mremap_move_within_range(unsigned int pattern_seed, char *rand_addr)
 	}
 
 out:
-	if (munmap(ptr, size) == -1)
-		perror("munmap");
+	munmap(ptr, size);
 
 	if (success)
 		ksft_test_result_pass("%s\n", test_name);
@@ -510,10 +509,8 @@ static void mremap_move_multiple_vmas(unsigned int pattern_seed,
 	}
 
 out_unmap:
-	if (munmap(tgt_ptr, 2 * size))
-		perror("munmap tgt");
-	if (munmap(ptr, size))
-		perror("munmap src");
+	munmap(tgt_ptr, 2 * size);
+	munmap(ptr, size);
 
 out:
 	if (success)
@@ -590,10 +587,8 @@ static void mremap_shrink_multiple_vmas(unsigned long page_size,
 	}
 
 out_unmap:
-	if (munmap(tgt_ptr, size))
-		perror("munmap tgt");
-	if (munmap(ptr, size))
-		perror("munmap src");
+	munmap(tgt_ptr, size);
+	munmap(ptr, size);
 out:
 	if (success)
 		ksft_test_result_pass("%s%s\n", test_name,
@@ -713,10 +708,8 @@ static void mremap_move_multiple_vmas_split(unsigned int pattern_seed,
 	}
 
 out_unmap:
-	if (munmap(tgt_ptr, size))
-		perror("munmap tgt");
-	if (munmap(ptr, size))
-		perror("munmap src");
+	munmap(tgt_ptr, size);
+	munmap(ptr, size);
 out:
 	if (success)
 		ksft_test_result_pass("%s%s\n", test_name,
@@ -948,10 +941,8 @@ static void mremap_move_multi_invalid_vmas(FILE *maps_fp,
 	}
 
 out_unmap:
-	if (munmap(tgt_ptr, size))
-		perror("munmap tgt");
-	if (munmap(ptr, size))
-		perror("munmap src");
+	munmap(tgt_ptr, size);
+	munmap(ptr, size);
 out_close_uffd:
 	close(uffd);
 out:
@@ -1144,11 +1135,11 @@ static void mremap_move_1mb_from_start(unsigned int pattern_seed,
 	}
 
 out:
-	if (src && munmap(src, c.region_size) == -1)
-		perror("munmap src");
+	if (src)
+		munmap(src, c.region_size);
 
-	if (dest && munmap(dest, c.region_size) == -1)
-		perror("munmap dest");
+	if (dest)
+		munmap(dest, c.region_size);
 
 	if (success)
 		ksft_test_result_pass("%s\n", test_name);
-- 
2.53.0


^ permalink raw reply	[flat|nested] 13+ messages in thread

* [PATCH v2 03/12] selftests/mm: mremap_test: simplify errno handling
  2026-10-06  9:24 [PATCH v2 00/12] selftests/mm: improve mremap_test Sarthak Sharma
  2026-10-06  9:25 ` [PATCH v2 01/12] selftests/mm: mremap_test: remove command line options Sarthak Sharma
  2026-10-06  9:25 ` [PATCH v2 02/12] selftests/mm: mremap_test: drop munmap() checks from cleanup paths Sarthak Sharma
@ 2026-10-06  9:25 ` Sarthak Sharma
  2026-10-06  9:25 ` [PATCH v2 04/12] selftests/mm: mremap_test: use kselftest helpers Sarthak Sharma
                   ` (8 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: Sarthak Sharma @ 2026-10-06  9:25 UTC (permalink / raw)
  To: akpm, david
  Cc: ljs, liam, vbabka, rppt, surenb, mhocko, shuah, jhubbard,
	kaleshsingh, anshuman.khandual, linux-mm, linux-kselftest,
	linux-kernel, Sarthak Sharma

mremap_move_multi_invalid_vmas() saves and restores
errno around several checks even when no other function
call can change it. Remove these instances and compare
errno directly.

Also move perror() after the userfaultfd skip check
to avoid printing an error when the test is skipped.

Suggested-by: David Hildenbrand (Arm) <david@kernel.org>
Signed-off-by: Sarthak Sharma <sarthak.sharma@arm.com>
---
 tools/testing/selftests/mm/mremap_test.c | 19 ++++++-------------
 1 file changed, 6 insertions(+), 13 deletions(-)

diff --git a/tools/testing/selftests/mm/mremap_test.c b/tools/testing/selftests/mm/mremap_test.c
index 95ce6563289c..7cf1d235f309 100644
--- a/tools/testing/selftests/mm/mremap_test.c
+++ b/tools/testing/selftests/mm/mremap_test.c
@@ -727,7 +727,7 @@ static void mremap_move_multi_invalid_vmas(FILE *maps_fp,
 	const size_t size = 10 * page_size;
 	bool success = true;
 	char *ptr, *tgt_ptr;
-	int uffd, err, i;
+	int uffd, i;
 	void *res;
 	struct uffdio_api api = {
 		.api = UFFD_API,
@@ -736,12 +736,11 @@ static void mremap_move_multi_invalid_vmas(FILE *maps_fp,
 
 	uffd = syscall(__NR_userfaultfd, O_NONBLOCK);
 	if (uffd == -1) {
-		err = errno;
-		perror("userfaultfd");
-		if (err == EPERM) {
+		if (errno == EPERM) {
 			ksft_test_result_skip("%s - missing uffd", test_name);
 			return;
 		}
+		perror("userfaultfd");
 		success = false;
 		goto out;
 	}
@@ -810,14 +809,12 @@ static void mremap_move_multi_invalid_vmas(FILE *maps_fp,
 	 * time.
 	 */
 	res = mremap(ptr, size, size, MREMAP_MAYMOVE | MREMAP_FIXED, tgt_ptr);
-	err = errno;
 	if (res != MAP_FAILED) {
 		fprintf(stderr, "mremap() succeeded for multi VMA uffd armed\n");
 		success = false;
 		goto out_unmap;
 	}
-	if (err != EFAULT) {
-		errno = err;
+	if (errno != EFAULT) {
 		perror("mremap() unexpected error");
 		success = false;
 		goto out_unmap;
@@ -863,14 +860,12 @@ static void mremap_move_multi_invalid_vmas(FILE *maps_fp,
 	 * first VMA, but no others, and report a failure.
 	 */
 	res = mremap(ptr, size, size, MREMAP_MAYMOVE | MREMAP_FIXED, tgt_ptr);
-	err = errno;
 	if (res != MAP_FAILED) {
 		fprintf(stderr, "mremap() succeeded for multi VMA uffd armed\n");
 		success = false;
 		goto out_unmap;
 	}
-	if (err != EFAULT) {
-		errno = err;
+	if (errno != EFAULT) {
 		perror("mremap() unexpected error");
 		success = false;
 		goto out_unmap;
@@ -912,14 +907,12 @@ static void mremap_move_multi_invalid_vmas(FILE *maps_fp,
 	 * the last VMA, and report a failure.
 	 */
 	res = mremap(ptr, size, size, MREMAP_MAYMOVE | MREMAP_FIXED, tgt_ptr);
-	err = errno;
 	if (res != MAP_FAILED) {
 		fprintf(stderr, "mremap() succeeded for multi VMA uffd armed\n");
 		success = false;
 		goto out_unmap;
 	}
-	if (err != EFAULT) {
-		errno = err;
+	if (errno != EFAULT) {
 		perror("mremap() unexpected error");
 		success = false;
 		goto out_unmap;
-- 
2.53.0


^ permalink raw reply	[flat|nested] 13+ messages in thread

* [PATCH v2 04/12] selftests/mm: mremap_test: use kselftest helpers
  2026-10-06  9:24 [PATCH v2 00/12] selftests/mm: improve mremap_test Sarthak Sharma
                   ` (2 preceding siblings ...)
  2026-10-06  9:25 ` [PATCH v2 03/12] selftests/mm: mremap_test: simplify errno handling Sarthak Sharma
@ 2026-10-06  9:25 ` Sarthak Sharma
  2026-10-06  9:25 ` [PATCH v2 05/12] selftests/mm: mremap_test: skip test when userfaultfd is unavailable Sarthak Sharma
                   ` (7 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: Sarthak Sharma @ 2026-10-06  9:25 UTC (permalink / raw)
  To: akpm, david
  Cc: ljs, liam, vbabka, rppt, surenb, mhocko, shuah, jhubbard,
	kaleshsingh, anshuman.khandual, linux-mm, linux-kselftest,
	linux-kernel, Sarthak Sharma

mremap_test currently uses a lot of fprintf() and perror()
calls. It also uses a variable "failures" to track the number
of failed table driven tests.

Use ksft_print_msg() and ksft_perror() for diagnostics.
Remove the variable "failures" and let kselftest counters
handle the final exit status. Use ksft_finished() at
the end instead of manually checking if failures > 0. Replace

if (success)
	ksft_test_result_pass(...);
else
	ksft_test_result_fail(...);

calls with ksft_test_result(success, ...);

Also correct the duplicated "mremap" in "mremap move within
range" and the spelling of "dontunmap".

Signed-off-by: Sarthak Sharma <sarthak.sharma@arm.com>
---
 tools/testing/selftests/mm/mremap_test.c | 190 +++++++++--------------
 1 file changed, 73 insertions(+), 117 deletions(-)

diff --git a/tools/testing/selftests/mm/mremap_test.c b/tools/testing/selftests/mm/mremap_test.c
index 7cf1d235f309..e17edbc23325 100644
--- a/tools/testing/selftests/mm/mremap_test.c
+++ b/tools/testing/selftests/mm/mremap_test.c
@@ -257,10 +257,7 @@ static void mremap_expand_merge(FILE *maps_fp, unsigned long page_size)
 	munmap(start, 3 * page_size);
 
 out:
-	if (success)
-		ksft_test_result_pass("%s\n", test_name);
-	else
-		ksft_test_result_fail("%s\n", test_name);
+	ksft_test_result(success, "%s\n", test_name);
 }
 
 /*
@@ -297,10 +294,7 @@ static void mremap_expand_merge_offset(FILE *maps_fp, unsigned long page_size)
 	munmap(start, 3 * page_size);
 
 out:
-	if (success)
-		ksft_test_result_pass("%s\n", test_name);
-	else
-		ksft_test_result_fail("%s\n", test_name);
+	ksft_test_result(success, "%s\n", test_name);
 }
 
 /*
@@ -319,7 +313,7 @@ static void mremap_expand_merge_offset(FILE *maps_fp, unsigned long page_size)
  */
 static void mremap_move_within_range(unsigned int pattern_seed, char *rand_addr)
 {
-	char *test_name = "mremap mremap move within range";
+	char *test_name = "mremap move within range";
 	void *src, *dest;
 	unsigned int i, success = 1;
 
@@ -327,7 +321,7 @@ static void mremap_move_within_range(unsigned int pattern_seed, char *rand_addr)
 	void *ptr = mmap(NULL, size, PROT_READ | PROT_WRITE,
 			 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
 	if (ptr == MAP_FAILED) {
-		perror("mmap");
+		ksft_perror("mmap");
 		success = 0;
 		goto out;
 	}
@@ -342,9 +336,9 @@ static void mremap_move_within_range(unsigned int pattern_seed, char *rand_addr)
 	dest = src - SIZE_MB(2);
 
 	void *new_ptr = mremap(src + SIZE_MB(1), SIZE_MB(1), SIZE_MB(1),
-						   MREMAP_MAYMOVE | MREMAP_FIXED, dest + SIZE_MB(1));
+			       MREMAP_MAYMOVE | MREMAP_FIXED, dest + SIZE_MB(1));
 	if (new_ptr == MAP_FAILED) {
-		perror("mremap");
+		ksft_perror("mremap");
 		success = 0;
 		goto out;
 	}
@@ -366,10 +360,7 @@ static void mremap_move_within_range(unsigned int pattern_seed, char *rand_addr)
 out:
 	munmap(ptr, size);
 
-	if (success)
-		ksft_test_result_pass("%s\n", test_name);
-	else
-		ksft_test_result_fail("%s\n", test_name);
+	ksft_test_result(success, "%s\n", test_name);
 }
 
 static bool is_multiple_vma_range_ok(unsigned int pattern_seed,
@@ -414,7 +405,7 @@ static void mremap_move_multiple_vmas(unsigned int pattern_seed,
 	ptr = mmap(NULL, size, PROT_READ | PROT_WRITE,
 		   MAP_PRIVATE | MAP_ANON, -1, 0);
 	if (ptr == MAP_FAILED) {
-		perror("mmap");
+		ksft_perror("mmap");
 		success = false;
 		goto out;
 	}
@@ -422,12 +413,12 @@ static void mremap_move_multiple_vmas(unsigned int pattern_seed,
 	tgt_ptr = mmap(NULL, 2 * size, PROT_READ | PROT_WRITE,
 		       MAP_PRIVATE | MAP_ANON, -1, 0);
 	if (tgt_ptr == MAP_FAILED) {
-		perror("mmap");
+		ksft_perror("mmap");
 		success = false;
 		goto out;
 	}
 	if (munmap(tgt_ptr, 2 * size)) {
-		perror("munmap");
+		ksft_perror("munmap");
 		success = false;
 		goto out_unmap;
 	}
@@ -445,7 +436,7 @@ static void mremap_move_multiple_vmas(unsigned int pattern_seed,
 			continue;
 
 		if (munmap(&ptr[i * page_size], page_size)) {
-			perror("munmap");
+			ksft_perror("munmap");
 			success = false;
 			goto out_unmap;
 		}
@@ -465,7 +456,7 @@ static void mremap_move_multiple_vmas(unsigned int pattern_seed,
 
 	/* First, just move the whole thing. */
 	if (mremap(ptr, size, size, mremap_flags, tgt_ptr) == MAP_FAILED) {
-		perror("mremap");
+		ksft_perror("mremap");
 		success = false;
 		goto out_unmap;
 	}
@@ -478,7 +469,7 @@ static void mremap_move_multiple_vmas(unsigned int pattern_seed,
 	/* Move next to itself. */
 	if (mremap(tgt_ptr, size, size, mremap_flags,
 		   &tgt_ptr[size]) == MAP_FAILED) {
-		perror("mremap");
+		ksft_perror("mremap");
 		success = false;
 		goto out_unmap;
 	}
@@ -491,14 +482,14 @@ static void mremap_move_multiple_vmas(unsigned int pattern_seed,
 	/* Map a range to overwrite. */
 	if (mmap(tgt_ptr, size, PROT_NONE,
 		 MAP_PRIVATE | MAP_ANON | MAP_FIXED, -1, 0) == MAP_FAILED) {
-		perror("mmap tgt");
+		ksft_perror("mmap tgt");
 		success = false;
 		goto out_unmap;
 	}
 	/* Move and overwrite. */
 	if (mremap(&tgt_ptr[size], size, size,
 		   mremap_flags, tgt_ptr) == MAP_FAILED) {
-		perror("mremap");
+		ksft_perror("mremap");
 		success = false;
 		goto out_unmap;
 	}
@@ -511,14 +502,8 @@ static void mremap_move_multiple_vmas(unsigned int pattern_seed,
 out_unmap:
 	munmap(tgt_ptr, 2 * size);
 	munmap(ptr, size);
-
 out:
-	if (success)
-		ksft_test_result_pass("%s%s\n", test_name,
-				      dont_unmap ? " [dontunnmap]" : "");
-	else
-		ksft_test_result_fail("%s%s\n", test_name,
-				      dont_unmap ? " [dontunnmap]" : "");
+	ksft_test_result(success, "%s%s\n", test_name, dont_unmap ? " [dontunmap]" : "");
 }
 
 static void mremap_shrink_multiple_vmas(unsigned long page_size,
@@ -534,7 +519,7 @@ static void mremap_shrink_multiple_vmas(unsigned long page_size,
 	ptr = mmap(NULL, size, PROT_READ | PROT_WRITE,
 		   MAP_PRIVATE | MAP_ANON, -1, 0);
 	if (ptr == MAP_FAILED) {
-		perror("mmap");
+		ksft_perror("mmap");
 		success = false;
 		goto out;
 	}
@@ -542,12 +527,12 @@ static void mremap_shrink_multiple_vmas(unsigned long page_size,
 	tgt_ptr = mmap(NULL, size, PROT_READ | PROT_WRITE,
 		       MAP_PRIVATE | MAP_ANON, -1, 0);
 	if (tgt_ptr == MAP_FAILED) {
-		perror("mmap");
+		ksft_perror("mmap");
 		success = false;
 		goto out;
 	}
 	if (munmap(tgt_ptr, size)) {
-		perror("munmap");
+		ksft_perror("munmap");
 		success = false;
 		goto out_unmap;
 	}
@@ -561,7 +546,7 @@ static void mremap_shrink_multiple_vmas(unsigned long page_size,
 	 */
 	for (i = 1; i < 10; i += 2) {
 		if (munmap(&ptr[i * page_size], page_size)) {
-			perror("munmap");
+			ksft_perror("munmap");
 			success = false;
 			goto out_unmap;
 		}
@@ -581,7 +566,7 @@ static void mremap_shrink_multiple_vmas(unsigned long page_size,
 			     tgt_ptr);
 
 	if (res == MAP_FAILED) {
-		perror("mremap");
+		ksft_perror("mremap");
 		success = false;
 		goto out_unmap;
 	}
@@ -590,12 +575,7 @@ static void mremap_shrink_multiple_vmas(unsigned long page_size,
 	munmap(tgt_ptr, size);
 	munmap(ptr, size);
 out:
-	if (success)
-		ksft_test_result_pass("%s%s\n", test_name,
-				      inplace ? " [inplace]" : "");
-	else
-		ksft_test_result_fail("%s%s\n", test_name,
-				      inplace ? " [inplace]" : "");
+	ksft_test_result(success, "%s%s\n", test_name, inplace ? " [inplace]" : "");
 }
 
 static void mremap_move_multiple_vmas_split(unsigned int pattern_seed,
@@ -615,7 +595,7 @@ static void mremap_move_multiple_vmas_split(unsigned int pattern_seed,
 	ptr = mmap(NULL, size, PROT_READ | PROT_WRITE,
 		   MAP_PRIVATE | MAP_ANON, -1, 0);
 	if (ptr == MAP_FAILED) {
-		perror("mmap");
+		ksft_perror("mmap");
 		success = false;
 		goto out;
 	}
@@ -623,12 +603,12 @@ static void mremap_move_multiple_vmas_split(unsigned int pattern_seed,
 	tgt_ptr = mmap(NULL, size, PROT_READ | PROT_WRITE,
 		       MAP_PRIVATE | MAP_ANON, -1, 0);
 	if (tgt_ptr == MAP_FAILED) {
-		perror("mmap");
+		ksft_perror("mmap");
 		success = false;
 		goto out;
 	}
 	if (munmap(tgt_ptr, size)) {
-		perror("munmap");
+		ksft_perror("munmap");
 		success = false;
 		goto out_unmap;
 	}
@@ -642,7 +622,7 @@ static void mremap_move_multiple_vmas_split(unsigned int pattern_seed,
 	 *  0 1 2 3 4   5 6 7 8 9  pattern offset
 	 */
 	if (munmap(&ptr[5 * page_size], page_size)) {
-		perror("munmap");
+		ksft_perror("munmap");
 		success = false;
 		goto out_unmap;
 	}
@@ -678,7 +658,7 @@ static void mremap_move_multiple_vmas_split(unsigned int pattern_seed,
 	 */
 	if (mremap(&ptr[2 * page_size], size - 3 * page_size, size - 3 * page_size,
 		   mremap_flags, tgt_ptr) == MAP_FAILED) {
-		perror("mremap");
+		ksft_perror("mremap");
 		success = false;
 		goto out_unmap;
 	}
@@ -711,12 +691,7 @@ static void mremap_move_multiple_vmas_split(unsigned int pattern_seed,
 	munmap(tgt_ptr, size);
 	munmap(ptr, size);
 out:
-	if (success)
-		ksft_test_result_pass("%s%s\n", test_name,
-				      dont_unmap ? " [dontunnmap]" : "");
-	else
-		ksft_test_result_fail("%s%s\n", test_name,
-				      dont_unmap ? " [dontunnmap]" : "");
+	ksft_test_result(success, "%s%s\n", test_name, dont_unmap ? " [dontunmap]" : "");
 }
 
 #ifdef __NR_userfaultfd
@@ -737,15 +712,15 @@ static void mremap_move_multi_invalid_vmas(FILE *maps_fp,
 	uffd = syscall(__NR_userfaultfd, O_NONBLOCK);
 	if (uffd == -1) {
 		if (errno == EPERM) {
-			ksft_test_result_skip("%s - missing uffd", test_name);
+			ksft_test_result_skip("%s - missing uffd\n", test_name);
 			return;
 		}
-		perror("userfaultfd");
+		ksft_perror("userfaultfd");
 		success = false;
 		goto out;
 	}
 	if (ioctl(uffd, UFFDIO_API, &api)) {
-		perror("ioctl UFFDIO_API");
+		ksft_perror("ioctl UFFDIO_API");
 		success = false;
 		goto out_close_uffd;
 	}
@@ -753,19 +728,19 @@ static void mremap_move_multi_invalid_vmas(FILE *maps_fp,
 	ptr = mmap(NULL, size, PROT_READ | PROT_WRITE,
 		   MAP_PRIVATE | MAP_ANON, -1, 0);
 	if (ptr == MAP_FAILED) {
-		perror("mmap");
+		ksft_perror("mmap");
 		success = false;
 		goto out_close_uffd;
 	}
 
 	tgt_ptr = mmap(NULL, size, PROT_NONE, MAP_PRIVATE | MAP_ANON, -1, 0);
 	if (tgt_ptr == MAP_FAILED) {
-		perror("mmap");
+		ksft_perror("mmap");
 		success = false;
 		goto out_close_uffd;
 	}
 	if (munmap(tgt_ptr, size)) {
-		perror("munmap");
+		ksft_perror("munmap");
 		success = false;
 		goto out_unmap;
 	}
@@ -791,12 +766,12 @@ static void mremap_move_multi_invalid_vmas(FILE *maps_fp,
 		};
 
 		if (ioctl(uffd, UFFDIO_REGISTER, &reg) == -1) {
-			perror("ioctl UFFDIO_REGISTER");
+			ksft_perror("ioctl UFFDIO_REGISTER");
 			success = false;
 			goto out_unmap;
 		}
 		if (munmap(unmap_ptr, page_size)) {
-			perror("munmap");
+			ksft_perror("munmap");
 			success = false;
 			goto out_unmap;
 		}
@@ -810,18 +785,17 @@ static void mremap_move_multi_invalid_vmas(FILE *maps_fp,
 	 */
 	res = mremap(ptr, size, size, MREMAP_MAYMOVE | MREMAP_FIXED, tgt_ptr);
 	if (res != MAP_FAILED) {
-		fprintf(stderr, "mremap() succeeded for multi VMA uffd armed\n");
+		ksft_print_msg("mremap() succeeded for multi VMA uffd armed\n");
 		success = false;
 		goto out_unmap;
 	}
 	if (errno != EFAULT) {
-		perror("mremap() unexpected error");
+		ksft_perror("mremap() unexpected error");
 		success = false;
 		goto out_unmap;
 	}
 	if (is_ptr_mapped(maps_fp, tgt_ptr, page_size)) {
-		fprintf(stderr,
-			"Invalid uffd-armed VMA at start of multi range moved\n");
+		ksft_print_msg("Invalid uffd-armed VMA at start of multi range moved\n");
 		success = false;
 		goto out_unmap;
 	}
@@ -833,7 +807,7 @@ static void mremap_move_multi_invalid_vmas(FILE *maps_fp,
 	res = mremap(ptr, page_size, page_size,
 		     MREMAP_MAYMOVE | MREMAP_FIXED, tgt_ptr);
 	if (res == MAP_FAILED) {
-		perror("mremap single invalid-multi VMA");
+		ksft_perror("mremap single invalid-multi VMA");
 		success = false;
 		goto out_unmap;
 	}
@@ -843,14 +817,14 @@ static void mremap_move_multi_invalid_vmas(FILE *maps_fp,
 	 * move valid) VMA at the start of ptr range.
 	 */
 	if (munmap(tgt_ptr, page_size)) {
-		perror("munmap");
+		ksft_perror("munmap");
 		success = false;
 		goto out_unmap;
 	}
 	res = mmap(ptr, page_size, PROT_READ | PROT_WRITE,
 		   MAP_PRIVATE | MAP_ANON | MAP_FIXED, -1, 0);
 	if (res == MAP_FAILED) {
-		perror("mmap");
+		ksft_perror("mmap");
 		success = false;
 		goto out_unmap;
 	}
@@ -861,17 +835,17 @@ static void mremap_move_multi_invalid_vmas(FILE *maps_fp,
 	 */
 	res = mremap(ptr, size, size, MREMAP_MAYMOVE | MREMAP_FIXED, tgt_ptr);
 	if (res != MAP_FAILED) {
-		fprintf(stderr, "mremap() succeeded for multi VMA uffd armed\n");
+		ksft_print_msg("mremap() succeeded for multi VMA uffd armed\n");
 		success = false;
 		goto out_unmap;
 	}
 	if (errno != EFAULT) {
-		perror("mremap() unexpected error");
+		ksft_perror("mremap() unexpected error");
 		success = false;
 		goto out_unmap;
 	}
 	if (!is_ptr_mapped(maps_fp, tgt_ptr, page_size)) {
-		fprintf(stderr, "Valid VMA not moved\n");
+		ksft_print_msg("Valid VMA not moved\n");
 		success = false;
 		goto out_unmap;
 	}
@@ -882,12 +856,12 @@ static void mremap_move_multi_invalid_vmas(FILE *maps_fp,
 	 * multi-move VMAs.
 	 */
 	if (munmap(tgt_ptr, page_size)) {
-		perror("munmap");
+		ksft_perror("munmap");
 		success = false;
 		goto out_unmap;
 	}
 	if (munmap(ptr, size - 2 * page_size)) {
-		perror("munmap");
+		ksft_perror("munmap");
 		success = false;
 		goto out_unmap;
 	}
@@ -896,7 +870,7 @@ static void mremap_move_multi_invalid_vmas(FILE *maps_fp,
 			   PROT_READ | PROT_WRITE,
 			   MAP_PRIVATE | MAP_ANON | MAP_FIXED, -1, 0);
 		if (res == MAP_FAILED) {
-			perror("mmap");
+			ksft_perror("mmap");
 			success = false;
 			goto out_unmap;
 		}
@@ -908,12 +882,12 @@ static void mremap_move_multi_invalid_vmas(FILE *maps_fp,
 	 */
 	res = mremap(ptr, size, size, MREMAP_MAYMOVE | MREMAP_FIXED, tgt_ptr);
 	if (res != MAP_FAILED) {
-		fprintf(stderr, "mremap() succeeded for multi VMA uffd armed\n");
+		ksft_print_msg("mremap() succeeded for multi VMA uffd armed\n");
 		success = false;
 		goto out_unmap;
 	}
 	if (errno != EFAULT) {
-		perror("mremap() unexpected error");
+		ksft_perror("mremap() unexpected error");
 		success = false;
 		goto out_unmap;
 	}
@@ -923,11 +897,11 @@ static void mremap_move_multi_invalid_vmas(FILE *maps_fp,
 				&tgt_ptr[i * page_size], page_size);
 
 		if (i < 8 && !is_mapped) {
-			fprintf(stderr, "Valid VMA not moved at %d\n", i);
+			ksft_print_msg("Valid VMA not moved at %d\n", i);
 			success = false;
 			goto out_unmap;
 		} else if (i == 8 && is_mapped) {
-			fprintf(stderr, "Invalid VMA moved at %d\n", i);
+			ksft_print_msg("Invalid VMA moved at %d\n", i);
 			success = false;
 			goto out_unmap;
 		}
@@ -939,17 +913,14 @@ static void mremap_move_multi_invalid_vmas(FILE *maps_fp,
 out_close_uffd:
 	close(uffd);
 out:
-	if (success)
-		ksft_test_result_pass("%s\n", test_name);
-	else
-		ksft_test_result_fail("%s\n", test_name);
+	ksft_test_result(success, "%s\n", test_name);
 }
 #else
 static void mremap_move_multi_invalid_vmas(FILE *maps_fp, unsigned long page_size)
 {
 	char *test_name = "mremap move multiple invalid vmas";
 
-	ksft_test_result_skip("%s - missing uffd", test_name);
+	ksft_test_result_skip("%s - missing uffd\n", test_name);
 }
 #endif /* __NR_userfaultfd */
 
@@ -1020,7 +991,7 @@ static long long remap_region(struct config c, unsigned int threshold_mb,
 
 	clock_gettime(CLOCK_MONOTONIC, &t_start);
 	dest_addr = mremap(src_addr, c.region_size, c.region_size,
-					  MREMAP_MAYMOVE|MREMAP_FIXED, (char *) addr);
+			   MREMAP_MAYMOVE | MREMAP_FIXED, (char *)addr);
 	clock_gettime(CLOCK_MONOTONIC, &t_end);
 
 	if (dest_addr == MAP_FAILED) {
@@ -1106,9 +1077,9 @@ static void mremap_move_1mb_from_start(unsigned int pattern_seed,
 	munmap(dest, SIZE_MB(1));
 
 	void *new_ptr = mremap(src + SIZE_MB(1), SIZE_MB(1), SIZE_MB(1),
-						   MREMAP_MAYMOVE | MREMAP_FIXED, dest + SIZE_MB(1));
+			       MREMAP_MAYMOVE | MREMAP_FIXED, dest + SIZE_MB(1));
 	if (new_ptr == MAP_FAILED) {
-		perror("mremap");
+		ksft_perror("mremap");
 		success = 0;
 		goto out;
 	}
@@ -1134,13 +1105,10 @@ static void mremap_move_1mb_from_start(unsigned int pattern_seed,
 	if (dest)
 		munmap(dest, c.region_size);
 
-	if (success)
-		ksft_test_result_pass("%s\n", test_name);
-	else
-		ksft_test_result_fail("%s\n", test_name);
+	ksft_test_result(success, "%s\n", test_name);
 }
 
-static void run_mremap_test_case(struct test test_case, int *failures,
+static void run_mremap_test_case(struct test test_case,
 				 unsigned int threshold_mb,
 				 char *rand_addr)
 {
@@ -1148,27 +1116,22 @@ static void run_mremap_test_case(struct test test_case, int *failures,
 					    rand_addr);
 
 	if (remap_time < 0) {
-		if (test_case.expect_failure) {
-			ksft_print_msg("%s: expected mremap failure\n",
-				       test_case.name);
-			ksft_test_result_xfail("%s\n", test_case.name);
-		} else {
+		if (test_case.expect_failure)
+			ksft_test_result_xfail("%s: expected mremap failure\n",
+					       test_case.name);
+		else
 			ksft_test_result_fail("%s\n", test_case.name);
-			*failures += 1;
-		}
 	} else {
 		/*
 		 * Comparing mremap time is only applicable if entire region
 		 * was faulted in.
 		 */
 		if (threshold_mb == VALIDATION_NO_THRESHOLD ||
-		    test_case.config.region_size <= threshold_mb * _1MB) {
-			ksft_print_msg("%s: mremap time: %12lldns\n",
-				       test_case.name, remap_time);
-			ksft_test_result_pass("%s\n", test_case.name);
-		} else {
+		    test_case.config.region_size <= threshold_mb * _1MB)
+			ksft_test_result_pass("%s: mremap time: %12lldns\n",
+					      test_case.name, remap_time);
+		else
 			ksft_test_result_pass("%s\n", test_case.name);
-		}
 	}
 }
 
@@ -1176,7 +1139,6 @@ static void run_mremap_test_case(struct test test_case, int *failures,
 #define MAX_PERF_TEST 3
 int main(void)
 {
-	int failures = 0;
 	unsigned int i;
 	int run_perf_tests;
 	unsigned int threshold_mb = VALIDATION_DEFAULT_THRESHOLD;
@@ -1222,10 +1184,8 @@ int main(void)
 
 	rand_addr = (char *)mmap(NULL, rand_size, PROT_READ | PROT_WRITE,
 				 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
-	if (rand_addr == MAP_FAILED) {
-		perror("mmap");
-		ksft_exit_fail_msg("cannot mmap rand_addr\n");
-	}
+	if (rand_addr == MAP_FAILED)
+		ksft_exit_fail_perror("cannot mmap rand_addr");
 
 	/* fill stream of random bytes */
 	srand(pattern_seed);
@@ -1302,8 +1262,7 @@ int main(void)
 		      ARRAY_SIZE(perf_test_cases) : 0) + num_expand_tests + num_misc_tests);
 
 	for (i = 0; i < ARRAY_SIZE(test_cases); i++)
-		run_mremap_test_case(test_cases[i], &failures, threshold_mb,
-				     rand_addr);
+		run_mremap_test_case(test_cases[i], threshold_mb, rand_addr);
 
 	maps_fp = fopen("/proc/self/maps", "r");
 
@@ -1328,18 +1287,15 @@ int main(void)
 	fclose(maps_fp);
 
 	if (run_perf_tests) {
-		ksft_print_msg("\n%s\n",
+		ksft_print_msg("%s\n",
 		 "mremap HAVE_MOVE_PMD/PUD optimization time comparison for 1GB region:");
 		for (i = 0; i < ARRAY_SIZE(perf_test_cases); i++)
-			run_mremap_test_case(perf_test_cases[i], &failures,
+			run_mremap_test_case(perf_test_cases[i],
 					     threshold_mb,
 					     rand_addr);
 	}
 
 	munmap(rand_addr, rand_size);
 
-	if (failures > 0)
-		ksft_exit_fail();
-	else
-		ksft_exit_pass();
+	ksft_finished();
 }
-- 
2.53.0


^ permalink raw reply	[flat|nested] 13+ messages in thread

* [PATCH v2 05/12] selftests/mm: mremap_test: skip test when userfaultfd is unavailable
  2026-10-06  9:24 [PATCH v2 00/12] selftests/mm: improve mremap_test Sarthak Sharma
                   ` (3 preceding siblings ...)
  2026-10-06  9:25 ` [PATCH v2 04/12] selftests/mm: mremap_test: use kselftest helpers Sarthak Sharma
@ 2026-10-06  9:25 ` Sarthak Sharma
  2026-10-06  9:25 ` [PATCH v2 06/12] selftests/mm: mremap_test: fail unexpected mremap successes Sarthak Sharma
                   ` (6 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: Sarthak Sharma @ 2026-10-06  9:25 UTC (permalink / raw)
  To: akpm, david
  Cc: ljs, liam, vbabka, rppt, surenb, mhocko, shuah, jhubbard,
	kaleshsingh, anshuman.khandual, linux-mm, linux-kselftest,
	linux-kernel, Sarthak Sharma

The userfaultfd syscall can return ENOSYS even when __NR_userfaultfd is
defined by the architecture headers, for example when the kernel is
built without CONFIG_USERFAULTFD. The test currently skips for EPERM
when the caller lacks permission to use userfaultfd but treats
ENOSYS as a failure.

Handle ENOSYS like EPERM and skip the mremap_move_multi_invalid_vmas()
test when userfaultfd syscall is not implemented.

Fixes: 742d3663a577 ("selftests/mm: add test for invalid multi VMA operations")
Acked-by: David Hildenbrand (Arm) <david@kernel.org>
Signed-off-by: Sarthak Sharma <sarthak.sharma@arm.com>
---
 tools/testing/selftests/mm/mremap_test.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/tools/testing/selftests/mm/mremap_test.c b/tools/testing/selftests/mm/mremap_test.c
index e17edbc23325..0be47348ecd0 100644
--- a/tools/testing/selftests/mm/mremap_test.c
+++ b/tools/testing/selftests/mm/mremap_test.c
@@ -711,7 +711,7 @@ static void mremap_move_multi_invalid_vmas(FILE *maps_fp,
 
 	uffd = syscall(__NR_userfaultfd, O_NONBLOCK);
 	if (uffd == -1) {
-		if (errno == EPERM) {
+		if (errno == EPERM || errno == ENOSYS) {
 			ksft_test_result_skip("%s - missing uffd\n", test_name);
 			return;
 		}
-- 
2.53.0


^ permalink raw reply	[flat|nested] 13+ messages in thread

* [PATCH v2 06/12] selftests/mm: mremap_test: fail unexpected mremap successes
  2026-10-06  9:24 [PATCH v2 00/12] selftests/mm: improve mremap_test Sarthak Sharma
                   ` (4 preceding siblings ...)
  2026-10-06  9:25 ` [PATCH v2 05/12] selftests/mm: mremap_test: skip test when userfaultfd is unavailable Sarthak Sharma
@ 2026-10-06  9:25 ` Sarthak Sharma
  2026-10-06  9:25 ` [PATCH v2 07/12] selftests/mm: mremap_test: fail on data corruption Sarthak Sharma
                   ` (5 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: Sarthak Sharma @ 2026-10-06  9:25 UTC (permalink / raw)
  To: akpm, david
  Cc: ljs, liam, vbabka, rppt, surenb, mhocko, shuah, jhubbard,
	kaleshsingh, anshuman.khandual, linux-mm, linux-kselftest,
	linux-kernel, Sarthak Sharma

run_mremap_test_case() reports a test as pass when remap_region()
succeeds. But if the test was expecting failure and remap succeeds,
it should be treated as a failure and not a success.

Check test_case.expect_failure on the successful remap path. If
it expected failure, report a failure instead of success.

Fixes: 7df666253f26 ("kselftests: vm: add mremap tests")
Acked-by: David Hildenbrand (Arm) <david@kernel.org>
Signed-off-by: Sarthak Sharma <sarthak.sharma@arm.com>
---
 tools/testing/selftests/mm/mremap_test.c | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/tools/testing/selftests/mm/mremap_test.c b/tools/testing/selftests/mm/mremap_test.c
index 0be47348ecd0..1baf6374ec67 100644
--- a/tools/testing/selftests/mm/mremap_test.c
+++ b/tools/testing/selftests/mm/mremap_test.c
@@ -1122,12 +1122,15 @@ static void run_mremap_test_case(struct test test_case,
 		else
 			ksft_test_result_fail("%s\n", test_case.name);
 	} else {
+		if (test_case.expect_failure)
+			ksft_test_result_fail("%s: unexpected mremap success\n",
+					      test_case.name);
 		/*
 		 * Comparing mremap time is only applicable if entire region
 		 * was faulted in.
 		 */
-		if (threshold_mb == VALIDATION_NO_THRESHOLD ||
-		    test_case.config.region_size <= threshold_mb * _1MB)
+		else if (threshold_mb == VALIDATION_NO_THRESHOLD ||
+			 test_case.config.region_size <= threshold_mb * _1MB)
 			ksft_test_result_pass("%s: mremap time: %12lldns\n",
 					      test_case.name, remap_time);
 		else
-- 
2.53.0


^ permalink raw reply	[flat|nested] 13+ messages in thread

* [PATCH v2 07/12] selftests/mm: mremap_test: fail on data corruption
  2026-10-06  9:24 [PATCH v2 00/12] selftests/mm: improve mremap_test Sarthak Sharma
                   ` (5 preceding siblings ...)
  2026-10-06  9:25 ` [PATCH v2 06/12] selftests/mm: mremap_test: fail unexpected mremap successes Sarthak Sharma
@ 2026-10-06  9:25 ` Sarthak Sharma
  2026-10-06  9:25 ` [PATCH v2 08/12] selftests/mm: mremap_test: handle cleanup after mmap failures Sarthak Sharma
                   ` (4 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: Sarthak Sharma @ 2026-10-06  9:25 UTC (permalink / raw)
  To: akpm, david
  Cc: ljs, liam, vbabka, rppt, surenb, mhocko, shuah, jhubbard,
	kaleshsingh, anshuman.khandual, linux-mm, linux-kselftest,
	linux-kernel, Sarthak Sharma

In mremap_move_multiple_vmas_split(), if data is corrupted
after mremap, the control jumps to cleanup without marking
the test as failed.

Set success to false before moving to cleanup.

Fixes: 7d6597dfef11 ("tools/testing/selftests: explicitly test split multi VMA mremap move")
Acked-by: David Hildenbrand (Arm) <david@kernel.org>
Signed-off-by: Sarthak Sharma <sarthak.sharma@arm.com>
---
 tools/testing/selftests/mm/mremap_test.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/tools/testing/selftests/mm/mremap_test.c b/tools/testing/selftests/mm/mremap_test.c
index 1baf6374ec67..833efa85e5c6 100644
--- a/tools/testing/selftests/mm/mremap_test.c
+++ b/tools/testing/selftests/mm/mremap_test.c
@@ -682,6 +682,7 @@ static void mremap_move_multiple_vmas_split(unsigned int pattern_seed,
 			if (chr != buf[j]) {
 				ksft_print_msg("page %d offset %d corrupted, expected %d got %d\n",
 					       i, j, chr, buf[j]);
+				success = false;
 				goto out_unmap;
 			}
 		}
-- 
2.53.0


^ permalink raw reply	[flat|nested] 13+ messages in thread

* [PATCH v2 08/12] selftests/mm: mremap_test: handle cleanup after mmap failures
  2026-10-06  9:24 [PATCH v2 00/12] selftests/mm: improve mremap_test Sarthak Sharma
                   ` (6 preceding siblings ...)
  2026-10-06  9:25 ` [PATCH v2 07/12] selftests/mm: mremap_test: fail on data corruption Sarthak Sharma
@ 2026-10-06  9:25 ` Sarthak Sharma
  2026-10-06  9:25 ` [PATCH v2 09/12] selftests/mm: mremap_test: remove perf tests and timing Sarthak Sharma
                   ` (3 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: Sarthak Sharma @ 2026-10-06  9:25 UTC (permalink / raw)
  To: akpm, david
  Cc: ljs, liam, vbabka, rppt, surenb, mhocko, shuah, jhubbard,
	kaleshsingh, anshuman.khandual, linux-mm, linux-kselftest,
	linux-kernel, Sarthak Sharma

In several tests, when target mapping fails, we directly
jump to the result handling, without unmapping the
previously created source mapping. This leaks the
source mapping. Unmap the source mapping when target
mapping fails.

Also bypass munmap() when source mapping fails in
mremap_move_within_range().

Signed-off-by: Sarthak Sharma <sarthak.sharma@arm.com>
---
 tools/testing/selftests/mm/mremap_test.c | 18 +++++++++++-------
 1 file changed, 11 insertions(+), 7 deletions(-)

diff --git a/tools/testing/selftests/mm/mremap_test.c b/tools/testing/selftests/mm/mremap_test.c
index 833efa85e5c6..37bba5049ecc 100644
--- a/tools/testing/selftests/mm/mremap_test.c
+++ b/tools/testing/selftests/mm/mremap_test.c
@@ -340,7 +340,7 @@ static void mremap_move_within_range(unsigned int pattern_seed, char *rand_addr)
 	if (new_ptr == MAP_FAILED) {
 		ksft_perror("mremap");
 		success = 0;
-		goto out;
+		goto out_unmap;
 	}
 
 	/* Verify byte pattern after remapping */
@@ -357,9 +357,9 @@ static void mremap_move_within_range(unsigned int pattern_seed, char *rand_addr)
 		}
 	}
 
-out:
+out_unmap:
 	munmap(ptr, size);
-
+out:
 	ksft_test_result(success, "%s\n", test_name);
 }
 
@@ -415,7 +415,7 @@ static void mremap_move_multiple_vmas(unsigned int pattern_seed,
 	if (tgt_ptr == MAP_FAILED) {
 		ksft_perror("mmap");
 		success = false;
-		goto out;
+		goto out_unmap_src;
 	}
 	if (munmap(tgt_ptr, 2 * size)) {
 		ksft_perror("munmap");
@@ -501,6 +501,7 @@ static void mremap_move_multiple_vmas(unsigned int pattern_seed,
 
 out_unmap:
 	munmap(tgt_ptr, 2 * size);
+out_unmap_src:
 	munmap(ptr, size);
 out:
 	ksft_test_result(success, "%s%s\n", test_name, dont_unmap ? " [dontunmap]" : "");
@@ -529,7 +530,7 @@ static void mremap_shrink_multiple_vmas(unsigned long page_size,
 	if (tgt_ptr == MAP_FAILED) {
 		ksft_perror("mmap");
 		success = false;
-		goto out;
+		goto out_unmap_src;
 	}
 	if (munmap(tgt_ptr, size)) {
 		ksft_perror("munmap");
@@ -573,6 +574,7 @@ static void mremap_shrink_multiple_vmas(unsigned long page_size,
 
 out_unmap:
 	munmap(tgt_ptr, size);
+out_unmap_src:
 	munmap(ptr, size);
 out:
 	ksft_test_result(success, "%s%s\n", test_name, inplace ? " [inplace]" : "");
@@ -605,7 +607,7 @@ static void mremap_move_multiple_vmas_split(unsigned int pattern_seed,
 	if (tgt_ptr == MAP_FAILED) {
 		ksft_perror("mmap");
 		success = false;
-		goto out;
+		goto out_unmap_src;
 	}
 	if (munmap(tgt_ptr, size)) {
 		ksft_perror("munmap");
@@ -690,6 +692,7 @@ static void mremap_move_multiple_vmas_split(unsigned int pattern_seed,
 
 out_unmap:
 	munmap(tgt_ptr, size);
+out_unmap_src:
 	munmap(ptr, size);
 out:
 	ksft_test_result(success, "%s%s\n", test_name, dont_unmap ? " [dontunmap]" : "");
@@ -738,7 +741,7 @@ static void mremap_move_multi_invalid_vmas(FILE *maps_fp,
 	if (tgt_ptr == MAP_FAILED) {
 		ksft_perror("mmap");
 		success = false;
-		goto out_close_uffd;
+		goto out_unmap_src;
 	}
 	if (munmap(tgt_ptr, size)) {
 		ksft_perror("munmap");
@@ -910,6 +913,7 @@ static void mremap_move_multi_invalid_vmas(FILE *maps_fp,
 
 out_unmap:
 	munmap(tgt_ptr, size);
+out_unmap_src:
 	munmap(ptr, size);
 out_close_uffd:
 	close(uffd);
-- 
2.53.0


^ permalink raw reply	[flat|nested] 13+ messages in thread

* [PATCH v2 09/12] selftests/mm: mremap_test: remove perf tests and timing
  2026-10-06  9:24 [PATCH v2 00/12] selftests/mm: improve mremap_test Sarthak Sharma
                   ` (7 preceding siblings ...)
  2026-10-06  9:25 ` [PATCH v2 08/12] selftests/mm: mremap_test: handle cleanup after mmap failures Sarthak Sharma
@ 2026-10-06  9:25 ` Sarthak Sharma
  2026-10-06  9:25 ` [PATCH v2 10/12] selftests/mm: mremap_test: replace validation threshold with sampled checks Sarthak Sharma
                   ` (2 subsequent siblings)
  11 siblings, 0 replies; 13+ messages in thread
From: Sarthak Sharma @ 2026-10-06  9:25 UTC (permalink / raw)
  To: akpm, david
  Cc: ljs, liam, vbabka, rppt, surenb, mhocko, shuah, jhubbard,
	kaleshsingh, anshuman.khandual, linux-mm, linux-kselftest,
	linux-kernel, Sarthak Sharma

mremap_test contains three perf tests that report the time
taken to move 1GB mappings with different page table level
alignments. Although they validate the remapped data,
their main purpose is to report timing information. The
recorded time also does not affect the test result. Also,
they are not run with the default validation threshold.

Remove these tests and the timing infrastructure from
mremap_test.c. The regular tests continue to cover PUD
and PMD aligned remaps.

Suggested-by: David Hildenbrand (Arm) <david@kernel.org>
Acked-by: David Hildenbrand (Arm) <david@kernel.org>
Signed-off-by: Sarthak Sharma <sarthak.sharma@arm.com>
---
 tools/testing/selftests/mm/mremap_test.c | 64 +++---------------------
 1 file changed, 7 insertions(+), 57 deletions(-)

diff --git a/tools/testing/selftests/mm/mremap_test.c b/tools/testing/selftests/mm/mremap_test.c
index 37bba5049ecc..403c5495e160 100644
--- a/tools/testing/selftests/mm/mremap_test.c
+++ b/tools/testing/selftests/mm/mremap_test.c
@@ -22,7 +22,6 @@
 #define EXPECT_FAILURE 1
 #define NON_OVERLAPPING 0
 #define OVERLAPPING 1
-#define NS_PER_SEC 1000000000ULL
 #define VALIDATION_DEFAULT_THRESHOLD 4	/* 4MB */
 #define VALIDATION_NO_THRESHOLD 0	/* Verify the entire region */
 
@@ -929,14 +928,13 @@ static void mremap_move_multi_invalid_vmas(FILE *maps_fp, unsigned long page_siz
 }
 #endif /* __NR_userfaultfd */
 
-/* Returns the time taken for the remap on success else returns -1. */
-static long long remap_region(struct config c, unsigned int threshold_mb,
-			      char *rand_addr)
+static int remap_region(struct config c, unsigned int threshold_mb,
+			char *rand_addr)
 {
 	void *addr, *tmp_addr, *src_addr, *dest_addr, *dest_preamble_addr = NULL;
-	struct timespec t_start = {0, 0}, t_end = {0, 0};
-	long long  start_ns, end_ns, align_mask, ret, offset;
+	long long align_mask, offset;
 	unsigned long long threshold;
+	int ret = 0;
 
 	if (threshold_mb == VALIDATION_NO_THRESHOLD)
 		threshold = c.region_size;
@@ -994,10 +992,8 @@ static long long remap_region(struct config c, unsigned int threshold_mb,
 		memcpy(dest_preamble_addr, rand_addr, c.dest_preamble_size);
 	}
 
-	clock_gettime(CLOCK_MONOTONIC, &t_start);
 	dest_addr = mremap(src_addr, c.region_size, c.region_size,
 			   MREMAP_MAYMOVE | MREMAP_FIXED, (char *)addr);
-	clock_gettime(CLOCK_MONOTONIC, &t_end);
 
 	if (dest_addr == MAP_FAILED) {
 		ksft_print_msg("mremap failed: %s\n", strerror(errno));
@@ -1020,16 +1016,6 @@ static long long remap_region(struct config c, unsigned int threshold_mb,
 		goto clean_up_dest;
 	}
 
-	start_ns = t_start.tv_sec * NS_PER_SEC + t_start.tv_nsec;
-	end_ns = t_end.tv_sec * NS_PER_SEC + t_end.tv_nsec;
-	ret = end_ns - start_ns;
-
-/*
- * Since the destination address is specified using MREMAP_FIXED, subsequent
- * mremap will unmap any previous mapping at the address range specified by
- * dest_addr and region_size. This significantly affects the remap time of
- * subsequent tests. So we clean up mappings after each test.
- */
 clean_up_dest:
 	munmap(dest_addr, c.region_size);
 clean_up_dest_preamble:
@@ -1117,10 +1103,9 @@ static void run_mremap_test_case(struct test test_case,
 				 unsigned int threshold_mb,
 				 char *rand_addr)
 {
-	long long remap_time = remap_region(test_case.config, threshold_mb,
-					    rand_addr);
+	int ret = remap_region(test_case.config, threshold_mb, rand_addr);
 
-	if (remap_time < 0) {
+	if (ret < 0) {
 		if (test_case.expect_failure)
 			ksft_test_result_xfail("%s: expected mremap failure\n",
 					       test_case.name);
@@ -1130,25 +1115,15 @@ static void run_mremap_test_case(struct test test_case,
 		if (test_case.expect_failure)
 			ksft_test_result_fail("%s: unexpected mremap success\n",
 					      test_case.name);
-		/*
-		 * Comparing mremap time is only applicable if entire region
-		 * was faulted in.
-		 */
-		else if (threshold_mb == VALIDATION_NO_THRESHOLD ||
-			 test_case.config.region_size <= threshold_mb * _1MB)
-			ksft_test_result_pass("%s: mremap time: %12lldns\n",
-					      test_case.name, remap_time);
 		else
 			ksft_test_result_pass("%s\n", test_case.name);
 	}
 }
 
 #define MAX_TEST 15
-#define MAX_PERF_TEST 3
 int main(void)
 {
 	unsigned int i;
-	int run_perf_tests;
 	unsigned int threshold_mb = VALIDATION_DEFAULT_THRESHOLD;
 
 	/* hard-coded test configs */
@@ -1162,7 +1137,6 @@ int main(void)
 	int num_expand_tests = 2;
 	int num_misc_tests = 9;
 	struct test test_cases[MAX_TEST] = {};
-	struct test perf_test_cases[MAX_PERF_TEST];
 	int page_size;
 	time_t t;
 	FILE *maps_fp;
@@ -1252,22 +1226,7 @@ int main(void)
 				  "5MB mremap - Source 1MB-aligned, Dest 1MB-aligned with 40MB Preamble");
 	test_cases[14].config.dest_preamble_size = 10 * _4MB;
 
-	perf_test_cases[0] =  MAKE_TEST(page_size, page_size, _1GB, NON_OVERLAPPING, EXPECT_SUCCESS,
-					"1GB mremap - Source PTE-aligned, Destination PTE-aligned");
-	/*
-	 * mremap 1GB region - Page table level aligned time
-	 * comparison.
-	 */
-	perf_test_cases[1] = MAKE_TEST(PMD, PMD, _1GB, NON_OVERLAPPING, EXPECT_SUCCESS,
-				       "1GB mremap - Source PMD-aligned, Destination PMD-aligned");
-	perf_test_cases[2] = MAKE_TEST(PUD, PUD, _1GB, NON_OVERLAPPING, EXPECT_SUCCESS,
-				       "1GB mremap - Source PUD-aligned, Destination PUD-aligned");
-
-	run_perf_tests =  (threshold_mb == VALIDATION_NO_THRESHOLD) ||
-				(threshold_mb * _1MB >= _1GB);
-
-	ksft_set_plan(ARRAY_SIZE(test_cases) + (run_perf_tests ?
-		      ARRAY_SIZE(perf_test_cases) : 0) + num_expand_tests + num_misc_tests);
+	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);
@@ -1294,15 +1253,6 @@ int main(void)
 
 	fclose(maps_fp);
 
-	if (run_perf_tests) {
-		ksft_print_msg("%s\n",
-		 "mremap HAVE_MOVE_PMD/PUD optimization time comparison for 1GB region:");
-		for (i = 0; i < ARRAY_SIZE(perf_test_cases); i++)
-			run_mremap_test_case(perf_test_cases[i],
-					     threshold_mb,
-					     rand_addr);
-	}
-
 	munmap(rand_addr, rand_size);
 
 	ksft_finished();
-- 
2.53.0


^ permalink raw reply	[flat|nested] 13+ messages in thread

* [PATCH v2 10/12] selftests/mm: mremap_test: replace validation threshold with sampled checks
  2026-10-06  9:24 [PATCH v2 00/12] selftests/mm: improve mremap_test Sarthak Sharma
                   ` (8 preceding siblings ...)
  2026-10-06  9:25 ` [PATCH v2 09/12] selftests/mm: mremap_test: remove perf tests and timing Sarthak Sharma
@ 2026-10-06  9:25 ` Sarthak Sharma
  2026-10-06  9:25 ` [PATCH v2 11/12] selftests/mm: mremap_test: replace random data with deterministic pattern Sarthak Sharma
  2026-10-06  9:25 ` [PATCH v2 12/12] selftests/mm: mremap_test: strengthen multi VMA validation Sarthak Sharma
  11 siblings, 0 replies; 13+ messages in thread
From: Sarthak Sharma @ 2026-10-06  9:25 UTC (permalink / raw)
  To: akpm, david
  Cc: ljs, liam, vbabka, rppt, surenb, mhocko, shuah, jhubbard,
	kaleshsingh, anshuman.khandual, linux-mm, linux-kselftest,
	linux-kernel, Sarthak Sharma

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@kernel.org>
Signed-off-by: Sarthak Sharma <sarthak.sharma@arm.com>
---
 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


^ permalink raw reply	[flat|nested] 13+ messages in thread

* [PATCH v2 11/12] selftests/mm: mremap_test: replace random data with deterministic pattern
  2026-10-06  9:24 [PATCH v2 00/12] selftests/mm: improve mremap_test Sarthak Sharma
                   ` (9 preceding siblings ...)
  2026-10-06  9:25 ` [PATCH v2 10/12] selftests/mm: mremap_test: replace validation threshold with sampled checks Sarthak Sharma
@ 2026-10-06  9:25 ` Sarthak Sharma
  2026-10-06  9:25 ` [PATCH v2 12/12] selftests/mm: mremap_test: strengthen multi VMA validation Sarthak Sharma
  11 siblings, 0 replies; 13+ messages in thread
From: Sarthak Sharma @ 2026-10-06  9:25 UTC (permalink / raw)
  To: akpm, david
  Cc: ljs, liam, vbabka, rppt, surenb, mhocko, shuah, jhubbard,
	kaleshsingh, anshuman.khandual, linux-mm, linux-kselftest,
	linux-kernel, Sarthak Sharma

mremap_test uses a random data stream to detect corruption after remap
operations. This requires seed handling and byte by byte validation,
which is inefficient.

Replace it with a deterministic pattern where every word in a page
contains its one-based page index. Use memcpy() and memcmp() to
initialize and validate the mappings. Remove the pattern seed and
update the comment diagrams to reflect the new deterministic pattern.

Suggested-by: David Hildenbrand (Arm) <david@kernel.org>
Signed-off-by: Sarthak Sharma <sarthak.sharma@arm.com>
---
 tools/testing/selftests/mm/mremap_test.c | 220 +++++++++--------------
 1 file changed, 85 insertions(+), 135 deletions(-)

diff --git a/tools/testing/selftests/mm/mremap_test.c b/tools/testing/selftests/mm/mremap_test.c
index 955727607d4f..92ffcbe547b5 100644
--- a/tools/testing/selftests/mm/mremap_test.c
+++ b/tools/testing/selftests/mm/mremap_test.c
@@ -13,8 +13,8 @@
 #include <sys/ioctl.h>
 #include <sys/mman.h>
 #include <syscall.h>
-#include <time.h>
 #include <stdbool.h>
+#include <stdint.h>
 
 #include "kselftest.h"
 
@@ -304,11 +304,11 @@ static void mremap_expand_merge_offset(FILE *maps_fp, unsigned long page_size)
  *
  * |DDDDddddSSSSssss|
  */
-static void mremap_move_within_range(unsigned int pattern_seed, char *rand_addr)
+static void mremap_move_within_range(char *pattern_addr)
 {
 	char *test_name = "mremap move within range";
 	void *src, *dest;
-	unsigned int i, success = 1;
+	unsigned int success = 1;
 
 	size_t size = SIZE_MB(20);
 	void *ptr = mmap(NULL, size, PROT_READ | PROT_WRITE,
@@ -324,7 +324,7 @@ static void mremap_move_within_range(unsigned int pattern_seed, char *rand_addr)
 	src = (void *)((unsigned long)src & ~(SIZE_MB(2) - 1));
 
 	/* Set byte pattern for source block. */
-	memcpy(src, rand_addr, SIZE_MB(2));
+	memcpy(src, pattern_addr + SIZE_MB(2), SIZE_MB(2));
 
 	dest = src - SIZE_MB(2);
 
@@ -337,17 +337,9 @@ static void mremap_move_within_range(unsigned int pattern_seed, char *rand_addr)
 	}
 
 	/* Verify byte pattern after remapping */
-	srand(pattern_seed);
-	for (i = 0; i < SIZE_MB(1); i++) {
-		char c = (char) rand();
-
-		if (((char *)src)[i] != c) {
-			ksft_print_msg("Data at src at %d got corrupted due to unrelated mremap\n",
-				       i);
-			ksft_print_msg("Expected: %#x\t Got: %#x\n", c & 0xff,
-					((char *) src)[i] & 0xff);
-			success = 0;
-		}
+	if (memcmp(src, pattern_addr + SIZE_MB(2), SIZE_MB(1))) {
+		ksft_print_msg("Source data was corrupted\n");
+		success = 0;
 	}
 
 out_unmap:
@@ -356,32 +348,24 @@ static void mremap_move_within_range(unsigned int pattern_seed, char *rand_addr)
 	ksft_test_result(success, "%s\n", test_name);
 }
 
-static bool is_multiple_vma_range_ok(unsigned int pattern_seed,
-				     char *ptr, unsigned long page_size)
+static bool is_multiple_vma_range_ok(char *pattern_addr, char *ptr,
+				     unsigned long page_size)
 {
-	int i;
-
-	srand(pattern_seed);
-	for (i = 0; i <= 10; i += 2) {
-		int j;
-		char *buf = &ptr[i * page_size];
+	for (int i = 0; i <= 10; i += 2) {
 		size_t size = i == 4 ? 2 * page_size : page_size;
 
-		for (j = 0; j < size; j++) {
-			char chr = rand();
-
-			if (chr != buf[j]) {
-				ksft_print_msg("page %d offset %d corrupted, expected %d got %d\n",
-					       i, j, chr, buf[j]);
-				return false;
-			}
+		if (memcmp(ptr + i * page_size, pattern_addr + i * page_size,
+			   size)) {
+			ksft_print_msg("Data in VMA starting at page %d got corrupted\n",
+				       i);
+			return false;
 		}
 	}
 
 	return true;
 }
 
-static void mremap_move_multiple_vmas(unsigned int pattern_seed,
+static void mremap_move_multiple_vmas(char *pattern_addr,
 				      unsigned long page_size,
 				      bool dont_unmap)
 {
@@ -416,13 +400,15 @@ static void mremap_move_multiple_vmas(unsigned int pattern_seed,
 		goto out_unmap;
 	}
 
+	memcpy(ptr, pattern_addr, size);
+
 	/*
 	 * Unmap so we end up with:
 	 *
 	 *  0   2   4 5 6   8   10 offset in buffer
 	 * |*| |*| |*****| |*| |*|
 	 * |*| |*| |*****| |*| |*|
-	 *  0   1   2 3 4   5   6  pattern offset
+	 *  0   2   4 5 6   8   10  pattern offset
 	 */
 	for (i = 1; i < 10; i += 2) {
 		if (i == 5)
@@ -435,18 +421,6 @@ static void mremap_move_multiple_vmas(unsigned int pattern_seed,
 		}
 	}
 
-	srand(pattern_seed);
-
-	/* Set up random patterns. */
-	for (i = 0; i <= 10; i += 2) {
-		int j;
-		size_t size = i == 4 ? 2 * page_size : page_size;
-		char *buf = &ptr[i * page_size];
-
-		for (j = 0; j < size; j++)
-			buf[j] = rand();
-	}
-
 	/* First, just move the whole thing. */
 	if (mremap(ptr, size, size, mremap_flags, tgt_ptr) == MAP_FAILED) {
 		ksft_perror("mremap");
@@ -454,7 +428,7 @@ static void mremap_move_multiple_vmas(unsigned int pattern_seed,
 		goto out_unmap;
 	}
 	/* Check move was ok. */
-	if (!is_multiple_vma_range_ok(pattern_seed, tgt_ptr, page_size)) {
+	if (!is_multiple_vma_range_ok(pattern_addr, tgt_ptr, page_size)) {
 		success = false;
 		goto out_unmap;
 	}
@@ -467,7 +441,7 @@ static void mremap_move_multiple_vmas(unsigned int pattern_seed,
 		goto out_unmap;
 	}
 	/* Check that the move is ok. */
-	if (!is_multiple_vma_range_ok(pattern_seed, &tgt_ptr[size], page_size)) {
+	if (!is_multiple_vma_range_ok(pattern_addr, &tgt_ptr[size], page_size)) {
 		success = false;
 		goto out_unmap;
 	}
@@ -487,7 +461,7 @@ static void mremap_move_multiple_vmas(unsigned int pattern_seed,
 		goto out_unmap;
 	}
 	/* Check that the move is ok. */
-	if (!is_multiple_vma_range_ok(pattern_seed, tgt_ptr, page_size)) {
+	if (!is_multiple_vma_range_ok(pattern_addr, tgt_ptr, page_size)) {
 		success = false;
 		goto out_unmap;
 	}
@@ -573,7 +547,7 @@ static void mremap_shrink_multiple_vmas(unsigned long page_size,
 	ksft_test_result(success, "%s%s\n", test_name, inplace ? " [inplace]" : "");
 }
 
-static void mremap_move_multiple_vmas_split(unsigned int pattern_seed,
+static void mremap_move_multiple_vmas_split(char *pattern_addr,
 					    unsigned long page_size,
 					    bool dont_unmap)
 {
@@ -608,13 +582,15 @@ static void mremap_move_multiple_vmas_split(unsigned int pattern_seed,
 		goto out_unmap;
 	}
 
+	memcpy(ptr, pattern_addr, size);
+
 	/*
 	 * Unmap so we end up with:
 	 *
 	 *  0 1 2 3 4 5 6 7 8 9 10 offset in buffer
 	 * |**********| |*******|
 	 * |**********| |*******|
-	 *  0 1 2 3 4   5 6 7 8 9  pattern offset
+	 *  0 1 2 3 4 5 6 7 8 9 10 pattern offset
 	 */
 	if (munmap(&ptr[5 * page_size], page_size)) {
 		ksft_perror("munmap");
@@ -622,19 +598,6 @@ static void mremap_move_multiple_vmas_split(unsigned int pattern_seed,
 		goto out_unmap;
 	}
 
-	/* Set up random patterns. */
-	srand(pattern_seed);
-	for (i = 0; i < 10; i++) {
-		int j;
-		char *buf = &ptr[i * page_size];
-
-		if (i == 5)
-			continue;
-
-		for (j = 0; j < page_size; j++)
-			buf[j] = rand();
-	}
-
 	/*
 	 * Move the below:
 	 *
@@ -642,14 +605,14 @@ static void mremap_move_multiple_vmas_split(unsigned int pattern_seed,
 	 *  0 1 2 3 4 5 6 7 8 9 10 offset in buffer
 	 * |**********| |*******|
 	 * |**********| |*******|
-	 *  0 1 2 3 4   5 6 7 8 9  pattern offset
+	 *  0 1 2 3 4 5 6 7 8 9 10  pattern offset
 	 *
 	 * Into:
 	 *
 	 * 0 1 2 3 4 5 6 7 offset in buffer
 	 * |*****| |*****|
 	 * |*****| |*****|
-	 * 2 3 4   5 6 7   pattern offset
+	 * 2 3 4 5 6 7 8 9 pattern offset
 	 */
 	if (mremap(&ptr[2 * page_size], size - 3 * page_size, size - 3 * page_size,
 		   mremap_flags, tgt_ptr) == MAP_FAILED) {
@@ -658,28 +621,16 @@ static void mremap_move_multiple_vmas_split(unsigned int pattern_seed,
 		goto out_unmap;
 	}
 
-	/* Offset into random pattern. */
-	srand(pattern_seed);
-	for (i = 0; i < 2 * page_size; i++)
-		rand();
-
 	/* Check pattern. */
 	for (i = 0; i < 7; i++) {
-		int j;
-		char *buf = &tgt_ptr[i * page_size];
-
 		if (i == 3)
 			continue;
 
-		for (j = 0; j < page_size; j++) {
-			char chr = rand();
-
-			if (chr != buf[j]) {
-				ksft_print_msg("page %d offset %d corrupted, expected %d got %d\n",
-					       i, j, chr, buf[j]);
-				success = false;
-				goto out_unmap;
-			}
+		if (memcmp(tgt_ptr + i * page_size,
+			   pattern_addr + (i + 2) * page_size, page_size)) {
+			ksft_print_msg("Data in page %d got corrupted\n", i + 2);
+			success = false;
+			goto out_unmap;
 		}
 	}
 
@@ -958,11 +909,12 @@ static bool validate_test_data(char *addr, size_t size, char *pattern_addr,
 	       !memcmp(addr + end, pattern_addr + 2 * len, len);
 }
 
-static int remap_region(struct config c, char *rand_addr, size_t rand_size,
+static int remap_region(struct config c, char *pattern_addr, size_t pattern_size,
 		size_t page_size)
 {
 	void *addr, *tmp_addr, *src_addr, *dest_addr, *dest_preamble_addr = NULL;
 	long long align_mask, offset;
+	char *preamble_pattern = NULL;
 	int ret = 0;
 
 	src_addr = get_source_mapping(c);
@@ -972,7 +924,8 @@ static int remap_region(struct config c, char *rand_addr, size_t rand_size,
 	}
 
 	/* Set byte pattern for source block. */
-	populate_test_data(src_addr, c.region_size, rand_addr, rand_size, page_size);
+	populate_test_data(src_addr, c.region_size, pattern_addr,
+			   pattern_size, page_size);
 
 	/* Mask to zero out lower bits of address for alignment */
 	align_mask = ~(c.dest_alignment - 1);
@@ -1012,8 +965,9 @@ static int remap_region(struct config c, char *rand_addr, size_t rand_size,
 			goto clean_up_src;
 		}
 
+		preamble_pattern = pattern_addr + pattern_size - c.dest_preamble_size;
 		/* Set byte pattern for the dest preamble block. */
-		memcpy(dest_preamble_addr, rand_addr, c.dest_preamble_size);
+		memcpy(dest_preamble_addr, preamble_pattern, c.dest_preamble_size);
 	}
 
 	dest_addr = mremap(src_addr, c.region_size, c.region_size,
@@ -1026,8 +980,8 @@ static int remap_region(struct config c, char *rand_addr, size_t rand_size,
 	}
 
 	/* Verify byte pattern after remapping */
-	if (!validate_test_data(dest_addr, c.region_size, rand_addr,
-				rand_size, page_size)) {
+	if (!validate_test_data(dest_addr, c.region_size, pattern_addr,
+				pattern_size, page_size)) {
 		ksft_print_msg("Data after remap doesn't match\n");
 		ret = -1;
 		goto clean_up_dest;
@@ -1035,7 +989,7 @@ static int remap_region(struct config c, char *rand_addr, size_t rand_size,
 
 	/* Verify the dest preamble byte pattern after remapping */
 	if (c.dest_preamble_size &&
-	    memcmp(dest_preamble_addr, rand_addr, c.dest_preamble_size)) {
+	    memcmp(dest_preamble_addr, preamble_pattern, c.dest_preamble_size)) {
 		ksft_print_msg("Preamble data after remap doesn't match\n");
 		ret = -1;
 		goto clean_up_dest;
@@ -1057,12 +1011,11 @@ static int remap_region(struct config c, char *rand_addr, size_t rand_size,
  * the beginning of the mapping just because the aligned
  * down address landed on a mapping that maybe does not exist.
  */
-static void mremap_move_1mb_from_start(unsigned int pattern_seed,
-				       char *rand_addr)
+static void mremap_move_1mb_from_start(char *pattern_addr)
 {
 	char *test_name = "mremap move 1mb from start at 1MB+256KB aligned src";
 	void *src = NULL, *dest = NULL;
-	unsigned int i, success = 1;
+	unsigned int success = 1;
 
 	/* Config to reuse get_source_mapping() to do an aligned mmap. */
 	struct config c = {
@@ -1084,7 +1037,7 @@ static void mremap_move_1mb_from_start(unsigned int pattern_seed,
 	}
 
 	/* Set byte pattern for source block. */
-	memcpy(src, rand_addr, SIZE_MB(2));
+	memcpy(src, pattern_addr, SIZE_MB(2));
 
 	/*
 	 * Unmap the beginning of dest so that the aligned address
@@ -1101,17 +1054,9 @@ static void mremap_move_1mb_from_start(unsigned int pattern_seed,
 	}
 
 	/* Verify byte pattern after remapping */
-	srand(pattern_seed);
-	for (i = 0; i < SIZE_MB(1); i++) {
-		char c = (char) rand();
-
-		if (((char *)src)[i] != c) {
-			ksft_print_msg("Data at src at %d got corrupted due to unrelated mremap\n",
-				       i);
-			ksft_print_msg("Expected: %#x\t Got: %#x\n", c & 0xff,
-					((char *) src)[i] & 0xff);
-			success = 0;
-		}
+	if (memcmp(src, pattern_addr, SIZE_MB(1))) {
+		ksft_print_msg("Data before the remapped range was corrupted\n");
+		success = 0;
 	}
 
 out:
@@ -1125,11 +1070,11 @@ static void mremap_move_1mb_from_start(unsigned int pattern_seed,
 }
 
 static void run_mremap_test_case(struct test test_case,
-				 char *rand_addr,
-				 size_t rand_size,
+				 char *pattern_addr,
+				 size_t pattern_size,
 				 size_t page_size)
 {
-	int ret = remap_region(test_case.config, rand_addr, rand_size, page_size);
+	int ret = remap_region(test_case.config, pattern_addr, pattern_size, page_size);
 
 	if (ret < 0) {
 		if (test_case.expect_failure)
@@ -1146,47 +1091,52 @@ static void run_mremap_test_case(struct test test_case,
 	}
 }
 
+static void fill_pattern(char *pattern_addr, size_t pattern_size, size_t page_size)
+{
+	size_t nr_pages = pattern_size / page_size;
+	size_t words_per_page = page_size / sizeof(uint32_t);
+	size_t page, word;
+
+	for (page = 0; page < nr_pages; page++) {
+		uint32_t *page_addr = (uint32_t *)pattern_addr + page * words_per_page;
+		uint32_t val = page + 1;
+
+		for (word = 0; word < words_per_page; word++)
+			page_addr[word] = val;
+	}
+}
+
 #define MAX_TEST 15
 int main(void)
 {
 	unsigned int i;
 
-	unsigned int pattern_seed;
-	char *rand_addr;
-	size_t rand_size;
+	char *pattern_addr;
+	size_t pattern_size;
 	int num_expand_tests = 2;
 	int num_misc_tests = 9;
 	struct test test_cases[MAX_TEST] = {};
 	int page_size;
-	time_t t;
 	FILE *maps_fp;
 
 	ksft_print_header();
 
 	get_mmap_min_addr();
 
-	pattern_seed = (unsigned int) time(&t);
-
-	ksft_print_msg("Test configs:\n");
-	ksft_print_msg("pattern_seed=%u\n", pattern_seed);
-
 	/*
-	 * The 40MB destination preamble determines the random buffer size
+	 * The 40MB destination preamble determines the pattern buffer size
 	 */
-	rand_size = 10 * _4MB;
+	pattern_size = 10 * _4MB;
 
-	rand_addr = (char *)mmap(NULL, rand_size, PROT_READ | PROT_WRITE,
-				 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
-	if (rand_addr == MAP_FAILED)
-		ksft_exit_fail_perror("cannot mmap rand_addr");
-
-	/* fill stream of random bytes */
-	srand(pattern_seed);
-	for (unsigned long i = 0; i < rand_size; ++i)
-		rand_addr[i] = (char) rand();
+	pattern_addr = (char *)mmap(NULL, pattern_size, PROT_READ | PROT_WRITE,
+				    MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+	if (pattern_addr == MAP_FAILED)
+		ksft_exit_fail_perror("cannot mmap pattern_addr");
 
 	page_size = sysconf(_SC_PAGESIZE);
 
+	fill_pattern(pattern_addr, pattern_size, page_size);
+
 	/* Expected mremap failures */
 	test_cases[0] =	MAKE_TEST(page_size, page_size, page_size,
 				  OVERLAPPING, EXPECT_FAILURE,
@@ -1240,31 +1190,31 @@ 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], rand_addr, rand_size, page_size);
+		run_mremap_test_case(test_cases[i], pattern_addr, pattern_size, page_size);
 
 	maps_fp = fopen("/proc/self/maps", "r");
 
 	if (maps_fp == NULL) {
-		munmap(rand_addr, rand_size);
+		munmap(pattern_addr, pattern_size);
 		ksft_exit_fail_msg("Failed to read /proc/self/maps: %s\n", strerror(errno));
 	}
 
 	mremap_expand_merge(maps_fp, page_size);
 	mremap_expand_merge_offset(maps_fp, page_size);
 
-	mremap_move_within_range(pattern_seed, rand_addr);
-	mremap_move_1mb_from_start(pattern_seed, rand_addr);
+	mremap_move_within_range(pattern_addr);
+	mremap_move_1mb_from_start(pattern_addr);
 	mremap_shrink_multiple_vmas(page_size, /* inplace= */true);
 	mremap_shrink_multiple_vmas(page_size, /* inplace= */false);
-	mremap_move_multiple_vmas(pattern_seed, page_size, /* dontunmap= */ false);
-	mremap_move_multiple_vmas(pattern_seed, page_size, /* dontunmap= */ true);
-	mremap_move_multiple_vmas_split(pattern_seed, page_size, /* dontunmap= */ false);
-	mremap_move_multiple_vmas_split(pattern_seed, page_size, /* dontunmap= */ true);
+	mremap_move_multiple_vmas(pattern_addr, page_size, /* dontunmap= */ false);
+	mremap_move_multiple_vmas(pattern_addr, page_size, /* dontunmap= */ true);
+	mremap_move_multiple_vmas_split(pattern_addr, page_size, /* dontunmap= */ false);
+	mremap_move_multiple_vmas_split(pattern_addr, page_size, /* dontunmap= */ true);
 	mremap_move_multi_invalid_vmas(maps_fp, page_size);
 
 	fclose(maps_fp);
 
-	munmap(rand_addr, rand_size);
+	munmap(pattern_addr, pattern_size);
 
 	ksft_finished();
 }
-- 
2.53.0


^ permalink raw reply	[flat|nested] 13+ messages in thread

* [PATCH v2 12/12] selftests/mm: mremap_test: strengthen multi VMA validation
  2026-10-06  9:24 [PATCH v2 00/12] selftests/mm: improve mremap_test Sarthak Sharma
                   ` (10 preceding siblings ...)
  2026-10-06  9:25 ` [PATCH v2 11/12] selftests/mm: mremap_test: replace random data with deterministic pattern Sarthak Sharma
@ 2026-10-06  9:25 ` Sarthak Sharma
  11 siblings, 0 replies; 13+ messages in thread
From: Sarthak Sharma @ 2026-10-06  9:25 UTC (permalink / raw)
  To: akpm, david
  Cc: ljs, liam, vbabka, rppt, surenb, mhocko, shuah, jhubbard,
	kaleshsingh, anshuman.khandual, linux-mm, linux-kselftest,
	linux-kernel, Sarthak Sharma

Tests in mremap_test.c where a multi VMA range is involved only
check if the data remains consistent across mapped pages after
remap. They do not verify the mapping state of gaps in the
remapped range.

Add helpers to check whether a range is mapped with the
expected permissions using /proc/self/maps. Use them to
verify that gaps remain unmapped after regular multi VMA
moves and after the partial move in the userfaultfd
multi VMA test. Also verify that gaps retain PROT_NONE
permissions when remapping over an existing mapping
with PROT_NONE permissions.

Signed-off-by: Sarthak Sharma <sarthak.sharma@arm.com>
---
 tools/testing/selftests/mm/mremap_test.c | 105 ++++++++++++++++++-----
 1 file changed, 85 insertions(+), 20 deletions(-)

diff --git a/tools/testing/selftests/mm/mremap_test.c b/tools/testing/selftests/mm/mremap_test.c
index 92ffcbe547b5..2a349b967695 100644
--- a/tools/testing/selftests/mm/mremap_test.c
+++ b/tools/testing/selftests/mm/mremap_test.c
@@ -122,13 +122,14 @@ static unsigned long long get_mmap_min_addr(void)
 }
 
 /*
- * Using /proc/self/maps, assert that the specified address range is contained
- * within a single mapping.
+ * Using /proc/self/maps, check whether the specified address range is contained
+ * within a single mapping with the expected permissions, if supplied.
  */
-static bool is_range_mapped(FILE *maps_fp, unsigned long start,
-			    unsigned long end)
+static bool is_range_mapped_with_perms(FILE *maps_fp, unsigned long start,
+		unsigned long end, const char *expected_perms)
 {
 	char *line = NULL;
+	char perms[5];
 	size_t len = 0;
 	bool success = false;
 	unsigned long first_val, second_val;
@@ -136,12 +137,13 @@ static bool is_range_mapped(FILE *maps_fp, unsigned long start,
 	rewind(maps_fp);
 
 	while (getline(&line, &len, maps_fp) != -1) {
-		if (sscanf(line, "%lx-%lx", &first_val, &second_val) != 2) {
+		if (sscanf(line, "%lx-%lx %4s", &first_val, &second_val, perms) != 3) {
 			ksft_exit_fail_msg("cannot parse /proc/self/maps\n");
 			break;
 		}
 
-		if (first_val <= start && second_val >= end) {
+		if (first_val <= start && second_val >= end &&
+		    (!expected_perms || !strcmp(perms, expected_perms))) {
 			success = true;
 			fflush(maps_fp);
 			break;
@@ -152,6 +154,12 @@ static bool is_range_mapped(FILE *maps_fp, unsigned long start,
 	return success;
 }
 
+static bool is_range_mapped(FILE *maps_fp, unsigned long start,
+			    unsigned long end)
+{
+	return is_range_mapped_with_perms(maps_fp, start, end, NULL);
+}
+
 /* Check if [ptr, ptr + size) mapped in /proc/self/maps. */
 static bool is_ptr_mapped(FILE *maps_fp, void *ptr, unsigned long size)
 {
@@ -161,6 +169,20 @@ static bool is_ptr_mapped(FILE *maps_fp, void *ptr, unsigned long size)
 	return is_range_mapped(maps_fp, start, end);
 }
 
+/*
+ * Check if [ptr, ptr + size) is mapped with the required permissions in
+ * /proc/self/maps.
+ */
+static bool is_ptr_mapped_with_perms(FILE *maps_fp, void *ptr,
+				     unsigned long size,
+				     const char *expected_perms)
+{
+	unsigned long start = (unsigned long)ptr;
+	unsigned long end = start + size;
+
+	return is_range_mapped_with_perms(maps_fp, start, end, expected_perms);
+}
+
 /*
  * Returns the start address of the mapping on success, else returns
  * NULL on failure.
@@ -348,10 +370,33 @@ static void mremap_move_within_range(char *pattern_addr)
 	ksft_test_result(success, "%s\n", test_name);
 }
 
-static bool is_multiple_vma_range_ok(char *pattern_addr, char *ptr,
-				     unsigned long page_size)
+static bool is_multiple_vma_range_ok(FILE *maps_fp, char *pattern_addr,
+				     char *ptr, unsigned long page_size,
+				     bool expect_gaps_mapped)
 {
-	for (int i = 0; i <= 10; i += 2) {
+	for (int i = 0; i <= 10; i++) {
+
+		if (i == 5)
+			continue;
+
+		/* Odd pages correspond to gaps between the source VMAs. */
+		if (i & 1) {
+			if (expect_gaps_mapped) {
+				if (!is_ptr_mapped_with_perms(maps_fp,
+							      ptr + i * page_size,
+							      page_size, "---p")) {
+					ksft_print_msg("Page %d PROT_NONE mapping overwritten\n",
+						       i);
+					return false;
+				}
+			} else if (is_ptr_mapped(maps_fp, ptr + i * page_size,
+						 page_size)) {
+				ksft_print_msg("Page %d is unexpectedly mapped\n", i);
+				return false;
+			}
+			continue;
+		}
+
 		size_t size = i == 4 ? 2 * page_size : page_size;
 
 		if (memcmp(ptr + i * page_size, pattern_addr + i * page_size,
@@ -365,7 +410,7 @@ static bool is_multiple_vma_range_ok(char *pattern_addr, char *ptr,
 	return true;
 }
 
-static void mremap_move_multiple_vmas(char *pattern_addr,
+static void mremap_move_multiple_vmas(FILE *maps_fp, char *pattern_addr,
 				      unsigned long page_size,
 				      bool dont_unmap)
 {
@@ -428,7 +473,8 @@ static void mremap_move_multiple_vmas(char *pattern_addr,
 		goto out_unmap;
 	}
 	/* Check move was ok. */
-	if (!is_multiple_vma_range_ok(pattern_addr, tgt_ptr, page_size)) {
+	if (!is_multiple_vma_range_ok(maps_fp, pattern_addr, tgt_ptr,
+				      page_size, false)) {
 		success = false;
 		goto out_unmap;
 	}
@@ -441,7 +487,8 @@ static void mremap_move_multiple_vmas(char *pattern_addr,
 		goto out_unmap;
 	}
 	/* Check that the move is ok. */
-	if (!is_multiple_vma_range_ok(pattern_addr, &tgt_ptr[size], page_size)) {
+	if (!is_multiple_vma_range_ok(maps_fp, pattern_addr, &tgt_ptr[size],
+				      page_size, false)) {
 		success = false;
 		goto out_unmap;
 	}
@@ -461,7 +508,8 @@ static void mremap_move_multiple_vmas(char *pattern_addr,
 		goto out_unmap;
 	}
 	/* Check that the move is ok. */
-	if (!is_multiple_vma_range_ok(pattern_addr, tgt_ptr, page_size)) {
+	if (!is_multiple_vma_range_ok(maps_fp, pattern_addr, tgt_ptr,
+				      page_size, true)) {
 		success = false;
 		goto out_unmap;
 	}
@@ -547,7 +595,8 @@ static void mremap_shrink_multiple_vmas(unsigned long page_size,
 	ksft_test_result(success, "%s%s\n", test_name, inplace ? " [inplace]" : "");
 }
 
-static void mremap_move_multiple_vmas_split(char *pattern_addr,
+static void mremap_move_multiple_vmas_split(FILE *maps_fp,
+					    char *pattern_addr,
 					    unsigned long page_size,
 					    bool dont_unmap)
 {
@@ -623,8 +672,15 @@ static void mremap_move_multiple_vmas_split(char *pattern_addr,
 
 	/* Check pattern. */
 	for (i = 0; i < 7; i++) {
-		if (i == 3)
+		if (i == 3) {
+			if (is_ptr_mapped(maps_fp, tgt_ptr + i * page_size,
+					  page_size)) {
+				ksft_print_msg("Page %d is unexpectedly mapped\n", i);
+				success = false;
+				goto out_unmap;
+			}
 			continue;
+		}
 
 		if (memcmp(tgt_ptr + i * page_size,
 			   pattern_addr + (i + 2) * page_size, page_size)) {
@@ -840,10 +896,19 @@ static void mremap_move_multi_invalid_vmas(FILE *maps_fp,
 		goto out_unmap;
 	}
 
-	for (i = 0; i < 10; i += 2) {
+	for (i = 0; i < 10; i++) {
 		bool is_mapped = is_ptr_mapped(maps_fp,
 				&tgt_ptr[i * page_size], page_size);
 
+		if (i & 1) {
+			if (is_mapped) {
+				ksft_print_msg("Gap unexpectedly mapped at %d\n", i);
+				success = false;
+				goto out_unmap;
+			}
+			continue;
+		}
+
 		if (i < 8 && !is_mapped) {
 			ksft_print_msg("Valid VMA not moved at %d\n", i);
 			success = false;
@@ -1206,10 +1271,10 @@ int main(void)
 	mremap_move_1mb_from_start(pattern_addr);
 	mremap_shrink_multiple_vmas(page_size, /* inplace= */true);
 	mremap_shrink_multiple_vmas(page_size, /* inplace= */false);
-	mremap_move_multiple_vmas(pattern_addr, page_size, /* dontunmap= */ false);
-	mremap_move_multiple_vmas(pattern_addr, page_size, /* dontunmap= */ true);
-	mremap_move_multiple_vmas_split(pattern_addr, page_size, /* dontunmap= */ false);
-	mremap_move_multiple_vmas_split(pattern_addr, page_size, /* dontunmap= */ true);
+	mremap_move_multiple_vmas(maps_fp, pattern_addr, page_size, /* dontunmap= */ false);
+	mremap_move_multiple_vmas(maps_fp, pattern_addr, page_size, /* dontunmap= */ true);
+	mremap_move_multiple_vmas_split(maps_fp, pattern_addr, page_size, /* dontunmap= */ false);
+	mremap_move_multiple_vmas_split(maps_fp, pattern_addr, page_size, /* dontunmap= */ true);
 	mremap_move_multi_invalid_vmas(maps_fp, page_size);
 
 	fclose(maps_fp);
-- 
2.53.0


^ permalink raw reply	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2026-10-06  9:26 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-10-06  9:24 [PATCH v2 00/12] selftests/mm: improve mremap_test Sarthak Sharma
2026-10-06  9:25 ` [PATCH v2 01/12] selftests/mm: mremap_test: remove command line options Sarthak Sharma
2026-10-06  9:25 ` [PATCH v2 02/12] selftests/mm: mremap_test: drop munmap() checks from cleanup paths Sarthak Sharma
2026-10-06  9:25 ` [PATCH v2 03/12] selftests/mm: mremap_test: simplify errno handling Sarthak Sharma
2026-10-06  9:25 ` [PATCH v2 04/12] selftests/mm: mremap_test: use kselftest helpers Sarthak Sharma
2026-10-06  9:25 ` [PATCH v2 05/12] selftests/mm: mremap_test: skip test when userfaultfd is unavailable Sarthak Sharma
2026-10-06  9:25 ` [PATCH v2 06/12] selftests/mm: mremap_test: fail unexpected mremap successes Sarthak Sharma
2026-10-06  9:25 ` [PATCH v2 07/12] selftests/mm: mremap_test: fail on data corruption Sarthak Sharma
2026-10-06  9:25 ` [PATCH v2 08/12] selftests/mm: mremap_test: handle cleanup after mmap failures Sarthak Sharma
2026-10-06  9:25 ` [PATCH v2 09/12] selftests/mm: mremap_test: remove perf tests and timing Sarthak Sharma
2026-10-06  9:25 ` [PATCH v2 10/12] selftests/mm: mremap_test: replace validation threshold with sampled checks Sarthak Sharma
2026-10-06  9:25 ` [PATCH v2 11/12] selftests/mm: mremap_test: replace random data with deterministic pattern Sarthak Sharma
2026-10-06  9:25 ` [PATCH v2 12/12] selftests/mm: mremap_test: strengthen multi VMA validation Sarthak Sharma

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®