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
139
140
141
142
143
144
145
146
|
/* SPDX-License-Identifier: LGPL-2.1+ */
#include <stdio.h>
#include "cgroup.h"
#include "manager.h"
#include "rm-rf.h"
#include "tests.h"
#include "unit.h"
static int test_default_memory_low(void) {
_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_se(get_testdata_dir("units", &unit_dir) >= 0);
assert_se(set_unit_path(unit_dir) >= 0);
assert_se(runtime_dir = setup_fake_runtime_dir());
r = manager_new(UNIT_FILE_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_se(r >= 0);
assert_se(manager_startup(m, NULL, NULL) >= 0);
/* 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-explicit-ml.service sets MemoryLow=70, 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_se(manager_load_startable_unit_or_warn(m, "dml.slice", NULL, &dml) >= 0);
assert_se(manager_load_startable_unit_or_warn(m, "dml-passthrough.slice", NULL, &dml_passthrough) >= 0);
assert_se(UNIT_DEREF(dml_passthrough->slice) == dml);
assert_se(manager_load_startable_unit_or_warn(m, "dml-passthrough-empty.service", NULL, &dml_passthrough_empty) >= 0);
assert_se(UNIT_DEREF(dml_passthrough_empty->slice) == dml_passthrough);
assert_se(manager_load_startable_unit_or_warn(m, "dml-passthrough-set-dml.service", NULL, &dml_passthrough_set_dml) >= 0);
assert_se(UNIT_DEREF(dml_passthrough_set_dml->slice) == dml_passthrough);
assert_se(manager_load_startable_unit_or_warn(m, "dml-passthrough-set-ml.service", NULL, &dml_passthrough_set_ml) >= 0);
assert_se(UNIT_DEREF(dml_passthrough_set_ml->slice) == dml_passthrough);
assert_se(manager_load_startable_unit_or_warn(m, "dml-override.slice", NULL, &dml_override) >= 0);
assert_se(UNIT_DEREF(dml_override->slice) == dml);
assert_se(manager_load_startable_unit_or_warn(m, "dml-override-empty.service", NULL, &dml_override_empty) >= 0);
assert_se(UNIT_DEREF(dml_override_empty->slice) == dml_override);
assert_se(manager_load_startable_unit_or_warn(m, "dml-discard.slice", NULL, &dml_discard) >= 0);
assert_se(UNIT_DEREF(dml_discard->slice) == dml);
assert_se(manager_load_startable_unit_or_warn(m, "dml-discard-empty.service", NULL, &dml_discard_empty) >= 0);
assert_se(UNIT_DEREF(dml_discard_empty->slice) == dml_discard);
assert_se(manager_load_startable_unit_or_warn(m, "dml-discard-set-ml.service", NULL, &dml_discard_set_ml) >= 0);
assert_se(UNIT_DEREF(dml_discard_set_ml->slice) == dml_discard);
root = UNIT_DEREF(dml->slice);
assert_se(!UNIT_ISSET(root->slice));
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;
}
int main(int argc, char* argv[]) {
int rc = EXIT_SUCCESS;
test_setup_logging(LOG_DEBUG);
TEST_REQ_RUNNING_SYSTEMD(rc = test_default_memory_low());
return rc;
}
|