mirror of
https://github.com/systemd/systemd.git
synced 2025-03-21 02:50:18 +03:00
core: Make (user) instance aware of delegated cgroup controllers
systemd user instance assumed same controllers are available to it as to PID 1. That is not true generally, in v1 (legacy, hybrid) we don't delegate any controllers to anyone and in v2 (unified) we may delegate only subset of controllers. The user instance would fail silently when the controller cgroup cannot be created or the controller cannot be enabled on the unified hierarchy. The changes in 7b63961415 ("cgroup: Swap cgroup v1 deletion and migration") caused some attempts of operating on non-delegated controllers to be logged. Make the user instance first check what controllers are availble to it and narrow operations only to these controllers. The original checks are kept in place. Note that daemon-reexec needs to be invoked in order to update the set of unabled controllers after a change. Fixes: #18047 Fixes: #17862
This commit is contained in:
parent
81504017f4
commit
0fa7b50053
@ -527,15 +527,21 @@ int cg_get_path(const char *controller, const char *path, const char *suffix, ch
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int controller_is_v1_accessible(const char *controller) {
|
||||
const char *cc, *dn;
|
||||
static int controller_is_v1_accessible(const char *root, const char *controller) {
|
||||
const char *cpath, *dn;
|
||||
|
||||
assert(controller);
|
||||
|
||||
dn = controller_to_dirname(controller);
|
||||
cc = strjoina("/sys/fs/cgroup/", dn);
|
||||
cpath = strjoina("/sys/fs/cgroup/", dn);
|
||||
if (root)
|
||||
/* Also check that:
|
||||
* - possible subcgroup is created at root,
|
||||
* - we can modify the hierarchy.
|
||||
* "Leak" cpath on stack */
|
||||
cpath = strjoina(cpath, root, "/cgroup.procs");
|
||||
|
||||
if (laccess(cc, F_OK) < 0)
|
||||
if (laccess(cpath, root ? W_OK : F_OK) < 0)
|
||||
return -errno;
|
||||
|
||||
return 0;
|
||||
@ -560,7 +566,7 @@ int cg_get_path_and_check(const char *controller, const char *path, const char *
|
||||
return -EOPNOTSUPP;
|
||||
} else {
|
||||
/* Check if the specified controller is actually accessible */
|
||||
r = controller_is_v1_accessible(controller);
|
||||
r = controller_is_v1_accessible(NULL, controller);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
@ -1847,7 +1853,7 @@ int cg_mask_from_string(const char *value, CGroupMask *ret) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cg_mask_supported(CGroupMask *ret) {
|
||||
int cg_mask_supported_subtree(const char *root, CGroupMask *ret) {
|
||||
CGroupMask mask;
|
||||
int r;
|
||||
|
||||
@ -1859,15 +1865,11 @@ int cg_mask_supported(CGroupMask *ret) {
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r > 0) {
|
||||
_cleanup_free_ char *root = NULL, *controllers = NULL, *path = NULL;
|
||||
_cleanup_free_ char *controllers = NULL, *path = NULL;
|
||||
|
||||
/* In the unified hierarchy we can read the supported and accessible controllers from
|
||||
* the top-level cgroup attribute */
|
||||
|
||||
r = cg_get_root_path(&root);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = cg_get_path(SYSTEMD_CGROUP_CONTROLLER, root, "cgroup.controllers", &path);
|
||||
if (r < 0)
|
||||
return r;
|
||||
@ -1886,7 +1888,7 @@ int cg_mask_supported(CGroupMask *ret) {
|
||||
} else {
|
||||
CGroupController c;
|
||||
|
||||
/* In the legacy hierarchy, we check which hierarchies are mounted. */
|
||||
/* In the legacy hierarchy, we check which hierarchies are accessible. */
|
||||
|
||||
mask = 0;
|
||||
for (c = 0; c < _CGROUP_CONTROLLER_MAX; c++) {
|
||||
@ -1897,7 +1899,7 @@ int cg_mask_supported(CGroupMask *ret) {
|
||||
continue;
|
||||
|
||||
n = cgroup_controller_to_string(c);
|
||||
if (controller_is_v1_accessible(n) >= 0)
|
||||
if (controller_is_v1_accessible(root, n) >= 0)
|
||||
mask |= bit;
|
||||
}
|
||||
}
|
||||
@ -1906,6 +1908,17 @@ int cg_mask_supported(CGroupMask *ret) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cg_mask_supported(CGroupMask *ret) {
|
||||
_cleanup_free_ char *root = NULL;
|
||||
int r;
|
||||
|
||||
r = cg_get_root_path(&root);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return cg_mask_supported_subtree(root, ret);
|
||||
}
|
||||
|
||||
int cg_kernel_controllers(Set **ret) {
|
||||
_cleanup_set_free_free_ Set *controllers = NULL;
|
||||
_cleanup_fclose_ FILE *f = NULL;
|
||||
|
@ -257,6 +257,7 @@ int cg_slice_to_path(const char *unit, char **ret);
|
||||
typedef const char* (*cg_migrate_callback_t)(CGroupMask mask, void *userdata);
|
||||
|
||||
int cg_mask_supported(CGroupMask *ret);
|
||||
int cg_mask_supported_subtree(const char *root, CGroupMask *ret);
|
||||
int cg_mask_from_string(const char *s, CGroupMask *ret);
|
||||
int cg_mask_to_string(CGroupMask mask, char **ret);
|
||||
|
||||
|
@ -3110,7 +3110,7 @@ int manager_setup_cgroup(Manager *m) {
|
||||
(void) cg_set_attribute("memory", "/", "memory.use_hierarchy", "1");
|
||||
|
||||
/* 8. Figure out which controllers are supported */
|
||||
r = cg_mask_supported(&m->cgroup_supported);
|
||||
r = cg_mask_supported_subtree(m->cgroup_root, &m->cgroup_supported);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to determine supported controllers: %m");
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user