Home | History | Annotate | Download | only in hugemmap
      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