1--- 2title: Control Group APIs and Delegation 3category: Interfaces 4layout: default 5SPDX-License-Identifier: LGPL-2.1-or-later 6--- 7 8# Control Group APIs and Delegation 9 10*Intended audience: hackers working on userspace subsystems that require direct 11cgroup access, such as container managers and similar.* 12 13So you are wondering about resource management with systemd, you know Linux 14control groups (cgroups) a bit and are trying to integrate your software with 15what systemd has to offer there. Here's a bit of documentation about the 16concepts and interfaces involved with this. 17 18What's described here has been part of systemd and documented since v205 19times. However, it has been updated and improved substantially, even 20though the concepts stayed mostly the same. This is an attempt to provide more 21comprehensive up-to-date information about all this, particular in light of the 22poor implementations of the components interfacing with systemd of current 23container managers. 24 25Before you read on, please make sure you read the low-level kernel 26documentation about the 27[unified cgroup hierarchy](https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v2.html). 28This document then adds in the higher-level view from systemd. 29 30This document augments the existing documentation we already have: 31 32* [The New Control Group Interfaces](https://www.freedesktop.org/wiki/Software/systemd/ControlGroupInterface/) 33* [Writing VM and Container Managers](https://www.freedesktop.org/wiki/Software/systemd/writing-vm-managers/) 34 35These wiki documents are not as up to date as they should be, currently, but 36the basic concepts still fully apply. You should read them too, if you do something 37with cgroups and systemd, in particular as they shine more light on the various 38D-Bus APIs provided. (That said, sooner or later we should probably fold that 39wiki documentation into this very document, too.) 40 41## Two Key Design Rules 42 43Much of the philosophy behind these concepts is based on a couple of basic 44design ideas of cgroup v2 (which we however try to adapt as far as we can to 45cgroup v1 too). Specifically two cgroup v2 rules are the most relevant: 46 471. The **no-processes-in-inner-nodes** rule: this means that it's not permitted 48to have processes directly attached to a cgroup that also has child cgroups and 49vice versa. A cgroup is either an inner node or a leaf node of the tree, and if 50it's an inner node it may not contain processes directly, and if it's a leaf 51node then it may not have child cgroups. (Note that there are some minor 52exceptions to this rule, though. E.g. the root cgroup is special and allows 53both processes and children — which is used in particular to maintain kernel 54threads.) 55 562. The **single-writer** rule: this means that each cgroup only has a single 57writer, i.e. a single process managing it. It's OK if different cgroups have 58different processes managing them. However, only a single process should own a 59specific cgroup, and when it does that ownership is exclusive, and nothing else 60should manipulate it at the same time. This rule ensures that various pieces of 61software don't step on each other's toes constantly. 62 63These two rules have various effects. For example, one corollary of this is: if 64your container manager creates and manages cgroups in the system's root cgroup 65you violate rule #2, as the root cgroup is managed by systemd and hence off 66limits to everybody else. 67 68Note that rule #1 is generally enforced by the kernel if cgroup v2 is used: as 69soon as you add a process to a cgroup it is ensured the rule is not 70violated. On cgroup v1 this rule didn't exist, and hence isn't enforced, even 71though it's a good thing to follow it then too. Rule #2 is not enforced on 72either cgroup v1 nor cgroup v2 (this is UNIX after all, in the general case 73root can do anything, modulo SELinux and friends), but if you ignore it you'll 74be in constant pain as various pieces of software will fight over cgroup 75ownership. 76 77Note that cgroup v1 is currently the most deployed implementation, even though 78it's semantically broken in many ways, and in many cases doesn't actually do 79what people think it does. cgroup v2 is where things are going, and most new 80kernel features in this area are only added to cgroup v2, and not cgroup v1 81anymore. For example cgroup v2 provides proper cgroup-empty notifications, has 82support for all kinds of per-cgroup BPF magic, supports secure delegation of 83cgroup trees to less privileged processes and so on, which all are not 84available on cgroup v1. 85 86## Three Different Tree Setups 87 88systemd supports three different modes how cgroups are set up. Specifically: 89 901. **Unified** — this is the simplest mode, and exposes a pure cgroup v2 91logic. In this mode `/sys/fs/cgroup` is the only mounted cgroup API file system 92and all available controllers are exclusively exposed through it. 93 942. **Legacy** — this is the traditional cgroup v1 mode. In this mode the 95various controllers each get their own cgroup file system mounted to 96`/sys/fs/cgroup/<controller>/`. On top of that systemd manages its own cgroup 97hierarchy for managing purposes as `/sys/fs/cgroup/systemd/`. 98 993. **Hybrid** — this is a hybrid between the unified and legacy mode. It's set 100up mostly like legacy, except that there's also an additional hierarchy 101`/sys/fs/cgroup/unified/` that contains the cgroup v2 hierarchy. (Note that in 102this mode the unified hierarchy won't have controllers attached, the 103controllers are all mounted as separate hierarchies as in legacy mode, 104i.e. `/sys/fs/cgroup/unified/` is purely and exclusively about core cgroup v2 105functionality and not about resource management.) In this mode compatibility 106with cgroup v1 is retained while some cgroup v2 features are available 107too. This mode is a stopgap. Don't bother with this too much unless you have 108too much free time. 109 110To say this clearly, legacy and hybrid modes have no future. If you develop 111software today and don't focus on the unified mode, then you are writing 112software for yesterday, not tomorrow. They are primarily supported for 113compatibility reasons and will not receive new features. Sorry. 114 115Superficially, in legacy and hybrid modes it might appear that the parallel 116cgroup hierarchies for each controller are orthogonal from each other. In 117systemd they are not: the hierarchies of all controllers are always kept in 118sync (at least mostly: sub-trees might be suppressed in certain hierarchies if 119no controller usage is required for them). The fact that systemd keeps these 120hierarchies in sync means that the legacy and hybrid hierarchies are 121conceptually very close to the unified hierarchy. In particular this allows us 122to talk of one specific cgroup and actually mean the same cgroup in all 123available controller hierarchies. E.g. if we talk about the cgroup `/foo/bar/` 124then we actually mean `/sys/fs/cgroup/cpu/foo/bar/` as well as 125`/sys/fs/cgroup/memory/foo/bar/`, `/sys/fs/cgroup/pids/foo/bar/`, and so on. 126Note that in cgroup v2 the controller hierarchies aren't orthogonal, hence 127thinking about them as orthogonal won't help you in the long run anyway. 128 129If you wonder how to detect which of these three modes is currently used, use 130`statfs()` on `/sys/fs/cgroup/`. If it reports `CGROUP2_SUPER_MAGIC` in its 131`.f_type` field, then you are in unified mode. If it reports `TMPFS_MAGIC` then 132you are either in legacy or hybrid mode. To distinguish these two cases, run 133`statfs()` again on `/sys/fs/cgroup/unified/`. If that succeeds and reports 134`CGROUP2_SUPER_MAGIC` you are in hybrid mode, otherwise not. 135From a shell, you can check the `Type` in `stat -f /sys/fs/cgroup` and 136`stat -f /sys/fs/cgroup/unified`. 137 138## systemd's Unit Types 139 140The low-level kernel cgroups feature is exposed in systemd in three different 141"unit" types. Specifically: 142 1431. The `.service` unit type. This unit type is for units encapsulating 144 processes systemd itself starts. Units of these types have cgroups that are 145 the leaves of the cgroup tree the systemd instance manages (though possibly 146 they might contain a sub-tree of their own managed by something else, made 147 possible by the concept of delegation, see below). Service units are usually 148 instantiated based on a unit file on disk that describes the command line to 149 invoke and other properties of the service. However, service units may also 150 be declared and started programmatically at runtime through a D-Bus API 151 (which is called *transient* services). 152 1532. The `.scope` unit type. This is very similar to `.service`. The main 154 difference: the processes the units of this type encapsulate are forked off 155 by some unrelated manager process, and that manager asked systemd to expose 156 them as a unit. Unlike services, scopes can only be declared and started 157 programmatically, i.e. are always transient. That's because they encapsulate 158 processes forked off by something else, i.e. existing runtime objects, and 159 hence cannot really be defined fully in 'offline' concepts such as unit 160 files. 161 1623. The `.slice` unit type. Units of this type do not directly contain any 163 processes. Units of this type are the inner nodes of part of the cgroup tree 164 the systemd instance manages. Much like services, slices can be defined 165 either on disk with unit files or programmatically as transient units. 166 167Slices expose the trunk and branches of a tree, and scopes and services are 168attached to those branches as leaves. The idea is that scopes and services can 169be moved around though, i.e. assigned to a different slice if needed. 170 171The naming of slice units directly maps to the cgroup tree path. This is not 172the case for service and scope units however. A slice named `foo-bar-baz.slice` 173maps to a cgroup `/foo.slice/foo-bar.slice/foo-bar-baz.slice/`. A service 174`quux.service` which is attached to the slice `foo-bar-baz.slice` maps to the 175cgroup `/foo.slice/foo-bar.slice/foo-bar-baz.slice/quux.service/`. 176 177By default systemd sets up four slice units: 178 1791. `-.slice` is the root slice. i.e. the parent of everything else. On the host 180 system it maps directly to the top-level directory of cgroup v2. 181 1822. `system.slice` is where system services are by default placed, unless 183 configured otherwise. 184 1853. `user.slice` is where user sessions are placed. Each user gets a slice of 186 its own below that. 187 1884. `machines.slice` is where VMs and containers are supposed to be 189 placed. `systemd-nspawn` makes use of this by default, and you're very welcome 190 to place your containers and VMs there too if you hack on managers for those. 191 192Users may define any amount of additional slices they like though, the four 193above are just the defaults. 194 195## Delegation 196 197Container managers and suchlike often want to control cgroups directly using 198the raw kernel APIs. That's entirely fine and supported, as long as proper 199*delegation* is followed. Delegation is a concept we inherited from cgroup v2, 200but we expose it on cgroup v1 too. Delegation means that some parts of the 201cgroup tree may be managed by different managers than others. As long as it is 202clear which manager manages which part of the tree each one can do within its 203sub-graph of the tree whatever it wants. 204 205Only sub-trees can be delegated (though whoever decides to request a sub-tree 206can delegate sub-sub-trees further to somebody else if they like). Delegation 207takes place at a specific cgroup: in systemd there's a `Delegate=` property you 208can set for a service or scope unit. If you do, it's the cut-off point for 209systemd's cgroup management: the unit itself is managed by systemd, i.e. all 210its attributes are managed exclusively by systemd, however your program may 211create/remove sub-cgroups inside it freely, and those then become exclusive 212property of your program, systemd won't touch them — all attributes of *those* 213sub-cgroups can be manipulated freely and exclusively by your program. 214 215By turning on the `Delegate=` property for a scope or service you get a few 216guarantees: 217 2181. systemd won't fiddle with your sub-tree of the cgroup tree anymore. It won't 219 change attributes of any cgroups below it, nor will it create or remove any 220 cgroups thereunder, nor migrate processes across the boundaries of that 221 sub-tree as it deems useful anymore. 222 2232. If your service makes use of the `User=` functionality, then the sub-tree 224 will be `chown()`ed to the indicated user so that it can correctly create 225 cgroups below it. Note however that systemd will do that only in the unified 226 hierarchy (in unified and hybrid mode) as well as on systemd's own private 227 hierarchy (in legacy and hybrid mode). It won't pass ownership of the legacy 228 controller hierarchies. Delegation to less privileged processes is not safe 229 in cgroup v1 (as a limitation of the kernel), hence systemd won't facilitate 230 access to it. 231 2323. Any BPF IP filter programs systemd installs will be installed with 233 `BPF_F_ALLOW_MULTI` so that your program can install additional ones. 234 235In unit files the `Delegate=` property is superficially exposed as 236boolean. However, since v236 it optionally takes a list of controller names 237instead. If so, delegation is requested for listed controllers 238specifically. Note that this only encodes a request. Depending on various 239parameters it might happen that your service actually will get fewer 240controllers delegated (for example, because the controller is not available on 241the current kernel or was turned off) or more. If no list is specified 242(i.e. the property simply set to `yes`) then all available controllers are 243delegated. 244 245Let's stress one thing: delegation is available on scope and service units 246only. It's expressly not available on slice units. Why? Because slice units are 247our *inner* nodes of the cgroup trees and we freely attach services and scopes 248to them. If we'd allow delegation on slice units then this would mean that 249both systemd and your own manager would create/delete cgroups below the slice 250unit and that conflicts with the single-writer rule. 251 252So, if you want to do your own raw cgroups kernel level access, then allocate a 253scope unit, or a service unit (or just use the service unit you already have 254for your service code), and turn on delegation for it. 255 256The service manager sets the `user.delegate` extended attribute (readable via 257`getxattr(2)` and related calls) to the character `1` on cgroup directories 258where delegation is enabled (and removes it on those cgroups where it is 259not). This may be used by service programs to determine whether a cgroup tree 260was delegated to them. Note that this is only supported on kernels 5.6 and 261newer in combination with systemd 251 and newer. 262 263(OK, here's one caveat: if you turn on delegation for a service, and that 264service has `ExecStartPost=`, `ExecReload=`, `ExecStop=` or `ExecStopPost=` 265set, then these commands will be executed within the `.control/` sub-cgroup of 266your service's cgroup. This is necessary because by turning on delegation we 267have to assume that the cgroup delegated to your service is now an *inner* 268cgroup, which means that it may not directly contain any processes. Hence, if 269your service has any of these four settings set, you must be prepared that a 270`.control/` subcgroup might appear, managed by the service manager. This also 271means that your service code should have moved itself further down the cgroup 272tree by the time it notifies the service manager about start-up readiness, so 273that the service's main cgroup is definitely an inner node by the time the 274service manager might start `ExecStartPost=`.) 275 276(Also note, if you intend to use "threaded" cgroups — as added in Linux 4.14 —, 277then you should do that *two* levels down from the main service cgroup your 278turned delegation on for. Why that? You need one level so that systemd can 279properly create the `.control` subgroup, as described above. But that one 280cannot be threaded, since that would mean `.control` has to be threaded too — 281this is a requirement of threaded cgroups: either a cgroup and all its siblings 282are threaded or none –, but systemd expects it to be a regular cgroup. Thus you 283have to nest a second cgroup beneath it which then can be threaded.) 284 285## Three Scenarios 286 287Let's say you write a container manager, and you wonder what to do regarding 288cgroups for it, as you want your manager to be able to run on systemd systems. 289 290You basically have three options: 291 2921. The *integration-is-good* option. For this, you register each container 293 you have either as a systemd service (i.e. let systemd invoke the executor 294 binary for you) or a systemd scope (i.e. your manager executes the binary 295 directly, but then tells systemd about it. In this mode the administrator 296 can use the usual systemd resource management and reporting commands 297 individually on those containers. By turning on `Delegate=` for these scopes 298 or services you make it possible to run cgroup-enabled programs in your 299 containers, for example a nested systemd instance. This option has two 300 sub-options: 301 302 a. You transiently register the service or scope by directly contacting 303 systemd via D-Bus. In this case systemd will just manage the unit for you 304 and nothing else. 305 306 b. Instead you register the service or scope through `systemd-machined` 307 (also via D-Bus). This mini-daemon is basically just a proxy for the same 308 operations as in a. The main benefit of this: this way you let the system 309 know that what you are registering is a container, and this opens up 310 certain additional integration points. For example, `journalctl -M` can 311 then be used to directly look into any container's journal logs (should 312 the container run systemd inside), or `systemctl -M` can be used to 313 directly invoke systemd operations inside the containers. Moreover tools 314 like "ps" can then show you to which container a process belongs (`ps -eo 315 pid,comm,machine`), and even gnome-system-monitor supports it. 316 3172. The *i-like-islands* option. If all you care about is your own cgroup tree, 318 and you want to have to do as little as possible with systemd and no 319 interest in integration with the rest of the system, then this is a valid 320 option. For this all you have to do is turn on `Delegate=` for your main 321 manager daemon. Then figure out the cgroup systemd placed your daemon in: 322 you can now freely create sub-cgroups beneath it. Don't forget the 323 *no-processes-in-inner-nodes* rule however: you have to move your main 324 daemon process out of that cgroup (and into a sub-cgroup) before you can 325 start further processes in any of your sub-cgroups. 326 3273. The *i-like-continents* option. In this option you'd leave your manager 328 daemon where it is, and would not turn on delegation on its unit. However, 329 as you start your first managed process (a container, for example) you would 330 register a new scope unit with systemd, and that scope unit would have 331 `Delegate=` turned on, and it would contain the PID of this process; all 332 your managed processes subsequently created should also be moved into this 333 scope. From systemd's PoV there'd be two units: your manager service and the 334 big scope that contains all your managed processes in one. 335 336BTW: if for whatever reason you say "I hate D-Bus, I'll never call any D-Bus 337API, kthxbye", then options #1 and #3 are not available, as they generally 338involve talking to systemd from your program code, via D-Bus. You still have 339option #2 in that case however, as you can simply set `Delegate=` in your 340service's unit file and you are done and have your own sub-tree. In fact, #2 is 341the one option that allows you to completely ignore systemd's existence: you 342can entirely generically follow the single rule that you just use the cgroup 343you are started in, and everything below it, whatever that might be. That said, 344maybe if you dislike D-Bus and systemd that much, the better approach might be 345to work on that, and widen your horizon a bit. You are welcome. 346 347## Controller Support 348 349systemd supports a number of controllers (but not all). Specifically, supported 350are: 351 352* on cgroup v1: `cpu`, `cpuacct`, `blkio`, `memory`, `devices`, `pids` 353* on cgroup v2: `cpu`, `io`, `memory`, `pids` 354 355It is our intention to natively support all cgroup v2 controllers as they are 356added to the kernel. However, regarding cgroup v1: at this point we will not 357add support for any other controllers anymore. This means systemd currently 358does not and will never manage the following controllers on cgroup v1: 359`freezer`, `cpuset`, `net_cls`, `perf_event`, `net_prio`, `hugetlb`. Why not? 360Depending on the case, either their API semantics or implementations aren't 361really usable, or it's very clear they have no future on cgroup v2, and we 362won't add new code for stuff that clearly has no future. 363 364Effectively this means that all those mentioned cgroup v1 controllers are up 365for grabs: systemd won't manage them, and hence won't delegate them to your 366code (however, systemd will still mount their hierarchies, simply because it 367mounts all controller hierarchies it finds available in the kernel). If you 368decide to use them, then that's fine, but systemd won't help you with it (but 369also not interfere with it). To be nice to other tenants it might be wise to 370replicate the cgroup hierarchies of the other controllers in them too however, 371but of course that's between you and those other tenants, and systemd won't 372care. Replicating the cgroup hierarchies in those unsupported controllers would 373mean replicating the full cgroup paths in them, and hence the prefixing 374`.slice` components too, otherwise the hierarchies will start being orthogonal 375after all, and that's not really desirable. One more thing: systemd will clean 376up after you in the hierarchies it manages: if your daemon goes down, its 377cgroups will be removed too. You basically get the guarantee that you start 378with a pristine cgroup sub-tree for your service or scope whenever it is 379started. This is not the case however in the hierarchies systemd doesn't 380manage. This means that your programs should be ready to deal with left-over 381cgroups in them — from previous runs, and be extra careful with them as they 382might still carry settings that might not be valid anymore. 383 384Note a particular asymmetry here: if your systemd version doesn't support a 385specific controller on cgroup v1 you can still make use of it for delegation, 386by directly fiddling with its hierarchy and replicating the cgroup tree there 387as necessary (as suggested above). However, on cgroup v2 this is different: 388separately mounted hierarchies are not available, and delegation has always to 389happen through systemd itself. This means: when you update your kernel and it 390adds a new, so far unseen controller, and you want to use it for delegation, 391then you also need to update systemd to a version that groks it. 392 393## systemd as Container Payload 394 395systemd can happily run as a container payload's PID 1. Note that systemd 396unconditionally needs write access to the cgroup tree however, hence you need 397to delegate a sub-tree to it. Note that there's nothing too special you have to 398do beyond that: just invoke systemd as PID 1 inside the root of the delegated 399cgroup sub-tree, and it will figure out the rest: it will determine the cgroup 400it is running in and take possession of it. It won't interfere with any cgroup 401outside of the sub-tree it was invoked in. Use of `CLONE_NEWCGROUP` is hence 402optional (but of course wise). 403 404Note one particular asymmetry here though: systemd will try to take possession 405of the root cgroup you pass to it *in* *full*, i.e. it will not only 406create/remove child cgroups below it, it will also attempt to manage the 407attributes of it. OTOH as mentioned above, when delegating a cgroup tree to 408somebody else it only passes the rights to create/remove sub-cgroups, but will 409insist on managing the delegated cgroup tree's top-level attributes. Or in 410other words: systemd is *greedy* when accepting delegated cgroup trees and also 411*greedy* when delegating them to others: it insists on managing attributes on 412the specific cgroup in both cases. A container manager that is itself a payload 413of a host systemd which wants to run a systemd as its own container payload 414instead hence needs to insert an extra level in the hierarchy in between, so 415that the systemd on the host and the one in the container won't fight for the 416attributes. That said, you likely should do that anyway, due to the 417no-processes-in-inner-cgroups rule, see below. 418 419When systemd runs as container payload it will make use of all hierarchies it 420has write access to. For legacy mode you need to make at least 421`/sys/fs/cgroup/systemd/` available, all other hierarchies are optional. For 422hybrid mode you need to add `/sys/fs/cgroup/unified/`. Finally, for fully 423unified you (of course, I guess) need to provide only `/sys/fs/cgroup/` itself. 424 425## Some Dos 426 4271. ⚡ If you go for implementation option 1a or 1b (as in the list above), then 428 each of your containers will have its own systemd-managed unit and hence 429 cgroup with possibly further sub-cgroups below. Typically the first process 430 running in that unit will be some kind of executor program, which will in 431 turn fork off the payload processes of the container. In this case don't 432 forget that there are two levels of delegation involved: first, systemd 433 delegates a group sub-tree to your executor. And then your executor should 434 delegate a sub-tree further down to the container payload. Oh, and because 435 of the no-process-in-inner-nodes rule, your executor needs to migrate itself 436 to a sub-cgroup of the cgroup it got delegated, too. Most likely you hence 437 want a two-pronged approach: below the cgroup you got started in, you want 438 one cgroup maybe called `supervisor/` where your manager runs in and then 439 for each container a sibling cgroup of that maybe called `payload-xyz/`. 440 4412. ⚡ Don't forget that the cgroups you create have to have names that are 442 suitable as UNIX file names, and that they live in the same namespace as the 443 various kernel attribute files. Hence, when you want to allow the user 444 arbitrary naming, you might need to escape some of the names (for example, 445 you really don't want to create a cgroup named `tasks`, just because the 446 user created a container by that name, because `tasks` after all is a magic 447 attribute in cgroup v1, and your `mkdir()` will hence fail with `EEXIST`. In 448 systemd we do escaping by prefixing names that might collide with a kernel 449 attribute name with an underscore. You might want to do the same, but this 450 is really up to you how you do it. Just do it, and be careful. 451 452## Some Don'ts 453 4541. Never create your own cgroups below arbitrary cgroups systemd manages, i.e 455 cgroups you haven't set `Delegate=` in. Specifically: don't create your 456 own cgroups below the root cgroup . That's owned by systemd, and you will 457 step on systemd's toes if you ignore that, and systemd will step on 458 yours. Get your own delegated sub-tree, you may create as many cgroups there 459 as you like. Seriously, if you create cgroups directly in the cgroup root, 460 then all you do is ask for trouble. 461 4622. Don't attempt to set `Delegate=` in slice units, and in particular not in 463 `-.slice`. It's not supported, and will generate an error. 464 4653. Never *write* to any of the attributes of a cgroup systemd created for 466 you. It's systemd's private property. You are welcome to manipulate the 467 attributes of cgroups you created in your own delegated sub-tree, but the 468 cgroup tree of systemd itself is out of limits for you. It's fine to *read* 469 from any attribute you like however. That's totally OK and welcome. 470 4714. When not using `CLONE_NEWCGROUP` when delegating a sub-tree to a 472 container payload running systemd, then don't get the idea that you can bind 473 mount only a sub-tree of the host's cgroup tree into the container. Part of 474 the cgroup API is that `/proc/$PID/cgroup` reports the cgroup path of every 475 process, and hence any path below `/sys/fs/cgroup/` needs to match what 476 `/proc/$PID/cgroup` of the payload processes reports. What you can do safely 477 however, is mount the upper parts of the cgroup tree read-only (or even 478 replace the middle bits with an intermediary `tmpfs` — but be careful not to 479 break the `statfs()` detection logic discussed above), as long as the path 480 to the delegated sub-tree remains accessible as-is. 481 4825. ⚡ Currently, the algorithm for mapping between slice/scope/service unit 483 naming and their cgroup paths is not considered public API of systemd, and 484 may change in future versions. This means: it's best to avoid implementing a 485 local logic of translating cgroup paths to slice/scope/service names in your 486 program, or vice versa — it's likely going to break sooner or later. Use the 487 appropriate D-Bus API calls for that instead, so that systemd translates 488 this for you. (Specifically: each Unit object has a `ControlGroup` property 489 to get the cgroup for a unit. The method `GetUnitByControlGroup()` may be 490 used to get the unit for a cgroup.) 491 4926. ⚡ Think twice before delegating cgroup v1 controllers to less privileged 493 containers. It's not safe, you basically allow your containers to freeze the 494 system with that and worse. Delegation is a strongpoint of cgroup v2 though, 495 and there it's safe to treat delegation boundaries as privilege boundaries. 496 497And that's it for now. If you have further questions, refer to the systemd 498mailing list. 499 500— Berlin, 2018-04-20 501