1 #define TST_NO_DEFAULT_MAIN
2
3 #include "config.h"
4 #include <sys/types.h>
5 #include <sys/mman.h>
6 #include <sys/mount.h>
7 #include <sys/stat.h>
8 #include <sys/wait.h>
9 #include <sys/param.h>
10 #include <errno.h>
11 #include <fcntl.h>
12 #if HAVE_NUMA_H
13 #include <numa.h>
14 #endif
15 #if HAVE_NUMAIF_H
16 #include <numaif.h>
17 #endif
18 #include <pthread.h>
19 #include <stdarg.h>
20 #include <stdio.h>
21 #include <string.h>
22 #include <stdlib.h>
23 #include <unistd.h>
24
25 #include "mem.h"
26 #include "numa_helper.h"
27
28 /* OOM */
29
30 long overcommit = -1;
31
alloc_mem(long int length,int testcase)32 static int alloc_mem(long int length, int testcase)
33 {
34 char *s;
35 long i, pagesz = getpagesize();
36 int loop = 10;
37
38 tst_res(TINFO, "thread (%lx), allocating %ld bytes.",
39 (unsigned long) pthread_self(), length);
40
41 s = mmap(NULL, length, PROT_READ | PROT_WRITE,
42 MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
43 if (s == MAP_FAILED)
44 return errno;
45
46 if (testcase == MLOCK) {
47 while (mlock(s, length) == -1 && loop > 0) {
48 if (EAGAIN != errno)
49 return errno;
50 usleep(300000);
51 loop--;
52 }
53 }
54
55 #ifdef HAVE_DECL_MADV_MERGEABLE
56 if (testcase == KSM && madvise(s, length, MADV_MERGEABLE) == -1)
57 return errno;
58 #endif
59 for (i = 0; i < length; i += pagesz)
60 s[i] = '\a';
61
62 return 0;
63 }
64
child_alloc_thread(void * args)65 static void *child_alloc_thread(void *args)
66 {
67 int ret = 0;
68
69 /* keep allocating until there's an error */
70 while (!ret)
71 ret = alloc_mem(LENGTH, (long)args);
72 exit(ret);
73 }
74
child_alloc(int testcase,int lite,int threads)75 static void child_alloc(int testcase, int lite, int threads)
76 {
77 int i;
78 pthread_t *th;
79
80 if (lite) {
81 int ret = alloc_mem(TESTMEM * 2 + MB, testcase);
82 exit(ret);
83 }
84
85 th = malloc(sizeof(pthread_t) * threads);
86 if (!th) {
87 tst_res(TINFO | TERRNO, "malloc");
88 goto out;
89 }
90
91 for (i = 0; i < threads; i++) {
92 TEST(pthread_create(&th[i], NULL, child_alloc_thread,
93 (void *)((long)testcase)));
94 if (TST_RET) {
95 tst_res(TINFO | TRERRNO, "pthread_create");
96 /*
97 * Keep going if thread other than first fails to
98 * spawn due to lack of resources.
99 */
100 if (i == 0 || TST_RET != EAGAIN)
101 goto out;
102 }
103 }
104
105 /* wait for one of threads to exit whole process */
106 while (1)
107 sleep(1);
108 out:
109 exit(1);
110 }
111
112 /*
113 * oom - allocates memory according to specified testcase and checks
114 * desired outcome (e.g. child killed, operation failed with ENOMEM)
115 * @testcase: selects how child allocates memory
116 * valid choices are: NORMAL, MLOCK and KSM
117 * @lite: if non-zero, child makes only single TESTMEM+MB allocation
118 * if zero, child keeps allocating memory until it gets killed
119 * or some operation fails
120 * @retcode: expected return code of child process
121 * if matches child ret code, this function reports PASS,
122 * otherwise it reports FAIL
123 * @allow_sigkill: if zero and child is killed, this function reports FAIL
124 * if non-zero, then if child is killed by SIGKILL
125 * it is considered as PASS
126 */
oom(int testcase,int lite,int retcode,int allow_sigkill)127 void oom(int testcase, int lite, int retcode, int allow_sigkill)
128 {
129 pid_t pid;
130 int status, threads;
131
132 tst_enable_oom_protection(0);
133
134 switch (pid = SAFE_FORK()) {
135 case 0:
136 tst_disable_oom_protection(0);
137 threads = MAX(1, tst_ncpus() - 1);
138 child_alloc(testcase, lite, threads);
139 default:
140 break;
141 }
142
143 tst_res(TINFO, "expected victim is %d.", pid);
144 SAFE_WAITPID(-1, &status, 0);
145
146 if (WIFSIGNALED(status)) {
147 if (allow_sigkill && WTERMSIG(status) == SIGKILL) {
148 tst_res(TPASS, "victim signalled: (%d) %s",
149 SIGKILL,
150 tst_strsig(SIGKILL));
151 } else {
152 tst_res(TFAIL, "victim signalled: (%d) %s",
153 WTERMSIG(status),
154 tst_strsig(WTERMSIG(status)));
155 }
156 } else if (WIFEXITED(status)) {
157 if (WEXITSTATUS(status) == retcode) {
158 tst_res(TPASS, "victim retcode: (%d) %s",
159 retcode, strerror(retcode));
160 } else {
161 tst_res(TFAIL, "victim unexpectedly ended with "
162 "retcode: %d, expected: %d",
163 WEXITSTATUS(status), retcode);
164 }
165 } else {
166 tst_res(TFAIL, "victim unexpectedly ended");
167 }
168 }
169
170 #ifdef HAVE_NUMA_V2
set_global_mempolicy(int mempolicy)171 static void set_global_mempolicy(int mempolicy)
172 {
173 unsigned long nmask[MAXNODES / BITS_PER_LONG] = { 0 };
174 int num_nodes, *nodes;
175 int ret;
176
177 if (mempolicy) {
178 ret = get_allowed_nodes_arr(NH_MEMS|NH_CPUS, &num_nodes, &nodes);
179 if (ret != 0)
180 tst_brk(TBROK|TERRNO, "get_allowed_nodes_arr");
181 if (num_nodes < 2) {
182 tst_res(TINFO, "mempolicy need NUMA system support");
183 free(nodes);
184 return;
185 }
186 switch(mempolicy) {
187 case MPOL_BIND:
188 /* bind the second node */
189 set_node(nmask, nodes[1]);
190 break;
191 case MPOL_INTERLEAVE:
192 case MPOL_PREFERRED:
193 if (num_nodes == 2) {
194 tst_res(TINFO, "The mempolicy need "
195 "more than 2 numa nodes");
196 free(nodes);
197 return;
198 } else {
199 /* Using the 2nd,3rd node */
200 set_node(nmask, nodes[1]);
201 set_node(nmask, nodes[2]);
202 }
203 break;
204 default:
205 tst_brk(TBROK|TERRNO, "Bad mempolicy mode");
206 }
207 if (set_mempolicy(mempolicy, nmask, MAXNODES) == -1)
208 tst_brk(TBROK|TERRNO, "set_mempolicy");
209 }
210 }
211 #else
set_global_mempolicy(int mempolicy LTP_ATTRIBUTE_UNUSED)212 static void set_global_mempolicy(int mempolicy LTP_ATTRIBUTE_UNUSED) { }
213 #endif
214
testoom(int mempolicy,int lite,int retcode,int allow_sigkill)215 void testoom(int mempolicy, int lite, int retcode, int allow_sigkill)
216 {
217 int ksm_run_orig;
218
219 set_global_mempolicy(mempolicy);
220
221 tst_res(TINFO, "start normal OOM testing.");
222 oom(NORMAL, lite, retcode, allow_sigkill);
223
224 tst_res(TINFO, "start OOM testing for mlocked pages.");
225 oom(MLOCK, lite, retcode, allow_sigkill);
226
227 /*
228 * Skip oom(KSM) if lite == 1, since limit_in_bytes may vary from
229 * run to run, which isn't reliable for oom03 cgroup test.
230 */
231 if (access(PATH_KSM, F_OK) == -1 || lite == 1) {
232 tst_res(TINFO, "KSM is not configed or lite == 1, "
233 "skip OOM test for KSM pags");
234 } else {
235 tst_res(TINFO, "start OOM testing for KSM pages.");
236 SAFE_FILE_SCANF(PATH_KSM "run", "%d", &ksm_run_orig);
237 SAFE_FILE_PRINTF(PATH_KSM "run", "1");
238 oom(KSM, lite, retcode, allow_sigkill);
239 SAFE_FILE_PRINTF(PATH_KSM "run", "%d", ksm_run_orig);
240 }
241 }
242
243 /* KSM */
244
check(char * path,long int value)245 static void check(char *path, long int value)
246 {
247 char fullpath[BUFSIZ];
248 long actual_val;
249
250 snprintf(fullpath, BUFSIZ, PATH_KSM "%s", path);
251 SAFE_FILE_SCANF(fullpath, "%ld", &actual_val);
252
253 if (actual_val != value)
254 tst_res(TFAIL, "%s is not %ld but %ld.", path, value,
255 actual_val);
256 else
257 tst_res(TPASS, "%s is %ld.", path, actual_val);
258 }
259
final_group_check(int run,int pages_shared,int pages_sharing,int pages_volatile,int pages_unshared,int sleep_millisecs,int pages_to_scan)260 static void final_group_check(int run, int pages_shared, int pages_sharing,
261 int pages_volatile, int pages_unshared,
262 int sleep_millisecs, int pages_to_scan)
263 {
264 int ksm_run_orig;
265
266 tst_res(TINFO, "check!");
267 check("run", run);
268
269 /*
270 * Temporarily stop the KSM scan during the checks: during the
271 * KSM scan the rmap_items in the stale unstable tree of the
272 * old pass are removed from it and are later reinserted in
273 * the new unstable tree of the current pass. So if the checks
274 * run in the race window between removal and re-insertion, it
275 * can lead to unexpected false positives where page_volatile
276 * is elevated and page_unshared is recessed.
277 */
278 SAFE_FILE_SCANF(PATH_KSM "run", "%d", &ksm_run_orig);
279 SAFE_FILE_PRINTF(PATH_KSM "run", "0");
280
281 check("pages_shared", pages_shared);
282 check("pages_sharing", pages_sharing);
283 check("pages_volatile", pages_volatile);
284 check("pages_unshared", pages_unshared);
285 check("sleep_millisecs", sleep_millisecs);
286 check("pages_to_scan", pages_to_scan);
287
288 SAFE_FILE_PRINTF(PATH_KSM "run", "%d", ksm_run_orig);
289 }
290
ksm_group_check(int run,int pages_shared,int pages_sharing,int pages_volatile,int pages_unshared,int sleep_millisecs,int pages_to_scan)291 void ksm_group_check(int run, int pages_shared, int pages_sharing,
292 int pages_volatile, int pages_unshared,
293 int sleep_millisecs, int pages_to_scan)
294 {
295 if (run != 1) {
296 tst_res(TFAIL, "group_check run is not 1, %d.", run);
297 } else {
298 /* wait for ksm daemon to scan all mergeable pages. */
299 wait_ksmd_full_scan();
300 }
301
302 final_group_check(run, pages_shared, pages_sharing,
303 pages_volatile, pages_unshared,
304 sleep_millisecs, pages_to_scan);
305 }
306
verify(char ** memory,char value,int proc,int start,int end,int start2,int end2)307 static void verify(char **memory, char value, int proc,
308 int start, int end, int start2, int end2)
309 {
310 int i, j;
311 void *s = NULL;
312
313 s = SAFE_MALLOC((end - start) * (end2 - start2));
314
315 tst_res(TINFO, "child %d verifies memory content.", proc);
316 memset(s, value, (end - start) * (end2 - start2));
317 if (memcmp(memory[start], s, (end - start) * (end2 - start2))
318 != 0)
319 for (j = start; j < end; j++)
320 for (i = start2; i < end2; i++)
321 if (memory[j][i] != value)
322 tst_res(TFAIL, "child %d has %c at "
323 "%d,%d,%d.",
324 proc, memory[j][i], proc,
325 j, i);
326 free(s);
327 }
328
check_hugepage(void)329 void check_hugepage(void)
330 {
331 if (access(PATH_HUGEPAGES, F_OK))
332 tst_brk(TCONF, "Huge page is not supported.");
333 }
334
335 struct ksm_merge_data {
336 char data;
337 unsigned int mergeable_size;
338 };
339
ksm_child_memset(int child_num,int size,int total_unit,struct ksm_merge_data ksm_merge_data,char ** memory)340 static void ksm_child_memset(int child_num, int size, int total_unit,
341 struct ksm_merge_data ksm_merge_data, char **memory)
342 {
343 int i = 0, j;
344 int unit = size / total_unit;
345
346 tst_res(TINFO, "child %d continues...", child_num);
347
348 if (ksm_merge_data.mergeable_size == size * MB) {
349 tst_res(TINFO, "child %d allocates %d MB filled with '%c'",
350 child_num, size, ksm_merge_data.data);
351
352 } else {
353 tst_res(TINFO, "child %d allocates %d MB filled with '%c'"
354 " except one page with 'e'",
355 child_num, size, ksm_merge_data.data);
356 }
357
358 for (j = 0; j < total_unit; j++) {
359 for (i = 0; (unsigned int)i < unit * MB; i++)
360 memory[j][i] = ksm_merge_data.data;
361 }
362
363 /* if it contains unshared page, then set 'e' char
364 * at the end of the last page
365 */
366 if (ksm_merge_data.mergeable_size < size * MB)
367 memory[j-1][i-1] = 'e';
368 }
369
create_ksm_child(int child_num,int size,int unit,struct ksm_merge_data * ksm_merge_data)370 static void create_ksm_child(int child_num, int size, int unit,
371 struct ksm_merge_data *ksm_merge_data)
372 {
373 int j, total_unit;
374 char **memory;
375
376 /* The total units in all */
377 total_unit = size / unit;
378
379 /* Apply for the space for memory */
380 memory = SAFE_MALLOC(total_unit * sizeof(char *));
381 for (j = 0; j < total_unit; j++) {
382 memory[j] = SAFE_MMAP(NULL, unit * MB, PROT_READ|PROT_WRITE,
383 MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
384 #ifdef HAVE_DECL_MADV_MERGEABLE
385 if (madvise(memory[j], unit * MB, MADV_MERGEABLE) == -1)
386 tst_brk(TBROK|TERRNO, "madvise");
387 #endif
388 }
389
390 tst_res(TINFO, "child %d stops.", child_num);
391 if (raise(SIGSTOP) == -1)
392 tst_brk(TBROK|TERRNO, "kill");
393 fflush(stdout);
394
395 for (j = 0; j < 4; j++) {
396
397 ksm_child_memset(child_num, size, total_unit,
398 ksm_merge_data[j], memory);
399
400 fflush(stdout);
401
402 tst_res(TINFO, "child %d stops.", child_num);
403 if (raise(SIGSTOP) == -1)
404 tst_brk(TBROK|TERRNO, "kill");
405
406 if (ksm_merge_data[j].mergeable_size < size * MB) {
407 verify(memory, 'e', child_num, total_unit - 1,
408 total_unit, unit * MB - 1, unit * MB);
409 verify(memory, ksm_merge_data[j].data, child_num,
410 0, total_unit, 0, unit * MB - 1);
411 } else {
412 verify(memory, ksm_merge_data[j].data, child_num,
413 0, total_unit, 0, unit * MB);
414 }
415 }
416
417 tst_res(TINFO, "child %d finished.", child_num);
418 }
419
stop_ksm_children(int * child,int num)420 static void stop_ksm_children(int *child, int num)
421 {
422 int k, status;
423
424 tst_res(TINFO, "wait for all children to stop.");
425 for (k = 0; k < num; k++) {
426 SAFE_WAITPID(child[k], &status, WUNTRACED);
427 if (!WIFSTOPPED(status))
428 tst_brk(TBROK, "child %d was not stopped", k);
429 }
430 }
431
resume_ksm_children(int * child,int num)432 static void resume_ksm_children(int *child, int num)
433 {
434 int k;
435
436 tst_res(TINFO, "resume all children.");
437 for (k = 0; k < num; k++)
438 SAFE_KILL(child[k], SIGCONT);
439
440 fflush(stdout);
441 }
442
create_same_memory(int size,int num,int unit)443 void create_same_memory(int size, int num, int unit)
444 {
445 int i, j, status, *child;
446 unsigned long ps, pages;
447 struct ksm_merge_data **ksm_data;
448
449 struct ksm_merge_data ksm_data0[] = {
450 {'c', size*MB}, {'c', size*MB}, {'d', size*MB}, {'d', size*MB},
451 };
452 struct ksm_merge_data ksm_data1[] = {
453 {'a', size*MB}, {'b', size*MB}, {'d', size*MB}, {'d', size*MB-1},
454 };
455 struct ksm_merge_data ksm_data2[] = {
456 {'a', size*MB}, {'a', size*MB}, {'d', size*MB}, {'d', size*MB},
457 };
458
459 ps = sysconf(_SC_PAGE_SIZE);
460 pages = MB / ps;
461
462 ksm_data = malloc((num - 3) * sizeof(struct ksm_merge_data *));
463 /* Since from third child, the data is same with the first child's */
464 for (i = 0; i < num - 3; i++) {
465 ksm_data[i] = malloc(4 * sizeof(struct ksm_merge_data));
466 for (j = 0; j < 4; j++) {
467 ksm_data[i][j].data = ksm_data0[j].data;
468 ksm_data[i][j].mergeable_size =
469 ksm_data0[j].mergeable_size;
470 }
471 }
472
473 child = SAFE_MALLOC(num * sizeof(int));
474
475 for (i = 0; i < num; i++) {
476 fflush(stdout);
477 switch (child[i] = SAFE_FORK()) {
478 case 0:
479 if (i == 0) {
480 create_ksm_child(i, size, unit, ksm_data0);
481 exit(0);
482 } else if (i == 1) {
483 create_ksm_child(i, size, unit, ksm_data1);
484 exit(0);
485 } else if (i == 2) {
486 create_ksm_child(i, size, unit, ksm_data2);
487 exit(0);
488 } else {
489 create_ksm_child(i, size, unit, ksm_data[i-3]);
490 exit(0);
491 }
492 }
493 }
494
495 stop_ksm_children(child, num);
496
497 tst_res(TINFO, "KSM merging...");
498 if (access(PATH_KSM "max_page_sharing", F_OK) == 0) {
499 SAFE_FILE_PRINTF(PATH_KSM "run", "2");
500 SAFE_FILE_PRINTF(PATH_KSM "max_page_sharing", "%ld", size * pages * num);
501 }
502
503 SAFE_FILE_PRINTF(PATH_KSM "run", "1");
504 SAFE_FILE_PRINTF(PATH_KSM "pages_to_scan", "%ld", size * pages * num);
505 SAFE_FILE_PRINTF(PATH_KSM "sleep_millisecs", "0");
506
507 resume_ksm_children(child, num);
508 stop_ksm_children(child, num);
509 ksm_group_check(1, 2, size * num * pages - 2, 0, 0, 0, size * pages * num);
510
511 resume_ksm_children(child, num);
512 stop_ksm_children(child, num);
513 ksm_group_check(1, 3, size * num * pages - 3, 0, 0, 0, size * pages * num);
514
515 resume_ksm_children(child, num);
516 stop_ksm_children(child, num);
517 ksm_group_check(1, 1, size * num * pages - 1, 0, 0, 0, size * pages * num);
518
519 resume_ksm_children(child, num);
520 stop_ksm_children(child, num);
521 ksm_group_check(1, 1, size * num * pages - 2, 0, 1, 0, size * pages * num);
522
523 tst_res(TINFO, "KSM unmerging...");
524 SAFE_FILE_PRINTF(PATH_KSM "run", "2");
525
526 resume_ksm_children(child, num);
527 final_group_check(2, 0, 0, 0, 0, 0, size * pages * num);
528
529 tst_res(TINFO, "stop KSM.");
530 SAFE_FILE_PRINTF(PATH_KSM "run", "0");
531 final_group_check(0, 0, 0, 0, 0, 0, size * pages * num);
532
533 while (waitpid(-1, &status, 0) > 0)
534 if (WEXITSTATUS(status) != 0)
535 tst_res(TFAIL, "child exit status is %d",
536 WEXITSTATUS(status));
537 }
538
539 /* THP */
540
541 /* cpuset/memcg */
gather_node_cpus(char * cpus,long nd)542 static void gather_node_cpus(char *cpus, long nd)
543 {
544 int ncpus = 0;
545 int i;
546 long online;
547 char buf[BUFSIZ];
548 char path[BUFSIZ], path1[BUFSIZ];
549
550 while (path_exist(PATH_SYS_SYSTEM "/cpu/cpu%d", ncpus))
551 ncpus++;
552
553 for (i = 0; i < ncpus; i++) {
554 snprintf(path, BUFSIZ,
555 PATH_SYS_SYSTEM "/node/node%ld/cpu%d", nd, i);
556 if (path_exist(path)) {
557 snprintf(path1, BUFSIZ, "%s/online", path);
558 /*
559 * if there is no online knob, then the cpu cannot
560 * be taken offline
561 */
562 if (path_exist(path1)) {
563 SAFE_FILE_SCANF(path1, "%ld", &online);
564 if (online == 0)
565 continue;
566 }
567 sprintf(buf, "%d,", i);
568 strcat(cpus, buf);
569 }
570 }
571 /* Remove the trailing comma. */
572 cpus[strlen(cpus) - 1] = '\0';
573 }
574
write_cpusets(const struct tst_cg_group * cg,long nd)575 void write_cpusets(const struct tst_cg_group *cg, long nd)
576 {
577 char cpus[BUFSIZ] = "";
578
579 SAFE_CG_PRINTF(cg, "cpuset.mems", "%ld", nd);
580
581 gather_node_cpus(cpus, nd);
582 /*
583 * If the 'nd' node doesn't contain any CPUs,
584 * the first ID of CPU '0' will be used as
585 * the value of cpuset.cpus.
586 */
587 if (strlen(cpus) != 0) {
588 SAFE_CG_PRINT(cg, "cpuset.cpus", cpus);
589 } else {
590 tst_res(TINFO, "No CPUs in the node%ld; "
591 "using only CPU0", nd);
592 SAFE_CG_PRINT(cg, "cpuset.cpus", "0");
593 }
594 }
595
596 /* shared */
597
598 /* Warning: *DO NOT* use this function in child */
get_a_numa_node(void)599 unsigned int get_a_numa_node(void)
600 {
601 unsigned int nd1, nd2;
602 int ret;
603
604 ret = get_allowed_nodes(0, 2, &nd1, &nd2);
605 switch (ret) {
606 case 0:
607 break;
608 case -3:
609 tst_brk(TCONF, "requires a NUMA system.");
610 default:
611 tst_brk(TBROK | TERRNO, "1st get_allowed_nodes");
612 }
613
614 ret = get_allowed_nodes(NH_MEMS | NH_CPUS, 1, &nd1);
615 switch (ret) {
616 case 0:
617 tst_res(TINFO, "get node%u.", nd1);
618 return nd1;
619 case -3:
620 tst_brk(TCONF, "requires a NUMA system that has "
621 "at least one node with both memory and CPU "
622 "available.");
623 default:
624 tst_brk(TBROK | TERRNO, "2nd get_allowed_nodes");
625 }
626
627 /* not reached */
628 abort();
629 }
630
path_exist(const char * path,...)631 int path_exist(const char *path, ...)
632 {
633 va_list ap;
634 char pathbuf[PATH_MAX];
635
636 va_start(ap, path);
637 vsnprintf(pathbuf, sizeof(pathbuf), path, ap);
638 va_end(ap);
639
640 return access(pathbuf, F_OK) == 0;
641 }
642
set_sys_tune(char * sys_file,long tune,int check)643 void set_sys_tune(char *sys_file, long tune, int check)
644 {
645 long val;
646 char path[BUFSIZ];
647
648 tst_res(TINFO, "set %s to %ld", sys_file, tune);
649
650 snprintf(path, BUFSIZ, PATH_SYSVM "%s", sys_file);
651 SAFE_FILE_PRINTF(path, "%ld", tune);
652
653 if (check) {
654 val = get_sys_tune(sys_file);
655 if (val != tune)
656 tst_brk(TBROK, "%s = %ld, but expect %ld",
657 sys_file, val, tune);
658 }
659 }
660
get_sys_tune(char * sys_file)661 long get_sys_tune(char *sys_file)
662 {
663 char path[BUFSIZ];
664 long tune;
665
666 snprintf(path, BUFSIZ, PATH_SYSVM "%s", sys_file);
667 SAFE_FILE_SCANF(path, "%ld", &tune);
668
669 return tune;
670 }
671
update_shm_size(size_t * shm_size)672 void update_shm_size(size_t * shm_size)
673 {
674 size_t shmmax;
675
676 SAFE_FILE_SCANF(PATH_SHMMAX, "%zu", &shmmax);
677 if (*shm_size > shmmax) {
678 tst_res(TINFO, "Set shm_size to shmmax: %zu", shmmax);
679 *shm_size = shmmax;
680 }
681 }
682
range_is_mapped(unsigned long low,unsigned long high)683 int range_is_mapped(unsigned long low, unsigned long high)
684 {
685 FILE *fp;
686
687 fp = fopen("/proc/self/maps", "r");
688 if (fp == NULL)
689 tst_brk(TBROK | TERRNO, "Failed to open /proc/self/maps.");
690
691 while (!feof(fp)) {
692 unsigned long start, end;
693 int ret;
694
695 ret = fscanf(fp, "%lx-%lx %*[^\n]\n", &start, &end);
696 if (ret != 2) {
697 fclose(fp);
698 tst_brk(TBROK | TERRNO, "Couldn't parse /proc/self/maps line.");
699 }
700
701 if ((start >= low) && (start < high)) {
702 fclose(fp);
703 return 1;
704 }
705 if ((end >= low) && (end < high)) {
706 fclose(fp);
707 return 1;
708 }
709 }
710
711 fclose(fp);
712 return 0;
713 }
714