Skip to content

Commit 7d6597d

Browse files
lorenzo-stoakesakpm00
authored andcommitted
tools/testing/selftests: explicitly test split multi VMA mremap move
Check that moving a range of VMAs where we are offset into the first and last VMAs works correctly. This results in the VMAs being split at these points at which we are offset into VMAs. We explicitly test both the ordinary MREMAP_FIXED multi VMA move case and the MREMAP_DONTUNMAP multi VMA move case. Link: https://lkml.kernel.org/r/b04920bb6c09dc86c207c251eab8ec670fbbcaef.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 7062387 commit 7d6597d

File tree

1 file changed

+126
-1
lines changed

1 file changed

+126
-1
lines changed

tools/testing/selftests/mm/mremap_test.c

Lines changed: 126 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -610,6 +610,129 @@ static void mremap_shrink_multiple_vmas(unsigned long page_size,
610610
inplace ? " [inplace]" : "");
611611
}
612612

613+
static void mremap_move_multiple_vmas_split(unsigned int pattern_seed,
614+
unsigned long page_size,
615+
bool dont_unmap)
616+
{
617+
char *test_name = "mremap move multiple vmas split";
618+
int mremap_flags = MREMAP_FIXED | MREMAP_MAYMOVE;
619+
const size_t size = 10 * page_size;
620+
bool success = true;
621+
char *ptr, *tgt_ptr;
622+
int i;
623+
624+
if (dont_unmap)
625+
mremap_flags |= MREMAP_DONTUNMAP;
626+
627+
ptr = mmap(NULL, size, PROT_READ | PROT_WRITE,
628+
MAP_PRIVATE | MAP_ANON, -1, 0);
629+
if (ptr == MAP_FAILED) {
630+
perror("mmap");
631+
success = false;
632+
goto out;
633+
}
634+
635+
tgt_ptr = mmap(NULL, size, PROT_READ | PROT_WRITE,
636+
MAP_PRIVATE | MAP_ANON, -1, 0);
637+
if (tgt_ptr == MAP_FAILED) {
638+
perror("mmap");
639+
success = false;
640+
goto out;
641+
}
642+
if (munmap(tgt_ptr, size)) {
643+
perror("munmap");
644+
success = false;
645+
goto out_unmap;
646+
}
647+
648+
/*
649+
* Unmap so we end up with:
650+
*
651+
* 0 1 2 3 4 5 6 7 8 9 10 offset in buffer
652+
* |**********| |*******|
653+
* |**********| |*******|
654+
* 0 1 2 3 4 5 6 7 8 9 pattern offset
655+
*/
656+
if (munmap(&ptr[5 * page_size], page_size)) {
657+
perror("munmap");
658+
success = false;
659+
goto out_unmap;
660+
}
661+
662+
/* Set up random patterns. */
663+
srand(pattern_seed);
664+
for (i = 0; i < 10; i++) {
665+
int j;
666+
char *buf = &ptr[i * page_size];
667+
668+
if (i == 5)
669+
continue;
670+
671+
for (j = 0; j < page_size; j++)
672+
buf[j] = rand();
673+
}
674+
675+
/*
676+
* Move the below:
677+
*
678+
* <------------->
679+
* 0 1 2 3 4 5 6 7 8 9 10 offset in buffer
680+
* |**********| |*******|
681+
* |**********| |*******|
682+
* 0 1 2 3 4 5 6 7 8 9 pattern offset
683+
*
684+
* Into:
685+
*
686+
* 0 1 2 3 4 5 6 7 offset in buffer
687+
* |*****| |*****|
688+
* |*****| |*****|
689+
* 2 3 4 5 6 7 pattern offset
690+
*/
691+
if (mremap(&ptr[2 * page_size], size - 3 * page_size, size - 3 * page_size,
692+
mremap_flags, tgt_ptr) == MAP_FAILED) {
693+
perror("mremap");
694+
success = false;
695+
goto out_unmap;
696+
}
697+
698+
/* Offset into random pattern. */
699+
srand(pattern_seed);
700+
for (i = 0; i < 2 * page_size; i++)
701+
rand();
702+
703+
/* Check pattern. */
704+
for (i = 0; i < 7; i++) {
705+
int j;
706+
char *buf = &tgt_ptr[i * page_size];
707+
708+
if (i == 3)
709+
continue;
710+
711+
for (j = 0; j < page_size; j++) {
712+
char chr = rand();
713+
714+
if (chr != buf[j]) {
715+
ksft_print_msg("page %d offset %d corrupted, expected %d got %d\n",
716+
i, j, chr, buf[j]);
717+
goto out_unmap;
718+
}
719+
}
720+
}
721+
722+
out_unmap:
723+
if (munmap(tgt_ptr, size))
724+
perror("munmap tgt");
725+
if (munmap(ptr, size))
726+
perror("munmap src");
727+
out:
728+
if (success)
729+
ksft_test_result_pass("%s%s\n", test_name,
730+
dont_unmap ? " [dontunnmap]" : "");
731+
else
732+
ksft_test_result_fail("%s%s\n", test_name,
733+
dont_unmap ? " [dontunnmap]" : "");
734+
}
735+
613736
/* Returns the time taken for the remap on success else returns -1. */
614737
static long long remap_region(struct config c, unsigned int threshold_mb,
615738
char *rand_addr)
@@ -951,7 +1074,7 @@ int main(int argc, char **argv)
9511074
char *rand_addr;
9521075
size_t rand_size;
9531076
int num_expand_tests = 2;
954-
int num_misc_tests = 6;
1077+
int num_misc_tests = 8;
9551078
struct test test_cases[MAX_TEST] = {};
9561079
struct test perf_test_cases[MAX_PERF_TEST];
9571080
int page_size;
@@ -1082,6 +1205,8 @@ int main(int argc, char **argv)
10821205
mremap_shrink_multiple_vmas(page_size, /* inplace= */false);
10831206
mremap_move_multiple_vmas(pattern_seed, page_size, /* dontunmap= */ false);
10841207
mremap_move_multiple_vmas(pattern_seed, page_size, /* dontunmap= */ true);
1208+
mremap_move_multiple_vmas_split(pattern_seed, page_size, /* dontunmap= */ false);
1209+
mremap_move_multiple_vmas_split(pattern_seed, page_size, /* dontunmap= */ true);
10851210

10861211
if (run_perf_tests) {
10871212
ksft_print_msg("\n%s\n",

0 commit comments

Comments
 (0)