| File: | build-scan/../src/core/cgroup.c |
| Warning: | line 162, column 17 Use of memory after it is freed |
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_A63 = ((period)); const typeof((resolution)) __unique_prefix_B64 = ((resolution)); __unique_prefix_A63 > __unique_prefix_B64 ? __unique_prefix_A63 : __unique_prefix_B64; }); __extension__ ({ const typeof((_c)) __unique_prefix_A65 = ((_c)); const typeof ((resolution * ((usec_t) 1000000ULL) / quota)) __unique_prefix_B66 = ((resolution * ((usec_t) 1000000ULL) / quota)); __unique_prefix_A65 > __unique_prefix_B66 ? __unique_prefix_A65 : __unique_prefix_B66 ; }); }))) __unique_prefix_A67 = ((__extension__ ({ const typeof (period) _c = __extension__ ({ const typeof((period)) __unique_prefix_A63 = ((period)); const typeof((resolution)) __unique_prefix_B64 = ((resolution)); __unique_prefix_A63 > __unique_prefix_B64 ? __unique_prefix_A63 : __unique_prefix_B64; }); __extension__ ({ const typeof((_c)) __unique_prefix_A65 = ((_c)); const typeof ((resolution * ((usec_t) 1000000ULL) / quota)) __unique_prefix_B66 = ((resolution * ((usec_t) 1000000ULL) / quota)); __unique_prefix_A65 > __unique_prefix_B66 ? __unique_prefix_A65 : __unique_prefix_B66 ; }); }))); const typeof((max_period)) __unique_prefix_B68 = ( (max_period)); __unique_prefix_A67 < __unique_prefix_B68 ? __unique_prefix_A67 : __unique_prefix_B68; }); | |||
| 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_A69 = (((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_B70 = ( (((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_A69 > __unique_prefix_B70 ? __unique_prefix_A69 : __unique_prefix_B70 ; })]; | |||
| 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_A71 = ((quota * period / ((usec_t) 1000000ULL))); const typeof(( ((usec_t) 1000ULL))) __unique_prefix_B72 = ((((usec_t) 1000ULL ))); __unique_prefix_A71 > __unique_prefix_B72 ? __unique_prefix_A71 : __unique_prefix_B72; }), 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_A71 = ((quota * period / ((usec_t) 1000000ULL))); const typeof(( ((usec_t) 1000ULL))) __unique_prefix_B72 = ((((usec_t) 1000ULL ))); __unique_prefix_A71 > __unique_prefix_B72 ? __unique_prefix_A71 : __unique_prefix_B72; }), 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_A73 = (((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_B74 = (((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_A73 > __unique_prefix_B74 ? __unique_prefix_A73 : __unique_prefix_B74; }) + 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_A75 = ((quota * period / ((usec_t) 1000000ULL))); const typeof((((usec_t) 1000ULL ))) __unique_prefix_B76 = ((((usec_t) 1000ULL))); __unique_prefix_A75 > __unique_prefix_B76 ? __unique_prefix_A75 : __unique_prefix_B76 ; })) < (__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_X77 = ((shares * 100UL / 1024UL)); const typeof((1UL)) __unique_prefix_LOW78 = ((1UL)); const typeof((10000UL)) __unique_prefix_HIGH79 = ( (10000UL)); __unique_prefix_X77 > __unique_prefix_HIGH79 ? __unique_prefix_HIGH79 : __unique_prefix_X77 < __unique_prefix_LOW78 ? __unique_prefix_LOW78 : __unique_prefix_X77; }) | |||
| 678 | CGROUP_WEIGHT_MIN, CGROUP_WEIGHT_MAX)__extension__ ({ const typeof((shares * 100UL / 1024UL)) __unique_prefix_X77 = ((shares * 100UL / 1024UL)); const typeof((1UL)) __unique_prefix_LOW78 = ((1UL)); const typeof((10000UL)) __unique_prefix_HIGH79 = ( (10000UL)); __unique_prefix_X77 > __unique_prefix_HIGH79 ? __unique_prefix_HIGH79 : __unique_prefix_X77 < __unique_prefix_LOW78 ? __unique_prefix_LOW78 : __unique_prefix_X77; }); | |||
| 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_X80 = ((weight * 1024UL / 100UL)); const typeof((2UL)) __unique_prefix_LOW81 = ((2UL)); const typeof((262144UL)) __unique_prefix_HIGH82 = ((262144UL)); __unique_prefix_X80 > __unique_prefix_HIGH82 ? __unique_prefix_HIGH82 : __unique_prefix_X80 < __unique_prefix_LOW81 ? __unique_prefix_LOW81 : __unique_prefix_X80; }) | |||
| 683 | CGROUP_CPU_SHARES_MIN, CGROUP_CPU_SHARES_MAX)__extension__ ({ const typeof((weight * 1024UL / 100UL)) __unique_prefix_X80 = ((weight * 1024UL / 100UL)); const typeof((2UL)) __unique_prefix_LOW81 = ((2UL)); const typeof((262144UL)) __unique_prefix_HIGH82 = ((262144UL)); __unique_prefix_X80 > __unique_prefix_HIGH82 ? __unique_prefix_HIGH82 : __unique_prefix_X80 < __unique_prefix_LOW81 ? __unique_prefix_LOW81 : __unique_prefix_X80; }); | |||
| 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_X83 = ((blkio_weight * 100UL / 500UL)); const typeof((1UL)) __unique_prefix_LOW84 = ((1UL)); const typeof( (10000UL)) __unique_prefix_HIGH85 = ((10000UL)); __unique_prefix_X83 > __unique_prefix_HIGH85 ? __unique_prefix_HIGH85 : __unique_prefix_X83 < __unique_prefix_LOW84 ? __unique_prefix_LOW84 : __unique_prefix_X83 ; }) | |||
| 740 | CGROUP_WEIGHT_MIN, CGROUP_WEIGHT_MAX)__extension__ ({ const typeof((blkio_weight * 100UL / 500UL)) __unique_prefix_X83 = ((blkio_weight * 100UL / 500UL)); const typeof((1UL)) __unique_prefix_LOW84 = ((1UL)); const typeof( (10000UL)) __unique_prefix_HIGH85 = ((10000UL)); __unique_prefix_X83 > __unique_prefix_HIGH85 ? __unique_prefix_HIGH85 : __unique_prefix_X83 < __unique_prefix_LOW84 ? __unique_prefix_LOW84 : __unique_prefix_X83 ; }); | |||
| 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_X86 = ((io_weight * 500UL / 100UL)); const typeof((10UL)) __unique_prefix_LOW87 = ((10UL)); const typeof((1000UL)) __unique_prefix_HIGH88 = ( (1000UL)); __unique_prefix_X86 > __unique_prefix_HIGH88 ? __unique_prefix_HIGH88 : __unique_prefix_X86 < __unique_prefix_LOW87 ? __unique_prefix_LOW87 : __unique_prefix_X86; }) | |||
| 745 | CGROUP_BLKIO_WEIGHT_MIN, CGROUP_BLKIO_WEIGHT_MAX)__extension__ ({ const typeof((io_weight * 500UL / 100UL)) __unique_prefix_X86 = ((io_weight * 500UL / 100UL)); const typeof((10UL)) __unique_prefix_LOW87 = ((10UL)); const typeof((1000UL)) __unique_prefix_HIGH88 = ( (1000UL)); __unique_prefix_X86 > __unique_prefix_HIGH88 ? __unique_prefix_HIGH88 : __unique_prefix_X86 < __unique_prefix_LOW87 ? __unique_prefix_LOW87 : __unique_prefix_X86; }); | |||
| 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 || u->cgroup_bpf_state != UNIT_CGROUP_BPF_OFF; | |||
| 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 < 0) | |||
| 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); }; |