File: | build-scan/../src/core/cgroup.c |
Warning: | line 1555, column 24 Potential leak of memory pointed to by 'p' |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* SPDX-License-Identifier: LGPL-2.1+ */ | |||
2 | ||||
3 | #include <fcntl.h> | |||
4 | #include <fnmatch.h> | |||
5 | ||||
6 | #include "alloc-util.h" | |||
7 | #include "blockdev-util.h" | |||
8 | #include "bpf-firewall.h" | |||
9 | #include "btrfs-util.h" | |||
10 | #include "bus-error.h" | |||
11 | #include "cgroup-util.h" | |||
12 | #include "cgroup.h" | |||
13 | #include "fd-util.h" | |||
14 | #include "fileio.h" | |||
15 | #include "fs-util.h" | |||
16 | #include "parse-util.h" | |||
17 | #include "path-util.h" | |||
18 | #include "process-util.h" | |||
19 | #include "procfs-util.h" | |||
20 | #include "special.h" | |||
21 | #include "stdio-util.h" | |||
22 | #include "string-table.h" | |||
23 | #include "string-util.h" | |||
24 | #include "virt.h" | |||
25 | ||||
26 | #define CGROUP_CPU_QUOTA_DEFAULT_PERIOD_USEC((usec_t) 100 * ((usec_t) 1000ULL)) ((usec_t) 100 * USEC_PER_MSEC((usec_t) 1000ULL)) | |||
27 | ||||
28 | bool_Bool manager_owns_root_cgroup(Manager *m) { | |||
29 | assert(m)do { if ((__builtin_expect(!!(!(m)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("m"), "../src/core/cgroup.c", 29, __PRETTY_FUNCTION__ ); } while (0); | |||
30 | ||||
31 | /* Returns true if we are managing the root cgroup. Note that it isn't sufficient to just check whether the | |||
32 | * group root path equals "/" since that will also be the case if CLONE_NEWCGROUP is in the mix. Since there's | |||
33 | * appears to be no nice way to detect whether we are in a CLONE_NEWCGROUP namespace we instead just check if | |||
34 | * we run in any kind of container virtualization. */ | |||
35 | ||||
36 | if (detect_container() > 0) | |||
37 | return false0; | |||
38 | ||||
39 | return empty_or_root(m->cgroup_root); | |||
40 | } | |||
41 | ||||
42 | bool_Bool unit_has_root_cgroup(Unit *u) { | |||
43 | assert(u)do { if ((__builtin_expect(!!(!(u)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("u"), "../src/core/cgroup.c", 43, __PRETTY_FUNCTION__ ); } while (0); | |||
44 | ||||
45 | /* Returns whether this unit manages the root cgroup. This will return true if this unit is the root slice and | |||
46 | * the manager manages the root cgroup. */ | |||
47 | ||||
48 | if (!manager_owns_root_cgroup(u->manager)) | |||
49 | return false0; | |||
50 | ||||
51 | return unit_has_name(u, SPECIAL_ROOT_SLICE"-.slice"); | |||
52 | } | |||
53 | ||||
54 | static void cgroup_compat_warn(void) { | |||
55 | static bool_Bool cgroup_compat_warned = false0; | |||
56 | ||||
57 | if (cgroup_compat_warned) | |||
58 | return; | |||
59 | ||||
60 | log_warning("cgroup compatibility translation between legacy and unified hierarchy settings activated. "({ int _level = (((4))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/core/cgroup.c", 61, __func__, "cgroup compatibility translation between legacy and unified hierarchy settings activated. " "See cgroup-compat debug messages for details.") : -abs(_e); }) | |||
61 | "See cgroup-compat debug messages for details.")({ int _level = (((4))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/core/cgroup.c", 61, __func__, "cgroup compatibility translation between legacy and unified hierarchy settings activated. " "See cgroup-compat debug messages for details.") : -abs(_e); }); | |||
62 | ||||
63 | cgroup_compat_warned = true1; | |||
64 | } | |||
65 | ||||
66 | #define log_cgroup_compat(unit, fmt, ...)do { cgroup_compat_warn(); ({ const Unit *_u = (unit); _u ? log_object_internal (7, 0, "../src/core/cgroup.c", 66, __func__, _u->manager-> unit_log_field, _u->id, _u->manager->invocation_log_field , _u->invocation_id_string, "cgroup-compat: " fmt, ...) : log_internal_realm (((LOG_REALM_SYSTEMD) << 10 | ((7))), 0, "../src/core/cgroup.c" , 66, __func__, "cgroup-compat: " fmt, ...); }); } while (0) do { \ | |||
67 | cgroup_compat_warn(); \ | |||
68 | log_unit_debug(unit, "cgroup-compat: " fmt, ##__VA_ARGS__)({ const Unit *_u = (unit); _u ? log_object_internal(7, 0, "../src/core/cgroup.c" , 68, __func__, _u->manager->unit_log_field, _u->id, _u->manager->invocation_log_field, _u->invocation_id_string , "cgroup-compat: " fmt, ##__VA_ARGS__) : log_internal_realm( ((LOG_REALM_SYSTEMD) << 10 | ((7))), 0, "../src/core/cgroup.c" , 68, __func__, "cgroup-compat: " fmt, ##__VA_ARGS__); }); \ | |||
69 | } while (false0) | |||
70 | ||||
71 | void cgroup_context_init(CGroupContext *c) { | |||
72 | assert(c)do { if ((__builtin_expect(!!(!(c)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("c"), "../src/core/cgroup.c", 72, __PRETTY_FUNCTION__ ); } while (0); | |||
73 | ||||
74 | /* Initialize everything to the kernel defaults. */ | |||
75 | ||||
76 | *c = (CGroupContext) { | |||
77 | .cpu_weight = CGROUP_WEIGHT_INVALID((uint64_t) -1), | |||
78 | .startup_cpu_weight = CGROUP_WEIGHT_INVALID((uint64_t) -1), | |||
79 | .cpu_quota_per_sec_usec = USEC_INFINITY((usec_t) -1), | |||
80 | .cpu_quota_period_usec = USEC_INFINITY((usec_t) -1), | |||
81 | ||||
82 | .cpu_shares = CGROUP_CPU_SHARES_INVALID((uint64_t) -1), | |||
83 | .startup_cpu_shares = CGROUP_CPU_SHARES_INVALID((uint64_t) -1), | |||
84 | ||||
85 | .memory_high = CGROUP_LIMIT_MAX((uint64_t) -1), | |||
86 | .memory_max = CGROUP_LIMIT_MAX((uint64_t) -1), | |||
87 | .memory_swap_max = CGROUP_LIMIT_MAX((uint64_t) -1), | |||
88 | ||||
89 | .memory_limit = CGROUP_LIMIT_MAX((uint64_t) -1), | |||
90 | ||||
91 | .io_weight = CGROUP_WEIGHT_INVALID((uint64_t) -1), | |||
92 | .startup_io_weight = CGROUP_WEIGHT_INVALID((uint64_t) -1), | |||
93 | ||||
94 | .blockio_weight = CGROUP_BLKIO_WEIGHT_INVALID((uint64_t) -1), | |||
95 | .startup_blockio_weight = CGROUP_BLKIO_WEIGHT_INVALID((uint64_t) -1), | |||
96 | ||||
97 | .tasks_max = CGROUP_LIMIT_MAX((uint64_t) -1), | |||
98 | }; | |||
99 | } | |||
100 | ||||
101 | void cgroup_context_free_device_allow(CGroupContext *c, CGroupDeviceAllow *a) { | |||
102 | assert(c)do { if ((__builtin_expect(!!(!(c)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("c"), "../src/core/cgroup.c", 102, __PRETTY_FUNCTION__ ); } while (0); | |||
103 | assert(a)do { if ((__builtin_expect(!!(!(a)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("a"), "../src/core/cgroup.c", 103, __PRETTY_FUNCTION__ ); } while (0); | |||
104 | ||||
105 | LIST_REMOVE(device_allow, c->device_allow, a)do { typeof(*(c->device_allow)) **_head = &(c->device_allow ), *_item = (a); do { if ((__builtin_expect(!!(!(_item)),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("_item"), "../src/core/cgroup.c" , 105, __PRETTY_FUNCTION__); } while (0); if (_item->device_allow_next ) _item->device_allow_next->device_allow_prev = _item-> device_allow_prev; if (_item->device_allow_prev) _item-> device_allow_prev->device_allow_next = _item->device_allow_next ; else { do { if ((__builtin_expect(!!(!(*_head == _item)),0) )) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("*_head == _item" ), "../src/core/cgroup.c", 105, __PRETTY_FUNCTION__); } while (0); *_head = _item->device_allow_next; } _item->device_allow_next = _item->device_allow_prev = ((void*)0); } while (0); | |||
106 | free(a->path); | |||
107 | free(a); | |||
108 | } | |||
109 | ||||
110 | void cgroup_context_free_io_device_weight(CGroupContext *c, CGroupIODeviceWeight *w) { | |||
111 | assert(c)do { if ((__builtin_expect(!!(!(c)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("c"), "../src/core/cgroup.c", 111, __PRETTY_FUNCTION__ ); } while (0); | |||
112 | assert(w)do { if ((__builtin_expect(!!(!(w)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("w"), "../src/core/cgroup.c", 112, __PRETTY_FUNCTION__ ); } while (0); | |||
113 | ||||
114 | LIST_REMOVE(device_weights, c->io_device_weights, w)do { typeof(*(c->io_device_weights)) **_head = &(c-> io_device_weights), *_item = (w); do { if ((__builtin_expect( !!(!(_item)),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ( "_item"), "../src/core/cgroup.c", 114, __PRETTY_FUNCTION__); } while (0); if (_item->device_weights_next) _item->device_weights_next ->device_weights_prev = _item->device_weights_prev; if ( _item->device_weights_prev) _item->device_weights_prev-> device_weights_next = _item->device_weights_next; else { do { if ((__builtin_expect(!!(!(*_head == _item)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("*_head == _item"), "../src/core/cgroup.c" , 114, __PRETTY_FUNCTION__); } while (0); *_head = _item-> device_weights_next; } _item->device_weights_next = _item-> device_weights_prev = ((void*)0); } while (0); | |||
115 | free(w->path); | |||
116 | free(w); | |||
117 | } | |||
118 | ||||
119 | void cgroup_context_free_io_device_latency(CGroupContext *c, CGroupIODeviceLatency *l) { | |||
120 | assert(c)do { if ((__builtin_expect(!!(!(c)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("c"), "../src/core/cgroup.c", 120, __PRETTY_FUNCTION__ ); } while (0); | |||
121 | assert(l)do { if ((__builtin_expect(!!(!(l)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("l"), "../src/core/cgroup.c", 121, __PRETTY_FUNCTION__ ); } while (0); | |||
122 | ||||
123 | LIST_REMOVE(device_latencies, c->io_device_latencies, l)do { typeof(*(c->io_device_latencies)) **_head = &(c-> io_device_latencies), *_item = (l); do { if ((__builtin_expect (!!(!(_item)),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("_item"), "../src/core/cgroup.c", 123, __PRETTY_FUNCTION__) ; } while (0); if (_item->device_latencies_next) _item-> device_latencies_next->device_latencies_prev = _item->device_latencies_prev ; if (_item->device_latencies_prev) _item->device_latencies_prev ->device_latencies_next = _item->device_latencies_next; else { do { if ((__builtin_expect(!!(!(*_head == _item)),0)) ) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("*_head == _item" ), "../src/core/cgroup.c", 123, __PRETTY_FUNCTION__); } while (0); *_head = _item->device_latencies_next; } _item->device_latencies_next = _item->device_latencies_prev = ((void*)0); } while (0); | |||
124 | free(l->path); | |||
125 | free(l); | |||
126 | } | |||
127 | ||||
128 | void cgroup_context_free_io_device_limit(CGroupContext *c, CGroupIODeviceLimit *l) { | |||
129 | assert(c)do { if ((__builtin_expect(!!(!(c)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("c"), "../src/core/cgroup.c", 129, __PRETTY_FUNCTION__ ); } while (0); | |||
130 | assert(l)do { if ((__builtin_expect(!!(!(l)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("l"), "../src/core/cgroup.c", 130, __PRETTY_FUNCTION__ ); } while (0); | |||
131 | ||||
132 | LIST_REMOVE(device_limits, c->io_device_limits, l)do { typeof(*(c->io_device_limits)) **_head = &(c-> io_device_limits), *_item = (l); do { if ((__builtin_expect(! !(!(_item)),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ( "_item"), "../src/core/cgroup.c", 132, __PRETTY_FUNCTION__); } while (0); if (_item->device_limits_next) _item->device_limits_next ->device_limits_prev = _item->device_limits_prev; if (_item ->device_limits_prev) _item->device_limits_prev->device_limits_next = _item->device_limits_next; else { do { if ((__builtin_expect (!!(!(*_head == _item)),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD , ("*_head == _item"), "../src/core/cgroup.c", 132, __PRETTY_FUNCTION__ ); } while (0); *_head = _item->device_limits_next; } _item ->device_limits_next = _item->device_limits_prev = ((void *)0); } while (0); | |||
133 | free(l->path); | |||
134 | free(l); | |||
135 | } | |||
136 | ||||
137 | void cgroup_context_free_blockio_device_weight(CGroupContext *c, CGroupBlockIODeviceWeight *w) { | |||
138 | assert(c)do { if ((__builtin_expect(!!(!(c)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("c"), "../src/core/cgroup.c", 138, __PRETTY_FUNCTION__ ); } while (0); | |||
139 | assert(w)do { if ((__builtin_expect(!!(!(w)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("w"), "../src/core/cgroup.c", 139, __PRETTY_FUNCTION__ ); } while (0); | |||
140 | ||||
141 | LIST_REMOVE(device_weights, c->blockio_device_weights, w)do { typeof(*(c->blockio_device_weights)) **_head = &( c->blockio_device_weights), *_item = (w); do { if ((__builtin_expect (!!(!(_item)),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("_item"), "../src/core/cgroup.c", 141, __PRETTY_FUNCTION__) ; } while (0); if (_item->device_weights_next) _item->device_weights_next ->device_weights_prev = _item->device_weights_prev; if ( _item->device_weights_prev) _item->device_weights_prev-> device_weights_next = _item->device_weights_next; else { do { if ((__builtin_expect(!!(!(*_head == _item)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("*_head == _item"), "../src/core/cgroup.c" , 141, __PRETTY_FUNCTION__); } while (0); *_head = _item-> device_weights_next; } _item->device_weights_next = _item-> device_weights_prev = ((void*)0); } while (0); | |||
142 | free(w->path); | |||
143 | free(w); | |||
144 | } | |||
145 | ||||
146 | void cgroup_context_free_blockio_device_bandwidth(CGroupContext *c, CGroupBlockIODeviceBandwidth *b) { | |||
147 | assert(c)do { if ((__builtin_expect(!!(!(c)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("c"), "../src/core/cgroup.c", 147, __PRETTY_FUNCTION__ ); } while (0); | |||
148 | assert(b)do { if ((__builtin_expect(!!(!(b)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("b"), "../src/core/cgroup.c", 148, __PRETTY_FUNCTION__ ); } while (0); | |||
149 | ||||
150 | LIST_REMOVE(device_bandwidths, c->blockio_device_bandwidths, b)do { typeof(*(c->blockio_device_bandwidths)) **_head = & (c->blockio_device_bandwidths), *_item = (b); do { if ((__builtin_expect (!!(!(_item)),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("_item"), "../src/core/cgroup.c", 150, __PRETTY_FUNCTION__) ; } while (0); if (_item->device_bandwidths_next) _item-> device_bandwidths_next->device_bandwidths_prev = _item-> device_bandwidths_prev; if (_item->device_bandwidths_prev) _item->device_bandwidths_prev->device_bandwidths_next = _item->device_bandwidths_next; else { do { if ((__builtin_expect (!!(!(*_head == _item)),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD , ("*_head == _item"), "../src/core/cgroup.c", 150, __PRETTY_FUNCTION__ ); } while (0); *_head = _item->device_bandwidths_next; } _item ->device_bandwidths_next = _item->device_bandwidths_prev = ((void*)0); } while (0); | |||
151 | free(b->path); | |||
152 | free(b); | |||
153 | } | |||
154 | ||||
155 | void cgroup_context_done(CGroupContext *c) { | |||
156 | assert(c)do { if ((__builtin_expect(!!(!(c)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("c"), "../src/core/cgroup.c", 156, __PRETTY_FUNCTION__ ); } while (0); | |||
157 | ||||
158 | while (c->io_device_weights) | |||
159 | cgroup_context_free_io_device_weight(c, c->io_device_weights); | |||
160 | ||||
161 | while (c->io_device_latencies) | |||
162 | cgroup_context_free_io_device_latency(c, c->io_device_latencies); | |||
163 | ||||
164 | while (c->io_device_limits) | |||
165 | cgroup_context_free_io_device_limit(c, c->io_device_limits); | |||
166 | ||||
167 | while (c->blockio_device_weights) | |||
168 | cgroup_context_free_blockio_device_weight(c, c->blockio_device_weights); | |||
169 | ||||
170 | while (c->blockio_device_bandwidths) | |||
171 | cgroup_context_free_blockio_device_bandwidth(c, c->blockio_device_bandwidths); | |||
172 | ||||
173 | while (c->device_allow) | |||
174 | cgroup_context_free_device_allow(c, c->device_allow); | |||
175 | ||||
176 | c->ip_address_allow = ip_address_access_free_all(c->ip_address_allow); | |||
177 | c->ip_address_deny = ip_address_access_free_all(c->ip_address_deny); | |||
178 | ||||
179 | cpu_set_reset(&c->cpuset_cpus); | |||
180 | cpu_set_reset(&c->cpuset_mems); | |||
181 | } | |||
182 | ||||
183 | void cgroup_context_dump(CGroupContext *c, FILE* f, const char *prefix) { | |||
184 | _cleanup_free___attribute__((cleanup(freep))) char *cpuset_cpus = NULL((void*)0); | |||
185 | _cleanup_free___attribute__((cleanup(freep))) char *cpuset_mems = NULL((void*)0); | |||
186 | CGroupIODeviceLimit *il; | |||
187 | CGroupIODeviceWeight *iw; | |||
188 | CGroupIODeviceLatency *l; | |||
189 | CGroupBlockIODeviceBandwidth *b; | |||
190 | CGroupBlockIODeviceWeight *w; | |||
191 | CGroupDeviceAllow *a; | |||
192 | IPAddressAccessItem *iaai; | |||
193 | char u[FORMAT_TIMESPAN_MAX64]; | |||
194 | char v[FORMAT_TIMESPAN_MAX64]; | |||
195 | ||||
196 | assert(c)do { if ((__builtin_expect(!!(!(c)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("c"), "../src/core/cgroup.c", 196, __PRETTY_FUNCTION__ ); } while (0); | |||
197 | assert(f)do { if ((__builtin_expect(!!(!(f)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("f"), "../src/core/cgroup.c", 197, __PRETTY_FUNCTION__ ); } while (0); | |||
198 | ||||
199 | prefix = strempty(prefix); | |||
200 | ||||
201 | cpuset_cpus = cpu_set_to_range_string(&c->cpuset_cpus); | |||
202 | cpuset_mems = cpu_set_to_range_string(&c->cpuset_mems); | |||
203 | ||||
204 | fprintf(f, | |||
205 | "%sCPUAccounting=%s\n" | |||
206 | "%sIOAccounting=%s\n" | |||
207 | "%sBlockIOAccounting=%s\n" | |||
208 | "%sMemoryAccounting=%s\n" | |||
209 | "%sTasksAccounting=%s\n" | |||
210 | "%sIPAccounting=%s\n" | |||
211 | "%sCPUWeight=%" PRIu64"l" "u" "\n" | |||
212 | "%sStartupCPUWeight=%" PRIu64"l" "u" "\n" | |||
213 | "%sCPUShares=%" PRIu64"l" "u" "\n" | |||
214 | "%sStartupCPUShares=%" PRIu64"l" "u" "\n" | |||
215 | "%sCPUQuotaPerSecSec=%s\n" | |||
216 | "%sCPUQuotaPeriodSec=%s\n" | |||
217 | "%sAllowedCPUs=%s\n" | |||
218 | "%sAllowedMemoryNodes=%s\n" | |||
219 | "%sIOWeight=%" PRIu64"l" "u" "\n" | |||
220 | "%sStartupIOWeight=%" PRIu64"l" "u" "\n" | |||
221 | "%sBlockIOWeight=%" PRIu64"l" "u" "\n" | |||
222 | "%sStartupBlockIOWeight=%" PRIu64"l" "u" "\n" | |||
223 | "%sDefaultMemoryMin=%" PRIu64"l" "u" "\n" | |||
224 | "%sDefaultMemoryLow=%" PRIu64"l" "u" "\n" | |||
225 | "%sMemoryMin=%" PRIu64"l" "u" "\n" | |||
226 | "%sMemoryLow=%" PRIu64"l" "u" "\n" | |||
227 | "%sMemoryHigh=%" PRIu64"l" "u" "\n" | |||
228 | "%sMemoryMax=%" PRIu64"l" "u" "\n" | |||
229 | "%sMemorySwapMax=%" PRIu64"l" "u" "\n" | |||
230 | "%sMemoryLimit=%" PRIu64"l" "u" "\n" | |||
231 | "%sTasksMax=%" PRIu64"l" "u" "\n" | |||
232 | "%sDevicePolicy=%s\n" | |||
233 | "%sDelegate=%s\n", | |||
234 | prefix, yes_no(c->cpu_accounting), | |||
235 | prefix, yes_no(c->io_accounting), | |||
236 | prefix, yes_no(c->blockio_accounting), | |||
237 | prefix, yes_no(c->memory_accounting), | |||
238 | prefix, yes_no(c->tasks_accounting), | |||
239 | prefix, yes_no(c->ip_accounting), | |||
240 | prefix, c->cpu_weight, | |||
241 | prefix, c->startup_cpu_weight, | |||
242 | prefix, c->cpu_shares, | |||
243 | prefix, c->startup_cpu_shares, | |||
244 | prefix, format_timespan(u, sizeof(u), c->cpu_quota_per_sec_usec, 1), | |||
245 | prefix, format_timespan(v, sizeof(v), c->cpu_quota_period_usec, 1), | |||
246 | prefix, cpuset_cpus, | |||
247 | prefix, cpuset_mems, | |||
248 | prefix, c->io_weight, | |||
249 | prefix, c->startup_io_weight, | |||
250 | prefix, c->blockio_weight, | |||
251 | prefix, c->startup_blockio_weight, | |||
252 | prefix, c->default_memory_min, | |||
253 | prefix, c->default_memory_low, | |||
254 | prefix, c->memory_min, | |||
255 | prefix, c->memory_low, | |||
256 | prefix, c->memory_high, | |||
257 | prefix, c->memory_max, | |||
258 | prefix, c->memory_swap_max, | |||
259 | prefix, c->memory_limit, | |||
260 | prefix, c->tasks_max, | |||
261 | prefix, cgroup_device_policy_to_string(c->device_policy), | |||
262 | prefix, yes_no(c->delegate)); | |||
263 | ||||
264 | if (c->delegate) { | |||
265 | _cleanup_free___attribute__((cleanup(freep))) char *t = NULL((void*)0); | |||
266 | ||||
267 | (void) cg_mask_to_string(c->delegate_controllers, &t); | |||
268 | ||||
269 | fprintf(f, "%sDelegateControllers=%s\n", | |||
270 | prefix, | |||
271 | strempty(t)); | |||
272 | } | |||
273 | ||||
274 | LIST_FOREACH(device_allow, a, c->device_allow)for ((a) = (c->device_allow); (a); (a) = (a)->device_allow_next ) | |||
275 | fprintf(f, | |||
276 | "%sDeviceAllow=%s %s%s%s\n", | |||
277 | prefix, | |||
278 | a->path, | |||
279 | a->r ? "r" : "", a->w ? "w" : "", a->m ? "m" : ""); | |||
280 | ||||
281 | LIST_FOREACH(device_weights, iw, c->io_device_weights)for ((iw) = (c->io_device_weights); (iw); (iw) = (iw)-> device_weights_next) | |||
282 | fprintf(f, | |||
283 | "%sIODeviceWeight=%s %" PRIu64"l" "u" "\n", | |||
284 | prefix, | |||
285 | iw->path, | |||
286 | iw->weight); | |||
287 | ||||
288 | LIST_FOREACH(device_latencies, l, c->io_device_latencies)for ((l) = (c->io_device_latencies); (l); (l) = (l)->device_latencies_next ) | |||
289 | fprintf(f, | |||
290 | "%sIODeviceLatencyTargetSec=%s %s\n", | |||
291 | prefix, | |||
292 | l->path, | |||
293 | format_timespan(u, sizeof(u), l->target_usec, 1)); | |||
294 | ||||
295 | LIST_FOREACH(device_limits, il, c->io_device_limits)for ((il) = (c->io_device_limits); (il); (il) = (il)->device_limits_next ) { | |||
296 | char buf[FORMAT_BYTES_MAX8]; | |||
297 | CGroupIOLimitType type; | |||
298 | ||||
299 | for (type = 0; type < _CGROUP_IO_LIMIT_TYPE_MAX; type++) | |||
300 | if (il->limits[type] != cgroup_io_limit_defaults[type]) | |||
301 | fprintf(f, | |||
302 | "%s%s=%s %s\n", | |||
303 | prefix, | |||
304 | cgroup_io_limit_type_to_string(type), | |||
305 | il->path, | |||
306 | format_bytes(buf, sizeof(buf), il->limits[type])); | |||
307 | } | |||
308 | ||||
309 | LIST_FOREACH(device_weights, w, c->blockio_device_weights)for ((w) = (c->blockio_device_weights); (w); (w) = (w)-> device_weights_next) | |||
310 | fprintf(f, | |||
311 | "%sBlockIODeviceWeight=%s %" PRIu64"l" "u", | |||
312 | prefix, | |||
313 | w->path, | |||
314 | w->weight); | |||
315 | ||||
316 | LIST_FOREACH(device_bandwidths, b, c->blockio_device_bandwidths)for ((b) = (c->blockio_device_bandwidths); (b); (b) = (b)-> device_bandwidths_next) { | |||
317 | char buf[FORMAT_BYTES_MAX8]; | |||
318 | ||||
319 | if (b->rbps != CGROUP_LIMIT_MAX((uint64_t) -1)) | |||
320 | fprintf(f, | |||
321 | "%sBlockIOReadBandwidth=%s %s\n", | |||
322 | prefix, | |||
323 | b->path, | |||
324 | format_bytes(buf, sizeof(buf), b->rbps)); | |||
325 | if (b->wbps != CGROUP_LIMIT_MAX((uint64_t) -1)) | |||
326 | fprintf(f, | |||
327 | "%sBlockIOWriteBandwidth=%s %s\n", | |||
328 | prefix, | |||
329 | b->path, | |||
330 | format_bytes(buf, sizeof(buf), b->wbps)); | |||
331 | } | |||
332 | ||||
333 | LIST_FOREACH(items, iaai, c->ip_address_allow)for ((iaai) = (c->ip_address_allow); (iaai); (iaai) = (iaai )->items_next) { | |||
334 | _cleanup_free___attribute__((cleanup(freep))) char *k = NULL((void*)0); | |||
335 | ||||
336 | (void) in_addr_to_string(iaai->family, &iaai->address, &k); | |||
337 | fprintf(f, "%sIPAddressAllow=%s/%u\n", prefix, strnull(k), iaai->prefixlen); | |||
338 | } | |||
339 | ||||
340 | LIST_FOREACH(items, iaai, c->ip_address_deny)for ((iaai) = (c->ip_address_deny); (iaai); (iaai) = (iaai )->items_next) { | |||
341 | _cleanup_free___attribute__((cleanup(freep))) char *k = NULL((void*)0); | |||
342 | ||||
343 | (void) in_addr_to_string(iaai->family, &iaai->address, &k); | |||
344 | fprintf(f, "%sIPAddressDeny=%s/%u\n", prefix, strnull(k), iaai->prefixlen); | |||
345 | } | |||
346 | } | |||
347 | ||||
348 | int cgroup_add_device_allow(CGroupContext *c, const char *dev, const char *mode) { | |||
349 | _cleanup_free___attribute__((cleanup(freep))) CGroupDeviceAllow *a = NULL((void*)0); | |||
350 | _cleanup_free___attribute__((cleanup(freep))) char *d = NULL((void*)0); | |||
351 | ||||
352 | assert(c)do { if ((__builtin_expect(!!(!(c)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("c"), "../src/core/cgroup.c", 352, __PRETTY_FUNCTION__ ); } while (0); | |||
353 | assert(dev)do { if ((__builtin_expect(!!(!(dev)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("dev"), "../src/core/cgroup.c", 353, __PRETTY_FUNCTION__ ); } while (0); | |||
354 | assert(isempty(mode) || in_charset(mode, "rwm"))do { if ((__builtin_expect(!!(!(isempty(mode) || in_charset(mode , "rwm"))),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("isempty(mode) || in_charset(mode, \"rwm\")" ), "../src/core/cgroup.c", 354, __PRETTY_FUNCTION__); } while (0); | |||
355 | ||||
356 | a = new(CGroupDeviceAllow, 1)((CGroupDeviceAllow*) malloc_multiply(sizeof(CGroupDeviceAllow ), (1))); | |||
357 | if (!a) | |||
358 | return -ENOMEM12; | |||
359 | ||||
360 | d = strdup(dev); | |||
361 | if (!d) | |||
362 | return -ENOMEM12; | |||
363 | ||||
364 | *a = (CGroupDeviceAllow) { | |||
365 | .path = TAKE_PTR(d)({ typeof(d) _ptr_ = (d); (d) = ((void*)0); _ptr_; }), | |||
366 | .r = isempty(mode) || !!strchr(mode, 'r'), | |||
367 | .w = isempty(mode) || !!strchr(mode, 'w'), | |||
368 | .m = isempty(mode) || !!strchr(mode, 'm'), | |||
369 | }; | |||
370 | ||||
371 | LIST_PREPEND(device_allow, c->device_allow, a)do { typeof(*(c->device_allow)) **_head = &(c->device_allow ), *_item = (a); do { if ((__builtin_expect(!!(!(_item)),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("_item"), "../src/core/cgroup.c" , 371, __PRETTY_FUNCTION__); } while (0); if ((_item->device_allow_next = *_head)) _item->device_allow_next->device_allow_prev = _item; _item->device_allow_prev = ((void*)0); *_head = _item ; } while (0); | |||
372 | TAKE_PTR(a)({ typeof(a) _ptr_ = (a); (a) = ((void*)0); _ptr_; }); | |||
373 | ||||
374 | return 0; | |||
375 | } | |||
376 | ||||
377 | #define UNIT_DEFINE_ANCESTOR_MEMORY_LOOKUP(entry)uint64_t unit_get_ancestor_entry(Unit *u) { CGroupContext *c; do { if ((__builtin_expect(!!(!(u)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("u"), "../src/core/cgroup.c", 377, __PRETTY_FUNCTION__ ); } while (0); c = unit_get_cgroup_context(u); if (c->entry_set ) return c->entry; while ((!!(u->slice).target)) { u = ( (u->slice).target); c = unit_get_cgroup_context(u); if (c-> default_entry_set) return c->default_entry; } return 0UL; } \ | |||
378 | uint64_t unit_get_ancestor_##entry(Unit *u) { \ | |||
379 | CGroupContext *c; \ | |||
380 | \ | |||
381 | /* 1. Is entry set in this unit? If so, use that. \ | |||
382 | * 2. Is the default for this entry set in any \ | |||
383 | * ancestor? If so, use that. \ | |||
384 | * 3. Otherwise, return CGROUP_LIMIT_MIN. */ \ | |||
385 | \ | |||
386 | assert(u)do { if ((__builtin_expect(!!(!(u)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("u"), "../src/core/cgroup.c", 386, __PRETTY_FUNCTION__ ); } while (0); \ | |||
387 | \ | |||
388 | c = unit_get_cgroup_context(u); \ | |||
389 | \ | |||
390 | if (c->entry##_set) \ | |||
391 | return c->entry; \ | |||
392 | \ | |||
393 | while (UNIT_ISSET(u->slice)(!!(u->slice).target)) { \ | |||
394 | u = UNIT_DEREF(u->slice)((u->slice).target); \ | |||
395 | c = unit_get_cgroup_context(u); \ | |||
396 | \ | |||
397 | if (c->default_##entry##_set) \ | |||
398 | return c->default_##entry; \ | |||
399 | } \ | |||
400 | \ | |||
401 | /* We've reached the root, but nobody had default for \ | |||
402 | * this entry set, so set it to the kernel default. */ \ | |||
403 | return CGROUP_LIMIT_MIN0UL; \ | |||
404 | } | |||
405 | ||||
406 | UNIT_DEFINE_ANCESTOR_MEMORY_LOOKUP(memory_low)uint64_t unit_get_ancestor_memory_low(Unit *u) { CGroupContext *c; do { if ((__builtin_expect(!!(!(u)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("u"), "../src/core/cgroup.c", 406, __PRETTY_FUNCTION__ ); } while (0); c = unit_get_cgroup_context(u); if (c->memory_low_set ) return c->memory_low; while ((!!(u->slice).target)) { u = ((u->slice).target); c = unit_get_cgroup_context(u); if (c->default_memory_low_set) return c->default_memory_low ; } return 0UL; }; | |||
407 | UNIT_DEFINE_ANCESTOR_MEMORY_LOOKUP(memory_min)uint64_t unit_get_ancestor_memory_min(Unit *u) { CGroupContext *c; do { if ((__builtin_expect(!!(!(u)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("u"), "../src/core/cgroup.c", 407, __PRETTY_FUNCTION__ ); } while (0); c = unit_get_cgroup_context(u); if (c->memory_min_set ) return c->memory_min; while ((!!(u->slice).target)) { u = ((u->slice).target); c = unit_get_cgroup_context(u); if (c->default_memory_min_set) return c->default_memory_min ; } return 0UL; }; | |||
408 | ||||
409 | static int lookup_block_device(const char *p, dev_t *ret) { | |||
410 | struct stat st; | |||
411 | int r; | |||
412 | ||||
413 | assert(p)do { if ((__builtin_expect(!!(!(p)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("p"), "../src/core/cgroup.c", 413, __PRETTY_FUNCTION__ ); } while (0); | |||
414 | assert(ret)do { if ((__builtin_expect(!!(!(ret)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("ret"), "../src/core/cgroup.c", 414, __PRETTY_FUNCTION__ ); } while (0); | |||
415 | ||||
416 | if (stat(p, &st) < 0) | |||
417 | return log_warning_errno(errno, "Couldn't stat device '%s': %m", p)({ int _level = ((4)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/core/cgroup.c", 417, __func__, "Couldn't stat device '%s': %m" , p) : -abs(_e); }); | |||
418 | ||||
419 | if (S_ISBLK(st.st_mode)((((st.st_mode)) & 0170000) == (0060000))) | |||
420 | *ret = st.st_rdev; | |||
421 | else if (major(st.st_dev)gnu_dev_major (st.st_dev) != 0) | |||
422 | *ret = st.st_dev; /* If this is not a device node then use the block device this file is stored on */ | |||
423 | else { | |||
424 | /* If this is btrfs, getting the backing block device is a bit harder */ | |||
425 | r = btrfs_get_block_device(p, ret); | |||
426 | if (r < 0 && r != -ENOTTY25) | |||
427 | return log_warning_errno(r, "Failed to determine block device backing btrfs file system '%s': %m", p)({ int _level = ((4)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/core/cgroup.c", 427, __func__, "Failed to determine block device backing btrfs file system '%s': %m" , p) : -abs(_e); }); | |||
428 | if (r == -ENOTTY25) { | |||
429 | log_warning("'%s' is not a block device node, and file system block device cannot be determined or is not local.", p)({ int _level = (((4))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/core/cgroup.c", 429, __func__, "'%s' is not a block device node, and file system block device cannot be determined or is not local." , p) : -abs(_e); }); | |||
430 | return -ENODEV19; | |||
431 | } | |||
432 | } | |||
433 | ||||
434 | /* If this is a LUKS device, try to get the originating block device */ | |||
435 | (void) block_get_originating(*ret, ret); | |||
436 | ||||
437 | /* If this is a partition, try to get the originating block device */ | |||
438 | (void) block_get_whole_disk(*ret, ret); | |||
439 | return 0; | |||
440 | } | |||
441 | ||||
442 | static int whitelist_device(const char *path, const char *node, const char *acc) { | |||
443 | char buf[2+DECIMAL_STR_MAX(dev_t)(2+(sizeof(dev_t) <= 1 ? 3 : sizeof(dev_t) <= 2 ? 5 : sizeof (dev_t) <= 4 ? 10 : sizeof(dev_t) <= 8 ? 20 : sizeof(int [-2*(sizeof(dev_t) > 8)])))*2+2+4]; | |||
444 | struct stat st; | |||
445 | bool_Bool ignore_notfound; | |||
446 | int r; | |||
447 | ||||
448 | assert(path)do { if ((__builtin_expect(!!(!(path)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("path"), "../src/core/cgroup.c", 448, __PRETTY_FUNCTION__ ); } while (0); | |||
449 | assert(acc)do { if ((__builtin_expect(!!(!(acc)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("acc"), "../src/core/cgroup.c", 449, __PRETTY_FUNCTION__ ); } while (0); | |||
450 | ||||
451 | if (node[0] == '-') { | |||
452 | /* Non-existent paths starting with "-" must be silently ignored */ | |||
453 | node++; | |||
454 | ignore_notfound = true1; | |||
455 | } else | |||
456 | ignore_notfound = false0; | |||
457 | ||||
458 | if (stat(node, &st) < 0) { | |||
459 | if (errno(*__errno_location ()) == ENOENT2 && ignore_notfound) | |||
460 | return 0; | |||
461 | ||||
462 | return log_warning_errno(errno, "Couldn't stat device %s: %m", node)({ int _level = ((4)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/core/cgroup.c", 462, __func__, "Couldn't stat device %s: %m" , node) : -abs(_e); }); | |||
463 | } | |||
464 | ||||
465 | if (!S_ISCHR(st.st_mode)((((st.st_mode)) & 0170000) == (0020000)) && !S_ISBLK(st.st_mode)((((st.st_mode)) & 0170000) == (0060000))) { | |||
466 | log_warning("%s is not a device.", node)({ int _level = (((4))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/core/cgroup.c", 466, __func__, "%s is not a device." , node) : -abs(_e); }); | |||
467 | return -ENODEV19; | |||
468 | } | |||
469 | ||||
470 | sprintf(buf, | |||
471 | "%c %u:%u %s", | |||
472 | S_ISCHR(st.st_mode)((((st.st_mode)) & 0170000) == (0020000)) ? 'c' : 'b', | |||
473 | major(st.st_rdev)gnu_dev_major (st.st_rdev), minor(st.st_rdev)gnu_dev_minor (st.st_rdev), | |||
474 | acc); | |||
475 | ||||
476 | r = cg_set_attribute("devices", path, "devices.allow", buf); | |||
477 | if (r < 0) | |||
478 | log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EINVAL, -EACCES) ? LOG_DEBUG : LOG_WARNING, r,({ int _level = ((({ _Bool _found = 0; static __attribute__ ( (unused)) char _static_assert__macros_need_to_be_extended[20 - sizeof((int[]){-2, -30, -22, -13})/sizeof(int)]; switch(r) { case -2: case -30: case -22: case -13: _found = 1; break; default : break; } _found; }) ? 7 : 4)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/core/cgroup.c", 479, __func__, "Failed to set devices.allow on %s: %m" , path) : -abs(_e); }) | |||
479 | "Failed to set devices.allow on %s: %m", path)({ int _level = ((({ _Bool _found = 0; static __attribute__ ( (unused)) char _static_assert__macros_need_to_be_extended[20 - sizeof((int[]){-2, -30, -22, -13})/sizeof(int)]; switch(r) { case -2: case -30: case -22: case -13: _found = 1; break; default : break; } _found; }) ? 7 : 4)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/core/cgroup.c", 479, __func__, "Failed to set devices.allow on %s: %m" , path) : -abs(_e); }); | |||
480 | ||||
481 | return r; | |||
482 | } | |||
483 | ||||
484 | static int whitelist_major(const char *path, const char *name, char type, const char *acc) { | |||
485 | _cleanup_fclose___attribute__((cleanup(fclosep))) FILE *f = NULL((void*)0); | |||
486 | char line[LINE_MAX2048]; | |||
487 | bool_Bool good = false0; | |||
488 | int r; | |||
489 | ||||
490 | assert(path)do { if ((__builtin_expect(!!(!(path)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("path"), "../src/core/cgroup.c", 490, __PRETTY_FUNCTION__ ); } while (0); | |||
491 | assert(acc)do { if ((__builtin_expect(!!(!(acc)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("acc"), "../src/core/cgroup.c", 491, __PRETTY_FUNCTION__ ); } while (0); | |||
492 | assert(IN_SET(type, 'b', 'c'))do { if ((__builtin_expect(!!(!(({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended[20 - sizeof((int[]){'b', 'c'})/sizeof(int)]; switch(type) { case 'b': case 'c': _found = 1; break; default: break; } _found; } ))),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("IN_SET(type, 'b', 'c')" ), "../src/core/cgroup.c", 492, __PRETTY_FUNCTION__); } while (0); | |||
493 | ||||
494 | f = fopen("/proc/devices", "re"); | |||
495 | if (!f) | |||
496 | return log_warning_errno(errno, "Cannot open /proc/devices to resolve %s (%c): %m", name, type)({ int _level = ((4)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/core/cgroup.c", 496, __func__, "Cannot open /proc/devices to resolve %s (%c): %m" , name, type) : -abs(_e); }); | |||
497 | ||||
498 | FOREACH_LINE(line, f, goto fail)for (;;) if (!fgets(line, sizeof(line), f)) { if (ferror(f)) { goto fail; } break; } else { | |||
499 | char buf[2+DECIMAL_STR_MAX(unsigned)(2+(sizeof(unsigned) <= 1 ? 3 : sizeof(unsigned) <= 2 ? 5 : sizeof(unsigned) <= 4 ? 10 : sizeof(unsigned) <= 8 ? 20 : sizeof(int[-2*(sizeof(unsigned) > 8)])))+3+4], *p, *w; | |||
500 | unsigned maj; | |||
501 | ||||
502 | truncate_nl(line); | |||
503 | ||||
504 | if (type == 'c' && streq(line, "Character devices:")(strcmp((line),("Character devices:")) == 0)) { | |||
505 | good = true1; | |||
506 | continue; | |||
507 | } | |||
508 | ||||
509 | if (type == 'b' && streq(line, "Block devices:")(strcmp((line),("Block devices:")) == 0)) { | |||
510 | good = true1; | |||
511 | continue; | |||
512 | } | |||
513 | ||||
514 | if (isempty(line)) { | |||
515 | good = false0; | |||
516 | continue; | |||
517 | } | |||
518 | ||||
519 | if (!good) | |||
520 | continue; | |||
521 | ||||
522 | p = strstrip(line); | |||
523 | ||||
524 | w = strpbrk(p, WHITESPACE" \t\n\r"); | |||
525 | if (!w) | |||
526 | continue; | |||
527 | *w = 0; | |||
528 | ||||
529 | r = safe_atou(p, &maj); | |||
530 | if (r < 0) | |||
531 | continue; | |||
532 | if (maj <= 0) | |||
533 | continue; | |||
534 | ||||
535 | w++; | |||
536 | w += strspn(w, WHITESPACE" \t\n\r"); | |||
537 | ||||
538 | if (fnmatch(name, w, 0) != 0) | |||
539 | continue; | |||
540 | ||||
541 | sprintf(buf, | |||
542 | "%c %u:* %s", | |||
543 | type, | |||
544 | maj, | |||
545 | acc); | |||
546 | ||||
547 | r = cg_set_attribute("devices", path, "devices.allow", buf); | |||
548 | if (r < 0) | |||
549 | log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EINVAL, -EACCES) ? LOG_DEBUG : LOG_WARNING, r,({ int _level = ((({ _Bool _found = 0; static __attribute__ ( (unused)) char _static_assert__macros_need_to_be_extended[20 - sizeof((int[]){-2, -30, -22, -13})/sizeof(int)]; switch(r) { case -2: case -30: case -22: case -13: _found = 1; break; default : break; } _found; }) ? 7 : 4)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/core/cgroup.c", 550, __func__, "Failed to set devices.allow on %s: %m" , path) : -abs(_e); }) | |||
550 | "Failed to set devices.allow on %s: %m", path)({ int _level = ((({ _Bool _found = 0; static __attribute__ ( (unused)) char _static_assert__macros_need_to_be_extended[20 - sizeof((int[]){-2, -30, -22, -13})/sizeof(int)]; switch(r) { case -2: case -30: case -22: case -13: _found = 1; break; default : break; } _found; }) ? 7 : 4)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/core/cgroup.c", 550, __func__, "Failed to set devices.allow on %s: %m" , path) : -abs(_e); }); | |||
551 | } | |||
552 | ||||
553 | return 0; | |||
554 | ||||
555 | fail: | |||
556 | return log_warning_errno(errno, "Failed to read /proc/devices: %m")({ int _level = ((4)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/core/cgroup.c", 556, __func__, "Failed to read /proc/devices: %m" ) : -abs(_e); }); | |||
557 | } | |||
558 | ||||
559 | static bool_Bool cgroup_context_has_cpu_weight(CGroupContext *c) { | |||
560 | return c->cpu_weight != CGROUP_WEIGHT_INVALID((uint64_t) -1) || | |||
561 | c->startup_cpu_weight != CGROUP_WEIGHT_INVALID((uint64_t) -1); | |||
562 | } | |||
563 | ||||
564 | static bool_Bool cgroup_context_has_cpu_shares(CGroupContext *c) { | |||
565 | return c->cpu_shares != CGROUP_CPU_SHARES_INVALID((uint64_t) -1) || | |||
566 | c->startup_cpu_shares != CGROUP_CPU_SHARES_INVALID((uint64_t) -1); | |||
567 | } | |||
568 | ||||
569 | static uint64_t cgroup_context_cpu_weight(CGroupContext *c, ManagerState state) { | |||
570 | if (IN_SET(state, MANAGER_STARTING, MANAGER_INITIALIZING)({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){MANAGER_STARTING, MANAGER_INITIALIZING}) /sizeof(int)]; switch(state) { case MANAGER_STARTING: case MANAGER_INITIALIZING : _found = 1; break; default: break; } _found; }) && | |||
571 | c->startup_cpu_weight != CGROUP_WEIGHT_INVALID((uint64_t) -1)) | |||
572 | return c->startup_cpu_weight; | |||
573 | else if (c->cpu_weight != CGROUP_WEIGHT_INVALID((uint64_t) -1)) | |||
574 | return c->cpu_weight; | |||
575 | else | |||
576 | return CGROUP_WEIGHT_DEFAULT100UL; | |||
577 | } | |||
578 | ||||
579 | static uint64_t cgroup_context_cpu_shares(CGroupContext *c, ManagerState state) { | |||
580 | if (IN_SET(state, MANAGER_STARTING, MANAGER_INITIALIZING)({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){MANAGER_STARTING, MANAGER_INITIALIZING}) /sizeof(int)]; switch(state) { case MANAGER_STARTING: case MANAGER_INITIALIZING : _found = 1; break; default: break; } _found; }) && | |||
581 | c->startup_cpu_shares != CGROUP_CPU_SHARES_INVALID((uint64_t) -1)) | |||
582 | return c->startup_cpu_shares; | |||
583 | else if (c->cpu_shares != CGROUP_CPU_SHARES_INVALID((uint64_t) -1)) | |||
584 | return c->cpu_shares; | |||
585 | else | |||
586 | return CGROUP_CPU_SHARES_DEFAULT1024UL; | |||
587 | } | |||
588 | ||||
589 | usec_t cgroup_cpu_adjust_period(usec_t period, usec_t quota, usec_t resolution, usec_t max_period) { | |||
590 | /* kernel uses a minimum resolution of 1ms, so both period and (quota * period) | |||
591 | * need to be higher than that boundary. quota is specified in USecPerSec. | |||
592 | * Additionally, period must be at most max_period. */ | |||
593 | assert(quota > 0)do { if ((__builtin_expect(!!(!(quota > 0)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("quota > 0"), "../src/core/cgroup.c", 593, __PRETTY_FUNCTION__); } while (0); | |||
594 | ||||
595 | return MIN(MAX3(period, resolution, resolution * USEC_PER_SEC / quota), max_period)__extension__ ({ const typeof((__extension__ ({ const typeof( period) _c = __extension__ ({ const typeof((period)) __unique_prefix_A245 = ((period)); const typeof((resolution)) __unique_prefix_B246 = ((resolution)); __unique_prefix_A245 > __unique_prefix_B246 ? __unique_prefix_A245 : __unique_prefix_B246; }); __extension__ ({ const typeof((_c)) __unique_prefix_A247 = ((_c)); const typeof ((resolution * ((usec_t) 1000000ULL) / quota)) __unique_prefix_B248 = ((resolution * ((usec_t) 1000000ULL) / quota)); __unique_prefix_A247 > __unique_prefix_B248 ? __unique_prefix_A247 : __unique_prefix_B248 ; }); }))) __unique_prefix_A249 = ((__extension__ ({ const typeof (period) _c = __extension__ ({ const typeof((period)) __unique_prefix_A245 = ((period)); const typeof((resolution)) __unique_prefix_B246 = ((resolution)); __unique_prefix_A245 > __unique_prefix_B246 ? __unique_prefix_A245 : __unique_prefix_B246; }); __extension__ ({ const typeof((_c)) __unique_prefix_A247 = ((_c)); const typeof ((resolution * ((usec_t) 1000000ULL) / quota)) __unique_prefix_B248 = ((resolution * ((usec_t) 1000000ULL) / quota)); __unique_prefix_A247 > __unique_prefix_B248 ? __unique_prefix_A247 : __unique_prefix_B248 ; }); }))); const typeof((max_period)) __unique_prefix_B250 = ((max_period)); __unique_prefix_A249 < __unique_prefix_B250 ? __unique_prefix_A249 : __unique_prefix_B250; }); | |||
596 | } | |||
597 | ||||
598 | static usec_t cgroup_cpu_adjust_period_and_log(Unit *u, usec_t period, usec_t quota) { | |||
599 | usec_t new_period; | |||
600 | ||||
601 | if (quota == USEC_INFINITY((usec_t) -1)) | |||
602 | /* Always use default period for infinity quota. */ | |||
603 | return CGROUP_CPU_QUOTA_DEFAULT_PERIOD_USEC((usec_t) 100 * ((usec_t) 1000ULL)); | |||
604 | ||||
605 | if (period == USEC_INFINITY((usec_t) -1)) | |||
606 | /* Default period was requested. */ | |||
607 | period = CGROUP_CPU_QUOTA_DEFAULT_PERIOD_USEC((usec_t) 100 * ((usec_t) 1000ULL)); | |||
608 | ||||
609 | /* Clamp to interval [1ms, 1s] */ | |||
610 | new_period = cgroup_cpu_adjust_period(period, quota, USEC_PER_MSEC((usec_t) 1000ULL), USEC_PER_SEC((usec_t) 1000000ULL)); | |||
611 | ||||
612 | if (new_period != period) { | |||
613 | char v[FORMAT_TIMESPAN_MAX64]; | |||
614 | log_unit_full(u, u->warned_clamping_cpu_quota_period ? LOG_DEBUG : LOG_WARNING, 0,({ const Unit *_u = (u); _u ? log_object_internal(u->warned_clamping_cpu_quota_period ? 7 : 4, 0, "../src/core/cgroup.c", 616, __func__, _u->manager ->unit_log_field, _u->id, _u->manager->invocation_log_field , _u->invocation_id_string, "Clamping CPU interval for cpu.max: period is now %s" , format_timespan(v, sizeof(v), new_period, 1)) : log_internal_realm (((LOG_REALM_SYSTEMD) << 10 | ((u->warned_clamping_cpu_quota_period ? 7 : 4))), 0, "../src/core/cgroup.c", 616, __func__, "Clamping CPU interval for cpu.max: period is now %s" , format_timespan(v, sizeof(v), new_period, 1)); }) | |||
615 | "Clamping CPU interval for cpu.max: period is now %s",({ const Unit *_u = (u); _u ? log_object_internal(u->warned_clamping_cpu_quota_period ? 7 : 4, 0, "../src/core/cgroup.c", 616, __func__, _u->manager ->unit_log_field, _u->id, _u->manager->invocation_log_field , _u->invocation_id_string, "Clamping CPU interval for cpu.max: period is now %s" , format_timespan(v, sizeof(v), new_period, 1)) : log_internal_realm (((LOG_REALM_SYSTEMD) << 10 | ((u->warned_clamping_cpu_quota_period ? 7 : 4))), 0, "../src/core/cgroup.c", 616, __func__, "Clamping CPU interval for cpu.max: period is now %s" , format_timespan(v, sizeof(v), new_period, 1)); }) | |||
616 | format_timespan(v, sizeof(v), new_period, 1))({ const Unit *_u = (u); _u ? log_object_internal(u->warned_clamping_cpu_quota_period ? 7 : 4, 0, "../src/core/cgroup.c", 616, __func__, _u->manager ->unit_log_field, _u->id, _u->manager->invocation_log_field , _u->invocation_id_string, "Clamping CPU interval for cpu.max: period is now %s" , format_timespan(v, sizeof(v), new_period, 1)) : log_internal_realm (((LOG_REALM_SYSTEMD) << 10 | ((u->warned_clamping_cpu_quota_period ? 7 : 4))), 0, "../src/core/cgroup.c", 616, __func__, "Clamping CPU interval for cpu.max: period is now %s" , format_timespan(v, sizeof(v), new_period, 1)); }); | |||
617 | u->warned_clamping_cpu_quota_period = true1; | |||
618 | } | |||
619 | ||||
620 | return new_period; | |||
621 | } | |||
622 | ||||
623 | static void cgroup_apply_unified_cpu_config(Unit *u, uint64_t weight, uint64_t quota, usec_t period) { | |||
624 | char buf[MAX(DECIMAL_STR_MAX(uint64_t) + 1, (DECIMAL_STR_MAX(usec_t) + 1) * 2)__extension__ ({ const typeof(((2+(sizeof(uint64_t) <= 1 ? 3 : sizeof(uint64_t) <= 2 ? 5 : sizeof(uint64_t) <= 4 ? 10 : sizeof(uint64_t) <= 8 ? 20 : sizeof(int[-2*(sizeof(uint64_t ) > 8)]))) + 1)) __unique_prefix_A251 = (((2+(sizeof(uint64_t ) <= 1 ? 3 : sizeof(uint64_t) <= 2 ? 5 : sizeof(uint64_t ) <= 4 ? 10 : sizeof(uint64_t) <= 8 ? 20 : sizeof(int[- 2*(sizeof(uint64_t) > 8)]))) + 1)); const typeof((((2+(sizeof (usec_t) <= 1 ? 3 : sizeof(usec_t) <= 2 ? 5 : sizeof(usec_t ) <= 4 ? 10 : sizeof(usec_t) <= 8 ? 20 : sizeof(int[-2* (sizeof(usec_t) > 8)]))) + 1) * 2)) __unique_prefix_B252 = ((((2+(sizeof(usec_t) <= 1 ? 3 : sizeof(usec_t) <= 2 ? 5 : sizeof(usec_t) <= 4 ? 10 : sizeof(usec_t) <= 8 ? 20 : sizeof(int[-2*(sizeof(usec_t) > 8)]))) + 1) * 2)); __unique_prefix_A251 > __unique_prefix_B252 ? __unique_prefix_A251 : __unique_prefix_B252 ; })]; | |||
625 | int r; | |||
626 | ||||
627 | xsprintf(buf, "%" PRIu64 "\n", weight)do { if ((__builtin_expect(!!(!(((size_t) snprintf(buf, __extension__ (__builtin_choose_expr( !__builtin_types_compatible_p(typeof (buf), typeof(&*(buf))), sizeof(buf)/sizeof((buf)[0]), (( void)0))), "%" "l" "u" "\n", weight) < (__extension__ (__builtin_choose_expr ( !__builtin_types_compatible_p(typeof(buf), typeof(&*(buf ))), sizeof(buf)/sizeof((buf)[0]), ((void)0))))))),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("xsprintf: " "buf" "[] must be big enough" ), "../src/core/cgroup.c", 627, __PRETTY_FUNCTION__); } while (0); | |||
628 | r = cg_set_attribute("cpu", u->cgroup_path, "cpu.weight", buf); | |||
629 | if (r < 0) | |||
630 | log_unit_full(u, IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r,({ const Unit *_u = (u); _u ? log_object_internal(({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){-2, -30, -13})/sizeof(int)]; switch(r) { case -2: case -30: case -13: _found = 1; break; default: break ; } _found; }) ? 7 : 4, r, "../src/core/cgroup.c", 631, __func__ , _u->manager->unit_log_field, _u->id, _u->manager ->invocation_log_field, _u->invocation_id_string, "Failed to set cpu.weight: %m" ) : log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((( { _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){-2, -30, -13})/sizeof(int)]; switch(r) { case -2: case -30: case -13: _found = 1; break; default: break ; } _found; }) ? 7 : 4))), r, "../src/core/cgroup.c", 631, __func__ , "Failed to set cpu.weight: %m"); }) | |||
631 | "Failed to set cpu.weight: %m")({ const Unit *_u = (u); _u ? log_object_internal(({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){-2, -30, -13})/sizeof(int)]; switch(r) { case -2: case -30: case -13: _found = 1; break; default: break ; } _found; }) ? 7 : 4, r, "../src/core/cgroup.c", 631, __func__ , _u->manager->unit_log_field, _u->id, _u->manager ->invocation_log_field, _u->invocation_id_string, "Failed to set cpu.weight: %m" ) : log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((( { _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){-2, -30, -13})/sizeof(int)]; switch(r) { case -2: case -30: case -13: _found = 1; break; default: break ; } _found; }) ? 7 : 4))), r, "../src/core/cgroup.c", 631, __func__ , "Failed to set cpu.weight: %m"); }); | |||
632 | ||||
633 | period = cgroup_cpu_adjust_period_and_log(u, period, quota); | |||
634 | if (quota != USEC_INFINITY((usec_t) -1)) | |||
635 | xsprintf(buf, USEC_FMT " " USEC_FMT "\n",do { if ((__builtin_expect(!!(!(((size_t) snprintf(buf, __extension__ (__builtin_choose_expr( !__builtin_types_compatible_p(typeof (buf), typeof(&*(buf))), sizeof(buf)/sizeof((buf)[0]), (( void)0))), "%" "l" "u" " " "%" "l" "u" "\n", __extension__ ({ const typeof((quota * period / ((usec_t) 1000000ULL))) __unique_prefix_A253 = ((quota * period / ((usec_t) 1000000ULL))); const typeof(( ((usec_t) 1000ULL))) __unique_prefix_B254 = ((((usec_t) 1000ULL ))); __unique_prefix_A253 > __unique_prefix_B254 ? __unique_prefix_A253 : __unique_prefix_B254; }), period) < (__extension__ (__builtin_choose_expr ( !__builtin_types_compatible_p(typeof(buf), typeof(&*(buf ))), sizeof(buf)/sizeof((buf)[0]), ((void)0))))))),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("xsprintf: " "buf" "[] must be big enough" ), "../src/core/cgroup.c", 636, __PRETTY_FUNCTION__); } while (0) | |||
636 | MAX(quota * period / USEC_PER_SEC, USEC_PER_MSEC), period)do { if ((__builtin_expect(!!(!(((size_t) snprintf(buf, __extension__ (__builtin_choose_expr( !__builtin_types_compatible_p(typeof (buf), typeof(&*(buf))), sizeof(buf)/sizeof((buf)[0]), (( void)0))), "%" "l" "u" " " "%" "l" "u" "\n", __extension__ ({ const typeof((quota * period / ((usec_t) 1000000ULL))) __unique_prefix_A253 = ((quota * period / ((usec_t) 1000000ULL))); const typeof(( ((usec_t) 1000ULL))) __unique_prefix_B254 = ((((usec_t) 1000ULL ))); __unique_prefix_A253 > __unique_prefix_B254 ? __unique_prefix_A253 : __unique_prefix_B254; }), period) < (__extension__ (__builtin_choose_expr ( !__builtin_types_compatible_p(typeof(buf), typeof(&*(buf ))), sizeof(buf)/sizeof((buf)[0]), ((void)0))))))),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("xsprintf: " "buf" "[] must be big enough" ), "../src/core/cgroup.c", 636, __PRETTY_FUNCTION__); } while (0); | |||
637 | else | |||
638 | xsprintf(buf, "max " USEC_FMT "\n", period)do { if ((__builtin_expect(!!(!(((size_t) snprintf(buf, __extension__ (__builtin_choose_expr( !__builtin_types_compatible_p(typeof (buf), typeof(&*(buf))), sizeof(buf)/sizeof((buf)[0]), (( void)0))), "max " "%" "l" "u" "\n", period) < (__extension__ (__builtin_choose_expr( !__builtin_types_compatible_p(typeof (buf), typeof(&*(buf))), sizeof(buf)/sizeof((buf)[0]), (( void)0))))))),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("xsprintf: " "buf" "[] must be big enough"), "../src/core/cgroup.c" , 638, __PRETTY_FUNCTION__); } while (0); | |||
639 | ||||
640 | r = cg_set_attribute("cpu", u->cgroup_path, "cpu.max", buf); | |||
641 | ||||
642 | if (r < 0) | |||
643 | log_unit_full(u, IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r,({ const Unit *_u = (u); _u ? log_object_internal(({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){-2, -30, -13})/sizeof(int)]; switch(r) { case -2: case -30: case -13: _found = 1; break; default: break ; } _found; }) ? 7 : 4, r, "../src/core/cgroup.c", 644, __func__ , _u->manager->unit_log_field, _u->id, _u->manager ->invocation_log_field, _u->invocation_id_string, "Failed to set cpu.max: %m" ) : log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((( { _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){-2, -30, -13})/sizeof(int)]; switch(r) { case -2: case -30: case -13: _found = 1; break; default: break ; } _found; }) ? 7 : 4))), r, "../src/core/cgroup.c", 644, __func__ , "Failed to set cpu.max: %m"); }) | |||
644 | "Failed to set cpu.max: %m")({ const Unit *_u = (u); _u ? log_object_internal(({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){-2, -30, -13})/sizeof(int)]; switch(r) { case -2: case -30: case -13: _found = 1; break; default: break ; } _found; }) ? 7 : 4, r, "../src/core/cgroup.c", 644, __func__ , _u->manager->unit_log_field, _u->id, _u->manager ->invocation_log_field, _u->invocation_id_string, "Failed to set cpu.max: %m" ) : log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((( { _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){-2, -30, -13})/sizeof(int)]; switch(r) { case -2: case -30: case -13: _found = 1; break; default: break ; } _found; }) ? 7 : 4))), r, "../src/core/cgroup.c", 644, __func__ , "Failed to set cpu.max: %m"); }); | |||
645 | } | |||
646 | ||||
647 | static void cgroup_apply_legacy_cpu_config(Unit *u, uint64_t shares, uint64_t quota, usec_t period) { | |||
648 | char buf[MAX(DECIMAL_STR_MAX(uint64_t), DECIMAL_STR_MAX(usec_t))__extension__ ({ const typeof(((2+(sizeof(uint64_t) <= 1 ? 3 : sizeof(uint64_t) <= 2 ? 5 : sizeof(uint64_t) <= 4 ? 10 : sizeof(uint64_t) <= 8 ? 20 : sizeof(int[-2*(sizeof(uint64_t ) > 8)]))))) __unique_prefix_A255 = (((2+(sizeof(uint64_t) <= 1 ? 3 : sizeof(uint64_t) <= 2 ? 5 : sizeof(uint64_t ) <= 4 ? 10 : sizeof(uint64_t) <= 8 ? 20 : sizeof(int[- 2*(sizeof(uint64_t) > 8)]))))); const typeof(((2+(sizeof(usec_t ) <= 1 ? 3 : sizeof(usec_t) <= 2 ? 5 : sizeof(usec_t) <= 4 ? 10 : sizeof(usec_t) <= 8 ? 20 : sizeof(int[-2*(sizeof (usec_t) > 8)]))))) __unique_prefix_B256 = (((2+(sizeof(usec_t ) <= 1 ? 3 : sizeof(usec_t) <= 2 ? 5 : sizeof(usec_t) <= 4 ? 10 : sizeof(usec_t) <= 8 ? 20 : sizeof(int[-2*(sizeof (usec_t) > 8)]))))); __unique_prefix_A255 > __unique_prefix_B256 ? __unique_prefix_A255 : __unique_prefix_B256; }) + 1]; | |||
649 | int r; | |||
650 | ||||
651 | xsprintf(buf, "%" PRIu64 "\n", shares)do { if ((__builtin_expect(!!(!(((size_t) snprintf(buf, __extension__ (__builtin_choose_expr( !__builtin_types_compatible_p(typeof (buf), typeof(&*(buf))), sizeof(buf)/sizeof((buf)[0]), (( void)0))), "%" "l" "u" "\n", shares) < (__extension__ (__builtin_choose_expr ( !__builtin_types_compatible_p(typeof(buf), typeof(&*(buf ))), sizeof(buf)/sizeof((buf)[0]), ((void)0))))))),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("xsprintf: " "buf" "[] must be big enough" ), "../src/core/cgroup.c", 651, __PRETTY_FUNCTION__); } while (0); | |||
652 | r = cg_set_attribute("cpu", u->cgroup_path, "cpu.shares", buf); | |||
653 | if (r < 0) | |||
654 | log_unit_full(u, IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r,({ const Unit *_u = (u); _u ? log_object_internal(({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){-2, -30, -13})/sizeof(int)]; switch(r) { case -2: case -30: case -13: _found = 1; break; default: break ; } _found; }) ? 7 : 4, r, "../src/core/cgroup.c", 655, __func__ , _u->manager->unit_log_field, _u->id, _u->manager ->invocation_log_field, _u->invocation_id_string, "Failed to set cpu.shares: %m" ) : log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((( { _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){-2, -30, -13})/sizeof(int)]; switch(r) { case -2: case -30: case -13: _found = 1; break; default: break ; } _found; }) ? 7 : 4))), r, "../src/core/cgroup.c", 655, __func__ , "Failed to set cpu.shares: %m"); }) | |||
655 | "Failed to set cpu.shares: %m")({ const Unit *_u = (u); _u ? log_object_internal(({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){-2, -30, -13})/sizeof(int)]; switch(r) { case -2: case -30: case -13: _found = 1; break; default: break ; } _found; }) ? 7 : 4, r, "../src/core/cgroup.c", 655, __func__ , _u->manager->unit_log_field, _u->id, _u->manager ->invocation_log_field, _u->invocation_id_string, "Failed to set cpu.shares: %m" ) : log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((( { _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){-2, -30, -13})/sizeof(int)]; switch(r) { case -2: case -30: case -13: _found = 1; break; default: break ; } _found; }) ? 7 : 4))), r, "../src/core/cgroup.c", 655, __func__ , "Failed to set cpu.shares: %m"); }); | |||
656 | ||||
657 | period = cgroup_cpu_adjust_period_and_log(u, period, quota); | |||
658 | ||||
659 | xsprintf(buf, USEC_FMT "\n", period)do { if ((__builtin_expect(!!(!(((size_t) snprintf(buf, __extension__ (__builtin_choose_expr( !__builtin_types_compatible_p(typeof (buf), typeof(&*(buf))), sizeof(buf)/sizeof((buf)[0]), (( void)0))), "%" "l" "u" "\n", period) < (__extension__ (__builtin_choose_expr ( !__builtin_types_compatible_p(typeof(buf), typeof(&*(buf ))), sizeof(buf)/sizeof((buf)[0]), ((void)0))))))),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("xsprintf: " "buf" "[] must be big enough" ), "../src/core/cgroup.c", 659, __PRETTY_FUNCTION__); } while (0); | |||
660 | r = cg_set_attribute("cpu", u->cgroup_path, "cpu.cfs_period_us", buf); | |||
661 | if (r < 0) | |||
662 | log_unit_full(u, IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r,({ const Unit *_u = (u); _u ? log_object_internal(({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){-2, -30, -13})/sizeof(int)]; switch(r) { case -2: case -30: case -13: _found = 1; break; default: break ; } _found; }) ? 7 : 4, r, "../src/core/cgroup.c", 663, __func__ , _u->manager->unit_log_field, _u->id, _u->manager ->invocation_log_field, _u->invocation_id_string, "Failed to set cpu.cfs_period_us: %m" ) : log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((( { _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){-2, -30, -13})/sizeof(int)]; switch(r) { case -2: case -30: case -13: _found = 1; break; default: break ; } _found; }) ? 7 : 4))), r, "../src/core/cgroup.c", 663, __func__ , "Failed to set cpu.cfs_period_us: %m"); }) | |||
663 | "Failed to set cpu.cfs_period_us: %m")({ const Unit *_u = (u); _u ? log_object_internal(({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){-2, -30, -13})/sizeof(int)]; switch(r) { case -2: case -30: case -13: _found = 1; break; default: break ; } _found; }) ? 7 : 4, r, "../src/core/cgroup.c", 663, __func__ , _u->manager->unit_log_field, _u->id, _u->manager ->invocation_log_field, _u->invocation_id_string, "Failed to set cpu.cfs_period_us: %m" ) : log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((( { _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){-2, -30, -13})/sizeof(int)]; switch(r) { case -2: case -30: case -13: _found = 1; break; default: break ; } _found; }) ? 7 : 4))), r, "../src/core/cgroup.c", 663, __func__ , "Failed to set cpu.cfs_period_us: %m"); }); | |||
664 | ||||
665 | if (quota != USEC_INFINITY((usec_t) -1)) { | |||
666 | xsprintf(buf, USEC_FMT "\n", MAX(quota * period / USEC_PER_SEC, USEC_PER_MSEC))do { if ((__builtin_expect(!!(!(((size_t) snprintf(buf, __extension__ (__builtin_choose_expr( !__builtin_types_compatible_p(typeof (buf), typeof(&*(buf))), sizeof(buf)/sizeof((buf)[0]), (( void)0))), "%" "l" "u" "\n", __extension__ ({ const typeof((quota * period / ((usec_t) 1000000ULL))) __unique_prefix_A257 = (( quota * period / ((usec_t) 1000000ULL))); const typeof((((usec_t ) 1000ULL))) __unique_prefix_B258 = ((((usec_t) 1000ULL))); __unique_prefix_A257 > __unique_prefix_B258 ? __unique_prefix_A257 : __unique_prefix_B258 ; })) < (__extension__ (__builtin_choose_expr( !__builtin_types_compatible_p (typeof(buf), typeof(&*(buf))), sizeof(buf)/sizeof((buf)[ 0]), ((void)0))))))),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD , ("xsprintf: " "buf" "[] must be big enough"), "../src/core/cgroup.c" , 666, __PRETTY_FUNCTION__); } while (0); | |||
667 | r = cg_set_attribute("cpu", u->cgroup_path, "cpu.cfs_quota_us", buf); | |||
668 | } | |||
669 | else | |||
670 | r = cg_set_attribute("cpu", u->cgroup_path, "cpu.cfs_quota_us", "-1"); | |||
671 | if (r < 0) | |||
672 | log_unit_full(u, IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r,({ const Unit *_u = (u); _u ? log_object_internal(({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){-2, -30, -13})/sizeof(int)]; switch(r) { case -2: case -30: case -13: _found = 1; break; default: break ; } _found; }) ? 7 : 4, r, "../src/core/cgroup.c", 673, __func__ , _u->manager->unit_log_field, _u->id, _u->manager ->invocation_log_field, _u->invocation_id_string, "Failed to set cpu.cfs_quota_us: %m" ) : log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((( { _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){-2, -30, -13})/sizeof(int)]; switch(r) { case -2: case -30: case -13: _found = 1; break; default: break ; } _found; }) ? 7 : 4))), r, "../src/core/cgroup.c", 673, __func__ , "Failed to set cpu.cfs_quota_us: %m"); }) | |||
673 | "Failed to set cpu.cfs_quota_us: %m")({ const Unit *_u = (u); _u ? log_object_internal(({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){-2, -30, -13})/sizeof(int)]; switch(r) { case -2: case -30: case -13: _found = 1; break; default: break ; } _found; }) ? 7 : 4, r, "../src/core/cgroup.c", 673, __func__ , _u->manager->unit_log_field, _u->id, _u->manager ->invocation_log_field, _u->invocation_id_string, "Failed to set cpu.cfs_quota_us: %m" ) : log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((( { _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){-2, -30, -13})/sizeof(int)]; switch(r) { case -2: case -30: case -13: _found = 1; break; default: break ; } _found; }) ? 7 : 4))), r, "../src/core/cgroup.c", 673, __func__ , "Failed to set cpu.cfs_quota_us: %m"); }); | |||
674 | } | |||
675 | ||||
676 | static uint64_t cgroup_cpu_shares_to_weight(uint64_t shares) { | |||
677 | return CLAMP(shares * CGROUP_WEIGHT_DEFAULT / CGROUP_CPU_SHARES_DEFAULT,__extension__ ({ const typeof((shares * 100UL / 1024UL)) __unique_prefix_X259 = ((shares * 100UL / 1024UL)); const typeof((1UL)) __unique_prefix_LOW260 = ((1UL)); const typeof((10000UL)) __unique_prefix_HIGH261 = ((10000UL)); __unique_prefix_X259 > __unique_prefix_HIGH261 ? __unique_prefix_HIGH261 : __unique_prefix_X259 < __unique_prefix_LOW260 ? __unique_prefix_LOW260 : __unique_prefix_X259; }) | |||
678 | CGROUP_WEIGHT_MIN, CGROUP_WEIGHT_MAX)__extension__ ({ const typeof((shares * 100UL / 1024UL)) __unique_prefix_X259 = ((shares * 100UL / 1024UL)); const typeof((1UL)) __unique_prefix_LOW260 = ((1UL)); const typeof((10000UL)) __unique_prefix_HIGH261 = ((10000UL)); __unique_prefix_X259 > __unique_prefix_HIGH261 ? __unique_prefix_HIGH261 : __unique_prefix_X259 < __unique_prefix_LOW260 ? __unique_prefix_LOW260 : __unique_prefix_X259; }); | |||
679 | } | |||
680 | ||||
681 | static uint64_t cgroup_cpu_weight_to_shares(uint64_t weight) { | |||
682 | return CLAMP(weight * CGROUP_CPU_SHARES_DEFAULT / CGROUP_WEIGHT_DEFAULT,__extension__ ({ const typeof((weight * 1024UL / 100UL)) __unique_prefix_X262 = ((weight * 1024UL / 100UL)); const typeof((2UL)) __unique_prefix_LOW263 = ((2UL)); const typeof((262144UL)) __unique_prefix_HIGH264 = ((262144UL)); __unique_prefix_X262 > __unique_prefix_HIGH264 ? __unique_prefix_HIGH264 : __unique_prefix_X262 < __unique_prefix_LOW263 ? __unique_prefix_LOW263 : __unique_prefix_X262; }) | |||
683 | CGROUP_CPU_SHARES_MIN, CGROUP_CPU_SHARES_MAX)__extension__ ({ const typeof((weight * 1024UL / 100UL)) __unique_prefix_X262 = ((weight * 1024UL / 100UL)); const typeof((2UL)) __unique_prefix_LOW263 = ((2UL)); const typeof((262144UL)) __unique_prefix_HIGH264 = ((262144UL)); __unique_prefix_X262 > __unique_prefix_HIGH264 ? __unique_prefix_HIGH264 : __unique_prefix_X262 < __unique_prefix_LOW263 ? __unique_prefix_LOW263 : __unique_prefix_X262; }); | |||
684 | } | |||
685 | ||||
686 | static void cgroup_apply_unified_cpuset(Unit *u, CPUSet cpus, const char *name) { | |||
687 | _cleanup_free___attribute__((cleanup(freep))) char *buf = NULL((void*)0); | |||
688 | int r; | |||
689 | ||||
690 | buf = cpu_set_to_range_string_kernel(&cpus); | |||
691 | if (!buf) | |||
692 | return; | |||
693 | ||||
694 | r = cg_set_attribute("cpuset", u->cgroup_path, name, buf); | |||
695 | if (r < 0) | |||
696 | log_unit_full(u, IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r,({ const Unit *_u = (u); _u ? log_object_internal(({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){-2, -30, -13})/sizeof(int)]; switch(r) { case -2: case -30: case -13: _found = 1; break; default: break ; } _found; }) ? 7 : 4, r, "../src/core/cgroup.c", 697, __func__ , _u->manager->unit_log_field, _u->id, _u->manager ->invocation_log_field, _u->invocation_id_string, "Failed to set %s: %m" , name) : log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended[20 - sizeof((int[ ]){-2, -30, -13})/sizeof(int)]; switch(r) { case -2: case -30 : case -13: _found = 1; break; default: break; } _found; }) ? 7 : 4))), r, "../src/core/cgroup.c", 697, __func__, "Failed to set %s: %m" , name); }) | |||
697 | "Failed to set %s: %m", name)({ const Unit *_u = (u); _u ? log_object_internal(({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){-2, -30, -13})/sizeof(int)]; switch(r) { case -2: case -30: case -13: _found = 1; break; default: break ; } _found; }) ? 7 : 4, r, "../src/core/cgroup.c", 697, __func__ , _u->manager->unit_log_field, _u->id, _u->manager ->invocation_log_field, _u->invocation_id_string, "Failed to set %s: %m" , name) : log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended[20 - sizeof((int[ ]){-2, -30, -13})/sizeof(int)]; switch(r) { case -2: case -30 : case -13: _found = 1; break; default: break; } _found; }) ? 7 : 4))), r, "../src/core/cgroup.c", 697, __func__, "Failed to set %s: %m" , name); }); | |||
698 | ||||
699 | } | |||
700 | ||||
701 | static bool_Bool cgroup_context_has_io_config(CGroupContext *c) { | |||
702 | return c->io_accounting || | |||
703 | c->io_weight != CGROUP_WEIGHT_INVALID((uint64_t) -1) || | |||
704 | c->startup_io_weight != CGROUP_WEIGHT_INVALID((uint64_t) -1) || | |||
705 | c->io_device_weights || | |||
706 | c->io_device_latencies || | |||
707 | c->io_device_limits; | |||
708 | } | |||
709 | ||||
710 | static bool_Bool cgroup_context_has_blockio_config(CGroupContext *c) { | |||
711 | return c->blockio_accounting || | |||
712 | c->blockio_weight != CGROUP_BLKIO_WEIGHT_INVALID((uint64_t) -1) || | |||
713 | c->startup_blockio_weight != CGROUP_BLKIO_WEIGHT_INVALID((uint64_t) -1) || | |||
714 | c->blockio_device_weights || | |||
715 | c->blockio_device_bandwidths; | |||
716 | } | |||
717 | ||||
718 | static uint64_t cgroup_context_io_weight(CGroupContext *c, ManagerState state) { | |||
719 | if (IN_SET(state, MANAGER_STARTING, MANAGER_INITIALIZING)({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){MANAGER_STARTING, MANAGER_INITIALIZING}) /sizeof(int)]; switch(state) { case MANAGER_STARTING: case MANAGER_INITIALIZING : _found = 1; break; default: break; } _found; }) && | |||
720 | c->startup_io_weight != CGROUP_WEIGHT_INVALID((uint64_t) -1)) | |||
721 | return c->startup_io_weight; | |||
722 | else if (c->io_weight != CGROUP_WEIGHT_INVALID((uint64_t) -1)) | |||
723 | return c->io_weight; | |||
724 | else | |||
725 | return CGROUP_WEIGHT_DEFAULT100UL; | |||
726 | } | |||
727 | ||||
728 | static uint64_t cgroup_context_blkio_weight(CGroupContext *c, ManagerState state) { | |||
729 | if (IN_SET(state, MANAGER_STARTING, MANAGER_INITIALIZING)({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){MANAGER_STARTING, MANAGER_INITIALIZING}) /sizeof(int)]; switch(state) { case MANAGER_STARTING: case MANAGER_INITIALIZING : _found = 1; break; default: break; } _found; }) && | |||
730 | c->startup_blockio_weight != CGROUP_BLKIO_WEIGHT_INVALID((uint64_t) -1)) | |||
731 | return c->startup_blockio_weight; | |||
732 | else if (c->blockio_weight != CGROUP_BLKIO_WEIGHT_INVALID((uint64_t) -1)) | |||
733 | return c->blockio_weight; | |||
734 | else | |||
735 | return CGROUP_BLKIO_WEIGHT_DEFAULT500UL; | |||
736 | } | |||
737 | ||||
738 | static uint64_t cgroup_weight_blkio_to_io(uint64_t blkio_weight) { | |||
739 | return CLAMP(blkio_weight * CGROUP_WEIGHT_DEFAULT / CGROUP_BLKIO_WEIGHT_DEFAULT,__extension__ ({ const typeof((blkio_weight * 100UL / 500UL)) __unique_prefix_X265 = ((blkio_weight * 100UL / 500UL)); const typeof((1UL)) __unique_prefix_LOW266 = ((1UL)); const typeof ((10000UL)) __unique_prefix_HIGH267 = ((10000UL)); __unique_prefix_X265 > __unique_prefix_HIGH267 ? __unique_prefix_HIGH267 : __unique_prefix_X265 < __unique_prefix_LOW266 ? __unique_prefix_LOW266 : __unique_prefix_X265 ; }) | |||
740 | CGROUP_WEIGHT_MIN, CGROUP_WEIGHT_MAX)__extension__ ({ const typeof((blkio_weight * 100UL / 500UL)) __unique_prefix_X265 = ((blkio_weight * 100UL / 500UL)); const typeof((1UL)) __unique_prefix_LOW266 = ((1UL)); const typeof ((10000UL)) __unique_prefix_HIGH267 = ((10000UL)); __unique_prefix_X265 > __unique_prefix_HIGH267 ? __unique_prefix_HIGH267 : __unique_prefix_X265 < __unique_prefix_LOW266 ? __unique_prefix_LOW266 : __unique_prefix_X265 ; }); | |||
741 | } | |||
742 | ||||
743 | static uint64_t cgroup_weight_io_to_blkio(uint64_t io_weight) { | |||
744 | return CLAMP(io_weight * CGROUP_BLKIO_WEIGHT_DEFAULT / CGROUP_WEIGHT_DEFAULT,__extension__ ({ const typeof((io_weight * 500UL / 100UL)) __unique_prefix_X268 = ((io_weight * 500UL / 100UL)); const typeof((10UL)) __unique_prefix_LOW269 = ((10UL)); const typeof((1000UL)) __unique_prefix_HIGH270 = ((1000UL)); __unique_prefix_X268 > __unique_prefix_HIGH270 ? __unique_prefix_HIGH270 : __unique_prefix_X268 < __unique_prefix_LOW269 ? __unique_prefix_LOW269 : __unique_prefix_X268; }) | |||
745 | CGROUP_BLKIO_WEIGHT_MIN, CGROUP_BLKIO_WEIGHT_MAX)__extension__ ({ const typeof((io_weight * 500UL / 100UL)) __unique_prefix_X268 = ((io_weight * 500UL / 100UL)); const typeof((10UL)) __unique_prefix_LOW269 = ((10UL)); const typeof((1000UL)) __unique_prefix_HIGH270 = ((1000UL)); __unique_prefix_X268 > __unique_prefix_HIGH270 ? __unique_prefix_HIGH270 : __unique_prefix_X268 < __unique_prefix_LOW269 ? __unique_prefix_LOW269 : __unique_prefix_X268; }); | |||
746 | } | |||
747 | ||||
748 | static void cgroup_apply_io_device_weight(Unit *u, const char *dev_path, uint64_t io_weight) { | |||
749 | char buf[DECIMAL_STR_MAX(dev_t)(2+(sizeof(dev_t) <= 1 ? 3 : sizeof(dev_t) <= 2 ? 5 : sizeof (dev_t) <= 4 ? 10 : sizeof(dev_t) <= 8 ? 20 : sizeof(int [-2*(sizeof(dev_t) > 8)])))*2+2+DECIMAL_STR_MAX(uint64_t)(2+(sizeof(uint64_t) <= 1 ? 3 : sizeof(uint64_t) <= 2 ? 5 : sizeof(uint64_t) <= 4 ? 10 : sizeof(uint64_t) <= 8 ? 20 : sizeof(int[-2*(sizeof(uint64_t) > 8)])))+1]; | |||
750 | dev_t dev; | |||
751 | int r; | |||
752 | ||||
753 | r = lookup_block_device(dev_path, &dev); | |||
754 | if (r < 0) | |||
755 | return; | |||
756 | ||||
757 | xsprintf(buf, "%u:%u %" PRIu64 "\n", major(dev), minor(dev), io_weight)do { if ((__builtin_expect(!!(!(((size_t) snprintf(buf, __extension__ (__builtin_choose_expr( !__builtin_types_compatible_p(typeof (buf), typeof(&*(buf))), sizeof(buf)/sizeof((buf)[0]), (( void)0))), "%u:%u %" "l" "u" "\n", gnu_dev_major (dev), gnu_dev_minor (dev), io_weight) < (__extension__ (__builtin_choose_expr ( !__builtin_types_compatible_p(typeof(buf), typeof(&*(buf ))), sizeof(buf)/sizeof((buf)[0]), ((void)0))))))),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("xsprintf: " "buf" "[] must be big enough" ), "../src/core/cgroup.c", 757, __PRETTY_FUNCTION__); } while (0); | |||
758 | r = cg_set_attribute("io", u->cgroup_path, "io.weight", buf); | |||
759 | if (r < 0) | |||
760 | log_unit_full(u, IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r,({ const Unit *_u = (u); _u ? log_object_internal(({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){-2, -30, -13})/sizeof(int)]; switch(r) { case -2: case -30: case -13: _found = 1; break; default: break ; } _found; }) ? 7 : 4, r, "../src/core/cgroup.c", 761, __func__ , _u->manager->unit_log_field, _u->id, _u->manager ->invocation_log_field, _u->invocation_id_string, "Failed to set io.weight: %m" ) : log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((( { _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){-2, -30, -13})/sizeof(int)]; switch(r) { case -2: case -30: case -13: _found = 1; break; default: break ; } _found; }) ? 7 : 4))), r, "../src/core/cgroup.c", 761, __func__ , "Failed to set io.weight: %m"); }) | |||
761 | "Failed to set io.weight: %m")({ const Unit *_u = (u); _u ? log_object_internal(({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){-2, -30, -13})/sizeof(int)]; switch(r) { case -2: case -30: case -13: _found = 1; break; default: break ; } _found; }) ? 7 : 4, r, "../src/core/cgroup.c", 761, __func__ , _u->manager->unit_log_field, _u->id, _u->manager ->invocation_log_field, _u->invocation_id_string, "Failed to set io.weight: %m" ) : log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((( { _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){-2, -30, -13})/sizeof(int)]; switch(r) { case -2: case -30: case -13: _found = 1; break; default: break ; } _found; }) ? 7 : 4))), r, "../src/core/cgroup.c", 761, __func__ , "Failed to set io.weight: %m"); }); | |||
762 | } | |||
763 | ||||
764 | static void cgroup_apply_blkio_device_weight(Unit *u, const char *dev_path, uint64_t blkio_weight) { | |||
765 | char buf[DECIMAL_STR_MAX(dev_t)(2+(sizeof(dev_t) <= 1 ? 3 : sizeof(dev_t) <= 2 ? 5 : sizeof (dev_t) <= 4 ? 10 : sizeof(dev_t) <= 8 ? 20 : sizeof(int [-2*(sizeof(dev_t) > 8)])))*2+2+DECIMAL_STR_MAX(uint64_t)(2+(sizeof(uint64_t) <= 1 ? 3 : sizeof(uint64_t) <= 2 ? 5 : sizeof(uint64_t) <= 4 ? 10 : sizeof(uint64_t) <= 8 ? 20 : sizeof(int[-2*(sizeof(uint64_t) > 8)])))+1]; | |||
766 | dev_t dev; | |||
767 | int r; | |||
768 | ||||
769 | r = lookup_block_device(dev_path, &dev); | |||
770 | if (r < 0) | |||
771 | return; | |||
772 | ||||
773 | xsprintf(buf, "%u:%u %" PRIu64 "\n", major(dev), minor(dev), blkio_weight)do { if ((__builtin_expect(!!(!(((size_t) snprintf(buf, __extension__ (__builtin_choose_expr( !__builtin_types_compatible_p(typeof (buf), typeof(&*(buf))), sizeof(buf)/sizeof((buf)[0]), (( void)0))), "%u:%u %" "l" "u" "\n", gnu_dev_major (dev), gnu_dev_minor (dev), blkio_weight) < (__extension__ (__builtin_choose_expr ( !__builtin_types_compatible_p(typeof(buf), typeof(&*(buf ))), sizeof(buf)/sizeof((buf)[0]), ((void)0))))))),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("xsprintf: " "buf" "[] must be big enough" ), "../src/core/cgroup.c", 773, __PRETTY_FUNCTION__); } while (0); | |||
774 | r = cg_set_attribute("blkio", u->cgroup_path, "blkio.weight_device", buf); | |||
775 | if (r < 0) | |||
776 | log_unit_full(u, IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r,({ const Unit *_u = (u); _u ? log_object_internal(({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){-2, -30, -13})/sizeof(int)]; switch(r) { case -2: case -30: case -13: _found = 1; break; default: break ; } _found; }) ? 7 : 4, r, "../src/core/cgroup.c", 777, __func__ , _u->manager->unit_log_field, _u->id, _u->manager ->invocation_log_field, _u->invocation_id_string, "Failed to set blkio.weight_device: %m" ) : log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((( { _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){-2, -30, -13})/sizeof(int)]; switch(r) { case -2: case -30: case -13: _found = 1; break; default: break ; } _found; }) ? 7 : 4))), r, "../src/core/cgroup.c", 777, __func__ , "Failed to set blkio.weight_device: %m"); }) | |||
777 | "Failed to set blkio.weight_device: %m")({ const Unit *_u = (u); _u ? log_object_internal(({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){-2, -30, -13})/sizeof(int)]; switch(r) { case -2: case -30: case -13: _found = 1; break; default: break ; } _found; }) ? 7 : 4, r, "../src/core/cgroup.c", 777, __func__ , _u->manager->unit_log_field, _u->id, _u->manager ->invocation_log_field, _u->invocation_id_string, "Failed to set blkio.weight_device: %m" ) : log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((( { _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){-2, -30, -13})/sizeof(int)]; switch(r) { case -2: case -30: case -13: _found = 1; break; default: break ; } _found; }) ? 7 : 4))), r, "../src/core/cgroup.c", 777, __func__ , "Failed to set blkio.weight_device: %m"); }); | |||
778 | } | |||
779 | ||||
780 | static void cgroup_apply_io_device_latency(Unit *u, const char *dev_path, usec_t target) { | |||
781 | char buf[DECIMAL_STR_MAX(dev_t)(2+(sizeof(dev_t) <= 1 ? 3 : sizeof(dev_t) <= 2 ? 5 : sizeof (dev_t) <= 4 ? 10 : sizeof(dev_t) <= 8 ? 20 : sizeof(int [-2*(sizeof(dev_t) > 8)])))*2+2+7+DECIMAL_STR_MAX(uint64_t)(2+(sizeof(uint64_t) <= 1 ? 3 : sizeof(uint64_t) <= 2 ? 5 : sizeof(uint64_t) <= 4 ? 10 : sizeof(uint64_t) <= 8 ? 20 : sizeof(int[-2*(sizeof(uint64_t) > 8)])))+1]; | |||
782 | dev_t dev; | |||
783 | int r; | |||
784 | ||||
785 | r = lookup_block_device(dev_path, &dev); | |||
786 | if (r < 0) | |||
787 | return; | |||
788 | ||||
789 | if (target != USEC_INFINITY((usec_t) -1)) | |||
790 | xsprintf(buf, "%u:%u target=%" PRIu64 "\n", major(dev), minor(dev), target)do { if ((__builtin_expect(!!(!(((size_t) snprintf(buf, __extension__ (__builtin_choose_expr( !__builtin_types_compatible_p(typeof (buf), typeof(&*(buf))), sizeof(buf)/sizeof((buf)[0]), (( void)0))), "%u:%u target=%" "l" "u" "\n", gnu_dev_major (dev) , gnu_dev_minor (dev), target) < (__extension__ (__builtin_choose_expr ( !__builtin_types_compatible_p(typeof(buf), typeof(&*(buf ))), sizeof(buf)/sizeof((buf)[0]), ((void)0))))))),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("xsprintf: " "buf" "[] must be big enough" ), "../src/core/cgroup.c", 790, __PRETTY_FUNCTION__); } while (0); | |||
791 | else | |||
792 | xsprintf(buf, "%u:%u target=max\n", major(dev), minor(dev))do { if ((__builtin_expect(!!(!(((size_t) snprintf(buf, __extension__ (__builtin_choose_expr( !__builtin_types_compatible_p(typeof (buf), typeof(&*(buf))), sizeof(buf)/sizeof((buf)[0]), (( void)0))), "%u:%u target=max\n", gnu_dev_major (dev), gnu_dev_minor (dev)) < (__extension__ (__builtin_choose_expr( !__builtin_types_compatible_p (typeof(buf), typeof(&*(buf))), sizeof(buf)/sizeof((buf)[ 0]), ((void)0))))))),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD , ("xsprintf: " "buf" "[] must be big enough"), "../src/core/cgroup.c" , 792, __PRETTY_FUNCTION__); } while (0); | |||
793 | ||||
794 | r = cg_set_attribute("io", u->cgroup_path, "io.latency", buf); | |||
795 | if (r < 0) | |||
796 | log_unit_full(u, IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r,({ const Unit *_u = (u); _u ? log_object_internal(({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){-2, -30, -13})/sizeof(int)]; switch(r) { case -2: case -30: case -13: _found = 1; break; default: break ; } _found; }) ? 7 : 4, r, "../src/core/cgroup.c", 797, __func__ , _u->manager->unit_log_field, _u->id, _u->manager ->invocation_log_field, _u->invocation_id_string, "Failed to set io.latency on cgroup %s: %m" , u->cgroup_path) : log_internal_realm(((LOG_REALM_SYSTEMD ) << 10 | ((({ _Bool _found = 0; static __attribute__ ( (unused)) char _static_assert__macros_need_to_be_extended[20 - sizeof((int[]){-2, -30, -13})/sizeof(int)]; switch(r) { case -2: case -30: case -13: _found = 1; break; default: break; } _found; }) ? 7 : 4))), r, "../src/core/cgroup.c", 797, __func__ , "Failed to set io.latency on cgroup %s: %m", u->cgroup_path ); }) | |||
797 | "Failed to set io.latency on cgroup %s: %m", u->cgroup_path)({ const Unit *_u = (u); _u ? log_object_internal(({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){-2, -30, -13})/sizeof(int)]; switch(r) { case -2: case -30: case -13: _found = 1; break; default: break ; } _found; }) ? 7 : 4, r, "../src/core/cgroup.c", 797, __func__ , _u->manager->unit_log_field, _u->id, _u->manager ->invocation_log_field, _u->invocation_id_string, "Failed to set io.latency on cgroup %s: %m" , u->cgroup_path) : log_internal_realm(((LOG_REALM_SYSTEMD ) << 10 | ((({ _Bool _found = 0; static __attribute__ ( (unused)) char _static_assert__macros_need_to_be_extended[20 - sizeof((int[]){-2, -30, -13})/sizeof(int)]; switch(r) { case -2: case -30: case -13: _found = 1; break; default: break; } _found; }) ? 7 : 4))), r, "../src/core/cgroup.c", 797, __func__ , "Failed to set io.latency on cgroup %s: %m", u->cgroup_path ); }); | |||
798 | } | |||
799 | ||||
800 | static void cgroup_apply_io_device_limit(Unit *u, const char *dev_path, uint64_t *limits) { | |||
801 | char limit_bufs[_CGROUP_IO_LIMIT_TYPE_MAX][DECIMAL_STR_MAX(uint64_t)(2+(sizeof(uint64_t) <= 1 ? 3 : sizeof(uint64_t) <= 2 ? 5 : sizeof(uint64_t) <= 4 ? 10 : sizeof(uint64_t) <= 8 ? 20 : sizeof(int[-2*(sizeof(uint64_t) > 8)])))]; | |||
802 | char buf[DECIMAL_STR_MAX(dev_t)(2+(sizeof(dev_t) <= 1 ? 3 : sizeof(dev_t) <= 2 ? 5 : sizeof (dev_t) <= 4 ? 10 : sizeof(dev_t) <= 8 ? 20 : sizeof(int [-2*(sizeof(dev_t) > 8)])))*2+2+(6+DECIMAL_STR_MAX(uint64_t)(2+(sizeof(uint64_t) <= 1 ? 3 : sizeof(uint64_t) <= 2 ? 5 : sizeof(uint64_t) <= 4 ? 10 : sizeof(uint64_t) <= 8 ? 20 : sizeof(int[-2*(sizeof(uint64_t) > 8)])))+1)*4]; | |||
803 | CGroupIOLimitType type; | |||
804 | dev_t dev; | |||
805 | int r; | |||
806 | ||||
807 | r = lookup_block_device(dev_path, &dev); | |||
808 | if (r < 0) | |||
809 | return; | |||
810 | ||||
811 | for (type = 0; type < _CGROUP_IO_LIMIT_TYPE_MAX; type++) | |||
812 | if (limits[type] != cgroup_io_limit_defaults[type]) | |||
813 | xsprintf(limit_bufs[type], "%" PRIu64, limits[type])do { if ((__builtin_expect(!!(!(((size_t) snprintf(limit_bufs [type], __extension__ (__builtin_choose_expr( !__builtin_types_compatible_p (typeof(limit_bufs[type]), typeof(&*(limit_bufs[type]))), sizeof(limit_bufs[type])/sizeof((limit_bufs[type])[0]), ((void )0))), "%" "l" "u", limits[type]) < (__extension__ (__builtin_choose_expr ( !__builtin_types_compatible_p(typeof(limit_bufs[type]), typeof (&*(limit_bufs[type]))), sizeof(limit_bufs[type])/sizeof( (limit_bufs[type])[0]), ((void)0))))))),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("xsprintf: " "limit_bufs[type]" "[] must be big enough" ), "../src/core/cgroup.c", 813, __PRETTY_FUNCTION__); } while (0); | |||
814 | else | |||
815 | xsprintf(limit_bufs[type], "%s", limits[type] == CGROUP_LIMIT_MAX ? "max" : "0")do { if ((__builtin_expect(!!(!(((size_t) snprintf(limit_bufs [type], __extension__ (__builtin_choose_expr( !__builtin_types_compatible_p (typeof(limit_bufs[type]), typeof(&*(limit_bufs[type]))), sizeof(limit_bufs[type])/sizeof((limit_bufs[type])[0]), ((void )0))), "%s", limits[type] == ((uint64_t) -1) ? "max" : "0") < (__extension__ (__builtin_choose_expr( !__builtin_types_compatible_p (typeof(limit_bufs[type]), typeof(&*(limit_bufs[type]))), sizeof(limit_bufs[type])/sizeof((limit_bufs[type])[0]), ((void )0))))))),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("xsprintf: " "limit_bufs[type]" "[] must be big enough"), "../src/core/cgroup.c" , 815, __PRETTY_FUNCTION__); } while (0); | |||
816 | ||||
817 | xsprintf(buf, "%u:%u rbps=%s wbps=%s riops=%s wiops=%s\n", major(dev), minor(dev),do { if ((__builtin_expect(!!(!(((size_t) snprintf(buf, __extension__ (__builtin_choose_expr( !__builtin_types_compatible_p(typeof (buf), typeof(&*(buf))), sizeof(buf)/sizeof((buf)[0]), (( void)0))), "%u:%u rbps=%s wbps=%s riops=%s wiops=%s\n", gnu_dev_major (dev), gnu_dev_minor (dev), limit_bufs[CGROUP_IO_RBPS_MAX], limit_bufs [CGROUP_IO_WBPS_MAX], limit_bufs[CGROUP_IO_RIOPS_MAX], limit_bufs [CGROUP_IO_WIOPS_MAX]) < (__extension__ (__builtin_choose_expr ( !__builtin_types_compatible_p(typeof(buf), typeof(&*(buf ))), sizeof(buf)/sizeof((buf)[0]), ((void)0))))))),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("xsprintf: " "buf" "[] must be big enough" ), "../src/core/cgroup.c", 819, __PRETTY_FUNCTION__); } while (0) | |||
818 | limit_bufs[CGROUP_IO_RBPS_MAX], limit_bufs[CGROUP_IO_WBPS_MAX],do { if ((__builtin_expect(!!(!(((size_t) snprintf(buf, __extension__ (__builtin_choose_expr( !__builtin_types_compatible_p(typeof (buf), typeof(&*(buf))), sizeof(buf)/sizeof((buf)[0]), (( void)0))), "%u:%u rbps=%s wbps=%s riops=%s wiops=%s\n", gnu_dev_major (dev), gnu_dev_minor (dev), limit_bufs[CGROUP_IO_RBPS_MAX], limit_bufs [CGROUP_IO_WBPS_MAX], limit_bufs[CGROUP_IO_RIOPS_MAX], limit_bufs [CGROUP_IO_WIOPS_MAX]) < (__extension__ (__builtin_choose_expr ( !__builtin_types_compatible_p(typeof(buf), typeof(&*(buf ))), sizeof(buf)/sizeof((buf)[0]), ((void)0))))))),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("xsprintf: " "buf" "[] must be big enough" ), "../src/core/cgroup.c", 819, __PRETTY_FUNCTION__); } while (0) | |||
819 | limit_bufs[CGROUP_IO_RIOPS_MAX], limit_bufs[CGROUP_IO_WIOPS_MAX])do { if ((__builtin_expect(!!(!(((size_t) snprintf(buf, __extension__ (__builtin_choose_expr( !__builtin_types_compatible_p(typeof (buf), typeof(&*(buf))), sizeof(buf)/sizeof((buf)[0]), (( void)0))), "%u:%u rbps=%s wbps=%s riops=%s wiops=%s\n", gnu_dev_major (dev), gnu_dev_minor (dev), limit_bufs[CGROUP_IO_RBPS_MAX], limit_bufs [CGROUP_IO_WBPS_MAX], limit_bufs[CGROUP_IO_RIOPS_MAX], limit_bufs [CGROUP_IO_WIOPS_MAX]) < (__extension__ (__builtin_choose_expr ( !__builtin_types_compatible_p(typeof(buf), typeof(&*(buf ))), sizeof(buf)/sizeof((buf)[0]), ((void)0))))))),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("xsprintf: " "buf" "[] must be big enough" ), "../src/core/cgroup.c", 819, __PRETTY_FUNCTION__); } while (0); | |||
820 | r = cg_set_attribute("io", u->cgroup_path, "io.max", buf); | |||
821 | if (r < 0) | |||
822 | log_unit_full(u, IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r,({ const Unit *_u = (u); _u ? log_object_internal(({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){-2, -30, -13})/sizeof(int)]; switch(r) { case -2: case -30: case -13: _found = 1; break; default: break ; } _found; }) ? 7 : 4, r, "../src/core/cgroup.c", 823, __func__ , _u->manager->unit_log_field, _u->id, _u->manager ->invocation_log_field, _u->invocation_id_string, "Failed to set io.max: %m" ) : log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((( { _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){-2, -30, -13})/sizeof(int)]; switch(r) { case -2: case -30: case -13: _found = 1; break; default: break ; } _found; }) ? 7 : 4))), r, "../src/core/cgroup.c", 823, __func__ , "Failed to set io.max: %m"); }) | |||
823 | "Failed to set io.max: %m")({ const Unit *_u = (u); _u ? log_object_internal(({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){-2, -30, -13})/sizeof(int)]; switch(r) { case -2: case -30: case -13: _found = 1; break; default: break ; } _found; }) ? 7 : 4, r, "../src/core/cgroup.c", 823, __func__ , _u->manager->unit_log_field, _u->id, _u->manager ->invocation_log_field, _u->invocation_id_string, "Failed to set io.max: %m" ) : log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((( { _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){-2, -30, -13})/sizeof(int)]; switch(r) { case -2: case -30: case -13: _found = 1; break; default: break ; } _found; }) ? 7 : 4))), r, "../src/core/cgroup.c", 823, __func__ , "Failed to set io.max: %m"); }); | |||
824 | } | |||
825 | ||||
826 | static void cgroup_apply_blkio_device_limit(Unit *u, const char *dev_path, uint64_t rbps, uint64_t wbps) { | |||
827 | char buf[DECIMAL_STR_MAX(dev_t)(2+(sizeof(dev_t) <= 1 ? 3 : sizeof(dev_t) <= 2 ? 5 : sizeof (dev_t) <= 4 ? 10 : sizeof(dev_t) <= 8 ? 20 : sizeof(int [-2*(sizeof(dev_t) > 8)])))*2+2+DECIMAL_STR_MAX(uint64_t)(2+(sizeof(uint64_t) <= 1 ? 3 : sizeof(uint64_t) <= 2 ? 5 : sizeof(uint64_t) <= 4 ? 10 : sizeof(uint64_t) <= 8 ? 20 : sizeof(int[-2*(sizeof(uint64_t) > 8)])))+1]; | |||
828 | dev_t dev; | |||
829 | int r; | |||
830 | ||||
831 | r = lookup_block_device(dev_path, &dev); | |||
832 | if (r < 0) | |||
833 | return; | |||
834 | ||||
835 | sprintf(buf, "%u:%u %" PRIu64"l" "u" "\n", major(dev)gnu_dev_major (dev), minor(dev)gnu_dev_minor (dev), rbps); | |||
836 | r = cg_set_attribute("blkio", u->cgroup_path, "blkio.throttle.read_bps_device", buf); | |||
837 | if (r < 0) | |||
838 | log_unit_full(u, IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r,({ const Unit *_u = (u); _u ? log_object_internal(({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){-2, -30, -13})/sizeof(int)]; switch(r) { case -2: case -30: case -13: _found = 1; break; default: break ; } _found; }) ? 7 : 4, r, "../src/core/cgroup.c", 839, __func__ , _u->manager->unit_log_field, _u->id, _u->manager ->invocation_log_field, _u->invocation_id_string, "Failed to set blkio.throttle.read_bps_device: %m" ) : log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((( { _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){-2, -30, -13})/sizeof(int)]; switch(r) { case -2: case -30: case -13: _found = 1; break; default: break ; } _found; }) ? 7 : 4))), r, "../src/core/cgroup.c", 839, __func__ , "Failed to set blkio.throttle.read_bps_device: %m"); }) | |||
839 | "Failed to set blkio.throttle.read_bps_device: %m")({ const Unit *_u = (u); _u ? log_object_internal(({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){-2, -30, -13})/sizeof(int)]; switch(r) { case -2: case -30: case -13: _found = 1; break; default: break ; } _found; }) ? 7 : 4, r, "../src/core/cgroup.c", 839, __func__ , _u->manager->unit_log_field, _u->id, _u->manager ->invocation_log_field, _u->invocation_id_string, "Failed to set blkio.throttle.read_bps_device: %m" ) : log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((( { _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){-2, -30, -13})/sizeof(int)]; switch(r) { case -2: case -30: case -13: _found = 1; break; default: break ; } _found; }) ? 7 : 4))), r, "../src/core/cgroup.c", 839, __func__ , "Failed to set blkio.throttle.read_bps_device: %m"); }); | |||
840 | ||||
841 | sprintf(buf, "%u:%u %" PRIu64"l" "u" "\n", major(dev)gnu_dev_major (dev), minor(dev)gnu_dev_minor (dev), wbps); | |||
842 | r = cg_set_attribute("blkio", u->cgroup_path, "blkio.throttle.write_bps_device", buf); | |||
843 | if (r < 0) | |||
844 | log_unit_full(u, IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r,({ const Unit *_u = (u); _u ? log_object_internal(({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){-2, -30, -13})/sizeof(int)]; switch(r) { case -2: case -30: case -13: _found = 1; break; default: break ; } _found; }) ? 7 : 4, r, "../src/core/cgroup.c", 845, __func__ , _u->manager->unit_log_field, _u->id, _u->manager ->invocation_log_field, _u->invocation_id_string, "Failed to set blkio.throttle.write_bps_device: %m" ) : log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((( { _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){-2, -30, -13})/sizeof(int)]; switch(r) { case -2: case -30: case -13: _found = 1; break; default: break ; } _found; }) ? 7 : 4))), r, "../src/core/cgroup.c", 845, __func__ , "Failed to set blkio.throttle.write_bps_device: %m"); }) | |||
845 | "Failed to set blkio.throttle.write_bps_device: %m")({ const Unit *_u = (u); _u ? log_object_internal(({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){-2, -30, -13})/sizeof(int)]; switch(r) { case -2: case -30: case -13: _found = 1; break; default: break ; } _found; }) ? 7 : 4, r, "../src/core/cgroup.c", 845, __func__ , _u->manager->unit_log_field, _u->id, _u->manager ->invocation_log_field, _u->invocation_id_string, "Failed to set blkio.throttle.write_bps_device: %m" ) : log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((( { _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){-2, -30, -13})/sizeof(int)]; switch(r) { case -2: case -30: case -13: _found = 1; break; default: break ; } _found; }) ? 7 : 4))), r, "../src/core/cgroup.c", 845, __func__ , "Failed to set blkio.throttle.write_bps_device: %m"); }); | |||
846 | } | |||
847 | ||||
848 | static bool_Bool unit_has_unified_memory_config(Unit *u) { | |||
849 | CGroupContext *c; | |||
850 | ||||
851 | assert(u)do { if ((__builtin_expect(!!(!(u)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("u"), "../src/core/cgroup.c", 851, __PRETTY_FUNCTION__ ); } while (0); | |||
852 | ||||
853 | c = unit_get_cgroup_context(u); | |||
854 | assert(c)do { if ((__builtin_expect(!!(!(c)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("c"), "../src/core/cgroup.c", 854, __PRETTY_FUNCTION__ ); } while (0); | |||
855 | ||||
856 | return unit_get_ancestor_memory_min(u) > 0 || unit_get_ancestor_memory_low(u) > 0 || | |||
857 | c->memory_high != CGROUP_LIMIT_MAX((uint64_t) -1) || c->memory_max != CGROUP_LIMIT_MAX((uint64_t) -1) || | |||
858 | c->memory_swap_max != CGROUP_LIMIT_MAX((uint64_t) -1); | |||
859 | } | |||
860 | ||||
861 | static void cgroup_apply_unified_memory_limit(Unit *u, const char *file, uint64_t v) { | |||
862 | char buf[DECIMAL_STR_MAX(uint64_t)(2+(sizeof(uint64_t) <= 1 ? 3 : sizeof(uint64_t) <= 2 ? 5 : sizeof(uint64_t) <= 4 ? 10 : sizeof(uint64_t) <= 8 ? 20 : sizeof(int[-2*(sizeof(uint64_t) > 8)]))) + 1] = "max"; | |||
863 | int r; | |||
864 | ||||
865 | if (v != CGROUP_LIMIT_MAX((uint64_t) -1)) | |||
866 | xsprintf(buf, "%" PRIu64 "\n", v)do { if ((__builtin_expect(!!(!(((size_t) snprintf(buf, __extension__ (__builtin_choose_expr( !__builtin_types_compatible_p(typeof (buf), typeof(&*(buf))), sizeof(buf)/sizeof((buf)[0]), (( void)0))), "%" "l" "u" "\n", v) < (__extension__ (__builtin_choose_expr ( !__builtin_types_compatible_p(typeof(buf), typeof(&*(buf ))), sizeof(buf)/sizeof((buf)[0]), ((void)0))))))),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("xsprintf: " "buf" "[] must be big enough" ), "../src/core/cgroup.c", 866, __PRETTY_FUNCTION__); } while (0); | |||
867 | ||||
868 | r = cg_set_attribute("memory", u->cgroup_path, file, buf); | |||
869 | if (r < 0) | |||
870 | log_unit_full(u, IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r,({ const Unit *_u = (u); _u ? log_object_internal(({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){-2, -30, -13})/sizeof(int)]; switch(r) { case -2: case -30: case -13: _found = 1; break; default: break ; } _found; }) ? 7 : 4, r, "../src/core/cgroup.c", 871, __func__ , _u->manager->unit_log_field, _u->id, _u->manager ->invocation_log_field, _u->invocation_id_string, "Failed to set %s: %m" , file) : log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended[20 - sizeof((int[ ]){-2, -30, -13})/sizeof(int)]; switch(r) { case -2: case -30 : case -13: _found = 1; break; default: break; } _found; }) ? 7 : 4))), r, "../src/core/cgroup.c", 871, __func__, "Failed to set %s: %m" , file); }) | |||
871 | "Failed to set %s: %m", file)({ const Unit *_u = (u); _u ? log_object_internal(({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){-2, -30, -13})/sizeof(int)]; switch(r) { case -2: case -30: case -13: _found = 1; break; default: break ; } _found; }) ? 7 : 4, r, "../src/core/cgroup.c", 871, __func__ , _u->manager->unit_log_field, _u->id, _u->manager ->invocation_log_field, _u->invocation_id_string, "Failed to set %s: %m" , file) : log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended[20 - sizeof((int[ ]){-2, -30, -13})/sizeof(int)]; switch(r) { case -2: case -30 : case -13: _found = 1; break; default: break; } _found; }) ? 7 : 4))), r, "../src/core/cgroup.c", 871, __func__, "Failed to set %s: %m" , file); }); | |||
872 | } | |||
873 | ||||
874 | static void cgroup_apply_firewall(Unit *u) { | |||
875 | assert(u)do { if ((__builtin_expect(!!(!(u)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("u"), "../src/core/cgroup.c", 875, __PRETTY_FUNCTION__ ); } while (0); | |||
876 | ||||
877 | /* Best-effort: let's apply IP firewalling and/or accounting if that's enabled */ | |||
878 | ||||
879 | if (bpf_firewall_compile(u) < 0) | |||
880 | return; | |||
881 | ||||
882 | (void) bpf_firewall_install(u); | |||
883 | } | |||
884 | ||||
885 | static void cgroup_context_apply( | |||
886 | Unit *u, | |||
887 | CGroupMask apply_mask, | |||
888 | bool_Bool apply_bpf, | |||
889 | ManagerState state) { | |||
890 | ||||
891 | const char *path; | |||
892 | CGroupContext *c; | |||
893 | bool_Bool is_root; | |||
894 | int r; | |||
895 | ||||
896 | assert(u)do { if ((__builtin_expect(!!(!(u)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("u"), "../src/core/cgroup.c", 896, __PRETTY_FUNCTION__ ); } while (0); | |||
897 | ||||
898 | /* Nothing to do? Exit early! */ | |||
899 | if (apply_mask == 0 && !apply_bpf) | |||
900 | return; | |||
901 | ||||
902 | /* Some cgroup attributes are not supported on the root cgroup, hence silently ignore */ | |||
903 | is_root = unit_has_root_cgroup(u); | |||
904 | ||||
905 | assert_se(c = unit_get_cgroup_context(u))do { if ((__builtin_expect(!!(!(c = unit_get_cgroup_context(u ))),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("c = unit_get_cgroup_context(u)" ), "../src/core/cgroup.c", 905, __PRETTY_FUNCTION__); } while (0); | |||
906 | assert_se(path = u->cgroup_path)do { if ((__builtin_expect(!!(!(path = u->cgroup_path)),0) )) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("path = u->cgroup_path" ), "../src/core/cgroup.c", 906, __PRETTY_FUNCTION__); } while (0); | |||
907 | ||||
908 | if (is_root) /* Make sure we don't try to display messages with an empty path. */ | |||
909 | path = "/"; | |||
910 | ||||
911 | /* We generally ignore errors caused by read-only mounted | |||
912 | * cgroup trees (assuming we are running in a container then), | |||
913 | * and missing cgroups, i.e. EROFS and ENOENT. */ | |||
914 | ||||
915 | if ((apply_mask & CGROUP_MASK_CPU) && !is_root) { | |||
916 | bool_Bool has_weight, has_shares; | |||
917 | ||||
918 | has_weight = cgroup_context_has_cpu_weight(c); | |||
919 | has_shares = cgroup_context_has_cpu_shares(c); | |||
920 | ||||
921 | if (cg_all_unified() > 0) { | |||
922 | uint64_t weight; | |||
923 | ||||
924 | if (has_weight) | |||
925 | weight = cgroup_context_cpu_weight(c, state); | |||
926 | else if (has_shares) { | |||
927 | uint64_t shares = cgroup_context_cpu_shares(c, state); | |||
928 | ||||
929 | weight = cgroup_cpu_shares_to_weight(shares); | |||
930 | ||||
931 | log_cgroup_compat(u, "Applying [Startup]CpuShares %" PRIu64 " as [Startup]CpuWeight %" PRIu64 " on %s",do { cgroup_compat_warn(); ({ const Unit *_u = (u); _u ? log_object_internal (7, 0, "../src/core/cgroup.c", 932, __func__, _u->manager-> unit_log_field, _u->id, _u->manager->invocation_log_field , _u->invocation_id_string, "cgroup-compat: " "Applying [Startup]CpuShares %" "l" "u" " as [Startup]CpuWeight %" "l" "u" " on %s", shares, weight, path) : log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((7))), 0, "../src/core/cgroup.c", 932, __func__, "cgroup-compat: " "Applying [Startup]CpuShares %" "l" "u" " as [Startup]CpuWeight %" "l" "u" " on %s", shares, weight, path); }); } while (0) | |||
932 | shares, weight, path)do { cgroup_compat_warn(); ({ const Unit *_u = (u); _u ? log_object_internal (7, 0, "../src/core/cgroup.c", 932, __func__, _u->manager-> unit_log_field, _u->id, _u->manager->invocation_log_field , _u->invocation_id_string, "cgroup-compat: " "Applying [Startup]CpuShares %" "l" "u" " as [Startup]CpuWeight %" "l" "u" " on %s", shares, weight, path) : log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((7))), 0, "../src/core/cgroup.c", 932, __func__, "cgroup-compat: " "Applying [Startup]CpuShares %" "l" "u" " as [Startup]CpuWeight %" "l" "u" " on %s", shares, weight, path); }); } while (0); | |||
933 | } else | |||
934 | weight = CGROUP_WEIGHT_DEFAULT100UL; | |||
935 | ||||
936 | cgroup_apply_unified_cpu_config(u, weight, c->cpu_quota_per_sec_usec, c->cpu_quota_period_usec); | |||
937 | } else { | |||
938 | uint64_t shares; | |||
939 | ||||
940 | if (has_weight) { | |||
941 | uint64_t weight = cgroup_context_cpu_weight(c, state); | |||
942 | ||||
943 | shares = cgroup_cpu_weight_to_shares(weight); | |||
944 | ||||
945 | log_cgroup_compat(u, "Applying [Startup]CpuWeight %" PRIu64 " as [Startup]CpuShares %" PRIu64 " on %s",do { cgroup_compat_warn(); ({ const Unit *_u = (u); _u ? log_object_internal (7, 0, "../src/core/cgroup.c", 946, __func__, _u->manager-> unit_log_field, _u->id, _u->manager->invocation_log_field , _u->invocation_id_string, "cgroup-compat: " "Applying [Startup]CpuWeight %" "l" "u" " as [Startup]CpuShares %" "l" "u" " on %s", weight, shares, path) : log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((7))), 0, "../src/core/cgroup.c", 946, __func__, "cgroup-compat: " "Applying [Startup]CpuWeight %" "l" "u" " as [Startup]CpuShares %" "l" "u" " on %s", weight, shares, path); }); } while (0) | |||
946 | weight, shares, path)do { cgroup_compat_warn(); ({ const Unit *_u = (u); _u ? log_object_internal (7, 0, "../src/core/cgroup.c", 946, __func__, _u->manager-> unit_log_field, _u->id, _u->manager->invocation_log_field , _u->invocation_id_string, "cgroup-compat: " "Applying [Startup]CpuWeight %" "l" "u" " as [Startup]CpuShares %" "l" "u" " on %s", weight, shares, path) : log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((7))), 0, "../src/core/cgroup.c", 946, __func__, "cgroup-compat: " "Applying [Startup]CpuWeight %" "l" "u" " as [Startup]CpuShares %" "l" "u" " on %s", weight, shares, path); }); } while (0); | |||
947 | } else if (has_shares) | |||
948 | shares = cgroup_context_cpu_shares(c, state); | |||
949 | else | |||
950 | shares = CGROUP_CPU_SHARES_DEFAULT1024UL; | |||
951 | ||||
952 | cgroup_apply_legacy_cpu_config(u, shares, c->cpu_quota_per_sec_usec, c->cpu_quota_period_usec); | |||
953 | } | |||
954 | } | |||
955 | ||||
956 | if ((apply_mask & CGROUP_MASK_CPUSET) && !is_root) { | |||
957 | cgroup_apply_unified_cpuset(u, c->cpuset_cpus, "cpuset.cpus"); | |||
958 | cgroup_apply_unified_cpuset(u, c->cpuset_mems, "cpuset.mems"); | |||
959 | } | |||
960 | ||||
961 | if (apply_mask & CGROUP_MASK_IO) { | |||
962 | bool_Bool has_io = cgroup_context_has_io_config(c); | |||
963 | bool_Bool has_blockio = cgroup_context_has_blockio_config(c); | |||
964 | ||||
965 | if (!is_root) { | |||
966 | char buf[8+DECIMAL_STR_MAX(uint64_t)(2+(sizeof(uint64_t) <= 1 ? 3 : sizeof(uint64_t) <= 2 ? 5 : sizeof(uint64_t) <= 4 ? 10 : sizeof(uint64_t) <= 8 ? 20 : sizeof(int[-2*(sizeof(uint64_t) > 8)])))+1]; | |||
967 | uint64_t weight; | |||
968 | ||||
969 | if (has_io) | |||
970 | weight = cgroup_context_io_weight(c, state); | |||
971 | else if (has_blockio) { | |||
972 | uint64_t blkio_weight = cgroup_context_blkio_weight(c, state); | |||
973 | ||||
974 | weight = cgroup_weight_blkio_to_io(blkio_weight); | |||
975 | ||||
976 | log_cgroup_compat(u, "Applying [Startup]BlockIOWeight %" PRIu64 " as [Startup]IOWeight %" PRIu64,do { cgroup_compat_warn(); ({ const Unit *_u = (u); _u ? log_object_internal (7, 0, "../src/core/cgroup.c", 977, __func__, _u->manager-> unit_log_field, _u->id, _u->manager->invocation_log_field , _u->invocation_id_string, "cgroup-compat: " "Applying [Startup]BlockIOWeight %" "l" "u" " as [Startup]IOWeight %" "l" "u", blkio_weight, weight ) : log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((7 ))), 0, "../src/core/cgroup.c", 977, __func__, "cgroup-compat: " "Applying [Startup]BlockIOWeight %" "l" "u" " as [Startup]IOWeight %" "l" "u", blkio_weight, weight); }); } while (0) | |||
977 | blkio_weight, weight)do { cgroup_compat_warn(); ({ const Unit *_u = (u); _u ? log_object_internal (7, 0, "../src/core/cgroup.c", 977, __func__, _u->manager-> unit_log_field, _u->id, _u->manager->invocation_log_field , _u->invocation_id_string, "cgroup-compat: " "Applying [Startup]BlockIOWeight %" "l" "u" " as [Startup]IOWeight %" "l" "u", blkio_weight, weight ) : log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((7 ))), 0, "../src/core/cgroup.c", 977, __func__, "cgroup-compat: " "Applying [Startup]BlockIOWeight %" "l" "u" " as [Startup]IOWeight %" "l" "u", blkio_weight, weight); }); } while (0); | |||
978 | } else | |||
979 | weight = CGROUP_WEIGHT_DEFAULT100UL; | |||
980 | ||||
981 | xsprintf(buf, "default %" PRIu64 "\n", weight)do { if ((__builtin_expect(!!(!(((size_t) snprintf(buf, __extension__ (__builtin_choose_expr( !__builtin_types_compatible_p(typeof (buf), typeof(&*(buf))), sizeof(buf)/sizeof((buf)[0]), (( void)0))), "default %" "l" "u" "\n", weight) < (__extension__ (__builtin_choose_expr( !__builtin_types_compatible_p(typeof (buf), typeof(&*(buf))), sizeof(buf)/sizeof((buf)[0]), (( void)0))))))),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("xsprintf: " "buf" "[] must be big enough"), "../src/core/cgroup.c" , 981, __PRETTY_FUNCTION__); } while (0); | |||
982 | r = cg_set_attribute("io", path, "io.weight", buf); | |||
983 | if (r < 0) | |||
984 | log_unit_full(u, IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r,({ const Unit *_u = (u); _u ? log_object_internal(({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){-2, -30, -13})/sizeof(int)]; switch(r) { case -2: case -30: case -13: _found = 1; break; default: break ; } _found; }) ? 7 : 4, r, "../src/core/cgroup.c", 985, __func__ , _u->manager->unit_log_field, _u->id, _u->manager ->invocation_log_field, _u->invocation_id_string, "Failed to set io.weight: %m" ) : log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((( { _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){-2, -30, -13})/sizeof(int)]; switch(r) { case -2: case -30: case -13: _found = 1; break; default: break ; } _found; }) ? 7 : 4))), r, "../src/core/cgroup.c", 985, __func__ , "Failed to set io.weight: %m"); }) | |||
985 | "Failed to set io.weight: %m")({ const Unit *_u = (u); _u ? log_object_internal(({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){-2, -30, -13})/sizeof(int)]; switch(r) { case -2: case -30: case -13: _found = 1; break; default: break ; } _found; }) ? 7 : 4, r, "../src/core/cgroup.c", 985, __func__ , _u->manager->unit_log_field, _u->id, _u->manager ->invocation_log_field, _u->invocation_id_string, "Failed to set io.weight: %m" ) : log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((( { _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){-2, -30, -13})/sizeof(int)]; switch(r) { case -2: case -30: case -13: _found = 1; break; default: break ; } _found; }) ? 7 : 4))), r, "../src/core/cgroup.c", 985, __func__ , "Failed to set io.weight: %m"); }); | |||
986 | ||||
987 | if (has_io) { | |||
988 | CGroupIODeviceWeight *w; | |||
989 | ||||
990 | LIST_FOREACH(device_weights, w, c->io_device_weights)for ((w) = (c->io_device_weights); (w); (w) = (w)->device_weights_next ) | |||
991 | cgroup_apply_io_device_weight(u, w->path, w->weight); | |||
992 | } else if (has_blockio) { | |||
993 | CGroupBlockIODeviceWeight *w; | |||
994 | ||||
995 | LIST_FOREACH(device_weights, w, c->blockio_device_weights)for ((w) = (c->blockio_device_weights); (w); (w) = (w)-> device_weights_next) { | |||
996 | weight = cgroup_weight_blkio_to_io(w->weight); | |||
997 | ||||
998 | log_cgroup_compat(u, "Applying BlockIODeviceWeight %" PRIu64 " as IODeviceWeight %" PRIu64 " for %s",do { cgroup_compat_warn(); ({ const Unit *_u = (u); _u ? log_object_internal (7, 0, "../src/core/cgroup.c", 999, __func__, _u->manager-> unit_log_field, _u->id, _u->manager->invocation_log_field , _u->invocation_id_string, "cgroup-compat: " "Applying BlockIODeviceWeight %" "l" "u" " as IODeviceWeight %" "l" "u" " for %s", w->weight , weight, w->path) : log_internal_realm(((LOG_REALM_SYSTEMD ) << 10 | ((7))), 0, "../src/core/cgroup.c", 999, __func__ , "cgroup-compat: " "Applying BlockIODeviceWeight %" "l" "u" " as IODeviceWeight %" "l" "u" " for %s", w->weight, weight, w->path); }); } while (0) | |||
999 | w->weight, weight, w->path)do { cgroup_compat_warn(); ({ const Unit *_u = (u); _u ? log_object_internal (7, 0, "../src/core/cgroup.c", 999, __func__, _u->manager-> unit_log_field, _u->id, _u->manager->invocation_log_field , _u->invocation_id_string, "cgroup-compat: " "Applying BlockIODeviceWeight %" "l" "u" " as IODeviceWeight %" "l" "u" " for %s", w->weight , weight, w->path) : log_internal_realm(((LOG_REALM_SYSTEMD ) << 10 | ((7))), 0, "../src/core/cgroup.c", 999, __func__ , "cgroup-compat: " "Applying BlockIODeviceWeight %" "l" "u" " as IODeviceWeight %" "l" "u" " for %s", w->weight, weight, w->path); }); } while (0); | |||
1000 | ||||
1001 | cgroup_apply_io_device_weight(u, w->path, weight); | |||
1002 | } | |||
1003 | } | |||
1004 | ||||
1005 | if (has_io) { | |||
1006 | CGroupIODeviceLatency *l; | |||
1007 | ||||
1008 | LIST_FOREACH(device_latencies, l, c->io_device_latencies)for ((l) = (c->io_device_latencies); (l); (l) = (l)->device_latencies_next ) | |||
1009 | cgroup_apply_io_device_latency(u, l->path, l->target_usec); | |||
1010 | } | |||
1011 | } | |||
1012 | ||||
1013 | if (has_io) { | |||
1014 | CGroupIODeviceLimit *l; | |||
1015 | ||||
1016 | LIST_FOREACH(device_limits, l, c->io_device_limits)for ((l) = (c->io_device_limits); (l); (l) = (l)->device_limits_next ) | |||
1017 | cgroup_apply_io_device_limit(u, l->path, l->limits); | |||
1018 | ||||
1019 | } else if (has_blockio) { | |||
1020 | CGroupBlockIODeviceBandwidth *b; | |||
1021 | ||||
1022 | LIST_FOREACH(device_bandwidths, b, c->blockio_device_bandwidths)for ((b) = (c->blockio_device_bandwidths); (b); (b) = (b)-> device_bandwidths_next) { | |||
1023 | uint64_t limits[_CGROUP_IO_LIMIT_TYPE_MAX]; | |||
1024 | CGroupIOLimitType type; | |||
1025 | ||||
1026 | for (type = 0; type < _CGROUP_IO_LIMIT_TYPE_MAX; type++) | |||
1027 | limits[type] = cgroup_io_limit_defaults[type]; | |||
1028 | ||||
1029 | limits[CGROUP_IO_RBPS_MAX] = b->rbps; | |||
1030 | limits[CGROUP_IO_WBPS_MAX] = b->wbps; | |||
1031 | ||||
1032 | log_cgroup_compat(u, "Applying BlockIO{Read|Write}Bandwidth %" PRIu64 " %" PRIu64 " as IO{Read|Write}BandwidthMax for %s",do { cgroup_compat_warn(); ({ const Unit *_u = (u); _u ? log_object_internal (7, 0, "../src/core/cgroup.c", 1033, __func__, _u->manager ->unit_log_field, _u->id, _u->manager->invocation_log_field , _u->invocation_id_string, "cgroup-compat: " "Applying BlockIO{Read|Write}Bandwidth %" "l" "u" " %" "l" "u" " as IO{Read|Write}BandwidthMax for %s" , b->rbps, b->wbps, b->path) : log_internal_realm((( LOG_REALM_SYSTEMD) << 10 | ((7))), 0, "../src/core/cgroup.c" , 1033, __func__, "cgroup-compat: " "Applying BlockIO{Read|Write}Bandwidth %" "l" "u" " %" "l" "u" " as IO{Read|Write}BandwidthMax for %s" , b->rbps, b->wbps, b->path); }); } while (0) | |||
1033 | b->rbps, b->wbps, b->path)do { cgroup_compat_warn(); ({ const Unit *_u = (u); _u ? log_object_internal (7, 0, "../src/core/cgroup.c", 1033, __func__, _u->manager ->unit_log_field, _u->id, _u->manager->invocation_log_field , _u->invocation_id_string, "cgroup-compat: " "Applying BlockIO{Read|Write}Bandwidth %" "l" "u" " %" "l" "u" " as IO{Read|Write}BandwidthMax for %s" , b->rbps, b->wbps, b->path) : log_internal_realm((( LOG_REALM_SYSTEMD) << 10 | ((7))), 0, "../src/core/cgroup.c" , 1033, __func__, "cgroup-compat: " "Applying BlockIO{Read|Write}Bandwidth %" "l" "u" " %" "l" "u" " as IO{Read|Write}BandwidthMax for %s" , b->rbps, b->wbps, b->path); }); } while (0); | |||
1034 | ||||
1035 | cgroup_apply_io_device_limit(u, b->path, limits); | |||
1036 | } | |||
1037 | } | |||
1038 | } | |||
1039 | ||||
1040 | if (apply_mask & CGROUP_MASK_BLKIO) { | |||
1041 | bool_Bool has_io = cgroup_context_has_io_config(c); | |||
1042 | bool_Bool has_blockio = cgroup_context_has_blockio_config(c); | |||
1043 | ||||
1044 | if (!is_root) { | |||
1045 | char buf[DECIMAL_STR_MAX(uint64_t)(2+(sizeof(uint64_t) <= 1 ? 3 : sizeof(uint64_t) <= 2 ? 5 : sizeof(uint64_t) <= 4 ? 10 : sizeof(uint64_t) <= 8 ? 20 : sizeof(int[-2*(sizeof(uint64_t) > 8)])))+1]; | |||
1046 | uint64_t weight; | |||
1047 | ||||
1048 | if (has_io) { | |||
1049 | uint64_t io_weight = cgroup_context_io_weight(c, state); | |||
1050 | ||||
1051 | weight = cgroup_weight_io_to_blkio(cgroup_context_io_weight(c, state)); | |||
1052 | ||||
1053 | log_cgroup_compat(u, "Applying [Startup]IOWeight %" PRIu64 " as [Startup]BlockIOWeight %" PRIu64,do { cgroup_compat_warn(); ({ const Unit *_u = (u); _u ? log_object_internal (7, 0, "../src/core/cgroup.c", 1054, __func__, _u->manager ->unit_log_field, _u->id, _u->manager->invocation_log_field , _u->invocation_id_string, "cgroup-compat: " "Applying [Startup]IOWeight %" "l" "u" " as [Startup]BlockIOWeight %" "l" "u", io_weight, weight ) : log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((7 ))), 0, "../src/core/cgroup.c", 1054, __func__, "cgroup-compat: " "Applying [Startup]IOWeight %" "l" "u" " as [Startup]BlockIOWeight %" "l" "u", io_weight, weight); }); } while (0) | |||
1054 | io_weight, weight)do { cgroup_compat_warn(); ({ const Unit *_u = (u); _u ? log_object_internal (7, 0, "../src/core/cgroup.c", 1054, __func__, _u->manager ->unit_log_field, _u->id, _u->manager->invocation_log_field , _u->invocation_id_string, "cgroup-compat: " "Applying [Startup]IOWeight %" "l" "u" " as [Startup]BlockIOWeight %" "l" "u", io_weight, weight ) : log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((7 ))), 0, "../src/core/cgroup.c", 1054, __func__, "cgroup-compat: " "Applying [Startup]IOWeight %" "l" "u" " as [Startup]BlockIOWeight %" "l" "u", io_weight, weight); }); } while (0); | |||
1055 | } else if (has_blockio) | |||
1056 | weight = cgroup_context_blkio_weight(c, state); | |||
1057 | else | |||
1058 | weight = CGROUP_BLKIO_WEIGHT_DEFAULT500UL; | |||
1059 | ||||
1060 | xsprintf(buf, "%" PRIu64 "\n", weight)do { if ((__builtin_expect(!!(!(((size_t) snprintf(buf, __extension__ (__builtin_choose_expr( !__builtin_types_compatible_p(typeof (buf), typeof(&*(buf))), sizeof(buf)/sizeof((buf)[0]), (( void)0))), "%" "l" "u" "\n", weight) < (__extension__ (__builtin_choose_expr ( !__builtin_types_compatible_p(typeof(buf), typeof(&*(buf ))), sizeof(buf)/sizeof((buf)[0]), ((void)0))))))),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("xsprintf: " "buf" "[] must be big enough" ), "../src/core/cgroup.c", 1060, __PRETTY_FUNCTION__); } while (0); | |||
1061 | r = cg_set_attribute("blkio", path, "blkio.weight", buf); | |||
1062 | if (r < 0) | |||
1063 | log_unit_full(u, IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r,({ const Unit *_u = (u); _u ? log_object_internal(({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){-2, -30, -13})/sizeof(int)]; switch(r) { case -2: case -30: case -13: _found = 1; break; default: break ; } _found; }) ? 7 : 4, r, "../src/core/cgroup.c", 1064, __func__ , _u->manager->unit_log_field, _u->id, _u->manager ->invocation_log_field, _u->invocation_id_string, "Failed to set blkio.weight: %m" ) : log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((( { _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){-2, -30, -13})/sizeof(int)]; switch(r) { case -2: case -30: case -13: _found = 1; break; default: break ; } _found; }) ? 7 : 4))), r, "../src/core/cgroup.c", 1064, __func__ , "Failed to set blkio.weight: %m"); }) | |||
1064 | "Failed to set blkio.weight: %m")({ const Unit *_u = (u); _u ? log_object_internal(({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){-2, -30, -13})/sizeof(int)]; switch(r) { case -2: case -30: case -13: _found = 1; break; default: break ; } _found; }) ? 7 : 4, r, "../src/core/cgroup.c", 1064, __func__ , _u->manager->unit_log_field, _u->id, _u->manager ->invocation_log_field, _u->invocation_id_string, "Failed to set blkio.weight: %m" ) : log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((( { _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){-2, -30, -13})/sizeof(int)]; switch(r) { case -2: case -30: case -13: _found = 1; break; default: break ; } _found; }) ? 7 : 4))), r, "../src/core/cgroup.c", 1064, __func__ , "Failed to set blkio.weight: %m"); }); | |||
1065 | ||||
1066 | /* FIXME: drop this when distro kernels properly support BFQ through "blkio.weight" | |||
1067 | * See also: https://github.com/systemd/systemd/pull/13335 */ | |||
1068 | xsprintf(buf, "%" PRIu64 "\n", weight)do { if ((__builtin_expect(!!(!(((size_t) snprintf(buf, __extension__ (__builtin_choose_expr( !__builtin_types_compatible_p(typeof (buf), typeof(&*(buf))), sizeof(buf)/sizeof((buf)[0]), (( void)0))), "%" "l" "u" "\n", weight) < (__extension__ (__builtin_choose_expr ( !__builtin_types_compatible_p(typeof(buf), typeof(&*(buf ))), sizeof(buf)/sizeof((buf)[0]), ((void)0))))))),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("xsprintf: " "buf" "[] must be big enough" ), "../src/core/cgroup.c", 1068, __PRETTY_FUNCTION__); } while (0); | |||
1069 | r = cg_set_attribute("blkio", path, "blkio.bfq.weight", buf); | |||
1070 | if (r < 0) | |||
1071 | log_unit_full(u, IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r,({ const Unit *_u = (u); _u ? log_object_internal(({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){-2, -30, -13})/sizeof(int)]; switch(r) { case -2: case -30: case -13: _found = 1; break; default: break ; } _found; }) ? 7 : 4, r, "../src/core/cgroup.c", 1072, __func__ , _u->manager->unit_log_field, _u->id, _u->manager ->invocation_log_field, _u->invocation_id_string, "Failed to set blkio.bfq.weight: %m" ) : log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((( { _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){-2, -30, -13})/sizeof(int)]; switch(r) { case -2: case -30: case -13: _found = 1; break; default: break ; } _found; }) ? 7 : 4))), r, "../src/core/cgroup.c", 1072, __func__ , "Failed to set blkio.bfq.weight: %m"); }) | |||
1072 | "Failed to set blkio.bfq.weight: %m")({ const Unit *_u = (u); _u ? log_object_internal(({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){-2, -30, -13})/sizeof(int)]; switch(r) { case -2: case -30: case -13: _found = 1; break; default: break ; } _found; }) ? 7 : 4, r, "../src/core/cgroup.c", 1072, __func__ , _u->manager->unit_log_field, _u->id, _u->manager ->invocation_log_field, _u->invocation_id_string, "Failed to set blkio.bfq.weight: %m" ) : log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((( { _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){-2, -30, -13})/sizeof(int)]; switch(r) { case -2: case -30: case -13: _found = 1; break; default: break ; } _found; }) ? 7 : 4))), r, "../src/core/cgroup.c", 1072, __func__ , "Failed to set blkio.bfq.weight: %m"); }); | |||
1073 | ||||
1074 | if (has_io) { | |||
1075 | CGroupIODeviceWeight *w; | |||
1076 | ||||
1077 | LIST_FOREACH(device_weights, w, c->io_device_weights)for ((w) = (c->io_device_weights); (w); (w) = (w)->device_weights_next ) { | |||
1078 | weight = cgroup_weight_io_to_blkio(w->weight); | |||
1079 | ||||
1080 | log_cgroup_compat(u, "Applying IODeviceWeight %" PRIu64 " as BlockIODeviceWeight %" PRIu64 " for %s",do { cgroup_compat_warn(); ({ const Unit *_u = (u); _u ? log_object_internal (7, 0, "../src/core/cgroup.c", 1081, __func__, _u->manager ->unit_log_field, _u->id, _u->manager->invocation_log_field , _u->invocation_id_string, "cgroup-compat: " "Applying IODeviceWeight %" "l" "u" " as BlockIODeviceWeight %" "l" "u" " for %s", w-> weight, weight, w->path) : log_internal_realm(((LOG_REALM_SYSTEMD ) << 10 | ((7))), 0, "../src/core/cgroup.c", 1081, __func__ , "cgroup-compat: " "Applying IODeviceWeight %" "l" "u" " as BlockIODeviceWeight %" "l" "u" " for %s", w->weight, weight, w->path); }); } while (0) | |||
1081 | w->weight, weight, w->path)do { cgroup_compat_warn(); ({ const Unit *_u = (u); _u ? log_object_internal (7, 0, "../src/core/cgroup.c", 1081, __func__, _u->manager ->unit_log_field, _u->id, _u->manager->invocation_log_field , _u->invocation_id_string, "cgroup-compat: " "Applying IODeviceWeight %" "l" "u" " as BlockIODeviceWeight %" "l" "u" " for %s", w-> weight, weight, w->path) : log_internal_realm(((LOG_REALM_SYSTEMD ) << 10 | ((7))), 0, "../src/core/cgroup.c", 1081, __func__ , "cgroup-compat: " "Applying IODeviceWeight %" "l" "u" " as BlockIODeviceWeight %" "l" "u" " for %s", w->weight, weight, w->path); }); } while (0); | |||
1082 | ||||
1083 | cgroup_apply_blkio_device_weight(u, w->path, weight); | |||
1084 | } | |||
1085 | } else if (has_blockio) { | |||
1086 | CGroupBlockIODeviceWeight *w; | |||
1087 | ||||
1088 | LIST_FOREACH(device_weights, w, c->blockio_device_weights)for ((w) = (c->blockio_device_weights); (w); (w) = (w)-> device_weights_next) | |||
1089 | cgroup_apply_blkio_device_weight(u, w->path, w->weight); | |||
1090 | } | |||
1091 | } | |||
1092 | ||||
1093 | if (has_io) { | |||
1094 | CGroupIODeviceLimit *l; | |||
1095 | ||||
1096 | LIST_FOREACH(device_limits, l, c->io_device_limits)for ((l) = (c->io_device_limits); (l); (l) = (l)->device_limits_next ) { | |||
1097 | log_cgroup_compat(u, "Applying IO{Read|Write}Bandwidth %" PRIu64 " %" PRIu64 " as BlockIO{Read|Write}BandwidthMax for %s",do { cgroup_compat_warn(); ({ const Unit *_u = (u); _u ? log_object_internal (7, 0, "../src/core/cgroup.c", 1098, __func__, _u->manager ->unit_log_field, _u->id, _u->manager->invocation_log_field , _u->invocation_id_string, "cgroup-compat: " "Applying IO{Read|Write}Bandwidth %" "l" "u" " %" "l" "u" " as BlockIO{Read|Write}BandwidthMax for %s" , l->limits[CGROUP_IO_RBPS_MAX], l->limits[CGROUP_IO_WBPS_MAX ], l->path) : log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((7))), 0, "../src/core/cgroup.c", 1098, __func__, "cgroup-compat: " "Applying IO{Read|Write}Bandwidth %" "l" "u" " %" "l" "u" " as BlockIO{Read|Write}BandwidthMax for %s" , l->limits[CGROUP_IO_RBPS_MAX], l->limits[CGROUP_IO_WBPS_MAX ], l->path); }); } while (0) | |||
1098 | l->limits[CGROUP_IO_RBPS_MAX], l->limits[CGROUP_IO_WBPS_MAX], l->path)do { cgroup_compat_warn(); ({ const Unit *_u = (u); _u ? log_object_internal (7, 0, "../src/core/cgroup.c", 1098, __func__, _u->manager ->unit_log_field, _u->id, _u->manager->invocation_log_field , _u->invocation_id_string, "cgroup-compat: " "Applying IO{Read|Write}Bandwidth %" "l" "u" " %" "l" "u" " as BlockIO{Read|Write}BandwidthMax for %s" , l->limits[CGROUP_IO_RBPS_MAX], l->limits[CGROUP_IO_WBPS_MAX ], l->path) : log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((7))), 0, "../src/core/cgroup.c", 1098, __func__, "cgroup-compat: " "Applying IO{Read|Write}Bandwidth %" "l" "u" " %" "l" "u" " as BlockIO{Read|Write}BandwidthMax for %s" , l->limits[CGROUP_IO_RBPS_MAX], l->limits[CGROUP_IO_WBPS_MAX ], l->path); }); } while (0); | |||
1099 | ||||
1100 | cgroup_apply_blkio_device_limit(u, l->path, l->limits[CGROUP_IO_RBPS_MAX], l->limits[CGROUP_IO_WBPS_MAX]); | |||
1101 | } | |||
1102 | } else if (has_blockio) { | |||
1103 | CGroupBlockIODeviceBandwidth *b; | |||
1104 | ||||
1105 | LIST_FOREACH(device_bandwidths, b, c->blockio_device_bandwidths)for ((b) = (c->blockio_device_bandwidths); (b); (b) = (b)-> device_bandwidths_next) | |||
1106 | cgroup_apply_blkio_device_limit(u, b->path, b->rbps, b->wbps); | |||
1107 | } | |||
1108 | } | |||
1109 | ||||
1110 | if ((apply_mask & CGROUP_MASK_MEMORY) && !is_root) { | |||
1111 | if (cg_all_unified() > 0) { | |||
1112 | uint64_t max, swap_max = CGROUP_LIMIT_MAX((uint64_t) -1); | |||
1113 | ||||
1114 | if (unit_has_unified_memory_config(u)) { | |||
1115 | max = c->memory_max; | |||
1116 | swap_max = c->memory_swap_max; | |||
1117 | } else { | |||
1118 | max = c->memory_limit; | |||
1119 | ||||
1120 | if (max != CGROUP_LIMIT_MAX((uint64_t) -1)) | |||
1121 | log_cgroup_compat(u, "Applying MemoryLimit %" PRIu64 " as MemoryMax", max)do { cgroup_compat_warn(); ({ const Unit *_u = (u); _u ? log_object_internal (7, 0, "../src/core/cgroup.c", 1121, __func__, _u->manager ->unit_log_field, _u->id, _u->manager->invocation_log_field , _u->invocation_id_string, "cgroup-compat: " "Applying MemoryLimit %" "l" "u" " as MemoryMax", max) : log_internal_realm(((LOG_REALM_SYSTEMD ) << 10 | ((7))), 0, "../src/core/cgroup.c", 1121, __func__ , "cgroup-compat: " "Applying MemoryLimit %" "l" "u" " as MemoryMax" , max); }); } while (0); | |||
1122 | } | |||
1123 | ||||
1124 | cgroup_apply_unified_memory_limit(u, "memory.min", unit_get_ancestor_memory_min(u)); | |||
1125 | cgroup_apply_unified_memory_limit(u, "memory.low", unit_get_ancestor_memory_low(u)); | |||
1126 | cgroup_apply_unified_memory_limit(u, "memory.high", c->memory_high); | |||
1127 | cgroup_apply_unified_memory_limit(u, "memory.max", max); | |||
1128 | cgroup_apply_unified_memory_limit(u, "memory.swap.max", swap_max); | |||
1129 | } else { | |||
1130 | char buf[DECIMAL_STR_MAX(uint64_t)(2+(sizeof(uint64_t) <= 1 ? 3 : sizeof(uint64_t) <= 2 ? 5 : sizeof(uint64_t) <= 4 ? 10 : sizeof(uint64_t) <= 8 ? 20 : sizeof(int[-2*(sizeof(uint64_t) > 8)]))) + 1]; | |||
1131 | uint64_t val; | |||
1132 | ||||
1133 | if (unit_has_unified_memory_config(u)) { | |||
1134 | val = c->memory_max; | |||
1135 | log_cgroup_compat(u, "Applying MemoryMax %" PRIi64 " as MemoryLimit", val)do { cgroup_compat_warn(); ({ const Unit *_u = (u); _u ? log_object_internal (7, 0, "../src/core/cgroup.c", 1135, __func__, _u->manager ->unit_log_field, _u->id, _u->manager->invocation_log_field , _u->invocation_id_string, "cgroup-compat: " "Applying MemoryMax %" "l" "i" " as MemoryLimit", val) : log_internal_realm(((LOG_REALM_SYSTEMD ) << 10 | ((7))), 0, "../src/core/cgroup.c", 1135, __func__ , "cgroup-compat: " "Applying MemoryMax %" "l" "i" " as MemoryLimit" , val); }); } while (0); | |||
1136 | } else | |||
1137 | val = c->memory_limit; | |||
1138 | ||||
1139 | if (val == CGROUP_LIMIT_MAX((uint64_t) -1)) | |||
1140 | strncpy(buf, "-1\n", sizeof(buf)); | |||
1141 | else | |||
1142 | xsprintf(buf, "%" PRIu64 "\n", val)do { if ((__builtin_expect(!!(!(((size_t) snprintf(buf, __extension__ (__builtin_choose_expr( !__builtin_types_compatible_p(typeof (buf), typeof(&*(buf))), sizeof(buf)/sizeof((buf)[0]), (( void)0))), "%" "l" "u" "\n", val) < (__extension__ (__builtin_choose_expr ( !__builtin_types_compatible_p(typeof(buf), typeof(&*(buf ))), sizeof(buf)/sizeof((buf)[0]), ((void)0))))))),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("xsprintf: " "buf" "[] must be big enough" ), "../src/core/cgroup.c", 1142, __PRETTY_FUNCTION__); } while (0); | |||
1143 | ||||
1144 | r = cg_set_attribute("memory", path, "memory.limit_in_bytes", buf); | |||
1145 | if (r < 0) | |||
1146 | log_unit_full(u, IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r,({ const Unit *_u = (u); _u ? log_object_internal(({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){-2, -30, -13})/sizeof(int)]; switch(r) { case -2: case -30: case -13: _found = 1; break; default: break ; } _found; }) ? 7 : 4, r, "../src/core/cgroup.c", 1147, __func__ , _u->manager->unit_log_field, _u->id, _u->manager ->invocation_log_field, _u->invocation_id_string, "Failed to set memory.limit_in_bytes: %m" ) : log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((( { _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){-2, -30, -13})/sizeof(int)]; switch(r) { case -2: case -30: case -13: _found = 1; break; default: break ; } _found; }) ? 7 : 4))), r, "../src/core/cgroup.c", 1147, __func__ , "Failed to set memory.limit_in_bytes: %m"); }) | |||
1147 | "Failed to set memory.limit_in_bytes: %m")({ const Unit *_u = (u); _u ? log_object_internal(({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){-2, -30, -13})/sizeof(int)]; switch(r) { case -2: case -30: case -13: _found = 1; break; default: break ; } _found; }) ? 7 : 4, r, "../src/core/cgroup.c", 1147, __func__ , _u->manager->unit_log_field, _u->id, _u->manager ->invocation_log_field, _u->invocation_id_string, "Failed to set memory.limit_in_bytes: %m" ) : log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((( { _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){-2, -30, -13})/sizeof(int)]; switch(r) { case -2: case -30: case -13: _found = 1; break; default: break ; } _found; }) ? 7 : 4))), r, "../src/core/cgroup.c", 1147, __func__ , "Failed to set memory.limit_in_bytes: %m"); }); | |||
1148 | } | |||
1149 | } | |||
1150 | ||||
1151 | if ((apply_mask & CGROUP_MASK_DEVICES) && !is_root) { | |||
1152 | CGroupDeviceAllow *a; | |||
1153 | ||||
1154 | /* Changing the devices list of a populated cgroup | |||
1155 | * might result in EINVAL, hence ignore EINVAL | |||
1156 | * here. */ | |||
1157 | ||||
1158 | if (c->device_allow || c->device_policy != CGROUP_AUTO) | |||
1159 | r = cg_set_attribute("devices", path, "devices.deny", "a"); | |||
1160 | else | |||
1161 | r = cg_set_attribute("devices", path, "devices.allow", "a"); | |||
1162 | if (r < 0) | |||
1163 | log_unit_full(u, IN_SET(r, -ENOENT, -EROFS, -EINVAL, -EACCES) ? LOG_DEBUG : LOG_WARNING, r,({ const Unit *_u = (u); _u ? log_object_internal(({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){-2, -30, -22, -13})/sizeof(int)]; switch (r) { case -2: case -30: case -22: case -13: _found = 1; break ; default: break; } _found; }) ? 7 : 4, r, "../src/core/cgroup.c" , 1164, __func__, _u->manager->unit_log_field, _u->id , _u->manager->invocation_log_field, _u->invocation_id_string , "Failed to reset devices.list: %m") : log_internal_realm((( LOG_REALM_SYSTEMD) << 10 | ((({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){-2, -30, -22, -13})/sizeof(int)]; switch (r) { case -2: case -30: case -22: case -13: _found = 1; break ; default: break; } _found; }) ? 7 : 4))), r, "../src/core/cgroup.c" , 1164, __func__, "Failed to reset devices.list: %m"); }) | |||
1164 | "Failed to reset devices.list: %m")({ const Unit *_u = (u); _u ? log_object_internal(({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){-2, -30, -22, -13})/sizeof(int)]; switch (r) { case -2: case -30: case -22: case -13: _found = 1; break ; default: break; } _found; }) ? 7 : 4, r, "../src/core/cgroup.c" , 1164, __func__, _u->manager->unit_log_field, _u->id , _u->manager->invocation_log_field, _u->invocation_id_string , "Failed to reset devices.list: %m") : log_internal_realm((( LOG_REALM_SYSTEMD) << 10 | ((({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){-2, -30, -22, -13})/sizeof(int)]; switch (r) { case -2: case -30: case -22: case -13: _found = 1; break ; default: break; } _found; }) ? 7 : 4))), r, "../src/core/cgroup.c" , 1164, __func__, "Failed to reset devices.list: %m"); }); | |||
1165 | ||||
1166 | if (c->device_policy == CGROUP_CLOSED || | |||
1167 | (c->device_policy == CGROUP_AUTO && c->device_allow)) { | |||
1168 | static const char auto_devices[] = | |||
1169 | "/dev/null\0" "rwm\0" | |||
1170 | "/dev/zero\0" "rwm\0" | |||
1171 | "/dev/full\0" "rwm\0" | |||
1172 | "/dev/random\0" "rwm\0" | |||
1173 | "/dev/urandom\0" "rwm\0" | |||
1174 | "/dev/tty\0" "rwm\0" | |||
1175 | "/dev/ptmx\0" "rwm\0" | |||
1176 | /* Allow /run/systemd/inaccessible/{chr,blk} devices for mapping InaccessiblePaths */ | |||
1177 | "-/run/systemd/inaccessible/chr\0" "rwm\0" | |||
1178 | "-/run/systemd/inaccessible/blk\0" "rwm\0"; | |||
1179 | ||||
1180 | const char *x, *y; | |||
1181 | ||||
1182 | NULSTR_FOREACH_PAIR(x, y, auto_devices)for ((x) = (auto_devices), (y) = strchr((x), 0)+1; (x) && *(x); (x) = strchr((y), 0)+1, (y) = *(x) ? strchr((x), 0)+1 : (x)) | |||
1183 | whitelist_device(path, x, y); | |||
1184 | ||||
1185 | /* PTS (/dev/pts) devices may not be duplicated, but accessed */ | |||
1186 | whitelist_major(path, "pts", 'c', "rw"); | |||
1187 | } | |||
1188 | ||||
1189 | LIST_FOREACH(device_allow, a, c->device_allow)for ((a) = (c->device_allow); (a); (a) = (a)->device_allow_next ) { | |||
1190 | char acc[4], *val; | |||
1191 | unsigned k = 0; | |||
1192 | ||||
1193 | if (a->r) | |||
1194 | acc[k++] = 'r'; | |||
1195 | if (a->w) | |||
1196 | acc[k++] = 'w'; | |||
1197 | if (a->m) | |||
1198 | acc[k++] = 'm'; | |||
1199 | ||||
1200 | if (k == 0) | |||
1201 | continue; | |||
1202 | ||||
1203 | acc[k++] = 0; | |||
1204 | ||||
1205 | if (path_startswith(a->path, "/dev/")) | |||
1206 | whitelist_device(path, a->path, acc); | |||
1207 | else if ((val = startswith(a->path, "block-"))) | |||
1208 | whitelist_major(path, val, 'b', acc); | |||
1209 | else if ((val = startswith(a->path, "char-"))) | |||
1210 | whitelist_major(path, val, 'c', acc); | |||
1211 | else | |||
1212 | log_unit_debug(u, "Ignoring device %s while writing cgroup attribute.", a->path)({ const Unit *_u = (u); _u ? log_object_internal(7, 0, "../src/core/cgroup.c" , 1212, __func__, _u->manager->unit_log_field, _u->id , _u->manager->invocation_log_field, _u->invocation_id_string , "Ignoring device %s while writing cgroup attribute.", a-> path) : log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((7))), 0, "../src/core/cgroup.c", 1212, __func__, "Ignoring device %s while writing cgroup attribute." , a->path); }); | |||
1213 | } | |||
1214 | } | |||
1215 | ||||
1216 | if (apply_mask & CGROUP_MASK_PIDS) { | |||
1217 | ||||
1218 | if (is_root) { | |||
1219 | /* So, the "pids" controller does not expose anything on the root cgroup, in order not to | |||
1220 | * replicate knobs exposed elsewhere needlessly. We abstract this away here however, and when | |||
1221 | * the knobs of the root cgroup are modified propagate this to the relevant sysctls. There's a | |||
1222 | * non-obvious asymmetry however: unlike the cgroup properties we don't really want to take | |||
1223 | * exclusive ownership of the sysctls, but we still want to honour things if the user sets | |||
1224 | * limits. Hence we employ sort of a one-way strategy: when the user sets a bounded limit | |||
1225 | * through us it counts. When the user afterwards unsets it again (i.e. sets it to unbounded) | |||
1226 | * it also counts. But if the user never set a limit through us (i.e. we are the default of | |||
1227 | * "unbounded") we leave things unmodified. For this we manage a global boolean that we turn on | |||
1228 | * the first time we set a limit. Note that this boolean is flushed out on manager reload, | |||
1229 | * which is desirable so that there's an offical way to release control of the sysctl from | |||
1230 | * systemd: set the limit to unbounded and reload. */ | |||
1231 | ||||
1232 | if (c->tasks_max != CGROUP_LIMIT_MAX((uint64_t) -1)) { | |||
1233 | u->manager->sysctl_pid_max_changed = true1; | |||
1234 | r = procfs_tasks_set_limit(c->tasks_max); | |||
1235 | } else if (u->manager->sysctl_pid_max_changed) | |||
1236 | r = procfs_tasks_set_limit(TASKS_MAX4194303U); | |||
1237 | else | |||
1238 | r = 0; | |||
1239 | ||||
1240 | if (r < 0) | |||
1241 | log_unit_full(u, IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r,({ const Unit *_u = (u); _u ? log_object_internal(({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){-2, -30, -13})/sizeof(int)]; switch(r) { case -2: case -30: case -13: _found = 1; break; default: break ; } _found; }) ? 7 : 4, r, "../src/core/cgroup.c", 1242, __func__ , _u->manager->unit_log_field, _u->id, _u->manager ->invocation_log_field, _u->invocation_id_string, "Failed to write to tasks limit sysctls: %m" ) : log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((( { _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){-2, -30, -13})/sizeof(int)]; switch(r) { case -2: case -30: case -13: _found = 1; break; default: break ; } _found; }) ? 7 : 4))), r, "../src/core/cgroup.c", 1242, __func__ , "Failed to write to tasks limit sysctls: %m"); }) | |||
1242 | "Failed to write to tasks limit sysctls: %m")({ const Unit *_u = (u); _u ? log_object_internal(({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){-2, -30, -13})/sizeof(int)]; switch(r) { case -2: case -30: case -13: _found = 1; break; default: break ; } _found; }) ? 7 : 4, r, "../src/core/cgroup.c", 1242, __func__ , _u->manager->unit_log_field, _u->id, _u->manager ->invocation_log_field, _u->invocation_id_string, "Failed to write to tasks limit sysctls: %m" ) : log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((( { _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){-2, -30, -13})/sizeof(int)]; switch(r) { case -2: case -30: case -13: _found = 1; break; default: break ; } _found; }) ? 7 : 4))), r, "../src/core/cgroup.c", 1242, __func__ , "Failed to write to tasks limit sysctls: %m"); }); | |||
1243 | ||||
1244 | } else { | |||
1245 | if (c->tasks_max != CGROUP_LIMIT_MAX((uint64_t) -1)) { | |||
1246 | char buf[DECIMAL_STR_MAX(uint64_t)(2+(sizeof(uint64_t) <= 1 ? 3 : sizeof(uint64_t) <= 2 ? 5 : sizeof(uint64_t) <= 4 ? 10 : sizeof(uint64_t) <= 8 ? 20 : sizeof(int[-2*(sizeof(uint64_t) > 8)]))) + 2]; | |||
1247 | ||||
1248 | sprintf(buf, "%" PRIu64"l" "u" "\n", c->tasks_max); | |||
1249 | r = cg_set_attribute("pids", path, "pids.max", buf); | |||
1250 | } else | |||
1251 | r = cg_set_attribute("pids", path, "pids.max", "max"); | |||
1252 | if (r < 0) | |||
1253 | log_unit_full(u, IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r,({ const Unit *_u = (u); _u ? log_object_internal(({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){-2, -30, -13})/sizeof(int)]; switch(r) { case -2: case -30: case -13: _found = 1; break; default: break ; } _found; }) ? 7 : 4, r, "../src/core/cgroup.c", 1254, __func__ , _u->manager->unit_log_field, _u->id, _u->manager ->invocation_log_field, _u->invocation_id_string, "Failed to set pids.max: %m" ) : log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((( { _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){-2, -30, -13})/sizeof(int)]; switch(r) { case -2: case -30: case -13: _found = 1; break; default: break ; } _found; }) ? 7 : 4))), r, "../src/core/cgroup.c", 1254, __func__ , "Failed to set pids.max: %m"); }) | |||
1254 | "Failed to set pids.max: %m")({ const Unit *_u = (u); _u ? log_object_internal(({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){-2, -30, -13})/sizeof(int)]; switch(r) { case -2: case -30: case -13: _found = 1; break; default: break ; } _found; }) ? 7 : 4, r, "../src/core/cgroup.c", 1254, __func__ , _u->manager->unit_log_field, _u->id, _u->manager ->invocation_log_field, _u->invocation_id_string, "Failed to set pids.max: %m" ) : log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((( { _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){-2, -30, -13})/sizeof(int)]; switch(r) { case -2: case -30: case -13: _found = 1; break; default: break ; } _found; }) ? 7 : 4))), r, "../src/core/cgroup.c", 1254, __func__ , "Failed to set pids.max: %m"); }); | |||
1255 | } | |||
1256 | } | |||
1257 | ||||
1258 | if (apply_bpf) | |||
1259 | cgroup_apply_firewall(u); | |||
1260 | } | |||
1261 | ||||
1262 | static CGroupMask unit_get_cgroup_mask(Unit *u) { | |||
1263 | CGroupMask mask = 0; | |||
1264 | CGroupContext *c; | |||
1265 | ||||
1266 | assert(u)do { if ((__builtin_expect(!!(!(u)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("u"), "../src/core/cgroup.c", 1266, __PRETTY_FUNCTION__ ); } while (0); | |||
1267 | ||||
1268 | c = unit_get_cgroup_context(u); | |||
1269 | ||||
1270 | /* Figure out which controllers we need */ | |||
1271 | ||||
1272 | if (c->cpu_accounting || | |||
1273 | cgroup_context_has_cpu_weight(c) || | |||
1274 | cgroup_context_has_cpu_shares(c) || | |||
1275 | c->cpu_quota_per_sec_usec != USEC_INFINITY((usec_t) -1)) | |||
1276 | mask |= CGROUP_MASK_CPUACCT | CGROUP_MASK_CPU; | |||
1277 | ||||
1278 | if (c->cpuset_cpus.set || c->cpuset_mems.set) | |||
1279 | mask |= CGROUP_MASK_CPUSET; | |||
1280 | ||||
1281 | if (cgroup_context_has_io_config(c) || cgroup_context_has_blockio_config(c)) | |||
1282 | mask |= CGROUP_MASK_IO | CGROUP_MASK_BLKIO; | |||
1283 | ||||
1284 | if (c->memory_accounting || | |||
1285 | c->memory_limit != CGROUP_LIMIT_MAX((uint64_t) -1) || | |||
1286 | unit_has_unified_memory_config(u)) | |||
1287 | mask |= CGROUP_MASK_MEMORY; | |||
1288 | ||||
1289 | if (c->device_allow || | |||
1290 | c->device_policy != CGROUP_AUTO) | |||
1291 | mask |= CGROUP_MASK_DEVICES; | |||
1292 | ||||
1293 | if (c->tasks_accounting || | |||
1294 | c->tasks_max != CGROUP_LIMIT_MAX((uint64_t) -1)) | |||
1295 | mask |= CGROUP_MASK_PIDS; | |||
1296 | ||||
1297 | return mask; | |||
1298 | } | |||
1299 | ||||
1300 | CGroupMask unit_get_own_mask(Unit *u) { | |||
1301 | CGroupContext *c; | |||
1302 | ||||
1303 | /* Returns the mask of controllers the unit needs for itself */ | |||
1304 | ||||
1305 | c = unit_get_cgroup_context(u); | |||
1306 | if (!c) | |||
1307 | return 0; | |||
1308 | ||||
1309 | return unit_get_cgroup_mask(u) | unit_get_delegate_mask(u); | |||
1310 | } | |||
1311 | ||||
1312 | CGroupMask unit_get_delegate_mask(Unit *u) { | |||
1313 | CGroupContext *c; | |||
1314 | ||||
1315 | /* If delegation is turned on, then turn on selected controllers, unless we are on the legacy hierarchy and the | |||
1316 | * process we fork into is known to drop privileges, and hence shouldn't get access to the controllers. | |||
1317 | * | |||
1318 | * Note that on the unified hierarchy it is safe to delegate controllers to unprivileged services. */ | |||
1319 | ||||
1320 | if (!unit_cgroup_delegate(u)) | |||
1321 | return 0; | |||
1322 | ||||
1323 | if (cg_all_unified() <= 0) { | |||
1324 | ExecContext *e; | |||
1325 | ||||
1326 | e = unit_get_exec_context(u); | |||
1327 | if (e && !exec_context_maintains_privileges(e)) | |||
1328 | return 0; | |||
1329 | } | |||
1330 | ||||
1331 | assert_se(c = unit_get_cgroup_context(u))do { if ((__builtin_expect(!!(!(c = unit_get_cgroup_context(u ))),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("c = unit_get_cgroup_context(u)" ), "../src/core/cgroup.c", 1331, __PRETTY_FUNCTION__); } while (0); | |||
1332 | return c->delegate_controllers; | |||
1333 | } | |||
1334 | ||||
1335 | CGroupMask unit_get_members_mask(Unit *u) { | |||
1336 | assert(u)do { if ((__builtin_expect(!!(!(u)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("u"), "../src/core/cgroup.c", 1336, __PRETTY_FUNCTION__ ); } while (0); | |||
1337 | ||||
1338 | /* Returns the mask of controllers all of the unit's children require, merged */ | |||
1339 | ||||
1340 | if (u->cgroup_members_mask_valid) | |||
1341 | return u->cgroup_members_mask; | |||
1342 | ||||
1343 | u->cgroup_members_mask = 0; | |||
1344 | ||||
1345 | if (u->type == UNIT_SLICE) { | |||
1346 | void *v; | |||
1347 | Unit *member; | |||
1348 | Iterator i; | |||
1349 | ||||
1350 | HASHMAP_FOREACH_KEY(v, member, u->dependencies[UNIT_BEFORE], i)for ((i) = ((Iterator) { .idx = ((2147483647 *2U +1U) - 1), . next_key = ((void*)0) }); hashmap_iterate((u->dependencies [UNIT_BEFORE]), &(i), (void**)&(v), (const void**) & (member)); ) { | |||
1351 | ||||
1352 | if (member == u) | |||
1353 | continue; | |||
1354 | ||||
1355 | if (UNIT_DEREF(member->slice)((member->slice).target) != u) | |||
1356 | continue; | |||
1357 | ||||
1358 | u->cgroup_members_mask |= unit_get_subtree_mask(member); /* note that this calls ourselves again, for the children */ | |||
1359 | } | |||
1360 | } | |||
1361 | ||||
1362 | u->cgroup_members_mask_valid = true1; | |||
1363 | return u->cgroup_members_mask; | |||
1364 | } | |||
1365 | ||||
1366 | CGroupMask unit_get_siblings_mask(Unit *u) { | |||
1367 | assert(u)do { if ((__builtin_expect(!!(!(u)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("u"), "../src/core/cgroup.c", 1367, __PRETTY_FUNCTION__ ); } while (0); | |||
1368 | ||||
1369 | /* Returns the mask of controllers all of the unit's siblings | |||
1370 | * require, i.e. the members mask of the unit's parent slice | |||
1371 | * if there is one. */ | |||
1372 | ||||
1373 | if (UNIT_ISSET(u->slice)(!!(u->slice).target)) | |||
1374 | return unit_get_members_mask(UNIT_DEREF(u->slice)((u->slice).target)); | |||
1375 | ||||
1376 | return unit_get_subtree_mask(u); /* we are the top-level slice */ | |||
1377 | } | |||
1378 | ||||
1379 | CGroupMask unit_get_subtree_mask(Unit *u) { | |||
1380 | ||||
1381 | /* Returns the mask of this subtree, meaning of the group | |||
1382 | * itself and its children. */ | |||
1383 | ||||
1384 | return unit_get_own_mask(u) | unit_get_members_mask(u); | |||
1385 | } | |||
1386 | ||||
1387 | CGroupMask unit_get_target_mask(Unit *u) { | |||
1388 | CGroupMask mask; | |||
1389 | ||||
1390 | /* This returns the cgroup mask of all controllers to enable | |||
1391 | * for a specific cgroup, i.e. everything it needs itself, | |||
1392 | * plus all that its children need, plus all that its siblings | |||
1393 | * need. This is primarily useful on the legacy cgroup | |||
1394 | * hierarchy, where we need to duplicate each cgroup in each | |||
1395 | * hierarchy that shall be enabled for it. */ | |||
1396 | ||||
1397 | mask = unit_get_own_mask(u) | unit_get_members_mask(u) | unit_get_siblings_mask(u); | |||
1398 | mask &= u->manager->cgroup_supported; | |||
1399 | ||||
1400 | return mask; | |||
1401 | } | |||
1402 | ||||
1403 | CGroupMask unit_get_enable_mask(Unit *u) { | |||
1404 | CGroupMask mask; | |||
1405 | ||||
1406 | /* This returns the cgroup mask of all controllers to enable | |||
1407 | * for the children of a specific cgroup. This is primarily | |||
1408 | * useful for the unified cgroup hierarchy, where each cgroup | |||
1409 | * controls which controllers are enabled for its children. */ | |||
1410 | ||||
1411 | mask = unit_get_members_mask(u); | |||
1412 | mask &= u->manager->cgroup_supported; | |||
1413 | ||||
1414 | return mask; | |||
1415 | } | |||
1416 | ||||
1417 | bool_Bool unit_get_needs_bpf(Unit *u) { | |||
1418 | CGroupContext *c; | |||
1419 | Unit *p; | |||
1420 | assert(u)do { if ((__builtin_expect(!!(!(u)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("u"), "../src/core/cgroup.c", 1420, __PRETTY_FUNCTION__ ); } while (0); | |||
1421 | ||||
1422 | c = unit_get_cgroup_context(u); | |||
1423 | if (!c) | |||
1424 | return false0; | |||
1425 | ||||
1426 | if (c->ip_accounting || | |||
1427 | c->ip_address_allow || | |||
1428 | c->ip_address_deny) | |||
1429 | return true1; | |||
1430 | ||||
1431 | /* If any parent slice has an IP access list defined, it applies too */ | |||
1432 | for (p = UNIT_DEREF(u->slice)((u->slice).target); p; p = UNIT_DEREF(p->slice)((p->slice).target)) { | |||
1433 | c = unit_get_cgroup_context(p); | |||
1434 | if (!c) | |||
1435 | return false0; | |||
1436 | ||||
1437 | if (c->ip_address_allow || | |||
1438 | c->ip_address_deny) | |||
1439 | return true1; | |||
1440 | } | |||
1441 | ||||
1442 | return false0; | |||
1443 | } | |||
1444 | ||||
1445 | /* Recurse from a unit up through its containing slices, propagating | |||
1446 | * mask bits upward. A unit is also member of itself. */ | |||
1447 | void unit_update_cgroup_members_masks(Unit *u) { | |||
1448 | CGroupMask m; | |||
1449 | bool_Bool more; | |||
1450 | ||||
1451 | assert(u)do { if ((__builtin_expect(!!(!(u)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("u"), "../src/core/cgroup.c", 1451, __PRETTY_FUNCTION__ ); } while (0); | |||
1452 | ||||
1453 | /* Calculate subtree mask */ | |||
1454 | m = unit_get_subtree_mask(u); | |||
1455 | ||||
1456 | /* See if anything changed from the previous invocation. If | |||
1457 | * not, we're done. */ | |||
1458 | if (u->cgroup_subtree_mask_valid && m == u->cgroup_subtree_mask) | |||
1459 | return; | |||
1460 | ||||
1461 | more = | |||
1462 | u->cgroup_subtree_mask_valid && | |||
1463 | ((m & ~u->cgroup_subtree_mask) != 0) && | |||
1464 | ((~m & u->cgroup_subtree_mask) == 0); | |||
1465 | ||||
1466 | u->cgroup_subtree_mask = m; | |||
1467 | u->cgroup_subtree_mask_valid = true1; | |||
1468 | ||||
1469 | if (UNIT_ISSET(u->slice)(!!(u->slice).target)) { | |||
1470 | Unit *s = UNIT_DEREF(u->slice)((u->slice).target); | |||
1471 | ||||
1472 | if (more) | |||
1473 | /* There's more set now than before. We | |||
1474 | * propagate the new mask to the parent's mask | |||
1475 | * (not caring if it actually was valid or | |||
1476 | * not). */ | |||
1477 | ||||
1478 | s->cgroup_members_mask |= m; | |||
1479 | ||||
1480 | else | |||
1481 | /* There's less set now than before (or we | |||
1482 | * don't know), we need to recalculate | |||
1483 | * everything, so let's invalidate the | |||
1484 | * parent's members mask */ | |||
1485 | ||||
1486 | s->cgroup_members_mask_valid = false0; | |||
1487 | ||||
1488 | /* And now make sure that this change also hits our | |||
1489 | * grandparents */ | |||
1490 | unit_update_cgroup_members_masks(s); | |||
1491 | } | |||
1492 | } | |||
1493 | ||||
1494 | const char *unit_get_realized_cgroup_path(Unit *u, CGroupMask mask) { | |||
1495 | ||||
1496 | /* Returns the realized cgroup path of the specified unit where all specified controllers are available. */ | |||
1497 | ||||
1498 | while (u) { | |||
1499 | ||||
1500 | if (u->cgroup_path && | |||
1501 | u->cgroup_realized && | |||
1502 | FLAGS_SET(u->cgroup_realized_mask, mask)(((u->cgroup_realized_mask) & (mask)) == (mask))) | |||
1503 | return u->cgroup_path; | |||
1504 | ||||
1505 | u = UNIT_DEREF(u->slice)((u->slice).target); | |||
1506 | } | |||
1507 | ||||
1508 | return NULL((void*)0); | |||
1509 | } | |||
1510 | ||||
1511 | static const char *migrate_callback(CGroupMask mask, void *userdata) { | |||
1512 | return unit_get_realized_cgroup_path(userdata, mask); | |||
1513 | } | |||
1514 | ||||
1515 | char *unit_default_cgroup_path(Unit *u) { | |||
1516 | _cleanup_free___attribute__((cleanup(freep))) char *escaped = NULL((void*)0), *slice = NULL((void*)0); | |||
1517 | int r; | |||
1518 | ||||
1519 | assert(u)do { if ((__builtin_expect(!!(!(u)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("u"), "../src/core/cgroup.c", 1519, __PRETTY_FUNCTION__ ); } while (0); | |||
1520 | ||||
1521 | if (unit_has_name(u, SPECIAL_ROOT_SLICE"-.slice")) | |||
1522 | return strdup(u->manager->cgroup_root); | |||
1523 | ||||
1524 | if (UNIT_ISSET(u->slice)(!!(u->slice).target) && !unit_has_name(UNIT_DEREF(u->slice)((u->slice).target), SPECIAL_ROOT_SLICE"-.slice")) { | |||
1525 | r = cg_slice_to_path(UNIT_DEREF(u->slice)((u->slice).target)->id, &slice); | |||
1526 | if (r < 0) | |||
1527 | return NULL((void*)0); | |||
1528 | } | |||
1529 | ||||
1530 | escaped = cg_escape(u->id); | |||
1531 | if (!escaped) | |||
1532 | return NULL((void*)0); | |||
1533 | ||||
1534 | if (slice) | |||
1535 | return strjoin(u->manager->cgroup_root, "/", slice, "/",strjoin_real((u->manager->cgroup_root), "/", slice, "/" , escaped, ((void*)0)) | |||
1536 | escaped)strjoin_real((u->manager->cgroup_root), "/", slice, "/" , escaped, ((void*)0)); | |||
1537 | else | |||
1538 | return strjoin(u->manager->cgroup_root, "/", escaped)strjoin_real((u->manager->cgroup_root), "/", escaped, ( (void*)0)); | |||
1539 | } | |||
1540 | ||||
1541 | int unit_set_cgroup_path(Unit *u, const char *path) { | |||
1542 | _cleanup_free___attribute__((cleanup(freep))) char *p = NULL((void*)0); | |||
1543 | int r; | |||
1544 | ||||
1545 | assert(u)do { if ((__builtin_expect(!!(!(u)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("u"), "../src/core/cgroup.c", 1545, __PRETTY_FUNCTION__ ); } while (0); | |||
1546 | ||||
1547 | if (path
| |||
1548 | p = strdup(path); | |||
1549 | if (!p) | |||
1550 | return -ENOMEM12; | |||
1551 | } else | |||
1552 | p = NULL((void*)0); | |||
1553 | ||||
1554 | if (streq_ptr(u->cgroup_path, p)) | |||
1555 | return 0; | |||
| ||||
1556 | ||||
1557 | if (p) { | |||
1558 | r = hashmap_put(u->manager->cgroup_unit, p, u); | |||
1559 | if (r < 0) | |||
1560 | return r; | |||
1561 | } | |||
1562 | ||||
1563 | unit_release_cgroup(u); | |||
1564 | ||||
1565 | u->cgroup_path = TAKE_PTR(p)({ typeof(p) _ptr_ = (p); (p) = ((void*)0); _ptr_; }); | |||
1566 | ||||
1567 | return 1; | |||
1568 | } | |||
1569 | ||||
1570 | int unit_watch_cgroup(Unit *u) { | |||
1571 | _cleanup_free___attribute__((cleanup(freep))) char *events = NULL((void*)0); | |||
1572 | int r; | |||
1573 | ||||
1574 | assert(u)do { if ((__builtin_expect(!!(!(u)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("u"), "../src/core/cgroup.c", 1574, __PRETTY_FUNCTION__ ); } while (0); | |||
1575 | ||||
1576 | if (!u->cgroup_path) | |||
1577 | return 0; | |||
1578 | ||||
1579 | if (u->cgroup_inotify_wd >= 0) | |||
1580 | return 0; | |||
1581 | ||||
1582 | /* Only applies to the unified hierarchy */ | |||
1583 | r = cg_unified_controller(SYSTEMD_CGROUP_CONTROLLER"_systemd"); | |||
1584 | if (r < 0) | |||
1585 | return log_error_errno(r, "Failed to determine whether the name=systemd hierarchy is unified: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/core/cgroup.c", 1585, __func__, "Failed to determine whether the name=systemd hierarchy is unified: %m" ) : -abs(_e); }); | |||
1586 | if (r == 0) | |||
1587 | return 0; | |||
1588 | ||||
1589 | /* Don't watch the root slice, it's pointless. */ | |||
1590 | if (unit_has_name(u, SPECIAL_ROOT_SLICE"-.slice")) | |||
1591 | return 0; | |||
1592 | ||||
1593 | r = hashmap_ensure_allocated(&u->manager->cgroup_inotify_wd_unit, &trivial_hash_ops)internal_hashmap_ensure_allocated(&u->manager->cgroup_inotify_wd_unit , &trivial_hash_ops ); | |||
1594 | if (r < 0) | |||
1595 | return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/core/cgroup.c", 1595 , __func__); | |||
1596 | ||||
1597 | r = cg_get_path(SYSTEMD_CGROUP_CONTROLLER"_systemd", u->cgroup_path, "cgroup.events", &events); | |||
1598 | if (r < 0) | |||
1599 | return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/core/cgroup.c", 1599 , __func__); | |||
1600 | ||||
1601 | u->cgroup_inotify_wd = inotify_add_watch(u->manager->cgroup_inotify_fd, events, IN_MODIFY0x00000002); | |||
1602 | if (u->cgroup_inotify_wd < 0) { | |||
1603 | ||||
1604 | if (errno(*__errno_location ()) == ENOENT2) /* If the directory is already | |||
1605 | * gone we don't need to track | |||
1606 | * it, so this is not an error */ | |||
1607 | return 0; | |||
1608 | ||||
1609 | return log_unit_error_errno(u, errno, "Failed to add inotify watch descriptor for control group %s: %m", u->cgroup_path)({ const Unit *_u = (u); _u ? log_object_internal(3, (*__errno_location ()), "../src/core/cgroup.c", 1609, __func__, _u->manager-> unit_log_field, _u->id, _u->manager->invocation_log_field , _u->invocation_id_string, "Failed to add inotify watch descriptor for control group %s: %m" , u->cgroup_path) : log_internal_realm(((LOG_REALM_SYSTEMD ) << 10 | ((3))), (*__errno_location ()), "../src/core/cgroup.c" , 1609, __func__, "Failed to add inotify watch descriptor for control group %s: %m" , u->cgroup_path); }); | |||
1610 | } | |||
1611 | ||||
1612 | r = hashmap_put(u->manager->cgroup_inotify_wd_unit, INT_TO_PTR(u->cgroup_inotify_wd)((void *) ((intptr_t) (u->cgroup_inotify_wd))), u); | |||
1613 | if (r < 0) | |||
1614 | return log_unit_error_errno(u, r, "Failed to add inotify watch descriptor to hash map: %m")({ const Unit *_u = (u); _u ? log_object_internal(3, r, "../src/core/cgroup.c" , 1614, __func__, _u->manager->unit_log_field, _u->id , _u->manager->invocation_log_field, _u->invocation_id_string , "Failed to add inotify watch descriptor to hash map: %m") : log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((3))) , r, "../src/core/cgroup.c", 1614, __func__, "Failed to add inotify watch descriptor to hash map: %m" ); }); | |||
1615 | ||||
1616 | return 0; | |||
1617 | } | |||
1618 | ||||
1619 | int unit_pick_cgroup_path(Unit *u) { | |||
1620 | _cleanup_free___attribute__((cleanup(freep))) char *path = NULL((void*)0); | |||
1621 | int r; | |||
1622 | ||||
1623 | assert(u)do { if ((__builtin_expect(!!(!(u)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("u"), "../src/core/cgroup.c", 1623, __PRETTY_FUNCTION__ ); } while (0); | |||
1624 | ||||
1625 | if (u->cgroup_path) | |||
1626 | return 0; | |||
1627 | ||||
1628 | if (!UNIT_HAS_CGROUP_CONTEXT(u)(unit_vtable[(u)->type]->cgroup_context_offset > 0)) | |||
1629 | return -EINVAL22; | |||
1630 | ||||
1631 | path = unit_default_cgroup_path(u); | |||
1632 | if (!path) | |||
1633 | return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/core/cgroup.c", 1633 , __func__); | |||
1634 | ||||
1635 | r = unit_set_cgroup_path(u, path); | |||
1636 | if (r == -EEXIST17) | |||
1637 | return log_unit_error_errno(u, r, "Control group %s exists already.", path)({ const Unit *_u = (u); _u ? log_object_internal(3, r, "../src/core/cgroup.c" , 1637, __func__, _u->manager->unit_log_field, _u->id , _u->manager->invocation_log_field, _u->invocation_id_string , "Control group %s exists already.", path) : log_internal_realm (((LOG_REALM_SYSTEMD) << 10 | ((3))), r, "../src/core/cgroup.c" , 1637, __func__, "Control group %s exists already.", path); } ); | |||
1638 | if (r < 0) | |||
1639 | return log_unit_error_errno(u, r, "Failed to set unit's control group path to %s: %m", path)({ const Unit *_u = (u); _u ? log_object_internal(3, r, "../src/core/cgroup.c" , 1639, __func__, _u->manager->unit_log_field, _u->id , _u->manager->invocation_log_field, _u->invocation_id_string , "Failed to set unit's control group path to %s: %m", path) : log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((3))) , r, "../src/core/cgroup.c", 1639, __func__, "Failed to set unit's control group path to %s: %m" , path); }); | |||
1640 | ||||
1641 | return 0; | |||
1642 | } | |||
1643 | ||||
1644 | static int unit_create_cgroup( | |||
1645 | Unit *u, | |||
1646 | CGroupMask target_mask, | |||
1647 | CGroupMask enable_mask, | |||
1648 | bool_Bool needs_bpf) { | |||
1649 | ||||
1650 | CGroupContext *c; | |||
1651 | int r; | |||
1652 | bool_Bool created; | |||
1653 | ||||
1654 | assert(u)do { if ((__builtin_expect(!!(!(u)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("u"), "../src/core/cgroup.c", 1654, __PRETTY_FUNCTION__ ); } while (0); | |||
1655 | ||||
1656 | c = unit_get_cgroup_context(u); | |||
1657 | if (!c) | |||
1658 | return 0; | |||
1659 | ||||
1660 | /* Figure out our cgroup path */ | |||
1661 | r = unit_pick_cgroup_path(u); | |||
1662 | if (r < 0) | |||
1663 | return r; | |||
1664 | ||||
1665 | /* First, create our own group */ | |||
1666 | r = cg_create_everywhere(u->manager->cgroup_supported, target_mask, u->cgroup_path); | |||
1667 | if (r < 0) | |||
1668 | return log_unit_error_errno(u, r, "Failed to create cgroup %s: %m", u->cgroup_path)({ const Unit *_u = (u); _u ? log_object_internal(3, r, "../src/core/cgroup.c" , 1668, __func__, _u->manager->unit_log_field, _u->id , _u->manager->invocation_log_field, _u->invocation_id_string , "Failed to create cgroup %s: %m", u->cgroup_path) : log_internal_realm (((LOG_REALM_SYSTEMD) << 10 | ((3))), r, "../src/core/cgroup.c" , 1668, __func__, "Failed to create cgroup %s: %m", u->cgroup_path ); }); | |||
1669 | created = !!r; | |||
1670 | ||||
1671 | /* Start watching it */ | |||
1672 | (void) unit_watch_cgroup(u); | |||
1673 | ||||
1674 | /* Preserve enabled controllers in delegated units, adjust others. */ | |||
1675 | if (created || !unit_cgroup_delegate(u)) { | |||
1676 | ||||
1677 | /* Enable all controllers we need */ | |||
1678 | r = cg_enable_everywhere(u->manager->cgroup_supported, enable_mask, u->cgroup_path); | |||
1679 | if (r < 0) | |||
1680 | log_unit_warning_errno(u, r, "Failed to enable controllers on cgroup %s, ignoring: %m",({ const Unit *_u = (u); _u ? log_object_internal(4, r, "../src/core/cgroup.c" , 1681, __func__, _u->manager->unit_log_field, _u->id , _u->manager->invocation_log_field, _u->invocation_id_string , "Failed to enable controllers on cgroup %s, ignoring: %m", u ->cgroup_path) : log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((4))), r, "../src/core/cgroup.c", 1681, __func__, "Failed to enable controllers on cgroup %s, ignoring: %m" , u->cgroup_path); }) | |||
1681 | u->cgroup_path)({ const Unit *_u = (u); _u ? log_object_internal(4, r, "../src/core/cgroup.c" , 1681, __func__, _u->manager->unit_log_field, _u->id , _u->manager->invocation_log_field, _u->invocation_id_string , "Failed to enable controllers on cgroup %s, ignoring: %m", u ->cgroup_path) : log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((4))), r, "../src/core/cgroup.c", 1681, __func__, "Failed to enable controllers on cgroup %s, ignoring: %m" , u->cgroup_path); }); | |||
1682 | } | |||
1683 | ||||
1684 | /* Keep track that this is now realized */ | |||
1685 | u->cgroup_realized = true1; | |||
1686 | u->cgroup_realized_mask = target_mask; | |||
1687 | u->cgroup_enabled_mask = enable_mask; | |||
1688 | u->cgroup_bpf_state = needs_bpf ? UNIT_CGROUP_BPF_ON : UNIT_CGROUP_BPF_OFF; | |||
1689 | ||||
1690 | if (u->type != UNIT_SLICE && !unit_cgroup_delegate(u)) { | |||
1691 | ||||
1692 | /* Then, possibly move things over, but not if | |||
1693 | * subgroups may contain processes, which is the case | |||
1694 | * for slice and delegation units. */ | |||
1695 | r = cg_migrate_everywhere(u->manager->cgroup_supported, u->cgroup_path, u->cgroup_path, migrate_callback, u); | |||
1696 | if (r < 0) | |||
1697 | log_unit_warning_errno(u, r, "Failed to migrate cgroup from to %s, ignoring: %m", u->cgroup_path)({ const Unit *_u = (u); _u ? log_object_internal(4, r, "../src/core/cgroup.c" , 1697, __func__, _u->manager->unit_log_field, _u->id , _u->manager->invocation_log_field, _u->invocation_id_string , "Failed to migrate cgroup from to %s, ignoring: %m", u-> cgroup_path) : log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((4))), r, "../src/core/cgroup.c", 1697, __func__, "Failed to migrate cgroup from to %s, ignoring: %m" , u->cgroup_path); }); | |||
1698 | } | |||
1699 | ||||
1700 | return 0; | |||
1701 | } | |||
1702 | ||||
1703 | static int unit_attach_pid_to_cgroup_via_bus(Unit *u, pid_t pid, const char *suffix_path) { | |||
1704 | _cleanup_(sd_bus_error_free)__attribute__((cleanup(sd_bus_error_free))) sd_bus_error error = SD_BUS_ERROR_NULL((const sd_bus_error) {(((void*)0)), (((void*)0)), 0}); | |||
1705 | char *pp; | |||
1706 | int r; | |||
1707 | ||||
1708 | assert(u)do { if ((__builtin_expect(!!(!(u)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("u"), "../src/core/cgroup.c", 1708, __PRETTY_FUNCTION__ ); } while (0); | |||
1709 | ||||
1710 | if (MANAGER_IS_SYSTEM(u->manager)((u->manager)->unit_file_scope == UNIT_FILE_SYSTEM)) | |||
1711 | return -EINVAL22; | |||
1712 | ||||
1713 | if (!u->manager->system_bus) | |||
1714 | return -EIO5; | |||
1715 | ||||
1716 | if (!u->cgroup_path) | |||
1717 | return -EINVAL22; | |||
1718 | ||||
1719 | /* Determine this unit's cgroup path relative to our cgroup root */ | |||
1720 | pp = path_startswith(u->cgroup_path, u->manager->cgroup_root); | |||
1721 | if (!pp) | |||
1722 | return -EINVAL22; | |||
1723 | ||||
1724 | pp = strjoina("/", pp, suffix_path)({ const char *_appendees_[] = { "/", pp, suffix_path }; char *_d_, *_p_; size_t _len_ = 0; size_t _i_; for (_i_ = 0; _i_ < __extension__ (__builtin_choose_expr( !__builtin_types_compatible_p (typeof(_appendees_), typeof(&*(_appendees_))), sizeof(_appendees_ )/sizeof((_appendees_)[0]), ((void)0))) && _appendees_ [_i_]; _i_++) _len_ += strlen(_appendees_[_i_]); _p_ = _d_ = __builtin_alloca (_len_ + 1); for (_i_ = 0; _i_ < __extension__ (__builtin_choose_expr ( !__builtin_types_compatible_p(typeof(_appendees_), typeof(& *(_appendees_))), sizeof(_appendees_)/sizeof((_appendees_)[0] ), ((void)0))) && _appendees_[_i_]; _i_++) _p_ = stpcpy (_p_, _appendees_[_i_]); *_p_ = 0; _d_; }); | |||
1725 | path_simplify(pp, false0); | |||
1726 | ||||
1727 | r = sd_bus_call_method(u->manager->system_bus, | |||
1728 | "org.freedesktop.systemd1", | |||
1729 | "/org/freedesktop/systemd1", | |||
1730 | "org.freedesktop.systemd1.Manager", | |||
1731 | "AttachProcessesToUnit", | |||
1732 | &error, NULL((void*)0), | |||
1733 | "ssau", | |||
1734 | NULL((void*)0) /* empty unit name means client's unit, i.e. us */, pp, 1, (uint32_t) pid); | |||
1735 | if (r < 0) | |||
1736 | return log_unit_debug_errno(u, r, "Failed to attach unit process " PID_FMT " via the bus: %s", pid, bus_error_message(&error, r))({ const Unit *_u = (u); _u ? log_object_internal(7, r, "../src/core/cgroup.c" , 1736, __func__, _u->manager->unit_log_field, _u->id , _u->manager->invocation_log_field, _u->invocation_id_string , "Failed to attach unit process " "%" "i" " via the bus: %s" , pid, bus_error_message(&error, r)) : log_internal_realm (((LOG_REALM_SYSTEMD) << 10 | ((7))), r, "../src/core/cgroup.c" , 1736, __func__, "Failed to attach unit process " "%" "i" " via the bus: %s" , pid, bus_error_message(&error, r)); }); | |||
1737 | ||||
1738 | return 0; | |||
1739 | } | |||
1740 | ||||
1741 | int unit_attach_pids_to_cgroup(Unit *u, Set *pids, const char *suffix_path) { | |||
1742 | CGroupMask delegated_mask; | |||
1743 | const char *p; | |||
1744 | Iterator i; | |||
1745 | void *pidp; | |||
1746 | int r, q; | |||
1747 | ||||
1748 | assert(u)do { if ((__builtin_expect(!!(!(u)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("u"), "../src/core/cgroup.c", 1748, __PRETTY_FUNCTION__ ); } while (0); | |||
1749 | ||||
1750 | if (!UNIT_HAS_CGROUP_CONTEXT(u)(unit_vtable[(u)->type]->cgroup_context_offset > 0)) | |||
1751 | return -EINVAL22; | |||
1752 | ||||
1753 | if (set_isempty(pids)) | |||
1754 | return 0; | |||
1755 | ||||
1756 | r = unit_realize_cgroup(u); | |||
1757 | if (r < 0) | |||
1758 | return r; | |||
1759 | ||||
1760 | if (isempty(suffix_path)) | |||
1761 | p = u->cgroup_path; | |||
1762 | else | |||
1763 | p = strjoina(u->cgroup_path, "/", suffix_path)({ const char *_appendees_[] = { u->cgroup_path, "/", suffix_path }; char *_d_, *_p_; size_t _len_ = 0; size_t _i_; for (_i_ = 0; _i_ < __extension__ (__builtin_choose_expr( !__builtin_types_compatible_p (typeof(_appendees_), typeof(&*(_appendees_))), sizeof(_appendees_ )/sizeof((_appendees_)[0]), ((void)0))) && _appendees_ [_i_]; _i_++) _len_ += strlen(_appendees_[_i_]); _p_ = _d_ = __builtin_alloca (_len_ + 1); for (_i_ = 0; _i_ < __extension__ (__builtin_choose_expr ( !__builtin_types_compatible_p(typeof(_appendees_), typeof(& *(_appendees_))), sizeof(_appendees_)/sizeof((_appendees_)[0] ), ((void)0))) && _appendees_[_i_]; _i_++) _p_ = stpcpy (_p_, _appendees_[_i_]); *_p_ = 0; _d_; }); | |||
1764 | ||||
1765 | delegated_mask = unit_get_delegate_mask(u); | |||
1766 | ||||
1767 | r = 0; | |||
1768 | SET_FOREACH(pidp, pids, i)for ((i) = ((Iterator) { .idx = ((2147483647 *2U +1U) - 1), . next_key = ((void*)0) }); set_iterate((pids), &(i), (void **)&(pidp)); ) { | |||
1769 | pid_t pid = PTR_TO_PID(pidp); | |||
1770 | CGroupController c; | |||
1771 | ||||
1772 | /* First, attach the PID to the main cgroup hierarchy */ | |||
1773 | q = cg_attach(SYSTEMD_CGROUP_CONTROLLER"_systemd", p, pid); | |||
1774 | if (q < 0) { | |||
1775 | log_unit_debug_errno(u, q, "Couldn't move process " PID_FMT " to requested cgroup '%s': %m", pid, p)({ const Unit *_u = (u); _u ? log_object_internal(7, q, "../src/core/cgroup.c" , 1775, __func__, _u->manager->unit_log_field, _u->id , _u->manager->invocation_log_field, _u->invocation_id_string , "Couldn't move process " "%" "i" " to requested cgroup '%s': %m" , pid, p) : log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((7))), q, "../src/core/cgroup.c", 1775, __func__, "Couldn't move process " "%" "i" " to requested cgroup '%s': %m", pid, p); }); | |||
1776 | ||||
1777 | if (MANAGER_IS_USER(u->manager)((u->manager)->unit_file_scope != UNIT_FILE_SYSTEM) && IN_SET(q, -EPERM, -EACCES)({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){-1, -13})/sizeof(int)]; switch(q) { case -1: case -13: _found = 1; break; default: break; } _found; } )) { | |||
1778 | int z; | |||
1779 | ||||
1780 | /* If we are in a user instance, and we can't move the process ourselves due to | |||
1781 | * permission problems, let's ask the system instance about it instead. Since it's more | |||
1782 | * privileged it might be able to move the process across the leaves of a subtree who's | |||
1783 | * top node is not owned by us. */ | |||
1784 | ||||
1785 | z = unit_attach_pid_to_cgroup_via_bus(u, pid, suffix_path); | |||
1786 | if (z < 0) | |||
1787 | log_unit_debug_errno(u, z, "Couldn't move process " PID_FMT " to requested cgroup '%s' via the system bus either: %m", pid, p)({ const Unit *_u = (u); _u ? log_object_internal(7, z, "../src/core/cgroup.c" , 1787, __func__, _u->manager->unit_log_field, _u->id , _u->manager->invocation_log_field, _u->invocation_id_string , "Couldn't move process " "%" "i" " to requested cgroup '%s' via the system bus either: %m" , pid, p) : log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((7))), z, "../src/core/cgroup.c", 1787, __func__, "Couldn't move process " "%" "i" " to requested cgroup '%s' via the system bus either: %m" , pid, p); }); | |||
1788 | else | |||
1789 | continue; /* When the bus thing worked via the bus we are fully done for this PID. */ | |||
1790 | } | |||
1791 | ||||
1792 | if (r >= 0) | |||
1793 | r = q; /* Remember first error */ | |||
1794 | ||||
1795 | continue; | |||
1796 | } | |||
1797 | ||||
1798 | q = cg_all_unified(); | |||
1799 | if (q < 0) | |||
1800 | return q; | |||
1801 | if (q > 0) | |||
1802 | continue; | |||
1803 | ||||
1804 | /* In the legacy hierarchy, attach the process to the request cgroup if possible, and if not to the | |||
1805 | * innermost realized one */ | |||
1806 | ||||
1807 | for (c = 0; c < _CGROUP_CONTROLLER_MAX; c++) { | |||
1808 | CGroupMask bit = CGROUP_CONTROLLER_TO_MASK(c)(1 << (c)); | |||
1809 | const char *realized; | |||
1810 | ||||
1811 | if (!(u->manager->cgroup_supported & bit)) | |||
1812 | continue; | |||
1813 | ||||
1814 | /* If this controller is delegated and realized, honour the caller's request for the cgroup suffix. */ | |||
1815 | if (delegated_mask & u->cgroup_realized_mask & bit) { | |||
1816 | q = cg_attach(cgroup_controller_to_string(c), p, pid); | |||
1817 | if (q >= 0) | |||
1818 | continue; /* Success! */ | |||
1819 | ||||
1820 | log_unit_debug_errno(u, q, "Failed to attach PID " PID_FMT " to requested cgroup %s in controller %s, falling back to unit's cgroup: %m",({ const Unit *_u = (u); _u ? log_object_internal(7, q, "../src/core/cgroup.c" , 1821, __func__, _u->manager->unit_log_field, _u->id , _u->manager->invocation_log_field, _u->invocation_id_string , "Failed to attach PID " "%" "i" " to requested cgroup %s in controller %s, falling back to unit's cgroup: %m" , pid, p, cgroup_controller_to_string(c)) : log_internal_realm (((LOG_REALM_SYSTEMD) << 10 | ((7))), q, "../src/core/cgroup.c" , 1821, __func__, "Failed to attach PID " "%" "i" " to requested cgroup %s in controller %s, falling back to unit's cgroup: %m" , pid, p, cgroup_controller_to_string(c)); }) | |||
1821 | pid, p, cgroup_controller_to_string(c))({ const Unit *_u = (u); _u ? log_object_internal(7, q, "../src/core/cgroup.c" , 1821, __func__, _u->manager->unit_log_field, _u->id , _u->manager->invocation_log_field, _u->invocation_id_string , "Failed to attach PID " "%" "i" " to requested cgroup %s in controller %s, falling back to unit's cgroup: %m" , pid, p, cgroup_controller_to_string(c)) : log_internal_realm (((LOG_REALM_SYSTEMD) << 10 | ((7))), q, "../src/core/cgroup.c" , 1821, __func__, "Failed to attach PID " "%" "i" " to requested cgroup %s in controller %s, falling back to unit's cgroup: %m" , pid, p, cgroup_controller_to_string(c)); }); | |||
1822 | } | |||
1823 | ||||
1824 | /* So this controller is either not delegate or realized, or something else weird happened. In | |||
1825 | * that case let's attach the PID at least to the closest cgroup up the tree that is | |||
1826 | * realized. */ | |||
1827 | realized = unit_get_realized_cgroup_path(u, bit); | |||
1828 | if (!realized) | |||
1829 | continue; /* Not even realized in the root slice? Then let's not bother */ | |||
1830 | ||||
1831 | q = cg_attach(cgroup_controller_to_string(c), realized, pid); | |||
1832 | if (q < 0) | |||
1833 | log_unit_debug_errno(u, q, "Failed to attach PID " PID_FMT " to realized cgroup %s in controller %s, ignoring: %m",({ const Unit *_u = (u); _u ? log_object_internal(7, q, "../src/core/cgroup.c" , 1834, __func__, _u->manager->unit_log_field, _u->id , _u->manager->invocation_log_field, _u->invocation_id_string , "Failed to attach PID " "%" "i" " to realized cgroup %s in controller %s, ignoring: %m" , pid, realized, cgroup_controller_to_string(c)) : log_internal_realm (((LOG_REALM_SYSTEMD) << 10 | ((7))), q, "../src/core/cgroup.c" , 1834, __func__, "Failed to attach PID " "%" "i" " to realized cgroup %s in controller %s, ignoring: %m" , pid, realized, cgroup_controller_to_string(c)); }) | |||
1834 | pid, realized, cgroup_controller_to_string(c))({ const Unit *_u = (u); _u ? log_object_internal(7, q, "../src/core/cgroup.c" , 1834, __func__, _u->manager->unit_log_field, _u->id , _u->manager->invocation_log_field, _u->invocation_id_string , "Failed to attach PID " "%" "i" " to realized cgroup %s in controller %s, ignoring: %m" , pid, realized, cgroup_controller_to_string(c)) : log_internal_realm (((LOG_REALM_SYSTEMD) << 10 | ((7))), q, "../src/core/cgroup.c" , 1834, __func__, "Failed to attach PID " "%" "i" " to realized cgroup %s in controller %s, ignoring: %m" , pid, realized, cgroup_controller_to_string(c)); }); | |||
1835 | } | |||
1836 | } | |||
1837 | ||||
1838 | return r; | |||
1839 | } | |||
1840 | ||||
1841 | static void cgroup_xattr_apply(Unit *u) { | |||
1842 | char ids[SD_ID128_STRING_MAX33]; | |||
1843 | int r; | |||
1844 | ||||
1845 | assert(u)do { if ((__builtin_expect(!!(!(u)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("u"), "../src/core/cgroup.c", 1845, __PRETTY_FUNCTION__ ); } while (0); | |||
1846 | ||||
1847 | if (!MANAGER_IS_SYSTEM(u->manager)((u->manager)->unit_file_scope == UNIT_FILE_SYSTEM)) | |||
1848 | return; | |||
1849 | ||||
1850 | if (sd_id128_is_null(u->invocation_id)) | |||
1851 | return; | |||
1852 | ||||
1853 | r = cg_set_xattr(SYSTEMD_CGROUP_CONTROLLER"_systemd", u->cgroup_path, | |||
1854 | "trusted.invocation_id", | |||
1855 | sd_id128_to_string(u->invocation_id, ids), 32, | |||
1856 | 0); | |||
1857 | if (r < 0) | |||
1858 | log_unit_debug_errno(u, r, "Failed to set invocation ID on control group %s, ignoring: %m", u->cgroup_path)({ const Unit *_u = (u); _u ? log_object_internal(7, r, "../src/core/cgroup.c" , 1858, __func__, _u->manager->unit_log_field, _u->id , _u->manager->invocation_log_field, _u->invocation_id_string , "Failed to set invocation ID on control group %s, ignoring: %m" , u->cgroup_path) : log_internal_realm(((LOG_REALM_SYSTEMD ) << 10 | ((7))), r, "../src/core/cgroup.c", 1858, __func__ , "Failed to set invocation ID on control group %s, ignoring: %m" , u->cgroup_path); }); | |||
1859 | } | |||
1860 | ||||
1861 | static bool_Bool unit_has_mask_realized( | |||
1862 | Unit *u, | |||
1863 | CGroupMask target_mask, | |||
1864 | CGroupMask enable_mask, | |||
1865 | bool_Bool needs_bpf) { | |||
1866 | ||||
1867 | assert(u)do { if ((__builtin_expect(!!(!(u)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("u"), "../src/core/cgroup.c", 1867, __PRETTY_FUNCTION__ ); } while (0); | |||
1868 | ||||
1869 | return u->cgroup_realized && | |||
1870 | u->cgroup_realized_mask == target_mask && | |||
1871 | u->cgroup_enabled_mask == enable_mask && | |||
1872 | ((needs_bpf && u->cgroup_bpf_state == UNIT_CGROUP_BPF_ON) || | |||
1873 | (!needs_bpf && u->cgroup_bpf_state == UNIT_CGROUP_BPF_OFF)); | |||
1874 | } | |||
1875 | ||||
1876 | static void unit_add_to_cgroup_realize_queue(Unit *u) { | |||
1877 | assert(u)do { if ((__builtin_expect(!!(!(u)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("u"), "../src/core/cgroup.c", 1877, __PRETTY_FUNCTION__ ); } while (0); | |||
1878 | ||||
1879 | if (u->in_cgroup_realize_queue) | |||
1880 | return; | |||
1881 | ||||
1882 | LIST_PREPEND(cgroup_realize_queue, u->manager->cgroup_realize_queue, u)do { typeof(*(u->manager->cgroup_realize_queue)) **_head = &(u->manager->cgroup_realize_queue), *_item = (u ); do { if ((__builtin_expect(!!(!(_item)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("_item"), "../src/core/cgroup.c", 1882, __PRETTY_FUNCTION__ ); } while (0); if ((_item->cgroup_realize_queue_next = *_head )) _item->cgroup_realize_queue_next->cgroup_realize_queue_prev = _item; _item->cgroup_realize_queue_prev = ((void*)0); * _head = _item; } while (0); | |||
1883 | u->in_cgroup_realize_queue = true1; | |||
1884 | } | |||
1885 | ||||
1886 | static void unit_remove_from_cgroup_realize_queue(Unit *u) { | |||
1887 | assert(u)do { if ((__builtin_expect(!!(!(u)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("u"), "../src/core/cgroup.c", 1887, __PRETTY_FUNCTION__ ); } while (0); | |||
1888 | ||||
1889 | if (!u->in_cgroup_realize_queue) | |||
1890 | return; | |||
1891 | ||||
1892 | LIST_REMOVE(cgroup_realize_queue, u->manager->cgroup_realize_queue, u)do { typeof(*(u->manager->cgroup_realize_queue)) **_head = &(u->manager->cgroup_realize_queue), *_item = (u ); do { if ((__builtin_expect(!!(!(_item)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("_item"), "../src/core/cgroup.c", 1892, __PRETTY_FUNCTION__ ); } while (0); if (_item->cgroup_realize_queue_next) _item ->cgroup_realize_queue_next->cgroup_realize_queue_prev = _item->cgroup_realize_queue_prev; if (_item->cgroup_realize_queue_prev ) _item->cgroup_realize_queue_prev->cgroup_realize_queue_next = _item->cgroup_realize_queue_next; else { do { if ((__builtin_expect (!!(!(*_head == _item)),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD , ("*_head == _item"), "../src/core/cgroup.c", 1892, __PRETTY_FUNCTION__ ); } while (0); *_head = _item->cgroup_realize_queue_next; } _item->cgroup_realize_queue_next = _item->cgroup_realize_queue_prev = ((void*)0); } while (0); | |||
1893 | u->in_cgroup_realize_queue = false0; | |||
1894 | } | |||
1895 | ||||
1896 | /* Check if necessary controllers and attributes for a unit are in place. | |||
1897 | * | |||
1898 | * If so, do nothing. | |||
1899 | * If not, create paths, move processes over, and set attributes. | |||
1900 | * | |||
1901 | * Returns 0 on success and < 0 on failure. */ | |||
1902 | static int unit_realize_cgroup_now(Unit *u, ManagerState state) { | |||
1903 | CGroupMask target_mask, enable_mask; | |||
1904 | bool_Bool needs_bpf, apply_bpf; | |||
1905 | int r; | |||
1906 | ||||
1907 | assert(u)do { if ((__builtin_expect(!!(!(u)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("u"), "../src/core/cgroup.c", 1907, __PRETTY_FUNCTION__ ); } while (0); | |||
1908 | ||||
1909 | unit_remove_from_cgroup_realize_queue(u); | |||
1910 | ||||
1911 | target_mask = unit_get_target_mask(u); | |||
1912 | enable_mask = unit_get_enable_mask(u); | |||
1913 | needs_bpf = unit_get_needs_bpf(u); | |||
1914 | ||||
1915 | if (unit_has_mask_realized(u, target_mask, enable_mask, needs_bpf)) | |||
1916 | return 0; | |||
1917 | ||||
1918 | /* Make sure we apply the BPF filters either when one is configured, or if none is configured but previously | |||
1919 | * the state was anything but off. This way, if a unit with a BPF filter applied is reconfigured to lose it | |||
1920 | * this will trickle down properly to cgroupfs. */ | |||
1921 | apply_bpf = needs_bpf
| |||
1922 | ||||
1923 | /* First, realize parents */ | |||
1924 | if (UNIT_ISSET(u->slice)(!!(u->slice).target)) { | |||
1925 | r = unit_realize_cgroup_now(UNIT_DEREF(u->slice)((u->slice).target), state); | |||
1926 | if (r
| |||
1927 | return r; | |||
1928 | } | |||
1929 | ||||
1930 | /* And then do the real work */ | |||
1931 | r = unit_create_cgroup(u, target_mask, enable_mask, needs_bpf); | |||
1932 | if (r < 0) | |||
1933 | return r; | |||
1934 | ||||
1935 | /* Finally, apply the necessary attributes. */ | |||
1936 | cgroup_context_apply(u, target_mask, apply_bpf, state); | |||
1937 | cgroup_xattr_apply(u); | |||
1938 | ||||
1939 | return 0; | |||
1940 | } | |||
1941 | ||||
1942 | unsigned manager_dispatch_cgroup_realize_queue(Manager *m) { | |||
1943 | ManagerState state; | |||
1944 | unsigned n = 0; | |||
1945 | Unit *i; | |||
1946 | int r; | |||
1947 | ||||
1948 | assert(m)do { if ((__builtin_expect(!!(!(m)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("m"), "../src/core/cgroup.c", 1948, __PRETTY_FUNCTION__ ); } while (0); | |||
| ||||
1949 | ||||
1950 | state = manager_state(m); | |||
1951 | ||||
1952 | while ((i = m->cgroup_realize_queue)) { | |||
1953 | assert(i->in_cgroup_realize_queue)do { if ((__builtin_expect(!!(!(i->in_cgroup_realize_queue )),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("i->in_cgroup_realize_queue" ), "../src/core/cgroup.c", 1953, __PRETTY_FUNCTION__); } while (0); | |||
1954 | ||||
1955 | if (UNIT_IS_INACTIVE_OR_FAILED(unit_active_state(i))) { | |||
1956 | /* Maybe things changed, and the unit is not actually active anymore? */ | |||
1957 | unit_remove_from_cgroup_realize_queue(i); | |||
1958 | continue; | |||
1959 | } | |||
1960 | ||||
1961 | r = unit_realize_cgroup_now(i, state); | |||
1962 | if (r < 0) | |||
1963 | log_warning_errno(r, "Failed to realize cgroups for queued unit %s, ignoring: %m", i->id)({ int _level = ((4)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/core/cgroup.c", 1963, __func__, "Failed to realize cgroups for queued unit %s, ignoring: %m" , i->id) : -abs(_e); }); | |||
1964 | ||||
1965 | n++; | |||
1966 | } | |||
1967 | ||||
1968 | return n; | |||
1969 | } | |||
1970 | ||||
1971 | static void unit_add_siblings_to_cgroup_realize_queue(Unit *u) { | |||
1972 | Unit *slice; | |||
1973 | ||||
1974 | /* This adds the siblings of the specified unit and the siblings of all parent units to the cgroup | |||
1975 | * queue. (But neither the specified unit itself nor the parents.) */ | |||
1976 | ||||
1977 | while ((slice = UNIT_DEREF(u->slice)((u->slice).target))) { | |||
1978 | Iterator i; | |||
1979 | Unit *m; | |||
1980 | void *v; | |||
1981 | ||||
1982 | HASHMAP_FOREACH_KEY(v, m, slice->dependencies[UNIT_BEFORE], i)for ((i) = ((Iterator) { .idx = ((2147483647 *2U +1U) - 1), . next_key = ((void*)0) }); hashmap_iterate((slice->dependencies [UNIT_BEFORE]), &(i), (void**)&(v), (const void**) & (m)); ) { | |||
1983 | /* Skip units that have a dependency on the slice but aren't actually in it. */ | |||
1984 | if (UNIT_DEREF(m->slice)((m->slice).target) != slice) | |||
1985 | continue; | |||
1986 | ||||
1987 | /* No point in doing cgroup application for units without active processes. */ | |||
1988 | if (UNIT_IS_INACTIVE_OR_FAILED(unit_active_state(m))) | |||
1989 | continue; | |||
1990 | ||||
1991 | /* If the unit doesn't need any new controllers and has current ones realized, it | |||
1992 | * doesn't need any changes. */ | |||
1993 | if (unit_has_mask_realized(m, | |||
1994 | unit_get_target_mask(m), | |||
1995 | unit_get_enable_mask(m), | |||
1996 | unit_get_needs_bpf(m))) | |||
1997 | continue; | |||
1998 | ||||
1999 | unit_add_to_cgroup_realize_queue(m); | |||
2000 | } | |||
2001 | ||||
2002 | u = slice; | |||
2003 | } | |||
2004 | } | |||
2005 | ||||
2006 | int unit_realize_cgroup(Unit *u) { | |||
2007 | assert(u)do { if ((__builtin_expect(!!(!(u)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("u"), "../src/core/cgroup.c", 2007, __PRETTY_FUNCTION__ ); } while (0); | |||
2008 | ||||
2009 | if (!UNIT_HAS_CGROUP_CONTEXT(u)(unit_vtable[(u)->type]->cgroup_context_offset > 0)) | |||
2010 | return 0; | |||
2011 | ||||
2012 | /* So, here's the deal: when realizing the cgroups for this | |||
2013 | * unit, we need to first create all parents, but there's more | |||
2014 | * actually: for the weight-based controllers we also need to | |||
2015 | * make sure that all our siblings (i.e. units that are in the | |||
2016 | * same slice as we are) have cgroups, too. Otherwise, things | |||
2017 | * would become very uneven as each of their processes would | |||
2018 | * get as much resources as all our group together. This call | |||
2019 | * will synchronously create the parent cgroups, but will | |||
2020 | * defer work on the siblings to the next event loop | |||
2021 | * iteration. */ | |||
2022 | ||||
2023 | /* Add all sibling slices to the cgroup queue. */ | |||
2024 | unit_add_siblings_to_cgroup_realize_queue(u); | |||
2025 | ||||
2026 | /* And realize this one now (and apply the values) */ | |||
2027 | return unit_realize_cgroup_now(u, manager_state(u->manager)); | |||
2028 | } | |||
2029 | ||||
2030 | void unit_release_cgroup(Unit *u) { | |||
2031 | assert(u)do { if ((__builtin_expect(!!(!(u)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("u"), "../src/core/cgroup.c", 2031, __PRETTY_FUNCTION__ ); } while (0); | |||
2032 | ||||
2033 | /* Forgets all cgroup details for this cgroup */ | |||
2034 | ||||
2035 | if (u->cgroup_path) { | |||
2036 | (void) hashmap_remove(u->manager->cgroup_unit, u->cgroup_path); | |||
2037 | u->cgroup_path = mfree(u->cgroup_path); | |||
2038 | } | |||
2039 | ||||
2040 | if (u->cgroup_inotify_wd >= 0) { | |||
2041 | if (inotify_rm_watch(u->manager->cgroup_inotify_fd, u->cgroup_inotify_wd) < 0) | |||
2042 | log_unit_debug_errno(u, errno, "Failed to remove cgroup inotify watch %i for %s, ignoring", u->cgroup_inotify_wd, u->id)({ const Unit *_u = (u); _u ? log_object_internal(7, (*__errno_location ()), "../src/core/cgroup.c", 2042, __func__, _u->manager-> unit_log_field, _u->id, _u->manager->invocation_log_field , _u->invocation_id_string, "Failed to remove cgroup inotify watch %i for %s, ignoring" , u->cgroup_inotify_wd, u->id) : log_internal_realm(((LOG_REALM_SYSTEMD ) << 10 | ((7))), (*__errno_location ()), "../src/core/cgroup.c" , 2042, __func__, "Failed to remove cgroup inotify watch %i for %s, ignoring" , u->cgroup_inotify_wd, u->id); }); | |||
2043 | ||||
2044 | (void) hashmap_remove(u->manager->cgroup_inotify_wd_unit, INT_TO_PTR(u->cgroup_inotify_wd)((void *) ((intptr_t) (u->cgroup_inotify_wd)))); | |||
2045 | u->cgroup_inotify_wd = -1; | |||
2046 | } | |||
2047 | } | |||
2048 | ||||
2049 | void unit_prune_cgroup(Unit *u) { | |||
2050 | int r; | |||
2051 | bool_Bool is_root_slice; | |||
2052 | ||||
2053 | assert(u)do { if ((__builtin_expect(!!(!(u)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("u"), "../src/core/cgroup.c", 2053, __PRETTY_FUNCTION__ ); } while (0); | |||
2054 | ||||
2055 | /* Removes the cgroup, if empty and possible, and stops watching it. */ | |||
2056 | ||||
2057 | if (!u->cgroup_path) | |||
2058 | return; | |||
2059 | ||||
2060 | (void) unit_get_cpu_usage(u, NULL((void*)0)); /* Cache the last CPU usage value before we destroy the cgroup */ | |||
2061 | ||||
2062 | is_root_slice = unit_has_name(u, SPECIAL_ROOT_SLICE"-.slice"); | |||
2063 | ||||
2064 | r = cg_trim_everywhere(u->manager->cgroup_supported, u->cgroup_path, !is_root_slice); | |||
2065 | if (r < 0) { | |||
2066 | log_unit_debug_errno(u, r, "Failed to destroy cgroup %s, ignoring: %m", u->cgroup_path)({ const Unit *_u = (u); _u ? log_object_internal(7, r, "../src/core/cgroup.c" , 2066, __func__, _u->manager->unit_log_field, _u->id , _u->manager->invocation_log_field, _u->invocation_id_string , "Failed to destroy cgroup %s, ignoring: %m", u->cgroup_path ) : log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((7 ))), r, "../src/core/cgroup.c", 2066, __func__, "Failed to destroy cgroup %s, ignoring: %m" , u->cgroup_path); }); | |||
2067 | return; | |||
2068 | } | |||
2069 | ||||
2070 | if (is_root_slice) | |||
2071 | return; | |||
2072 | ||||
2073 | unit_release_cgroup(u); | |||
2074 | ||||
2075 | u->cgroup_realized = false0; | |||
2076 | u->cgroup_realized_mask = 0; | |||
2077 | u->cgroup_enabled_mask = 0; | |||
2078 | } | |||
2079 | ||||
2080 | int unit_search_main_pid(Unit *u, pid_t *ret) { | |||
2081 | _cleanup_fclose___attribute__((cleanup(fclosep))) FILE *f = NULL((void*)0); | |||
2082 | pid_t pid = 0, npid; | |||
2083 | int r; | |||
2084 | ||||
2085 | assert(u)do { if ((__builtin_expect(!!(!(u)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("u"), "../src/core/cgroup.c", 2085, __PRETTY_FUNCTION__ ); } while (0); | |||
2086 | assert(ret)do { if ((__builtin_expect(!!(!(ret)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("ret"), "../src/core/cgroup.c", 2086, __PRETTY_FUNCTION__ ); } while (0); | |||
2087 | ||||
2088 | if (!u->cgroup_path) | |||
2089 | return -ENXIO6; | |||
2090 | ||||
2091 | r = cg_enumerate_processes(SYSTEMD_CGROUP_CONTROLLER"_systemd", u->cgroup_path, &f); | |||
2092 | if (r < 0) | |||
2093 | return r; | |||
2094 | ||||
2095 | while (cg_read_pid(f, &npid) > 0) { | |||
2096 | ||||
2097 | if (npid == pid) | |||
2098 | continue; | |||
2099 | ||||
2100 | if (pid_is_my_child(npid) == 0) | |||
2101 | continue; | |||
2102 | ||||
2103 | if (pid != 0) | |||
2104 | /* Dang, there's more than one daemonized PID | |||
2105 | in this group, so we don't know what process | |||
2106 | is the main process. */ | |||
2107 | ||||
2108 | return -ENODATA61; | |||
2109 | ||||
2110 | pid = npid; | |||
2111 | } | |||
2112 | ||||
2113 | *ret = pid; | |||
2114 | return 0; | |||
2115 | } | |||
2116 | ||||
2117 | static int unit_watch_pids_in_path(Unit *u, const char *path) { | |||
2118 | _cleanup_closedir___attribute__((cleanup(closedirp))) DIR *d = NULL((void*)0); | |||
2119 | _cleanup_fclose___attribute__((cleanup(fclosep))) FILE *f = NULL((void*)0); | |||
2120 | int ret = 0, r; | |||
2121 | ||||
2122 | assert(u)do { if ((__builtin_expect(!!(!(u)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("u"), "../src/core/cgroup.c", 2122, __PRETTY_FUNCTION__ ); } while (0); | |||
2123 | assert(path)do { if ((__builtin_expect(!!(!(path)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("path"), "../src/core/cgroup.c", 2123, __PRETTY_FUNCTION__ ); } while (0); | |||
2124 | ||||
2125 | r = cg_enumerate_processes(SYSTEMD_CGROUP_CONTROLLER"_systemd", path, &f); | |||
2126 | if (r < 0) | |||
2127 | ret = r; | |||
2128 | else { | |||
2129 | pid_t pid; | |||
2130 | ||||
2131 | while ((r = cg_read_pid(f, &pid)) > 0) { | |||
2132 | r = unit_watch_pid(u, pid, false0); | |||
2133 | if (r < 0 && ret >= 0) | |||
2134 | ret = r; | |||
2135 | } | |||
2136 | ||||
2137 | if (r < 0 && ret >= 0) | |||
2138 | ret = r; | |||
2139 | } | |||
2140 | ||||
2141 | r = cg_enumerate_subgroups(SYSTEMD_CGROUP_CONTROLLER"_systemd", path, &d); | |||
2142 | if (r < 0) { | |||
2143 | if (ret >= 0) | |||
2144 | ret = r; | |||
2145 | } else { | |||
2146 | char *fn; | |||
2147 | ||||
2148 | while ((r = cg_read_subgroup(d, &fn)) > 0) { | |||
2149 | _cleanup_free___attribute__((cleanup(freep))) char *p = NULL((void*)0); | |||
2150 | ||||
2151 | p = strjoin(path, "/", fn)strjoin_real((path), "/", fn, ((void*)0)); | |||
2152 | free(fn); | |||
2153 | ||||
2154 | if (!p) | |||
2155 | return -ENOMEM12; | |||
2156 | ||||
2157 | r = unit_watch_pids_in_path(u, p); | |||
2158 | if (r < 0 && ret >= 0) | |||
2159 | ret = r; | |||
2160 | } | |||
2161 | ||||
2162 | if (r < 0 && ret >= 0) | |||
2163 | ret = r; | |||
2164 | } | |||
2165 | ||||
2166 | return ret; | |||
2167 | } | |||
2168 | ||||
2169 | int unit_synthesize_cgroup_empty_event(Unit *u) { | |||
2170 | int r; | |||
2171 | ||||
2172 | assert(u)do { if ((__builtin_expect(!!(!(u)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("u"), "../src/core/cgroup.c", 2172, __PRETTY_FUNCTION__ ); } while (0); | |||
2173 | ||||
2174 | /* Enqueue a synthetic cgroup empty event if this unit doesn't watch any PIDs anymore. This is compatibility | |||
2175 | * support for non-unified systems where notifications aren't reliable, and hence need to take whatever we can | |||
2176 | * get as notification source as soon as we stopped having any useful PIDs to watch for. */ | |||
2177 | ||||
2178 | if (!u->cgroup_path) | |||
2179 | return -ENOENT2; | |||
2180 | ||||
2181 | r = cg_unified_controller(SYSTEMD_CGROUP_CONTROLLER"_systemd"); | |||
2182 | if (r < 0) | |||
2183 | return r; | |||
2184 | if (r > 0) /* On unified we have reliable notifications, and don't need this */ | |||
2185 | return 0; | |||
2186 | ||||
2187 | if (!set_isempty(u->pids)) | |||
2188 | return 0; | |||
2189 | ||||
2190 | unit_add_to_cgroup_empty_queue(u); | |||
2191 | return 0; | |||
2192 | } | |||
2193 | ||||
2194 | int unit_watch_all_pids(Unit *u) { | |||
2195 | int r; | |||
2196 | ||||
2197 | assert(u)do { if ((__builtin_expect(!!(!(u)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("u"), "../src/core/cgroup.c", 2197, __PRETTY_FUNCTION__ ); } while (0); | |||
2198 | ||||
2199 | /* Adds all PIDs from our cgroup to the set of PIDs we | |||
2200 | * watch. This is a fallback logic for cases where we do not | |||
2201 | * get reliable cgroup empty notifications: we try to use | |||
2202 | * SIGCHLD as replacement. */ | |||
2203 | ||||
2204 | if (!u->cgroup_path) | |||
2205 | return -ENOENT2; | |||
2206 | ||||
2207 | r = cg_unified_controller(SYSTEMD_CGROUP_CONTROLLER"_systemd"); | |||
2208 | if (r < 0) | |||
2209 | return r; | |||
2210 | if (r > 0) /* On unified we can use proper notifications */ | |||
2211 | return 0; | |||
2212 | ||||
2213 | return unit_watch_pids_in_path(u, u->cgroup_path); | |||
2214 | } | |||
2215 | ||||
2216 | static int on_cgroup_empty_event(sd_event_source *s, void *userdata) { | |||
2217 | Manager *m = userdata; | |||
2218 | Unit *u; | |||
2219 | int r; | |||
2220 | ||||
2221 | assert(s)do { if ((__builtin_expect(!!(!(s)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("s"), "../src/core/cgroup.c", 2221, __PRETTY_FUNCTION__ ); } while (0); | |||
2222 | assert(m)do { if ((__builtin_expect(!!(!(m)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("m"), "../src/core/cgroup.c", 2222, __PRETTY_FUNCTION__ ); } while (0); | |||
2223 | ||||
2224 | u = m->cgroup_empty_queue; | |||
2225 | if (!u) | |||
2226 | return 0; | |||
2227 | ||||
2228 | assert(u->in_cgroup_empty_queue)do { if ((__builtin_expect(!!(!(u->in_cgroup_empty_queue)) ,0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("u->in_cgroup_empty_queue" ), "../src/core/cgroup.c", 2228, __PRETTY_FUNCTION__); } while (0); | |||
2229 | u->in_cgroup_empty_queue = false0; | |||
2230 | LIST_REMOVE(cgroup_empty_queue, m->cgroup_empty_queue, u)do { typeof(*(m->cgroup_empty_queue)) **_head = &(m-> cgroup_empty_queue), *_item = (u); do { if ((__builtin_expect (!!(!(_item)),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("_item"), "../src/core/cgroup.c", 2230, __PRETTY_FUNCTION__ ); } while (0); if (_item->cgroup_empty_queue_next) _item-> cgroup_empty_queue_next->cgroup_empty_queue_prev = _item-> cgroup_empty_queue_prev; if (_item->cgroup_empty_queue_prev ) _item->cgroup_empty_queue_prev->cgroup_empty_queue_next = _item->cgroup_empty_queue_next; else { do { if ((__builtin_expect (!!(!(*_head == _item)),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD , ("*_head == _item"), "../src/core/cgroup.c", 2230, __PRETTY_FUNCTION__ ); } while (0); *_head = _item->cgroup_empty_queue_next; } _item->cgroup_empty_queue_next = _item->cgroup_empty_queue_prev = ((void*)0); } while (0); | |||
2231 | ||||
2232 | if (m->cgroup_empty_queue) { | |||
2233 | /* More stuff queued, let's make sure we remain enabled */ | |||
2234 | r = sd_event_source_set_enabled(s, SD_EVENT_ONESHOT); | |||
2235 | if (r < 0) | |||
2236 | log_debug_errno(r, "Failed to reenable cgroup empty event source, ignoring: %m")({ int _level = ((7)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/core/cgroup.c", 2236, __func__, "Failed to reenable cgroup empty event source, ignoring: %m" ) : -abs(_e); }); | |||
2237 | } | |||
2238 | ||||
2239 | unit_add_to_gc_queue(u); | |||
2240 | ||||
2241 | if (UNIT_VTABLE(u)unit_vtable[(u)->type]->notify_cgroup_empty) | |||
2242 | UNIT_VTABLE(u)unit_vtable[(u)->type]->notify_cgroup_empty(u); | |||
2243 | ||||
2244 | return 0; | |||
2245 | } | |||
2246 | ||||
2247 | void unit_add_to_cgroup_empty_queue(Unit *u) { | |||
2248 | int r; | |||
2249 | ||||
2250 | assert(u)do { if ((__builtin_expect(!!(!(u)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("u"), "../src/core/cgroup.c", 2250, __PRETTY_FUNCTION__ ); } while (0); | |||
2251 | ||||
2252 | /* Note that there are four different ways how cgroup empty events reach us: | |||
2253 | * | |||
2254 | * 1. On the unified hierarchy we get an inotify event on the cgroup | |||
2255 | * | |||
2256 | * 2. On the legacy hierarchy, when running in system mode, we get a datagram on the cgroup agent socket | |||
2257 | * | |||
2258 | * 3. On the legacy hierarchy, when running in user mode, we get a D-Bus signal on the system bus | |||
2259 | * | |||
2260 | * 4. On the legacy hierarchy, in service units we start watching all processes of the cgroup for SIGCHLD as | |||
2261 | * soon as we get one SIGCHLD, to deal with unreliable cgroup notifications. | |||
2262 | * | |||
2263 | * Regardless which way we got the notification, we'll verify it here, and then add it to a separate | |||
2264 | * queue. This queue will be dispatched at a lower priority than the SIGCHLD handler, so that we always use | |||
2265 | * SIGCHLD if we can get it first, and only use the cgroup empty notifications if there's no SIGCHLD pending | |||
2266 | * (which might happen if the cgroup doesn't contain processes that are our own child, which is typically the | |||
2267 | * case for scope units). */ | |||
2268 | ||||
2269 | if (u->in_cgroup_empty_queue) | |||
2270 | return; | |||
2271 | ||||
2272 | /* Let's verify that the cgroup is really empty */ | |||
2273 | if (!u->cgroup_path) | |||
2274 | return; | |||
2275 | r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER"_systemd", u->cgroup_path); | |||
2276 | if (r < 0) { | |||
2277 | log_unit_debug_errno(u, r, "Failed to determine whether cgroup %s is empty: %m", u->cgroup_path)({ const Unit *_u = (u); _u ? log_object_internal(7, r, "../src/core/cgroup.c" , 2277, __func__, _u->manager->unit_log_field, _u->id , _u->manager->invocation_log_field, _u->invocation_id_string , "Failed to determine whether cgroup %s is empty: %m", u-> cgroup_path) : log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((7))), r, "../src/core/cgroup.c", 2277, __func__, "Failed to determine whether cgroup %s is empty: %m" , u->cgroup_path); }); | |||
2278 | return; | |||
2279 | } | |||
2280 | if (r == 0) | |||
2281 | return; | |||
2282 | ||||
2283 | LIST_PREPEND(cgroup_empty_queue, u->manager->cgroup_empty_queue, u)do { typeof(*(u->manager->cgroup_empty_queue)) **_head = &(u->manager->cgroup_empty_queue), *_item = (u); do { if ((__builtin_expect(!!(!(_item)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("_item"), "../src/core/cgroup.c", 2283, __PRETTY_FUNCTION__ ); } while (0); if ((_item->cgroup_empty_queue_next = *_head )) _item->cgroup_empty_queue_next->cgroup_empty_queue_prev = _item; _item->cgroup_empty_queue_prev = ((void*)0); *_head = _item; } while (0); | |||
2284 | u->in_cgroup_empty_queue = true1; | |||
2285 | ||||
2286 | /* Trigger the defer event */ | |||
2287 | r = sd_event_source_set_enabled(u->manager->cgroup_empty_event_source, SD_EVENT_ONESHOT); | |||
2288 | if (r < 0) | |||
2289 | log_debug_errno(r, "Failed to enable cgroup empty event source: %m")({ int _level = ((7)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/core/cgroup.c", 2289, __func__, "Failed to enable cgroup empty event source: %m" ) : -abs(_e); }); | |||
2290 | } | |||
2291 | ||||
2292 | static void unit_remove_from_cgroup_empty_queue(Unit *u) { | |||
2293 | assert(u)do { if ((__builtin_expect(!!(!(u)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("u"), "../src/core/cgroup.c", 2293, __PRETTY_FUNCTION__ ); } while (0); | |||
2294 | ||||
2295 | if (!u->in_cgroup_empty_queue) | |||
2296 | return; | |||
2297 | ||||
2298 | LIST_REMOVE(cgroup_empty_queue, u->manager->cgroup_empty_queue, u)do { typeof(*(u->manager->cgroup_empty_queue)) **_head = &(u->manager->cgroup_empty_queue), *_item = (u); do { if ((__builtin_expect(!!(!(_item)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("_item"), "../src/core/cgroup.c", 2298, __PRETTY_FUNCTION__ ); } while (0); if (_item->cgroup_empty_queue_next) _item-> cgroup_empty_queue_next->cgroup_empty_queue_prev = _item-> cgroup_empty_queue_prev; if (_item->cgroup_empty_queue_prev ) _item->cgroup_empty_queue_prev->cgroup_empty_queue_next = _item->cgroup_empty_queue_next; else { do { if ((__builtin_expect (!!(!(*_head == _item)),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD , ("*_head == _item"), "../src/core/cgroup.c", 2298, __PRETTY_FUNCTION__ ); } while (0); *_head = _item->cgroup_empty_queue_next; } _item->cgroup_empty_queue_next = _item->cgroup_empty_queue_prev = ((void*)0); } while (0); | |||
2299 | u->in_cgroup_empty_queue = false0; | |||
2300 | } | |||
2301 | ||||
2302 | static int unit_check_cgroup_events(Unit *u) { | |||
2303 | char *values[2] = {}; | |||
2304 | int r; | |||
2305 | ||||
2306 | assert(u)do { if ((__builtin_expect(!!(!(u)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("u"), "../src/core/cgroup.c", 2306, __PRETTY_FUNCTION__ ); } while (0); | |||
2307 | ||||
2308 | r = cg_get_keyed_attribute_graceful(SYSTEMD_CGROUP_CONTROLLER"_systemd", u->cgroup_path, "cgroup.events", | |||
2309 | STRV_MAKE("populated", "frozen")((char**) ((const char*[]) { "populated", "frozen", ((void*)0 ) })), values); | |||
2310 | if (r < 0) | |||
2311 | return r; | |||
2312 | ||||
2313 | /* The cgroup.events notifications can be merged together so act as we saw the given state for the | |||
2314 | * first time. The functions we call to handle given state are idempotent, which makes them | |||
2315 | * effectively remember the previous state. */ | |||
2316 | if (values[0]) { | |||
2317 | if (streq(values[0], "1")(strcmp((values[0]),("1")) == 0)) | |||
2318 | unit_remove_from_cgroup_empty_queue(u); | |||
2319 | else | |||
2320 | unit_add_to_cgroup_empty_queue(u); | |||
2321 | } | |||
2322 | ||||
2323 | /* Disregard freezer state changes due to operations not initiated by us */ | |||
2324 | if (values[1] && IN_SET(u->freezer_state, FREEZER_FREEZING, FREEZER_THAWING)({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){FREEZER_FREEZING, FREEZER_THAWING})/sizeof (int)]; switch(u->freezer_state) { case FREEZER_FREEZING: case FREEZER_THAWING: _found = 1; break; default: break; } _found ; })) { | |||
2325 | if (streq(values[1], "0")(strcmp((values[1]),("0")) == 0)) | |||
2326 | unit_thawed(u); | |||
2327 | else | |||
2328 | unit_frozen(u); | |||
2329 | } | |||
2330 | ||||
2331 | free(values[0]); | |||
2332 | free(values[1]); | |||
2333 | ||||
2334 | return 0; | |||
2335 | } | |||
2336 | ||||
2337 | static int on_cgroup_inotify_event(sd_event_source *s, int fd, uint32_t revents, void *userdata) { | |||
2338 | Manager *m = userdata; | |||
2339 | ||||
2340 | assert(s)do { if ((__builtin_expect(!!(!(s)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("s"), "../src/core/cgroup.c", 2340, __PRETTY_FUNCTION__ ); } while (0); | |||
2341 | assert(fd >= 0)do { if ((__builtin_expect(!!(!(fd >= 0)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("fd >= 0"), "../src/core/cgroup.c", 2341 , __PRETTY_FUNCTION__); } while (0); | |||
2342 | assert(m)do { if ((__builtin_expect(!!(!(m)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("m"), "../src/core/cgroup.c", 2342, __PRETTY_FUNCTION__ ); } while (0); | |||
2343 | ||||
2344 | for (;;) { | |||
2345 | union inotify_event_buffer buffer; | |||
2346 | struct inotify_event *e; | |||
2347 | ssize_t l; | |||
2348 | ||||
2349 | l = read(fd, &buffer, sizeof(buffer)); | |||
2350 | if (l < 0) { | |||
2351 | if (IN_SET(errno, EINTR, EAGAIN)({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){4, 11})/sizeof(int)]; switch((*__errno_location ())) { case 4: case 11: _found = 1; break; default: break; } _found; })) | |||
2352 | return 0; | |||
2353 | ||||
2354 | return log_error_errno(errno, "Failed to read control group inotify events: %m")({ int _level = ((3)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/core/cgroup.c", 2354, __func__, "Failed to read control group inotify events: %m" ) : -abs(_e); }); | |||
2355 | } | |||
2356 | ||||
2357 | FOREACH_INOTIFY_EVENT(e, buffer, l)for ((e) = &buffer.ev; (uint8_t*) (e) < (uint8_t*) (buffer .raw) + (l); (e) = (struct inotify_event*) ((uint8_t*) (e) + sizeof (struct inotify_event) + (e)->len)) { | |||
2358 | Unit *u; | |||
2359 | ||||
2360 | if (e->wd < 0) | |||
2361 | /* Queue overflow has no watch descriptor */ | |||
2362 | continue; | |||
2363 | ||||
2364 | if (e->mask & IN_IGNORED0x00008000) | |||
2365 | /* The watch was just removed */ | |||
2366 | continue; | |||
2367 | ||||
2368 | /* Note that inotify might deliver events for a watch even after it was removed, | |||
2369 | * because it was queued before the removal. Let's ignore this here safely. */ | |||
2370 | ||||
2371 | u = hashmap_get(m->cgroup_inotify_wd_unit, INT_TO_PTR(e->wd)((void *) ((intptr_t) (e->wd)))); | |||
2372 | if (u) | |||
2373 | unit_check_cgroup_events(u); | |||
2374 | } | |||
2375 | } | |||
2376 | } | |||
2377 | ||||
2378 | int manager_setup_cgroup(Manager *m) { | |||
2379 | _cleanup_free___attribute__((cleanup(freep))) char *path = NULL((void*)0); | |||
2380 | const char *scope_path; | |||
2381 | CGroupController c; | |||
2382 | int r, all_unified; | |||
2383 | char *e; | |||
2384 | ||||
2385 | assert(m)do { if ((__builtin_expect(!!(!(m)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("m"), "../src/core/cgroup.c", 2385, __PRETTY_FUNCTION__ ); } while (0); | |||
2386 | ||||
2387 | /* 1. Determine hierarchy */ | |||
2388 | m->cgroup_root = mfree(m->cgroup_root); | |||
2389 | r = cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER"_systemd", 0, &m->cgroup_root); | |||
2390 | if (r < 0) | |||
2391 | return log_error_errno(r, "Cannot determine cgroup we are running in: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/core/cgroup.c", 2391, __func__, "Cannot determine cgroup we are running in: %m" ) : -abs(_e); }); | |||
2392 | ||||
2393 | /* Chop off the init scope, if we are already located in it */ | |||
2394 | e = endswith(m->cgroup_root, "/" SPECIAL_INIT_SCOPE"init.scope"); | |||
2395 | ||||
2396 | /* LEGACY: Also chop off the system slice if we are in | |||
2397 | * it. This is to support live upgrades from older systemd | |||
2398 | * versions where PID 1 was moved there. Also see | |||
2399 | * cg_get_root_path(). */ | |||
2400 | if (!e && MANAGER_IS_SYSTEM(m)((m)->unit_file_scope == UNIT_FILE_SYSTEM)) { | |||
2401 | e = endswith(m->cgroup_root, "/" SPECIAL_SYSTEM_SLICE"system.slice"); | |||
2402 | if (!e) | |||
2403 | e = endswith(m->cgroup_root, "/system"); /* even more legacy */ | |||
2404 | } | |||
2405 | if (e) | |||
2406 | *e = 0; | |||
2407 | ||||
2408 | /* And make sure to store away the root value without trailing slash, even for the root dir, so that we can | |||
2409 | * easily prepend it everywhere. */ | |||
2410 | delete_trailing_chars(m->cgroup_root, "/"); | |||
2411 | ||||
2412 | /* 2. Show data */ | |||
2413 | r = cg_get_path(SYSTEMD_CGROUP_CONTROLLER"_systemd", m->cgroup_root, NULL((void*)0), &path); | |||
2414 | if (r < 0) | |||
2415 | return log_error_errno(r, "Cannot find cgroup mount point: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/core/cgroup.c", 2415, __func__, "Cannot find cgroup mount point: %m" ) : -abs(_e); }); | |||
2416 | ||||
2417 | r = cg_unified_flush(); | |||
2418 | if (r < 0) | |||
2419 | return log_error_errno(r, "Couldn't determine if we are running in the unified hierarchy: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/core/cgroup.c", 2419, __func__, "Couldn't determine if we are running in the unified hierarchy: %m" ) : -abs(_e); }); | |||
2420 | ||||
2421 | all_unified = cg_all_unified(); | |||
2422 | if (all_unified < 0) | |||
2423 | return log_error_errno(all_unified, "Couldn't determine whether we are in all unified mode: %m")({ int _level = ((3)), _e = ((all_unified)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/core/cgroup.c", 2423, __func__, "Couldn't determine whether we are in all unified mode: %m" ) : -abs(_e); }); | |||
2424 | if (all_unified > 0) | |||
2425 | log_debug("Unified cgroup hierarchy is located at %s.", path)({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/core/cgroup.c", 2425, __func__, "Unified cgroup hierarchy is located at %s." , path) : -abs(_e); }); | |||
2426 | else { | |||
2427 | r = cg_unified_controller(SYSTEMD_CGROUP_CONTROLLER"_systemd"); | |||
2428 | if (r < 0) | |||
2429 | return log_error_errno(r, "Failed to determine whether systemd's own controller is in unified mode: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/core/cgroup.c", 2429, __func__, "Failed to determine whether systemd's own controller is in unified mode: %m" ) : -abs(_e); }); | |||
2430 | if (r > 0) | |||
2431 | log_debug("Unified cgroup hierarchy is located at %s. Controllers are on legacy hierarchies.", path)({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/core/cgroup.c", 2431, __func__, "Unified cgroup hierarchy is located at %s. Controllers are on legacy hierarchies." , path) : -abs(_e); }); | |||
2432 | else | |||
2433 | log_debug("Using cgroup controller " SYSTEMD_CGROUP_CONTROLLER_LEGACY ". File system hierarchy is at %s.", path)({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/core/cgroup.c", 2433, __func__, "Using cgroup controller " "name=systemd" ". File system hierarchy is at %s.", path) : - abs(_e); }); | |||
2434 | } | |||
2435 | ||||
2436 | /* 3. Allocate cgroup empty defer event source */ | |||
2437 | m->cgroup_empty_event_source = sd_event_source_unref(m->cgroup_empty_event_source); | |||
2438 | r = sd_event_add_defer(m->event, &m->cgroup_empty_event_source, on_cgroup_empty_event, m); | |||
2439 | if (r < 0) | |||
2440 | return log_error_errno(r, "Failed to create cgroup empty event source: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/core/cgroup.c", 2440, __func__, "Failed to create cgroup empty event source: %m" ) : -abs(_e); }); | |||
2441 | ||||
2442 | r = sd_event_source_set_priority(m->cgroup_empty_event_source, SD_EVENT_PRIORITY_NORMAL-5); | |||
2443 | if (r < 0) | |||
2444 | return log_error_errno(r, "Failed to set priority of cgroup empty event source: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/core/cgroup.c", 2444, __func__, "Failed to set priority of cgroup empty event source: %m" ) : -abs(_e); }); | |||
2445 | ||||
2446 | r = sd_event_source_set_enabled(m->cgroup_empty_event_source, SD_EVENT_OFF); | |||
2447 | if (r < 0) | |||
2448 | return log_error_errno(r, "Failed to disable cgroup empty event source: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/core/cgroup.c", 2448, __func__, "Failed to disable cgroup empty event source: %m" ) : -abs(_e); }); | |||
2449 | ||||
2450 | (void) sd_event_source_set_description(m->cgroup_empty_event_source, "cgroup-empty"); | |||
2451 | ||||
2452 | /* 4. Install notifier inotify object, or agent */ | |||
2453 | if (cg_unified_controller(SYSTEMD_CGROUP_CONTROLLER"_systemd") > 0) { | |||
2454 | ||||
2455 | /* In the unified hierarchy we can get cgroup empty notifications via inotify. */ | |||
2456 | ||||
2457 | m->cgroup_inotify_event_source = sd_event_source_unref(m->cgroup_inotify_event_source); | |||
2458 | safe_close(m->cgroup_inotify_fd); | |||
2459 | ||||
2460 | m->cgroup_inotify_fd = inotify_init1(IN_NONBLOCKIN_NONBLOCK|IN_CLOEXECIN_CLOEXEC); | |||
2461 | if (m->cgroup_inotify_fd < 0) | |||
2462 | return log_error_errno(errno, "Failed to create control group inotify object: %m")({ int _level = ((3)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/core/cgroup.c", 2462, __func__, "Failed to create control group inotify object: %m" ) : -abs(_e); }); | |||
2463 | ||||
2464 | r = sd_event_add_io(m->event, &m->cgroup_inotify_event_source, m->cgroup_inotify_fd, EPOLLINEPOLLIN, on_cgroup_inotify_event, m); | |||
2465 | if (r < 0) | |||
2466 | return log_error_errno(r, "Failed to watch control group inotify object: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/core/cgroup.c", 2466, __func__, "Failed to watch control group inotify object: %m" ) : -abs(_e); }); | |||
2467 | ||||
2468 | /* Process cgroup empty notifications early, but after service notifications and SIGCHLD. Also | |||
2469 | * see handling of cgroup agent notifications, for the classic cgroup hierarchy support. */ | |||
2470 | r = sd_event_source_set_priority(m->cgroup_inotify_event_source, SD_EVENT_PRIORITY_NORMAL-4); | |||
2471 | if (r < 0) | |||
2472 | return log_error_errno(r, "Failed to set priority of inotify event source: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/core/cgroup.c", 2472, __func__, "Failed to set priority of inotify event source: %m" ) : -abs(_e); }); | |||
2473 | ||||
2474 | (void) sd_event_source_set_description(m->cgroup_inotify_event_source, "cgroup-inotify"); | |||
2475 | ||||
2476 | } else if (MANAGER_IS_SYSTEM(m)((m)->unit_file_scope == UNIT_FILE_SYSTEM) && m->test_run_flags == 0) { | |||
2477 | ||||
2478 | /* On the legacy hierarchy we only get notifications via cgroup agents. (Which isn't really reliable, | |||
2479 | * since it does not generate events when control groups with children run empty. */ | |||
2480 | ||||
2481 | r = cg_install_release_agent(SYSTEMD_CGROUP_CONTROLLER"_systemd", SYSTEMD_CGROUP_AGENT_PATH"/usr/lib/systemd/systemd-cgroups-agent"); | |||
2482 | if (r < 0) | |||
2483 | log_warning_errno(r, "Failed to install release agent, ignoring: %m")({ int _level = ((4)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/core/cgroup.c", 2483, __func__, "Failed to install release agent, ignoring: %m" ) : -abs(_e); }); | |||
2484 | else if (r > 0) | |||
2485 | log_debug("Installed release agent.")({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/core/cgroup.c", 2485, __func__, "Installed release agent." ) : -abs(_e); }); | |||
2486 | else if (r == 0) | |||
2487 | log_debug("Release agent already installed.")({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/core/cgroup.c", 2487, __func__, "Release agent already installed." ) : -abs(_e); }); | |||
2488 | } | |||
2489 | ||||
2490 | /* 5. Make sure we are in the special "init.scope" unit in the root slice. */ | |||
2491 | scope_path = strjoina(m->cgroup_root, "/" SPECIAL_INIT_SCOPE)({ const char *_appendees_[] = { m->cgroup_root, "/" "init.scope" }; char *_d_, *_p_; size_t _len_ = 0; size_t _i_; for (_i_ = 0; _i_ < __extension__ (__builtin_choose_expr( !__builtin_types_compatible_p (typeof(_appendees_), typeof(&*(_appendees_))), sizeof(_appendees_ )/sizeof((_appendees_)[0]), ((void)0))) && _appendees_ [_i_]; _i_++) _len_ += strlen(_appendees_[_i_]); _p_ = _d_ = __builtin_alloca (_len_ + 1); for (_i_ = 0; _i_ < __extension__ (__builtin_choose_expr ( !__builtin_types_compatible_p(typeof(_appendees_), typeof(& *(_appendees_))), sizeof(_appendees_)/sizeof((_appendees_)[0] ), ((void)0))) && _appendees_[_i_]; _i_++) _p_ = stpcpy (_p_, _appendees_[_i_]); *_p_ = 0; _d_; }); | |||
2492 | r = cg_create_and_attach(SYSTEMD_CGROUP_CONTROLLER"_systemd", scope_path, 0); | |||
2493 | if (r >= 0) { | |||
2494 | /* Also, move all other userspace processes remaining in the root cgroup into that scope. */ | |||
2495 | r = cg_migrate(SYSTEMD_CGROUP_CONTROLLER"_systemd", m->cgroup_root, SYSTEMD_CGROUP_CONTROLLER"_systemd", scope_path, 0); | |||
2496 | if (r < 0) | |||
2497 | log_warning_errno(r, "Couldn't move remaining userspace processes, ignoring: %m")({ int _level = ((4)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/core/cgroup.c", 2497, __func__, "Couldn't move remaining userspace processes, ignoring: %m" ) : -abs(_e); }); | |||
2498 | ||||
2499 | /* 6. And pin it, so that it cannot be unmounted */ | |||
2500 | safe_close(m->pin_cgroupfs_fd); | |||
2501 | m->pin_cgroupfs_fd = open(path, O_RDONLY00|O_CLOEXEC02000000|O_DIRECTORY0200000|O_NOCTTY0400|O_NONBLOCK04000); | |||
2502 | if (m->pin_cgroupfs_fd < 0) | |||
2503 | return log_error_errno(errno, "Failed to open pin file: %m")({ int _level = ((3)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/core/cgroup.c", 2503, __func__, "Failed to open pin file: %m" ) : -abs(_e); }); | |||
2504 | ||||
2505 | } else if (r < 0 && !m->test_run_flags) | |||
2506 | return log_error_errno(r, "Failed to create %s control group: %m", scope_path)({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/core/cgroup.c", 2506, __func__, "Failed to create %s control group: %m" , scope_path) : -abs(_e); }); | |||
2507 | ||||
2508 | /* 7. Always enable hierarchical support if it exists... */ | |||
2509 | if (!all_unified && m->test_run_flags == 0) | |||
2510 | (void) cg_set_attribute("memory", "/", "memory.use_hierarchy", "1"); | |||
2511 | ||||
2512 | /* 8. Figure out which controllers are supported, and log about it */ | |||
2513 | r = cg_mask_supported(&m->cgroup_supported); | |||
2514 | if (r < 0) | |||
2515 | return log_error_errno(r, "Failed to determine supported controllers: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/core/cgroup.c", 2515, __func__, "Failed to determine supported controllers: %m" ) : -abs(_e); }); | |||
2516 | for (c = 0; c < _CGROUP_CONTROLLER_MAX; c++) | |||
2517 | log_debug("Controller '%s' supported: %s", cgroup_controller_to_string(c), yes_no(m->cgroup_supported & CGROUP_CONTROLLER_TO_MASK(c)))({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/core/cgroup.c", 2517, __func__, "Controller '%s' supported: %s" , cgroup_controller_to_string(c), yes_no(m->cgroup_supported & (1 << (c)))) : -abs(_e); }); | |||
2518 | ||||
2519 | return 0; | |||
2520 | } | |||
2521 | ||||
2522 | void manager_shutdown_cgroup(Manager *m, bool_Bool delete) { | |||
2523 | assert(m)do { if ((__builtin_expect(!!(!(m)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("m"), "../src/core/cgroup.c", 2523, __PRETTY_FUNCTION__ ); } while (0); | |||
2524 | ||||
2525 | /* We can't really delete the group, since we are in it. But | |||
2526 | * let's trim it. */ | |||
2527 | if (delete && m->cgroup_root && m->test_run_flags != MANAGER_TEST_RUN_MINIMAL) | |||
2528 | (void) cg_trim(SYSTEMD_CGROUP_CONTROLLER"_systemd", m->cgroup_root, false0); | |||
2529 | ||||
2530 | m->cgroup_empty_event_source = sd_event_source_unref(m->cgroup_empty_event_source); | |||
2531 | ||||
2532 | m->cgroup_inotify_wd_unit = hashmap_free(m->cgroup_inotify_wd_unit); | |||
2533 | ||||
2534 | m->cgroup_inotify_event_source = sd_event_source_unref(m->cgroup_inotify_event_source); | |||
2535 | m->cgroup_inotify_fd = safe_close(m->cgroup_inotify_fd); | |||
2536 | ||||
2537 | m->pin_cgroupfs_fd = safe_close(m->pin_cgroupfs_fd); | |||
2538 | ||||
2539 | m->cgroup_root = mfree(m->cgroup_root); | |||
2540 | } | |||
2541 | ||||
2542 | Unit* manager_get_unit_by_cgroup(Manager *m, const char *cgroup) { | |||
2543 | char *p; | |||
2544 | Unit *u; | |||
2545 | ||||
2546 | assert(m)do { if ((__builtin_expect(!!(!(m)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("m"), "../src/core/cgroup.c", 2546, __PRETTY_FUNCTION__ ); } while (0); | |||
2547 | assert(cgroup)do { if ((__builtin_expect(!!(!(cgroup)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("cgroup"), "../src/core/cgroup.c", 2547, __PRETTY_FUNCTION__); } while (0); | |||
2548 | ||||
2549 | u = hashmap_get(m->cgroup_unit, cgroup); | |||
2550 | if (u) | |||
2551 | return u; | |||
2552 | ||||
2553 | p = strdupa(cgroup)(__extension__ ({ const char *__old = (cgroup); size_t __len = strlen (__old) + 1; char *__new = (char *) __builtin_alloca ( __len); (char *) memcpy (__new, __old, __len); })); | |||
2554 | for (;;) { | |||
2555 | char *e; | |||
2556 | ||||
2557 | e = strrchr(p, '/'); | |||
2558 | if (!e || e == p) | |||
2559 | return hashmap_get(m->cgroup_unit, SPECIAL_ROOT_SLICE"-.slice"); | |||
2560 | ||||
2561 | *e = 0; | |||
2562 | ||||
2563 | u = hashmap_get(m->cgroup_unit, p); | |||
2564 | if (u) | |||
2565 | return u; | |||
2566 | } | |||
2567 | } | |||
2568 | ||||
2569 | Unit *manager_get_unit_by_pid_cgroup(Manager *m, pid_t pid) { | |||
2570 | _cleanup_free___attribute__((cleanup(freep))) char *cgroup = NULL((void*)0); | |||
2571 | ||||
2572 | assert(m)do { if ((__builtin_expect(!!(!(m)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("m"), "../src/core/cgroup.c", 2572, __PRETTY_FUNCTION__ ); } while (0); | |||
2573 | ||||
2574 | if (!pid_is_valid(pid)) | |||
2575 | return NULL((void*)0); | |||
2576 | ||||
2577 | if (cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER"_systemd", pid, &cgroup) < 0) | |||
2578 | return NULL((void*)0); | |||
2579 | ||||
2580 | return manager_get_unit_by_cgroup(m, cgroup); | |||
2581 | } | |||
2582 | ||||
2583 | Unit *manager_get_unit_by_pid(Manager *m, pid_t pid) { | |||
2584 | Unit *u, **array; | |||
2585 | ||||
2586 | assert(m)do { if ((__builtin_expect(!!(!(m)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("m"), "../src/core/cgroup.c", 2586, __PRETTY_FUNCTION__ ); } while (0); | |||
2587 | ||||
2588 | /* Note that a process might be owned by multiple units, we return only one here, which is good enough for most | |||
2589 | * cases, though not strictly correct. We prefer the one reported by cgroup membership, as that's the most | |||
2590 | * relevant one as children of the process will be assigned to that one, too, before all else. */ | |||
2591 | ||||
2592 | if (!pid_is_valid(pid)) | |||
2593 | return NULL((void*)0); | |||
2594 | ||||
2595 | if (pid == getpid_cached()) | |||
2596 | return hashmap_get(m->units, SPECIAL_INIT_SCOPE"init.scope"); | |||
2597 | ||||
2598 | u = manager_get_unit_by_pid_cgroup(m, pid); | |||
2599 | if (u) | |||
2600 | return u; | |||
2601 | ||||
2602 | u = hashmap_get(m->watch_pids, PID_TO_PTR(pid)); | |||
2603 | if (u) | |||
2604 | return u; | |||
2605 | ||||
2606 | array = hashmap_get(m->watch_pids, PID_TO_PTR(-pid)); | |||
2607 | if (array) | |||
2608 | return array[0]; | |||
2609 | ||||
2610 | return NULL((void*)0); | |||
2611 | } | |||
2612 | ||||
2613 | int manager_notify_cgroup_empty(Manager *m, const char *cgroup) { | |||
2614 | Unit *u; | |||
2615 | ||||
2616 | assert(m)do { if ((__builtin_expect(!!(!(m)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("m"), "../src/core/cgroup.c", 2616, __PRETTY_FUNCTION__ ); } while (0); | |||
2617 | assert(cgroup)do { if ((__builtin_expect(!!(!(cgroup)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("cgroup"), "../src/core/cgroup.c", 2617, __PRETTY_FUNCTION__); } while (0); | |||
2618 | ||||
2619 | /* Called on the legacy hierarchy whenever we get an explicit cgroup notification from the cgroup agent process | |||
2620 | * or from the --system instance */ | |||
2621 | ||||
2622 | log_debug("Got cgroup empty notification for: %s", cgroup)({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/core/cgroup.c", 2622, __func__, "Got cgroup empty notification for: %s" , cgroup) : -abs(_e); }); | |||
2623 | ||||
2624 | u = manager_get_unit_by_cgroup(m, cgroup); | |||
2625 | if (!u) | |||
2626 | return 0; | |||
2627 | ||||
2628 | unit_add_to_cgroup_empty_queue(u); | |||
2629 | return 1; | |||
2630 | } | |||
2631 | ||||
2632 | int unit_get_memory_current(Unit *u, uint64_t *ret) { | |||
2633 | _cleanup_free___attribute__((cleanup(freep))) char *v = NULL((void*)0); | |||
2634 | int r; | |||
2635 | ||||
2636 | assert(u)do { if ((__builtin_expect(!!(!(u)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("u"), "../src/core/cgroup.c", 2636, __PRETTY_FUNCTION__ ); } while (0); | |||
2637 | assert(ret)do { if ((__builtin_expect(!!(!(ret)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("ret"), "../src/core/cgroup.c", 2637, __PRETTY_FUNCTION__ ); } while (0); | |||
2638 | ||||
2639 | if (!UNIT_CGROUP_BOOL(u, memory_accounting)({ CGroupContext *cc = unit_get_cgroup_context(u); cc ? cc-> memory_accounting : 0; })) | |||
2640 | return -ENODATA61; | |||
2641 | ||||
2642 | if (!u->cgroup_path) | |||
2643 | return -ENODATA61; | |||
2644 | ||||
2645 | /* The root cgroup doesn't expose this information, let's get it from /proc instead */ | |||
2646 | if (unit_has_root_cgroup(u)) | |||
2647 | return procfs_memory_get_used(ret); | |||
2648 | ||||
2649 | if ((u->cgroup_realized_mask & CGROUP_MASK_MEMORY) == 0) | |||
2650 | return -ENODATA61; | |||
2651 | ||||
2652 | r = cg_all_unified(); | |||
2653 | if (r < 0) | |||
2654 | return r; | |||
2655 | if (r > 0) | |||
2656 | r = cg_get_attribute("memory", u->cgroup_path, "memory.current", &v); | |||
2657 | else | |||
2658 | r = cg_get_attribute("memory", u->cgroup_path, "memory.usage_in_bytes", &v); | |||
2659 | if (r == -ENOENT2) | |||
2660 | return -ENODATA61; | |||
2661 | if (r < 0) | |||
2662 | return r; | |||
2663 | ||||
2664 | return safe_atou64(v, ret); | |||
2665 | } | |||
2666 | ||||
2667 | int unit_get_tasks_current(Unit *u, uint64_t *ret) { | |||
2668 | _cleanup_free___attribute__((cleanup(freep))) char *v = NULL((void*)0); | |||
2669 | int r; | |||
2670 | ||||
2671 | assert(u)do { if ((__builtin_expect(!!(!(u)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("u"), "../src/core/cgroup.c", 2671, __PRETTY_FUNCTION__ ); } while (0); | |||
2672 | assert(ret)do { if ((__builtin_expect(!!(!(ret)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("ret"), "../src/core/cgroup.c", 2672, __PRETTY_FUNCTION__ ); } while (0); | |||
2673 | ||||
2674 | if (!UNIT_CGROUP_BOOL(u, tasks_accounting)({ CGroupContext *cc = unit_get_cgroup_context(u); cc ? cc-> tasks_accounting : 0; })) | |||
2675 | return -ENODATA61; | |||
2676 | ||||
2677 | if (!u->cgroup_path) | |||
2678 | return -ENODATA61; | |||
2679 | ||||
2680 | /* The root cgroup doesn't expose this information, let's get it from /proc instead */ | |||
2681 | if (unit_has_root_cgroup(u)) | |||
2682 | return procfs_tasks_get_current(ret); | |||
2683 | ||||
2684 | if ((u->cgroup_realized_mask & CGROUP_MASK_PIDS) == 0) | |||
2685 | return -ENODATA61; | |||
2686 | ||||
2687 | r = cg_get_attribute("pids", u->cgroup_path, "pids.current", &v); | |||
2688 | if (r == -ENOENT2) | |||
2689 | return -ENODATA61; | |||
2690 | if (r < 0) | |||
2691 | return r; | |||
2692 | ||||
2693 | return safe_atou64(v, ret); | |||
2694 | } | |||
2695 | ||||
2696 | static int unit_get_cpu_usage_raw(Unit *u, nsec_t *ret) { | |||
2697 | _cleanup_free___attribute__((cleanup(freep))) char *v = NULL((void*)0); | |||
2698 | uint64_t ns; | |||
2699 | int r; | |||
2700 | ||||
2701 | assert(u)do { if ((__builtin_expect(!!(!(u)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("u"), "../src/core/cgroup.c", 2701, __PRETTY_FUNCTION__ ); } while (0); | |||
2702 | assert(ret)do { if ((__builtin_expect(!!(!(ret)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("ret"), "../src/core/cgroup.c", 2702, __PRETTY_FUNCTION__ ); } while (0); | |||
2703 | ||||
2704 | if (!u->cgroup_path) | |||
2705 | return -ENODATA61; | |||
2706 | ||||
2707 | /* The root cgroup doesn't expose this information, let's get it from /proc instead */ | |||
2708 | if (unit_has_root_cgroup(u)) | |||
2709 | return procfs_cpu_get_usage(ret); | |||
2710 | ||||
2711 | r = cg_all_unified(); | |||
2712 | if (r < 0) | |||
2713 | return r; | |||
2714 | if (r > 0) { | |||
2715 | _cleanup_free___attribute__((cleanup(freep))) char *val = NULL((void*)0); | |||
2716 | uint64_t us; | |||
2717 | ||||
2718 | if ((u->cgroup_realized_mask & CGROUP_MASK_CPU) == 0) | |||
2719 | return -ENODATA61; | |||
2720 | ||||
2721 | r = cg_get_keyed_attribute("cpu", u->cgroup_path, "cpu.stat", STRV_MAKE("usage_usec")((char**) ((const char*[]) { "usage_usec", ((void*)0) })), &val); | |||
2722 | if (r < 0) | |||
2723 | return r; | |||
2724 | if (IN_SET(r, -ENOENT, -ENXIO)({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){-2, -6})/sizeof(int)]; switch(r) { case - 2: case -6: _found = 1; break; default: break; } _found; })) | |||
2725 | return -ENODATA61; | |||
2726 | ||||
2727 | r = safe_atou64(val, &us); | |||
2728 | if (r < 0) | |||
2729 | return r; | |||
2730 | ||||
2731 | ns = us * NSEC_PER_USEC((nsec_t) 1000ULL); | |||
2732 | } else { | |||
2733 | if ((u->cgroup_realized_mask & CGROUP_MASK_CPUACCT) == 0) | |||
2734 | return -ENODATA61; | |||
2735 | ||||
2736 | r = cg_get_attribute("cpuacct", u->cgroup_path, "cpuacct.usage", &v); | |||
2737 | if (r == -ENOENT2) | |||
2738 | return -ENODATA61; | |||
2739 | if (r < 0) | |||
2740 | return r; | |||
2741 | ||||
2742 | r = safe_atou64(v, &ns); | |||
2743 | if (r < 0) | |||
2744 | return r; | |||
2745 | } | |||
2746 | ||||
2747 | *ret = ns; | |||
2748 | return 0; | |||
2749 | } | |||
2750 | ||||
2751 | int unit_get_cpu_usage(Unit *u, nsec_t *ret) { | |||
2752 | nsec_t ns; | |||
2753 | int r; | |||
2754 | ||||
2755 | assert(u)do { if ((__builtin_expect(!!(!(u)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("u"), "../src/core/cgroup.c", 2755, __PRETTY_FUNCTION__ ); } while (0); | |||
2756 | ||||
2757 | /* Retrieve the current CPU usage counter. This will subtract the CPU counter taken when the unit was | |||
2758 | * started. If the cgroup has been removed already, returns the last cached value. To cache the value, simply | |||
2759 | * call this function with a NULL return value. */ | |||
2760 | ||||
2761 | if (!UNIT_CGROUP_BOOL(u, cpu_accounting)({ CGroupContext *cc = unit_get_cgroup_context(u); cc ? cc-> cpu_accounting : 0; })) | |||
2762 | return -ENODATA61; | |||
2763 | ||||
2764 | r = unit_get_cpu_usage_raw(u, &ns); | |||
2765 | if (r == -ENODATA61 && u->cpu_usage_last != NSEC_INFINITY((nsec_t) -1)) { | |||
2766 | /* If we can't get the CPU usage anymore (because the cgroup was already removed, for example), use our | |||
2767 | * cached value. */ | |||
2768 | ||||
2769 | if (ret) | |||
2770 | *ret = u->cpu_usage_last; | |||
2771 | return 0; | |||
2772 | } | |||
2773 | if (r < 0) | |||
2774 | return r; | |||
2775 | ||||
2776 | if (ns > u->cpu_usage_base) | |||
2777 | ns -= u->cpu_usage_base; | |||
2778 | else | |||
2779 | ns = 0; | |||
2780 | ||||
2781 | u->cpu_usage_last = ns; | |||
2782 | if (ret) | |||
2783 | *ret = ns; | |||
2784 | ||||
2785 | return 0; | |||
2786 | } | |||
2787 | ||||
2788 | int unit_get_ip_accounting( | |||
2789 | Unit *u, | |||
2790 | CGroupIPAccountingMetric metric, | |||
2791 | uint64_t *ret) { | |||
2792 | ||||
2793 | uint64_t value; | |||
2794 | int fd, r; | |||
2795 | ||||
2796 | assert(u)do { if ((__builtin_expect(!!(!(u)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("u"), "../src/core/cgroup.c", 2796, __PRETTY_FUNCTION__ ); } while (0); | |||
2797 | assert(metric >= 0)do { if ((__builtin_expect(!!(!(metric >= 0)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("metric >= 0"), "../src/core/cgroup.c" , 2797, __PRETTY_FUNCTION__); } while (0); | |||
2798 | assert(metric < _CGROUP_IP_ACCOUNTING_METRIC_MAX)do { if ((__builtin_expect(!!(!(metric < _CGROUP_IP_ACCOUNTING_METRIC_MAX )),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("metric < _CGROUP_IP_ACCOUNTING_METRIC_MAX" ), "../src/core/cgroup.c", 2798, __PRETTY_FUNCTION__); } while (0); | |||
2799 | assert(ret)do { if ((__builtin_expect(!!(!(ret)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("ret"), "../src/core/cgroup.c", 2799, __PRETTY_FUNCTION__ ); } while (0); | |||
2800 | ||||
2801 | if (!UNIT_CGROUP_BOOL(u, ip_accounting)({ CGroupContext *cc = unit_get_cgroup_context(u); cc ? cc-> ip_accounting : 0; })) | |||
2802 | return -ENODATA61; | |||
2803 | ||||
2804 | fd = IN_SET(metric, CGROUP_IP_INGRESS_BYTES, CGROUP_IP_INGRESS_PACKETS)({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){CGROUP_IP_INGRESS_BYTES, CGROUP_IP_INGRESS_PACKETS })/sizeof(int)]; switch(metric) { case CGROUP_IP_INGRESS_BYTES : case CGROUP_IP_INGRESS_PACKETS: _found = 1; break; default: break; } _found; }) ? | |||
2805 | u->ip_accounting_ingress_map_fd : | |||
2806 | u->ip_accounting_egress_map_fd; | |||
2807 | if (fd < 0) | |||
2808 | return -ENODATA61; | |||
2809 | ||||
2810 | if (IN_SET(metric, CGROUP_IP_INGRESS_BYTES, CGROUP_IP_EGRESS_BYTES)({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){CGROUP_IP_INGRESS_BYTES, CGROUP_IP_EGRESS_BYTES })/sizeof(int)]; switch(metric) { case CGROUP_IP_INGRESS_BYTES : case CGROUP_IP_EGRESS_BYTES: _found = 1; break; default: break ; } _found; })) | |||
2811 | r = bpf_firewall_read_accounting(fd, &value, NULL((void*)0)); | |||
2812 | else | |||
2813 | r = bpf_firewall_read_accounting(fd, NULL((void*)0), &value); | |||
2814 | if (r < 0) | |||
2815 | return r; | |||
2816 | ||||
2817 | /* Add in additional metrics from a previous runtime. Note that when reexecing/reloading the daemon we compile | |||
2818 | * all BPF programs and maps anew, but serialize the old counters. When deserializing we store them in the | |||
2819 | * ip_accounting_extra[] field, and add them in here transparently. */ | |||
2820 | ||||
2821 | *ret = value + u->ip_accounting_extra[metric]; | |||
2822 | ||||
2823 | return r; | |||
2824 | } | |||
2825 | ||||
2826 | int unit_reset_cpu_accounting(Unit *u) { | |||
2827 | nsec_t ns; | |||
2828 | int r; | |||
2829 | ||||
2830 | assert(u)do { if ((__builtin_expect(!!(!(u)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("u"), "../src/core/cgroup.c", 2830, __PRETTY_FUNCTION__ ); } while (0); | |||
2831 | ||||
2832 | u->cpu_usage_last = NSEC_INFINITY((nsec_t) -1); | |||
2833 | ||||
2834 | r = unit_get_cpu_usage_raw(u, &ns); | |||
2835 | if (r < 0) { | |||
2836 | u->cpu_usage_base = 0; | |||
2837 | return r; | |||
2838 | } | |||
2839 | ||||
2840 | u->cpu_usage_base = ns; | |||
2841 | return 0; | |||
2842 | } | |||
2843 | ||||
2844 | int unit_reset_ip_accounting(Unit *u) { | |||
2845 | int r = 0, q = 0; | |||
2846 | ||||
2847 | assert(u)do { if ((__builtin_expect(!!(!(u)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("u"), "../src/core/cgroup.c", 2847, __PRETTY_FUNCTION__ ); } while (0); | |||
2848 | ||||
2849 | if (u->ip_accounting_ingress_map_fd >= 0) | |||
2850 | r = bpf_firewall_reset_accounting(u->ip_accounting_ingress_map_fd); | |||
2851 | ||||
2852 | if (u->ip_accounting_egress_map_fd >= 0) | |||
2853 | q = bpf_firewall_reset_accounting(u->ip_accounting_egress_map_fd); | |||
2854 | ||||
2855 | zero(u->ip_accounting_extra)(({ size_t _l_ = (sizeof(u->ip_accounting_extra)); void *_x_ = (&(u->ip_accounting_extra)); _l_ == 0 ? _x_ : memset (_x_, 0, _l_); })); | |||
2856 | ||||
2857 | return r < 0 ? r : q; | |||
2858 | } | |||
2859 | ||||
2860 | void unit_invalidate_cgroup(Unit *u, CGroupMask m) { | |||
2861 | assert(u)do { if ((__builtin_expect(!!(!(u)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("u"), "../src/core/cgroup.c", 2861, __PRETTY_FUNCTION__ ); } while (0); | |||
2862 | ||||
2863 | if (!UNIT_HAS_CGROUP_CONTEXT(u)(unit_vtable[(u)->type]->cgroup_context_offset > 0)) | |||
2864 | return; | |||
2865 | ||||
2866 | if (m == 0) | |||
2867 | return; | |||
2868 | ||||
2869 | /* always invalidate compat pairs together */ | |||
2870 | if (m & (CGROUP_MASK_IO | CGROUP_MASK_BLKIO)) | |||
2871 | m |= CGROUP_MASK_IO | CGROUP_MASK_BLKIO; | |||
2872 | ||||
2873 | if (m & (CGROUP_MASK_CPU | CGROUP_MASK_CPUACCT)) | |||
2874 | m |= CGROUP_MASK_CPU | CGROUP_MASK_CPUACCT; | |||
2875 | ||||
2876 | if ((u->cgroup_realized_mask & m) == 0) /* NOP? */ | |||
2877 | return; | |||
2878 | ||||
2879 | u->cgroup_realized_mask &= ~m; | |||
2880 | unit_add_to_cgroup_realize_queue(u); | |||
2881 | } | |||
2882 | ||||
2883 | void unit_invalidate_cgroup_bpf(Unit *u) { | |||
2884 | assert(u)do { if ((__builtin_expect(!!(!(u)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("u"), "../src/core/cgroup.c", 2884, __PRETTY_FUNCTION__ ); } while (0); | |||
2885 | ||||
2886 | if (!UNIT_HAS_CGROUP_CONTEXT(u)(unit_vtable[(u)->type]->cgroup_context_offset > 0)) | |||
2887 | return; | |||
2888 | ||||
2889 | if (u->cgroup_bpf_state == UNIT_CGROUP_BPF_INVALIDATED) /* NOP? */ | |||
2890 | return; | |||
2891 | ||||
2892 | u->cgroup_bpf_state = UNIT_CGROUP_BPF_INVALIDATED; | |||
2893 | unit_add_to_cgroup_realize_queue(u); | |||
2894 | ||||
2895 | /* If we are a slice unit, we also need to put compile a new BPF program for all our children, as the IP access | |||
2896 | * list of our children includes our own. */ | |||
2897 | if (u->type == UNIT_SLICE) { | |||
2898 | Unit *member; | |||
2899 | Iterator i; | |||
2900 | void *v; | |||
2901 | ||||
2902 | HASHMAP_FOREACH_KEY(v, member, u->dependencies[UNIT_BEFORE], i)for ((i) = ((Iterator) { .idx = ((2147483647 *2U +1U) - 1), . next_key = ((void*)0) }); hashmap_iterate((u->dependencies [UNIT_BEFORE]), &(i), (void**)&(v), (const void**) & (member)); ) { | |||
2903 | if (member == u) | |||
2904 | continue; | |||
2905 | ||||
2906 | if (UNIT_DEREF(member->slice)((member->slice).target) != u) | |||
2907 | continue; | |||
2908 | ||||
2909 | unit_invalidate_cgroup_bpf(member); | |||
2910 | } | |||
2911 | } | |||
2912 | } | |||
2913 | ||||
2914 | bool_Bool unit_cgroup_delegate(Unit *u) { | |||
2915 | CGroupContext *c; | |||
2916 | ||||
2917 | assert(u)do { if ((__builtin_expect(!!(!(u)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("u"), "../src/core/cgroup.c", 2917, __PRETTY_FUNCTION__ ); } while (0); | |||
2918 | ||||
2919 | if (!UNIT_VTABLE(u)unit_vtable[(u)->type]->can_delegate) | |||
2920 | return false0; | |||
2921 | ||||
2922 | c = unit_get_cgroup_context(u); | |||
2923 | if (!c) | |||
2924 | return false0; | |||
2925 | ||||
2926 | return c->delegate; | |||
2927 | } | |||
2928 | ||||
2929 | void manager_invalidate_startup_units(Manager *m) { | |||
2930 | Iterator i; | |||
2931 | Unit *u; | |||
2932 | ||||
2933 | assert(m)do { if ((__builtin_expect(!!(!(m)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("m"), "../src/core/cgroup.c", 2933, __PRETTY_FUNCTION__ ); } while (0); | |||
2934 | ||||
2935 | SET_FOREACH(u, m->startup_units, i)for ((i) = ((Iterator) { .idx = ((2147483647 *2U +1U) - 1), . next_key = ((void*)0) }); set_iterate((m->startup_units), & (i), (void**)&(u)); ) | |||
2936 | unit_invalidate_cgroup(u, CGROUP_MASK_CPU|CGROUP_MASK_IO|CGROUP_MASK_BLKIO); | |||
2937 | } | |||
2938 | ||||
2939 | int unit_cgroup_freezer_action(Unit *u, FreezerAction action) { | |||
2940 | _cleanup_free___attribute__((cleanup(freep))) char *path = NULL((void*)0); | |||
2941 | FreezerState target, kernel = _FREEZER_STATE_INVALID; | |||
2942 | int r; | |||
2943 | ||||
2944 | assert(u)do { if ((__builtin_expect(!!(!(u)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("u"), "../src/core/cgroup.c", 2944, __PRETTY_FUNCTION__ ); } while (0); | |||
2945 | assert(IN_SET(action, FREEZER_FREEZE, FREEZER_THAW))do { if ((__builtin_expect(!!(!(({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended[20 - sizeof((int[]){FREEZER_FREEZE, FREEZER_THAW})/sizeof(int)] ; switch(action) { case FREEZER_FREEZE: case FREEZER_THAW: _found = 1; break; default: break; } _found; }))),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("IN_SET(action, FREEZER_FREEZE, FREEZER_THAW)" ), "../src/core/cgroup.c", 2945, __PRETTY_FUNCTION__); } while (0); | |||
2946 | ||||
2947 | if (!cg_freezer_supported()) | |||
2948 | return 0; | |||
2949 | ||||
2950 | if (!u->cgroup_realized) | |||
2951 | return -EBUSY16; | |||
2952 | ||||
2953 | target = action == FREEZER_FREEZE ? FREEZER_FROZEN : FREEZER_RUNNING; | |||
2954 | ||||
2955 | r = unit_freezer_state_kernel(u, &kernel); | |||
2956 | if (r < 0) | |||
2957 | log_unit_debug_errno(u, r, "Failed to obtain cgroup freezer state: %m")({ const Unit *_u = (u); _u ? log_object_internal(7, r, "../src/core/cgroup.c" , 2957, __func__, _u->manager->unit_log_field, _u->id , _u->manager->invocation_log_field, _u->invocation_id_string , "Failed to obtain cgroup freezer state: %m") : log_internal_realm (((LOG_REALM_SYSTEMD) << 10 | ((7))), r, "../src/core/cgroup.c" , 2957, __func__, "Failed to obtain cgroup freezer state: %m" ); }); | |||
2958 | ||||
2959 | if (target == kernel) { | |||
2960 | u->freezer_state = target; | |||
2961 | return 0; | |||
2962 | } | |||
2963 | ||||
2964 | r = cg_get_path(SYSTEMD_CGROUP_CONTROLLER"_systemd", u->cgroup_path, "cgroup.freeze", &path); | |||
2965 | if (r < 0) | |||
2966 | return r; | |||
2967 | ||||
2968 | log_unit_debug(u, "%s unit.", action == FREEZER_FREEZE ? "Freezing" : "Thawing")({ const Unit *_u = (u); _u ? log_object_internal(7, 0, "../src/core/cgroup.c" , 2968, __func__, _u->manager->unit_log_field, _u->id , _u->manager->invocation_log_field, _u->invocation_id_string , "%s unit.", action == FREEZER_FREEZE ? "Freezing" : "Thawing" ) : log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((7 ))), 0, "../src/core/cgroup.c", 2968, __func__, "%s unit.", action == FREEZER_FREEZE ? "Freezing" : "Thawing"); }); | |||
2969 | ||||
2970 | if (action == FREEZER_FREEZE) | |||
2971 | u->freezer_state = FREEZER_FREEZING; | |||
2972 | else | |||
2973 | u->freezer_state = FREEZER_THAWING; | |||
2974 | ||||
2975 | r = write_string_file(path, one_zero(action == FREEZER_FREEZE), WRITE_STRING_FILE_DISABLE_BUFFER); | |||
2976 | if (r < 0) | |||
2977 | return r; | |||
2978 | ||||
2979 | return 1; | |||
2980 | } | |||
2981 | ||||
2982 | static const char* const cgroup_device_policy_table[_CGROUP_DEVICE_POLICY_MAX] = { | |||
2983 | [CGROUP_AUTO] = "auto", | |||
2984 | [CGROUP_CLOSED] = "closed", | |||
2985 | [CGROUP_STRICT] = "strict", | |||
2986 | }; | |||
2987 | ||||
2988 | int unit_get_cpuset(Unit *u, CPUSet *cpus, const char *name) { | |||
2989 | _cleanup_free___attribute__((cleanup(freep))) char *v = NULL((void*)0); | |||
2990 | int r; | |||
2991 | ||||
2992 | assert(u)do { if ((__builtin_expect(!!(!(u)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("u"), "../src/core/cgroup.c", 2992, __PRETTY_FUNCTION__ ); } while (0); | |||
2993 | assert(cpus)do { if ((__builtin_expect(!!(!(cpus)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("cpus"), "../src/core/cgroup.c", 2993, __PRETTY_FUNCTION__ ); } while (0); | |||
2994 | ||||
2995 | if (!u->cgroup_path) | |||
2996 | return -ENODATA61; | |||
2997 | ||||
2998 | if ((u->cgroup_realized_mask & CGROUP_MASK_CPUSET) == 0) | |||
2999 | return -ENODATA61; | |||
3000 | ||||
3001 | r = cg_all_unified(); | |||
3002 | if (r < 0) | |||
3003 | return r; | |||
3004 | if (r == 0) | |||
3005 | return -ENODATA61; | |||
3006 | if (r > 0) | |||
3007 | r = cg_get_attribute("cpuset", u->cgroup_path, name, &v); | |||
3008 | if (r == -ENOENT2) | |||
3009 | return -ENODATA61; | |||
3010 | if (r < 0) | |||
3011 | return r; | |||
3012 | ||||
3013 | return parse_cpu_set_full(v, cpus, false0, NULL((void*)0), NULL((void*)0), 0, NULL((void*)0)); | |||
3014 | } | |||
3015 | ||||
3016 | DEFINE_STRING_TABLE_LOOKUP(cgroup_device_policy, CGroupDevicePolicy)const char *cgroup_device_policy_to_string(CGroupDevicePolicy i) { if (i < 0 || i >= (CGroupDevicePolicy) __extension__ (__builtin_choose_expr( !__builtin_types_compatible_p(typeof (cgroup_device_policy_table), typeof(&*(cgroup_device_policy_table ))), sizeof(cgroup_device_policy_table)/sizeof((cgroup_device_policy_table )[0]), ((void)0)))) return ((void*)0); return cgroup_device_policy_table [i]; } CGroupDevicePolicy cgroup_device_policy_from_string(const char *s) { return (CGroupDevicePolicy) string_table_lookup(cgroup_device_policy_table , __extension__ (__builtin_choose_expr( !__builtin_types_compatible_p (typeof(cgroup_device_policy_table), typeof(&*(cgroup_device_policy_table ))), sizeof(cgroup_device_policy_table)/sizeof((cgroup_device_policy_table )[0]), ((void)0))), s); }; | |||
3017 | ||||
3018 | static const char* const freezer_action_table[_FREEZER_ACTION_MAX] = { | |||
3019 | [FREEZER_FREEZE] = "freeze", | |||
3020 | [FREEZER_THAW] = "thaw", | |||
3021 | }; | |||
3022 | ||||
3023 | DEFINE_STRING_TABLE_LOOKUP(freezer_action, FreezerAction)const char *freezer_action_to_string(FreezerAction i) { if (i < 0 || i >= (FreezerAction) __extension__ (__builtin_choose_expr ( !__builtin_types_compatible_p(typeof(freezer_action_table), typeof(&*(freezer_action_table))), sizeof(freezer_action_table )/sizeof((freezer_action_table)[0]), ((void)0)))) return ((void *)0); return freezer_action_table[i]; } FreezerAction freezer_action_from_string (const char *s) { return (FreezerAction) string_table_lookup( freezer_action_table, __extension__ (__builtin_choose_expr( ! __builtin_types_compatible_p(typeof(freezer_action_table), typeof (&*(freezer_action_table))), sizeof(freezer_action_table) /sizeof((freezer_action_table)[0]), ((void)0))), s); }; |