This test extends the current mremap tests to validate that
the MREMAP_DONTUNMAP operation can be performed on shmem mappings.

Signed-off-by: Brian Geffon <bgef...@google.com>
---
 tools/testing/selftests/vm/mremap_dontunmap.c | 52 +++++++++++++++++++
 1 file changed, 52 insertions(+)

diff --git a/tools/testing/selftests/vm/mremap_dontunmap.c 
b/tools/testing/selftests/vm/mremap_dontunmap.c
index 3a7b5ef0b0c6..f01dc4a85b0b 100644
--- a/tools/testing/selftests/vm/mremap_dontunmap.c
+++ b/tools/testing/selftests/vm/mremap_dontunmap.c
@@ -127,6 +127,57 @@ static void mremap_dontunmap_simple()
               "unable to unmap source mapping");
 }
 
+// This test validates that MREMAP_DONTUNMAP on a shared mapping works as 
expected.
+static void mremap_dontunmap_simple_shmem()
+{
+       unsigned long num_pages = 5;
+
+       int mem_fd = memfd_create("memfd", MFD_CLOEXEC);
+       BUG_ON(mem_fd < 0, "memfd_create");
+
+       BUG_ON(ftruncate(mem_fd, num_pages * page_size) < 0,
+                       "ftruncate");
+
+       void *source_mapping =
+           mmap(NULL, num_pages * page_size, PROT_READ | PROT_WRITE,
+                MAP_FILE | MAP_SHARED, mem_fd, 0);
+       BUG_ON(source_mapping == MAP_FAILED, "mmap");
+
+       BUG_ON(close(mem_fd) < 0, "close");
+
+       memset(source_mapping, 'a', num_pages * page_size);
+
+       // Try to just move the whole mapping anywhere (not fixed).
+       void *dest_mapping =
+           mremap(source_mapping, num_pages * page_size, num_pages * page_size,
+                  MREMAP_DONTUNMAP | MREMAP_MAYMOVE, NULL);
+       if (dest_mapping == MAP_FAILED && errno == EINVAL) {
+               // Old kernel which doesn't support MREMAP_DONTUNMAP on shmem.
+               BUG_ON(munmap(source_mapping, num_pages * page_size) == -1,
+                       "unable to unmap source mapping");
+               return;
+       }
+
+       BUG_ON(dest_mapping == MAP_FAILED, "mremap");
+
+       // Validate that the pages have been moved, we know they were moved if
+       // the dest_mapping contains a's.
+       BUG_ON(check_region_contains_byte
+              (dest_mapping, num_pages * page_size, 'a') != 0,
+              "pages did not migrate");
+
+       // Because the region is backed by shmem, we will actually see the same
+       // memory at the source location still.
+       BUG_ON(check_region_contains_byte
+              (source_mapping, num_pages * page_size, 'a') != 0,
+              "source should have no ptes");
+
+       BUG_ON(munmap(dest_mapping, num_pages * page_size) == -1,
+              "unable to unmap destination mapping");
+       BUG_ON(munmap(source_mapping, num_pages * page_size) == -1,
+              "unable to unmap source mapping");
+}
+
 // This test validates MREMAP_DONTUNMAP will move page tables to a specific
 // destination using MREMAP_FIXED, also while validating that the source
 // remains intact.
@@ -300,6 +351,7 @@ int main(void)
        BUG_ON(page_buffer == MAP_FAILED, "unable to mmap a page.");
 
        mremap_dontunmap_simple();
+       mremap_dontunmap_simple_shmem();
        mremap_dontunmap_simple_fixed();
        mremap_dontunmap_partial_mapping();
        mremap_dontunmap_partial_mapping_overwrite();
-- 
2.31.0.291.g576ba9dcdaf-goog

Reply via email to