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
10static 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
61static 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
73int main(void)
74{
75	return test_harness(test_main, "hugetlb_vs_thp");
76}
77