return c->delegate;
}
+void unit_cgroup_disable_all_controllers(Unit *u) {
+ int r;
+
+ assert(u);
+
+ CGroupRuntime *crt = unit_get_cgroup_runtime(u);
+ if (!crt || !crt->cgroup_path)
+ return;
+
+ if (!unit_cgroup_delegate(u))
+ return;
+
+ /* For delegated units, the previous payload may have enabled controllers (e.g. "pids") in
+ * cgroup.subtree_control. These persist after the service stops and turn the cgroup into an
+ * "internal node", causing clone3(CLONE_INTO_CGROUP) to fail with EBUSY. Clear them now, right
+ * before the new start, so that resource control is preserved for lingering processes as long as
+ * possible. Ignore errors — if sub-cgroups still have live processes the write will fail, but so
+ * will the upcoming spawn. */
+ r = cg_enable(u->manager->cgroup_supported, /* mask= */ 0, crt->cgroup_path, &crt->cgroup_enabled_mask);
+ if (r < 0)
+ log_unit_debug_errno(u, r, "Failed to disable controllers on cgroup %s, ignoring: %m", empty_to_root(crt->cgroup_path));
+}
+
void manager_invalidate_startup_units(Manager *m) {
Unit *u;
bool unit_cgroup_delegate(Unit *u);
+void unit_cgroup_disable_all_controllers(Unit *u);
+
int unit_get_cpuset(Unit *u, CPUSet *cpus, const char *name);
int unit_cgroup_freezer_action(Unit *u, FreezerAction action);
#include "bus-common-errors.h"
#include "bus-error.h"
#include "bus-util.h"
+#include "cgroup.h"
#include "chase.h"
#include "dbus-service.h"
#include "dbus-unit.h"
exec_status_reset(&s->main_exec_status);
CGroupRuntime *crt = unit_get_cgroup_runtime(u);
- if (crt)
+ if (crt) {
+ unit_cgroup_disable_all_controllers(u);
crt->reset_accounting = true;
+ }
service_enter_condition(s);
return 1;
goto fail;
}
+ unit_cgroup_disable_all_controllers(u);
r = unit_fork_and_watch_rm_rf(u, l, &s->control_pid);
if (r < 0) {
log_unit_warning_errno(u, r, "Failed to spawn cleaning task: %m");