b7dd4d
From 2820f1706275acd787c72d9a57892200566f0bbe Mon Sep 17 00:00:00 2001
ff479f
From: Daan De Meyer <daan.j.demeyer@gmail.com>
ff479f
Date: Mon, 18 Oct 2021 14:17:02 +0200
ff479f
Subject: [PATCH] core: Propagate condition failed state to triggering units.
ff479f
ff479f
Alternative to https://github.com/systemd/systemd/pull/20531.
ff479f
ff479f
Whenever a service triggered by another unit fails condition checks,
ff479f
stop the triggering unit to prevent systemd busy looping trying to
ff479f
start the triggered unit.
ff479f
ff479f
(cherry picked from commit 12ab94a1e4961a39c32efb60b71866ab588d3ea2)
ff479f
b7dd4d
Resolves: #2065322
ff479f
---
ff479f
 src/core/automount.c | 14 ++++++++++----
ff479f
 src/core/automount.h |  1 +
ff479f
 src/core/path.c      | 16 +++++++++++-----
ff479f
 src/core/path.h      |  1 +
ff479f
 src/core/socket.c    | 28 +++++++++++++++++++---------
ff479f
 src/core/socket.h    |  1 +
ff479f
 src/core/timer.c     | 12 +++++++++---
ff479f
 src/core/timer.h     |  1 +
ff479f
 src/core/unit.c      | 10 ++++++++++
ff479f
 src/core/unit.h      |  2 ++
ff479f
 10 files changed, 65 insertions(+), 21 deletions(-)
ff479f
ff479f
diff --git a/src/core/automount.c b/src/core/automount.c
ff479f
index c1c513d4a5..bac3b2fab7 100644
ff479f
--- a/src/core/automount.c
ff479f
+++ b/src/core/automount.c
ff479f
@@ -776,6 +776,11 @@ static void automount_enter_running(Automount *a) {
ff479f
                 goto fail;
ff479f
         }
ff479f
 
ff479f
+        if (unit_has_failed_condition_or_assert(trigger)) {
ff479f
+                automount_enter_dead(a, AUTOMOUNT_FAILURE_MOUNT_CONDITION_FAILED);
ff479f
+                return;
ff479f
+        }
ff479f
+
ff479f
         r = manager_add_job(UNIT(a)->manager, JOB_START, trigger, JOB_REPLACE, NULL, &error, NULL);
