1 /*
2 *
3 * Copyright (c) International Business Machines Corp., 2004
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
13 * the GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20 /*
21 * Test Name: hugemmap02
22 *
23 * Test Description: There is both a low hugepage region (at 2-3G for use by
24 * 32-bit processes) and a high hugepage region (at 1-1.5T). The high region
25 * is always exclusively for hugepages, but the low region has to be activated
26 * before it can be used for hugepages. When the kernel attempts to do a
27 * hugepage mapping in a 32-bit process it will automatically attempt to open
28 * the low region. However, that will fail if there are any normal
29 * (non-hugepage) mappings in the region already.
30 *
31 * When run as a 64-bit process the kernel will still do a non-hugepage mapping
32 * in the low region, but the following hugepage mapping will succeed. This is
33 * because it comes from the high region, which is available to the 64-bit
34 * process.
35 *
36 * This test case is checking this behavior.
37 *
38 * HISTORY
39 * 04/2004 Written by Robbie Williamson
40 */
41
42 #include <sys/types.h>
43 #include <sys/mman.h>
44 #include <sys/mount.h>
45 #include <sys/stat.h>
46 #include <errno.h>
47 #include <fcntl.h>
48 #include <signal.h>
49 #include <stdint.h>
50 #include <stdio.h>
51 #include <stdlib.h>
52 #include <string.h>
53 #include <unistd.h>
54
55 #include "test.h"
56 #include "safe_macros.h"
57 #include "mem.h"
58 #include "hugetlb.h"
59
60 #define LOW_ADDR 0x80000000
61 #define LOW_ADDR2 0x90000000
62
63 static char TEMPFILE[MAXPATHLEN];
64
65 char *TCID = "hugemmap02";
66 int TST_TOTAL = 1;
67 static unsigned long *addr;
68 static unsigned long *addr2;
69 static unsigned long low_addr = LOW_ADDR;
70 static unsigned long low_addr2 = LOW_ADDR2;
71 static unsigned long *addrlist[5];
72 static int i;
73 static int fildes;
74 static int nfildes;
75 static char *Hopt;
76 static long hugepages = 128;
77
78 static void help(void);
79
main(int ac,char ** av)80 int main(int ac, char **av)
81 {
82 int lc;
83 int Hflag = 0;
84 long page_sz, map_sz;
85 int sflag = 0;
86
87 option_t options[] = {
88 {"H:", &Hflag, &Hopt},
89 {"s:", &sflag, &nr_opt},
90 {NULL, NULL, NULL}
91 };
92
93 tst_parse_opts(ac, av, options, &help);
94
95 check_hugepage();
96
97 if (!Hflag) {
98 tst_tmpdir();
99 Hopt = tst_get_tmpdir();
100 }
101 if (sflag)
102 hugepages = SAFE_STRTOL(NULL, nr_opt, 0, LONG_MAX);
103
104 page_sz = getpagesize();
105 map_sz = read_meminfo("Hugepagesize:") * 1024 * 2;
106
107 setup();
108
109 for (lc = 0; TEST_LOOPING(lc); lc++) {
110 /* Creat a temporary file used for huge mapping */
111 fildes = open(TEMPFILE, O_RDWR | O_CREAT, 0666);
112 if (fildes < 0)
113 tst_brkm(TBROK | TERRNO, cleanup,
114 "opening %s failed", TEMPFILE);
115
116 /* Creat a file used for normal mapping */
117 nfildes = open("/dev/zero", O_RDONLY, 0666);
118 if (nfildes < 0)
119 tst_brkm(TBROK | TERRNO, cleanup,
120 "opening /dev/zero failed");
121
122 tst_count = 0;
123
124 /*
125 * Call mmap on /dev/zero 5 times
126 */
127 for (i = 0; i < 5; i++) {
128 addr = mmap(0, 256 * 1024 * 1024, PROT_READ,
129 MAP_SHARED, nfildes, 0);
130 addrlist[i] = addr;
131 }
132
133 while (range_is_mapped(cleanup, low_addr, low_addr + map_sz) == 1) {
134 low_addr = low_addr + 0x10000000;
135
136 if (low_addr < LOW_ADDR)
137 tst_brkm(TBROK | TERRNO, cleanup,
138 "no empty region to use");
139 }
140 /* mmap using normal pages and a low memory address */
141 addr = mmap((void *)low_addr, page_sz, PROT_READ,
142 MAP_SHARED | MAP_FIXED, nfildes, 0);
143 if (addr == MAP_FAILED)
144 tst_brkm(TBROK | TERRNO, cleanup,
145 "mmap failed on nfildes");
146
147 while (range_is_mapped(cleanup, low_addr2, low_addr2 + map_sz) == 1) {
148 low_addr2 = low_addr2 + 0x10000000;
149
150 if (low_addr2 < LOW_ADDR2)
151 tst_brkm(TBROK | TERRNO, cleanup,
152 "no empty region to use");
153 }
154 /* Attempt to mmap a huge page into a low memory address */
155 addr2 = mmap((void *)low_addr2, map_sz, PROT_READ | PROT_WRITE,
156 MAP_SHARED, fildes, 0);
157 #if __WORDSIZE == 64 /* 64-bit process */
158 if (addr2 == MAP_FAILED) {
159 tst_resm(TFAIL | TERRNO, "huge mmap failed unexpectedly"
160 " with %s (64-bit)", TEMPFILE);
161 } else {
162 tst_resm(TPASS, "huge mmap succeeded (64-bit)");
163 }
164 #else /* 32-bit process */
165 if (addr2 == MAP_FAILED)
166 tst_resm(TFAIL | TERRNO, "huge mmap failed unexpectedly"
167 " with %s (32-bit)", TEMPFILE);
168 else if (addr2 > 0) {
169 tst_resm(TCONF,
170 "huge mmap failed to test the scenario");
171 } else if (addr == 0)
172 tst_resm(TPASS, "huge mmap succeeded (32-bit)");
173 #endif
174
175 /* Clean up things in case we are looping */
176 for (i = 0; i < 5; i++) {
177 if (munmap(addrlist[i], 256 * 1024 * 1024) == -1)
178 tst_resm(TBROK | TERRNO,
179 "munmap of addrlist[%d] failed", i);
180 }
181
182 if (munmap(addr2, map_sz) == -1)
183 tst_brkm(TFAIL | TERRNO, NULL, "huge munmap failed");
184 if (munmap(addr, page_sz) == -1)
185 tst_brkm(TFAIL | TERRNO, NULL, "munmap failed");
186
187 close(nfildes);
188 close(fildes);
189 }
190
191 cleanup();
192 tst_exit();
193 }
194
setup(void)195 void setup(void)
196 {
197 TEST_PAUSE;
198 tst_require_root();
199 if (mount("none", Hopt, "hugetlbfs", 0, NULL) < 0)
200 tst_brkm(TBROK | TERRNO, NULL, "mount failed on %s", Hopt);
201 orig_hugepages = get_sys_tune("nr_hugepages");
202 set_sys_tune("nr_hugepages", hugepages, 1);
203 snprintf(TEMPFILE, sizeof(TEMPFILE), "%s/mmapfile%d", Hopt, getpid());
204 }
205
cleanup(void)206 void cleanup(void)
207 {
208 unlink(TEMPFILE);
209 set_sys_tune("nr_hugepages", orig_hugepages, 0);
210
211 umount(Hopt);
212 tst_rmdir();
213 }
214
help(void)215 static void help(void)
216 {
217 printf(" -H /.. Location of hugetlbfs, i.e. -H /var/hugetlbfs\n");
218 printf(" -s num Set the number of the been allocated hugepages\n");
219 }
220