Home | History | Annotate | Download | only in hugeshmat
      1 /*
      2  * Copyright (c) 2015 Red Hat, Inc.
      3  *
      4  * This program is free software: you can redistribute it and/or modify
      5  * it under the terms of the GNU General Public License as published by
      6  * the Free Software Foundation, either version 3 of the License, or
      7  * (at your option) any later version.
      8  *
      9  * This program is distributed in the hope that it will be useful,
     10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     12  * GNU General Public License for more details.
     13  *
     14  * You should have received a copy of the GNU General Public License
     15  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
     16  */
     17 
     18 /*
     19  * DESCRIPTION
     20  *	shmget()/shmat() fails to allocate huge pages shared memory segment
     21  *	with EINVAL if its size is not in the range [ N*HUGE_PAGE_SIZE - 4095,
     22  *	N*HUGE_PAGE_SIZE ]. This is a problem in the memory segment size round
     23  *	up algorithm. The requested size is rounded up to PAGE_SIZE (4096), but
     24  *	if this roundup does not match HUGE_PAGE_SIZE (2Mb) boundary - the
     25  *	allocation fails.
     26  *
     27  *	This bug is present in all RHEL6 versions, but not in RHEL7. It looks
     28  *	like this was fixed in mainline kernel > v3.3 by the following patches:
     29  *
     30  *	091d0d5 (shm: fix null pointer deref when userspace specifies
     31  *		 invalid hugepage size)
     32  *	af73e4d (hugetlbfs: fix mmap failure in unaligned size request)
     33  *	42d7395 (mm: support more pagesizes for MAP_HUGETLB/SHM_HUGETLB)
     34  *	40716e2 (hugetlbfs: fix alignment of huge page requests)
     35  *
     36  * AUTHORS
     37  *	Vladislav Dronov <vdronov (at) redhat.com>
     38  *	Li Wang <liwang (at) redhat.com>
     39  *
     40  */
     41 
     42 #include <stdlib.h>
     43 #include <stdio.h>
     44 #include <sys/types.h>
     45 #include <sys/ipc.h>
     46 #include <sys/shm.h>
     47 #include <sys/mman.h>
     48 #include <fcntl.h>
     49 
     50 #include "test.h"
     51 #include "mem.h"
     52 #include "hugetlb.h"
     53 
     54 char *TCID = "hugeshmat05";
     55 int TST_TOTAL = 1;
     56 
     57 static long page_size;
     58 static long hpage_size;
     59 static long hugepages;
     60 
     61 #define N 4
     62 
     63 void setup(void)
     64 {
     65 	tst_require_root();
     66 	check_hugepage();
     67 
     68 	orig_hugepages = get_sys_tune("nr_hugepages");
     69 	page_size = getpagesize();
     70 	hpage_size = read_meminfo("Hugepagesize:") * 1024;
     71 
     72 	hugepages = N + 1;
     73 	set_sys_tune("nr_hugepages", hugepages, 1);
     74 
     75 	TEST_PAUSE;
     76 }
     77 
     78 void cleanup(void)
     79 {
     80 	set_sys_tune("nr_hugepages", orig_hugepages, 0);
     81 }
     82 
     83 void shm_test(int size)
     84 {
     85 	int shmid;
     86 	char *shmaddr;
     87 
     88 	shmid = shmget(IPC_PRIVATE, size, 0600 | IPC_CREAT | SHM_HUGETLB);
     89 	if (shmid < 0)
     90 		tst_brkm(TBROK | TERRNO, cleanup, "shmget failed");
     91 
     92 	shmaddr = shmat(shmid, 0, 0);
     93 	if (shmaddr == (char *)-1) {
     94 		shmctl(shmid, IPC_RMID, NULL);
     95 		tst_brkm(TFAIL | TERRNO, cleanup,
     96 			 "Bug: shared memory attach failure.");
     97 	}
     98 
     99 	shmaddr[0] = 1;
    100 	tst_resm(TINFO, "allocated %d huge bytes", size);
    101 
    102 	if (shmdt((const void *)shmaddr) != 0) {
    103 		shmctl(shmid, IPC_RMID, NULL);
    104 		tst_brkm(TFAIL | TERRNO, cleanup, "Detach failure.");
    105 	}
    106 
    107 	shmctl(shmid, IPC_RMID, NULL);
    108 }
    109 
    110 int main(int ac, char **av)
    111 {
    112 	int lc;
    113 	unsigned int i;
    114 
    115 	tst_parse_opts(ac, av, NULL, NULL);
    116 
    117 	setup();
    118 
    119 	const int tst_sizes[] = {
    120 		N * hpage_size - page_size,
    121 		N * hpage_size - page_size - 1,
    122 		hpage_size,
    123 		hpage_size + 1
    124 	};
    125 
    126 	for (lc = 0; TEST_LOOPING(lc); lc++) {
    127 		tst_count = 0;
    128 
    129 		for (i = 0; i < ARRAY_SIZE(tst_sizes); ++i)
    130 			shm_test(tst_sizes[i]);
    131 
    132 		tst_resm(TPASS, "No regression found.");
    133 	}
    134 
    135 	cleanup();
    136 	tst_exit();
    137 }
    138