Commit 85931004 authored by Brian Geffon's avatar Brian Geffon Committed by Linus Torvalds
Browse files

selftests: add a MREMAP_DONTUNMAP selftest for shmem

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

Link: https://lkml.kernel.org/r/20210323182520.2712101-3-bgeffon@google.com


Signed-off-by: default avatarBrian Geffon <bgeffon@google.com>
Cc: Axel Rasmussen <axelrasmussen@google.com>
Cc: Lokesh Gidra <lokeshgidra@google.com>
Cc: Mike Rapoport <rppt@linux.vnet.ibm.com>
Cc: Peter Xu <peterx@redhat.com>
Cc: Hugh Dickins <hughd@google.com>
Cc: "Michael S . Tsirkin" <mst@redhat.com>
Cc: Brian Geffon <bgeffon@google.com>
Cc: Andy Lutomirski <luto@amacapital.net>
Cc: Vlastimil Babka <vbabka@suse.cz>
Cc: Andrea Arcangeli <aarcange@redhat.com>
Cc: Sonny Rao <sonnyrao@google.com>
Cc: Minchan Kim <minchan@kernel.org>
Cc: "Kirill A . Shutemov" <kirill@shutemov.name>
Cc: Dmitry Safonov <dima@arista.com>
Cc: Michael Kerrisk <mtk.manpages@gmail.com>
Cc: Alejandro Colomar <alx.manpages@gmail.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 14d07113
Loading
Loading
Loading
Loading
+52 −0
Original line number Diff line number Diff line
@@ -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();