|
|
eb8b6e |
From 6f3b6308bb5705fdcadec3f4cac105211bc0a3e2 Mon Sep 17 00:00:00 2001
|
|
|
eb8b6e |
From: Daan De Meyer <daan.j.demeyer@gmail.com>
|
|
|
eb8b6e |
Date: Tue, 24 Aug 2021 16:46:47 +0100
|
|
|
eb8b6e |
Subject: [PATCH] core: Check unit start rate limiting earlier
|
|
|
eb8b6e |
|
|
|
eb8b6e |
Fixes #17433. Currently, if any of the validations we do before we
|
|
|
eb8b6e |
check start rate limiting fail, we can still enter a busy loop as
|
|
|
eb8b6e |
no rate limiting gets applied. A common occurence of this scenario
|
|
|
eb8b6e |
is path units triggering a service that fails a condition check.
|
|
|
eb8b6e |
|
|
|
eb8b6e |
To fix the issue, we simply move up start rate limiting checks to
|
|
|
eb8b6e |
be the first thing we do when starting a unit. To achieve this,
|
|
|
eb8b6e |
we add a new method to the unit vtable and implement it for the
|
|
|
eb8b6e |
relevant unit types so that we can do the start rate limit checks
|
|
|
eb8b6e |
earlier on.
|
|
|
eb8b6e |
|
|
|
eb8b6e |
(cherry picked from commit 9727f2427ff6b2e1f4ab927cc57ad8e888f04e95)
|
|
|
eb8b6e |
|
|
|
eb8b6e |
Related: #2037395
|
|
|
eb8b6e |
|
|
|
eb8b6e |
[msekleta: I've deleted part of the original commit that adds test for
|
|
|
eb8b6e |
issue #17433. This was necessary because upstream commit assumes newer
|
|
|
eb8b6e |
organization of the test code which we don't have in RHEL-8 tree. As
|
|
|
eb8b6e |
a consequence we must add explicit test for this in the internal
|
|
|
eb8b6e |
test-suite.]
|
|
|
eb8b6e |
---
|
|
|
eb8b6e |
src/core/automount.c | 23 +++++++++++++++++------
|
|
|
eb8b6e |
src/core/mount.c | 23 +++++++++++++++++------
|
|
|
eb8b6e |
src/core/path.c | 23 +++++++++++++++++------
|
|
|
eb8b6e |
src/core/service.c | 25 ++++++++++++++++++-------
|
|
|
eb8b6e |
src/core/socket.c | 23 +++++++++++++++++------
|
|
|
eb8b6e |
src/core/swap.c | 23 +++++++++++++++++------
|
|
|
eb8b6e |
src/core/timer.c | 22 ++++++++++++++++------
|
|
|
eb8b6e |
src/core/unit.c | 14 ++++++++++----
|
|
|
eb8b6e |
src/core/unit.h | 4 ++++
|
|
|
eb8b6e |
9 files changed, 133 insertions(+), 47 deletions(-)
|
|
|
eb8b6e |
|
|
|
eb8b6e |
diff --git a/src/core/automount.c b/src/core/automount.c
|
|
|
eb8b6e |
index 2bc160cb07..5e16adabb5 100644
|
|
|
eb8b6e |
--- a/src/core/automount.c
|
|
|
eb8b6e |
+++ b/src/core/automount.c
|
|
|
eb8b6e |
@@ -808,12 +808,6 @@ static int automount_start(Unit *u) {
|
|
|
eb8b6e |
return -ENOENT;
|
|
|
eb8b6e |
}
|
|
|
eb8b6e |
|
|
|
eb8b6e |
- r = unit_test_start_limit(u);
|
|
|
eb8b6e |
- if (r < 0) {
|
|
|
eb8b6e |
- automount_enter_dead(a, AUTOMOUNT_FAILURE_START_LIMIT_HIT);
|
|
|
eb8b6e |
- return r;
|
|
|
eb8b6e |
- }
|
|
|
eb8b6e |
-
|
|
|
eb8b6e |
r = unit_acquire_invocation_id(u);
|
|
|
eb8b6e |
if (r < 0)
|
|
|
eb8b6e |
return r;
|
|
|
eb8b6e |
@@ -1077,6 +1071,21 @@ static bool automount_supported(void) {
|
|
|
eb8b6e |
return supported;
|
|
|
eb8b6e |
}
|
|
|
eb8b6e |
|
|
|
eb8b6e |
+static int automount_test_start_limit(Unit *u) {
|
|
|
eb8b6e |
+ Automount *a = AUTOMOUNT(u);
|
|
|
eb8b6e |
+ int r;
|
|
|
eb8b6e |
+
|
|
|
eb8b6e |
+ assert(a);
|
|
|
eb8b6e |
+
|
|
|
eb8b6e |
+ r = unit_test_start_limit(u);
|
|
|
eb8b6e |
+ if (r < 0) {
|
|
|
eb8b6e |
+ automount_enter_dead(a, AUTOMOUNT_FAILURE_START_LIMIT_HIT);
|
|
|
eb8b6e |
+ return r;
|
|
|
eb8b6e |
+ }
|
|
|
eb8b6e |
+
|
|
|
eb8b6e |
+ return 0;
|
|
|
eb8b6e |
+}
|
|
|
eb8b6e |
+
|
|
|
eb8b6e |
static const char* const automount_result_table[_AUTOMOUNT_RESULT_MAX] = {
|
|
|
eb8b6e |
[AUTOMOUNT_SUCCESS] = "success",
|
|
|
eb8b6e |
[AUTOMOUNT_FAILURE_RESOURCES] = "resources",
|
|
|
eb8b6e |
@@ -1135,4 +1144,6 @@ const UnitVTable automount_vtable = {
|
|
|
eb8b6e |
[JOB_FAILED] = "Failed to unset automount %s.",
|
|
|
eb8b6e |
},
|
|
|
eb8b6e |
},
|
|
|
eb8b6e |
+
|
|
|
eb8b6e |
+ .test_start_limit = automount_test_start_limit,
|
|
|
eb8b6e |
};
|
|
|
eb8b6e |
diff --git a/src/core/mount.c b/src/core/mount.c
|
|
|
eb8b6e |
index 4cb49d845d..619f64d5b7 100644
|
|
|
eb8b6e |
--- a/src/core/mount.c
|
|
|
eb8b6e |
+++ b/src/core/mount.c
|
|
|
eb8b6e |
@@ -1065,12 +1065,6 @@ static int mount_start(Unit *u) {
|
|
|
eb8b6e |
|
|
|
eb8b6e |
assert(IN_SET(m->state, MOUNT_DEAD, MOUNT_FAILED));
|
|
|
eb8b6e |
|
|
|
eb8b6e |
- r = unit_test_start_limit(u);
|
|
|
eb8b6e |
- if (r < 0) {
|
|
|
eb8b6e |
- mount_enter_dead(m, MOUNT_FAILURE_START_LIMIT_HIT);
|
|
|
eb8b6e |
- return r;
|
|
|
eb8b6e |
- }
|
|
|
eb8b6e |
-
|
|
|
eb8b6e |
r = unit_acquire_invocation_id(u);
|
|
|
eb8b6e |
if (r < 0)
|
|
|
eb8b6e |
return r;
|
|
|
eb8b6e |
@@ -1953,6 +1947,21 @@ static int mount_control_pid(Unit *u) {
|
|
|
eb8b6e |
return m->control_pid;
|
|
|
eb8b6e |
}
|
|
|
eb8b6e |
|
|
|
eb8b6e |
+static int mount_test_start_limit(Unit *u) {
|
|
|
eb8b6e |
+ Mount *m = MOUNT(u);
|
|
|
eb8b6e |
+ int r;
|
|
|
eb8b6e |
+
|
|
|
eb8b6e |
+ assert(m);
|
|
|
eb8b6e |
+
|
|
|
eb8b6e |
+ r = unit_test_start_limit(u);
|
|
|
eb8b6e |
+ if (r < 0) {
|
|
|
eb8b6e |
+ mount_enter_dead(m, MOUNT_FAILURE_START_LIMIT_HIT);
|
|
|
eb8b6e |
+ return r;
|
|
|
eb8b6e |
+ }
|
|
|
eb8b6e |
+
|
|
|
eb8b6e |
+ return 0;
|
|
|
eb8b6e |
+}
|
|
|
eb8b6e |
+
|
|
|
eb8b6e |
static const char* const mount_exec_command_table[_MOUNT_EXEC_COMMAND_MAX] = {
|
|
|
eb8b6e |
[MOUNT_EXEC_MOUNT] = "ExecMount",
|
|
|
eb8b6e |
[MOUNT_EXEC_UNMOUNT] = "ExecUnmount",
|
|
|
eb8b6e |
@@ -2044,4 +2053,6 @@ const UnitVTable mount_vtable = {
|
|
|
eb8b6e |
[JOB_TIMEOUT] = "Timed out unmounting %s.",
|
|
|
eb8b6e |
},
|
|
|
eb8b6e |
},
|
|
|
eb8b6e |
+
|
|
|
eb8b6e |
+ .test_start_limit = mount_test_start_limit,
|
|
|
eb8b6e |
};
|
|
|
eb8b6e |
diff --git a/src/core/path.c b/src/core/path.c
|
|
|
eb8b6e |
index 4bccc0396b..1e69a1f05f 100644
|
|
|
eb8b6e |
--- a/src/core/path.c
|
|
|
eb8b6e |
+++ b/src/core/path.c
|
|
|
eb8b6e |
@@ -565,12 +565,6 @@ static int path_start(Unit *u) {
|
|
|
eb8b6e |
return -ENOENT;
|
|
|
eb8b6e |
}
|
|
|
eb8b6e |
|
|
|
eb8b6e |
- r = unit_test_start_limit(u);
|
|
|
eb8b6e |
- if (r < 0) {
|
|
|
eb8b6e |
- path_enter_dead(p, PATH_FAILURE_START_LIMIT_HIT);
|
|
|
eb8b6e |
- return r;
|
|
|
eb8b6e |
- }
|
|
|
eb8b6e |
-
|
|
|
eb8b6e |
r = unit_acquire_invocation_id(u);
|
|
|
eb8b6e |
if (r < 0)
|
|
|
eb8b6e |
return r;
|
|
|
eb8b6e |
@@ -730,6 +724,21 @@ static void path_reset_failed(Unit *u) {
|
|
|
eb8b6e |
p->result = PATH_SUCCESS;
|
|
|
eb8b6e |
}
|
|
|
eb8b6e |
|
|
|
eb8b6e |
+static int path_test_start_limit(Unit *u) {
|
|
|
eb8b6e |
+ Path *p = PATH(u);
|
|
|
eb8b6e |
+ int r;
|
|
|
eb8b6e |
+
|
|
|
eb8b6e |
+ assert(p);
|
|
|
eb8b6e |
+
|
|
|
eb8b6e |
+ r = unit_test_start_limit(u);
|
|
|
eb8b6e |
+ if (r < 0) {
|
|
|
eb8b6e |
+ path_enter_dead(p, PATH_FAILURE_START_LIMIT_HIT);
|
|
|
eb8b6e |
+ return r;
|
|
|
eb8b6e |
+ }
|
|
|
eb8b6e |
+
|
|
|
eb8b6e |
+ return 0;
|
|
|
eb8b6e |
+}
|
|
|
eb8b6e |
+
|
|
|
eb8b6e |
static const char* const path_type_table[_PATH_TYPE_MAX] = {
|
|
|
eb8b6e |
[PATH_EXISTS] = "PathExists",
|
|
|
eb8b6e |
[PATH_EXISTS_GLOB] = "PathExistsGlob",
|
|
|
eb8b6e |
@@ -782,4 +791,6 @@ const UnitVTable path_vtable = {
|
|
|
eb8b6e |
|
|
|
eb8b6e |
.bus_vtable = bus_path_vtable,
|
|
|
eb8b6e |
.bus_set_property = bus_path_set_property,
|
|
|
eb8b6e |
+
|
|
|
eb8b6e |
+ .test_start_limit = path_test_start_limit,
|
|
|
eb8b6e |
};
|
|
|
eb8b6e |
diff --git a/src/core/service.c b/src/core/service.c
|
|
|
eb8b6e |
index 01cb1a375e..a21d98ab8f 100644
|
|
|
eb8b6e |
--- a/src/core/service.c
|
|
|
eb8b6e |
+++ b/src/core/service.c
|
|
|
eb8b6e |
@@ -2356,13 +2356,6 @@ static int service_start(Unit *u) {
|
|
|
eb8b6e |
|
|
|
eb8b6e |
assert(IN_SET(s->state, SERVICE_DEAD, SERVICE_FAILED));
|
|
|
eb8b6e |
|
|
|
eb8b6e |
- /* Make sure we don't enter a busy loop of some kind. */
|
|
|
eb8b6e |
- r = unit_test_start_limit(u);
|
|
|
eb8b6e |
- if (r < 0) {
|
|
|
eb8b6e |
- service_enter_dead(s, SERVICE_FAILURE_START_LIMIT_HIT, false);
|
|
|
eb8b6e |
- return r;
|
|
|
eb8b6e |
- }
|
|
|
eb8b6e |
-
|
|
|
eb8b6e |
r = unit_acquire_invocation_id(u);
|
|
|
eb8b6e |
if (r < 0)
|
|
|
eb8b6e |
return r;
|
|
|
eb8b6e |
@@ -4050,6 +4043,22 @@ static bool service_needs_console(Unit *u) {
|
|
|
eb8b6e |
SERVICE_FINAL_SIGKILL);
|
|
|
eb8b6e |
}
|
|
|
eb8b6e |
|
|
|
eb8b6e |
+static int service_test_start_limit(Unit *u) {
|
|
|
eb8b6e |
+ Service *s = SERVICE(u);
|
|
|
eb8b6e |
+ int r;
|
|
|
eb8b6e |
+
|
|
|
eb8b6e |
+ assert(s);
|
|
|
eb8b6e |
+
|
|
|
eb8b6e |
+ /* Make sure we don't enter a busy loop of some kind. */
|
|
|
eb8b6e |
+ r = unit_test_start_limit(u);
|
|
|
eb8b6e |
+ if (r < 0) {
|
|
|
eb8b6e |
+ service_enter_dead(s, SERVICE_FAILURE_START_LIMIT_HIT, false);
|
|
|
eb8b6e |
+ return r;
|
|
|
eb8b6e |
+ }
|
|
|
eb8b6e |
+
|
|
|
eb8b6e |
+ return 0;
|
|
|
eb8b6e |
+}
|
|
|
eb8b6e |
+
|
|
|
eb8b6e |
static const char* const service_restart_table[_SERVICE_RESTART_MAX] = {
|
|
|
eb8b6e |
[SERVICE_RESTART_NO] = "no",
|
|
|
eb8b6e |
[SERVICE_RESTART_ON_SUCCESS] = "on-success",
|
|
|
eb8b6e |
@@ -4191,4 +4200,6 @@ const UnitVTable service_vtable = {
|
|
|
eb8b6e |
[JOB_FAILED] = "Stopped (with error) %s.",
|
|
|
eb8b6e |
},
|
|
|
eb8b6e |
},
|
|
|
eb8b6e |
+
|
|
|
eb8b6e |
+ .test_start_limit = service_test_start_limit,
|
|
|
eb8b6e |
};
|
|
|
eb8b6e |
diff --git a/src/core/socket.c b/src/core/socket.c
|
|
|
eb8b6e |
index 09491c6677..36d2e4f823 100644
|
|
|
eb8b6e |
--- a/src/core/socket.c
|
|
|
eb8b6e |
+++ b/src/core/socket.c
|
|
|
eb8b6e |
@@ -2469,12 +2469,6 @@ static int socket_start(Unit *u) {
|
|
|
eb8b6e |
|
|
|
eb8b6e |
assert(IN_SET(s->state, SOCKET_DEAD, SOCKET_FAILED));
|
|
|
eb8b6e |
|
|
|
eb8b6e |
- r = unit_test_start_limit(u);
|
|
|
eb8b6e |
- if (r < 0) {
|
|
|
eb8b6e |
- socket_enter_dead(s, SOCKET_FAILURE_START_LIMIT_HIT);
|
|
|
eb8b6e |
- return r;
|
|
|
eb8b6e |
- }
|
|
|
eb8b6e |
-
|
|
|
eb8b6e |
r = unit_acquire_invocation_id(u);
|
|
|
eb8b6e |
if (r < 0)
|
|
|
eb8b6e |
return r;
|
|
|
eb8b6e |
@@ -3267,6 +3261,21 @@ static int socket_control_pid(Unit *u) {
|
|
|
eb8b6e |
return s->control_pid;
|
|
|
eb8b6e |
}
|
|
|
eb8b6e |
|
|
|
eb8b6e |
+static int socket_test_start_limit(Unit *u) {
|
|
|
eb8b6e |
+ Socket *s = SOCKET(u);
|
|
|
eb8b6e |
+ int r;
|
|
|
eb8b6e |
+
|
|
|
eb8b6e |
+ assert(s);
|
|
|
eb8b6e |
+
|
|
|
eb8b6e |
+ r = unit_test_start_limit(u);
|
|
|
eb8b6e |
+ if (r < 0) {
|
|
|
eb8b6e |
+ socket_enter_dead(s, SOCKET_FAILURE_START_LIMIT_HIT);
|
|
|
eb8b6e |
+ return r;
|
|
|
eb8b6e |
+ }
|
|
|
eb8b6e |
+
|
|
|
eb8b6e |
+ return 0;
|
|
|
eb8b6e |
+}
|
|
|
eb8b6e |
+
|
|
|
eb8b6e |
static const char* const socket_exec_command_table[_SOCKET_EXEC_COMMAND_MAX] = {
|
|
|
eb8b6e |
[SOCKET_EXEC_START_PRE] = "ExecStartPre",
|
|
|
eb8b6e |
[SOCKET_EXEC_START_CHOWN] = "ExecStartChown",
|
|
|
eb8b6e |
@@ -3359,4 +3368,6 @@ const UnitVTable socket_vtable = {
|
|
|
eb8b6e |
[JOB_TIMEOUT] = "Timed out stopping %s.",
|
|
|
eb8b6e |
},
|
|
|
eb8b6e |
},
|
|
|
eb8b6e |
+
|
|
|
eb8b6e |
+ .test_start_limit = socket_test_start_limit,
|
|
|
eb8b6e |
};
|
|
|
eb8b6e |
diff --git a/src/core/swap.c b/src/core/swap.c
|
|
|
eb8b6e |
index 823699699e..90fcd69300 100644
|
|
|
eb8b6e |
--- a/src/core/swap.c
|
|
|
eb8b6e |
+++ b/src/core/swap.c
|
|
|
eb8b6e |
@@ -851,12 +851,6 @@ static int swap_start(Unit *u) {
|
|
|
eb8b6e |
if (UNIT(other)->job && UNIT(other)->job->state == JOB_RUNNING)
|
|
|
eb8b6e |
return -EAGAIN;
|
|
|
eb8b6e |
|
|
|
eb8b6e |
- r = unit_test_start_limit(u);
|
|
|
eb8b6e |
- if (r < 0) {
|
|
|
eb8b6e |
- swap_enter_dead(s, SWAP_FAILURE_START_LIMIT_HIT);
|
|
|
eb8b6e |
- return r;
|
|
|
eb8b6e |
- }
|
|
|
eb8b6e |
-
|
|
|
eb8b6e |
r = unit_acquire_invocation_id(u);
|
|
|
eb8b6e |
if (r < 0)
|
|
|
eb8b6e |
return r;
|
|
|
eb8b6e |
@@ -1458,6 +1452,21 @@ static int swap_control_pid(Unit *u) {
|
|
|
eb8b6e |
return s->control_pid;
|
|
|
eb8b6e |
}
|
|
|
eb8b6e |
|
|
|
eb8b6e |
+static int swap_test_start_limit(Unit *u) {
|
|
|
eb8b6e |
+ Swap *s = SWAP(u);
|
|
|
eb8b6e |
+ int r;
|
|
|
eb8b6e |
+
|
|
|
eb8b6e |
+ assert(s);
|
|
|
eb8b6e |
+
|
|
|
eb8b6e |
+ r = unit_test_start_limit(u);
|
|
|
eb8b6e |
+ if (r < 0) {
|
|
|
eb8b6e |
+ swap_enter_dead(s, SWAP_FAILURE_START_LIMIT_HIT);
|
|
|
eb8b6e |
+ return r;
|
|
|
eb8b6e |
+ }
|
|
|
eb8b6e |
+
|
|
|
eb8b6e |
+ return 0;
|
|
|
eb8b6e |
+}
|
|
|
eb8b6e |
+
|
|
|
eb8b6e |
static const char* const swap_exec_command_table[_SWAP_EXEC_COMMAND_MAX] = {
|
|
|
eb8b6e |
[SWAP_EXEC_ACTIVATE] = "ExecActivate",
|
|
|
eb8b6e |
[SWAP_EXEC_DEACTIVATE] = "ExecDeactivate",
|
|
|
eb8b6e |
@@ -1547,4 +1556,6 @@ const UnitVTable swap_vtable = {
|
|
|
eb8b6e |
[JOB_TIMEOUT] = "Timed out deactivating swap %s.",
|
|
|
eb8b6e |
},
|
|
|
eb8b6e |
},
|
|
|
eb8b6e |
+
|
|
|
eb8b6e |
+ .test_start_limit = swap_test_start_limit,
|
|
|
eb8b6e |
};
|
|
|
eb8b6e |
diff --git a/src/core/timer.c b/src/core/timer.c
|
|
|
eb8b6e |
index be16321296..fb9ae17990 100644
|
|
|
eb8b6e |
--- a/src/core/timer.c
|
|
|
eb8b6e |
+++ b/src/core/timer.c
|
|
|
eb8b6e |
@@ -599,12 +599,6 @@ static int timer_start(Unit *u) {
|
|
|
eb8b6e |
return -ENOENT;
|
|
|
eb8b6e |
}
|
|
|
eb8b6e |
|
|
|
eb8b6e |
- r = unit_test_start_limit(u);
|
|
|
eb8b6e |
- if (r < 0) {
|
|
|
eb8b6e |
- timer_enter_dead(t, TIMER_FAILURE_START_LIMIT_HIT);
|
|
|
eb8b6e |
- return r;
|
|
|
eb8b6e |
- }
|
|
|
eb8b6e |
-
|
|
|
eb8b6e |
r = unit_acquire_invocation_id(u);
|
|
|
eb8b6e |
if (r < 0)
|
|
|
eb8b6e |
return r;
|
|
|
eb8b6e |
@@ -829,6 +823,21 @@ static void timer_timezone_change(Unit *u) {
|
|
|
eb8b6e |
timer_enter_waiting(t, false);
|
|
|
eb8b6e |
}
|
|
|
eb8b6e |
|
|
|
eb8b6e |
+static int timer_test_start_limit(Unit *u) {
|
|
|
eb8b6e |
+ Timer *t = TIMER(u);
|
|
|
eb8b6e |
+ int r;
|
|
|
eb8b6e |
+
|
|
|
eb8b6e |
+ assert(t);
|
|
|
eb8b6e |
+
|
|
|
eb8b6e |
+ r = unit_test_start_limit(u);
|
|
|
eb8b6e |
+ if (r < 0) {
|
|
|
eb8b6e |
+ timer_enter_dead(t, TIMER_FAILURE_START_LIMIT_HIT);
|
|
|
eb8b6e |
+ return r;
|
|
|
eb8b6e |
+ }
|
|
|
eb8b6e |
+
|
|
|
eb8b6e |
+ return 0;
|
|
|
eb8b6e |
+}
|
|
|
eb8b6e |
+
|
|
|
eb8b6e |
static const char* const timer_base_table[_TIMER_BASE_MAX] = {
|
|
|
eb8b6e |
[TIMER_ACTIVE] = "OnActiveSec",
|
|
|
eb8b6e |
[TIMER_BOOT] = "OnBootSec",
|
|
|
eb8b6e |
@@ -884,4 +893,5 @@ const UnitVTable timer_vtable = {
|
|
|
eb8b6e |
.bus_set_property = bus_timer_set_property,
|
|
|
eb8b6e |
|
|
|
eb8b6e |
.can_transient = true,
|
|
|
eb8b6e |
+ .test_start_limit = timer_test_start_limit,
|
|
|
eb8b6e |
};
|
|
|
eb8b6e |
diff --git a/src/core/unit.c b/src/core/unit.c
|
|
|
eb8b6e |
index fa94a67fdd..9005f79df3 100644
|
|
|
eb8b6e |
--- a/src/core/unit.c
|
|
|
eb8b6e |
+++ b/src/core/unit.c
|
|
|
eb8b6e |
@@ -1726,10 +1726,16 @@ int unit_start(Unit *u) {
|
|
|
eb8b6e |
|
|
|
eb8b6e |
assert(u);
|
|
|
eb8b6e |
|
|
|
eb8b6e |
- /* If this is already started, then this will succeed. Note
|
|
|
eb8b6e |
- * that this will even succeed if this unit is not startable
|
|
|
eb8b6e |
- * by the user. This is relied on to detect when we need to
|
|
|
eb8b6e |
- * wait for units and when waiting is finished. */
|
|
|
eb8b6e |
+ /* Check start rate limiting early so that failure conditions don't cause us to enter a busy loop. */
|
|
|
eb8b6e |
+ if (UNIT_VTABLE(u)->test_start_limit) {
|
|
|
eb8b6e |
+ int r = UNIT_VTABLE(u)->test_start_limit(u);
|
|
|
eb8b6e |
+ if (r < 0)
|
|
|
eb8b6e |
+ return r;
|
|
|
eb8b6e |
+ }
|
|
|
eb8b6e |
+
|
|
|
eb8b6e |
+ /* If this is already started, then this will succeed. Note that this will even succeed if this unit
|
|
|
eb8b6e |
+ * is not startable by the user. This is relied on to detect when we need to wait for units and when
|
|
|
eb8b6e |
+ * waiting is finished. */
|
|
|
eb8b6e |
state = unit_active_state(u);
|
|
|
eb8b6e |
if (UNIT_IS_ACTIVE_OR_RELOADING(state))
|
|
|
eb8b6e |
return -EALREADY;
|
|
|
eb8b6e |
diff --git a/src/core/unit.h b/src/core/unit.h
|
|
|
eb8b6e |
index a8bc350b66..9e6f1bcf81 100644
|
|
|
eb8b6e |
--- a/src/core/unit.h
|
|
|
eb8b6e |
+++ b/src/core/unit.h
|
|
|
eb8b6e |
@@ -567,6 +567,10 @@ typedef struct UnitVTable {
|
|
|
eb8b6e |
/* The bus vtable */
|
|
|
eb8b6e |
const sd_bus_vtable *bus_vtable;
|
|
|
eb8b6e |
|
|
|
eb8b6e |
+ /* If this function is set, it's invoked first as part of starting a unit to allow start rate
|
|
|
eb8b6e |
+ * limiting checks to occur before we do anything else. */
|
|
|
eb8b6e |
+ int (*test_start_limit)(Unit *u);
|
|
|
eb8b6e |
+
|
|
|
eb8b6e |
/* The strings to print in status messages */
|
|
|
eb8b6e |
UnitStatusMessageFormats status_message_formats;
|
|
|
eb8b6e |
|