aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/tools/testing/selftests/mm/map_fixed_noreplace.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/testing/selftests/mm/map_fixed_noreplace.c')
-rw-r--r--tools/testing/selftests/mm/map_fixed_noreplace.c193
1 files changed, 193 insertions, 0 deletions
diff --git a/tools/testing/selftests/mm/map_fixed_noreplace.c b/tools/testing/selftests/mm/map_fixed_noreplace.c
new file mode 100644
index 000000000000..b74813fdc951
--- /dev/null
+++ b/tools/testing/selftests/mm/map_fixed_noreplace.c
@@ -0,0 +1,193 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/*
+ * Test that MAP_FIXED_NOREPLACE works.
+ *
+ * Copyright 2018, Jann Horn <jannh@google.com>
+ * Copyright 2018, Michael Ellerman, IBM Corporation.
+ */
+
+#include <sys/mman.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include "../kselftest.h"
+
+static void dump_maps(void)
+{
+ char cmd[32];
+
+ snprintf(cmd, sizeof(cmd), "cat /proc/%d/maps", getpid());
+ system(cmd);
+}
+
+static unsigned long find_base_addr(unsigned long size)
+{
+ void *addr;
+ unsigned long flags;
+
+ flags = MAP_PRIVATE | MAP_ANONYMOUS;
+ addr = mmap(NULL, size, PROT_NONE, flags, -1, 0);
+ if (addr == MAP_FAILED)
+ ksft_exit_fail_msg("Error: couldn't map the space we need for the test\n");
+
+ if (munmap(addr, size) != 0)
+ ksft_exit_fail_msg("Error: munmap failed\n");
+
+ return (unsigned long)addr;
+}
+
+int main(void)
+{
+ unsigned long base_addr;
+ unsigned long flags, addr, size, page_size;
+ char *p;
+
+ ksft_print_header();
+ ksft_set_plan(9);
+
+ page_size = sysconf(_SC_PAGE_SIZE);
+
+ /* let's find a base addr that is free before we start the tests */
+ size = 5 * page_size;
+ base_addr = find_base_addr(size);
+
+ flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED_NOREPLACE;
+
+ /* Check we can map all the areas we need below */
+ addr = base_addr;
+ size = 5 * page_size;
+ p = mmap((void *)addr, size, PROT_NONE, flags, -1, 0);
+ if (p == MAP_FAILED) {
+ dump_maps();
+ ksft_exit_fail_msg("Error: couldn't map the space we need for the test\n");
+ }
+ if (munmap((void *)addr, 5 * page_size) != 0) {
+ dump_maps();
+ ksft_exit_fail_msg("Error: munmap failed!?\n");
+ }
+ ksft_test_result_pass("mmap() @ 0x%lx-0x%lx p=%p result=%m\n", addr, addr + size, p);
+
+ addr = base_addr + page_size;
+ size = 3 * page_size;
+ p = mmap((void *)addr, size, PROT_NONE, flags, -1, 0);
+ if (p == MAP_FAILED) {
+ dump_maps();
+ ksft_exit_fail_msg("Error: first mmap() failed unexpectedly\n");
+ }
+ ksft_test_result_pass("mmap() @ 0x%lx-0x%lx p=%p result=%m\n", addr, addr + size, p);
+
+ /*
+ * Exact same mapping again:
+ * base | free | new
+ * +1 | mapped | new
+ * +2 | mapped | new
+ * +3 | mapped | new
+ * +4 | free | new
+ */
+ addr = base_addr;
+ size = 5 * page_size;
+ p = mmap((void *)addr, size, PROT_NONE, flags, -1, 0);
+ if (p != MAP_FAILED) {
+ dump_maps();
+ ksft_exit_fail_msg("Error:1: mmap() succeeded when it shouldn't have\n");
+ }
+ ksft_test_result_pass("mmap() @ 0x%lx-0x%lx p=%p result=%m\n", addr, addr + size, p);
+
+ /*
+ * Second mapping contained within first:
+ *
+ * base | free |
+ * +1 | mapped |
+ * +2 | mapped | new
+ * +3 | mapped |
+ * +4 | free |
+ */
+ addr = base_addr + (2 * page_size);
+ size = page_size;
+ p = mmap((void *)addr, size, PROT_NONE, flags, -1, 0);
+ if (p != MAP_FAILED) {
+ dump_maps();
+ ksft_exit_fail_msg("Error:2: mmap() succeeded when it shouldn't have\n");
+ }
+ ksft_test_result_pass("mmap() @ 0x%lx-0x%lx p=%p result=%m\n", addr, addr + size, p);
+
+ /*
+ * Overlap end of existing mapping:
+ * base | free |
+ * +1 | mapped |
+ * +2 | mapped |
+ * +3 | mapped | new
+ * +4 | free | new
+ */
+ addr = base_addr + (3 * page_size);
+ size = 2 * page_size;
+ p = mmap((void *)addr, size, PROT_NONE, flags, -1, 0);
+ if (p != MAP_FAILED) {
+ dump_maps();
+ ksft_exit_fail_msg("Error:3: mmap() succeeded when it shouldn't have\n");
+ }
+ ksft_test_result_pass("mmap() @ 0x%lx-0x%lx p=%p result=%m\n", addr, addr + size, p);
+
+ /*
+ * Overlap start of existing mapping:
+ * base | free | new
+ * +1 | mapped | new
+ * +2 | mapped |
+ * +3 | mapped |
+ * +4 | free |
+ */
+ addr = base_addr;
+ size = 2 * page_size;
+ p = mmap((void *)addr, size, PROT_NONE, flags, -1, 0);
+ if (p != MAP_FAILED) {
+ dump_maps();
+ ksft_exit_fail_msg("Error:4: mmap() succeeded when it shouldn't have\n");
+ }
+ ksft_test_result_pass("mmap() @ 0x%lx-0x%lx p=%p result=%m\n", addr, addr + size, p);
+
+ /*
+ * Adjacent to start of existing mapping:
+ * base | free | new
+ * +1 | mapped |
+ * +2 | mapped |
+ * +3 | mapped |
+ * +4 | free |
+ */
+ addr = base_addr;
+ size = page_size;
+ p = mmap((void *)addr, size, PROT_NONE, flags, -1, 0);
+ if (p == MAP_FAILED) {
+ dump_maps();
+ ksft_exit_fail_msg("Error:5: mmap() failed when it shouldn't have\n");
+ }
+ ksft_test_result_pass("mmap() @ 0x%lx-0x%lx p=%p result=%m\n", addr, addr + size, p);
+
+ /*
+ * Adjacent to end of existing mapping:
+ * base | free |
+ * +1 | mapped |
+ * +2 | mapped |
+ * +3 | mapped |
+ * +4 | free | new
+ */
+ addr = base_addr + (4 * page_size);
+ size = page_size;
+ p = mmap((void *)addr, size, PROT_NONE, flags, -1, 0);
+ if (p == MAP_FAILED) {
+ dump_maps();
+ ksft_exit_fail_msg("Error:6: mmap() failed when it shouldn't have\n");
+ }
+ ksft_test_result_pass("mmap() @ 0x%lx-0x%lx p=%p result=%m\n", addr, addr + size, p);
+
+ addr = base_addr;
+ size = 5 * page_size;
+ if (munmap((void *)addr, size) != 0) {
+ dump_maps();
+ ksft_exit_fail_msg("Error: munmap failed!?\n");
+ }
+ ksft_test_result_pass("Base Address unmap() successful\n");
+
+ ksft_finished();
+}