diff --git a/src/basic/cgroup-util.c b/src/basic/cgroup-util.c index bda5c555ad..c828d10149 100644 --- a/src/basic/cgroup-util.c +++ b/src/basic/cgroup-util.c @@ -55,6 +55,7 @@ #include "stdio-util.h" #include "string-table.h" #include "string-util.h" +#include "strv.h" #include "unit-name.h" #include "user-util.h" @@ -2211,6 +2212,60 @@ int cg_trim_everywhere(CGroupMask supported, const char *path, bool delete_root) return 0; } +int cg_mask_to_string(CGroupMask mask, char **ret) { + const char *controllers[_CGROUP_CONTROLLER_MAX + 1]; + CGroupController c; + int i = 0; + char *s; + + assert(ret); + + if (mask == 0) { + *ret = NULL; + return 0; + } + + for (c = 0; c < _CGROUP_CONTROLLER_MAX; c++) { + + if (!(mask & CGROUP_CONTROLLER_TO_MASK(c))) + continue; + + controllers[i++] = cgroup_controller_to_string(c); + controllers[i] = NULL; + } + + s = strv_join((char **)controllers, NULL); + if (!s) + return -ENOMEM; + + *ret = s; + return 0; +} + +int cg_mask_from_string(const char *value, CGroupMask *mask) { + assert(mask); + assert(value); + + for (;;) { + _cleanup_free_ char *n = NULL; + CGroupController v; + int r; + + r = extract_first_word(&value, &n, NULL, 0); + if (r < 0) + return r; + if (r == 0) + break; + + v = cgroup_controller_from_string(n); + if (v < 0) + continue; + + *mask |= CGROUP_CONTROLLER_TO_MASK(v); + } + return 0; +} + int cg_mask_supported(CGroupMask *ret) { CGroupMask mask = 0; int r; @@ -2224,7 +2279,6 @@ int cg_mask_supported(CGroupMask *ret) { return r; if (r > 0) { _cleanup_free_ char *root = NULL, *controllers = NULL, *path = NULL; - const char *c; /* In the unified hierarchy we can read the supported * and accessible controllers from a the top-level @@ -2242,23 +2296,9 @@ int cg_mask_supported(CGroupMask *ret) { if (r < 0) return r; - c = controllers; - for (;;) { - _cleanup_free_ char *n = NULL; - CGroupController v; - - r = extract_first_word(&c, &n, NULL, 0); - if (r < 0) - return r; - if (r == 0) - break; - - v = cgroup_controller_from_string(n); - if (v < 0) - continue; - - mask |= CGROUP_CONTROLLER_TO_MASK(v); - } + r = cg_mask_from_string(controllers, &mask); + if (r < 0) + return r; /* Currently, we support the cpu, memory, io and pids * controller in the unified hierarchy, mask diff --git a/src/basic/cgroup-util.h b/src/basic/cgroup-util.h index a522095d95..c16a33723c 100644 --- a/src/basic/cgroup-util.h +++ b/src/basic/cgroup-util.h @@ -235,6 +235,8 @@ int cg_trim_everywhere(CGroupMask supported, const char *path, bool delete_root) int cg_enable_everywhere(CGroupMask supported, CGroupMask mask, const char *p); int cg_mask_supported(CGroupMask *ret); +int cg_mask_from_string(const char *s, CGroupMask *ret); +int cg_mask_to_string(CGroupMask mask, char **ret); int cg_kernel_controllers(Set *controllers); diff --git a/src/core/unit.c b/src/core/unit.c index 01fa0d0d46..1919278301 100644 --- a/src/core/unit.c +++ b/src/core/unit.c @@ -956,9 +956,7 @@ void unit_dump(Unit *u, FILE *f, const char *prefix) { "%s\tPerpetual: %s\n" "%s\tSlice: %s\n" "%s\tCGroup: %s\n" - "%s\tCGroup realized: %s\n" - "%s\tCGroup mask: 0x%x\n" - "%s\tCGroup members mask: 0x%x\n", + "%s\tCGroup realized: %s\n", prefix, u->id, prefix, unit_description(u), prefix, strna(u->instance), @@ -975,9 +973,18 @@ void unit_dump(Unit *u, FILE *f, const char *prefix) { prefix, yes_no(u->perpetual), prefix, strna(unit_slice_name(u)), prefix, strna(u->cgroup_path), - prefix, yes_no(u->cgroup_realized), - prefix, u->cgroup_realized_mask, - prefix, u->cgroup_members_mask); + prefix, yes_no(u->cgroup_realized)); + + if (u->cgroup_realized_mask != 0) { + _cleanup_free_ char *s = NULL; + (void) cg_mask_to_string(u->cgroup_realized_mask, &s); + fprintf(f, "%s\tCGroup mask: %s\n", prefix, strnull(s)); + } + if (u->cgroup_members_mask != 0) { + _cleanup_free_ char *s = NULL; + (void) cg_mask_to_string(u->cgroup_members_mask, &s); + fprintf(f, "%s\tCGroup members mask: %s\n", prefix, strnull(s)); + } SET_FOREACH(t, u->names, i) fprintf(f, "%s\tName: %s\n", prefix, t); @@ -2697,6 +2704,25 @@ bool unit_can_serialize(Unit *u) { return UNIT_VTABLE(u)->serialize && UNIT_VTABLE(u)->deserialize_item; } +static int unit_serialize_cgroup_mask(FILE *f, const char *key, CGroupMask mask) { + _cleanup_free_ char *s = NULL; + int r = 0; + + assert(f); + assert(key); + + if (mask != 0) { + r = cg_mask_to_string(mask, &s); + if (r >= 0) { + fputs(key, f); + fputc('=', f); + fputs(s, f); + fputc('\n', f); + } + } + return r; +} + int unit_serialize(Unit *u, FILE *f, FDSet *fds, bool serialize_jobs) { int r; @@ -2744,6 +2770,8 @@ int unit_serialize(Unit *u, FILE *f, FDSet *fds, bool serialize_jobs) { if (u->cgroup_path) unit_serialize_item(u, f, "cgroup", u->cgroup_path); unit_serialize_item(u, f, "cgroup-realized", yes_no(u->cgroup_realized)); + (void) unit_serialize_cgroup_mask(f, "cgroup-realized-mask", u->cgroup_realized_mask); + (void) unit_serialize_cgroup_mask(f, "cgroup-enabled-mask", u->cgroup_enabled_mask); if (uid_is_valid(u->ref_uid)) unit_serialize_item_format(u, f, "ref-uid", UID_FMT, u->ref_uid); @@ -3001,6 +3029,20 @@ int unit_deserialize(Unit *u, FILE *f, FDSet *fds) { continue; + } else if (streq(l, "cgroup-realized-mask")) { + + r = cg_mask_from_string(v, &u->cgroup_realized_mask); + if (r < 0) + log_unit_debug(u, "Failed to parse cgroup-realized-mask %s, ignoring.", v); + continue; + + } else if (streq(l, "cgroup-enabled-mask")) { + + r = cg_mask_from_string(v, &u->cgroup_enabled_mask); + if (r < 0) + log_unit_debug(u, "Failed to parse cgroup-enabled-mask %s, ignoring.", v); + continue; + } else if (streq(l, "ref-uid")) { uid_t uid;