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

source code of linux/tools/testing/selftests/mm/write_to_hugetlbfs.c