ff479f
         if (r < 0) {
ff479f
                 log_unit_warning(UNIT(a), "Failed to queue mount startup job: %s", bus_error_message(&error, r));
ff479f
@@ -1087,10 +1092,11 @@ static int automount_can_start(Unit *u) {
ff479f
 }
ff479f
 
ff479f
 static const char* const automount_result_table[_AUTOMOUNT_RESULT_MAX] = {
ff479f
-        [AUTOMOUNT_SUCCESS] = "success",
ff479f
-        [AUTOMOUNT_FAILURE_RESOURCES] = "resources",
ff479f
-        [AUTOMOUNT_FAILURE_START_LIMIT_HIT] = "start-limit-hit",
ff479f
-        [AUTOMOUNT_FAILURE_MOUNT_START_LIMIT_HIT] = "mount-start-limit-hit",
ff479f
+        [AUTOMOUNT_SUCCESS]                        = "success",
ff479f
+        [AUTOMOUNT_FAILURE_RESOURCES]              = "resources",
ff479f
+        [AUTOMOUNT_FAILURE_START_LIMIT_HIT]        = "start-limit-hit",
ff479f
+        [AUTOMOUNT_FAILURE_MOUNT_START_LIMIT_HIT]  = "mount-start-limit-hit",
ff479f
+        [AUTOMOUNT_FAILURE_MOUNT_CONDITION_FAILED] = "mount-condition-failed",
ff479f
 };
ff479f
 
ff479f
 DEFINE_STRING_TABLE_LOOKUP(automount_result, AutomountResult);
ff479f
diff --git a/src/core/automount.h b/src/core/automount.h
ff479f
index 21dd1c0774..a7417d195c 100644
ff479f
--- a/src/core/automount.h
ff479f
+++ b/src/core/automount.h
ff479f
@@ -10,6 +10,7 @@ typedef enum AutomountResult {
ff479f
         AUTOMOUNT_FAILURE_RESOURCES,
ff479f
         AUTOMOUNT_FAILURE_START_LIMIT_HIT,
ff479f
         AUTOMOUNT_FAILURE_MOUNT_START_LIMIT_HIT,
ff479f
+        AUTOMOUNT_FAILURE_MOUNT_CONDITION_FAILED,
ff479f
         _AUTOMOUNT_RESULT_MAX,
ff479f
         _AUTOMOUNT_RESULT_INVALID = -1
ff479f
 } AutomountResult;
ff479f
diff --git a/src/core/path.c b/src/core/path.c
ff479f
index c2facf0b16..bf7e1bf3c2 100644
ff479f
--- a/src/core/path.c
ff479f
+++ b/src/core/path.c
ff479f
@@ -453,7 +453,7 @@ static void path_enter_dead(Path *p, PathResult f) {
ff479f
         else
ff479f
                 unit_log_failure(UNIT(p), path_result_to_string(p->result));
ff479f
 
ff479f
-        path_set_state(p, p->result != PATH_SUCCESS ? PATH_FAILED : PATH_DEAD);
ff479f
+        path_set_state(p, p->result == PATH_SUCCESS ? PATH_DEAD : PATH_FAILED);
ff479f
 }
ff479f
 
ff479f
 static void path_enter_running(Path *p) {
ff479f
@@ -711,6 +711,11 @@ static void path_trigger_notify(Unit *u, Unit *other) {
ff479f
                 return;
ff479f
         }
ff479f
 
ff479f
+        if (unit_has_failed_condition_or_assert(other)) {
ff479f
+                path_enter_dead(p, PATH_FAILURE_UNIT_CONDITION_FAILED);
ff479f
+                return;
ff479f
+        }
ff479f
+
ff479f
         /* Don't propagate anything if there's still a job queued */
ff479f
         if (other->job)
ff479f
                 return;
ff479f
@@ -763,10 +768,11 @@ static const char* const path_type_table[_PATH_TYPE_MAX] = {
ff479f
 DEFINE_STRING_TABLE_LOOKUP(path_type, PathType);
ff479f
 
ff479f
 static const char* const path_result_table[_PATH_RESULT_MAX] = {
ff479f
-        [PATH_SUCCESS] = "success",
ff479f
-        [PATH_FAILURE_RESOURCES] = "resources",
ff479f
-        [PATH_FAILURE_START_LIMIT_HIT] = "start-limit-hit",
ff479f
-        [PATH_FAILURE_UNIT_START_LIMIT_HIT] = "unit-start-limit-hit",
ff479f
+        [PATH_SUCCESS]                       = "success",
ff479f
+        [PATH_FAILURE_RESOURCES]             = "resources",
ff479f
+        [PATH_FAILURE_START_LIMIT_HIT]       = "start-limit-hit",
ff479f
+        [PATH_FAILURE_UNIT_START_LIMIT_HIT]  = "unit-start-limit-hit",
ff479f
+        [PATH_FAILURE_UNIT_CONDITION_FAILED] = "unit-condition-failed",
ff479f
 };
ff479f
 
ff479f
 DEFINE_STRING_TABLE_LOOKUP(path_result, PathResult);
ff479f
diff --git a/src/core/path.h b/src/core/path.h
ff479f
index 8a69f06c13..0ad6bd12c6 100644
ff479f
--- a/src/core/path.h
ff479f
+++ b/src/core/path.h
ff479f
@@ -46,6 +46,7 @@ typedef enum PathResult {
ff479f
         PATH_FAILURE_RESOURCES,
ff479f
         PATH_FAILURE_START_LIMIT_HIT,
ff479f
         PATH_FAILURE_UNIT_START_LIMIT_HIT,
ff479f
+        PATH_FAILURE_UNIT_CONDITION_FAILED,
ff479f
         _PATH_RESULT_MAX,
ff479f
         _PATH_RESULT_INVALID = -1
ff479f
 } PathResult;
ff479f
diff --git a/src/core/socket.c b/src/core/socket.c
ff479f
index 74c1cc70cb..6f9a0f7575 100644
ff479f
--- a/src/core/socket.c
ff479f
+++ b/src/core/socket.c
ff479f
@@ -2272,6 +2272,15 @@ static void socket_enter_running(Socket *s, int cfd) {
ff479f
                 goto refuse;
ff479f
         }
ff479f
 
ff479f
+        if (UNIT_ISSET(s->service) && cfd < 0) {
ff479f
+                Unit *service = UNIT_DEREF(s->service);
ff479f
+
ff479f
+                if (unit_has_failed_condition_or_assert(service)) {
ff479f
+                        socket_enter_dead(s, SOCKET_FAILURE_SERVICE_CONDITION_FAILED);
ff479f
+                        return;
ff479f
+                }
ff479f
+        }
ff479f
+
ff479f
         if (cfd < 0) {
ff479f
                 bool pending = false;
ff479f
                 Unit *other;
ff479f
@@ -3287,15 +3296,16 @@ static const char* const socket_exec_command_table[_SOCKET_EXEC_COMMAND_MAX] = {
ff479f
 DEFINE_STRING_TABLE_LOOKUP(socket_exec_command, SocketExecCommand);
ff479f
 
ff479f
 static const char* const socket_result_table[_SOCKET_RESULT_MAX] = {
ff479f
-        [SOCKET_SUCCESS] = "success",
ff479f
-        [SOCKET_FAILURE_RESOURCES] = "resources",
ff479f
-        [SOCKET_FAILURE_TIMEOUT] = "timeout",
ff479f
-        [SOCKET_FAILURE_EXIT_CODE] = "exit-code",
ff479f
-        [SOCKET_FAILURE_SIGNAL] = "signal",
ff479f
-        [SOCKET_FAILURE_CORE_DUMP] = "core-dump",
ff479f
-        [SOCKET_FAILURE_START_LIMIT_HIT] = "start-limit-hit",
ff479f
-        [SOCKET_FAILURE_TRIGGER_LIMIT_HIT] = "trigger-limit-hit",
ff479f
-        [SOCKET_FAILURE_SERVICE_START_LIMIT_HIT] = "service-start-limit-hit"
ff479f
+        [SOCKET_SUCCESS]                          = "success",
ff479f
+        [SOCKET_FAILURE_RESOURCES]                = "resources",
ff479f
+        [SOCKET_FAILURE_TIMEOUT]                  = "timeout",
ff479f
+        [SOCKET_FAILURE_EXIT_CODE]                = "exit-code",
ff479f
+        [SOCKET_FAILURE_SIGNAL]                   = "signal",
ff479f
+        [SOCKET_FAILURE_CORE_DUMP]                = "core-dump",
ff479f
+        [SOCKET_FAILURE_START_LIMIT_HIT]          = "start-limit-hit",
ff479f
+        [SOCKET_FAILURE_TRIGGER_LIMIT_HIT]        = "trigger-limit-hit",
ff479f
+        [SOCKET_FAILURE_SERVICE_START_LIMIT_HIT]  = "service-start-limit-hit",
ff479f
+        [SOCKET_FAILURE_SERVICE_CONDITION_FAILED] = "service-condition-failed",
ff479f
 };
ff479f
 
ff479f
 DEFINE_STRING_TABLE_LOOKUP(socket_result, SocketResult);
ff479f
diff --git a/src/core/socket.h b/src/core/socket.h
ff479f
index 2409dbf2a0..b171b94316 100644
ff479f
--- a/src/core/socket.h
ff479f
+++ b/src/core/socket.h
ff479f
@@ -39,6 +39,7 @@ typedef enum SocketResult {
ff479f
         SOCKET_FAILURE_START_LIMIT_HIT,
ff479f
         SOCKET_FAILURE_TRIGGER_LIMIT_HIT,
ff479f
         SOCKET_FAILURE_SERVICE_START_LIMIT_HIT,
ff479f
+        SOCKET_FAILURE_SERVICE_CONDITION_FAILED,
ff479f
         _SOCKET_RESULT_MAX,
ff479f
         _SOCKET_RESULT_INVALID = -1
ff479f
 } SocketResult;
ff479f
diff --git a/src/core/timer.c b/src/core/timer.c
ff479f
index 990f05fee4..3c8d89771d 100644
ff479f
--- a/src/core/timer.c
ff479f
+++ b/src/core/timer.c
ff479f
@@ -567,6 +567,11 @@ static void timer_enter_running(Timer *t) {
ff479f
                 return;
ff479f
         }
ff479f
 
ff479f
+        if (unit_has_failed_condition_or_assert(trigger)) {
ff479f
+                timer_enter_dead(t, TIMER_FAILURE_UNIT_CONDITION_FAILED);
ff479f
+                return;
ff479f
+        }
ff479f
+
ff479f
         r = manager_add_job(UNIT(t)->manager, JOB_START, trigger, JOB_REPLACE, NULL, &error, NULL);
ff479f
         if (r < 0)
ff479f
                 goto fail;
ff479f
@@ -850,9 +855,10 @@ static const char* const timer_base_table[_TIMER_BASE_MAX] = {
ff479f
 DEFINE_STRING_TABLE_LOOKUP(timer_base, TimerBase);
ff479f
 
ff479f
 static const char* const timer_result_table[_TIMER_RESULT_MAX] = {
ff479f
-        [TIMER_SUCCESS] = "success",
ff479f
-        [TIMER_FAILURE_RESOURCES] = "resources",
ff479f
-        [TIMER_FAILURE_START_LIMIT_HIT] = "start-limit-hit",
ff479f
+        [TIMER_SUCCESS]                       = "success",
ff479f
+        [TIMER_FAILURE_RESOURCES]             = "resources",
ff479f
+        [TIMER_FAILURE_START_LIMIT_HIT]       = "start-limit-hit",
ff479f
+        [TIMER_FAILURE_UNIT_CONDITION_FAILED] = "unit-condition-failed",
ff479f
 };
ff479f
 
ff479f
 DEFINE_STRING_TABLE_LOOKUP(timer_result, TimerResult);
ff479f
diff --git a/src/core/timer.h b/src/core/timer.h
ff479f
index 833aadb0b8..d23e19d622 100644
ff479f
--- a/src/core/timer.h
ff479f
+++ b/src/core/timer.h
ff479f
@@ -32,6 +32,7 @@ typedef enum TimerResult {
ff479f
         TIMER_SUCCESS,
ff479f
         TIMER_FAILURE_RESOURCES,
ff479f
         TIMER_FAILURE_START_LIMIT_HIT,
ff479f
+        TIMER_FAILURE_UNIT_CONDITION_FAILED,
ff479f
         _TIMER_RESULT_MAX,
ff479f
         _TIMER_RESULT_INVALID = -1
ff479f
 } TimerResult;
ff479f
diff --git a/src/core/unit.c b/src/core/unit.c
ff479f
index b825e2418c..c00d30e837 100644
ff479f
--- a/src/core/unit.c
ff479f
+++ b/src/core/unit.c
ff479f
@@ -5657,6 +5657,16 @@ int unit_thaw_vtable_common(Unit *u) {
ff479f
         return unit_cgroup_freezer_action(u, FREEZER_THAW);
ff479f
 }
ff479f
 
ff479f
+bool unit_has_failed_condition_or_assert(Unit *u) {
ff479f
+        if (dual_timestamp_is_set(&u->condition_timestamp) && !u->condition_result)
ff479f
+                return true;
ff479f
+
ff479f
+        if (dual_timestamp_is_set(&u->assert_timestamp) && !u->assert_result)
ff479f
+                return true;
ff479f
+
ff479f
+        return false;
ff479f
+}
ff479f
+
ff479f
 static const char* const collect_mode_table[_COLLECT_MODE_MAX] = {
ff479f
         [COLLECT_INACTIVE] = "inactive",
ff479f
         [COLLECT_INACTIVE_OR_FAILED] = "inactive-or-failed",
ff479f
diff --git a/src/core/unit.h b/src/core/unit.h
ff479f
index b8b914711f..a924bd2e83 100644
ff479f
--- a/src/core/unit.h
ff479f
+++ b/src/core/unit.h
ff479f
@@ -847,6 +847,8 @@ void unit_thawed(Unit *u);
ff479f
 int unit_freeze_vtable_common(Unit *u);
ff479f
 int unit_thaw_vtable_common(Unit *u);
ff479f
 
ff479f
+bool unit_has_failed_condition_or_assert(Unit *u);
ff479f
+
ff479f
 /* Macros which append UNIT= or USER_UNIT= to the message */
ff479f
 
ff479f
 #define log_unit_full(unit, level, error, ...)                          \