1 #include <stdio.h>
2 #include <sys/mman.h>
3 #include <unistd.h>
4 
5 #include "utils.h"
6 
7 /* This must match the huge page & THP size */
8 #define SIZE	(16 * 1024 * 1024)
9 
10 static int test_body(void)
11 {
12 	void *addr;
13 	char *p;
14 
15 	addr = (void *)0xa0000000;
16 
17 	p = mmap(addr, SIZE, PROT_READ | PROT_WRITE,
18 		 MAP_HUGETLB | MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
19 	if (p != MAP_FAILED) {
20 		/*
21 		 * Typically the mmap will fail because no huge pages are
22 		 * allocated on the system. But if there are huge pages
23 		 * allocated the mmap will succeed. That's fine too, we just
24 		 * munmap here before continuing.  munmap() length of
25 		 * MAP_HUGETLB memory must be hugepage aligned.
26 		 */
27 		if (munmap(addr, SIZE)) {
28 			perror("munmap");
29 			return 1;
30 		}
31 	}
32 
33 	p = mmap(addr, SIZE, PROT_READ | PROT_WRITE,
34 		 MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
35 	if (p == MAP_FAILED) {
36 		printf("Mapping failed @ %p\n", addr);
37 		perror("mmap");
38 		return 1;
39 	}
40 
41 	/*
42 	 * Either a user or kernel access is sufficient to trigger the bug.
43 	 * A kernel access is easier to spot & debug, as it will trigger the
44 	 * softlockup or RCU stall detectors, and when the system is kicked
45 	 * into xmon we get a backtrace in the kernel.
46 	 *
47 	 * A good option is:
48 	 *  getcwd(p, SIZE);
49 	 *
50 	 * For the purposes of this testcase it's preferable to spin in
51 	 * userspace, so the harness can kill us if we get stuck. That way we
52 	 * see a test failure rather than a dead system.
53 	 */
54 	*p = 0xf;
55 
56 	munmap(addr, SIZE);
57 
58 	return 0;
59 }
60 
61 static int test_main(void)
62 {
63 	int i;
64 
65 	/* 10,000 because it's a "bunch", and completes reasonably quickly */
66 	for (i = 0; i < 10000; i++)
67 		if (test_body())
68 			return 1;
69 
70 	return 0;
71 }
72 
73 int main(void)
74 {
75 	return test_harness(test_main, "hugetlb_vs_thp");
76 }
77