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