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