1/******************************************************************************/
2/*                                                                            */
3/* Copyright (c) 2009 FUJITSU LIMITED                                         */
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/* Author: Li Zefan <lizf@cn.fujitsu.com>                                     */
20/*                                                                            */
21/******************************************************************************/
22
23#include <sys/types.h>
24#include <sys/mman.h>
25#include <sys/shm.h>
26#include <sys/stat.h>
27#include <err.h>
28#include <errno.h>
29#include <fcntl.h>
30#include <getopt.h>
31#include <limits.h>
32#include <signal.h>
33#include <stdio.h>
34#include <stdlib.h>
35#include <string.h>
36#include <unistd.h>
37#define TST_NO_DEFAULT_MAIN
38#include "tst_test.h"
39
40static int fd;
41
42static volatile int flag_exit;
43static volatile int flag_allocated;
44
45static int opt_mmap_anon;
46static int opt_mmap_file;
47static int opt_mmap_lock1;
48static int opt_mmap_lock2;
49static int opt_shm;
50static int opt_hugepage;
51
52static int key_id;			/* used with opt_shm */
53static unsigned long memsize;
54
55#define FILE_HUGEPAGE	"/hugetlb/hugepagefile"
56
57#define MMAP_ANON	(SCHAR_MAX + 1)
58#define MMAP_FILE	(SCHAR_MAX + 2)
59#define MMAP_LOCK1	(SCHAR_MAX + 3)
60#define MMAP_LOCK2	(SCHAR_MAX + 4)
61#define SHM		(SCHAR_MAX + 5)
62#define HUGEPAGE	(SCHAR_MAX + 6)
63
64static const struct option long_opts[] = {
65	{"mmap-anon", 0, NULL, MMAP_ANON},
66	{"mmap-file", 0, NULL, MMAP_FILE},
67	{"mmap-lock1", 0, NULL, MMAP_LOCK1},
68	{"mmap-lock2", 0, NULL, MMAP_LOCK2},
69	{"shm", 0, NULL, SHM},
70	{"hugepage", 0, NULL, HUGEPAGE},
71	{"size", 1, NULL, 's'},
72	{"key", 1, NULL, 'k'},
73	{NULL, 0, NULL, 0},
74};
75
76/*
77 * process_options: read options from user input
78 */
79static void process_options(int argc, char *argv[])
80{
81	int c;
82	char *end;
83
84	while ((c = getopt_long(argc, argv, "k:s:", long_opts, NULL)) != -1) {
85		switch (c) {
86		case 'k':
87			key_id = atoi(optarg);
88			break;
89		case 's':
90			memsize = strtoul(optarg, &end, 10);
91			if (*end != '\0')
92				errx(1, "wrong -s argument!");
93			break;
94		case MMAP_ANON:
95			opt_mmap_anon = 1;
96			break;
97		case MMAP_FILE:
98			opt_mmap_file = 1;
99			break;
100		case MMAP_LOCK1:
101			opt_mmap_lock1 = 1;
102			break;
103		case MMAP_LOCK2:
104			opt_mmap_lock2 = 1;
105			break;
106		case SHM:
107			opt_shm = 1;
108			break;
109		case HUGEPAGE:
110			opt_hugepage = 1;
111			break;
112		default:
113			errx(1, "unknown option: %c", c);
114			break;
115		}
116	}
117}
118
119/*
120 * touch_memory: force allocating phy memory
121 */
122static void touch_memory(char *p, int size)
123{
124	int i;
125	int pagesize = getpagesize();
126
127	for (i = 0; i < size; i += pagesize)
128		p[i] = 0xef;
129}
130
131static void mmap_anon(void)
132{
133	static char *p;
134
135	if (!flag_allocated) {
136		p = mmap(NULL, memsize, PROT_WRITE | PROT_READ,
137			 MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
138		if (p == MAP_FAILED)
139			err(1, "mmap(anonymous) failed");
140		touch_memory(p, memsize);
141	} else {
142		if (munmap(p, memsize) == -1)
143			err(1, "munmap(anonymous) failed");
144	}
145}
146
147static void mmap_file(void)
148{
149	static char *p;
150	static int fd_hugepage;
151	int fd_tmp;
152
153	if (!flag_allocated) {
154		if (opt_hugepage) {
155			fd_hugepage = open(FILE_HUGEPAGE,
156					   O_CREAT | O_RDWR, 0755);
157			if (fd_hugepage < 0)
158				err(1, "open hugepage file failed");
159			fd_tmp = fd_hugepage;
160		} else
161			fd_tmp = fd;
162
163		p = mmap(NULL, memsize, PROT_WRITE | PROT_READ,
164			 MAP_SHARED, fd_tmp, 0);
165		if (p == MAP_FAILED) {
166			if (opt_hugepage)
167				unlink(FILE_HUGEPAGE);
168			err(1, "mmap(file) failed");
169		}
170		touch_memory(p, memsize);
171	} else {
172		if (munmap(p, memsize) == -1)
173			err(1, "munmap(file) failed");
174
175		if (opt_hugepage) {
176			close(fd_hugepage);
177			unlink(FILE_HUGEPAGE);
178		}
179	}
180}
181
182static void mmap_lock1(void)
183{
184	static char *p;
185
186	if (!flag_allocated) {
187		p = mmap(NULL, memsize, PROT_WRITE | PROT_READ,
188			 MAP_PRIVATE | MAP_ANONYMOUS | MAP_LOCKED, 0, 0);
189		if (p == MAP_FAILED)
190			err(1, "mmap(lock) failed");
191		touch_memory(p, memsize);
192	} else {
193		if (munmap(p, memsize) == -1)
194			err(1, "munmap(lock) failed");
195	}
196}
197
198static void mmap_lock2(void)
199{
200	static char *p;
201
202	if (!flag_allocated) {
203		p = mmap(NULL, memsize, PROT_WRITE | PROT_READ,
204			 MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
205		if (p == MAP_FAILED)
206			err(1, "mmap failed");
207
208		if (mlock(p, memsize) == -1) {
209			if (errno == EAGAIN)
210				exit(2);
211			else
212				err(1, "mlock failed");
213		}
214	} else {
215		if (munmap(p, memsize) == -1)
216			err(1, "munmap failed");
217	}
218}
219
220static void shm(void)
221{
222	static char *p;
223	static int shmid;
224	unsigned long flag;
225
226	key_t key;
227
228	if (!flag_allocated) {
229		flag = IPC_CREAT | SHM_R | SHM_W;
230		if (opt_hugepage)
231			flag |= SHM_HUGETLB;
232
233		key = ftok("/dev/null", key_id);
234		if (key == -1)
235			err(1, "ftok() failed");
236
237		shmid = shmget(key, memsize, flag);
238		if (shmid == -1)
239			err(1, "shmget() failed");
240
241		p = shmat(shmid, NULL, 0);
242		if (p == (void *)-1) {
243			shmctl(shmid, IPC_RMID, NULL);
244			err(1, "shmat() failed");
245		}
246
247		if (shmctl(shmid, IPC_RMID, NULL) == -1)
248			err(1, "shmctl() failed");
249
250		touch_memory(p, memsize);
251	} else {
252		if (shmdt(p) == -1)
253			err(1, "shmdt() failed");
254	}
255}
256
257/*
258 * sigint_handler: handle SIGINT by set the exit flag.
259 */
260static void sigint_handler(int __attribute__ ((unused)) signo)
261{
262	flag_exit = 1;
263}
264
265/*
266 * sigusr_handler: handler SIGUSR
267 *
268 * When we receive SIGUSR, we allocate some memory according
269 * to the user input when the process started.
270 *
271 * When we receive SIGUSR again, we will free all the allocated
272 * memory.
273 */
274static void sigusr_handler(int __attribute__ ((unused)) signo)
275{
276	if (opt_mmap_anon)
277		mmap_anon();
278
279	if (opt_mmap_file)
280		mmap_file();
281
282	if (opt_mmap_lock1)
283		mmap_lock1();
284
285	if (opt_mmap_lock2)
286		mmap_lock2();
287
288	if (opt_shm)
289		shm();
290
291	flag_allocated = !flag_allocated;
292}
293
294int main(int argc, char *argv[])
295{
296	struct sigaction sigint_action;
297	struct sigaction sigusr_action;
298
299	if ((fd = open("/dev/zero", O_RDWR)) == -1)
300		err(1, "open /dev/zero failed");
301
302	memset(&sigint_action, 0, sizeof(sigint_action));
303	memset(&sigusr_action, 0, sizeof(sigusr_action));
304
305	sigemptyset(&sigint_action.sa_mask);
306	sigint_action.sa_handler = &sigint_handler;
307	if (sigaction(SIGINT, &sigint_action, NULL))
308		err(1, "sigaction(SIGINT)");
309
310	sigemptyset(&sigusr_action.sa_mask);
311	sigusr_action.sa_handler = &sigusr_handler;
312	if (sigaction(SIGUSR1, &sigusr_action, NULL))
313		err(1, "sigaction(SIGUSR1)");
314
315	process_options(argc, argv);
316
317	tst_reinit();
318
319	TST_CHECKPOINT_WAKE(0);
320
321	while (!flag_exit)
322		sleep(1);
323
324	close(fd);
325
326	return 0;
327}
328