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
44static unsigned int pagesize;
45
46#define PAGES	1024u
47#define LEN	(PAGES*pagesize)
48
49static 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 */
62static 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
77static 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
85int 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