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