diff options
author | Luca Boccassi <luca.boccassi@microsoft.com> | 2021-12-18 17:56:05 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-12-18 17:56:05 +0100 |
commit | 5cfe61f2de3d388dd10a9d1e0cf07a844a429209 (patch) | |
tree | c812a5256c07a60340da95d743f6ba6e865a99c3 | |
parent | homed: Use new SD_BUS_METHOD_WITH_ARGS macro (diff) | |
parent | core: Add trigger limit for path units (diff) | |
download | systemd-5cfe61f2de3d388dd10a9d1e0cf07a844a429209.tar.xz systemd-5cfe61f2de3d388dd10a9d1e0cf07a844a429209.zip |
Merge pull request #21808 from DaanDeMeyer/path-trigger-limit
core: Add trigger limit for path units
-rw-r--r-- | src/core/automount.c | 16 | ||||
-rw-r--r-- | src/core/automount.h | 1 | ||||
-rw-r--r-- | src/core/path.c | 26 | ||||
-rw-r--r-- | src/core/path.h | 4 | ||||
-rw-r--r-- | src/core/socket.c | 28 | ||||
-rw-r--r-- | src/core/socket.h | 1 | ||||
-rw-r--r-- | src/core/timer.c | 12 | ||||
-rw-r--r-- | src/core/timer.h | 1 | ||||
-rw-r--r-- | src/core/unit.c | 10 | ||||
-rw-r--r-- | src/core/unit.h | 2 | ||||
-rw-r--r-- | test/units/testsuite-10.service | 2 | ||||
-rw-r--r-- | test/units/testsuite-63.service | 17 |
12 files changed, 51 insertions, 69 deletions
diff --git a/src/core/automount.c b/src/core/automount.c index 70dbbb637d..5adec9e966 100644 --- a/src/core/automount.c +++ b/src/core/automount.c @@ -811,11 +811,6 @@ static void automount_enter_running(Automount *a) { goto fail; } - if (unit_has_failed_condition_or_assert(trigger)) { - automount_enter_dead(a, AUTOMOUNT_FAILURE_MOUNT_CONDITION_FAILED); - return; - } - r = manager_add_job(UNIT(a)->manager, JOB_START, trigger, JOB_REPLACE, NULL, &error, NULL); if (r < 0) { log_unit_warning(UNIT(a), "Failed to queue mount startup job: %s", bus_error_message(&error, r)); @@ -1104,12 +1099,11 @@ static int automount_can_start(Unit *u) { } static const char* const automount_result_table[_AUTOMOUNT_RESULT_MAX] = { - [AUTOMOUNT_SUCCESS] = "success", - [AUTOMOUNT_FAILURE_RESOURCES] = "resources", - [AUTOMOUNT_FAILURE_START_LIMIT_HIT] = "start-limit-hit", - [AUTOMOUNT_FAILURE_MOUNT_START_LIMIT_HIT] = "mount-start-limit-hit", - [AUTOMOUNT_FAILURE_UNMOUNTED] = "unmounted", - [AUTOMOUNT_FAILURE_MOUNT_CONDITION_FAILED] = "mount-condition-failed", + [AUTOMOUNT_SUCCESS] = "success", + [AUTOMOUNT_FAILURE_RESOURCES] = "resources", + [AUTOMOUNT_FAILURE_START_LIMIT_HIT] = "start-limit-hit", + [AUTOMOUNT_FAILURE_MOUNT_START_LIMIT_HIT] = "mount-start-limit-hit", + [AUTOMOUNT_FAILURE_UNMOUNTED] = "unmounted", }; DEFINE_STRING_TABLE_LOOKUP(automount_result, AutomountResult); diff --git a/src/core/automount.h b/src/core/automount.h index 684f2759a6..e413f237ca 100644 --- a/src/core/automount.h +++ b/src/core/automount.h @@ -11,7 +11,6 @@ typedef enum AutomountResult { AUTOMOUNT_FAILURE_UNMOUNTED, AUTOMOUNT_FAILURE_START_LIMIT_HIT, AUTOMOUNT_FAILURE_MOUNT_START_LIMIT_HIT, - AUTOMOUNT_FAILURE_MOUNT_CONDITION_FAILED, _AUTOMOUNT_RESULT_MAX, _AUTOMOUNT_RESULT_INVALID = -EINVAL, } AutomountResult; diff --git a/src/core/path.c b/src/core/path.c index bcd922901b..f89e35a001 100644 --- a/src/core/path.c +++ b/src/core/path.c @@ -265,6 +265,9 @@ static void path_init(Unit *u) { assert(u->load_state == UNIT_STUB); p->directory_mode = 0755; + + p->trigger_limit.interval = 2 * USEC_PER_SEC; + p->trigger_limit.burst = 200; } void path_free_specs(Path *p) { @@ -480,7 +483,7 @@ static void path_enter_dead(Path *p, PathResult f) { p->result = f; unit_log_result(UNIT(p), p->result == PATH_SUCCESS, path_result_to_string(p->result)); - path_set_state(p, p->result == PATH_SUCCESS ? PATH_DEAD : PATH_FAILED); + path_set_state(p, p->result != PATH_SUCCESS ? PATH_FAILED : PATH_DEAD); } static void path_enter_running(Path *p) { @@ -494,6 +497,12 @@ static void path_enter_running(Path *p) { if (unit_stop_pending(UNIT(p))) return; + if (!ratelimit_below(&p->trigger_limit)) { + log_unit_warning(UNIT(p), "Trigger limit hit, refusing further activation."); + path_enter_dead(p, PATH_FAILURE_TRIGGER_LIMIT_HIT); + return; + } + trigger = UNIT_TRIGGER(UNIT(p)); if (!trigger) { log_unit_error(UNIT(p), "Unit to trigger vanished."); @@ -780,11 +789,6 @@ static void path_trigger_notify(Unit *u, Unit *other) { return; } - if (unit_has_failed_condition_or_assert(other)) { - path_enter_dead(p, PATH_FAILURE_UNIT_CONDITION_FAILED); - return; - } - /* Don't propagate anything if there's still a job queued */ if (other->job) return; @@ -837,11 +841,11 @@ static const char* const path_type_table[_PATH_TYPE_MAX] = { DEFINE_STRING_TABLE_LOOKUP(path_type, PathType); static const char* const path_result_table[_PATH_RESULT_MAX] = { - [PATH_SUCCESS] = "success", - [PATH_FAILURE_RESOURCES] = "resources", - [PATH_FAILURE_START_LIMIT_HIT] = "start-limit-hit", - [PATH_FAILURE_UNIT_START_LIMIT_HIT] = "unit-start-limit-hit", - [PATH_FAILURE_UNIT_CONDITION_FAILED] = "unit-condition-failed", + [PATH_SUCCESS] = "success", + [PATH_FAILURE_RESOURCES] = "resources", + [PATH_FAILURE_START_LIMIT_HIT] = "start-limit-hit", + [PATH_FAILURE_UNIT_START_LIMIT_HIT] = "unit-start-limit-hit", + [PATH_FAILURE_TRIGGER_LIMIT_HIT] = "trigger-limit-hit", }; DEFINE_STRING_TABLE_LOOKUP(path_result, PathResult); diff --git a/src/core/path.h b/src/core/path.h index 973cd594a6..d835c24166 100644 --- a/src/core/path.h +++ b/src/core/path.h @@ -46,7 +46,7 @@ typedef enum PathResult { PATH_FAILURE_RESOURCES, PATH_FAILURE_START_LIMIT_HIT, PATH_FAILURE_UNIT_START_LIMIT_HIT, - PATH_FAILURE_UNIT_CONDITION_FAILED, + PATH_FAILURE_TRIGGER_LIMIT_HIT, _PATH_RESULT_MAX, _PATH_RESULT_INVALID = -EINVAL, } PathResult; @@ -62,6 +62,8 @@ struct Path { mode_t directory_mode; PathResult result; + + RateLimit trigger_limit; }; void path_free_specs(Path *p); diff --git a/src/core/socket.c b/src/core/socket.c index 6b5ec9d987..8a5c7fdd0a 100644 --- a/src/core/socket.c +++ b/src/core/socket.c @@ -2336,15 +2336,6 @@ static void socket_enter_running(Socket *s, int cfd_in) { goto refuse; } - if (UNIT_ISSET(s->service) && cfd < 0) { - Unit *service = UNIT_DEREF(s->service); - - if (unit_has_failed_condition_or_assert(service)) { - socket_enter_dead(s, SOCKET_FAILURE_SERVICE_CONDITION_FAILED); - return; - } - } - if (cfd < 0) { bool pending = false; Unit *other; @@ -3452,16 +3443,15 @@ static const char* const socket_exec_command_table[_SOCKET_EXEC_COMMAND_MAX] = { DEFINE_STRING_TABLE_LOOKUP(socket_exec_command, SocketExecCommand); static const char* const socket_result_table[_SOCKET_RESULT_MAX] = { - [SOCKET_SUCCESS] = "success", - [SOCKET_FAILURE_RESOURCES] = "resources", - [SOCKET_FAILURE_TIMEOUT] = "timeout", - [SOCKET_FAILURE_EXIT_CODE] = "exit-code", - [SOCKET_FAILURE_SIGNAL] = "signal", - [SOCKET_FAILURE_CORE_DUMP] = "core-dump", - [SOCKET_FAILURE_START_LIMIT_HIT] = "start-limit-hit", - [SOCKET_FAILURE_TRIGGER_LIMIT_HIT] = "trigger-limit-hit", - [SOCKET_FAILURE_SERVICE_START_LIMIT_HIT] = "service-start-limit-hit", - [SOCKET_FAILURE_SERVICE_CONDITION_FAILED] = "service-condition-failed", + [SOCKET_SUCCESS] = "success", + [SOCKET_FAILURE_RESOURCES] = "resources", + [SOCKET_FAILURE_TIMEOUT] = "timeout", + [SOCKET_FAILURE_EXIT_CODE] = "exit-code", + [SOCKET_FAILURE_SIGNAL] = "signal", + [SOCKET_FAILURE_CORE_DUMP] = "core-dump", + [SOCKET_FAILURE_START_LIMIT_HIT] = "start-limit-hit", + [SOCKET_FAILURE_TRIGGER_LIMIT_HIT] = "trigger-limit-hit", + [SOCKET_FAILURE_SERVICE_START_LIMIT_HIT] = "service-start-limit-hit" }; DEFINE_STRING_TABLE_LOOKUP(socket_result, SocketResult); diff --git a/src/core/socket.h b/src/core/socket.h index 1a50ab5d92..6813bdcf8c 100644 --- a/src/core/socket.h +++ b/src/core/socket.h @@ -38,7 +38,6 @@ typedef enum SocketResult { SOCKET_FAILURE_START_LIMIT_HIT, SOCKET_FAILURE_TRIGGER_LIMIT_HIT, SOCKET_FAILURE_SERVICE_START_LIMIT_HIT, - SOCKET_FAILURE_SERVICE_CONDITION_FAILED, _SOCKET_RESULT_MAX, _SOCKET_RESULT_INVALID = -EINVAL, } SocketResult; diff --git a/src/core/timer.c b/src/core/timer.c index b22168fad5..a13b864741 100644 --- a/src/core/timer.c +++ b/src/core/timer.c @@ -598,11 +598,6 @@ static void timer_enter_running(Timer *t) { return; } - if (unit_has_failed_condition_or_assert(trigger)) { - timer_enter_dead(t, TIMER_FAILURE_UNIT_CONDITION_FAILED); - return; - } - r = manager_add_job(UNIT(t)->manager, JOB_START, trigger, JOB_REPLACE, NULL, &error, NULL); if (r < 0) goto fail; @@ -916,10 +911,9 @@ static const char* const timer_base_table[_TIMER_BASE_MAX] = { DEFINE_STRING_TABLE_LOOKUP(timer_base, TimerBase); static const char* const timer_result_table[_TIMER_RESULT_MAX] = { - [TIMER_SUCCESS] = "success", - [TIMER_FAILURE_RESOURCES] = "resources", - [TIMER_FAILURE_START_LIMIT_HIT] = "start-limit-hit", - [TIMER_FAILURE_UNIT_CONDITION_FAILED] = "unit-condition-failed", + [TIMER_SUCCESS] = "success", + [TIMER_FAILURE_RESOURCES] = "resources", + [TIMER_FAILURE_START_LIMIT_HIT] = "start-limit-hit", }; DEFINE_STRING_TABLE_LOOKUP(timer_result, TimerResult); diff --git a/src/core/timer.h b/src/core/timer.h index 91bf03803f..a51fbf56f3 100644 --- a/src/core/timer.h +++ b/src/core/timer.h @@ -32,7 +32,6 @@ typedef enum TimerResult { TIMER_SUCCESS, TIMER_FAILURE_RESOURCES, TIMER_FAILURE_START_LIMIT_HIT, - TIMER_FAILURE_UNIT_CONDITION_FAILED, _TIMER_RESULT_MAX, _TIMER_RESULT_INVALID = -EINVAL, } TimerResult; diff --git a/src/core/unit.c b/src/core/unit.c index a599e393a8..b1f1f5c82c 100644 --- a/src/core/unit.c +++ b/src/core/unit.c @@ -5866,16 +5866,6 @@ Condition *unit_find_failed_condition(Unit *u) { return failed_trigger && !has_succeeded_trigger ? failed_trigger : NULL; } -bool unit_has_failed_condition_or_assert(Unit *u) { - if (dual_timestamp_is_set(&u->condition_timestamp) && !u->condition_result) - return true; - - if (dual_timestamp_is_set(&u->assert_timestamp) && !u->assert_result) - return true; - - return false; -} - static const char* const collect_mode_table[_COLLECT_MODE_MAX] = { [COLLECT_INACTIVE] = "inactive", [COLLECT_INACTIVE_OR_FAILED] = "inactive-or-failed", diff --git a/src/core/unit.h b/src/core/unit.h index 76701519c2..94f2180951 100644 --- a/src/core/unit.h +++ b/src/core/unit.h @@ -991,8 +991,6 @@ int unit_thaw_vtable_common(Unit *u); Condition *unit_find_failed_condition(Unit *u); -bool unit_has_failed_condition_or_assert(Unit *u); - /* Macros which append UNIT= or USER_UNIT= to the message */ #define log_unit_full_errno_zerook(unit, level, error, ...) \ diff --git a/test/units/testsuite-10.service b/test/units/testsuite-10.service index f33c1b646a..9fcfd673c6 100644 --- a/test/units/testsuite-10.service +++ b/test/units/testsuite-10.service @@ -12,5 +12,5 @@ ExecStart=-nc -w20 -U /run/test.ctl # systemd enough time even on slower machines, to reach the trigger limit. ExecStart=sleep 10 ExecStart=sh -x -c 'test "$(systemctl show test10.socket -P ActiveState)" = failed' -ExecStart=sh -x -c 'test "$(systemctl show test10.socket -P Result)" = service-condition-failed' +ExecStart=sh -x -c 'test "$(systemctl show test10.socket -P Result)" = trigger-limit-hit' ExecStart=sh -x -c 'echo OK >/testok' diff --git a/test/units/testsuite-63.service b/test/units/testsuite-63.service index 616d8a6acc..40422127ff 100644 --- a/test/units/testsuite-63.service +++ b/test/units/testsuite-63.service @@ -5,13 +5,26 @@ Description=TEST-63-ISSUE-17433 [Service] ExecStartPre=rm -f /failed /testok Type=oneshot + +# Test that a path unit continuously triggering a service that fails condition checks eventually fails with +# the trigger-limit-hit error. ExecStart=rm -f /tmp/nonexistent ExecStart=systemctl start test63.path ExecStart=touch /tmp/test63 +# Make sure systemd has sufficient time to hit the trigger limit for test63.path. ExecStart=sleep 2 -# Ensure both the service and the corresponding path unit go inactive due to the failed condition check. ExecStart=sh -x -c 'test "$(systemctl show test63.service -P ActiveState)" = inactive' ExecStart=sh -x -c 'test "$(systemctl show test63.service -P Result)" = success' ExecStart=sh -x -c 'test "$(systemctl show test63.path -P ActiveState)" = failed' -ExecStart=sh -x -c 'test "$(systemctl show test63.path -P Result)" = unit-condition-failed' +ExecStart=sh -x -c 'test "$(systemctl show test63.path -P Result)" = trigger-limit-hit' + +# Test that starting the service manually doesn't affect the path unit. +ExecStart=rm -f /tmp/test63 +ExecStart=systemctl reset-failed +ExecStart=systemctl start test63.path +ExecStart=systemctl start test63.service +ExecStart=sh -x -c 'test "$(systemctl show test63.service -P ActiveState)" = inactive' +ExecStart=sh -x -c 'test "$(systemctl show test63.service -P Result)" = success' +ExecStart=sh -x -c 'test "$(systemctl show test63.path -P ActiveState)" = active' +ExecStart=sh -x -c 'test "$(systemctl show test63.path -P Result)" = success' ExecStart=sh -x -c 'echo OK >/testok' |