]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/oom/test-oomd-util.c
Merge pull request #26410 from DaanDeMeyer/xattr-symlink
[thirdparty/systemd.git] / src / oom / test-oomd-util.c
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
61ff7397
AZ
2
3#include <unistd.h>
4
5#include "alloc-util.h"
6#include "cgroup-setup.h"
7#include "cgroup-util.h"
282696ce 8#include "fd-util.h"
61ff7397
AZ
9#include "fileio.h"
10#include "fs-util.h"
11#include "oomd-util.h"
12#include "parse-util.h"
13#include "path-util.h"
14#include "string-util.h"
15#include "strv.h"
16#include "tests.h"
282696ce 17#include "tmpfile-util.h"
61ff7397
AZ
18
19static int fork_and_sleep(unsigned sleep_min) {
20 usec_t n, timeout, ts;
21
22 pid_t pid = fork();
23 assert_se(pid >= 0);
24
25 if (pid == 0) {
26 timeout = sleep_min * USEC_PER_MINUTE;
27 ts = now(CLOCK_MONOTONIC);
2940b128 28 for (;;) {
61ff7397
AZ
29 n = now(CLOCK_MONOTONIC);
30 if (ts + timeout < n) {
31 log_error("Child timed out waiting to be killed");
32 abort();
33 }
34 sleep(1);
35 }
36 }
37
38 return pid;
39}
40
41static void test_oomd_cgroup_kill(void) {
42 _cleanup_free_ char *cgroup_root = NULL, *cgroup = NULL;
43 int pid[2];
3e9b4f91 44 int r;
61ff7397
AZ
45
46 if (geteuid() != 0)
47 return (void) log_tests_skipped("not root");
48
49 if (cg_all_unified() <= 0)
50 return (void) log_tests_skipped("cgroups are not running in unified mode");
51
52 assert_se(cg_pid_get_path(NULL, 0, &cgroup_root) >= 0);
53
54 /* Create another cgroup below this one for the pids we forked off. We need this to be managed
55 * by the test so that pid1 doesn't delete it before we can read the xattrs. */
56 cgroup = path_join(cgroup_root, "oomdkilltest");
f21b863e 57 assert_se(cgroup);
3e9b4f91 58 assert_se(cg_create(SYSTEMD_CGROUP_CONTROLLER, cgroup) >= 0);
61ff7397
AZ
59
60 /* If we don't have permissions to set xattrs we're likely in a userns or missing capabilities */
3e9b4f91 61 r = cg_set_xattr(SYSTEMD_CGROUP_CONTROLLER, cgroup, "user.oomd_test", "test", 4, 0);
018b6f45 62 if (ERRNO_IS_PRIVILEGE(r) || ERRNO_IS_NOT_SUPPORTED(r))
3e9b4f91 63 return (void) log_tests_skipped("Cannot set user xattrs");
61ff7397
AZ
64
65 /* Do this twice to also check the increment behavior on the xattrs */
66 for (int i = 0; i < 2; i++) {
67 _cleanup_free_ char *v = NULL;
61ff7397
AZ
68
69 for (int j = 0; j < 2; j++) {
70 pid[j] = fork_and_sleep(5);
3e9b4f91 71 assert_se(cg_attach(SYSTEMD_CGROUP_CONTROLLER, cgroup, pid[j]) >= 0);
61ff7397
AZ
72 }
73
74 r = oomd_cgroup_kill(cgroup, false /* recurse */, false /* dry run */);
75 if (r <= 0) {
76 log_debug_errno(r, "Failed to kill processes under %s: %m", cgroup);
77 abort();
78 }
79
c0ebfef3
NK
80 assert_se(cg_get_xattr_malloc(SYSTEMD_CGROUP_CONTROLLER, cgroup, "user.oomd_ooms", &v) >= 0);
81 assert_se(streq(v, i == 0 ? "1" : "2"));
82 v = mfree(v);
83
61ff7397
AZ
84 /* Wait a bit since processes may take some time to be cleaned up. */
85 sleep(2);
86 assert_se(cg_is_empty(SYSTEMD_CGROUP_CONTROLLER, cgroup) == true);
87
e3038333 88 assert_se(cg_get_xattr_malloc(SYSTEMD_CGROUP_CONTROLLER, cgroup, "user.oomd_kill", &v) >= 0);
c0ebfef3 89 assert_se(streq(v, i == 0 ? "2" : "4"));
61ff7397
AZ
90 }
91}
92
93static void test_oomd_cgroup_context_acquire_and_insert(void) {
94 _cleanup_hashmap_free_ Hashmap *h1 = NULL, *h2 = NULL;
95 _cleanup_(oomd_cgroup_context_freep) OomdCGroupContext *ctx = NULL;
96 _cleanup_free_ char *cgroup = NULL;
97 OomdCGroupContext *c1, *c2;
8b2e2257 98 CGroupMask mask;
61ff7397
AZ
99
100 if (geteuid() != 0)
101 return (void) log_tests_skipped("not root");
102
103 if (!is_pressure_supported())
104 return (void) log_tests_skipped("system does not support pressure");
105
106 if (cg_all_unified() <= 0)
107 return (void) log_tests_skipped("cgroups are not running in unified mode");
108
8b2e2257
YW
109 assert_se(cg_mask_supported(&mask) >= 0);
110
111 if (!FLAGS_SET(mask, CGROUP_MASK_MEMORY))
112 return (void) log_tests_skipped("cgroup memory controller is not available");
113
61ff7397 114 assert_se(cg_pid_get_path(NULL, 0, &cgroup) >= 0);
61ff7397
AZ
115 assert_se(oomd_cgroup_context_acquire(cgroup, &ctx) == 0);
116
117 assert_se(streq(ctx->path, cgroup));
61ff7397
AZ
118 assert_se(ctx->current_memory_usage > 0);
119 assert_se(ctx->memory_min == 0);
120 assert_se(ctx->memory_low == 0);
121 assert_se(ctx->swap_usage == 0);
122 assert_se(ctx->last_pgscan == 0);
123 assert_se(ctx->pgscan == 0);
59331b8e
AZ
124 ctx = oomd_cgroup_context_free(ctx);
125
61ff7397
AZ
126 assert_se(oomd_cgroup_context_acquire("", &ctx) == 0);
127 assert_se(streq(ctx->path, "/"));
128 assert_se(ctx->current_memory_usage > 0);
129
130 /* Test hashmap inserts */
131 assert_se(h1 = hashmap_new(&oomd_cgroup_ctx_hash_ops));
132 assert_se(oomd_insert_cgroup_context(NULL, h1, cgroup) == 0);
133 c1 = hashmap_get(h1, cgroup);
134 assert_se(c1);
399d80ba 135 assert_se(oomd_insert_cgroup_context(NULL, h1, cgroup) == -EEXIST);
61ff7397
AZ
136
137 /* make sure certain values from h1 get updated in h2 */
df637ede 138 c1->pgscan = UINT64_MAX;
61ff7397 139 c1->mem_pressure_limit = 6789;
69c8f025 140 c1->mem_pressure_limit_hit_start = 42;
df637ede 141 c1->last_had_mem_reclaim = 888;
61ff7397
AZ
142 assert_se(h2 = hashmap_new(&oomd_cgroup_ctx_hash_ops));
143 assert_se(oomd_insert_cgroup_context(h1, h2, cgroup) == 0);
144 c1 = hashmap_get(h1, cgroup);
145 c2 = hashmap_get(h2, cgroup);
146 assert_se(c1);
147 assert_se(c2);
148 assert_se(c1 != c2);
df637ede 149 assert_se(c2->last_pgscan == UINT64_MAX);
61ff7397 150 assert_se(c2->mem_pressure_limit == 6789);
69c8f025 151 assert_se(c2->mem_pressure_limit_hit_start == 42);
df637ede 152 assert_se(c2->last_had_mem_reclaim == 888); /* assumes the live pgscan is less than UINT64_MAX */
61ff7397
AZ
153}
154
b037a6da
AZ
155static void test_oomd_update_cgroup_contexts_between_hashmaps(void) {
156 _cleanup_hashmap_free_ Hashmap *h_old = NULL, *h_new = NULL;
157 OomdCGroupContext *c_old, *c_new;
158 char **paths = STRV_MAKE("/0.slice",
159 "/1.slice");
160
df637ede 161 OomdCGroupContext ctx_old[2] = {
b037a6da
AZ
162 { .path = paths[0],
163 .mem_pressure_limit = 5,
69c8f025 164 .mem_pressure_limit_hit_start = 777,
df637ede 165 .last_had_mem_reclaim = 888,
b037a6da
AZ
166 .pgscan = 57 },
167 { .path = paths[1],
168 .mem_pressure_limit = 6,
69c8f025 169 .mem_pressure_limit_hit_start = 888,
df637ede 170 .last_had_mem_reclaim = 888,
b037a6da
AZ
171 .pgscan = 42 },
172 };
173
df637ede 174 OomdCGroupContext ctx_new[2] = {
b037a6da 175 { .path = paths[0],
df637ede 176 .pgscan = 57 },
b037a6da
AZ
177 { .path = paths[1],
178 .pgscan = 101 },
179 };
180
181 assert_se(h_old = hashmap_new(&string_hash_ops));
182 assert_se(hashmap_put(h_old, paths[0], &ctx_old[0]) >= 0);
183 assert_se(hashmap_put(h_old, paths[1], &ctx_old[1]) >= 0);
184
185 assert_se(h_new = hashmap_new(&string_hash_ops));
186 assert_se(hashmap_put(h_new, paths[0], &ctx_new[0]) >= 0);
187 assert_se(hashmap_put(h_new, paths[1], &ctx_new[1]) >= 0);
188
189 oomd_update_cgroup_contexts_between_hashmaps(h_old, h_new);
190
191 assert_se(c_old = hashmap_get(h_old, "/0.slice"));
192 assert_se(c_new = hashmap_get(h_new, "/0.slice"));
193 assert_se(c_old->pgscan == c_new->last_pgscan);
194 assert_se(c_old->mem_pressure_limit == c_new->mem_pressure_limit);
69c8f025 195 assert_se(c_old->mem_pressure_limit_hit_start == c_new->mem_pressure_limit_hit_start);
df637ede 196 assert_se(c_old->last_had_mem_reclaim == c_new->last_had_mem_reclaim);
b037a6da
AZ
197
198 assert_se(c_old = hashmap_get(h_old, "/1.slice"));
199 assert_se(c_new = hashmap_get(h_new, "/1.slice"));
200 assert_se(c_old->pgscan == c_new->last_pgscan);
201 assert_se(c_old->mem_pressure_limit == c_new->mem_pressure_limit);
69c8f025 202 assert_se(c_old->mem_pressure_limit_hit_start == c_new->mem_pressure_limit_hit_start);
df637ede 203 assert_se(c_new->last_had_mem_reclaim > c_old->last_had_mem_reclaim);
b037a6da
AZ
204}
205
61ff7397
AZ
206static void test_oomd_system_context_acquire(void) {
207 _cleanup_(unlink_tempfilep) char path[] = "/oomdgetsysctxtestXXXXXX";
254d1313 208 _cleanup_close_ int fd = -EBADF;
61ff7397
AZ
209 OomdSystemContext ctx;
210
211 if (geteuid() != 0)
212 return (void) log_tests_skipped("not root");
213
282696ce 214 assert_se((fd = mkostemp_safe(path)) >= 0);
61ff7397
AZ
215
216 assert_se(oomd_system_context_acquire("/verylikelynonexistentpath", &ctx) == -ENOENT);
217
47136b9d 218 assert_se(oomd_system_context_acquire(path, &ctx) == -EINVAL);
61ff7397
AZ
219
220 assert_se(write_string_file(path, "some\nwords\nacross\nmultiple\nlines", WRITE_STRING_FILE_CREATE) == 0);
47136b9d
AZ
221 assert_se(oomd_system_context_acquire(path, &ctx) == -EINVAL);
222
223 assert_se(write_string_file(path, "MemTotal: 32495256 kB trailing\n"
224 "MemFree: 9880512 kB data\n"
225 "SwapTotal: 8388604 kB is\n"
226 "SwapFree: 7604 kB bad\n", WRITE_STRING_FILE_CREATE) == 0);
227 assert_se(oomd_system_context_acquire(path, &ctx) == -EINVAL);
228
47136b9d
AZ
229 assert_se(write_string_file(path, "MemTotal: 32495256 kB\n"
230 "MemFree: 9880512 kB\n"
231 "MemAvailable: 21777088 kB\n"
232 "Buffers: 5968 kB\n"
233 "Cached: 14344796 kB\n"
234 "Unevictable: 740004 kB\n"
235 "Mlocked: 4484 kB\n"
236 "SwapTotal: 8388604 kB\n"
237 "SwapFree: 7604 kB\n", WRITE_STRING_FILE_CREATE) == 0);
61ff7397 238 assert_se(oomd_system_context_acquire(path, &ctx) == 0);
eeeaa422 239 assert_se(ctx.mem_total == 33275142144);
030bc91c 240 assert_se(ctx.mem_used == 10975404032);
47136b9d
AZ
241 assert_se(ctx.swap_total == 8589930496);
242 assert_se(ctx.swap_used == 8582144000);
61ff7397
AZ
243}
244
245static void test_oomd_pressure_above(void) {
246 _cleanup_hashmap_free_ Hashmap *h1 = NULL, *h2 = NULL;
247 _cleanup_set_free_ Set *t1 = NULL, *t2 = NULL, *t3 = NULL;
a6d6a51d 248 OomdCGroupContext ctx[2] = {}, *c;
61ff7397
AZ
249 loadavg_t threshold;
250
251 assert_se(store_loadavg_fixed_point(80, 0, &threshold) == 0);
252
253 /* /herp.slice */
254 assert_se(store_loadavg_fixed_point(99, 99, &(ctx[0].memory_pressure.avg10)) == 0);
255 assert_se(store_loadavg_fixed_point(99, 99, &(ctx[0].memory_pressure.avg60)) == 0);
256 assert_se(store_loadavg_fixed_point(99, 99, &(ctx[0].memory_pressure.avg300)) == 0);
257 ctx[0].mem_pressure_limit = threshold;
258
259 /* /derp.slice */
260 assert_se(store_loadavg_fixed_point(1, 11, &(ctx[1].memory_pressure.avg10)) == 0);
261 assert_se(store_loadavg_fixed_point(1, 11, &(ctx[1].memory_pressure.avg60)) == 0);
262 assert_se(store_loadavg_fixed_point(1, 11, &(ctx[1].memory_pressure.avg300)) == 0);
263 ctx[1].mem_pressure_limit = threshold;
264
61ff7397
AZ
265 /* High memory pressure */
266 assert_se(h1 = hashmap_new(&string_hash_ops));
267 assert_se(hashmap_put(h1, "/herp.slice", &ctx[0]) >= 0);
268 assert_se(oomd_pressure_above(h1, 0 /* duration */, &t1) == 1);
d9fe39b2 269 assert_se(set_contains(t1, &ctx[0]));
61ff7397 270 assert_se(c = hashmap_get(h1, "/herp.slice"));
69c8f025 271 assert_se(c->mem_pressure_limit_hit_start > 0);
61ff7397
AZ
272
273 /* Low memory pressure */
274 assert_se(h2 = hashmap_new(&string_hash_ops));
275 assert_se(hashmap_put(h2, "/derp.slice", &ctx[1]) >= 0);
276 assert_se(oomd_pressure_above(h2, 0 /* duration */, &t2) == 0);
d9fe39b2 277 assert_se(!t2);
61ff7397 278 assert_se(c = hashmap_get(h2, "/derp.slice"));
69c8f025 279 assert_se(c->mem_pressure_limit_hit_start == 0);
61ff7397
AZ
280
281 /* High memory pressure w/ multiple cgroups */
282 assert_se(hashmap_put(h1, "/derp.slice", &ctx[1]) >= 0);
283 assert_se(oomd_pressure_above(h1, 0 /* duration */, &t3) == 1);
d9fe39b2 284 assert_se(set_contains(t3, &ctx[0]));
61ff7397
AZ
285 assert_se(set_size(t3) == 1);
286 assert_se(c = hashmap_get(h1, "/herp.slice"));
69c8f025 287 assert_se(c->mem_pressure_limit_hit_start > 0);
61ff7397 288 assert_se(c = hashmap_get(h1, "/derp.slice"));
69c8f025 289 assert_se(c->mem_pressure_limit_hit_start == 0);
61ff7397
AZ
290}
291
eeeaa422 292static void test_oomd_mem_and_swap_free_below(void) {
61ff7397 293 OomdSystemContext ctx = (OomdSystemContext) {
eeeaa422
AZ
294 .mem_total = 20971512 * 1024U,
295 .mem_used = 3310136 * 1024U,
61ff7397
AZ
296 .swap_total = 20971512 * 1024U,
297 .swap_used = 20971440 * 1024U,
298 };
030bc91c 299 assert_se(oomd_mem_available_below(&ctx, 2000) == false);
d06e7fb5 300 assert_se(oomd_swap_free_below(&ctx, 2000) == true);
61ff7397
AZ
301
302 ctx = (OomdSystemContext) {
eeeaa422
AZ
303 .mem_total = 20971512 * 1024U,
304 .mem_used = 20971440 * 1024U,
61ff7397
AZ
305 .swap_total = 20971512 * 1024U,
306 .swap_used = 3310136 * 1024U,
307 };
030bc91c 308 assert_se(oomd_mem_available_below(&ctx, 2000) == true);
d06e7fb5 309 assert_se(oomd_swap_free_below(&ctx, 2000) == false);
408a3bbd
AZ
310
311 ctx = (OomdSystemContext) {
eeeaa422
AZ
312 .mem_total = 0,
313 .mem_used = 0,
408a3bbd
AZ
314 .swap_total = 0,
315 .swap_used = 0,
316 };
030bc91c 317 assert_se(oomd_mem_available_below(&ctx, 2000) == false);
d06e7fb5 318 assert_se(oomd_swap_free_below(&ctx, 2000) == false);
61ff7397
AZ
319}
320
321static void test_oomd_sort_cgroups(void) {
322 _cleanup_hashmap_free_ Hashmap *h = NULL;
323 _cleanup_free_ OomdCGroupContext **sorted_cgroups;
324 char **paths = STRV_MAKE("/herp.slice",
325 "/herp.slice/derp.scope",
326 "/herp.slice/derp.scope/sheep.service",
59331b8e 327 "/zupa.slice",
88e47952 328 "/boop.slice",
59331b8e
AZ
329 "/omitted.slice",
330 "/avoid.slice");
61ff7397 331
88e47952 332 OomdCGroupContext ctx[7] = {
61ff7397
AZ
333 { .path = paths[0],
334 .swap_usage = 20,
88e47952
AZ
335 .last_pgscan = 0,
336 .pgscan = 33,
1f76411b 337 .current_memory_usage = 10 },
61ff7397
AZ
338 { .path = paths[1],
339 .swap_usage = 60,
88e47952
AZ
340 .last_pgscan = 33,
341 .pgscan = 1,
1f76411b 342 .current_memory_usage = 20 },
61ff7397
AZ
343 { .path = paths[2],
344 .swap_usage = 40,
88e47952
AZ
345 .last_pgscan = 1,
346 .pgscan = 33,
1f76411b 347 .current_memory_usage = 40 },
61ff7397
AZ
348 { .path = paths[3],
349 .swap_usage = 10,
88e47952
AZ
350 .last_pgscan = 33,
351 .pgscan = 2,
1f76411b 352 .current_memory_usage = 10 },
59331b8e 353 { .path = paths[4],
88e47952
AZ
354 .swap_usage = 11,
355 .last_pgscan = 33,
356 .pgscan = 33,
357 .current_memory_usage = 10 },
358 { .path = paths[5],
59331b8e 359 .swap_usage = 90,
88e47952
AZ
360 .last_pgscan = 0,
361 .pgscan = UINT64_MAX,
59331b8e 362 .preference = MANAGED_OOM_PREFERENCE_OMIT },
88e47952 363 { .path = paths[6],
59331b8e 364 .swap_usage = 99,
88e47952
AZ
365 .last_pgscan = 0,
366 .pgscan = UINT64_MAX,
59331b8e 367 .preference = MANAGED_OOM_PREFERENCE_AVOID },
61ff7397
AZ
368 };
369
370 assert_se(h = hashmap_new(&string_hash_ops));
371
372 assert_se(hashmap_put(h, "/herp.slice", &ctx[0]) >= 0);
373 assert_se(hashmap_put(h, "/herp.slice/derp.scope", &ctx[1]) >= 0);
374 assert_se(hashmap_put(h, "/herp.slice/derp.scope/sheep.service", &ctx[2]) >= 0);
375 assert_se(hashmap_put(h, "/zupa.slice", &ctx[3]) >= 0);
88e47952
AZ
376 assert_se(hashmap_put(h, "/boop.slice", &ctx[4]) >= 0);
377 assert_se(hashmap_put(h, "/omitted.slice", &ctx[5]) >= 0);
378 assert_se(hashmap_put(h, "/avoid.slice", &ctx[6]) >= 0);
61ff7397 379
88e47952 380 assert_se(oomd_sort_cgroup_contexts(h, compare_swap_usage, NULL, &sorted_cgroups) == 6);
61ff7397
AZ
381 assert_se(sorted_cgroups[0] == &ctx[1]);
382 assert_se(sorted_cgroups[1] == &ctx[2]);
383 assert_se(sorted_cgroups[2] == &ctx[0]);
88e47952
AZ
384 assert_se(sorted_cgroups[3] == &ctx[4]);
385 assert_se(sorted_cgroups[4] == &ctx[3]);
386 assert_se(sorted_cgroups[5] == &ctx[6]);
61ff7397
AZ
387 sorted_cgroups = mfree(sorted_cgroups);
388
88e47952
AZ
389 assert_se(oomd_sort_cgroup_contexts(h, compare_pgscan_rate_and_memory_usage, NULL, &sorted_cgroups) == 6);
390 assert_se(sorted_cgroups[0] == &ctx[0]);
391 assert_se(sorted_cgroups[1] == &ctx[2]);
392 assert_se(sorted_cgroups[2] == &ctx[3]);
1f76411b 393 assert_se(sorted_cgroups[3] == &ctx[1]);
88e47952
AZ
394 assert_se(sorted_cgroups[4] == &ctx[4]);
395 assert_se(sorted_cgroups[5] == &ctx[6]);
61ff7397
AZ
396 sorted_cgroups = mfree(sorted_cgroups);
397
88e47952 398 assert_se(oomd_sort_cgroup_contexts(h, compare_pgscan_rate_and_memory_usage, "/herp.slice/derp.scope", &sorted_cgroups) == 2);
1f76411b
AZ
399 assert_se(sorted_cgroups[0] == &ctx[2]);
400 assert_se(sorted_cgroups[1] == &ctx[1]);
61ff7397
AZ
401 assert_se(sorted_cgroups[2] == 0);
402 assert_se(sorted_cgroups[3] == 0);
59331b8e
AZ
403 assert_se(sorted_cgroups[4] == 0);
404 assert_se(sorted_cgroups[5] == 0);
88e47952 405 assert_se(sorted_cgroups[6] == 0);
61ff7397
AZ
406 sorted_cgroups = mfree(sorted_cgroups);
407}
408
39f9eee8
NR
409static void test_oomd_fetch_cgroup_oom_preference(void) {
410 _cleanup_(oomd_cgroup_context_freep) OomdCGroupContext *ctx = NULL;
411 _cleanup_free_ char *cgroup = NULL;
412 ManagedOOMPreference root_pref;
413 CGroupMask mask;
414 bool test_xattrs;
415 int root_xattrs, r;
416
417 if (geteuid() != 0)
418 return (void) log_tests_skipped("not root");
419
420 if (!is_pressure_supported())
421 return (void) log_tests_skipped("system does not support pressure");
422
423 if (cg_all_unified() <= 0)
424 return (void) log_tests_skipped("cgroups are not running in unified mode");
425
426 assert_se(cg_mask_supported(&mask) >= 0);
427
428 if (!FLAGS_SET(mask, CGROUP_MASK_MEMORY))
429 return (void) log_tests_skipped("cgroup memory controller is not available");
430
431 assert_se(cg_pid_get_path(NULL, 0, &cgroup) >= 0);
432 assert_se(oomd_cgroup_context_acquire(cgroup, &ctx) == 0);
433
434 /* If we don't have permissions to set xattrs we're likely in a userns or missing capabilities
435 * so skip the xattr portions of the test. */
436 r = cg_set_xattr(SYSTEMD_CGROUP_CONTROLLER, cgroup, "user.oomd_test", "1", 1, 0);
437 test_xattrs = !ERRNO_IS_PRIVILEGE(r) && !ERRNO_IS_NOT_SUPPORTED(r);
438
439 if (test_xattrs) {
440 assert_se(oomd_fetch_cgroup_oom_preference(ctx, NULL) == 0);
441 assert_se(cg_set_xattr(SYSTEMD_CGROUP_CONTROLLER, cgroup, "user.oomd_omit", "1", 1, 0) >= 0);
442 assert_se(cg_set_xattr(SYSTEMD_CGROUP_CONTROLLER, cgroup, "user.oomd_avoid", "1", 1, 0) >= 0);
443
444 /* omit takes precedence over avoid when both are set to true */
445 assert_se(oomd_fetch_cgroup_oom_preference(ctx, NULL) == 0);
446 assert_se(ctx->preference == MANAGED_OOM_PREFERENCE_OMIT);
447 } else {
448 assert_se(oomd_fetch_cgroup_oom_preference(ctx, NULL) < 0);
449 assert_se(ctx->preference == MANAGED_OOM_PREFERENCE_NONE);
450 }
451 ctx = oomd_cgroup_context_free(ctx);
452
453 /* also check when only avoid is set to true */
454 if (test_xattrs) {
455 assert_se(cg_set_xattr(SYSTEMD_CGROUP_CONTROLLER, cgroup, "user.oomd_omit", "0", 1, 0) >= 0);
456 assert_se(cg_set_xattr(SYSTEMD_CGROUP_CONTROLLER, cgroup, "user.oomd_avoid", "1", 1, 0) >= 0);
457 assert_se(oomd_cgroup_context_acquire(cgroup, &ctx) == 0);
458 assert_se(oomd_fetch_cgroup_oom_preference(ctx, NULL) == 0);
459 assert_se(ctx->preference == MANAGED_OOM_PREFERENCE_AVOID);
460 ctx = oomd_cgroup_context_free(ctx);
461 }
462
463 /* Test the root cgroup */
464 /* Root cgroup is live and not made on demand like the cgroup the test runs in. It can have varying
465 * xattrs set already so let's read in the booleans first to get the final preference value. */
466 assert_se(oomd_cgroup_context_acquire("", &ctx) == 0);
467 root_xattrs = cg_get_xattr_bool(SYSTEMD_CGROUP_CONTROLLER, "", "user.oomd_omit");
468 root_pref = root_xattrs > 0 ? MANAGED_OOM_PREFERENCE_OMIT : MANAGED_OOM_PREFERENCE_NONE;
469 root_xattrs = cg_get_xattr_bool(SYSTEMD_CGROUP_CONTROLLER, "", "user.oomd_avoid");
470 root_pref = root_xattrs > 0 ? MANAGED_OOM_PREFERENCE_AVOID : MANAGED_OOM_PREFERENCE_NONE;
471 assert_se(oomd_fetch_cgroup_oom_preference(ctx, NULL) == 0);
472 assert_se(ctx->preference == root_pref);
473
474 assert_se(oomd_fetch_cgroup_oom_preference(ctx, "/herp.slice/derp.scope") == -EINVAL);
475
476 /* Assert that avoid/omit are not set if the cgroup and prefix are not
0b75493d 477 * owned by the same user. */
f05bcc18 478 if (test_xattrs && !empty_or_root(cgroup)) {
39f9eee8 479 ctx = oomd_cgroup_context_free(ctx);
f05bcc18 480 assert_se(cg_set_access(SYSTEMD_CGROUP_CONTROLLER, cgroup, 61183, 0) >= 0);
39f9eee8
NR
481 assert_se(oomd_cgroup_context_acquire(cgroup, &ctx) == 0);
482
483 assert_se(oomd_fetch_cgroup_oom_preference(ctx, NULL) == 0);
484 assert_se(ctx->preference == MANAGED_OOM_PREFERENCE_NONE);
485
486 assert_se(oomd_fetch_cgroup_oom_preference(ctx, ctx->path) == 0);
487 assert_se(ctx->preference == MANAGED_OOM_PREFERENCE_AVOID);
488 }
489}
490
61ff7397
AZ
491int main(void) {
492 int r;
493
494 test_setup_logging(LOG_DEBUG);
495
b037a6da 496 test_oomd_update_cgroup_contexts_between_hashmaps();
61ff7397
AZ
497 test_oomd_system_context_acquire();
498 test_oomd_pressure_above();
eeeaa422 499 test_oomd_mem_and_swap_free_below();
61ff7397
AZ
500 test_oomd_sort_cgroups();
501
502 /* The following tests operate on live cgroups */
503
504 r = enter_cgroup_root(NULL);
505 if (r < 0)
506 return log_tests_skipped_errno(r, "failed to enter a test cgroup scope");
507
508 test_oomd_cgroup_kill();
509 test_oomd_cgroup_context_acquire_and_insert();
39f9eee8 510 test_oomd_fetch_cgroup_oom_preference();
61ff7397
AZ
511
512 return 0;
513}