mremap() with an old size of 0 duplicates a shared mapping, and mremap_test has no case for it. Duplicate a shared anonymous mapping, once from its start and once from the middle. Check that the source and the duplicate are mapped by one VMA each and that they show the same pages. Acked-by: Lorenzo Stoakes (ARM) Reviewed-by: Jose A. Perez de Azpillaga Signed-off-by: Josef Bacik --- tools/testing/selftests/mm/mremap_test.c | 51 +++++++++++++++++++++++++++++++- 1 file changed, 50 insertions(+), 1 deletion(-) diff --git a/tools/testing/selftests/mm/mremap_test.c b/tools/testing/selftests/mm/mremap_test.c index 31b484517bda..df030409488b 100644 --- a/tools/testing/selftests/mm/mremap_test.c +++ b/tools/testing/selftests/mm/mremap_test.c @@ -603,6 +603,53 @@ static void mremap_shrink_multiple_vmas(unsigned long page_size, inplace ? " [inplace]" : ""); } +/* + * An old size of 0 duplicates a shared mapping: the pages show up at a second + * address, and the mapping they were taken from stays as it is. + */ +static void mremap_duplicate_shared(FILE *maps_fp, unsigned long page_size, + unsigned long offset) +{ + char *test_name = "mremap duplicate shared mapping"; + const size_t size = 3 * page_size; + const size_t dup_size = size - offset; + char *dup = MAP_FAILED; + bool success = false; + char *ptr; + + ptr = mmap(NULL, size, PROT_READ | PROT_WRITE, + MAP_SHARED | MAP_ANON, -1, 0); + if (ptr == MAP_FAILED) { + ksft_perror("mmap"); + goto out; + } + memset(ptr, 'a', size); + + dup = mremap(ptr + offset, 0, dup_size, MREMAP_MAYMOVE); + if (dup == MAP_FAILED) { + ksft_perror("mremap"); + goto out_unmap; + } + + /* Both are mapped, each by a single VMA. */ + if (!is_ptr_mapped(maps_fp, ptr, size) || + !is_ptr_mapped(maps_fp, dup, dup_size)) + goto out_unmap; + + /* They show the same pages. */ + ptr[offset] = 'b'; + dup[dup_size - 1] = 'c'; + success = dup[0] == 'b' && ptr[size - 1] == 'c' && ptr[0] != 'c'; + +out_unmap: + if (dup != MAP_FAILED) + munmap(dup, dup_size); + munmap(ptr, size); +out: + ksft_test_result(success, "%s%s\n", test_name, + offset ? " [from the middle]" : ""); +} + static void mremap_move_multiple_vmas_split(unsigned int pattern_seed, unsigned long page_size, bool dont_unmap) @@ -1248,7 +1295,7 @@ int main(int argc, char **argv) char *rand_addr; size_t rand_size; int num_expand_tests = 2; - int num_misc_tests = 9; + int num_misc_tests = 11; struct test test_cases[MAX_TEST] = {}; struct test perf_test_cases[MAX_PERF_TEST]; int page_size; @@ -1385,6 +1432,8 @@ int main(int argc, char **argv) mremap_move_multiple_vmas_split(pattern_seed, page_size, /* dontunmap= */ false); mremap_move_multiple_vmas_split(pattern_seed, page_size, /* dontunmap= */ true); mremap_move_multi_invalid_vmas(maps_fp, page_size); + mremap_duplicate_shared(maps_fp, page_size, 0); + mremap_duplicate_shared(maps_fp, page_size, page_size); fclose(maps_fp); -- 2.55.0