|
|
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 |
|