diff options
Diffstat (limited to 'tools/testing/selftests/vm/mremap_dontunmap.c')
-rw-r--r-- | tools/testing/selftests/vm/mremap_dontunmap.c | 312 |
1 files changed, 0 insertions, 312 deletions
diff --git a/tools/testing/selftests/vm/mremap_dontunmap.c b/tools/testing/selftests/vm/mremap_dontunmap.c deleted file mode 100644 index 3a7b5ef0b0c6..000000000000 --- a/tools/testing/selftests/vm/mremap_dontunmap.c +++ /dev/null @@ -1,312 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 - -/* - * Tests for mremap w/ MREMAP_DONTUNMAP. - * - * Copyright 2020, Brian Geffon <bgeffon@google.com> - */ -#define _GNU_SOURCE -#include <sys/mman.h> -#include <errno.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> - -#include "../kselftest.h" - -#ifndef MREMAP_DONTUNMAP -#define MREMAP_DONTUNMAP 4 -#endif - -unsigned long page_size; -char *page_buffer; - -static void dump_maps(void) -{ - char cmd[32]; - - snprintf(cmd, sizeof(cmd), "cat /proc/%d/maps", getpid()); - system(cmd); -} - -#define BUG_ON(condition, description) \ - do { \ - if (condition) { \ - fprintf(stderr, "[FAIL]\t%s():%d\t%s:%s\n", __func__, \ - __LINE__, (description), strerror(errno)); \ - dump_maps(); \ - exit(1); \ - } \ - } while (0) - -// Try a simple operation for to "test" for kernel support this prevents -// reporting tests as failed when it's run on an older kernel. -static int kernel_support_for_mremap_dontunmap() -{ - int ret = 0; - unsigned long num_pages = 1; - void *source_mapping = mmap(NULL, num_pages * page_size, PROT_NONE, - MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); - BUG_ON(source_mapping == MAP_FAILED, "mmap"); - - // This simple remap should only fail if MREMAP_DONTUNMAP isn't - // supported. - void *dest_mapping = - mremap(source_mapping, num_pages * page_size, num_pages * page_size, - MREMAP_DONTUNMAP | MREMAP_MAYMOVE, 0); - if (dest_mapping == MAP_FAILED) { - ret = errno; - } else { - 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"); - return ret; -} - -// This helper will just validate that an entire mapping contains the expected -// byte. -static int check_region_contains_byte(void *addr, unsigned long size, char byte) -{ - BUG_ON(size & (page_size - 1), - "check_region_contains_byte expects page multiples"); - BUG_ON((unsigned long)addr & (page_size - 1), - "check_region_contains_byte expects page alignment"); - - memset(page_buffer, byte, page_size); - - unsigned long num_pages = size / page_size; - unsigned long i; - - // Compare each page checking that it contains our expected byte. - for (i = 0; i < num_pages; ++i) { - int ret = - memcmp(addr + (i * page_size), page_buffer, page_size); - if (ret) { - return ret; - } - } - - return 0; -} - -// this test validates that MREMAP_DONTUNMAP moves the pagetables while leaving -// the source mapping mapped. -static void mremap_dontunmap_simple() -{ - unsigned long num_pages = 5; - - void *source_mapping = - mmap(NULL, num_pages * page_size, PROT_READ | PROT_WRITE, - MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); - BUG_ON(source_mapping == MAP_FAILED, "mmap"); - - 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); - 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"); - BUG_ON(check_region_contains_byte - (source_mapping, num_pages * page_size, 0) != 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. -static void mremap_dontunmap_simple_fixed() -{ - unsigned long num_pages = 5; - - // Since we want to guarantee that we can remap to a point, we will - // create a mapping up front. - void *dest_mapping = - mmap(NULL, num_pages * page_size, PROT_READ | PROT_WRITE, - MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); - BUG_ON(dest_mapping == MAP_FAILED, "mmap"); - memset(dest_mapping, 'X', num_pages * page_size); - - void *source_mapping = - mmap(NULL, num_pages * page_size, PROT_READ | PROT_WRITE, - MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); - BUG_ON(source_mapping == MAP_FAILED, "mmap"); - memset(source_mapping, 'a', num_pages * page_size); - - void *remapped_mapping = - mremap(source_mapping, num_pages * page_size, num_pages * page_size, - MREMAP_FIXED | MREMAP_DONTUNMAP | MREMAP_MAYMOVE, - dest_mapping); - BUG_ON(remapped_mapping == MAP_FAILED, "mremap"); - BUG_ON(remapped_mapping != dest_mapping, - "mremap should have placed the remapped mapping at dest_mapping"); - - // The dest mapping will have been unmap by mremap so we expect the Xs - // to be gone and replaced with a's. - BUG_ON(check_region_contains_byte - (dest_mapping, num_pages * page_size, 'a') != 0, - "pages did not migrate"); - - // And the source mapping will have had its ptes dropped. - BUG_ON(check_region_contains_byte - (source_mapping, num_pages * page_size, 0) != 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 that we can MREMAP_DONTUNMAP for a portion of an -// existing mapping. -static void mremap_dontunmap_partial_mapping() -{ - /* - * source mapping: - * -------------- - * | aaaaaaaaaa | - * -------------- - * to become: - * -------------- - * | aaaaa00000 | - * -------------- - * With the destination mapping containing 5 pages of As. - * --------- - * | aaaaa | - * --------- - */ - unsigned long num_pages = 10; - void *source_mapping = - mmap(NULL, num_pages * page_size, PROT_READ | PROT_WRITE, - MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); - BUG_ON(source_mapping == MAP_FAILED, "mmap"); - memset(source_mapping, 'a', num_pages * page_size); - - // We will grab the last 5 pages of the source and move them. - void *dest_mapping = - mremap(source_mapping + (5 * page_size), 5 * page_size, - 5 * page_size, - MREMAP_DONTUNMAP | MREMAP_MAYMOVE, NULL); - BUG_ON(dest_mapping == MAP_FAILED, "mremap"); - - // We expect the first 5 pages of the source to contain a's and the - // final 5 pages to contain zeros. - BUG_ON(check_region_contains_byte(source_mapping, 5 * page_size, 'a') != - 0, "first 5 pages of source should have original pages"); - BUG_ON(check_region_contains_byte - (source_mapping + (5 * page_size), 5 * page_size, 0) != 0, - "final 5 pages of source should have no ptes"); - - // Finally we expect the destination to have 5 pages worth of a's. - BUG_ON(check_region_contains_byte(dest_mapping, 5 * page_size, 'a') != - 0, "dest mapping should contain ptes from the source"); - - BUG_ON(munmap(dest_mapping, 5 * 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 that we can remap over only a portion of a mapping. -static void mremap_dontunmap_partial_mapping_overwrite(void) -{ - /* - * source mapping: - * --------- - * |aaaaa| - * --------- - * dest mapping initially: - * ----------- - * |XXXXXXXXXX| - * ------------ - * Source to become: - * --------- - * |00000| - * --------- - * With the destination mapping containing 5 pages of As. - * ------------ - * |aaaaaXXXXX| - * ------------ - */ - void *source_mapping = - mmap(NULL, 5 * page_size, PROT_READ | PROT_WRITE, - MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); - BUG_ON(source_mapping == MAP_FAILED, "mmap"); - memset(source_mapping, 'a', 5 * page_size); - - void *dest_mapping = - mmap(NULL, 10 * page_size, PROT_READ | PROT_WRITE, - MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); - BUG_ON(dest_mapping == MAP_FAILED, "mmap"); - memset(dest_mapping, 'X', 10 * page_size); - - // We will grab the last 5 pages of the source and move them. - void *remapped_mapping = - mremap(source_mapping, 5 * page_size, - 5 * page_size, - MREMAP_DONTUNMAP | MREMAP_MAYMOVE | MREMAP_FIXED, dest_mapping); - BUG_ON(dest_mapping == MAP_FAILED, "mremap"); - BUG_ON(dest_mapping != remapped_mapping, "expected to remap to dest_mapping"); - - BUG_ON(check_region_contains_byte(source_mapping, 5 * page_size, 0) != - 0, "first 5 pages of source should have no ptes"); - - // Finally we expect the destination to have 5 pages worth of a's. - BUG_ON(check_region_contains_byte(dest_mapping, 5 * page_size, 'a') != 0, - "dest mapping should contain ptes from the source"); - - // Finally the last 5 pages shouldn't have been touched. - BUG_ON(check_region_contains_byte(dest_mapping + (5 * page_size), - 5 * page_size, 'X') != 0, - "dest mapping should have retained the last 5 pages"); - - BUG_ON(munmap(dest_mapping, 10 * page_size) == -1, - "unable to unmap destination mapping"); - BUG_ON(munmap(source_mapping, 5 * page_size) == -1, - "unable to unmap source mapping"); -} - -int main(void) -{ - page_size = sysconf(_SC_PAGE_SIZE); - - // test for kernel support for MREMAP_DONTUNMAP skipping the test if - // not. - if (kernel_support_for_mremap_dontunmap() != 0) { - printf("No kernel support for MREMAP_DONTUNMAP\n"); - return KSFT_SKIP; - } - - // Keep a page sized buffer around for when we need it. - page_buffer = - mmap(NULL, page_size, PROT_READ | PROT_WRITE, - MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); - BUG_ON(page_buffer == MAP_FAILED, "unable to mmap a page."); - - mremap_dontunmap_simple(); - mremap_dontunmap_simple_fixed(); - mremap_dontunmap_partial_mapping(); - mremap_dontunmap_partial_mapping_overwrite(); - - BUG_ON(munmap(page_buffer, page_size) == -1, - "unable to unmap page buffer"); - - printf("OK\n"); - return 0; -} |