xref: /openbmc/linux/tools/testing/selftests/mm/write_to_hugetlbfs.c (revision fac59652993f075d57860769c99045b3ca18780d)
1baa489faSSeongJae Park // SPDX-License-Identifier: GPL-2.0
2baa489faSSeongJae Park /*
3baa489faSSeongJae Park  * This program reserves and uses hugetlb memory, supporting a bunch of
4baa489faSSeongJae Park  * scenarios needed by the charged_reserved_hugetlb.sh test.
5baa489faSSeongJae Park  */
6baa489faSSeongJae Park 
7baa489faSSeongJae Park #include <err.h>
8baa489faSSeongJae Park #include <errno.h>
9baa489faSSeongJae Park #include <signal.h>
10baa489faSSeongJae Park #include <stdio.h>
11baa489faSSeongJae Park #include <stdlib.h>
12baa489faSSeongJae Park #include <string.h>
13baa489faSSeongJae Park #include <unistd.h>
14baa489faSSeongJae Park #include <fcntl.h>
15baa489faSSeongJae Park #include <sys/types.h>
16baa489faSSeongJae Park #include <sys/shm.h>
17baa489faSSeongJae Park #include <sys/stat.h>
18baa489faSSeongJae Park #include <sys/mman.h>
19baa489faSSeongJae Park 
20baa489faSSeongJae Park /* Global definitions. */
21baa489faSSeongJae Park enum method {
22baa489faSSeongJae Park 	HUGETLBFS,
23baa489faSSeongJae Park 	MMAP_MAP_HUGETLB,
24baa489faSSeongJae Park 	SHM,
25baa489faSSeongJae Park 	MAX_METHOD
26baa489faSSeongJae Park };
27baa489faSSeongJae Park 
28baa489faSSeongJae Park 
29baa489faSSeongJae Park /* Global variables. */
30baa489faSSeongJae Park static const char *self;
31*dfb56976SDavid Hildenbrand static int *shmaddr;
32baa489faSSeongJae Park static int shmid;
33baa489faSSeongJae Park 
34baa489faSSeongJae Park /*
35baa489faSSeongJae Park  * Show usage and exit.
36baa489faSSeongJae Park  */
exit_usage(void)37baa489faSSeongJae Park static void exit_usage(void)
38baa489faSSeongJae Park {
39baa489faSSeongJae Park 	printf("Usage: %s -p <path to hugetlbfs file> -s <size to map> "
40baa489faSSeongJae Park 	       "[-m <0=hugetlbfs | 1=mmap(MAP_HUGETLB)>] [-l] [-r] "
41baa489faSSeongJae Park 	       "[-o] [-w] [-n]\n",
42baa489faSSeongJae Park 	       self);
43baa489faSSeongJae Park 	exit(EXIT_FAILURE);
44baa489faSSeongJae Park }
45baa489faSSeongJae Park 
sig_handler(int signo)46baa489faSSeongJae Park void sig_handler(int signo)
47baa489faSSeongJae Park {
48baa489faSSeongJae Park 	printf("Received %d.\n", signo);
49baa489faSSeongJae Park 	if (signo == SIGINT) {
50*dfb56976SDavid Hildenbrand 		if (shmaddr) {
51baa489faSSeongJae Park 			printf("Deleting the memory\n");
52baa489faSSeongJae Park 			if (shmdt((const void *)shmaddr) != 0) {
53baa489faSSeongJae Park 				perror("Detach failure");
54baa489faSSeongJae Park 				shmctl(shmid, IPC_RMID, NULL);
55baa489faSSeongJae Park 				exit(4);
56baa489faSSeongJae Park 			}
57baa489faSSeongJae Park 
58baa489faSSeongJae Park 			shmctl(shmid, IPC_RMID, NULL);
59baa489faSSeongJae Park 			printf("Done deleting the memory\n");
60baa489faSSeongJae Park 		}
61*dfb56976SDavid Hildenbrand 	}
62baa489faSSeongJae Park 	exit(2);
63baa489faSSeongJae Park }
64baa489faSSeongJae Park 
main(int argc,char ** argv)65baa489faSSeongJae Park int main(int argc, char **argv)
66baa489faSSeongJae Park {
67baa489faSSeongJae Park 	int fd = 0;
68baa489faSSeongJae Park 	int key = 0;
69baa489faSSeongJae Park 	int *ptr = NULL;
70baa489faSSeongJae Park 	int c = 0;
71baa489faSSeongJae Park 	int size = 0;
72baa489faSSeongJae Park 	char path[256] = "";
73baa489faSSeongJae Park 	enum method method = MAX_METHOD;
74baa489faSSeongJae Park 	int want_sleep = 0, private = 0;
75baa489faSSeongJae Park 	int populate = 0;
76baa489faSSeongJae Park 	int write = 0;
77baa489faSSeongJae Park 	int reserve = 1;
78baa489faSSeongJae Park 
79baa489faSSeongJae Park 	if (signal(SIGINT, sig_handler) == SIG_ERR)
80baa489faSSeongJae Park 		err(1, "\ncan't catch SIGINT\n");
81baa489faSSeongJae Park 
82baa489faSSeongJae Park 	/* Parse command-line arguments. */
83baa489faSSeongJae Park 	setvbuf(stdout, NULL, _IONBF, 0);
84baa489faSSeongJae Park 	self = argv[0];
85baa489faSSeongJae Park 
86baa489faSSeongJae Park 	while ((c = getopt(argc, argv, "s:p:m:owlrn")) != -1) {
87baa489faSSeongJae Park 		switch (c) {
88baa489faSSeongJae Park 		case 's':
89baa489faSSeongJae Park 			size = atoi(optarg);
90baa489faSSeongJae Park 			break;
91baa489faSSeongJae Park 		case 'p':
92baa489faSSeongJae Park 			strncpy(path, optarg, sizeof(path));
93baa489faSSeongJae Park 			break;
94baa489faSSeongJae Park 		case 'm':
95baa489faSSeongJae Park 			if (atoi(optarg) >= MAX_METHOD) {
96baa489faSSeongJae Park 				errno = EINVAL;
97baa489faSSeongJae Park 				perror("Invalid -m.");
98baa489faSSeongJae Park 				exit_usage();
99baa489faSSeongJae Park 			}
100baa489faSSeongJae Park 			method = atoi(optarg);
101baa489faSSeongJae Park 			break;
102baa489faSSeongJae Park 		case 'o':
103baa489faSSeongJae Park 			populate = 1;
104baa489faSSeongJae Park 			break;
105baa489faSSeongJae Park 		case 'w':
106baa489faSSeongJae Park 			write = 1;
107baa489faSSeongJae Park 			break;
108baa489faSSeongJae Park 		case 'l':
109baa489faSSeongJae Park 			want_sleep = 1;
110baa489faSSeongJae Park 			break;
111baa489faSSeongJae Park 		case 'r':
112baa489faSSeongJae Park 		    private
113baa489faSSeongJae Park 			= 1;
114baa489faSSeongJae Park 			break;
115baa489faSSeongJae Park 		case 'n':
116baa489faSSeongJae Park 			reserve = 0;
117baa489faSSeongJae Park 			break;
118baa489faSSeongJae Park 		default:
119baa489faSSeongJae Park 			errno = EINVAL;
120baa489faSSeongJae Park 			perror("Invalid arg");
121baa489faSSeongJae Park 			exit_usage();
122baa489faSSeongJae Park 		}
123baa489faSSeongJae Park 	}
124baa489faSSeongJae Park 
125baa489faSSeongJae Park 	if (strncmp(path, "", sizeof(path)) != 0) {
126baa489faSSeongJae Park 		printf("Writing to this path: %s\n", path);
127baa489faSSeongJae Park 	} else {
128baa489faSSeongJae Park 		errno = EINVAL;
129baa489faSSeongJae Park 		perror("path not found");
130baa489faSSeongJae Park 		exit_usage();
131baa489faSSeongJae Park 	}
132baa489faSSeongJae Park 
133baa489faSSeongJae Park 	if (size != 0) {
134baa489faSSeongJae Park 		printf("Writing this size: %d\n", size);
135baa489faSSeongJae Park 	} else {
136baa489faSSeongJae Park 		errno = EINVAL;
137baa489faSSeongJae Park 		perror("size not found");
138baa489faSSeongJae Park 		exit_usage();
139baa489faSSeongJae Park 	}
140baa489faSSeongJae Park 
141baa489faSSeongJae Park 	if (!populate)
142baa489faSSeongJae Park 		printf("Not populating.\n");
143baa489faSSeongJae Park 	else
144baa489faSSeongJae Park 		printf("Populating.\n");
145baa489faSSeongJae Park 
146baa489faSSeongJae Park 	if (!write)
147baa489faSSeongJae Park 		printf("Not writing to memory.\n");
148baa489faSSeongJae Park 
149baa489faSSeongJae Park 	if (method == MAX_METHOD) {
150baa489faSSeongJae Park 		errno = EINVAL;
151baa489faSSeongJae Park 		perror("-m Invalid");
152baa489faSSeongJae Park 		exit_usage();
153baa489faSSeongJae Park 	} else
154baa489faSSeongJae Park 		printf("Using method=%d\n", method);
155baa489faSSeongJae Park 
156baa489faSSeongJae Park 	if (!private)
157baa489faSSeongJae Park 		printf("Shared mapping.\n");
158baa489faSSeongJae Park 	else
159baa489faSSeongJae Park 		printf("Private mapping.\n");
160baa489faSSeongJae Park 
161baa489faSSeongJae Park 	if (!reserve)
162baa489faSSeongJae Park 		printf("NO_RESERVE mapping.\n");
163baa489faSSeongJae Park 	else
164baa489faSSeongJae Park 		printf("RESERVE mapping.\n");
165baa489faSSeongJae Park 
166baa489faSSeongJae Park 	switch (method) {
167baa489faSSeongJae Park 	case HUGETLBFS:
168baa489faSSeongJae Park 		printf("Allocating using HUGETLBFS.\n");
169baa489faSSeongJae Park 		fd = open(path, O_CREAT | O_RDWR, 0777);
170baa489faSSeongJae Park 		if (fd == -1)
171baa489faSSeongJae Park 			err(1, "Failed to open file.");
172baa489faSSeongJae Park 
173baa489faSSeongJae Park 		ptr = mmap(NULL, size, PROT_READ | PROT_WRITE,
174baa489faSSeongJae Park 			   (private ? MAP_PRIVATE : MAP_SHARED) |
175baa489faSSeongJae Park 				   (populate ? MAP_POPULATE : 0) |
176baa489faSSeongJae Park 				   (reserve ? 0 : MAP_NORESERVE),
177baa489faSSeongJae Park 			   fd, 0);
178baa489faSSeongJae Park 
179baa489faSSeongJae Park 		if (ptr == MAP_FAILED) {
180baa489faSSeongJae Park 			close(fd);
181baa489faSSeongJae Park 			err(1, "Error mapping the file");
182baa489faSSeongJae Park 		}
183baa489faSSeongJae Park 		break;
184baa489faSSeongJae Park 	case MMAP_MAP_HUGETLB:
185baa489faSSeongJae Park 		printf("Allocating using MAP_HUGETLB.\n");
186baa489faSSeongJae Park 		ptr = mmap(NULL, size, PROT_READ | PROT_WRITE,
187baa489faSSeongJae Park 			   (private ? (MAP_PRIVATE | MAP_ANONYMOUS) :
188baa489faSSeongJae Park 				      MAP_SHARED) |
189baa489faSSeongJae Park 				   MAP_HUGETLB | (populate ? MAP_POPULATE : 0) |
190baa489faSSeongJae Park 				   (reserve ? 0 : MAP_NORESERVE),
191baa489faSSeongJae Park 			   -1, 0);
192baa489faSSeongJae Park 
193baa489faSSeongJae Park 		if (ptr == MAP_FAILED)
194baa489faSSeongJae Park 			err(1, "mmap");
195baa489faSSeongJae Park 
196baa489faSSeongJae Park 		printf("Returned address is %p\n", ptr);
197baa489faSSeongJae Park 		break;
198baa489faSSeongJae Park 	case SHM:
199baa489faSSeongJae Park 		printf("Allocating using SHM.\n");
200baa489faSSeongJae Park 		shmid = shmget(key, size,
201baa489faSSeongJae Park 			       SHM_HUGETLB | IPC_CREAT | SHM_R | SHM_W);
202baa489faSSeongJae Park 		if (shmid < 0) {
203baa489faSSeongJae Park 			shmid = shmget(++key, size,
204baa489faSSeongJae Park 				       SHM_HUGETLB | IPC_CREAT | SHM_R | SHM_W);
205baa489faSSeongJae Park 			if (shmid < 0)
206baa489faSSeongJae Park 				err(1, "shmget");
207baa489faSSeongJae Park 		}
208baa489faSSeongJae Park 		printf("shmid: 0x%x, shmget key:%d\n", shmid, key);
209baa489faSSeongJae Park 
210baa489faSSeongJae Park 		ptr = shmat(shmid, NULL, 0);
211baa489faSSeongJae Park 		if (ptr == (int *)-1) {
212baa489faSSeongJae Park 			perror("Shared memory attach failure");
213baa489faSSeongJae Park 			shmctl(shmid, IPC_RMID, NULL);
214baa489faSSeongJae Park 			exit(2);
215baa489faSSeongJae Park 		}
216*dfb56976SDavid Hildenbrand 		shmaddr = ptr;
217*dfb56976SDavid Hildenbrand 		printf("shmaddr: %p\n", shmaddr);
218baa489faSSeongJae Park 
219baa489faSSeongJae Park 		break;
220baa489faSSeongJae Park 	default:
221baa489faSSeongJae Park 		errno = EINVAL;
222baa489faSSeongJae Park 		err(1, "Invalid method.");
223baa489faSSeongJae Park 	}
224baa489faSSeongJae Park 
225baa489faSSeongJae Park 	if (write) {
226baa489faSSeongJae Park 		printf("Writing to memory.\n");
227baa489faSSeongJae Park 		memset(ptr, 1, size);
228baa489faSSeongJae Park 	}
229baa489faSSeongJae Park 
230baa489faSSeongJae Park 	if (want_sleep) {
231baa489faSSeongJae Park 		/* Signal to caller that we're done. */
232baa489faSSeongJae Park 		printf("DONE\n");
233baa489faSSeongJae Park 
234baa489faSSeongJae Park 		/* Hold memory until external kill signal is delivered. */
235baa489faSSeongJae Park 		while (1)
236baa489faSSeongJae Park 			sleep(100);
237baa489faSSeongJae Park 	}
238baa489faSSeongJae Park 
239baa489faSSeongJae Park 	if (method == HUGETLBFS)
240baa489faSSeongJae Park 		close(fd);
241baa489faSSeongJae Park 
242baa489faSSeongJae Park 	return 0;
243baa489faSSeongJae Park }
244