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
23 static int fd = -1;
24 static long hpage_size;
25
do_remap(int fd,void * target)26 static 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
47 cleanup:
48 SAFE_MUNMAP(a, hpage_size);
49 return ret;
50 }
51
map_align(size_t size,size_t align)52 static 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
run_test(void)74 static 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
100 cleanup:
101 SAFE_CLOSE(fd);
102 }
103
setup(void)104 static void setup(void)
105 {
106 hpage_size = tst_get_hugepage_size();
107 }
108
cleanup(void)109 static void cleanup(void)
110 {
111 if (fd >= 0)
112 SAFE_CLOSE(fd);
113 }
114
115 static 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