d0811f
From 7a481a17ad01c7be526829a835f7da3d6b71577f Mon Sep 17 00:00:00 2001
d0811f
From: Lennart Poettering <lennart@poettering.net>
d0811f
Date: Fri, 11 Sep 2020 19:49:33 +0200
d0811f
Subject: [PATCH 1/3] core: propagate triggered unit in more load states
d0811f
d0811f
In 4c2ef3276735ad9f7fccf33f5bdcbe7d8751e7ec we enabled propagating
d0811f
triggered unit state to the triggering unit for service units in more
d0811f
load states, so that we don't accidentally stop tracking state
d0811f
correctly.
d0811f
d0811f
Do the same for our other triggering unit states: automounts, paths, and
d0811f
timers.
d0811f
d0811f
Also, make this an assertion rather than a simple test. After all it
d0811f
should never happen that we get called for half-loaded units or units of
d0811f
the wrong type. The load routines should already have made this
d0811f
impossible.
d0811f
---
d0811f
 src/core/automount.c   | 4 ++--
d0811f
 src/core/path.c        | 7 +++----
d0811f
 src/core/socket.c      | 9 ++-------
d0811f
 src/core/timer.c       | 4 ++--
d0811f
 src/core/transaction.c | 2 +-
d0811f
 src/core/unit.h        | 4 ++++
d0811f
 6 files changed, 14 insertions(+), 16 deletions(-)
