diff options
author | Zbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl> | 2022-03-02 13:09:06 +0100 |
---|---|---|
committer | Luca Boccassi <bluca@debian.org> | 2022-03-10 15:51:28 +0100 |
commit | 02de9614d4a541032da3039c2cae918ec852be28 (patch) | |
tree | b599807b46b1fa9f67217ce65519dd0553aa59a8 /src | |
parent | manager/service: when we have multiple candidates to handle, warn (diff) | |
download | systemd-02de9614d4a541032da3039c2cae918ec852be28.tar.xz systemd-02de9614d4a541032da3039c2cae918ec852be28.zip |
manager: prevent cleanup of triggering units before we start the handler
This fixes the following case:
OnFailure= would be spawned correctly, but OnSuccess= would be
spawned without the MONITOR_* metadata, because we'd "collect" the unit
that started successfully. So let's block cleanup while we have a job
running for the handler. The job cannot last infinitely, so at some point
we'll be able to collect both.
Diffstat (limited to 'src')
-rw-r--r-- | src/core/unit.c | 23 |
1 files changed, 19 insertions, 4 deletions
diff --git a/src/core/unit.c b/src/core/unit.c index c9f88c81ef..bd11049c77 100644 --- a/src/core/unit.c +++ b/src/core/unit.c @@ -375,6 +375,20 @@ int unit_set_description(Unit *u, const char *description) { return 0; } +static bool unit_success_failure_handler_has_jobs(Unit *unit) { + Unit *other; + + UNIT_FOREACH_DEPENDENCY(other, unit, UNIT_ATOM_ON_SUCCESS) + if (other->job || other->nop_job) + return true; + + UNIT_FOREACH_DEPENDENCY(other, unit, UNIT_ATOM_ON_FAILURE) + if (other->job || other->nop_job) + return true; + + return false; +} + bool unit_may_gc(Unit *u) { UnitActiveState state; int r; @@ -389,10 +403,7 @@ bool unit_may_gc(Unit *u) { * in unit_gc_sweep(), but using markers to properly collect dependency loops. */ - if (u->job) - return false; - - if (u->nop_job) + if (u->job || u->nop_job) return false; state = unit_active_state(u); @@ -427,6 +438,10 @@ bool unit_may_gc(Unit *u) { assert_not_reached(); } + /* Check if any OnFailure= or on Success= jobs may be pending */ + if (unit_success_failure_handler_has_jobs(u)) + return false; + if (u->cgroup_path) { /* If the unit has a cgroup, then check whether there's anything in it. If so, we should stay * around. Units with active processes should never be collected. */ |