[PATCH] selftest/mm: Add test for checking mmap across 128TB boundary

From: Aneesh Kumar K.V
Date: Mon Nov 13 2017 - 00:11:10 EST


Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@xxxxxxxxxxxxxxxxxx>
---
tools/testing/selftests/vm/Makefile | 1 +
tools/testing/selftests/vm/run_vmtests | 11 ++
tools/testing/selftests/vm/va_128TBswitch.c | 170 ++++++++++++++++++++++++++++
3 files changed, 182 insertions(+)
create mode 100644 tools/testing/selftests/vm/va_128TBswitch.c

diff --git a/tools/testing/selftests/vm/Makefile b/tools/testing/selftests/vm/Makefile
index cbb29e41ef2b..b1fb3cd7cf52 100644
--- a/tools/testing/selftests/vm/Makefile
+++ b/tools/testing/selftests/vm/Makefile
@@ -17,6 +17,7 @@ TEST_GEN_FILES += transhuge-stress
TEST_GEN_FILES += userfaultfd
TEST_GEN_FILES += mlock-random-test
TEST_GEN_FILES += virtual_address_range
+TEST_GEN_FILES += va_128TBswitch

TEST_PROGS := run_vmtests

diff --git a/tools/testing/selftests/vm/run_vmtests b/tools/testing/selftests/vm/run_vmtests
index 07548a1fa901..b367f7801b67 100755
--- a/tools/testing/selftests/vm/run_vmtests
+++ b/tools/testing/selftests/vm/run_vmtests
@@ -176,4 +176,15 @@ else
echo "[PASS]"
fi

