Ticket #17895: testutils.c

File testutils.c, 8.6 KB (added by korli, 2 years ago)
Line 
1/*
2 * libhugetlbfs - Easy use of Linux hugepages
3 * Copyright (C) 2005-2006 David Gibson & Adam Litke, IBM Corporation.
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public License
7 * as published by the Free Software Foundation; either version 2.1 of
8 * the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20#define _LARGEFILE64_SOURCE
21#define _GNU_SOURCE
22
23#include <stdio.h>
24#include <stdlib.h>
25#include <limits.h>
26#include <string.h>
27#include <errno.h>
28#include <ctype.h>
29#include <unistd.h>
30#include <signal.h>
31#include <sys/types.h>
32//#include <sys/vfs.h>
33#include <sys/ipc.h>
34//#include <sys/shm.h>
35#include <sys/stat.h>
36//#include <sys/sysinfo.h>
37#include <sys/types.h>
38#include <sys/mman.h>
39#include <fcntl.h>
40
41//#include "hugetlbfs.h"
42#include "hugetests.h"
43
44#define HUGETLBFS_MAGIC 0x958458f6
45#define BUF_SZ 1024
46#define MEMINFO_SZ 2048
47
48int verbose_test = 1;
49char *test_name;
50
51void check_must_be_root(void)
52{
53 uid_t uid = getuid();
54 if (uid != 0)
55 CONFIG("Must be root");
56}
57
58
59#if 0
60void check_hugetlb_shm_group(void)
61{
62 int fd;
63 ssize_t ret;
64 char gid_buffer[64] = {0};
65 gid_t hugetlb_shm_group;
66 gid_t gid = getgid();
67 uid_t uid = getuid();
68
69 /* root is an exception */
70 if (uid == 0)
71 return;
72
73 fd = open("/proc/sys/vm/hugetlb_shm_group", O_RDONLY);
74 if (fd < 0)
75 ERROR("Unable to open /proc/sys/vm/hugetlb_shm_group: %s",
76 strerror(errno));
77 ret = read(fd, &gid_buffer, sizeof(gid_buffer));
78 if (ret < 0)
79 ERROR("Unable to read /proc/sys/vm/hugetlb_shm_group: %s",
80 strerror(errno));
81 hugetlb_shm_group = atoi(gid_buffer);
82 close(fd);
83 if (hugetlb_shm_group != gid)
84 CONFIG("Do not have permission to use SHM_HUGETLB");
85}
86
87#define SYSFS_CPU_ONLINE_FMT "/sys/devices/system/cpu/cpu%d/online"
88
89void check_online_cpus(int online_cpus[], int nr_cpus_needed)
90{
91 char cpu_state, path_buf[64];
92 int total_cpus, cpu_idx, fd, ret, i;
93
94 total_cpus = get_nprocs_conf();
95 cpu_idx = 0;
96
97 if (get_nprocs() < nr_cpus_needed)
98 CONFIG("Atleast online %d cpus are required", nr_cpus_needed);
99
100 for (i = 0; i < total_cpus && cpu_idx < nr_cpus_needed; i++) {
101 errno = 0;
102 sprintf(path_buf, SYSFS_CPU_ONLINE_FMT, i);
103 fd = open(path_buf, O_RDONLY);
104 if (fd < 0) {
105 /* If 'online' is absent, the cpu cannot be offlined */
106 if (errno == ENOENT) {
107 online_cpus[cpu_idx] = i;
108 cpu_idx++;
109 continue;
110 } else {
111 FAIL("Unable to open %s: %s", path_buf,
112 strerror(errno));
113 }
114 }
115
116 ret = read(fd, &cpu_state, 1);
117 if (ret < 1)
118 FAIL("Unable to read %s: %s", path_buf,
119 strerror(errno));
120
121 if (cpu_state == '1') {
122 online_cpus[cpu_idx] = i;
123 cpu_idx++;
124 }
125
126 close(fd);
127 }
128
129 if (cpu_idx < nr_cpus_needed)
130 CONFIG("Atleast %d online cpus were not found", nr_cpus_needed);
131}
132#endif
133
134void __attribute__((weak)) cleanup(void)
135{
136}
137
138#if 0
139static void segv_handler(int signum, siginfo_t *si, void *uc)
140{
141 FAIL("Segmentation fault");
142}
143#endif
144
145static void sigint_handler(int signum, siginfo_t *si, void *uc)
146{
147 cleanup();
148 fprintf(stderr, "%s: %s (pid=%d)\n", test_name,
149 strsignal(signum), getpid());
150 exit(RC_BUG);
151}
152
153void test_init(int argc, char *argv[])
154{
155 int err;
156 struct sigaction sa_int = {
157 .sa_sigaction = sigint_handler,
158 };
159
160 test_name = argv[0];
161
162 err = sigaction(SIGINT, &sa_int, NULL);
163 if (err)
164 FAIL("Can't install SIGINT handler: %s", strerror(errno));
165
166 if (getenv("QUIET_TEST"))
167 verbose_test = 0;
168
169 verbose_printf("Starting testcase \"%s\", pid %d\n",
170 test_name, getpid());
171}
172
173
174#if 0
175
176#define MAPS_BUF_SZ 4096
177
178static int read_maps(unsigned long addr, char *buf)
179{
180 FILE *f;
181 char line[MAPS_BUF_SZ];
182 char *tmp;
183
184 f = fopen("/proc/self/maps", "r");
185 if (!f) {
186 ERROR("Failed to open /proc/self/maps: %s\n", strerror(errno));
187 return -1;
188 }
189
190 while (1) {
191 unsigned long start, end, off, ino;
192 int ret;
193
194 tmp = fgets(line, MAPS_BUF_SZ, f);
195 if (!tmp)
196 break;
197
198 buf[0] = '\0';
199 ret = sscanf(line, "%lx-%lx %*s %lx %*s %ld %255s",
200 &start, &end, &off, &ino,
201 buf);
202 if ((ret < 4) || (ret > 5)) {
203 ERROR("Couldn't parse /proc/self/maps line: %s\n",
204 line);
205 fclose(f);
206 return -1;
207 }
208
209 if ((start <= addr) && (addr < end)) {
210 fclose(f);
211 return 1;
212 }
213 }
214
215 fclose(f);
216 return 0;
217}
218
219int range_is_mapped(unsigned long low, unsigned long high)
220{
221 FILE *f;
222 char line[MAPS_BUF_SZ];
223 char *tmp;
224
225 f = fopen("/proc/self/maps", "r");
226 if (!f) {
227 ERROR("Failed to open /proc/self/maps: %s\n", strerror(errno));
228 return -1;
229 }
230
231 while (1) {
232 unsigned long start, end;
233 int ret;
234
235 tmp = fgets(line, MAPS_BUF_SZ, f);
236 if (!tmp)
237 break;
238
239 ret = sscanf(line, "%lx-%lx", &start, &end);
240 if (ret != 2) {
241 ERROR("Couldn't parse /proc/self/maps line: %s\n",
242 line);
243 fclose(f);
244 return -1;
245 }
246
247 if ((start >= low) && (start < high)) {
248 fclose(f);
249 return 1;
250 }
251 if ((end >= low) && (end < high)) {
252 fclose(f);
253 return 1;
254 }
255
256 }
257
258 fclose(f);
259 return 0;
260}
261
262/*
263 * With the inclusion of MAP_HUGETLB it is now possible to have huge pages
264 * without using hugetlbfs, so not all huge page regions will show with the
265 * test that reads /proc/self/maps. Instead we ask /proc/self/smaps for
266 * the KernelPageSize. On success we return the page size (in bytes) for the
267 * mapping that contains addr, on failure we return 0
268 */
269unsigned long long get_mapping_page_size(void *p)
270{
271 FILE *f;
272 char line[MAPS_BUF_SZ];
273 char *tmp;
274 unsigned long addr = (unsigned long)p;
275
276 f = fopen("/proc/self/smaps", "r");
277 if (!f) {
278 ERROR("Unable to open /proc/self/smaps\n");
279 return 0;
280 }
281
282 while ((tmp = fgets(line, MAPS_BUF_SZ, f))) {
283 unsigned long start, end, dummy;
284 char map_name[256];
285 char buf[64];
286 int ret;
287
288 ret = sscanf(line, "%lx-%lx %s %lx %s %ld %s", &start, &end,
289 buf, &dummy, buf, &dummy, map_name);
290 if (ret < 7 || start > addr || end <= addr)
291 continue;
292
293 while ((tmp = fgets(line, MAPS_BUF_SZ, f))) {
294 unsigned long long page_size;
295
296 ret = sscanf(line, "KernelPageSize: %lld kB",
297 &page_size);
298 if (ret == 0 )
299 continue;
300 if (ret < 1 || page_size <= 0) {
301 ERROR("Cannot parse /proc/self/smaps\n");
302 page_size = 0;
303 }
304
305 fclose(f);
306 /* page_size is reported in kB, we return B */
307 return page_size * 1024;
308 }
309 }
310
311 /* We couldn't find an entry for this addr in smaps */
312 fclose(f);
313 return 0;
314}
315
316/* We define this function standalone, rather than in terms of
317 * hugetlbfs_test_path() so that we can use it without -lhugetlbfs for
318 * testing PRELOAD */
319int test_addr_huge(void *p)
320{
321 char name[256];
322 char *dirend;
323 int ret;
324 struct statfs64 sb;
325
326 ret = read_maps((unsigned long)p, name);
327 if (ret < 0)
328 return ret;
329 if (ret == 0) {
330 verbose_printf("Couldn't find address %p in /proc/self/maps\n",
331 p);
332 return -1;
333 }
334
335 /* looks like a filename? */
336 if (name[0] != '/')
337 return 0;
338
339 /* Truncate the filename portion */
340
341 dirend = strrchr(name, '/');
342 if (dirend && dirend > name) {
343 *dirend = '\0';
344 }
345
346 ret = statfs64(name, &sb);
347 if (ret)
348 return -1;
349
350 return (sb.f_type == HUGETLBFS_MAGIC);
351}
352
353ino_t get_addr_inode(void *p)
354{
355 char name[256];
356 int ret;
357 struct stat sb;
358
359 ret = read_maps((unsigned long)p, name);
360 if (ret < 0)
361 return ret;
362 if (ret == 0) {
363 ERROR("Couldn't find address %p in /proc/self/maps\n", p);
364 return -1;
365 }
366
367 /* Don't care about non-filenames */
368 if (name[0] != '/')
369 return 0;
370
371 /* Truncate the filename portion */
372
373 ret = stat(name, &sb);
374 if (ret < 0) {
375 /* Don't care about unlinked files */
376 if (errno == ENOENT)
377 return 0;
378 ERROR("stat failed: %s\n", strerror(errno));
379 return -1;
380 }
381
382 return sb.st_ino;
383}
384
385
386int remove_shmid(int shmid)
387{
388 if (shmid >= 0) {
389 if (shmctl(shmid, IPC_RMID, NULL) != 0) {
390 ERROR("shmctl(%x, IPC_RMID) failed (%s)\n",
391 shmid, strerror(errno));
392 return -1;
393 }
394 }
395 return 0;
396}
397#endif
398
399#if 1
400int hugetlbfs_unlinked_fd(int size)
401{
402 const char *path;
403 char name[PATH_MAX+1];
404 int fd;
405
406 path = "/tmp";
407 if (!path)
408 return -1;
409
410 name[sizeof(name)-1] = '\0';
411
412 strcpy(name, path);
413 strncat(name, "/libhugetlbfs.tmp.XXXXXX", sizeof(name)-1);
414 /* FIXME: deal with overflows */
415
416 fd = mkstemp(name);
417
418 if (fd < 0) {
419 ERROR("mkstemp() failed: %s\n", strerror(errno));
420 return -1;
421 }
422
423 ftruncate(fd, size);
424
425 unlink(name);
426
427 return fd;
428}
429
430
431#endif