xref: /aosp_15_r20/external/ltp/lib/tst_memutils.c (revision 49cdfc7efb34551c7342be41a7384b9c40d7cab7)
1*49cdfc7eSAndroid Build Coastguard Worker // SPDX-License-Identifier: GPL-2.0-or-later
2*49cdfc7eSAndroid Build Coastguard Worker /*
3*49cdfc7eSAndroid Build Coastguard Worker  * Copyright (c) 2020 SUSE LLC <[email protected]>
4*49cdfc7eSAndroid Build Coastguard Worker  * Copyright (c) Linux Test Project, 2021-2023
5*49cdfc7eSAndroid Build Coastguard Worker  */
6*49cdfc7eSAndroid Build Coastguard Worker 
7*49cdfc7eSAndroid Build Coastguard Worker #include <stdio.h>
8*49cdfc7eSAndroid Build Coastguard Worker #include <unistd.h>
9*49cdfc7eSAndroid Build Coastguard Worker #include <limits.h>
10*49cdfc7eSAndroid Build Coastguard Worker #include <sys/sysinfo.h>
11*49cdfc7eSAndroid Build Coastguard Worker #include <stdlib.h>
12*49cdfc7eSAndroid Build Coastguard Worker 
13*49cdfc7eSAndroid Build Coastguard Worker #define TST_NO_DEFAULT_MAIN
14*49cdfc7eSAndroid Build Coastguard Worker #include "tst_test.h"
15*49cdfc7eSAndroid Build Coastguard Worker #include "tst_memutils.h"
16*49cdfc7eSAndroid Build Coastguard Worker #include "tst_capability.h"
17*49cdfc7eSAndroid Build Coastguard Worker #include "lapi/syscalls.h"
18*49cdfc7eSAndroid Build Coastguard Worker 
19*49cdfc7eSAndroid Build Coastguard Worker #define BLOCKSIZE (16 * 1024 * 1024)
20*49cdfc7eSAndroid Build Coastguard Worker 
tst_pollute_memory(size_t maxsize,int fillchar)21*49cdfc7eSAndroid Build Coastguard Worker void tst_pollute_memory(size_t maxsize, int fillchar)
22*49cdfc7eSAndroid Build Coastguard Worker {
23*49cdfc7eSAndroid Build Coastguard Worker 	size_t i, map_count = 0, safety = 0, blocksize = BLOCKSIZE;
24*49cdfc7eSAndroid Build Coastguard Worker 	unsigned long long freeram;
25*49cdfc7eSAndroid Build Coastguard Worker 	size_t min_free;
26*49cdfc7eSAndroid Build Coastguard Worker 	void **map_blocks;
27*49cdfc7eSAndroid Build Coastguard Worker 	struct sysinfo info;
28*49cdfc7eSAndroid Build Coastguard Worker 
29*49cdfc7eSAndroid Build Coastguard Worker 	SAFE_FILE_SCANF("/proc/sys/vm/min_free_kbytes", "%zi", &min_free);
30*49cdfc7eSAndroid Build Coastguard Worker 	min_free *= 1024;
31*49cdfc7eSAndroid Build Coastguard Worker 	/* Apply a margin because we cannot get below "min" watermark */
32*49cdfc7eSAndroid Build Coastguard Worker 	min_free += min_free / 10;
33*49cdfc7eSAndroid Build Coastguard Worker 
34*49cdfc7eSAndroid Build Coastguard Worker 	SAFE_SYSINFO(&info);
35*49cdfc7eSAndroid Build Coastguard Worker 	safety = MAX(4096 * SAFE_SYSCONF(_SC_PAGESIZE), 128L * 1024 * 1024);
36*49cdfc7eSAndroid Build Coastguard Worker 	safety = MAX(safety, min_free);
37*49cdfc7eSAndroid Build Coastguard Worker 	safety /= info.mem_unit;
38*49cdfc7eSAndroid Build Coastguard Worker 
39*49cdfc7eSAndroid Build Coastguard Worker 	if (info.freeswap > safety)
40*49cdfc7eSAndroid Build Coastguard Worker 		safety = 0;
41*49cdfc7eSAndroid Build Coastguard Worker 
42*49cdfc7eSAndroid Build Coastguard Worker 	/*
43*49cdfc7eSAndroid Build Coastguard Worker 	 * MemFree usually is lower than MemAvailable, although when setting
44*49cdfc7eSAndroid Build Coastguard Worker 	 * sysctl vm.lowmem_reserve_ratio, this could reverse.
45*49cdfc7eSAndroid Build Coastguard Worker 	 *
46*49cdfc7eSAndroid Build Coastguard Worker 	 * Use the lower value of both for pollutable memory. Usually this
47*49cdfc7eSAndroid Build Coastguard Worker 	 * means we will not evict any caches.
48*49cdfc7eSAndroid Build Coastguard Worker 	 */
49*49cdfc7eSAndroid Build Coastguard Worker 	freeram = MIN((long long)info.freeram, (tst_available_mem() * 1024));
50*49cdfc7eSAndroid Build Coastguard Worker 
51*49cdfc7eSAndroid Build Coastguard Worker 	/* Not enough free memory to avoid invoking OOM killer */
52*49cdfc7eSAndroid Build Coastguard Worker 	if (freeram <= safety)
53*49cdfc7eSAndroid Build Coastguard Worker 		return;
54*49cdfc7eSAndroid Build Coastguard Worker 
55*49cdfc7eSAndroid Build Coastguard Worker 	if (!maxsize)
56*49cdfc7eSAndroid Build Coastguard Worker 		maxsize = SIZE_MAX;
57*49cdfc7eSAndroid Build Coastguard Worker 
58*49cdfc7eSAndroid Build Coastguard Worker 	if (freeram - safety < maxsize / info.mem_unit)
59*49cdfc7eSAndroid Build Coastguard Worker 		maxsize = (freeram - safety) * info.mem_unit;
60*49cdfc7eSAndroid Build Coastguard Worker 
61*49cdfc7eSAndroid Build Coastguard Worker 	blocksize = MIN(maxsize, blocksize);
62*49cdfc7eSAndroid Build Coastguard Worker 	map_count = maxsize / blocksize;
63*49cdfc7eSAndroid Build Coastguard Worker 	map_blocks = SAFE_MALLOC(map_count * sizeof(void *));
64*49cdfc7eSAndroid Build Coastguard Worker 
65*49cdfc7eSAndroid Build Coastguard Worker 	/*
66*49cdfc7eSAndroid Build Coastguard Worker 	 * Keep allocating until the first failure. The address space may be
67*49cdfc7eSAndroid Build Coastguard Worker 	 * too fragmented or just smaller than maxsize.
68*49cdfc7eSAndroid Build Coastguard Worker 	 */
69*49cdfc7eSAndroid Build Coastguard Worker 	for (i = 0; i < map_count; i++) {
70*49cdfc7eSAndroid Build Coastguard Worker 		map_blocks[i] = mmap(NULL, blocksize, PROT_READ | PROT_WRITE,
71*49cdfc7eSAndroid Build Coastguard Worker 			MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
72*49cdfc7eSAndroid Build Coastguard Worker 
73*49cdfc7eSAndroid Build Coastguard Worker 		if (map_blocks[i] == MAP_FAILED) {
74*49cdfc7eSAndroid Build Coastguard Worker 			map_count = i;
75*49cdfc7eSAndroid Build Coastguard Worker 			break;
76*49cdfc7eSAndroid Build Coastguard Worker 		}
77*49cdfc7eSAndroid Build Coastguard Worker 
78*49cdfc7eSAndroid Build Coastguard Worker 		memset(map_blocks[i], fillchar, blocksize);
79*49cdfc7eSAndroid Build Coastguard Worker 	}
80*49cdfc7eSAndroid Build Coastguard Worker 
81*49cdfc7eSAndroid Build Coastguard Worker 	for (i = 0; i < map_count; i++)
82*49cdfc7eSAndroid Build Coastguard Worker 		SAFE_MUNMAP(map_blocks[i], blocksize);
83*49cdfc7eSAndroid Build Coastguard Worker 
84*49cdfc7eSAndroid Build Coastguard Worker 	free(map_blocks);
85*49cdfc7eSAndroid Build Coastguard Worker }
86*49cdfc7eSAndroid Build Coastguard Worker 
tst_available_mem(void)87*49cdfc7eSAndroid Build Coastguard Worker long long tst_available_mem(void)
88*49cdfc7eSAndroid Build Coastguard Worker {
89*49cdfc7eSAndroid Build Coastguard Worker 	unsigned long long mem_available = 0;
90*49cdfc7eSAndroid Build Coastguard Worker 
91*49cdfc7eSAndroid Build Coastguard Worker 	if (FILE_LINES_SCANF("/proc/meminfo", "MemAvailable: %llu",
92*49cdfc7eSAndroid Build Coastguard Worker 		&mem_available)) {
93*49cdfc7eSAndroid Build Coastguard Worker 		mem_available = SAFE_READ_MEMINFO("MemFree:")
94*49cdfc7eSAndroid Build Coastguard Worker 			+ SAFE_READ_MEMINFO("Cached:");
95*49cdfc7eSAndroid Build Coastguard Worker 	}
96*49cdfc7eSAndroid Build Coastguard Worker 
97*49cdfc7eSAndroid Build Coastguard Worker 	return mem_available;
98*49cdfc7eSAndroid Build Coastguard Worker }
99*49cdfc7eSAndroid Build Coastguard Worker 
tst_available_swap(void)100*49cdfc7eSAndroid Build Coastguard Worker long long tst_available_swap(void)
101*49cdfc7eSAndroid Build Coastguard Worker {
102*49cdfc7eSAndroid Build Coastguard Worker 	unsigned long long swap_available = 0;
103*49cdfc7eSAndroid Build Coastguard Worker 
104*49cdfc7eSAndroid Build Coastguard Worker 	FILE_LINES_SCANF("/proc/meminfo", "SwapFree: %llu", &swap_available);
105*49cdfc7eSAndroid Build Coastguard Worker 
106*49cdfc7eSAndroid Build Coastguard Worker 	return swap_available;
107*49cdfc7eSAndroid Build Coastguard Worker }
108*49cdfc7eSAndroid Build Coastguard Worker 
has_caps(void)109*49cdfc7eSAndroid Build Coastguard Worker static int has_caps(void)
110*49cdfc7eSAndroid Build Coastguard Worker {
111*49cdfc7eSAndroid Build Coastguard Worker 	struct tst_cap_user_header hdr = {
112*49cdfc7eSAndroid Build Coastguard Worker 		.version = 0x20080522,
113*49cdfc7eSAndroid Build Coastguard Worker 		.pid = tst_syscall(__NR_gettid),
114*49cdfc7eSAndroid Build Coastguard Worker 	};
115*49cdfc7eSAndroid Build Coastguard Worker 
116*49cdfc7eSAndroid Build Coastguard Worker 	struct tst_cap_user_data caps[2];
117*49cdfc7eSAndroid Build Coastguard Worker 
118*49cdfc7eSAndroid Build Coastguard Worker 	if (tst_capget(&hdr, caps))
119*49cdfc7eSAndroid Build Coastguard Worker 		tst_brk(TBROK | TERRNO, "tst_capget()");
120*49cdfc7eSAndroid Build Coastguard Worker 
121*49cdfc7eSAndroid Build Coastguard Worker 	if (caps[0].effective & (1U << CAP_SYS_RESOURCE))
122*49cdfc7eSAndroid Build Coastguard Worker 		return 1;
123*49cdfc7eSAndroid Build Coastguard Worker 
124*49cdfc7eSAndroid Build Coastguard Worker 	return 0;
125*49cdfc7eSAndroid Build Coastguard Worker }
126*49cdfc7eSAndroid Build Coastguard Worker 
write_score(const char * path,int score)127*49cdfc7eSAndroid Build Coastguard Worker static int write_score(const char *path, int score)
128*49cdfc7eSAndroid Build Coastguard Worker {
129*49cdfc7eSAndroid Build Coastguard Worker 	FILE *f;
130*49cdfc7eSAndroid Build Coastguard Worker 
131*49cdfc7eSAndroid Build Coastguard Worker 	f = fopen(path, "w");
132*49cdfc7eSAndroid Build Coastguard Worker 	if (!f)
133*49cdfc7eSAndroid Build Coastguard Worker 		return 1;
134*49cdfc7eSAndroid Build Coastguard Worker 
135*49cdfc7eSAndroid Build Coastguard Worker 	if (fprintf(f, "%d", score) <= 0) {
136*49cdfc7eSAndroid Build Coastguard Worker 		fclose(f);
137*49cdfc7eSAndroid Build Coastguard Worker 		return 1;
138*49cdfc7eSAndroid Build Coastguard Worker 	}
139*49cdfc7eSAndroid Build Coastguard Worker 
140*49cdfc7eSAndroid Build Coastguard Worker 	if (fclose(f))
141*49cdfc7eSAndroid Build Coastguard Worker 		return 1;
142*49cdfc7eSAndroid Build Coastguard Worker 
143*49cdfc7eSAndroid Build Coastguard Worker 	return 0;
144*49cdfc7eSAndroid Build Coastguard Worker }
145*49cdfc7eSAndroid Build Coastguard Worker 
set_oom_score_adj(pid_t pid,int value)146*49cdfc7eSAndroid Build Coastguard Worker static void set_oom_score_adj(pid_t pid, int value)
147*49cdfc7eSAndroid Build Coastguard Worker {
148*49cdfc7eSAndroid Build Coastguard Worker 	int val;
149*49cdfc7eSAndroid Build Coastguard Worker 	char score_path[64];
150*49cdfc7eSAndroid Build Coastguard Worker 
151*49cdfc7eSAndroid Build Coastguard Worker 	if (access("/proc/self/oom_score_adj", F_OK) == -1) {
152*49cdfc7eSAndroid Build Coastguard Worker 		tst_res(TINFO, "oom_score_adj does not exist, skipping the adjustment");
153*49cdfc7eSAndroid Build Coastguard Worker 		return;
154*49cdfc7eSAndroid Build Coastguard Worker 	}
155*49cdfc7eSAndroid Build Coastguard Worker 
156*49cdfc7eSAndroid Build Coastguard Worker 	if (pid == 0) {
157*49cdfc7eSAndroid Build Coastguard Worker 		sprintf(score_path, "/proc/self/oom_score_adj");
158*49cdfc7eSAndroid Build Coastguard Worker 	} else {
159*49cdfc7eSAndroid Build Coastguard Worker 		sprintf(score_path, "/proc/%d/oom_score_adj", pid);
160*49cdfc7eSAndroid Build Coastguard Worker 		if (access(score_path, F_OK) == -1)
161*49cdfc7eSAndroid Build Coastguard Worker 			tst_brk(TBROK, "%s does not exist, please check if PID is valid", score_path);
162*49cdfc7eSAndroid Build Coastguard Worker 	}
163*49cdfc7eSAndroid Build Coastguard Worker 
164*49cdfc7eSAndroid Build Coastguard Worker 	if (write_score(score_path, value)) {
165*49cdfc7eSAndroid Build Coastguard Worker 		if (!has_caps())
166*49cdfc7eSAndroid Build Coastguard Worker 			return;
167*49cdfc7eSAndroid Build Coastguard Worker 
168*49cdfc7eSAndroid Build Coastguard Worker 		tst_res(TWARN, "Can't adjust score, even with capabilities!?");
169*49cdfc7eSAndroid Build Coastguard Worker 		return;
170*49cdfc7eSAndroid Build Coastguard Worker 	}
171*49cdfc7eSAndroid Build Coastguard Worker 
172*49cdfc7eSAndroid Build Coastguard Worker 	FILE_SCANF(score_path, "%d", &val);
173*49cdfc7eSAndroid Build Coastguard Worker 
174*49cdfc7eSAndroid Build Coastguard Worker 	if (val != value)
175*49cdfc7eSAndroid Build Coastguard Worker 		tst_brk(TBROK, "oom_score_adj = %d, but expect %d.", val, value);
176*49cdfc7eSAndroid Build Coastguard Worker }
177*49cdfc7eSAndroid Build Coastguard Worker 
tst_enable_oom_protection(pid_t pid)178*49cdfc7eSAndroid Build Coastguard Worker void tst_enable_oom_protection(pid_t pid)
179*49cdfc7eSAndroid Build Coastguard Worker {
180*49cdfc7eSAndroid Build Coastguard Worker 	set_oom_score_adj(pid, -1000);
181*49cdfc7eSAndroid Build Coastguard Worker }
182*49cdfc7eSAndroid Build Coastguard Worker 
tst_disable_oom_protection(pid_t pid)183*49cdfc7eSAndroid Build Coastguard Worker void tst_disable_oom_protection(pid_t pid)
184*49cdfc7eSAndroid Build Coastguard Worker {
185*49cdfc7eSAndroid Build Coastguard Worker 	set_oom_score_adj(pid, 0);
186*49cdfc7eSAndroid Build Coastguard Worker }
187