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 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 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 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 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