From: Zbigniew Jędrzejewski-Szmek Date: Tue, 13 Feb 2018 13:37:11 +0000 (+0100) Subject: pid1: fix collection of cycles of units which reference one another X-Git-Tag: v238~97^2~6 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=2641f02e23ac7d5385db7f932aff221a063f245e;p=thirdparty%2Fsystemd.git pid1: fix collection of cycles of units which reference one another A .socket will reference a .service unit, by registering a UnitRef with the .service unit. If this .service unit has the .socket unit listed in Wants or Sockets or such, a cycle will be created. We would not free this cycle properly, because we treated any unit with non-empty refs as uncollectable. To solve this issue, treats refs with UnitRef in u->refs_by_target similarly to the refs in u->dependencies, and check if the "other" unit is known to be needed. If it is not needed, do not treat the reference from it as preventing the unit we are looking at from being freed. --- diff --git a/src/core/manager.c b/src/core/manager.c index c36a954e613..f6c88ba1142 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 761ce40f2a4..0330ae51fdd 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;