Blob Blame History Raw
From 96efdf51429812ec9b09f5ddb6ff24c80719e628 Mon Sep 17 00:00:00 2001
Message-Id: <96efdf51429812ec9b09f5ddb6ff24c80719e628.1566225007.git.aquini@redhat.com>
In-Reply-To: <d42f467a923dfc09309acb7a83b42e3285fbd8f4.1566225007.git.aquini@redhat.com>
References: <d42f467a923dfc09309acb7a83b42e3285fbd8f4.1566225007.git.aquini@redhat.com>
From: David Gibson <david@gibson.dropbear.id.au>
Date: Sun, 18 Aug 2019 16:03:21 +1000
Subject: [RHEL7 PATCH 27/31] tests: Improve TASK_SIZE detection in
 task-size-overrun

task-size-overrun is designed to test kernel behaviour in some edge cases
involving making a hugepage mapping right near the address space limits.
In order to do that, it needs to know the TASK_SIZE of the kernel it's
running on.

Currently it does that with a linear search from the last extant mapping.
But with kernels supporting a very large address space that can take
prohibitively long.  We've had problems with that before, resulting in some
hacks to skip a large chunk of address space.

Those hacks are dependent on platform, though, which is ugly and fragile.
Case in point, recent powerpc kernels now support a 4PiB address space,
so the logic we have there is insufficient to finish the search in
reasonable time.

To handle this in a more robust way, this replaces the linear search with
a binary search between the last extant mapping and (2^wordsize).

Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Signed-off-by: Eric B Munson <eric@munsonfam.org>
Signed-off-by: Rafael Aquini <aquini@redhat.com>
---
 tests/task-size-overrun.c | 57 +++++++++++++++++++++++------------------------
 1 file changed, 28 insertions(+), 29 deletions(-)

diff --git a/tests/task-size-overrun.c b/tests/task-size-overrun.c
index 914ef65..29b6045 100644
--- a/tests/task-size-overrun.c
+++ b/tests/task-size-overrun.c
@@ -64,45 +64,44 @@ static unsigned long find_last_mapped(void)
 	return end;
 }
 
+#define ALIGN_DOWN(x,a) ((x) & ~((a) - 1))
+
 static unsigned long find_task_size(void)
 {
-	unsigned long addr;
+	unsigned long low, high; /* PFNs */
 	void *p;
 
-	addr = find_last_mapped();
-	if (!addr || ((addr % getpagesize()) != 0))
-		FAIL("Bogus stack end address, 0x%lx!?", addr);
+	low = find_last_mapped();
+	if (!low || ((low % getpagesize()) != 0))
+		FAIL("Bogus stack end address, 0x%lx!?", low);
+	low = low / getpagesize();
+
+	/* This sum should get us (2^(wordsize) - 2 pages) */
+	high = (unsigned long)(-2 * getpagesize()) / getpagesize();
+
+	verbose_printf("Binary searching for task size PFNs 0x%lx..0x%lx\n",
+		       low, high);
+
+	while (high > low + 1) {
+		unsigned long pfn = (low + high) / 2;
+		unsigned long addr = pfn * getpagesize();
+
+		assert((pfn >= low) && (pfn <= high));
 
-	while (addr) {
 		p = mmap64((void *)addr, getpagesize(), PROT_READ,
 			   MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED, -1, 0);
 		if (p == MAP_FAILED) {
-			verbose_printf("Searching map failed: %s\n", strerror(errno));
-			return addr;
+			verbose_printf("Map failed at 0x%lx (%s)\n",
+				       addr, strerror(errno));
+			high = pfn;
+		} else {
+			verbose_printf("Map succeeded at 0x%lx\n", addr);
+			munmap(p, getpagesize());
+			low = pfn;
 		}
-		munmap(p, getpagesize());
-		addr += getpagesize();
-#if defined(__powerpc64__)
-		if (addr > (1UL << 46) && addr < (1UL << 47))
-			addr = 1UL << 47;	/* 64TB */
-		else if (addr > (1UL << 47) && addr < (1UL << 48))
-			addr = 1UL << 48;	/* 128TB */
-		else if (addr > (1UL << 48) && addr < (1UL << 49))
-			addr = 1UL << 49;	/* 512TB */
-		else if (addr > (1UL << 49) && addr < (1UL << 50))
-			addr = 1UL << 50;	/* 1PB */
-		else if (addr > (1UL << 50) && addr < (1UL << 51))
-			addr = 1UL << 51;	/* 2PB */
-		else if (addr > (1UL << 51) && addr < (1UL << 52))
-			addr = 1UL << 52;	/* 4PB */
-#endif
-#if defined(__s390x__)
-		if (addr > (1UL << 42) && addr < (1UL << 53))
-			addr = 1UL << 53;
-#endif
 	}
-	/* addr wrapped around */
-	return 0;
+
+	return low * getpagesize();
 }
 
 int main(int argc, char *argv[])
-- 
1.8.3.1