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