1 #include <stdio.h>
2 #include "tests/sys_mman.h"
3 #include <stdlib.h>
4 #include <unistd.h>
5 
6 /* The code testing MAP_HUGETLB huge pages is disabled by default,
7    as many distros do not have huge pages configured
8    by default.
9    To have e.g. 20 huge pages configured, do (as root)
10       echo 20 > /proc/sys/vm/nr_hugepages
11   Once this is done, uncomment the below, and recompile.
12 */
13 //#define TEST_MAP_HUGETLB 1
14 
15 /* Similarly, testing SHM_HUGETLB huge pages is disabled by default.
16    To have shmget/shmat big pages working, do (as root)
17       echo 500 > /proc/sys/vm/hugetlb_shm_group
18    where 500 is the groupid of the user that runs this test
19   Once this is done, uncomment the below, and recompile.
20 */
21 //#define TEST_SHM_HUGETLB 1
22 
23 // Size to use for huge pages
24 #define HUGESZ (4 * 1024 * 1024)
25 
26 #ifdef TEST_MAP_HUGETLB
27 /* Ensure this compiles on pre 2.6 systems, or on glibc missing MAP_HUGETLB */
28 #ifndef MAP_HUGETLB
29 /* The below works for me on an f12/x86 linux */
30 #define MAP_HUGETLB 0x40000
31 #endif
32 
33 #endif /* TEST_MAP_HUGETLB */
34 
35 #ifdef TEST_SHM_HUGETLB
36 #include <sys/ipc.h>
37 #include <sys/shm.h>
38 #include <sys/stat.h>
39 #ifndef SHM_HUGETLB
40 #define SHM_HUGETLB 04000
41 #endif
42 #endif  /* TEST_SHM_HUGETLB */
43 
44 static unsigned int pagesize;
45 
46 #define PAGES	1024u
47 #define LEN	(PAGES*pagesize)
48 
domap(size_t len,int addflags)49 static void *domap(size_t len, int addflags)
50 {
51 	void *ret = mmap(0, len, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS|addflags, -1, 0);
52 
53 	if (ret == (void *)-1) {
54 		perror("mmap");
55 		exit(1);
56 	}
57 
58 	return ret;
59 }
60 
61 /* unmap in pieces to exercise munmap more */
nibblemap(void * p)62 static void nibblemap(void *p)
63 {
64 	int off;
65 	int i;
66 
67 	off = (random() % LEN) & ~(pagesize-1);
68 
69 	for(i = 0; i < PAGES; i++) {
70 		/* printf("unmapping off=%d\n", off/pagesize); */
71 		munmap((char *)p + off, pagesize);
72 		off += 619*pagesize;
73 		off %= LEN;
74 	}
75 }
76 
prmaps()77 static void prmaps()
78 {
79 	char buf[100];
80 	sprintf(buf, "/bin/cat /proc/%ld/maps", (long) getpid());
81 	system(buf);
82 	exit(1);
83 }
84 
main()85 int main()
86 {
87 	int i;
88 	void *expect1, *expect2;
89 
90 	pagesize = getpagesize();
91 
92 	expect1 = domap(LEN, 0);
93 	expect2 = domap(LEN, 0);
94 	munmap(expect1, LEN);
95 	munmap(expect2, LEN);
96 
97 	for(i = 0; i < 5; i++) {
98 		void *m1, *m2;
99 
100 		m1 = domap(LEN, 0);
101 		if (m1 != expect1) {
102 			printf("FAIL i=%d: m1=%p expect1=%p\n",
103 			       i, m1, expect1);
104 			prmaps();
105 			return 1;
106 		}
107 		m2 = domap(LEN, 0);
108 		if (m2 != expect2) {
109 			printf("FAIL i=%d: m2=%p expect2=%p\n",
110 			       i, m2, expect2);
111 			prmaps();
112 			return 1;
113 		}
114 		nibblemap(m2);
115 		munmap(m1, LEN);
116 	}
117 
118 #ifdef  TEST_MAP_HUGETLB
119         {
120            void *expect3;
121            expect3 = domap(HUGESZ, MAP_HUGETLB);
122            munmap(expect3, HUGESZ);
123         }
124 #endif
125 
126 #ifdef TEST_SHM_HUGETLB
127         {
128            int shmid;
129            void *expect4;
130 
131 
132            shmid = shmget(IPC_PRIVATE, HUGESZ,
133                           IPC_CREAT | IPC_EXCL | S_IRUSR | S_IWUSR | SHM_HUGETLB);
134            if (shmid == -1) {
135               perror("shmget");
136               exit(1);
137            }
138            expect4 = shmat(shmid, NULL, 0);
139            if (expect4 == (void*) -1){
140               perror("shmat");
141               exit(1);
142            }
143            if (shmdt(expect4) != 0) {
144               perror("shmdt");
145               exit(1);
146            }
147            if (shmctl(shmid, IPC_RMID, 0) != 0) {
148               perror("shmctl IPC_RMID");
149               exit(1);
150            }
151         }
152 #endif
153 
154 	printf("PASS\n");
155 	return 0;
156 }
157