1// SPDX-License-Identifier: LGPL-2.1-or-later
2/*
3 * Copyright (C) 2009 IBM Corporation.
4 * Author: David Gibson
5 */
6
7/*\
8 * [Description]
9 *
10 * The kernel has bug for mremap() on some architecture. mremap() can
11 * cause crashes on architectures with holes in the address space
12 * (like ia64) and on powerpc with it's distinct page size "slices".
13 *
14 * This test get the normal mapping address and mremap() hugepage mapping
15 * near to this normal mapping.
16 */
17
18#define _GNU_SOURCE
19#include "hugetlb.h"
20
21#define MNTPOINT "hugetlbfs/"
22
23static int fd = -1;
24static long hpage_size;
25
26static int do_remap(int fd, void *target)
27{
28	void *a, *b;
29	int ret;
30
31	a = SAFE_MMAP(NULL, hpage_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
32
33	ret = do_readback(a, hpage_size, "base huge");
34	if (ret)
35		goto cleanup;
36
37	b = mremap(a, hpage_size, hpage_size, MREMAP_MAYMOVE | MREMAP_FIXED,
38		   target);
39
40	if (b != MAP_FAILED) {
41		ret = do_readback(b, hpage_size, "remapped");
42		a = b;
43	} else {
44		tst_res(TINFO|TERRNO, "mremap(MAYMOVE|FIXED) disallowed");
45	}
46
47cleanup:
48	SAFE_MUNMAP(a, hpage_size);
49	return ret;
50}
51
52static void *map_align(size_t size, size_t align)
53{
54	unsigned long xsize = size + align - getpagesize();
55	size_t t;
56	void *p, *q;
57
58	p = SAFE_MMAP(NULL, xsize, PROT_READ|PROT_WRITE,
59		 MAP_SHARED | MAP_ANONYMOUS, -1, 0);
60
61	q = PALIGN(p, align);
62
63	t = q - p;
64	if (t)
65		SAFE_MUNMAP(p, t);
66
67	t = p + xsize - (q + size);
68	if (t)
69		SAFE_MUNMAP(q + size, t);
70
71	return q;
72}
73
74static void run_test(void)
75{
76	void *p;
77	int ret;
78
79	fd = tst_creat_unlinked(MNTPOINT, 0);
80	p = map_align(3*hpage_size, hpage_size);
81
82	SAFE_MUNMAP(p, hpage_size);
83	SAFE_MUNMAP(p + 2*hpage_size, hpage_size);
84
85	p = p + hpage_size;
86
87	tst_res(TINFO, "Normal mapping at %p", p);
88	ret = do_readback(p, hpage_size, "base normal page");
89	if (ret)
90		goto cleanup;
91
92	ret = do_remap(fd, p - hpage_size);
93	if (ret)
94		goto cleanup;
95
96	ret = do_remap(fd, p + hpage_size);
97	if (ret == 0)
98		tst_res(TPASS, "Successfully tested mremap hpage near normal mapping");
99
100cleanup:
101	SAFE_CLOSE(fd);
102}
103
104static void setup(void)
105{
106	hpage_size = tst_get_hugepage_size();
107}
108
109static void cleanup(void)
110{
111	if (fd >= 0)
112		SAFE_CLOSE(fd);
113}
114
115static struct tst_test test = {
116	.needs_root = 1,
117	.mntpoint = MNTPOINT,
118	.needs_hugetlbfs = 1,
119	.needs_tmpdir = 1,
120	.setup = setup,
121	.cleanup = cleanup,
122	.test_all = run_test,
123	.hugepages = {3, TST_NEEDS},
124};
125