}
static const char *migrate_callback(CGroupMask mask, void *userdata) {
- return unit_get_realized_cgroup_path(userdata, mask);
+ /* If not realized at all, migrate to root ("").
+ * It may happen if we're upgrading from older version that didn't clean up.
+ */
+ return strempty(unit_get_realized_cgroup_path(userdata, mask));
}
char *unit_default_cgroup_path(const Unit *u) {
return 0;
}
-static int unit_create_cgroup(
+static int unit_update_cgroup(
Unit *u,
CGroupMask target_mask,
CGroupMask enable_mask,
ManagerState state) {
- bool created;
+ bool created, is_root_slice;
+ CGroupMask migrate_mask = 0;
int r;
assert(u);
(void) unit_watch_cgroup(u);
(void) unit_watch_cgroup_memory(u);
- /* Preserve enabled controllers in delegated units, adjust others. */
+
+ /* For v2 we preserve enabled controllers in delegated units, adjust others,
+ * for v1 we figure out which controller hierarchies need migration. */
if (created || !u->cgroup_realized || !unit_cgroup_delegate(u)) {
CGroupMask result_mask = 0;
/* Remember what's actually enabled now */
u->cgroup_enabled_mask = result_mask;
+
+ migrate_mask = u->cgroup_realized_mask ^ target_mask;
}
/* Keep track that this is now realized */
u->cgroup_realized = true;
u->cgroup_realized_mask = target_mask;
- if (u->type != UNIT_SLICE && !unit_cgroup_delegate(u)) {
+ /* Migrate processes in controller hierarchies both downwards (enabling) and upwards (disabling).
+ *
+ * Unnecessary controller cgroups are trimmed (after emptied by upward migration).
+ * We perform migration also with whole slices for cases when users don't care about leave
+ * granularity. Since delegated_mask is subset of target mask, we won't trim slice subtree containing
+ * delegated units.
+ */
+ if (cg_all_unified() == 0) {
+ r = cg_migrate_v1_controllers(u->manager->cgroup_supported, migrate_mask, u->cgroup_path, migrate_callback, u);
+ if (r < 0)
+ log_unit_warning_errno(u, r, "Failed to migrate controller cgroups from %s, ignoring: %m", u->cgroup_path);
- /* Then, possibly move things over, but not if
- * subgroups may contain processes, which is the case
- * for slice and delegation units. */
- r = cg_migrate_everywhere(u->manager->cgroup_supported, u->cgroup_path, u->cgroup_path, migrate_callback, u);
+ is_root_slice = unit_has_name(u, SPECIAL_ROOT_SLICE);
+ r = cg_trim_v1_controllers(u->manager->cgroup_supported, ~target_mask, u->cgroup_path, !is_root_slice);
if (r < 0)
- log_unit_warning_errno(u, r, "Failed to migrate cgroup from to %s, ignoring: %m", u->cgroup_path);
+ log_unit_warning_errno(u, r, "Failed to delete controller cgroups %s, ignoring: %m", u->cgroup_path);
}
/* Set attributes */
new_target_mask = u->cgroup_realized_mask | target_mask;
new_enable_mask = u->cgroup_enabled_mask | enable_mask;
- return unit_create_cgroup(u, new_target_mask, new_enable_mask, state);
+ return unit_update_cgroup(u, new_target_mask, new_enable_mask, state);
}
/* Controllers can only be disabled depth-first, from the leaves of the
new_target_mask = m->cgroup_realized_mask & target_mask;
new_enable_mask = m->cgroup_enabled_mask & enable_mask;
- r = unit_create_cgroup(m, new_target_mask, new_enable_mask, state);
+ r = unit_update_cgroup(m, new_target_mask, new_enable_mask, state);
if (r < 0)
return r;
}
}
/* Now actually deal with the cgroup we were trying to realise and set attributes */
- r = unit_create_cgroup(u, target_mask, enable_mask, state);
+ r = unit_update_cgroup(u, target_mask, enable_mask, state);
if (r < 0)
return r;
n = cgroup_controller_to_string(c);
if (FLAGS_SET(mask, bit))
(void) cg_create(n, path);
- else
- (void) cg_trim(n, path, true);
done |= CGROUP_MASK_EXTEND_JOINED(bit);
}
return r;
}
-int cg_migrate_everywhere(CGroupMask supported, const char *from, const char *to, cg_migrate_callback_t to_callback, void *userdata) {
+int cg_migrate_v1_controllers(CGroupMask supported, CGroupMask mask, const char *from, cg_migrate_callback_t to_callback, void *userdata) {
CGroupController c;
CGroupMask done;
int r = 0, q;
- if (!path_equal(from, to)) {
- r = cg_migrate_recursive(SYSTEMD_CGROUP_CONTROLLER, from, SYSTEMD_CGROUP_CONTROLLER, to, CGROUP_REMOVE);
- if (r < 0)
- return r;
- }
-
- q = cg_all_unified();
- if (q < 0)
- return q;
- if (q > 0)
- return r;
+ assert(to_callback);
supported &= CGROUP_MASK_V1;
+ mask = CGROUP_MASK_EXTEND_JOINED(mask);
done = 0;
for (c = 0; c < _CGROUP_CONTROLLER_MAX; c++) {
CGroupMask bit = CGROUP_CONTROLLER_TO_MASK(c);
- const char *p = NULL;
+ const char *to = NULL;
if (!FLAGS_SET(supported, bit))
continue;
if (FLAGS_SET(done, bit))
continue;
- if (to_callback)
- p = to_callback(bit, userdata);
- if (!p)
- p = to;
+ if (!FLAGS_SET(mask, bit))
+ continue;
- (void) cg_migrate_recursive_fallback(SYSTEMD_CGROUP_CONTROLLER, to, cgroup_controller_to_string(c), p, 0);
- done |= CGROUP_MASK_EXTEND_JOINED(bit);
+ to = to_callback(bit, userdata);
+
+ /* Remember first error and try continuing */
+ q = cg_migrate_recursive_fallback(SYSTEMD_CGROUP_CONTROLLER, from, cgroup_controller_to_string(c), to, 0);
+ r = (r < 0) ? r : q;
}
return r;
}
int cg_trim_everywhere(CGroupMask supported, const char *path, bool delete_root) {
- CGroupController c;
- CGroupMask done;
int r, q;
r = cg_trim(SYSTEMD_CGROUP_CONTROLLER, path, delete_root);
if (q > 0)
return r;
+ return cg_trim_v1_controllers(supported, _CGROUP_MASK_ALL, path, delete_root);
+}
+
+int cg_trim_v1_controllers(CGroupMask supported, CGroupMask mask, const char *path, bool delete_root) {
+ CGroupController c;
+ CGroupMask done;
+ int r = 0, q;
+
supported &= CGROUP_MASK_V1;
+ mask = CGROUP_MASK_EXTEND_JOINED(mask);
done = 0;
for (c = 0; c < _CGROUP_CONTROLLER_MAX; c++) {
if (FLAGS_SET(done, bit))
continue;
- (void) cg_trim(cgroup_controller_to_string(c), path, delete_root);
+ if (FLAGS_SET(mask, bit)) {
+ /* Remember first error and try continuing */
+ q = cg_trim(cgroup_controller_to_string(c), path, delete_root);
+ r = (r < 0) ? r : q;
+ }
done |= CGROUP_MASK_EXTEND_JOINED(bit);
}
int cg_create_everywhere(CGroupMask supported, CGroupMask mask, const char *path);
int cg_attach_everywhere(CGroupMask supported, const char *path, pid_t pid, cg_migrate_callback_t callback, void *userdata);
int cg_attach_many_everywhere(CGroupMask supported, const char *path, Set* pids, cg_migrate_callback_t callback, void *userdata);
-int cg_migrate_everywhere(CGroupMask supported, const char *from, const char *to, cg_migrate_callback_t callback, void *userdata);
+int cg_migrate_v1_controllers(CGroupMask supported, CGroupMask mask, const char *from, cg_migrate_callback_t to_callback, void *userdata);
int cg_trim_everywhere(CGroupMask supported, const char *path, bool delete_root);
+int cg_trim_v1_controllers(CGroupMask supported, CGroupMask mask, const char *path, bool delete_root);
int cg_enable_everywhere(CGroupMask supported, CGroupMask mask, const char *p, CGroupMask *ret_result_mask);