1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
|
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <stdio.h>
#include "cgroup.h"
#include "manager.h"
#include "rm-rf.h"
#include "tests.h"
#include "unit.h"
TEST_RET(default_memory_low, .sd_booted = true) {
_cleanup_(rm_rf_physical_and_freep) char *runtime_dir = NULL;
_cleanup_(manager_freep) Manager *m = NULL;
Unit *root, *dml,
*dml_passthrough, *dml_passthrough_empty, *dml_passthrough_set_dml, *dml_passthrough_set_ml,
*dml_override, *dml_override_empty,
*dml_discard, *dml_discard_empty, *dml_discard_set_ml;
uint64_t dml_tree_default;
int r;
r = enter_cgroup_subroot(NULL);
if (r == -ENOMEDIUM)
return log_tests_skipped("cgroupfs not available");
_cleanup_free_ char *unit_dir = NULL;
ASSERT_OK(get_testdata_dir("units", &unit_dir));
ASSERT_OK(set_unit_path(unit_dir));
assert_se(runtime_dir = setup_fake_runtime_dir());
r = manager_new(RUNTIME_SCOPE_USER, MANAGER_TEST_RUN_BASIC, &m);
if (IN_SET(r, -EPERM, -EACCES)) {
log_error_errno(r, "manager_new: %m");
return log_tests_skipped("cannot create manager");
}
ASSERT_OK(r);
ASSERT_OK(manager_startup(m, NULL, NULL, NULL));
/* dml.slice has DefaultMemoryLow=50. Beyond that, individual subhierarchies look like this:
*
* 1. dml-passthrough.slice sets MemoryLow=100. This should not affect its children, as only
* DefaultMemoryLow is propagated, not MemoryLow. As such, all leaf services should end up with
* memory.low as 50, inherited from dml.slice, *except* for dml-passthrough-set-ml.service, which
* should have the value of 0, as it has MemoryLow explicitly set.
*
* ┌───────────┐
* │ dml.slice │
* └─────┬─────┘
* MemoryLow=100
* ┌───────────┴───────────┐
* │ dml-passthrough.slice │
* └───────────┬───────────┘
* ┌───────────────────────────────────┼───────────────────────────────────┐
* no new settings DefaultMemoryLow=15 MemoryLow=0
* ┌───────────────┴───────────────┐ ┌────────────────┴────────────────┐ ┌───────────────┴────────────────┐
* │ dml-passthrough-empty.service │ │ dml-passthrough-set-dml.service │ │ dml-passthrough-set-ml.service │
* └───────────────────────────────┘ └─────────────────────────────────┘ └────────────────────────────────┘
*
* 2. dml-override.slice sets DefaultMemoryLow=10. As such, dml-override-empty.service should also
* end up with a memory.low of 10. dml-override.slice should still have a memory.low of 50.
*
* ┌───────────┐
* │ dml.slice │
* └─────┬─────┘
* DefaultMemoryLow=10
* ┌─────────┴──────────┐
* │ dml-override.slice │
* └─────────┬──────────┘
* no new settings
* ┌─────────────┴──────────────┐
* │ dml-override-empty.service │
* └────────────────────────────┘
*
* 3. dml-discard.slice sets DefaultMemoryLow= with no rvalue. As such,
* dml-discard-empty.service should end up with a value of 0.
* dml-discard-set-ml.service sets MemoryLow=15, and as such should have that override the
* reset DefaultMemoryLow value. dml-discard.slice should still have an eventual memory.low of 50.
*
* ┌───────────┐
* │ dml.slice │
* └─────┬─────┘
* DefaultMemoryLow=
* ┌─────────┴─────────┐
* │ dml-discard.slice │
* └─────────┬─────────┘
* ┌──────────────┴───────────────┐
* no new settings MemoryLow=15
* ┌─────────────┴─────────────┐ ┌─────────────┴──────────────┐
* │ dml-discard-empty.service │ │ dml-discard-set-ml.service │
* └───────────────────────────┘ └────────────────────────────┘
*/
ASSERT_OK(manager_load_startable_unit_or_warn(m, "dml.slice", NULL, &dml));
ASSERT_OK(manager_load_startable_unit_or_warn(m, "dml-passthrough.slice", NULL, &dml_passthrough));
assert_se(UNIT_GET_SLICE(dml_passthrough) == dml);
ASSERT_OK(manager_load_startable_unit_or_warn(m, "dml-passthrough-empty.service", NULL, &dml_passthrough_empty));
assert_se(UNIT_GET_SLICE(dml_passthrough_empty) == dml_passthrough);
ASSERT_OK(manager_load_startable_unit_or_warn(m, "dml-passthrough-set-dml.service", NULL, &dml_passthrough_set_dml));
assert_se(UNIT_GET_SLICE(dml_passthrough_set_dml) == dml_passthrough);
ASSERT_OK(manager_load_startable_unit_or_warn(m, "dml-passthrough-set-ml.service", NULL, &dml_passthrough_set_ml));
assert_se(UNIT_GET_SLICE(dml_passthrough_set_ml) == dml_passthrough);
ASSERT_OK(manager_load_startable_unit_or_warn(m, "dml-override.slice", NULL, &dml_override));
assert_se(UNIT_GET_SLICE(dml_override) == dml);
ASSERT_OK(manager_load_startable_unit_or_warn(m, "dml-override-empty.service", NULL, &dml_override_empty));
assert_se(UNIT_GET_SLICE(dml_override_empty) == dml_override);
ASSERT_OK(manager_load_startable_unit_or_warn(m, "dml-discard.slice", NULL, &dml_discard));
assert_se(UNIT_GET_SLICE(dml_discard) == dml);
ASSERT_OK(manager_load_startable_unit_or_warn(m, "dml-discard-empty.service", NULL, &dml_discard_empty));
assert_se(UNIT_GET_SLICE(dml_discard_empty) == dml_discard);
ASSERT_OK(manager_load_startable_unit_or_warn(m, "dml-discard-set-ml.service", NULL, &dml_discard_set_ml));
assert_se(UNIT_GET_SLICE(dml_discard_set_ml) == dml_discard);
assert_se(root = UNIT_GET_SLICE(dml));
assert_se(!UNIT_GET_SLICE(root));
assert_se(unit_get_ancestor_memory_low(root) == CGROUP_LIMIT_MIN);
assert_se(unit_get_ancestor_memory_low(dml) == CGROUP_LIMIT_MIN);
dml_tree_default = unit_get_cgroup_context(dml)->default_memory_low;
assert_se(dml_tree_default == 50);
assert_se(unit_get_ancestor_memory_low(dml_passthrough) == 100);
assert_se(unit_get_ancestor_memory_low(dml_passthrough_empty) == dml_tree_default);
assert_se(unit_get_ancestor_memory_low(dml_passthrough_set_dml) == 50);
assert_se(unit_get_ancestor_memory_low(dml_passthrough_set_ml) == 0);
assert_se(unit_get_ancestor_memory_low(dml_override) == dml_tree_default);
assert_se(unit_get_ancestor_memory_low(dml_override_empty) == 10);
assert_se(unit_get_ancestor_memory_low(dml_discard) == dml_tree_default);
assert_se(unit_get_ancestor_memory_low(dml_discard_empty) == CGROUP_LIMIT_MIN);
assert_se(unit_get_ancestor_memory_low(dml_discard_set_ml) == 15);
return 0;
}
DEFINE_TEST_MAIN(LOG_DEBUG);
|