core: Fail to start/stop/reload unit if frozen

Previously, unit_{start,stop,reload} would call the low-level cgroup
unfreeze function whenever a unit was started, stopped, or reloaded. It
did so with no error checking. This call would ultimately recurse up the
cgroup tree, and unfreeze all the parent cgroups of the unit, unless an
error occurred (in which case I have no idea what would happen...)

After the freeze/thaw rework in a previous commit, this can no longer
work. If we recursively thaw the parent cgroups of the unit, there may
be sibling units marked as PARENT_FROZEN which will no longer actually
have frozen parents. Fixing this is a lot more complicated than simply
disallowing start/stop/reload on a frozen unit

Fixes https://github.com/systemd/systemd/issues/15849
This commit is contained in:
Adrian Vovk
2024-01-30 11:18:16 -05:00
parent 16b6af6ade
commit 4cb2e6af8d
5 changed files with 33 additions and 30 deletions
+4
View File
@@ -248,6 +248,8 @@ static int check_wait_response(BusWaitForJobs *d, WaitJobsFlags flags, const cha
log_error("Queued job for %s was garbage collected.", d->name);
else if (streq(d->result, "once"))
log_error("Unit %s was started already once and can't be started again.", d->name);
else if (streq(d->result, "frozen"))
log_error("Cannot perform operation on frozen unit %s.", d->name);
else if (endswith(d->name, ".service")) {
/* Job result is unknown. For services, let's also try Result property. */
_cleanup_free_ char *result = NULL;
@@ -276,6 +278,8 @@ static int check_wait_response(BusWaitForJobs *d, WaitJobsFlags flags, const cha
return -EOPNOTSUPP;
else if (streq(d->result, "once"))
return -ESTALE;
else if (streq(d->result, "frozen"))
return -EDEADLK;
return log_debug_errno(SYNTHETIC_ERRNO(ENOMEDIUM),
"Unexpected job result '%s' for unit '%s', assuming server side newer than us.",