d0811f
d0811f
diff --git a/src/core/automount.c b/src/core/automount.c
d0811f
index 1f05198766..73f0fb8c71 100644
d0811f
--- a/src/core/automount.c
d0811f
+++ b/src/core/automount.c
d0811f
@@ -507,8 +507,8 @@ static void automount_trigger_notify(Unit *u, Unit *other) {
d0811f
         assert(other);
d0811f
 
d0811f
         /* Filter out invocations with bogus state */
d0811f
-        if (other->load_state != UNIT_LOADED || other->type != UNIT_MOUNT)
d0811f
-                return;
d0811f
+        assert(UNIT_IS_LOAD_COMPLETE(other->load_state));
d0811f
+        assert(other->type == UNIT_MOUNT);
d0811f
 
d0811f
         /* Don't propagate state changes from the mount if we are already down */
d0811f
         if (!IN_SET(a->state, AUTOMOUNT_WAITING, AUTOMOUNT_RUNNING))
d0811f
diff --git a/src/core/path.c b/src/core/path.c
d0811f
index 1c3c28e341..8ffec72ede 100644
d0811f
--- a/src/core/path.c
d0811f
+++ b/src/core/path.c
d0811f
@@ -748,11 +748,10 @@ static void path_trigger_notify(Unit *u, Unit *other) {
d0811f
         assert(u);
d0811f
         assert(other);
d0811f
 
d0811f
-        /* Invoked whenever the unit we trigger changes state or gains
d0811f
-         * or loses a job */
d0811f
+        /* Invoked whenever the unit we trigger changes state or gains or loses a job */
d0811f
 
d0811f
-        if (other->load_state != UNIT_LOADED)
d0811f
-                return;
d0811f
+        /* Filter out invocations with bogus state */
d0811f
+        assert(UNIT_IS_LOAD_COMPLETE(other->load_state));
d0811f
 
d0811f
         if (p->state == PATH_RUNNING &&
d0811f
             UNIT_IS_INACTIVE_OR_FAILED(unit_active_state(other))) {
d0811f
diff --git a/src/core/socket.c b/src/core/socket.c
d0811f
index 127195c9fe..ebf5ce3b16 100644
d0811f
--- a/src/core/socket.c
d0811f
+++ b/src/core/socket.c
d0811f
@@ -3274,13 +3274,8 @@ static void socket_trigger_notify(Unit *u, Unit *other) {
d0811f
         assert(other);
d0811f
 
d0811f
         /* Filter out invocations with bogus state */
d0811f
-        if (!IN_SET(other->load_state,
d0811f
-                    UNIT_LOADED,
d0811f
-                    UNIT_NOT_FOUND,
d0811f
-                    UNIT_BAD_SETTING,
d0811f
-                    UNIT_ERROR,
d0811f
-                    UNIT_MASKED) || other->type != UNIT_SERVICE)
d0811f
-                return;
d0811f
+        assert(UNIT_IS_LOAD_COMPLETE(other->load_state));
d0811f
+        assert(other->type == UNIT_SERVICE);
d0811f
 
d0811f
         /* Don't propagate state changes from the service if we are already down */
d0811f
         if (!IN_SET(s->state, SOCKET_RUNNING, SOCKET_LISTENING))
d0811f
diff --git a/src/core/timer.c b/src/core/timer.c
d0811f
index 03a9c14f76..94388f0727 100644
d0811f
--- a/src/core/timer.c
d0811f
+++ b/src/core/timer.c
d0811f
@@ -746,8 +746,8 @@ static void timer_trigger_notify(Unit *u, Unit *other) {
d0811f
         assert(u);
d0811f
         assert(other);
d0811f
 
d0811f
-        if (other->load_state != UNIT_LOADED)
d0811f
-                return;
d0811f
+        /* Filter out invocations with bogus state */
d0811f
+        assert(UNIT_IS_LOAD_COMPLETE(other->load_state));
d0811f
 
d0811f
         /* Reenable all timers that depend on unit state */
d0811f
         LIST_FOREACH(value, v, t->values)
d0811f
diff --git a/src/core/transaction.c b/src/core/transaction.c
d0811f
index 0fa419787e..befac19788 100644
d0811f
--- a/src/core/transaction.c
d0811f
+++ b/src/core/transaction.c
d0811f
@@ -949,7 +949,7 @@ int transaction_add_job_and_dependencies(
d0811f
 
d0811f
         /* Safety check that the unit is a valid state, i.e. not in UNIT_STUB or UNIT_MERGED which should only be set
d0811f
          * temporarily. */
d0811f
-        if (!IN_SET(unit->load_state, UNIT_LOADED, UNIT_ERROR, UNIT_NOT_FOUND, UNIT_BAD_SETTING, UNIT_MASKED))
d0811f
+        if (!UNIT_IS_LOAD_COMPLETE(unit->load_state))
d0811f
                 return sd_bus_error_setf(e, BUS_ERROR_LOAD_FAILED, "Unit %s is not loaded properly.", unit->id);
d0811f
 
d0811f
         if (type != JOB_STOP) {
d0811f
diff --git a/src/core/unit.h b/src/core/unit.h
d0811f
index 4130cd50a9..ae2ce74243 100644
d0811f
--- a/src/core/unit.h
d0811f
+++ b/src/core/unit.h
d0811f
@@ -49,6 +49,10 @@ static inline bool UNIT_IS_INACTIVE_OR_FAILED(UnitActiveState t) {
d0811f
         return IN_SET(t, UNIT_INACTIVE, UNIT_FAILED);
d0811f
 }
d0811f
 
d0811f
+static inline bool UNIT_IS_LOAD_COMPLETE(UnitLoadState t) {
d0811f
+        return t >= 0 && t < _UNIT_LOAD_STATE_MAX && t != UNIT_STUB && t != UNIT_MERGED;
d0811f
+}
d0811f
+
d0811f
 /* Stores the 'reason' a dependency was created as a bit mask, i.e. due to which configuration source it came to be. We
d0811f
  * use this so that we can selectively flush out parts of dependencies again. Note that the same dependency might be
d0811f
  * created as a result of multiple "reasons", hence the bitmask. */
d0811f
-- 
d0811f
2.26.2
d0811f
d0811f
d0811f
From 6b083e21c2bfdba79d43d5d56f02dc795dae9368 Mon Sep 17 00:00:00 2001
d0811f
From: Lennart Poettering <lennart@poettering.net>
d0811f
Date: Fri, 11 Sep 2020 19:57:09 +0200
d0811f
Subject: [PATCH 2/3] core: propagate unit start limit hit state to triggering
d0811f
 path unit
d0811f
d0811f
We already do this for socket and automount units, do it for path units
d0811f
too: if the triggered service keeps hitting the start limit, then fail
d0811f
the triggering unit too, so that we don#t busy loop forever.
d0811f
d0811f
(Note that this leaves only timer units out in the cold for this kind of
d0811f
protection, but it shouldn't matter there, as they are naturally
d0811f
protected against busy loops: they are scheduled by time anyway).
d0811f
d0811f
Fixes: #16669
d0811f
---
d0811f
 src/core/path.c | 15 +++++++++++++++
d0811f
 src/core/path.h |  1 +
d0811f
 2 files changed, 16 insertions(+)
d0811f
d0811f
diff --git a/src/core/path.c b/src/core/path.c
d0811f
index 8ffec72ede..4f4e7100cf 100644
d0811f
--- a/src/core/path.c
d0811f
+++ b/src/core/path.c
d0811f
@@ -753,6 +753,20 @@ static void path_trigger_notify(Unit *u, Unit *other) {
d0811f
         /* Filter out invocations with bogus state */
d0811f
         assert(UNIT_IS_LOAD_COMPLETE(other->load_state));
d0811f
 
d0811f
+        /* Don't propagate state changes from the triggered unit if we are already down */
d0811f
+        if (!IN_SET(p->state, PATH_WAITING, PATH_RUNNING))
d0811f
+                return;
d0811f
+
d0811f
+        /* Propagate start limit hit state */
d0811f
+        if (other->start_limit_hit) {
d0811f
+                path_enter_dead(p, PATH_FAILURE_UNIT_START_LIMIT_HIT);
d0811f
+                return;
d0811f
+        }
d0811f
+
d0811f
+        /* Don't propagate anything if there's still a job queued */
d0811f
+        if (other->job)
d0811f
+                return;
d0811f
+
d0811f
         if (p->state == PATH_RUNNING &&
d0811f
             UNIT_IS_INACTIVE_OR_FAILED(unit_active_state(other))) {
d0811f
                 log_unit_debug(UNIT(p), "Got notified about unit deactivation.");
d0811f
@@ -789,6 +803,7 @@ static const char* const path_result_table[_PATH_RESULT_MAX] = {
d0811f
         [PATH_SUCCESS] = "success",
d0811f
         [PATH_FAILURE_RESOURCES] = "resources",
d0811f
         [PATH_FAILURE_START_LIMIT_HIT] = "start-limit-hit",
d0811f
+        [PATH_FAILURE_UNIT_START_LIMIT_HIT] = "unit-start-limit-hit",
d0811f
 };
d0811f
 
d0811f
 DEFINE_STRING_TABLE_LOOKUP(path_result, PathResult);
d0811f
diff --git a/src/core/path.h b/src/core/path.h
d0811f
index 9e2836535a..4043650fe0 100644
d0811f
--- a/src/core/path.h
d0811f
+++ b/src/core/path.h
d0811f
@@ -45,6 +45,7 @@ typedef enum PathResult {
d0811f
         PATH_SUCCESS,
d0811f
         PATH_FAILURE_RESOURCES,
d0811f
         PATH_FAILURE_START_LIMIT_HIT,
d0811f
+        PATH_FAILURE_UNIT_START_LIMIT_HIT,
d0811f
         _PATH_RESULT_MAX,
d0811f
         _PATH_RESULT_INVALID = -1
d0811f
 } PathResult;
d0811f
-- 
d0811f
2.26.2
d0811f
d0811f
d0811f
From 32c556c612ff38b09fe7d14d1840aceb2d76360d Mon Sep 17 00:00:00 2001
d0811f
From: Lennart Poettering <lennart@poettering.net>
d0811f
Date: Mon, 14 Sep 2020 12:59:38 +0200
d0811f
Subject: [PATCH 3/3] unit-def: drop pointless 0 initialization of first enum
d0811f
 value
d0811f
d0811f
This is implied in C and we generally don't bother with this, so don't
d0811f
bother with this here either.
d0811f
---
d0811f
 src/basic/unit-def.h | 4 ++--
d0811f
 1 file changed, 2 insertions(+), 2 deletions(-)
d0811f
d0811f
diff --git a/src/basic/unit-def.h b/src/basic/unit-def.h
d0811f
index 53419ecd8a..1fab6c78ab 100644
d0811f
--- a/src/basic/unit-def.h
d0811f
+++ b/src/basic/unit-def.h
d0811f
@@ -9,7 +9,7 @@
d0811f
  * when other criteria (cpu weight, nice level) are identical.
d0811f
  * In this case service units have the highest priority. */
d0811f
 typedef enum UnitType {
d0811f
-        UNIT_SERVICE = 0,
d0811f
+        UNIT_SERVICE,
d0811f
         UNIT_MOUNT,
d0811f
         UNIT_SWAP,
d0811f
         UNIT_SOCKET,
d0811f
@@ -25,7 +25,7 @@ typedef enum UnitType {
d0811f
 } UnitType;
d0811f
 
d0811f
 typedef enum UnitLoadState {
d0811f
-        UNIT_STUB = 0,
d0811f
+        UNIT_STUB,
d0811f
         UNIT_LOADED,
d0811f
         UNIT_NOT_FOUND,    /* error condition #1: unit file not found */
d0811f
         UNIT_BAD_SETTING,  /* error condition #2: we couldn't parse some essential unit file setting */
d0811f
-- 
d0811f
2.26.2
d0811f