Skip to content

Commit 10aed7d

Browse files
lorenzo-stoakesakpm00
authored andcommitted
tools/testing/selftests: add mremap() shrink test for multiple VMAs
Patch series "tools/testing: expand mremap testing". Expand our mremap() testing to further assert that behaviour is as expected. There is a poorly documented mremap() feature whereby it is possible to mremap() multiple VMAs (even with gaps) when shrinking, as long as the resultant shrunk range spans only a single VMA. So we start by asserting this behaviour functions correctly both with an in-place shrink and a shrink/move. Next, we further test the newly introduced ability to mremap() multiple VMAs when performing a MAP_FIXED move (that is without the size being changed), firstly by asserting that MREMAP_DONTUNMAP has no bearing on this behaviour. Finally, we explicitly test that such moves, when splitting source VMAs, function correctly. This patch (of 3): There is an apparently little-known feature of mremap() whereby, in stark contrast to other modes (other than the recently introduced capacity to move multiple VMAs), the input source range span multiple VMAs with gaps between. This is, when shrinking a VMA, whether moving it or not, and the shrink would reduce the range to a single VMA - this is permitted, as the shrink is actioned by an unmap. This patch adds tests to assert that this behaves as expected. Link: https://lkml.kernel.org/r/cover.1753119043.git.lorenzo.stoakes@oracle.com Link: https://lkml.kernel.org/r/f08122893a26092a2bec6e69443e87f468ffdbed.1753119043.git.lorenzo.stoakes@oracle.com Signed-off-by: Lorenzo Stoakes <lorenzo.stoakes@oracle.com> Cc: Jann Horn <jannh@google.com> Cc: Liam Howlett <liam.howlett@oracle.com> Cc: Vlastimil Babka <vbabka@suse.cz> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
1 parent 6f1cc9f commit 10aed7d

File tree

1 file changed

+82
-1
lines changed

1 file changed

+82
-1
lines changed

tools/testing/selftests/mm/mremap_test.c

Lines changed: 82 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -523,6 +523,85 @@ static void mremap_move_multiple_vmas(unsigned int pattern_seed,
523523
ksft_test_result_fail("%s\n", test_name);
524524
}
525525

526+
static void mremap_shrink_multiple_vmas(unsigned long page_size,
527+
bool inplace)
528+
{
529+
char *test_name = "mremap shrink multiple vmas";
530+
const size_t size = 10 * page_size;
531+
bool success = true;
532+
char *ptr, *tgt_ptr;
533+
void *res;
534+
int i;
535+
536+
ptr = mmap(NULL, size, PROT_READ | PROT_WRITE,
537+
MAP_PRIVATE | MAP_ANON, -1, 0);
538+
if (ptr == MAP_FAILED) {
539+
perror("mmap");
540+
success = false;
541+
goto out;
542+
}
543+
544+
tgt_ptr = mmap(NULL, size, PROT_READ | PROT_WRITE,
545+
MAP_PRIVATE | MAP_ANON, -1, 0);
546+
if (tgt_ptr == MAP_FAILED) {
547+
perror("mmap");
548+
success = false;
549+
goto out;
550+
}
551+
if (munmap(tgt_ptr, size)) {
552+
perror("munmap");
553+
success = false;
554+
goto out_unmap;
555+
}
556+
557+
/*
558+
* Unmap so we end up with:
559+
*
560+
* 0 2 4 6 8 10 offset in buffer
561+
* |*| |*| |*| |*| |*| |*|
562+
* |*| |*| |*| |*| |*| |*|
563+
*/
564+
for (i = 1; i < 10; i += 2) {
565+
if (munmap(&ptr[i * page_size], page_size)) {
566+
perror("munmap");
567+
success = false;
568+
goto out_unmap;
569+
}
570+
}
571+
572+
/*
573+
* Shrink in-place across multiple VMAs and gaps so we end up with:
574+
*
575+
* 0
576+
* |*|
577+
* |*|
578+
*/
579+
if (inplace)
580+
res = mremap(ptr, size, page_size, 0);
581+
else
582+
res = mremap(ptr, size, page_size, MREMAP_MAYMOVE | MREMAP_FIXED,
583+
tgt_ptr);
584+
585+
if (res == MAP_FAILED) {
586+
perror("mremap");
587+
success = false;
588+
goto out_unmap;
589+
}
590+
591+
out_unmap:
592+
if (munmap(tgt_ptr, size))
593+
perror("munmap tgt");
594+
if (munmap(ptr, size))
595+
perror("munmap src");
596+
out:
597+
if (success)
598+
ksft_test_result_pass("%s%s\n", test_name,
599+
inplace ? " [inplace]" : "");
600+
else
601+
ksft_test_result_fail("%s%s\n", test_name,
602+
inplace ? " [inplace]" : "");
603+
}
604+
526605
/* Returns the time taken for the remap on success else returns -1. */
527606
static long long remap_region(struct config c, unsigned int threshold_mb,
528607
char *rand_addr)
@@ -864,7 +943,7 @@ int main(int argc, char **argv)
864943
char *rand_addr;
865944
size_t rand_size;
866945
int num_expand_tests = 2;
867-
int num_misc_tests = 3;
946+
int num_misc_tests = 5;
868947
struct test test_cases[MAX_TEST] = {};
869948
struct test perf_test_cases[MAX_PERF_TEST];
870949
int page_size;
@@ -992,6 +1071,8 @@ int main(int argc, char **argv)
9921071
mremap_move_within_range(pattern_seed, rand_addr);
9931072
mremap_move_1mb_from_start(pattern_seed, rand_addr);
9941073
mremap_move_multiple_vmas(pattern_seed, page_size);
1074+
mremap_shrink_multiple_vmas(page_size, /* inplace= */true);
1075+
mremap_shrink_multiple_vmas(page_size, /* inplace= */false);
9951076

9961077
if (run_perf_tests) {
9971078
ksft_print_msg("\n%s\n",

0 commit comments

Comments
 (0)