diff --git a/src/core/manager.c b/src/core/manager.c index c36a954e61..f6c88ba114 100644 --- a/src/core/manager.c +++ b/src/core/manager.c @@ -1074,6 +1074,20 @@ static void unit_gc_sweep(Unit *u, unsigned gc_marker) { is_bad = false; } + if (u->refs_by_target) { + const UnitRef *ref; + + LIST_FOREACH(refs_by_target, ref, u->refs_by_target) { + unit_gc_sweep(ref->source, gc_marker); + + if (ref->source->gc_marker == gc_marker + GC_OFFSET_GOOD) + goto good; + + if (ref->source->gc_marker != gc_marker + GC_OFFSET_BAD) + is_bad = false; + } + } + if (is_bad) goto bad; diff --git a/src/core/unit.c b/src/core/unit.c index 761ce40f2a..0330ae51fd 100644 --- a/src/core/unit.c +++ b/src/core/unit.c @@ -344,7 +344,11 @@ bool unit_may_gc(Unit *u) { /* Checks whether the unit is ready to be unloaded for garbage collection. * Returns true when the unit may be collected, and false if there's some - * reason to keep it loaded. */ + * reason to keep it loaded. + * + * References from other units are *not* checked here. Instead, this is done + * in unit_gc_sweep(), but using markers to properly collect dependency loops. + */ if (u->job) return false; @@ -362,9 +366,6 @@ bool unit_may_gc(Unit *u) { if (u->perpetual) return false; - if (u->refs_by_target) - return false; - if (sd_bus_track_count(u->bus_track) > 0) return false;