Blame SOURCES/0754-pid1-fix-collection-of-cycles-of-units-which-referen.patch

17b0f1
From 703cc4991049cdf3ad3506e432cda982b3b3b007 Mon Sep 17 00:00:00 2001
17b0f1
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
17b0f1
Date: Tue, 13 Feb 2018 14:37:11 +0100
17b0f1
Subject: [PATCH] pid1: fix collection of cycles of units which reference one
17b0f1
 another
17b0f1
17b0f1
A .socket will reference a .service unit, by registering a UnitRef with the
17b0f1
.service unit. If this .service unit has the .socket unit listed in Wants or
17b0f1
Sockets or such, a cycle will be created. We would not free this cycle
17b0f1
properly, because we treated any unit with non-empty refs as uncollectable. To
17b0f1
solve this issue, treats refs with UnitRef in u->refs_by_target similarly to
17b0f1
the refs in u->dependencies, and check if the "other" unit is known to be
17b0f1
needed. If it is not needed, do not treat the reference from it as preventing
17b0f1
the unit we are looking at from being freed.
17b0f1
17b0f1
(cherry picked from commit 2641f02e23ac7d5385db7f932aff221a063f245e)
17b0f1
17b0f1
Resolves: #1718953
17b0f1
---
17b0f1
 src/core/manager.c | 14 ++++++++++++++
17b0f1
 src/core/unit.c    |  9 +++++----
17b0f1
 2 files changed, 19 insertions(+), 4 deletions(-)
17b0f1
17b0f1
diff --git a/src/core/manager.c b/src/core/manager.c
17b0f1
index 9dfdd67860..fdbb3c0fd9 100644
17b0f1
--- a/src/core/manager.c
17b0f1
+++ b/src/core/manager.c
17b0f1
@@ -888,6 +888,20 @@ static void unit_gc_sweep(Unit *u, unsigned gc_marker) {
17b0f1
                         is_bad = false;
17b0f1
         }
17b0f1
 
17b0f1
+        if (u->refs_by_target) {
17b0f1
+                const UnitRef *ref;
17b0f1
+
17b0f1
+                LIST_FOREACH(refs_by_target, ref, u->refs_by_target) {
17b0f1
+                        unit_gc_sweep(ref->source, gc_marker);
17b0f1
+
17b0f1
+                        if (ref->source->gc_marker == gc_marker + GC_OFFSET_GOOD)
17b0f1
+                                goto good;
17b0f1
+
17b0f1
+                        if (ref->source->gc_marker != gc_marker + GC_OFFSET_BAD)
17b0f1
+                                is_bad = false;
17b0f1
+                }
17b0f1
+        }
17b0f1
+
17b0f1
         if (is_bad)
17b0f1
                 goto bad;
17b0f1
 
17b0f1
diff --git a/src/core/unit.c b/src/core/unit.c
17b0f1
index 5376ef862f..2204be26d2 100644
17b0f1
--- a/src/core/unit.c
17b0f1
+++ b/src/core/unit.c
17b0f1
@@ -288,7 +288,11 @@ bool unit_may_gc(Unit *u) {
17b0f1
 
17b0f1
         /* Checks whether the unit is ready to be unloaded for garbage collection.
17b0f1
          * Returns true when the unit may be collected, and false if there's some
17b0f1
-         * reason to keep it loaded. */
17b0f1
+         * reason to keep it loaded.
17b0f1
+         *
17b0f1
+         * References from other units are *not* checked here. Instead, this is done
17b0f1
+         * in unit_gc_sweep(), but using markers to properly collect dependency loops.
17b0f1
+         */
17b0f1
 
17b0f1
         if (u->job)
17b0f1
                 return false;
17b0f1
@@ -315,9 +319,6 @@ bool unit_may_gc(Unit *u) {
17b0f1
         if (u->no_gc)
17b0f1
                 return false;
17b0f1
 
17b0f1
-        if (u->refs_by_target)
17b0f1
-                return false;
17b0f1
-
17b0f1
         if (UNIT_VTABLE(u)->may_gc && !UNIT_VTABLE(u)->may_gc(u))
17b0f1
                 return false;
17b0f1