1f08c3bdfSopenharmony_ci/*
2f08c3bdfSopenharmony_ci * Copyright (C) 2012-2017  Red Hat, Inc.
3f08c3bdfSopenharmony_ci *
4f08c3bdfSopenharmony_ci * This program is free software;  you can redistribute it and/or modify
5f08c3bdfSopenharmony_ci * it under the terms of the GNU General Public License as published by
6f08c3bdfSopenharmony_ci * the Free Software Foundation; either version 2 of the License, or
7f08c3bdfSopenharmony_ci * (at your option) any later version.
8f08c3bdfSopenharmony_ci *
9f08c3bdfSopenharmony_ci * This program is distributed in the hope that it will be useful,
10f08c3bdfSopenharmony_ci * but WITHOUT ANY WARRANTY;  without even the implied warranty of
11f08c3bdfSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
12f08c3bdfSopenharmony_ci * the GNU General Public License for more details.
13f08c3bdfSopenharmony_ci *
14f08c3bdfSopenharmony_ci * Description:
15f08c3bdfSopenharmony_ci *
16f08c3bdfSopenharmony_ci * The case is designed to test min_free_kbytes tunable.
17f08c3bdfSopenharmony_ci *
18f08c3bdfSopenharmony_ci * The tune is used to control free memory, and system always
19f08c3bdfSopenharmony_ci * reserve min_free_kbytes memory at least.
20f08c3bdfSopenharmony_ci *
21f08c3bdfSopenharmony_ci * Since the tune is not too large or too little, which will
22f08c3bdfSopenharmony_ci * lead to the system hang, so I choose two cases, and test them
23f08c3bdfSopenharmony_ci * on all overcommit_memory policy, at the same time, compare
24f08c3bdfSopenharmony_ci * the current free memory with the tunable value repeatedly.
25f08c3bdfSopenharmony_ci *
26f08c3bdfSopenharmony_ci * a) default min_free_kbytes with all overcommit memory policy
27f08c3bdfSopenharmony_ci * b) 2x default value with all overcommit memory policy
28f08c3bdfSopenharmony_ci * c) 5% of MemFree or %2 MemTotal with all overcommit memory policy
29f08c3bdfSopenharmony_ci */
30f08c3bdfSopenharmony_ci
31f08c3bdfSopenharmony_ci#include <sys/wait.h>
32f08c3bdfSopenharmony_ci#include <errno.h>
33f08c3bdfSopenharmony_ci#include <fcntl.h>
34f08c3bdfSopenharmony_ci#include <signal.h>
35f08c3bdfSopenharmony_ci#include <stdio.h>
36f08c3bdfSopenharmony_ci#include <stdlib.h>
37f08c3bdfSopenharmony_ci#include "lapi/abisize.h"
38f08c3bdfSopenharmony_ci#include "mem.h"
39f08c3bdfSopenharmony_ci
40f08c3bdfSopenharmony_ci#define MAP_SIZE (1UL<<20)
41f08c3bdfSopenharmony_ci
42f08c3bdfSopenharmony_civolatile int end;
43f08c3bdfSopenharmony_cistatic long default_tune = -1;
44f08c3bdfSopenharmony_cistatic unsigned long total_mem;
45f08c3bdfSopenharmony_ci
46f08c3bdfSopenharmony_cistatic void test_tune(unsigned long overcommit_policy);
47f08c3bdfSopenharmony_cistatic int eatup_mem(unsigned long overcommit_policy);
48f08c3bdfSopenharmony_cistatic void check_monitor(void);
49f08c3bdfSopenharmony_cistatic void sighandler(int signo LTP_ATTRIBUTE_UNUSED);
50f08c3bdfSopenharmony_ci
51f08c3bdfSopenharmony_cistatic void min_free_kbytes_test(void)
52f08c3bdfSopenharmony_ci{
53f08c3bdfSopenharmony_ci	int pid, status;
54f08c3bdfSopenharmony_ci	struct sigaction sa;
55f08c3bdfSopenharmony_ci
56f08c3bdfSopenharmony_ci	sa.sa_handler = sighandler;
57f08c3bdfSopenharmony_ci	if (sigemptyset(&sa.sa_mask) < 0)
58f08c3bdfSopenharmony_ci		tst_brk(TBROK | TERRNO, "sigemptyset");
59f08c3bdfSopenharmony_ci	sa.sa_flags = 0;
60f08c3bdfSopenharmony_ci	if (sigaction(SIGUSR1, &sa, NULL) < 0)
61f08c3bdfSopenharmony_ci		tst_brk(TBROK | TERRNO, "sigaction");
62f08c3bdfSopenharmony_ci
63f08c3bdfSopenharmony_ci	pid = SAFE_FORK();
64f08c3bdfSopenharmony_ci	if (pid == 0) {
65f08c3bdfSopenharmony_ci		/* startup the check monitor */
66f08c3bdfSopenharmony_ci		check_monitor();
67f08c3bdfSopenharmony_ci		exit(0);
68f08c3bdfSopenharmony_ci	}
69f08c3bdfSopenharmony_ci
70f08c3bdfSopenharmony_ci	test_tune(2);
71f08c3bdfSopenharmony_ci	test_tune(0);
72f08c3bdfSopenharmony_ci	test_tune(1);
73f08c3bdfSopenharmony_ci
74f08c3bdfSopenharmony_ci	SAFE_KILL(pid, SIGUSR1);
75f08c3bdfSopenharmony_ci	SAFE_WAITPID(pid, &status, WUNTRACED | WCONTINUED);
76f08c3bdfSopenharmony_ci
77f08c3bdfSopenharmony_ci	if (WIFEXITED(status) && WEXITSTATUS(status) != 0)
78f08c3bdfSopenharmony_ci		tst_res(TFAIL,
79f08c3bdfSopenharmony_ci			 "check_monitor child exit with status: %d", status);
80f08c3bdfSopenharmony_ci
81f08c3bdfSopenharmony_ci	tst_res(TPASS, "min_free_kbytes test pass");
82f08c3bdfSopenharmony_ci}
83f08c3bdfSopenharmony_ci
84f08c3bdfSopenharmony_cistatic void test_tune(unsigned long overcommit_policy)
85f08c3bdfSopenharmony_ci{
86f08c3bdfSopenharmony_ci	int status;
87f08c3bdfSopenharmony_ci	int pid[3];
88f08c3bdfSopenharmony_ci	int ret, i;
89f08c3bdfSopenharmony_ci	unsigned long tune, memfree, memtotal;
90f08c3bdfSopenharmony_ci
91f08c3bdfSopenharmony_ci	set_sys_tune("overcommit_memory", overcommit_policy, 1);
92f08c3bdfSopenharmony_ci
93f08c3bdfSopenharmony_ci	for (i = 0; i < 3; i++) {
94f08c3bdfSopenharmony_ci		/* case1 */
95f08c3bdfSopenharmony_ci		if (i == 0)
96f08c3bdfSopenharmony_ci			set_sys_tune("min_free_kbytes", default_tune, 1);
97f08c3bdfSopenharmony_ci		/* case2 */
98f08c3bdfSopenharmony_ci		else if (i == 1) {
99f08c3bdfSopenharmony_ci			set_sys_tune("min_free_kbytes", 2 * default_tune, 1);
100f08c3bdfSopenharmony_ci			/* case3 */
101f08c3bdfSopenharmony_ci		} else {
102f08c3bdfSopenharmony_ci			memfree = SAFE_READ_MEMINFO("MemFree:");
103f08c3bdfSopenharmony_ci			memtotal = SAFE_READ_MEMINFO("MemTotal:");
104f08c3bdfSopenharmony_ci			tune = memfree / 20;
105f08c3bdfSopenharmony_ci			if (tune > (memtotal / 50))
106f08c3bdfSopenharmony_ci				tune = memtotal / 50;
107f08c3bdfSopenharmony_ci
108f08c3bdfSopenharmony_ci			set_sys_tune("min_free_kbytes", tune, 1);
109f08c3bdfSopenharmony_ci		}
110f08c3bdfSopenharmony_ci
111f08c3bdfSopenharmony_ci		fflush(stdout);
112f08c3bdfSopenharmony_ci		switch (pid[i] = fork()) {
113f08c3bdfSopenharmony_ci		case -1:
114f08c3bdfSopenharmony_ci			tst_brk(TBROK | TERRNO, "fork");
115f08c3bdfSopenharmony_ci		case 0:
116f08c3bdfSopenharmony_ci			ret = eatup_mem(overcommit_policy);
117f08c3bdfSopenharmony_ci			exit(ret);
118f08c3bdfSopenharmony_ci		}
119f08c3bdfSopenharmony_ci
120f08c3bdfSopenharmony_ci		SAFE_WAITPID(pid[i], &status, WUNTRACED | WCONTINUED);
121f08c3bdfSopenharmony_ci
122f08c3bdfSopenharmony_ci		if (overcommit_policy == 2) {
123f08c3bdfSopenharmony_ci			if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
124f08c3bdfSopenharmony_ci				tst_res(TFAIL,
125f08c3bdfSopenharmony_ci					 "child unexpectedly failed: %d",
126f08c3bdfSopenharmony_ci					 status);
127f08c3bdfSopenharmony_ci		} else if (overcommit_policy == 1) {
128f08c3bdfSopenharmony_ci			if (!WIFSIGNALED(status) || WTERMSIG(status) != SIGKILL)
129f08c3bdfSopenharmony_ci#ifdef TST_ABI32
130f08c3bdfSopenharmony_ci			{
131f08c3bdfSopenharmony_ci				if (total_mem < 3145728UL)
132f08c3bdfSopenharmony_ci#endif
133f08c3bdfSopenharmony_ci					tst_res(TFAIL,
134f08c3bdfSopenharmony_ci						 "child unexpectedly failed: %d",
135f08c3bdfSopenharmony_ci						 status);
136f08c3bdfSopenharmony_ci#ifdef TST_ABI32
137f08c3bdfSopenharmony_ci				/* in 32-bit system, a process allocate about 3Gb memory at most */
138f08c3bdfSopenharmony_ci				else
139f08c3bdfSopenharmony_ci					tst_res(TINFO, "Child can't allocate "
140f08c3bdfSopenharmony_ci						 ">3Gb memory in 32bit system");
141f08c3bdfSopenharmony_ci			}
142f08c3bdfSopenharmony_ci#endif
143f08c3bdfSopenharmony_ci		} else {
144f08c3bdfSopenharmony_ci			if (WIFEXITED(status)) {
145f08c3bdfSopenharmony_ci				if (WEXITSTATUS(status) != 0) {
146f08c3bdfSopenharmony_ci					tst_res(TFAIL, "child unexpectedly "
147f08c3bdfSopenharmony_ci						 "failed: %d", status);
148f08c3bdfSopenharmony_ci				}
149f08c3bdfSopenharmony_ci			} else if (!WIFSIGNALED(status) ||
150f08c3bdfSopenharmony_ci				   WTERMSIG(status) != SIGKILL) {
151f08c3bdfSopenharmony_ci				tst_res(TFAIL,
152f08c3bdfSopenharmony_ci					 "child unexpectedly failed: %d",
153f08c3bdfSopenharmony_ci					 status);
154f08c3bdfSopenharmony_ci			}
155f08c3bdfSopenharmony_ci		}
156f08c3bdfSopenharmony_ci	}
157f08c3bdfSopenharmony_ci}
158f08c3bdfSopenharmony_ci
159f08c3bdfSopenharmony_cistatic int eatup_mem(unsigned long overcommit_policy)
160f08c3bdfSopenharmony_ci{
161f08c3bdfSopenharmony_ci	int ret = 0;
162f08c3bdfSopenharmony_ci	unsigned long memfree;
163f08c3bdfSopenharmony_ci	void *addrs;
164f08c3bdfSopenharmony_ci
165f08c3bdfSopenharmony_ci	memfree = SAFE_READ_MEMINFO("MemFree:");
166f08c3bdfSopenharmony_ci	printf("memfree is %lu kB before eatup mem\n", memfree);
167f08c3bdfSopenharmony_ci	while (1) {
168f08c3bdfSopenharmony_ci		addrs = mmap(NULL, MAP_SIZE, PROT_READ | PROT_WRITE,
169f08c3bdfSopenharmony_ci			     MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
170f08c3bdfSopenharmony_ci		if (addrs == MAP_FAILED) {
171f08c3bdfSopenharmony_ci			if (overcommit_policy != 1 && errno != ENOMEM) {
172f08c3bdfSopenharmony_ci				perror("mmap");
173f08c3bdfSopenharmony_ci				ret = -1;
174f08c3bdfSopenharmony_ci			}
175f08c3bdfSopenharmony_ci			break;
176f08c3bdfSopenharmony_ci		}
177f08c3bdfSopenharmony_ci		memset(addrs, 1, MAP_SIZE);
178f08c3bdfSopenharmony_ci	}
179f08c3bdfSopenharmony_ci	memfree = SAFE_READ_MEMINFO("MemFree:");
180f08c3bdfSopenharmony_ci	printf("memfree is %lu kB after eatup mem\n", memfree);
181f08c3bdfSopenharmony_ci
182f08c3bdfSopenharmony_ci	return ret;
183f08c3bdfSopenharmony_ci}
184f08c3bdfSopenharmony_ci
185f08c3bdfSopenharmony_cistatic void check_monitor(void)
186f08c3bdfSopenharmony_ci{
187f08c3bdfSopenharmony_ci	unsigned long tune;
188f08c3bdfSopenharmony_ci	unsigned long memfree;
189f08c3bdfSopenharmony_ci
190f08c3bdfSopenharmony_ci	while (end) {
191f08c3bdfSopenharmony_ci		memfree = SAFE_READ_MEMINFO("MemFree:");
192f08c3bdfSopenharmony_ci		tune = get_sys_tune("min_free_kbytes");
193f08c3bdfSopenharmony_ci
194f08c3bdfSopenharmony_ci		if (memfree < tune) {
195f08c3bdfSopenharmony_ci			tst_res(TINFO, "MemFree is %lu kB, "
196f08c3bdfSopenharmony_ci				 "min_free_kbytes is %lu kB", memfree, tune);
197f08c3bdfSopenharmony_ci			tst_res(TFAIL, "MemFree < min_free_kbytes");
198f08c3bdfSopenharmony_ci		}
199f08c3bdfSopenharmony_ci
200f08c3bdfSopenharmony_ci		sleep(2);
201f08c3bdfSopenharmony_ci	}
202f08c3bdfSopenharmony_ci}
203f08c3bdfSopenharmony_ci
204f08c3bdfSopenharmony_cistatic void sighandler(int signo LTP_ATTRIBUTE_UNUSED)
205f08c3bdfSopenharmony_ci{
206f08c3bdfSopenharmony_ci	end = 1;
207f08c3bdfSopenharmony_ci}
208f08c3bdfSopenharmony_ci
209f08c3bdfSopenharmony_cistatic void setup(void)
210f08c3bdfSopenharmony_ci{
211f08c3bdfSopenharmony_ci	if (get_sys_tune("panic_on_oom")) {
212f08c3bdfSopenharmony_ci		tst_brk(TCONF,
213f08c3bdfSopenharmony_ci			"panic_on_oom is set, disable it to run these testcases");
214f08c3bdfSopenharmony_ci	}
215f08c3bdfSopenharmony_ci
216f08c3bdfSopenharmony_ci	total_mem = SAFE_READ_MEMINFO("MemTotal:") + SAFE_READ_MEMINFO("SwapTotal:");
217f08c3bdfSopenharmony_ci
218f08c3bdfSopenharmony_ci	default_tune = get_sys_tune("min_free_kbytes");
219f08c3bdfSopenharmony_ci}
220f08c3bdfSopenharmony_ci
221f08c3bdfSopenharmony_cistatic struct tst_test test = {
222f08c3bdfSopenharmony_ci	.needs_root = 1,
223f08c3bdfSopenharmony_ci	.forks_child = 1,
224f08c3bdfSopenharmony_ci	.max_runtime = TST_UNLIMITED_RUNTIME,
225f08c3bdfSopenharmony_ci	.setup = setup,
226f08c3bdfSopenharmony_ci	.test_all = min_free_kbytes_test,
227f08c3bdfSopenharmony_ci	.save_restore = (const struct tst_path_val[]) {
228f08c3bdfSopenharmony_ci		{"/proc/sys/vm/overcommit_memory", NULL, TST_SR_TBROK},
229f08c3bdfSopenharmony_ci		{"/proc/sys/vm/min_free_kbytes", NULL, TST_SR_TBROK},
230f08c3bdfSopenharmony_ci		{}
231f08c3bdfSopenharmony_ci	},
232f08c3bdfSopenharmony_ci};
233