+echo "-----------------------------"
+echo "running virtual address 128TB switch test"
+echo "-----------------------------"
+./va_128TBswitch
+if [ $? -ne 0 ]; then
+ echo "[FAIL]"
+ exitcode=1
+else
+ echo "[PASS]"
+fi
+
exit $exitcode
diff --git a/tools/testing/selftests/vm/va_128TBswitch.c b/tools/testing/selftests/vm/va_128TBswitch.c
new file mode 100644
index 000000000000..dfa501b825a8
--- /dev/null
+++ b/tools/testing/selftests/vm/va_128TBswitch.c
@@ -0,0 +1,170 @@
+/*
+ * Copyright IBM Corporation, 2017
+ * Author Aneesh Kumar K.V <aneesh.kumar@xxxxxxxxxxxxxxxxxx>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2.1 of the GNU Lesser General Public License
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/mman.h>
+
+#ifdef DEBUG
+#define pr_debug(fmt, ...) printf(fmt, ##__VA_ARGS__)
+#else
+#define pr_debug(fmt, ...)
+#endif
+
+/*
+ * >= 128TB is the hint addr value we used to select
+ * large address space.
+ */
+#define ADDR_SWITCH_HINT (1UL << 47)
+
+#ifdef __powerpc64__
+#define MAP_SIZE 64*1024
+#else
+#define MAP_SIZE 4*1024
+#endif
+
+
+void report_failure(long in_addr, unsigned long flags)
+{
+ printf("Failed to map 0x%lx with flags 0x%lx\n", in_addr, flags);
+ exit(1);
+}
+
+int *__map_addr(long in_addr, int size, unsigned long flags, int unmap)
+{
+ int *addr;
+
+ addr = (int *)mmap((void *)in_addr, size, PROT_READ | PROT_WRITE,
+ MAP_ANONYMOUS | MAP_PRIVATE | flags, -1, 0);
+ if (addr == MAP_FAILED)
+ report_failure(in_addr, flags);
+ pr_debug("Mapped addr 0x%lx-0x%lx for request 0x%lx with flag 0x%lx\n",
+ (unsigned long)addr, ((unsigned long)addr + size), in_addr, flags);
+ /*
+ * Try to access to catch errors in fault handling/slb miss handling
+ */
+ *addr = 10;
+ if (unmap)
+ munmap(addr, size);
+ return addr;
+}
+
+int *map_addr(long in_addr, unsigned long flags, int unmap)
+{
+ return __map_addr(in_addr, MAP_SIZE, flags, unmap);
+}
+
+void boundary_check(void)
+{
+ int *a;
+
+ /*
+ * If stack is moved, we could possibly allocate
+ * this at the requested address.
+ */
+ a = map_addr((ADDR_SWITCH_HINT - MAP_SIZE), 0, 1);
+ if ((unsigned long)a > ADDR_SWITCH_HINT - MAP_SIZE)
+ report_failure(ADDR_SWITCH_HINT - MAP_SIZE, 0);
+
+ /*
+ * We should never allocate at the requested address or above it
+ * The len cross the 128TB boundary. Without MAP_FIXED
+ * we will always search in the lower address space.
+ */
+ a = __map_addr((ADDR_SWITCH_HINT - MAP_SIZE), 2*MAP_SIZE, 0, 1);
+ if ((unsigned long)a >= ADDR_SWITCH_HINT - MAP_SIZE)
+ report_failure(ADDR_SWITCH_HINT - MAP_SIZE, 0);
+ /*
+ * Exact mapping at 128TB, the area is free we should get that
+ * even without MAP_FIXED. Don't unmap. We check fixed in the
+ * same range later.
+ */
+ a = map_addr(ADDR_SWITCH_HINT, 0, 0);
+ if ((unsigned long)a != ADDR_SWITCH_HINT)
+ report_failure(ADDR_SWITCH_HINT, 0);
+
+ a = map_addr(ADDR_SWITCH_HINT + MAP_SIZE, 0, 1);
+ if ((unsigned long)a < ADDR_SWITCH_HINT)
+ report_failure(ADDR_SWITCH_HINT, 0);
+
+#if 0
+ /*
+ * Enable this with stack mapped MAP_SIZE below 128TB
+ */
+ a = map_addr((ADDR_SWITCH_HINT - MAP_SIZE), MAP_FIXED, 1);
+ if ((unsigned long)a != ADDR_SWITCH_HINT - MAP_SIZE)
+ report_failure(ADDR_SWITCH_HINT - MAP_SIZE, 0);
+ a = __map_addr((ADDR_SWITCH_HINT - MAP_SIZE), 2*MAP_SIZE, MAP_FIXED, 1);
+ if ((unsigned long)a != ADDR_SWITCH_HINT - MAP_SIZE)
+ report_failure(ADDR_SWITCH_HINT - MAP_SIZE, MAP_FIXED);
+
+#endif
+ a = map_addr(ADDR_SWITCH_HINT, MAP_FIXED, 1);
+ if ((unsigned long)a != ADDR_SWITCH_HINT)
+ report_failure(ADDR_SWITCH_HINT, MAP_FIXED);
+}
+
+static int supported_arch(void)
+{
+#if defined(__powerpc64__)
+ return 1;
+#elif defined(__x86_64__)
+ return 1;
+#else
+ return 0;
+#endif
+
+}
+
+int main(int argc, char *argv[])
+{
+ int *a;
+
+ if (!supported_arch())
+ return 0;
+ /*
+ * check the 128TB boundary before we update addr_limit
+ */
+ boundary_check();
+
+ a = map_addr(0, 0, 1);
+ if ((unsigned long)a > ADDR_SWITCH_HINT)
+ report_failure(0, 0);
+
+ a = map_addr(-1, 0, 1);
+ if ((unsigned long)a < ADDR_SWITCH_HINT)
+ report_failure(-1, 0);
+
+ /* don't unmap this one */
+ a = map_addr((1UL << 48), 0, 0);
+ if ((unsigned long)a != 1UL << 48)
+ report_failure((1UL << 48), 0);
+
+ a = map_addr((1UL << 48), 0, 1);
+ if ((unsigned long)a < ADDR_SWITCH_HINT)
+ report_failure((1UL << 48), 0);
+
+ a = map_addr(0, 0, 1);
+ if ((unsigned long)a > ADDR_SWITCH_HINT)
+ report_failure(0, 0);
+
+ a = map_addr(-1, 0, 1);
+ if ((unsigned long)a < ADDR_SWITCH_HINT)
+ report_failure(-1, 0);
+ /*
+ * Try boundary conditions again after we allocated something above 128TB
+ * and updated addr_limit.
+ */
+ boundary_check();
+}
--
2.14.3