From: Lennart Poettering Date: Tue, 12 Nov 2024 11:03:05 +0000 (+0100) Subject: cgroup: when we fail to clean up a cgroup, let's ask PID 1 for help X-Git-Tag: v258-rc1~1665^2~1 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=51a70c887570121588cbdf7cdf97ac4cec4f5bda;p=thirdparty%2Fsystemd.git cgroup: when we fail to clean up a cgroup, let's ask PID 1 for help --- diff --git a/src/core/cgroup.c b/src/core/cgroup.c index 345dc5cfbbd..e959b307c67 100644 --- a/src/core/cgroup.c +++ b/src/core/cgroup.c @@ -3610,6 +3610,51 @@ static bool unit_maybe_release_cgroup(Unit *u) { return false; } +static int unit_prune_cgroup_via_bus(Unit *u) { + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + int r; + + assert(u); + assert(u->manager); + + if (MANAGER_IS_SYSTEM(u->manager)) + return -EINVAL; + + if (!u->manager->system_bus) + return -EIO; + + CGroupRuntime *crt = unit_get_cgroup_runtime(u); + if (!crt || !crt->cgroup_path) + return -EOWNERDEAD; + + /* Determine this unit's cgroup path relative to our cgroup root */ + const char *pp = path_startswith(crt->cgroup_path, u->manager->cgroup_root); + if (!pp) + return -EINVAL; + + _cleanup_free_ char *absolute = NULL; + if (!path_is_absolute(pp)) { /* RemoveSubgroupFromUnit() wants an absolute path */ + absolute = strjoin("/", pp); + if (!absolute) + return -ENOMEM; + + pp = absolute; + } + + r = bus_call_method(u->manager->system_bus, + bus_systemd_mgr, + "RemoveSubgroupFromUnit", + &error, NULL, + "sst", + NULL /* empty unit name means client's unit, i.e. us */, + pp, + (uint64_t) 0); + if (r < 0) + return log_unit_debug_errno(u, r, "Failed to trim cgroup via the bus: %s", bus_error_message(&error, r)); + + return 0; +} + void unit_prune_cgroup(Unit *u) { bool is_root_slice; int r; @@ -3641,13 +3686,21 @@ void unit_prune_cgroup(Unit *u) { is_root_slice = unit_has_name(u, SPECIAL_ROOT_SLICE); r = cg_trim_everywhere(u->manager->cgroup_supported, crt->cgroup_path, !is_root_slice); - if (r < 0) - /* One reason we could have failed here is, that the cgroup still contains a process. - * However, if the cgroup becomes removable at a later time, it might be removed when - * the containing slice is stopped. So even if we failed now, this unit shouldn't assume - * that the cgroup is still realized the next time it is started. Do not return early - * on error, continue cleanup. */ - log_unit_full_errno(u, r == -EBUSY ? LOG_DEBUG : LOG_WARNING, r, "Failed to destroy cgroup %s, ignoring: %m", empty_to_root(crt->cgroup_path)); + if (r < 0) { + int k = unit_prune_cgroup_via_bus(u); + + if (k >= 0) + log_unit_debug_errno(u, r, "Failed to destroy cgroup %s on our own (%m), but worked when talking to PID 1.", empty_to_root(crt->cgroup_path)); + else { + /* One reason we could have failed here is, that the cgroup still contains a process. + * However, if the cgroup becomes removable at a later time, it might be removed when + * the containing slice is stopped. So even if we failed now, this unit shouldn't + * assume that the cgroup is still realized the next time it is started. Do not + * return early on error, continue cleanup. */ + log_unit_full_errno(u, r == -EBUSY ? LOG_DEBUG : LOG_WARNING, r, + "Failed to destroy cgroup %s, ignoring: %m", empty_to_root(crt->cgroup_path)); + } + } if (is_root_slice) return;