systemd-252-76
Resolves: RHEL-208860, RHEL-137251, RHEL-118224, RHEL-213655, RHEL-212610
This commit is contained in:
parent
63d29adf9b
commit
00712f2c9c
@ -0,0 +1,53 @@
|
||||
From 13549c3d3be415eafa0104199cea247706dfa452 Mon Sep 17 00:00:00 2001
|
||||
From: Milan Kyselica <mil.kyselica@gmail.com>
|
||||
Date: Thu, 9 Apr 2026 19:43:14 +0200
|
||||
Subject: [PATCH] resolved: replace assert() with error return in DNSSEC verify
|
||||
functions
|
||||
|
||||
dnssec_rsa_verify_raw() asserts that RSA_size(key) matches the RRSIG
|
||||
signature size, and dnssec_ecdsa_verify_raw() asserts that
|
||||
EC_KEY_check_key() succeeds. Both conditions depend on parsed DNS
|
||||
record content. Replace with proper error returns.
|
||||
|
||||
The actual crypto verify calls (EVP_PKEY_verify / ECDSA_do_verify)
|
||||
handle mismatches fine on their own, so the asserts were also redundant.
|
||||
|
||||
While at it, fix the misleading "EC_POINT_bn2point failed" log message
|
||||
that actually refers to an EC_KEY_set_public_key() failure.
|
||||
|
||||
Fixes: https://github.com/systemd/systemd/issues/41569
|
||||
(cherry picked from commit dd80e5a348bdb8185e040f66ede00fd4ffdee777)
|
||||
|
||||
Resolves: RHEL-208860
|
||||
---
|
||||
src/resolve/resolved-dns-dnssec.c | 9 ++++++---
|
||||
1 file changed, 6 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/src/resolve/resolved-dns-dnssec.c b/src/resolve/resolved-dns-dnssec.c
|
||||
index df25b7f619..7243c2119f 100644
|
||||
--- a/src/resolve/resolved-dns-dnssec.c
|
||||
+++ b/src/resolve/resolved-dns-dnssec.c
|
||||
@@ -125,7 +125,8 @@ static int dnssec_rsa_verify_raw(
|
||||
return -EIO;
|
||||
e = m = NULL;
|
||||
|
||||
- assert((size_t) RSA_size(rpubkey) == signature_size);
|
||||
+ if ((size_t) RSA_size(rpubkey) != signature_size)
|
||||
+ return -EINVAL;
|
||||
|
||||
epubkey = EVP_PKEY_new();
|
||||
if (!epubkey)
|
||||
@@ -337,9 +338,11 @@ static int dnssec_ecdsa_verify_raw(
|
||||
|
||||
if (EC_KEY_set_public_key(eckey, p) <= 0)
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(EIO),
|
||||
- "EC_POINT_bn2point failed: 0x%lx", ERR_get_error());
|
||||
+ "EC_KEY_set_public_key failed: 0x%lx", ERR_get_error());
|
||||
|
||||
- assert(EC_KEY_check_key(eckey) == 1);
|
||||
+ if (EC_KEY_check_key(eckey) != 1)
|
||||
+ return log_debug_errno(SYNTHETIC_ERRNO(EIO),
|
||||
+ "EC_KEY_check_key failed: 0x%lx", ERR_get_error());
|
||||
|
||||
r = BN_bin2bn(signature_r, signature_r_size, NULL);
|
||||
if (!r)
|
||||
399
1359-pid1-introduce-new-SERVICE_-DEAD-FAILED-_BEFORE_AUTO.patch
Normal file
399
1359-pid1-introduce-new-SERVICE_-DEAD-FAILED-_BEFORE_AUTO.patch
Normal file
@ -0,0 +1,399 @@
|
||||
From 3c1b490d6c754b8f91c3b7860a75ab59f8c3e6c8 Mon Sep 17 00:00:00 2001
|
||||
From: Lennart Poettering <lennart@poettering.net>
|
||||
Date: Fri, 24 Mar 2023 16:04:34 +0100
|
||||
Subject: [PATCH] pid1: introduce new SERVICE_{DEAD|FAILED}_BEFORE_AUTO_RESTART
|
||||
service substates
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
When a service deactivates and is then automatically restarted via
|
||||
Restart= we currently quickly transition through
|
||||
SERVICE_DEAD/SERVICE_FAILED. Which is weird given it's not the
|
||||
normal ("permanent") dead/failed state, but a transitory one we
|
||||
immediately leave from again. We do this so that software that looks for
|
||||
failures/successes can take notice, even if we restart as a consequence
|
||||
of the deactivation.
|
||||
|
||||
Let's clean this up a bit: let's introduce two new states:
|
||||
SERVICE_DEAD_BEFORE_AUTO_RESTART and SERVICE_FAILED_BEFORE_AUTO_RESTART
|
||||
that are used for the transitory states. Both the SERVICE_DEAD and
|
||||
SERVICE_DEAD_BEFORE_AUTO_RESTART will map to the high-level
|
||||
UNIT_INACTIVE state though. (and similar for the respective failed
|
||||
states). This means the high-level state machine won't change by this,
|
||||
only the low-level one.
|
||||
|
||||
This clearly seperates the substates, which makes the state engine
|
||||
cleaner, and allows clients to follow precisely whether we are in a
|
||||
transitory dead/failed state, or a permanent one, by looking at the
|
||||
service substate. Moreover it allows us to remove the 'n_keep_fd_store'
|
||||
which so far we used to ensure the fdstore was not released during this
|
||||
transitory dead/failed state but only during the permanent one. Since we
|
||||
can now distinguish these states properly we can just use that.
|
||||
|
||||
This has been bugging me for a while. Let's clean this up.
|
||||
|
||||
Note that the unit restart logic is already nicely covered in the
|
||||
testsiute, hence this adds no new tests for that.
|
||||
|
||||
And yes, this could be considered a compat break, but sofar we took the
|
||||
liberty to make changes to the low-level state machine (i.e. SERVICE_xyz
|
||||
states, sometimes called "substates") without considering this a bad
|
||||
breakage – the high-level state machine (i.e. UNIT_xyz states) should
|
||||
be considered API that cannot be changed.
|
||||
|
||||
(cherry picked from commit a1d315730ffddf283d4bb9d73878fbcd97a4d244)
|
||||
|
||||
Related: RHEL-137251
|
||||
---
|
||||
src/basic/unit-def.c | 44 ++++++++--------
|
||||
src/basic/unit-def.h | 2 +
|
||||
src/core/service.c | 116 +++++++++++++++++++++++++++++--------------
|
||||
src/core/service.h | 1 -
|
||||
src/core/socket.c | 4 +-
|
||||
5 files changed, 105 insertions(+), 62 deletions(-)
|
||||
|
||||
diff --git a/src/basic/unit-def.c b/src/basic/unit-def.c
|
||||
index bdb1860246..a0fab46a19 100644
|
||||
--- a/src/basic/unit-def.c
|
||||
+++ b/src/basic/unit-def.c
|
||||
@@ -180,27 +180,29 @@ static const char* const scope_state_table[_SCOPE_STATE_MAX] = {
|
||||
DEFINE_STRING_TABLE_LOOKUP(scope_state, ScopeState);
|
||||
|
||||
static const char* const service_state_table[_SERVICE_STATE_MAX] = {
|
||||
- [SERVICE_DEAD] = "dead",
|
||||
- [SERVICE_CONDITION] = "condition",
|
||||
- [SERVICE_START_PRE] = "start-pre",
|
||||
- [SERVICE_START] = "start",
|
||||
- [SERVICE_START_POST] = "start-post",
|
||||
- [SERVICE_RUNNING] = "running",
|
||||
- [SERVICE_EXITED] = "exited",
|
||||
- [SERVICE_RELOAD] = "reload",
|
||||
- [SERVICE_RELOAD_SIGNAL] = "reload-signal",
|
||||
- [SERVICE_RELOAD_NOTIFY] = "reload-notify",
|
||||
- [SERVICE_STOP] = "stop",
|
||||
- [SERVICE_STOP_WATCHDOG] = "stop-watchdog",
|
||||
- [SERVICE_STOP_SIGTERM] = "stop-sigterm",
|
||||
- [SERVICE_STOP_SIGKILL] = "stop-sigkill",
|
||||
- [SERVICE_STOP_POST] = "stop-post",
|
||||
- [SERVICE_FINAL_WATCHDOG] = "final-watchdog",
|
||||
- [SERVICE_FINAL_SIGTERM] = "final-sigterm",
|
||||
- [SERVICE_FINAL_SIGKILL] = "final-sigkill",
|
||||
- [SERVICE_FAILED] = "failed",
|
||||
- [SERVICE_AUTO_RESTART] = "auto-restart",
|
||||
- [SERVICE_CLEANING] = "cleaning",
|
||||
+ [SERVICE_DEAD] = "dead",
|
||||
+ [SERVICE_CONDITION] = "condition",
|
||||
+ [SERVICE_START_PRE] = "start-pre",
|
||||
+ [SERVICE_START] = "start",
|
||||
+ [SERVICE_START_POST] = "start-post",
|
||||
+ [SERVICE_RUNNING] = "running",
|
||||
+ [SERVICE_EXITED] = "exited",
|
||||
+ [SERVICE_RELOAD] = "reload",
|
||||
+ [SERVICE_RELOAD_SIGNAL] = "reload-signal",
|
||||
+ [SERVICE_RELOAD_NOTIFY] = "reload-notify",
|
||||
+ [SERVICE_STOP] = "stop",
|
||||
+ [SERVICE_STOP_WATCHDOG] = "stop-watchdog",
|
||||
+ [SERVICE_STOP_SIGTERM] = "stop-sigterm",
|
||||
+ [SERVICE_STOP_SIGKILL] = "stop-sigkill",
|
||||
+ [SERVICE_STOP_POST] = "stop-post",
|
||||
+ [SERVICE_FINAL_WATCHDOG] = "final-watchdog",
|
||||
+ [SERVICE_FINAL_SIGTERM] = "final-sigterm",
|
||||
+ [SERVICE_FINAL_SIGKILL] = "final-sigkill",
|
||||
+ [SERVICE_FAILED] = "failed",
|
||||
+ [SERVICE_DEAD_BEFORE_AUTO_RESTART] = "dead-before-auto-restart",
|
||||
+ [SERVICE_FAILED_BEFORE_AUTO_RESTART] = "failed-before-auto-restart",
|
||||
+ [SERVICE_AUTO_RESTART] = "auto-restart",
|
||||
+ [SERVICE_CLEANING] = "cleaning",
|
||||
};
|
||||
|
||||
DEFINE_STRING_TABLE_LOOKUP(service_state, ServiceState);
|
||||
diff --git a/src/basic/unit-def.h b/src/basic/unit-def.h
|
||||
index bae132ea09..2fab42e9c7 100644
|
||||
--- a/src/basic/unit-def.h
|
||||
+++ b/src/basic/unit-def.h
|
||||
@@ -144,6 +144,8 @@ typedef enum ServiceState {
|
||||
SERVICE_FINAL_SIGTERM, /* In case the STOP_POST executable hangs, we shoot that down, too */
|
||||
SERVICE_FINAL_SIGKILL,
|
||||
SERVICE_FAILED,
|
||||
+ SERVICE_DEAD_BEFORE_AUTO_RESTART,
|
||||
+ SERVICE_FAILED_BEFORE_AUTO_RESTART,
|
||||
SERVICE_AUTO_RESTART,
|
||||
SERVICE_CLEANING,
|
||||
_SERVICE_STATE_MAX,
|
||||
diff --git a/src/core/service.c b/src/core/service.c
|
||||
index e152fb6227..e6c0c71595 100644
|
||||
--- a/src/core/service.c
|
||||
+++ b/src/core/service.c
|
||||
@@ -65,6 +65,8 @@ static const UnitActiveState state_translation_table[_SERVICE_STATE_MAX] = {
|
||||
[SERVICE_FINAL_SIGTERM] = UNIT_DEACTIVATING,
|
||||
[SERVICE_FINAL_SIGKILL] = UNIT_DEACTIVATING,
|
||||
[SERVICE_FAILED] = UNIT_FAILED,
|
||||
+ [SERVICE_DEAD_BEFORE_AUTO_RESTART] = UNIT_INACTIVE,
|
||||
+ [SERVICE_FAILED_BEFORE_AUTO_RESTART] = UNIT_FAILED,
|
||||
[SERVICE_AUTO_RESTART] = UNIT_ACTIVATING,
|
||||
[SERVICE_CLEANING] = UNIT_MAINTENANCE,
|
||||
};
|
||||
@@ -91,6 +93,8 @@ static const UnitActiveState state_translation_table_idle[_SERVICE_STATE_MAX] =
|
||||
[SERVICE_FINAL_SIGTERM] = UNIT_DEACTIVATING,
|
||||
[SERVICE_FINAL_SIGKILL] = UNIT_DEACTIVATING,
|
||||
[SERVICE_FAILED] = UNIT_FAILED,
|
||||
+ [SERVICE_DEAD_BEFORE_AUTO_RESTART] = UNIT_INACTIVE,
|
||||
+ [SERVICE_FAILED_BEFORE_AUTO_RESTART] = UNIT_FAILED,
|
||||
[SERVICE_AUTO_RESTART] = UNIT_ACTIVATING,
|
||||
[SERVICE_CLEANING] = UNIT_MAINTENANCE,
|
||||
};
|
||||
@@ -335,9 +339,6 @@ static void service_fd_store_unlink(ServiceFDStore *fs) {
|
||||
static void service_release_fd_store(Service *s) {
|
||||
assert(s);
|
||||
|
||||
- if (s->n_keep_fd_store > 0)
|
||||
- return;
|
||||
-
|
||||
log_unit_debug(UNIT(s), "Releasing all stored fds");
|
||||
while (s->fd_store)
|
||||
service_fd_store_unlink(s->fd_store);
|
||||
@@ -350,6 +351,10 @@ static void service_release_resources(Unit *u) {
|
||||
|
||||
assert(s);
|
||||
|
||||
+ /* Don't release resources if this is a transitionary failed/dead state */
|
||||
+ if (IN_SET(s->state, SERVICE_DEAD_BEFORE_AUTO_RESTART, SERVICE_FAILED_BEFORE_AUTO_RESTART))
|
||||
+ return;
|
||||
+
|
||||
if (!s->fd_store && s->stdin_fd < 0 && s->stdout_fd < 0 && s->stderr_fd < 0)
|
||||
return;
|
||||
|
||||
@@ -1124,7 +1129,9 @@ static void service_set_state(Service *s, ServiceState state) {
|
||||
s->control_command_id = _SERVICE_EXEC_COMMAND_INVALID;
|
||||
}
|
||||
|
||||
- if (IN_SET(state, SERVICE_DEAD, SERVICE_FAILED, SERVICE_AUTO_RESTART)) {
|
||||
+ if (IN_SET(state,
|
||||
+ SERVICE_DEAD, SERVICE_FAILED,
|
||||
+ SERVICE_DEAD_BEFORE_AUTO_RESTART, SERVICE_FAILED_BEFORE_AUTO_RESTART, SERVICE_AUTO_RESTART)) {
|
||||
unit_unwatch_all_pids(UNIT(s));
|
||||
unit_dequeue_rewatch_pids(UNIT(s));
|
||||
}
|
||||
@@ -1237,7 +1244,10 @@ static int service_coldplug(Unit *u) {
|
||||
return r;
|
||||
}
|
||||
|
||||
- if (!IN_SET(s->deserialized_state, SERVICE_DEAD, SERVICE_FAILED, SERVICE_AUTO_RESTART, SERVICE_CLEANING)) {
|
||||
+ if (!IN_SET(s->deserialized_state,
|
||||
+ SERVICE_DEAD, SERVICE_FAILED,
|
||||
+ SERVICE_DEAD_BEFORE_AUTO_RESTART, SERVICE_FAILED_BEFORE_AUTO_RESTART, SERVICE_AUTO_RESTART,
|
||||
+ SERVICE_CLEANING)) {
|
||||
(void) unit_enqueue_rewatch_pids(u);
|
||||
(void) unit_setup_dynamic_creds(u);
|
||||
(void) unit_setup_exec_runtime(u);
|
||||
@@ -1815,14 +1825,14 @@ static bool service_will_restart(Unit *u) {
|
||||
|
||||
if (s->will_auto_restart)
|
||||
return true;
|
||||
- if (s->state == SERVICE_AUTO_RESTART)
|
||||
+ if (IN_SET(s->state, SERVICE_DEAD_BEFORE_AUTO_RESTART, SERVICE_FAILED_BEFORE_AUTO_RESTART, SERVICE_AUTO_RESTART))
|
||||
return true;
|
||||
|
||||
return unit_will_restart_default(u);
|
||||
}
|
||||
|
||||
static void service_enter_dead(Service *s, ServiceResult f, bool allow_restart) {
|
||||
- ServiceState end_state;
|
||||
+ ServiceState end_state, restart_state;
|
||||
int r;
|
||||
|
||||
assert(s);
|
||||
@@ -1838,12 +1848,15 @@ static void service_enter_dead(Service *s, ServiceResult f, bool allow_restart)
|
||||
if (s->result == SERVICE_SUCCESS) {
|
||||
unit_log_success(UNIT(s));
|
||||
end_state = SERVICE_DEAD;
|
||||
+ restart_state = SERVICE_DEAD_BEFORE_AUTO_RESTART;
|
||||
} else if (s->result == SERVICE_SKIP_CONDITION) {
|
||||
unit_log_skip(UNIT(s), service_result_to_string(s->result));
|
||||
end_state = SERVICE_DEAD;
|
||||
+ restart_state = SERVICE_DEAD_BEFORE_AUTO_RESTART;
|
||||
} else {
|
||||
unit_log_failure(UNIT(s), service_result_to_string(s->result));
|
||||
end_state = SERVICE_FAILED;
|
||||
+ restart_state = SERVICE_FAILED_BEFORE_AUTO_RESTART;
|
||||
}
|
||||
unit_warn_leftover_processes(UNIT(s), unit_log_leftover_process_stop);
|
||||
|
||||
@@ -1861,30 +1874,33 @@ static void service_enter_dead(Service *s, ServiceResult f, bool allow_restart)
|
||||
s->will_auto_restart = true;
|
||||
}
|
||||
|
||||
- /* Make sure service_release_resources() doesn't destroy our FD store, while we are changing through
|
||||
- * SERVICE_FAILED/SERVICE_DEAD before entering into SERVICE_AUTO_RESTART. */
|
||||
- s->n_keep_fd_store ++;
|
||||
-
|
||||
- service_set_state(s, end_state);
|
||||
-
|
||||
if (s->will_auto_restart) {
|
||||
s->will_auto_restart = false;
|
||||
|
||||
+ /* We make two state changes here: one that maps to the high-level UNIT_INACTIVE/UNIT_FAILED
|
||||
+ * state (i.e. a state indicating deactivation), and then one that that maps to the
|
||||
+ * high-level UNIT_STARTING state (i.e. a state indicating activation). We do this so that
|
||||
+ * external software can watch the state changes and see all service failures, even if they
|
||||
+ * are only transitionary and followed by an automatic restart. We have fine-grained
|
||||
+ * low-level states for this though so that software can distinguish the permanent UNIT_INACTIVE
|
||||
+ * state from this transitionary UNIT_INACTIVE state by looking at the low-level states. */
|
||||
+ service_set_state(s, restart_state);
|
||||
+
|
||||
r = service_arm_timer(s, /* relative= */ true, s->restart_usec);
|
||||
- if (r < 0) {
|
||||
- s->n_keep_fd_store--;
|
||||
+ if (r < 0)
|
||||
goto fail;
|
||||
- }
|
||||
|
||||
service_set_state(s, SERVICE_AUTO_RESTART);
|
||||
- } else
|
||||
+ } else {
|
||||
+ service_set_state(s, end_state);
|
||||
+
|
||||
/* If we shan't restart, then flush out the restart counter. But don't do that immediately, so that the
|
||||
* user can still introspect the counter. Do so on the next start. */
|
||||
s->flush_n_restarts = true;
|
||||
+ }
|
||||
|
||||
/* The new state is in effect, let's decrease the fd store ref counter again. Let's also re-add us to the GC
|
||||
* queue, so that the fd store is possibly gc'ed again */
|
||||
- s->n_keep_fd_store--;
|
||||
unit_add_to_gc_queue(UNIT(s));
|
||||
|
||||
/* The next restart might not be a manual stop, hence reset the flag indicating manual stops */
|
||||
@@ -2611,34 +2627,55 @@ static int service_stop(Unit *u) {
|
||||
/* Don't create restart jobs from manual stops. */
|
||||
s->forbid_restart = true;
|
||||
|
||||
- /* Already on it */
|
||||
- if (IN_SET(s->state,
|
||||
- SERVICE_STOP, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST,
|
||||
- SERVICE_FINAL_WATCHDOG, SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL))
|
||||
+ switch (s->state) {
|
||||
+
|
||||
+ case SERVICE_STOP:
|
||||
+ case SERVICE_STOP_SIGTERM:
|
||||
+ case SERVICE_STOP_SIGKILL:
|
||||
+ case SERVICE_STOP_POST:
|
||||
+ case SERVICE_FINAL_WATCHDOG:
|
||||
+ case SERVICE_FINAL_SIGTERM:
|
||||
+ case SERVICE_FINAL_SIGKILL:
|
||||
+ /* Already on it */
|
||||
return 0;
|
||||
|
||||
- /* A restart will be scheduled or is in progress. */
|
||||
- if (s->state == SERVICE_AUTO_RESTART) {
|
||||
+ case SERVICE_AUTO_RESTART:
|
||||
+ /* A restart will be scheduled or is in progress. */
|
||||
service_set_state(s, SERVICE_DEAD);
|
||||
return 0;
|
||||
- }
|
||||
|
||||
- /* If there's already something running we go directly into kill mode. */
|
||||
- if (IN_SET(s->state, SERVICE_CONDITION, SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST, SERVICE_RELOAD, SERVICE_RELOAD_SIGNAL, SERVICE_RELOAD_NOTIFY, SERVICE_STOP_WATCHDOG)) {
|
||||
+ case SERVICE_CONDITION:
|
||||
+ case SERVICE_START_PRE:
|
||||
+ case SERVICE_START:
|
||||
+ case SERVICE_START_POST:
|
||||
+ case SERVICE_RELOAD:
|
||||
+ case SERVICE_RELOAD_SIGNAL:
|
||||
+ case SERVICE_RELOAD_NOTIFY:
|
||||
+ case SERVICE_STOP_WATCHDOG:
|
||||
+ /* If there's already something running we go directly into kill mode. */
|
||||
service_enter_signal(s, SERVICE_STOP_SIGTERM, SERVICE_SUCCESS);
|
||||
return 0;
|
||||
- }
|
||||
|
||||
- /* If we are currently cleaning, then abort it, brutally. */
|
||||
- if (s->state == SERVICE_CLEANING) {
|
||||
+ case SERVICE_CLEANING:
|
||||
+ /* If we are currently cleaning, then abort it, brutally. */
|
||||
service_enter_signal(s, SERVICE_FINAL_SIGKILL, SERVICE_SUCCESS);
|
||||
return 0;
|
||||
+
|
||||
+ case SERVICE_RUNNING:
|
||||
+ case SERVICE_EXITED:
|
||||
+ service_enter_stop(s, SERVICE_SUCCESS);
|
||||
+ return 1;
|
||||
+
|
||||
+ case SERVICE_DEAD_BEFORE_AUTO_RESTART:
|
||||
+ case SERVICE_FAILED_BEFORE_AUTO_RESTART:
|
||||
+ case SERVICE_DEAD:
|
||||
+ case SERVICE_FAILED:
|
||||
+ default:
|
||||
+ /* Unknown state, or unit_stop() should already have handled these */
|
||||
+ assert_not_reached();
|
||||
}
|
||||
|
||||
- assert(IN_SET(s->state, SERVICE_RUNNING, SERVICE_EXITED));
|
||||
|
||||
- service_enter_stop(s, SERVICE_SUCCESS);
|
||||
- return 1;
|
||||
}
|
||||
|
||||
static int service_reload(Unit *u) {
|
||||
@@ -3214,6 +3251,11 @@ static bool service_may_gc(Unit *u) {
|
||||
control_pid_good(s) > 0)
|
||||
return false;
|
||||
|
||||
+ /* Only allow collection of actually dead services, i.e. not those that are in the transitionary
|
||||
+ * SERVICE_DEAD_BEFORE_AUTO_RESTART/SERVICE_FAILED_BEFORE_AUTO_RESTART states. */
|
||||
+ if (!IN_SET(s->state, SERVICE_DEAD, SERVICE_FAILED))
|
||||
+ return false;
|
||||
+
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -3375,11 +3417,9 @@ static void service_notify_cgroup_empty_event(Unit *u) {
|
||||
|
||||
switch (s->state) {
|
||||
|
||||
- /* Waiting for SIGCHLD is usually more interesting,
|
||||
- * because it includes return codes/signals. Which is
|
||||
- * why we ignore the cgroup events for most cases,
|
||||
- * except when we don't know pid which to expect the
|
||||
- * SIGCHLD for. */
|
||||
+ /* Waiting for SIGCHLD is usually more interesting, because it includes return
|
||||
+ * codes/signals. Which is why we ignore the cgroup events for most cases, except when we
|
||||
+ * don't know pid which to expect the SIGCHLD for. */
|
||||
|
||||
case SERVICE_START:
|
||||
if (IN_SET(s->type, SERVICE_NOTIFY, SERVICE_NOTIFY_RELOAD) &&
|
||||
diff --git a/src/core/service.h b/src/core/service.h
|
||||
index 194067f0e1..58780ebd41 100644
|
||||
--- a/src/core/service.h
|
||||
+++ b/src/core/service.h
|
||||
@@ -203,7 +203,6 @@ struct Service {
|
||||
ServiceFDStore *fd_store;
|
||||
size_t n_fd_store;
|
||||
unsigned n_fd_store_max;
|
||||
- unsigned n_keep_fd_store;
|
||||
|
||||
char *usb_function_descriptors;
|
||||
char *usb_function_strings;
|
||||
diff --git a/src/core/socket.c b/src/core/socket.c
|
||||
index 103b399ab8..ebb83cd5b0 100644
|
||||
--- a/src/core/socket.c
|
||||
+++ b/src/core/socket.c
|
||||
@@ -2471,7 +2471,7 @@ static int socket_start(Unit *u) {
|
||||
|
||||
/* If the service is already active we cannot start the
|
||||
* socket */
|
||||
- if (!IN_SET(service->state, SERVICE_DEAD, SERVICE_FAILED, SERVICE_AUTO_RESTART))
|
||||
+ if (!IN_SET(service->state, SERVICE_DEAD, SERVICE_FAILED, SERVICE_DEAD_BEFORE_AUTO_RESTART, SERVICE_FAILED_BEFORE_AUTO_RESTART, SERVICE_AUTO_RESTART))
|
||||
return log_unit_error_errno(u, SYNTHETIC_ERRNO(EBUSY), "Socket service %s already active, refusing.", UNIT(service)->id);
|
||||
}
|
||||
|
||||
@@ -3274,7 +3274,7 @@ static void socket_trigger_notify(Unit *u, Unit *other) {
|
||||
return;
|
||||
|
||||
if (IN_SET(SERVICE(other)->state,
|
||||
- SERVICE_DEAD, SERVICE_FAILED,
|
||||
+ SERVICE_DEAD, SERVICE_DEAD_BEFORE_AUTO_RESTART, SERVICE_FAILED, SERVICE_FAILED_BEFORE_AUTO_RESTART,
|
||||
SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL,
|
||||
SERVICE_AUTO_RESTART))
|
||||
socket_enter_listening(s);
|
||||
423
1360-service-add-new-RestartMode-option.patch
Normal file
423
1360-service-add-new-RestartMode-option.patch
Normal file
@ -0,0 +1,423 @@
|
||||
From 219f89250a9d41c357eb1224f624ae3cf08cf4e9 Mon Sep 17 00:00:00 2001
|
||||
From: Richard Phibel <rphibel@googlemail.com>
|
||||
Date: Thu, 6 Jul 2023 14:33:52 +0200
|
||||
Subject: [PATCH] service: add new RestartMode option
|
||||
|
||||
When this option is set to direct, the service restarts without entering a failed
|
||||
state. Dependent units are not notified of transitory failure.
|
||||
|
||||
This is useful for the following use case:
|
||||
|
||||
We have a target with Requires=my-service, After=my-service.
|
||||
my-service.service is a oneshot service and has Restart=on-failure in
|
||||
its definition.
|
||||
|
||||
my-service.service can get stuck for various reasons and time out, in
|
||||
which case it is restarted. Currently, when it fails the first time, the
|
||||
target fails, even though my-service is restarted.
|
||||
|
||||
The behavior we're looking for is that until my-service is not restarted
|
||||
anymore, the target stays pending waiting for my-service.service to
|
||||
start successfully or fail without being restarted anymore.
|
||||
|
||||
(cherry picked from commit e568fea9fcd2189d4366df254a8a4031dc433762)
|
||||
|
||||
Resolves: RHEL-137251
|
||||
---
|
||||
man/org.freedesktop.systemd1.xml | 6 +++++
|
||||
man/systemd.service.xml | 22 +++++++++++++++++++
|
||||
src/core/dbus-service.c | 6 +++++
|
||||
src/core/load-fragment-gperf.gperf.in | 1 +
|
||||
src/core/load-fragment.c | 2 ++
|
||||
src/core/load-fragment.h | 1 +
|
||||
src/core/service.c | 10 ++++++++-
|
||||
src/core/service.h | 11 ++++++++++
|
||||
src/shared/bus-unit-util.c | 1 +
|
||||
src/test/test-tables.c | 1 +
|
||||
.../fails-on-restart-restartdirect.service | 11 ++++++++++
|
||||
.../fails-on-restart-restartdirect.target | 3 +++
|
||||
.../fails-on-restart.service | 11 ++++++++++
|
||||
.../fails-on-restart.target | 3 +++
|
||||
.../succeeds-on-restart-restartdirect.service | 6 +++++
|
||||
.../succeeds-on-restart-restartdirect.target | 3 +++
|
||||
.../succeeds-on-restart.service | 6 +++++
|
||||
.../testsuite-03.units/succeeds-on-restart.sh | 10 +++++++++
|
||||
.../succeeds-on-restart.target | 3 +++
|
||||
test/units/testsuite-03.sh | 13 +++++++++++
|
||||
20 files changed, 129 insertions(+), 1 deletion(-)
|
||||
create mode 100644 test/testsuite-03.units/fails-on-restart-restartdirect.service
|
||||
create mode 100755 test/testsuite-03.units/fails-on-restart-restartdirect.target
|
||||
create mode 100644 test/testsuite-03.units/fails-on-restart.service
|
||||
create mode 100755 test/testsuite-03.units/fails-on-restart.target
|
||||
create mode 100755 test/testsuite-03.units/succeeds-on-restart-restartdirect.service
|
||||
create mode 100755 test/testsuite-03.units/succeeds-on-restart-restartdirect.target
|
||||
create mode 100755 test/testsuite-03.units/succeeds-on-restart.service
|
||||
create mode 100755 test/testsuite-03.units/succeeds-on-restart.sh
|
||||
create mode 100755 test/testsuite-03.units/succeeds-on-restart.target
|
||||
|
||||
diff --git a/man/org.freedesktop.systemd1.xml b/man/org.freedesktop.systemd1.xml
|
||||
index e7b9b0a127..8298b726b7 100644
|
||||
--- a/man/org.freedesktop.systemd1.xml
|
||||
+++ b/man/org.freedesktop.systemd1.xml
|
||||
@@ -2524,6 +2524,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
|
||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||
readonly s Restart = '...';
|
||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||
+ readonly s RestartMode = '...';
|
||||
+ @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||
readonly s PIDFile = '...';
|
||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||
readonly s NotifyAccess = '...';
|
||||
@@ -3128,6 +3130,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
|
||||
|
||||
<!--property Restart is not documented!-->
|
||||
|
||||
+ <!--property RestartMode is not documented!-->
|
||||
+
|
||||
<!--property PIDFile is not documented!-->
|
||||
|
||||
<!--property NotifyAccess is not documented!-->
|
||||
@@ -3666,6 +3670,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
|
||||
|
||||
<variablelist class="dbus-property" generated="True" extra-ref="Restart"/>
|
||||
|
||||
+ <variablelist class="dbus-property" generated="True" extra-ref="RestartMode"/>
|
||||
+
|
||||
<variablelist class="dbus-property" generated="True" extra-ref="PIDFile"/>
|
||||
|
||||
<variablelist class="dbus-property" generated="True" extra-ref="NotifyAccess"/>
|
||||
diff --git a/man/systemd.service.xml b/man/systemd.service.xml
|
||||
index ae54332440..d2d6f589da 100644
|
||||
--- a/man/systemd.service.xml
|
||||
+++ b/man/systemd.service.xml
|
||||
@@ -941,6 +941,28 @@
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
+ <varlistentry>
|
||||
+ <term><varname>RestartMode=</varname></term>
|
||||
+
|
||||
+ <listitem>
|
||||
+ <para>Takes a string value that specifies how a service should restart:
|
||||
+ <itemizedlist>
|
||||
+ <listitem><para>If set to <option>normal</option> (the default), the service restarts by
|
||||
+ going through a failed/inactive state.</para></listitem>
|
||||
+
|
||||
+ <listitem><para>If set to <option>direct</option>, the service transitions to the activating
|
||||
+ state directly during auto-restart, skipping failed/inactive state.
|
||||
+ <varname>ExecStopPost=</varname> is invoked.
|
||||
+ <varname>OnSuccess=</varname> and <varname>OnFailure=</varname> are skipped.</para></listitem>
|
||||
+ </itemizedlist>
|
||||
+ </para>
|
||||
+
|
||||
+ <para>This option is useful in cases where a dependency can fail temporarily
|
||||
+ but we don't want these temporary failures to make the dependent units fail.
|
||||
+ When this option is set to <option>direct</option>, dependent units are not notified of these temporary failures.</para>
|
||||
+ </listitem>
|
||||
+ </varlistentry>
|
||||
+
|
||||
<varlistentry>
|
||||
<term><varname>SuccessExitStatus=</varname></term>
|
||||
|
||||
diff --git a/src/core/dbus-service.c b/src/core/dbus-service.c
|
||||
index 3d130db66a..f8bf455707 100644
|
||||
--- a/src/core/dbus-service.c
|
||||
+++ b/src/core/dbus-service.c
|
||||
@@ -31,6 +31,7 @@ static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_exit_type, service_exit_type, S
|
||||
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_result, service_result, ServiceResult);
|
||||
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_restart, service_restart, ServiceRestart);
|
||||
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_notify_access, notify_access, NotifyAccess);
|
||||
+static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_restart_mode, service_restart_mode, ServiceRestartMode);
|
||||
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_emergency_action, emergency_action, EmergencyAction);
|
||||
static BUS_DEFINE_PROPERTY_GET(property_get_timeout_abort_usec, "t", Service, service_timeout_abort_usec);
|
||||
static BUS_DEFINE_PROPERTY_GET(property_get_watchdog_usec, "t", Service, service_get_watchdog_usec);
|
||||
@@ -193,6 +194,7 @@ const sd_bus_vtable bus_service_vtable[] = {
|
||||
SD_BUS_PROPERTY("Type", "s", property_get_type, offsetof(Service, type), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("ExitType", "s", property_get_exit_type, offsetof(Service, exit_type), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("Restart", "s", property_get_restart, offsetof(Service, restart), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
+ SD_BUS_PROPERTY("RestartMode", "s", property_get_restart_mode, offsetof(Service, restart_mode), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("PIDFile", "s", NULL, offsetof(Service, pid_file), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("NotifyAccess", "s", property_get_notify_access, offsetof(Service, notify_access), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("RestartUSec", "t", bus_property_get_usec, offsetof(Service, restart_usec), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
@@ -372,6 +374,7 @@ static BUS_DEFINE_SET_TRANSIENT_PARSE(notify_access, NotifyAccess, notify_access
|
||||
static BUS_DEFINE_SET_TRANSIENT_PARSE(service_type, ServiceType, service_type_from_string);
|
||||
static BUS_DEFINE_SET_TRANSIENT_PARSE(service_exit_type, ServiceExitType, service_exit_type_from_string);
|
||||
static BUS_DEFINE_SET_TRANSIENT_PARSE(service_restart, ServiceRestart, service_restart_from_string);
|
||||
+static BUS_DEFINE_SET_TRANSIENT_PARSE(service_restart_mode, ServiceRestartMode, service_restart_mode_from_string);
|
||||
static BUS_DEFINE_SET_TRANSIENT_PARSE(oom_policy, OOMPolicy, oom_policy_from_string);
|
||||
static BUS_DEFINE_SET_TRANSIENT_STRING_WITH_CHECK(bus_name, sd_bus_service_name_is_valid);
|
||||
static BUS_DEFINE_SET_TRANSIENT_PARSE(timeout_failure_mode, ServiceTimeoutFailureMode, service_timeout_failure_mode_from_string);
|
||||
@@ -511,6 +514,9 @@ static int bus_service_set_transient_property(
|
||||
if (streq(name, "Restart"))
|
||||
return bus_set_transient_service_restart(u, name, &s->restart, message, flags, error);
|
||||
|
||||
+ if (streq(name, "RestartMode"))
|
||||
+ return bus_set_transient_service_restart_mode(u, name, &s->restart_mode, message, flags, error);
|
||||
+
|
||||
if (streq(name, "RestartPreventExitStatus"))
|
||||
return bus_set_transient_exit_status(u, name, &s->restart_prevent_status, message, flags, error);
|
||||
|
||||
diff --git a/src/core/load-fragment-gperf.gperf.in b/src/core/load-fragment-gperf.gperf.in
|
||||
index 53089d5590..602cd2befd 100644
|
||||
--- a/src/core/load-fragment-gperf.gperf.in
|
||||
+++ b/src/core/load-fragment-gperf.gperf.in
|
||||
@@ -407,6 +407,7 @@ Service.RebootArgument, config_parse_unit_string_printf,
|
||||
Service.Type, config_parse_service_type, 0, offsetof(Service, type)
|
||||
Service.ExitType, config_parse_service_exit_type, 0, offsetof(Service, exit_type)
|
||||
Service.Restart, config_parse_service_restart, 0, offsetof(Service, restart)
|
||||
+Service.RestartMode, config_parse_service_restart_mode, 0, offsetof(Service, restart_mode)
|
||||
Service.PermissionsStartOnly, config_parse_bool, 0, offsetof(Service, permissions_start_only)
|
||||
Service.RootDirectoryStartOnly, config_parse_bool, 0, offsetof(Service, root_directory_start_only)
|
||||
Service.RemainAfterExit, config_parse_bool, 0, offsetof(Service, remain_after_exit)
|
||||
diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c
|
||||
index 2699ccf6ef..17863d7139 100644
|
||||
--- a/src/core/load-fragment.c
|
||||
+++ b/src/core/load-fragment.c
|
||||
@@ -140,6 +140,7 @@ DEFINE_CONFIG_PARSE_ENUM(config_parse_runtime_preserve_mode, exec_preserve_mode,
|
||||
DEFINE_CONFIG_PARSE_ENUM(config_parse_service_type, service_type, ServiceType, "Failed to parse service type");
|
||||
DEFINE_CONFIG_PARSE_ENUM(config_parse_service_exit_type, service_exit_type, ServiceExitType, "Failed to parse service exit type");
|
||||
DEFINE_CONFIG_PARSE_ENUM(config_parse_service_restart, service_restart, ServiceRestart, "Failed to parse service restart specifier");
|
||||
+DEFINE_CONFIG_PARSE_ENUM(config_parse_service_restart_mode, service_restart_mode, ServiceRestartMode, "Failed to parse service restart mode");
|
||||
DEFINE_CONFIG_PARSE_ENUM(config_parse_service_timeout_failure_mode, service_timeout_failure_mode, ServiceTimeoutFailureMode, "Failed to parse timeout failure mode");
|
||||
DEFINE_CONFIG_PARSE_ENUM(config_parse_socket_bind, socket_address_bind_ipv6_only_or_bool, SocketAddressBindIPv6Only, "Failed to parse bind IPv6 only value");
|
||||
DEFINE_CONFIG_PARSE_ENUM(config_parse_oom_policy, oom_policy, OOMPolicy, "Failed to parse OOM policy");
|
||||
@@ -6166,6 +6167,7 @@ void unit_dump_config_items(FILE *f) {
|
||||
{ config_parse_service_type, "SERVICETYPE" },
|
||||
{ config_parse_service_exit_type, "SERVICEEXITTYPE" },
|
||||
{ config_parse_service_restart, "SERVICERESTART" },
|
||||
+ { config_parse_service_restart_mode, "SERVICERESTARTMODE" },
|
||||
{ config_parse_service_timeout_failure_mode, "TIMEOUTMODE" },
|
||||
{ config_parse_kill_mode, "KILLMODE" },
|
||||
{ config_parse_signal, "SIGNAL" },
|
||||
diff --git a/src/core/load-fragment.h b/src/core/load-fragment.h
|
||||
index c57a6b2277..bdedbc51e2 100644
|
||||
--- a/src/core/load-fragment.h
|
||||
+++ b/src/core/load-fragment.h
|
||||
@@ -39,6 +39,7 @@ CONFIG_PARSER_PROTOTYPE(config_parse_service_timeout_failure_mode);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_service_type);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_service_exit_type);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_service_restart);
|
||||
+CONFIG_PARSER_PROTOTYPE(config_parse_service_restart_mode);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_socket_bindtodevice);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_exec_output);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_exec_input);
|
||||
diff --git a/src/core/service.c b/src/core/service.c
|
||||
index e6c0c71595..96f419bb47 100644
|
||||
--- a/src/core/service.c
|
||||
+++ b/src/core/service.c
|
||||
@@ -1884,7 +1884,8 @@ static void service_enter_dead(Service *s, ServiceResult f, bool allow_restart)
|
||||
* are only transitionary and followed by an automatic restart. We have fine-grained
|
||||
* low-level states for this though so that software can distinguish the permanent UNIT_INACTIVE
|
||||
* state from this transitionary UNIT_INACTIVE state by looking at the low-level states. */
|
||||
- service_set_state(s, restart_state);
|
||||
+ if (s->restart_mode != SERVICE_RESTART_MODE_DIRECT)
|
||||
+ service_set_state(s, restart_state);
|
||||
|
||||
r = service_arm_timer(s, /* relative= */ true, s->restart_usec);
|
||||
if (r < 0)
|
||||
@@ -4771,6 +4772,13 @@ static const char* const service_restart_table[_SERVICE_RESTART_MAX] = {
|
||||
|
||||
DEFINE_STRING_TABLE_LOOKUP(service_restart, ServiceRestart);
|
||||
|
||||
+static const char* const service_restart_mode_table[_SERVICE_RESTART_MODE_MAX] = {
|
||||
+ [SERVICE_RESTART_MODE_NORMAL] = "normal",
|
||||
+ [SERVICE_RESTART_MODE_DIRECT] = "direct",
|
||||
+};
|
||||
+
|
||||
+DEFINE_STRING_TABLE_LOOKUP(service_restart_mode, ServiceRestartMode);
|
||||
+
|
||||
static const char* const service_type_table[_SERVICE_TYPE_MAX] = {
|
||||
[SERVICE_SIMPLE] = "simple",
|
||||
[SERVICE_FORKING] = "forking",
|
||||
diff --git a/src/core/service.h b/src/core/service.h
|
||||
index 58780ebd41..bfbb3261a8 100644
|
||||
--- a/src/core/service.h
|
||||
+++ b/src/core/service.h
|
||||
@@ -90,6 +90,13 @@ typedef enum ServiceTimeoutFailureMode {
|
||||
_SERVICE_TIMEOUT_FAILURE_MODE_INVALID = -EINVAL,
|
||||
} ServiceTimeoutFailureMode;
|
||||
|
||||
+typedef enum ServiceRestartMode {
|
||||
+ SERVICE_RESTART_MODE_NORMAL,
|
||||
+ SERVICE_RESTART_MODE_DIRECT,
|
||||
+ _SERVICE_RESTART_MODE_MAX,
|
||||
+ _SERVICE_RESTART_MODE_INVALID = -EINVAL,
|
||||
+} ServiceRestartMode;
|
||||
+
|
||||
struct ServiceFDStore {
|
||||
Service *service;
|
||||
|
||||
@@ -107,6 +114,7 @@ struct Service {
|
||||
ServiceType type;
|
||||
ServiceExitType exit_type;
|
||||
ServiceRestart restart;
|
||||
+ ServiceRestartMode restart_mode;
|
||||
ExitStatusSet restart_prevent_status;
|
||||
ExitStatusSet restart_force_status;
|
||||
ExitStatusSet success_status;
|
||||
@@ -238,6 +246,9 @@ void service_close_socket_fd(Service *s);
|
||||
const char* service_restart_to_string(ServiceRestart i) _const_;
|
||||
ServiceRestart service_restart_from_string(const char *s) _pure_;
|
||||
|
||||
+const char* service_restart_mode_to_string(ServiceRestartMode i) _const_;
|
||||
+ServiceRestartMode service_restart_mode_from_string(const char *s) _pure_;
|
||||
+
|
||||
const char* service_type_to_string(ServiceType i) _const_;
|
||||
ServiceType service_type_from_string(const char *s) _pure_;
|
||||
|
||||
diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c
|
||||
index a9844e1cc3..43abdce1b4 100644
|
||||
--- a/src/shared/bus-unit-util.c
|
||||
+++ b/src/shared/bus-unit-util.c
|
||||
@@ -2156,6 +2156,7 @@ static int bus_append_service_property(sd_bus_message *m, const char *field, con
|
||||
"Type",
|
||||
"ExitType",
|
||||
"Restart",
|
||||
+ "RestartMode",
|
||||
"BusName",
|
||||
"NotifyAccess",
|
||||
"USBFunctionDescriptors",
|
||||
diff --git a/src/test/test-tables.c b/src/test/test-tables.c
|
||||
index d47d3d75cc..0be3c43cde 100644
|
||||
--- a/src/test/test-tables.c
|
||||
+++ b/src/test/test-tables.c
|
||||
@@ -98,6 +98,7 @@ int main(int argc, char **argv) {
|
||||
test_table(scope_state, SCOPE_STATE);
|
||||
test_table(service_exec_command, SERVICE_EXEC_COMMAND);
|
||||
test_table(service_restart, SERVICE_RESTART);
|
||||
+ test_table(service_restart_mode, SERVICE_RESTART_MODE);
|
||||
test_table(service_result, SERVICE_RESULT);
|
||||
test_table(service_state, SERVICE_STATE);
|
||||
test_table(service_type, SERVICE_TYPE);
|
||||
diff --git a/test/testsuite-03.units/fails-on-restart-restartdirect.service b/test/testsuite-03.units/fails-on-restart-restartdirect.service
|
||||
new file mode 100644
|
||||
index 0000000000..60ffd7a600
|
||||
--- /dev/null
|
||||
+++ b/test/testsuite-03.units/fails-on-restart-restartdirect.service
|
||||
@@ -0,0 +1,11 @@
|
||||
+# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
+[Unit]
|
||||
+Description=Fail on restart
|
||||
+StartLimitIntervalSec=1m
|
||||
+StartLimitBurst=3
|
||||
+
|
||||
+[Service]
|
||||
+Type=oneshot
|
||||
+ExecStart=false
|
||||
+Restart=on-failure
|
||||
+RestartMode=direct
|
||||
diff --git a/test/testsuite-03.units/fails-on-restart-restartdirect.target b/test/testsuite-03.units/fails-on-restart-restartdirect.target
|
||||
new file mode 100755
|
||||
index 0000000000..58e2561039
|
||||
--- /dev/null
|
||||
+++ b/test/testsuite-03.units/fails-on-restart-restartdirect.target
|
||||
@@ -0,0 +1,3 @@
|
||||
+# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
+[Unit]
|
||||
+Requires=fails-on-restart-restartdirect.service
|
||||
diff --git a/test/testsuite-03.units/fails-on-restart.service b/test/testsuite-03.units/fails-on-restart.service
|
||||
new file mode 100644
|
||||
index 0000000000..fb7e7aeb4c
|
||||
--- /dev/null
|
||||
+++ b/test/testsuite-03.units/fails-on-restart.service
|
||||
@@ -0,0 +1,11 @@
|
||||
+# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
+[Unit]
|
||||
+Description=Fail on restart
|
||||
+StartLimitIntervalSec=1m
|
||||
+StartLimitBurst=3
|
||||
+
|
||||
+[Service]
|
||||
+Type=oneshot
|
||||
+ExecStart=false
|
||||
+Restart=on-failure
|
||||
+RestartMode=normal
|
||||
diff --git a/test/testsuite-03.units/fails-on-restart.target b/test/testsuite-03.units/fails-on-restart.target
|
||||
new file mode 100755
|
||||
index 0000000000..865fb2af44
|
||||
--- /dev/null
|
||||
+++ b/test/testsuite-03.units/fails-on-restart.target
|
||||
@@ -0,0 +1,3 @@
|
||||
+# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
+[Unit]
|
||||
+Requires=fails-on-restart.service
|
||||
diff --git a/test/testsuite-03.units/succeeds-on-restart-restartdirect.service b/test/testsuite-03.units/succeeds-on-restart-restartdirect.service
|
||||
new file mode 100755
|
||||
index 0000000000..b05f2f8dcf
|
||||
--- /dev/null
|
||||
+++ b/test/testsuite-03.units/succeeds-on-restart-restartdirect.service
|
||||
@@ -0,0 +1,6 @@
|
||||
+# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
+[Service]
|
||||
+Type=oneshot
|
||||
+ExecStart=/usr/lib/systemd/tests/testdata/testsuite-03.units/succeeds-on-restart.sh
|
||||
+Restart=on-failure
|
||||
+RestartMode=direct
|
||||
diff --git a/test/testsuite-03.units/succeeds-on-restart-restartdirect.target b/test/testsuite-03.units/succeeds-on-restart-restartdirect.target
|
||||
new file mode 100755
|
||||
index 0000000000..2cf3c60d2a
|
||||
--- /dev/null
|
||||
+++ b/test/testsuite-03.units/succeeds-on-restart-restartdirect.target
|
||||
@@ -0,0 +1,3 @@
|
||||
+# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
+[Unit]
|
||||
+Requires=succeeds-on-restart-restartdirect.service
|
||||
diff --git a/test/testsuite-03.units/succeeds-on-restart.service b/test/testsuite-03.units/succeeds-on-restart.service
|
||||
new file mode 100755
|
||||
index 0000000000..d7b3c7a210
|
||||
--- /dev/null
|
||||
+++ b/test/testsuite-03.units/succeeds-on-restart.service
|
||||
@@ -0,0 +1,6 @@
|
||||
+# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
+[Service]
|
||||
+Type=oneshot
|
||||
+ExecStart=/usr/lib/systemd/tests/testdata/testsuite-03.units/succeeds-on-restart.sh
|
||||
+Restart=on-failure
|
||||
+RestartMode=normal
|
||||
diff --git a/test/testsuite-03.units/succeeds-on-restart.sh b/test/testsuite-03.units/succeeds-on-restart.sh
|
||||
new file mode 100755
|
||||
index 0000000000..1428b186e5
|
||||
--- /dev/null
|
||||
+++ b/test/testsuite-03.units/succeeds-on-restart.sh
|
||||
@@ -0,0 +1,10 @@
|
||||
+#!/usr/bin/env bash
|
||||
+# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
+if [[ ! -f "/succeeds-on-restart.ko" ]]
|
||||
+then
|
||||
+ touch "/succeeds-on-restart.ko"
|
||||
+ exit 1
|
||||
+else
|
||||
+ rm "/succeeds-on-restart.ko"
|
||||
+ exit 0
|
||||
+fi
|
||||
diff --git a/test/testsuite-03.units/succeeds-on-restart.target b/test/testsuite-03.units/succeeds-on-restart.target
|
||||
new file mode 100755
|
||||
index 0000000000..eb82f47aa3
|
||||
--- /dev/null
|
||||
+++ b/test/testsuite-03.units/succeeds-on-restart.target
|
||||
@@ -0,0 +1,3 @@
|
||||
+# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
+[Unit]
|
||||
+Requires=succeeds-on-restart.service
|
||||
diff --git a/test/units/testsuite-03.sh b/test/units/testsuite-03.sh
|
||||
index 1d4bf3aaaa..ec51b20bf0 100755
|
||||
--- a/test/units/testsuite-03.sh
|
||||
+++ b/test/units/testsuite-03.sh
|
||||
@@ -110,4 +110,17 @@ ELAPSED=$((END_SEC-START_SEC))
|
||||
[[ "$ELAPSED" -ge 3 ]] && [[ "$ELAPSED" -le 5 ]] || exit 1
|
||||
[[ "$RESULT" -ne 0 ]] || exit 1
|
||||
|
||||
+# Test restart mode direct
|
||||
+systemctl start succeeds-on-restart-restartdirect.target
|
||||
+assert_rc 0 systemctl --quiet is-active succeeds-on-restart-restartdirect.target
|
||||
+
|
||||
+systemctl start fails-on-restart-restartdirect.target || :
|
||||
+assert_rc 3 systemctl --quiet is-active fails-on-restart-restartdirect.target
|
||||
+
|
||||
+systemctl start succeeds-on-restart.target || :
|
||||
+assert_rc 3 systemctl --quiet is-active succeeds-on-restart.target
|
||||
+
|
||||
+systemctl start fails-on-restart.target || :
|
||||
+assert_rc 3 systemctl --quiet is-active fails-on-restart.target
|
||||
+
|
||||
touch /testok
|
||||
37
1361-core-service-drop-unneeded-unit_add_to_gc_queue.patch
Normal file
37
1361-core-service-drop-unneeded-unit_add_to_gc_queue.patch
Normal file
@ -0,0 +1,37 @@
|
||||
From 01efd088ea54f56ec5e8c7077be2e05dc5b316e4 Mon Sep 17 00:00:00 2001
|
||||
From: Mike Yuan <me@yhndnzj.com>
|
||||
Date: Wed, 12 Feb 2025 17:38:47 +0100
|
||||
Subject: [PATCH] core/service: drop unneeded unit_add_to_gc_queue()
|
||||
|
||||
Follow-up for a1d315730ffddf283d4bb9d73878fbcd97a4d244
|
||||
and 6ac62d61db737b01ad3776a7688d8a4c57b3f7d9
|
||||
|
||||
With the aforementioned commits, unit_release_resources()
|
||||
is dispatched in a dedicated queue, and Service.n_keep_fd_store
|
||||
has been dropped, hence the comment is outdated. Moreover,
|
||||
the unit is added to GC queue in unit_notify() already.
|
||||
No other unit types do this in corresponding _enter_dead()
|
||||
functions, nor does Service need it anymore.
|
||||
|
||||
(cherry picked from commit 818315ae61370998a4df7b92d89c338c9442c6df)
|
||||
|
||||
Related: RHEL-137251
|
||||
---
|
||||
src/core/service.c | 4 ----
|
||||
1 file changed, 4 deletions(-)
|
||||
|
||||
diff --git a/src/core/service.c b/src/core/service.c
|
||||
index 96f419bb47..0da2af7c35 100644
|
||||
--- a/src/core/service.c
|
||||
+++ b/src/core/service.c
|
||||
@@ -1900,10 +1900,6 @@ static void service_enter_dead(Service *s, ServiceResult f, bool allow_restart)
|
||||
s->flush_n_restarts = true;
|
||||
}
|
||||
|
||||
- /* The new state is in effect, let's decrease the fd store ref counter again. Let's also re-add us to the GC
|
||||
- * queue, so that the fd store is possibly gc'ed again */
|
||||
- unit_add_to_gc_queue(UNIT(s));
|
||||
-
|
||||
/* The next restart might not be a manual stop, hence reset the flag indicating manual stops */
|
||||
s->forbid_restart = false;
|
||||
|
||||
119
1362-core-get-rid-of-unused-Service.will_auto_restart-log.patch
Normal file
119
1362-core-get-rid-of-unused-Service.will_auto_restart-log.patch
Normal file
@ -0,0 +1,119 @@
|
||||
From 3907ede0d5bcb7e514b4875b8c01d67ea761a412 Mon Sep 17 00:00:00 2001
|
||||
From: Mike Yuan <me@yhndnzj.com>
|
||||
Date: Mon, 22 May 2023 08:30:30 +0800
|
||||
Subject: [PATCH] core: get rid of unused Service.will_auto_restart logic
|
||||
|
||||
The announced new behavior for OnFailure= never worked properly,
|
||||
and we've fixed the document instead in #27675.
|
||||
Therefore, let's get rid of the unused logic completely. More at #27594.
|
||||
|
||||
The to-be-added RestartMode= option should cover the use case hopefully.
|
||||
|
||||
Closes #27594
|
||||
|
||||
(cherry picked from commit 49b34f75e7c801210624e0c7dd00be990873628a)
|
||||
|
||||
Resolves: RHEL-118224
|
||||
---
|
||||
src/core/service.c | 16 ++++------------
|
||||
src/core/service.h | 2 --
|
||||
src/core/unit.c | 7 ++-----
|
||||
src/core/unit.h | 1 -
|
||||
4 files changed, 6 insertions(+), 20 deletions(-)
|
||||
|
||||
diff --git a/src/core/service.c b/src/core/service.c
|
||||
index 0da2af7c35..55e8bf5182 100644
|
||||
--- a/src/core/service.c
|
||||
+++ b/src/core/service.c
|
||||
@@ -1160,8 +1160,7 @@ static void service_set_state(Service *s, ServiceState state) {
|
||||
log_unit_debug(UNIT(s), "Changed %s -> %s", service_state_to_string(old_state), service_state_to_string(state));
|
||||
|
||||
unit_notify(UNIT(s), table[old_state], table[state],
|
||||
- (s->reload_result == SERVICE_SUCCESS ? 0 : UNIT_NOTIFY_RELOAD_FAILURE) |
|
||||
- (s->will_auto_restart ? UNIT_NOTIFY_WILL_AUTO_RESTART : 0));
|
||||
+ s->reload_result == SERVICE_SUCCESS ? 0 : UNIT_NOTIFY_RELOAD_FAILURE);
|
||||
}
|
||||
|
||||
static usec_t service_coldplug_timeout(Service *s) {
|
||||
@@ -1823,8 +1822,6 @@ static bool service_will_restart(Unit *u) {
|
||||
|
||||
assert(s);
|
||||
|
||||
- if (s->will_auto_restart)
|
||||
- return true;
|
||||
if (IN_SET(s->state, SERVICE_DEAD_BEFORE_AUTO_RESTART, SERVICE_FAILED_BEFORE_AUTO_RESTART, SERVICE_AUTO_RESTART))
|
||||
return true;
|
||||
|
||||
@@ -1864,19 +1861,14 @@ static void service_enter_dead(Service *s, ServiceResult f, bool allow_restart)
|
||||
log_unit_debug(UNIT(s), "Service restart not allowed.");
|
||||
else {
|
||||
const char *reason;
|
||||
- bool shall_restart;
|
||||
|
||||
- shall_restart = service_shall_restart(s, &reason);
|
||||
+ allow_restart = service_shall_restart(s, &reason);
|
||||
log_unit_debug(UNIT(s), "Service will %srestart (%s)",
|
||||
- shall_restart ? "" : "not ",
|
||||
+ allow_restart ? "" : "not ",
|
||||
reason);
|
||||
- if (shall_restart)
|
||||
- s->will_auto_restart = true;
|
||||
}
|
||||
|
||||
- if (s->will_auto_restart) {
|
||||
- s->will_auto_restart = false;
|
||||
-
|
||||
+ if (allow_restart) {
|
||||
/* We make two state changes here: one that maps to the high-level UNIT_INACTIVE/UNIT_FAILED
|
||||
* state (i.e. a state indicating deactivation), and then one that that maps to the
|
||||
* high-level UNIT_STARTING state (i.e. a state indicating activation). We do this so that
|
||||
diff --git a/src/core/service.h b/src/core/service.h
|
||||
index bfbb3261a8..0ca04caf24 100644
|
||||
--- a/src/core/service.h
|
||||
+++ b/src/core/service.h
|
||||
@@ -187,8 +187,6 @@ struct Service {
|
||||
bool main_pid_alien:1;
|
||||
bool bus_name_good:1;
|
||||
bool forbid_restart:1;
|
||||
- /* Keep restart intention between UNIT_FAILED and UNIT_ACTIVATING */
|
||||
- bool will_auto_restart:1;
|
||||
bool start_timeout_defined:1;
|
||||
bool exec_fd_hot:1;
|
||||
|
||||
diff --git a/src/core/unit.c b/src/core/unit.c
|
||||
index 0b58d0498b..c076b5126f 100644
|
||||
--- a/src/core/unit.c
|
||||
+++ b/src/core/unit.c
|
||||
@@ -2703,9 +2703,7 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, UnitNotifyFlag
|
||||
|
||||
if (ns != os && ns == UNIT_FAILED) {
|
||||
log_unit_debug(u, "Unit entered failed state.");
|
||||
-
|
||||
- if (!(flags & UNIT_NOTIFY_WILL_AUTO_RESTART))
|
||||
- unit_start_on_failure(u, "OnFailure=", UNIT_ATOM_ON_FAILURE, u->on_failure_job_mode);
|
||||
+ unit_start_on_failure(u, "OnFailure=", UNIT_ATOM_ON_FAILURE, u->on_failure_job_mode);
|
||||
}
|
||||
|
||||
if (UNIT_IS_ACTIVE_OR_RELOADING(ns) && !UNIT_IS_ACTIVE_OR_RELOADING(os)) {
|
||||
@@ -2722,8 +2720,7 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, UnitNotifyFlag
|
||||
unit_log_resources(u);
|
||||
}
|
||||
|
||||
- if (ns == UNIT_INACTIVE && !IN_SET(os, UNIT_FAILED, UNIT_INACTIVE, UNIT_MAINTENANCE) &&
|
||||
- !(flags & UNIT_NOTIFY_WILL_AUTO_RESTART))
|
||||
+ if (ns == UNIT_INACTIVE && !IN_SET(os, UNIT_FAILED, UNIT_INACTIVE, UNIT_MAINTENANCE))
|
||||
unit_start_on_failure(u, "OnSuccess=", UNIT_ATOM_ON_SUCCESS, u->on_success_job_mode);
|
||||
}
|
||||
|
||||
diff --git a/src/core/unit.h b/src/core/unit.h
|
||||
index acbf74477e..77cc429803 100644
|
||||
--- a/src/core/unit.h
|
||||
+++ b/src/core/unit.h
|
||||
@@ -903,7 +903,6 @@ void unit_notify_cgroup_oom(Unit *u, bool managed_oom);
|
||||
|
||||
typedef enum UnitNotifyFlags {
|
||||
UNIT_NOTIFY_RELOAD_FAILURE = 1 << 0,
|
||||
- UNIT_NOTIFY_WILL_AUTO_RESTART = 1 << 1,
|
||||
} UnitNotifyFlags;
|
||||
|
||||
void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, UnitNotifyFlags flags);
|
||||
239
1363-core-drop-UnitNotifyFlags.patch
Normal file
239
1363-core-drop-UnitNotifyFlags.patch
Normal file
@ -0,0 +1,239 @@
|
||||
From 762a8cff390322bb578b5844326a2b654e9d2c23 Mon Sep 17 00:00:00 2001
|
||||
From: Mike Yuan <me@yhndnzj.com>
|
||||
Date: Mon, 22 May 2023 08:35:53 +0800
|
||||
Subject: [PATCH] core: drop UnitNotifyFlags
|
||||
|
||||
This essentially reverts 2ad2e41a72ec19159c0746a78e15ff880fe32a63.
|
||||
|
||||
No longer needed after dropping UNIT_NOTIFY_WILL_AUTO_RESTART.
|
||||
|
||||
(cherry picked from commit 96b09de500f9d658b2e49abf3be15e06f9bd1ca6)
|
||||
|
||||
Related: RHEL-118224
|
||||
---
|
||||
src/core/automount.c | 2 +-
|
||||
src/core/device.c | 2 +-
|
||||
src/core/mount.c | 3 +--
|
||||
src/core/path.c | 2 +-
|
||||
src/core/scope.c | 2 +-
|
||||
src/core/service.c | 3 +--
|
||||
src/core/slice.c | 2 +-
|
||||
src/core/socket.c | 2 +-
|
||||
src/core/swap.c | 2 +-
|
||||
src/core/target.c | 2 +-
|
||||
src/core/timer.c | 2 +-
|
||||
src/core/unit.c | 10 +++++-----
|
||||
src/core/unit.h | 6 +-----
|
||||
13 files changed, 17 insertions(+), 23 deletions(-)
|
||||
|
||||
diff --git a/src/core/automount.c b/src/core/automount.c
|
||||
index ae8399d1af..f559454a88 100644
|
||||
--- a/src/core/automount.c
|
||||
+++ b/src/core/automount.c
|
||||
@@ -283,7 +283,7 @@ static void automount_set_state(Automount *a, AutomountState state) {
|
||||
if (state != old_state)
|
||||
log_unit_debug(UNIT(a), "Changed %s -> %s", automount_state_to_string(old_state), automount_state_to_string(state));
|
||||
|
||||
- unit_notify(UNIT(a), state_translation_table[old_state], state_translation_table[state], 0);
|
||||
+ unit_notify(UNIT(a), state_translation_table[old_state], state_translation_table[state], /* reload_success = */ true);
|
||||
}
|
||||
|
||||
static int automount_coldplug(Unit *u) {
|
||||
diff --git a/src/core/device.c b/src/core/device.c
|
||||
index f007bdfd9b..31f014d94b 100644
|
||||
--- a/src/core/device.c
|
||||
+++ b/src/core/device.c
|
||||
@@ -174,7 +174,7 @@ static void device_set_state(Device *d, DeviceState state) {
|
||||
if (state != old_state)
|
||||
log_unit_debug(UNIT(d), "Changed %s -> %s", device_state_to_string(old_state), device_state_to_string(state));
|
||||
|
||||
- unit_notify(UNIT(d), state_translation_table[old_state], state_translation_table[state], 0);
|
||||
+ unit_notify(UNIT(d), state_translation_table[old_state], state_translation_table[state], /* reload_success = */ true);
|
||||
}
|
||||
|
||||
static void device_found_changed(Device *d, DeviceFound previous, DeviceFound now) {
|
||||
diff --git a/src/core/mount.c b/src/core/mount.c
|
||||
index 5789a253cd..1a6aca0aa8 100644
|
||||
--- a/src/core/mount.c
|
||||
+++ b/src/core/mount.c
|
||||
@@ -753,8 +753,7 @@ static void mount_set_state(Mount *m, MountState state) {
|
||||
if (state != old_state)
|
||||
log_unit_debug(UNIT(m), "Changed %s -> %s", mount_state_to_string(old_state), mount_state_to_string(state));
|
||||
|
||||
- unit_notify(UNIT(m), state_translation_table[old_state], state_translation_table[state],
|
||||
- m->reload_result == MOUNT_SUCCESS ? 0 : UNIT_NOTIFY_RELOAD_FAILURE);
|
||||
+ unit_notify(UNIT(m), state_translation_table[old_state], state_translation_table[state], m->reload_result == MOUNT_SUCCESS);
|
||||
}
|
||||
|
||||
static int mount_coldplug(Unit *u) {
|
||||
diff --git a/src/core/path.c b/src/core/path.c
|
||||
index 6f850244f1..6b548d40bc 100644
|
||||
--- a/src/core/path.c
|
||||
+++ b/src/core/path.c
|
||||
@@ -475,7 +475,7 @@ static void path_set_state(Path *p, PathState state) {
|
||||
if (state != old_state)
|
||||
log_unit_debug(UNIT(p), "Changed %s -> %s", path_state_to_string(old_state), path_state_to_string(state));
|
||||
|
||||
- unit_notify(UNIT(p), state_translation_table[old_state], state_translation_table[state], 0);
|
||||
+ unit_notify(UNIT(p), state_translation_table[old_state], state_translation_table[state], /* reload_success = */ true);
|
||||
}
|
||||
|
||||
static void path_enter_waiting(Path *p, bool initial, bool from_trigger_notify);
|
||||
diff --git a/src/core/scope.c b/src/core/scope.c
|
||||
index 4e1a954c6c..1be18c21d6 100644
|
||||
--- a/src/core/scope.c
|
||||
+++ b/src/core/scope.c
|
||||
@@ -126,7 +126,7 @@ static void scope_set_state(Scope *s, ScopeState state) {
|
||||
if (state != old_state)
|
||||
log_debug("%s changed %s -> %s", UNIT(s)->id, scope_state_to_string(old_state), scope_state_to_string(state));
|
||||
|
||||
- unit_notify(UNIT(s), state_translation_table[old_state], state_translation_table[state], 0);
|
||||
+ unit_notify(UNIT(s), state_translation_table[old_state], state_translation_table[state], /* reload_success = */ true);
|
||||
}
|
||||
|
||||
static int scope_add_default_dependencies(Scope *s) {
|
||||
diff --git a/src/core/service.c b/src/core/service.c
|
||||
index 55e8bf5182..a3c6b1380f 100644
|
||||
--- a/src/core/service.c
|
||||
+++ b/src/core/service.c
|
||||
@@ -1159,8 +1159,7 @@ static void service_set_state(Service *s, ServiceState state) {
|
||||
if (old_state != state)
|
||||
log_unit_debug(UNIT(s), "Changed %s -> %s", service_state_to_string(old_state), service_state_to_string(state));
|
||||
|
||||
- unit_notify(UNIT(s), table[old_state], table[state],
|
||||
- s->reload_result == SERVICE_SUCCESS ? 0 : UNIT_NOTIFY_RELOAD_FAILURE);
|
||||
+ unit_notify(UNIT(s), table[old_state], table[state], s->reload_result == SERVICE_SUCCESS);
|
||||
}
|
||||
|
||||
static usec_t service_coldplug_timeout(Service *s) {
|
||||
diff --git a/src/core/slice.c b/src/core/slice.c
|
||||
index 8f913a8d45..cb6670ff45 100644
|
||||
--- a/src/core/slice.c
|
||||
+++ b/src/core/slice.c
|
||||
@@ -43,7 +43,7 @@ static void slice_set_state(Slice *t, SliceState state) {
|
||||
slice_state_to_string(old_state),
|
||||
slice_state_to_string(state));
|
||||
|
||||
- unit_notify(UNIT(t), state_translation_table[old_state], state_translation_table[state], 0);
|
||||
+ unit_notify(UNIT(t), state_translation_table[old_state], state_translation_table[state], /* reload_success = */ true);
|
||||
}
|
||||
|
||||
static int slice_add_parent_slice(Slice *s) {
|
||||
diff --git a/src/core/socket.c b/src/core/socket.c
|
||||
index ebb83cd5b0..c916ff7ee5 100644
|
||||
--- a/src/core/socket.c
|
||||
+++ b/src/core/socket.c
|
||||
@@ -1838,7 +1838,7 @@ static void socket_set_state(Socket *s, SocketState state) {
|
||||
if (state != old_state)
|
||||
log_unit_debug(UNIT(s), "Changed %s -> %s", socket_state_to_string(old_state), socket_state_to_string(state));
|
||||
|
||||
- unit_notify(UNIT(s), state_translation_table[old_state], state_translation_table[state], 0);
|
||||
+ unit_notify(UNIT(s), state_translation_table[old_state], state_translation_table[state], /* reload_success = */ true);
|
||||
}
|
||||
|
||||
static int socket_coldplug(Unit *u) {
|
||||
diff --git a/src/core/swap.c b/src/core/swap.c
|
||||
index 458c935b0c..535657d3b5 100644
|
||||
--- a/src/core/swap.c
|
||||
+++ b/src/core/swap.c
|
||||
@@ -586,7 +586,7 @@ static void swap_set_state(Swap *s, SwapState state) {
|
||||
if (state != old_state)
|
||||
log_unit_debug(UNIT(s), "Changed %s -> %s", swap_state_to_string(old_state), swap_state_to_string(state));
|
||||
|
||||
- unit_notify(UNIT(s), state_translation_table[old_state], state_translation_table[state], 0);
|
||||
+ unit_notify(UNIT(s), state_translation_table[old_state], state_translation_table[state], /* reload_success = */ true);
|
||||
|
||||
/* If there other units for the same device node have a job
|
||||
queued it might be worth checking again if it is runnable
|
||||
diff --git a/src/core/target.c b/src/core/target.c
|
||||
index 6225df5b0d..3519b4b653 100644
|
||||
--- a/src/core/target.c
|
||||
+++ b/src/core/target.c
|
||||
@@ -31,7 +31,7 @@ static void target_set_state(Target *t, TargetState state) {
|
||||
target_state_to_string(old_state),
|
||||
target_state_to_string(state));
|
||||
|
||||
- unit_notify(UNIT(t), state_translation_table[old_state], state_translation_table[state], 0);
|
||||
+ unit_notify(UNIT(t), state_translation_table[old_state], state_translation_table[state], /* reload_success = */ true);
|
||||
}
|
||||
|
||||
static int target_add_default_dependencies(Target *t) {
|
||||
diff --git a/src/core/timer.c b/src/core/timer.c
|
||||
index b96e88af90..310bc79903 100644
|
||||
--- a/src/core/timer.c
|
||||
+++ b/src/core/timer.c
|
||||
@@ -298,7 +298,7 @@ static void timer_set_state(Timer *t, TimerState state) {
|
||||
if (state != old_state)
|
||||
log_unit_debug(UNIT(t), "Changed %s -> %s", timer_state_to_string(old_state), timer_state_to_string(state));
|
||||
|
||||
- unit_notify(UNIT(t), state_translation_table[old_state], state_translation_table[state], 0);
|
||||
+ unit_notify(UNIT(t), state_translation_table[old_state], state_translation_table[state], /* reload_success = */ true);
|
||||
}
|
||||
|
||||
static void timer_enter_waiting(Timer *t, bool time_change);
|
||||
diff --git a/src/core/unit.c b/src/core/unit.c
|
||||
index c076b5126f..53098c5b08 100644
|
||||
--- a/src/core/unit.c
|
||||
+++ b/src/core/unit.c
|
||||
@@ -2017,7 +2017,7 @@ int unit_reload(Unit *u) {
|
||||
|
||||
if (!UNIT_VTABLE(u)->reload) {
|
||||
/* Unit doesn't have a reload function, but we need to propagate the reload anyway */
|
||||
- unit_notify(u, unit_active_state(u), unit_active_state(u), 0);
|
||||
+ unit_notify(u, unit_active_state(u), unit_active_state(u), /* reload_success = */ true);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -2547,7 +2547,7 @@ static void unit_emit_audit_stop(Unit *u, UnitActiveState state) {
|
||||
}
|
||||
}
|
||||
|
||||
-static bool unit_process_job(Job *j, UnitActiveState ns, UnitNotifyFlags flags) {
|
||||
+static bool unit_process_job(Job *j, UnitActiveState ns, bool reload_success) {
|
||||
bool unexpected = false;
|
||||
JobResult result;
|
||||
|
||||
@@ -2590,7 +2590,7 @@ static bool unit_process_job(Job *j, UnitActiveState ns, UnitNotifyFlags flags)
|
||||
|
||||
if (j->state == JOB_RUNNING) {
|
||||
if (ns == UNIT_ACTIVE)
|
||||
- job_finish_and_invalidate(j, (flags & UNIT_NOTIFY_RELOAD_FAILURE) ? JOB_FAILED : JOB_DONE, true, false);
|
||||
+ job_finish_and_invalidate(j, reload_success ? JOB_DONE : JOB_FAILED, true, false);
|
||||
else if (!IN_SET(ns, UNIT_ACTIVATING, UNIT_RELOADING)) {
|
||||
unexpected = true;
|
||||
|
||||
@@ -2621,7 +2621,7 @@ static bool unit_process_job(Job *j, UnitActiveState ns, UnitNotifyFlags flags)
|
||||
return unexpected;
|
||||
}
|
||||
|
||||
-void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, UnitNotifyFlags flags) {
|
||||
+void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_success) {
|
||||
const char *reason;
|
||||
Manager *m;
|
||||
|
||||
@@ -2686,7 +2686,7 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, UnitNotifyFlag
|
||||
|
||||
/* Let's propagate state changes to the job */
|
||||
if (u->job)
|
||||
- unexpected = unit_process_job(u->job, ns, flags);
|
||||
+ unexpected = unit_process_job(u->job, ns, reload_success);
|
||||
else
|
||||
unexpected = true;
|
||||
|
||||
diff --git a/src/core/unit.h b/src/core/unit.h
|
||||
index 77cc429803..08969d4cb9 100644
|
||||
--- a/src/core/unit.h
|
||||
+++ b/src/core/unit.h
|
||||
@@ -901,11 +901,7 @@ int unit_kill_common(Unit *u, KillWho who, int signo, pid_t main_pid, pid_t cont
|
||||
|
||||
void unit_notify_cgroup_oom(Unit *u, bool managed_oom);
|
||||
|
||||
-typedef enum UnitNotifyFlags {
|
||||
- UNIT_NOTIFY_RELOAD_FAILURE = 1 << 0,
|
||||
-} UnitNotifyFlags;
|
||||
-
|
||||
-void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, UnitNotifyFlags flags);
|
||||
+void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_success);
|
||||
|
||||
int unit_watch_pid(Unit *u, pid_t pid, bool exclusive);
|
||||
void unit_unwatch_pid(Unit *u, pid_t pid);
|
||||
128
1364-core-split-out-the-helper-to-serialize-deserialize-r.patch
Normal file
128
1364-core-split-out-the-helper-to-serialize-deserialize-r.patch
Normal file
@ -0,0 +1,128 @@
|
||||
From b8dabd7117205eadc185c9b86fcaa10e1d0e5f84 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
|
||||
Date: Wed, 15 Nov 2023 17:17:12 +0100
|
||||
Subject: [PATCH] core: split out the helper to serialize/deserialize
|
||||
ratelimits
|
||||
|
||||
(cherry picked from commit 07a6647abbd74288a00b1b8f17ec9a9cce080ae4)
|
||||
|
||||
Related: RHEL-213655
|
||||
---
|
||||
src/core/manager-serialize.c | 23 ++---------------------
|
||||
src/shared/serialize.c | 27 +++++++++++++++++++++++++++
|
||||
src/shared/serialize.h | 3 +++
|
||||
3 files changed, 32 insertions(+), 21 deletions(-)
|
||||
|
||||
diff --git a/src/core/manager-serialize.c b/src/core/manager-serialize.c
|
||||
index a87d490219..74853181b7 100644
|
||||
--- a/src/core/manager-serialize.c
|
||||
+++ b/src/core/manager-serialize.c
|
||||
@@ -164,13 +164,7 @@ int manager_serialize(
|
||||
(void) serialize_item_format(f, "user-lookup", "%i %i", copy0, copy1);
|
||||
}
|
||||
|
||||
- (void) serialize_item_format(f,
|
||||
- "dump-ratelimit",
|
||||
- USEC_FMT " " USEC_FMT " %u %u",
|
||||
- m->dump_ratelimit.begin,
|
||||
- m->dump_ratelimit.interval,
|
||||
- m->dump_ratelimit.num,
|
||||
- m->dump_ratelimit.burst);
|
||||
+ (void) serialize_ratelimit(f, "dump-ratelimit", &m->dump_ratelimit);
|
||||
|
||||
bus_track_serialize(m->subscribed, f, "subscribed");
|
||||
|
||||
@@ -558,20 +552,7 @@ int manager_deserialize(Manager *m, FILE *f, FDSet *fds) {
|
||||
if (deserialize_varlink_sockets)
|
||||
(void) varlink_server_deserialize_one(m->varlink_server, val, fds);
|
||||
} else if ((val = startswith(l, "dump-ratelimit="))) {
|
||||
- usec_t begin, interval;
|
||||
- unsigned num, burst;
|
||||
-
|
||||
- if (sscanf(val, USEC_FMT " " USEC_FMT " %u %u", &begin, &interval, &num, &burst) != 4)
|
||||
- log_notice("Failed to parse dump ratelimit, ignoring: %s", val);
|
||||
- else {
|
||||
- /* If we changed the values across versions, flush the counter */
|
||||
- if (interval != m->dump_ratelimit.interval || burst != m->dump_ratelimit.burst)
|
||||
- m->dump_ratelimit.num = 0;
|
||||
- else
|
||||
- m->dump_ratelimit.num = num;
|
||||
- m->dump_ratelimit.begin = begin;
|
||||
- }
|
||||
-
|
||||
+ deserialize_ratelimit(&m->dump_ratelimit, "dump-ratelimit", val);
|
||||
} else {
|
||||
ManagerTimestamp q;
|
||||
|
||||
diff --git a/src/shared/serialize.c b/src/shared/serialize.c
|
||||
index cd48286355..5c73fc5f8e 100644
|
||||
--- a/src/shared/serialize.c
|
||||
+++ b/src/shared/serialize.c
|
||||
@@ -130,6 +130,17 @@ int serialize_strv(FILE *f, const char *key, char **l) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
+int serialize_ratelimit(FILE *f, const char *key, const RateLimit *rl) {
|
||||
+ assert(rl);
|
||||
+
|
||||
+ return serialize_item_format(f, key,
|
||||
+ USEC_FMT " " USEC_FMT " %u %u",
|
||||
+ rl->begin,
|
||||
+ rl->interval,
|
||||
+ rl->num,
|
||||
+ rl->burst);
|
||||
+}
|
||||
+
|
||||
int deserialize_usec(const char *value, usec_t *ret) {
|
||||
int r;
|
||||
|
||||
@@ -194,6 +205,22 @@ int deserialize_environment(const char *value, char ***list) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
+void deserialize_ratelimit(RateLimit *rl, const char *name, const char *value) {
|
||||
+ usec_t begin, interval;
|
||||
+ unsigned num, burst;
|
||||
+
|
||||
+ assert(rl);
|
||||
+ assert(name);
|
||||
+ assert(value);
|
||||
+
|
||||
+ if (sscanf(value, USEC_FMT " " USEC_FMT " %u %u", &begin, &interval, &num, &burst) != 4)
|
||||
+ return log_notice("Failed to parse %s, ignoring: %s", name, value);
|
||||
+
|
||||
+ /* Preserve the counter only if the configuration didn't change. */
|
||||
+ rl->num = (interval == rl->interval && burst == rl->burst) ? num : 0;
|
||||
+ rl->begin = begin;
|
||||
+}
|
||||
+
|
||||
int open_serialization_fd(const char *ident) {
|
||||
int fd;
|
||||
|
||||
diff --git a/src/shared/serialize.h b/src/shared/serialize.h
|
||||
index 6d4f1ef418..3fc1e60911 100644
|
||||
--- a/src/shared/serialize.h
|
||||
+++ b/src/shared/serialize.h
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
#include "fdset.h"
|
||||
#include "macro.h"
|
||||
+#include "ratelimit.h"
|
||||
#include "string-util.h"
|
||||
#include "time-util.h"
|
||||
|
||||
@@ -15,6 +16,7 @@ int serialize_fd(FILE *f, FDSet *fds, const char *key, int fd);
|
||||
int serialize_usec(FILE *f, const char *key, usec_t usec);
|
||||
int serialize_dual_timestamp(FILE *f, const char *key, const dual_timestamp *t);
|
||||
int serialize_strv(FILE *f, const char *key, char **l);
|
||||
+int serialize_ratelimit(FILE *f, const char *key, const RateLimit *rl);
|
||||
|
||||
static inline int serialize_bool(FILE *f, const char *key, bool b) {
|
||||
return serialize_item(f, key, yes_no(b));
|
||||
@@ -23,5 +25,6 @@ static inline int serialize_bool(FILE *f, const char *key, bool b) {
|
||||
int deserialize_usec(const char *value, usec_t *timestamp);
|
||||
int deserialize_dual_timestamp(const char *value, dual_timestamp *t);
|
||||
int deserialize_environment(const char *value, char ***environment);
|
||||
+void deserialize_ratelimit(RateLimit *rl, const char *name, const char *value);
|
||||
|
||||
int open_serialization_fd(const char *ident);
|
||||
244
1365-core-make-manager-event-loop-rate-limit-configurable.patch
Normal file
244
1365-core-make-manager-event-loop-rate-limit-configurable.patch
Normal file
@ -0,0 +1,244 @@
|
||||
From 9d258e84de4235fe807990782752f8b9d8e54c59 Mon Sep 17 00:00:00 2001
|
||||
From: Michal Sekletar <msekleta@redhat.com>
|
||||
Date: Wed, 13 May 2026 16:20:55 +0200
|
||||
Subject: [PATCH] core: make manager event loop rate limit configurable
|
||||
|
||||
Co-developed-by: Claude Opus 4.6 <noreply@anthropic.com>
|
||||
(cherry picked from commit e1c63fd4c0657a7fc7b749c64283ab4dbc6fb39e)
|
||||
|
||||
Resolves: RHEL-213655
|
||||
---
|
||||
man/org.freedesktop.systemd1.xml | 12 ++++++++++++
|
||||
man/systemd-system.conf.xml | 15 +++++++++++++++
|
||||
src/core/dbus-manager.c | 2 ++
|
||||
src/core/main.c | 31 +++++++++++++++++++++++++++++++
|
||||
src/core/manager-serialize.c | 4 ++++
|
||||
src/core/manager.c | 3 +--
|
||||
src/core/manager.h | 3 +++
|
||||
src/core/system.conf.in | 2 ++
|
||||
src/core/user.conf.in | 2 ++
|
||||
9 files changed, 72 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/man/org.freedesktop.systemd1.xml b/man/org.freedesktop.systemd1.xml
|
||||
index 8298b726b7..51e017bf10 100644
|
||||
--- a/man/org.freedesktop.systemd1.xml
|
||||
+++ b/man/org.freedesktop.systemd1.xml
|
||||
@@ -524,6 +524,10 @@ node /org/freedesktop/systemd1 {
|
||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
|
||||
readonly t DefaultTasksMax = ...;
|
||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||
+ readonly t EventLoopRateLimitIntervalUSec = ...;
|
||||
+ @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||
+ readonly u EventLoopRateLimitBurst = ...;
|
||||
+ @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||
readonly t TimerSlackNSec = ...;
|
||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||
readonly s DefaultOOMPolicy = '...';
|
||||
@@ -776,6 +780,10 @@ node /org/freedesktop/systemd1 {
|
||||
|
||||
<!--property DefaultTasksMax is not documented!-->
|
||||
|
||||
+ <!--property EventLoopRateLimitIntervalUSec is not documented!-->
|
||||
+
|
||||
+ <!--property EventLoopRateLimitBurst is not documented!-->
|
||||
+
|
||||
<!--property TimerSlackNSec is not documented!-->
|
||||
|
||||
<!--property DefaultOOMPolicy is not documented!-->
|
||||
@@ -1200,6 +1208,10 @@ node /org/freedesktop/systemd1 {
|
||||
|
||||
<variablelist class="dbus-property" generated="True" extra-ref="DefaultTasksMax"/>
|
||||
|
||||
+ <variablelist class="dbus-property" generated="True" extra-ref="EventLoopRateLimitIntervalUSec"/>
|
||||
+
|
||||
+ <variablelist class="dbus-property" generated="True" extra-ref="EventLoopRateLimitBurst"/>
|
||||
+
|
||||
<variablelist class="dbus-property" generated="True" extra-ref="TimerSlackNSec"/>
|
||||
|
||||
<variablelist class="dbus-property" generated="True" extra-ref="DefaultOOMPolicy"/>
|
||||
diff --git a/man/systemd-system.conf.xml b/man/systemd-system.conf.xml
|
||||
index 00de04d426..e563be8615 100644
|
||||
--- a/man/systemd-system.conf.xml
|
||||
+++ b/man/systemd-system.conf.xml
|
||||
@@ -550,6 +550,21 @@
|
||||
<para>If the value is <literal>/</literal>, only labels specified with <varname>SmackProcessLabel=</varname>
|
||||
are assigned and the compile-time default is ignored.</para></listitem>
|
||||
</varlistentry>
|
||||
+
|
||||
+ <varlistentry>
|
||||
+ <term><varname>EventLoopRateLimitIntervalSec=</varname></term>
|
||||
+ <term><varname>EventLoopRateLimitBurst=</varname></term>
|
||||
+
|
||||
+ <listitem><para>Configures the rate limiting applied to the manager's main event loop. If the event
|
||||
+ loop iterates more than <varname>EventLoopRateLimitBurst=</varname> times within
|
||||
+ <varname>EventLoopRateLimitIntervalSec=</varname>, event processing is briefly paused to prevent
|
||||
+ excessive CPU usage. <varname>EventLoopRateLimitIntervalSec=</varname> defaults to 1s.
|
||||
+ <varname>EventLoopRateLimitBurst=</varname> defaults to 50000. These settings can also be set on the
|
||||
+ kernel command line via
|
||||
+ <varname>systemd.event_loop_ratelimit_interval_sec=</varname> and
|
||||
+ <varname>systemd.event_loop_ratelimit_burst=</varname>.</para></listitem>
|
||||
+ </varlistentry>
|
||||
+
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c
|
||||
index 16c9680d80..2537c4adf8 100644
|
||||
--- a/src/core/dbus-manager.c
|
||||
+++ b/src/core/dbus-manager.c
|
||||
@@ -2911,6 +2911,8 @@ const sd_bus_vtable bus_manager_vtable[] = {
|
||||
SD_BUS_PROPERTY("DefaultLimitRTTIME", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_RTTIME]), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("DefaultLimitRTTIMESoft", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_RTTIME]), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("DefaultTasksMax", "t", bus_property_get_tasks_max, offsetof(Manager, default_tasks_max), 0),
|
||||
+ SD_BUS_PROPERTY("EventLoopRateLimitIntervalUSec", "t", bus_property_get_usec, offsetof(Manager, event_loop_ratelimit.interval), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
+ SD_BUS_PROPERTY("EventLoopRateLimitBurst", "u", bus_property_get_unsigned, offsetof(Manager, event_loop_ratelimit.burst), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("TimerSlackNSec", "t", property_get_timer_slack_nsec, 0, SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("DefaultOOMPolicy", "s", bus_property_get_oom_policy, offsetof(Manager, default_oom_policy), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("DefaultOOMScoreAdjust", "i", property_get_oom_score_adjust, 0, SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
diff --git a/src/core/main.c b/src/core/main.c
|
||||
index 18f5781126..1e45ed6bd6 100644
|
||||
--- a/src/core/main.c
|
||||
+++ b/src/core/main.c
|
||||
@@ -173,6 +173,8 @@ static size_t arg_random_seed_size;
|
||||
static int arg_default_oom_score_adjust;
|
||||
static bool arg_default_oom_score_adjust_set;
|
||||
static char *arg_default_smack_process_label;
|
||||
+static usec_t arg_event_loop_ratelimit_interval_sec;
|
||||
+static unsigned arg_event_loop_ratelimit_burst;
|
||||
|
||||
/* A copy of the original environment block */
|
||||
static char **saved_env = NULL;
|
||||
@@ -483,6 +485,28 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat
|
||||
arg_random_seed = sz > 0 ? p : mfree(p);
|
||||
arg_random_seed_size = sz;
|
||||
|
||||
+ } else if (proc_cmdline_key_streq(key, "systemd.event_loop_ratelimit_interval_sec")) {
|
||||
+
|
||||
+ if (proc_cmdline_value_missing(key, value))
|
||||
+ return 0;
|
||||
+
|
||||
+ r = parse_sec(value, &arg_event_loop_ratelimit_interval_sec);
|
||||
+ if (r < 0) {
|
||||
+ log_warning_errno(r, "Failed to parse systemd.event_loop_ratelimit_interval_sec= argument '%s', ignoring: %m", value);
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
+ } else if (proc_cmdline_key_streq(key, "systemd.event_loop_ratelimit_burst")) {
|
||||
+
|
||||
+ if (proc_cmdline_value_missing(key, value))
|
||||
+ return 0;
|
||||
+
|
||||
+ r = safe_atou(value, &arg_event_loop_ratelimit_burst);
|
||||
+ if (r < 0) {
|
||||
+ log_warning_errno(r, "Failed to parse systemd.event_loop_ratelimit_burst= argument '%s', ignoring: %m", value);
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
} else if (streq(key, "quiet") && !value) {
|
||||
|
||||
if (arg_show_status == _SHOW_STATUS_INVALID)
|
||||
@@ -662,6 +686,8 @@ static int parse_config_file(void) {
|
||||
{ "Manager", "CtrlAltDelBurstAction", config_parse_emergency_action, arg_runtime_scope, &arg_cad_burst_action },
|
||||
{ "Manager", "DefaultOOMPolicy", config_parse_oom_policy, 0, &arg_default_oom_policy },
|
||||
{ "Manager", "DefaultOOMScoreAdjust", config_parse_oom_score_adjust, 0, NULL },
|
||||
+ { "Manager", "EventLoopRateLimitIntervalSec", config_parse_sec, 0, &arg_event_loop_ratelimit_interval_sec },
|
||||
+ { "Manager", "EventLoopRateLimitBurst", config_parse_unsigned, 0, &arg_event_loop_ratelimit_burst },
|
||||
#if ENABLE_SMACK
|
||||
{ "Manager", "DefaultSmackProcessLabel", config_parse_string, 0, &arg_default_smack_process_label },
|
||||
#else
|
||||
@@ -764,6 +790,8 @@ static void set_manager_settings(Manager *m) {
|
||||
m->confirm_spawn = arg_confirm_spawn;
|
||||
m->service_watchdogs = arg_service_watchdogs;
|
||||
m->cad_burst_action = arg_cad_burst_action;
|
||||
+ m->event_loop_ratelimit.interval = arg_event_loop_ratelimit_interval_sec;
|
||||
+ m->event_loop_ratelimit.burst = arg_event_loop_ratelimit_burst;
|
||||
|
||||
manager_set_watchdog(m, WATCHDOG_RUNTIME, arg_runtime_watchdog);
|
||||
manager_set_watchdog(m, WATCHDOG_REBOOT, arg_reboot_watchdog);
|
||||
@@ -2495,6 +2523,9 @@ static void reset_arguments(void) {
|
||||
|
||||
arg_default_oom_score_adjust_set = false;
|
||||
arg_default_smack_process_label = mfree(arg_default_smack_process_label);
|
||||
+ arg_event_loop_ratelimit_interval_sec = 1 * USEC_PER_SEC;
|
||||
+ arg_event_loop_ratelimit_burst = 50000;
|
||||
+
|
||||
}
|
||||
|
||||
static void determine_default_oom_score_adjust(void) {
|
||||
diff --git a/src/core/manager-serialize.c b/src/core/manager-serialize.c
|
||||
index 74853181b7..125783a48f 100644
|
||||
--- a/src/core/manager-serialize.c
|
||||
+++ b/src/core/manager-serialize.c
|
||||
@@ -166,6 +166,8 @@ int manager_serialize(
|
||||
|
||||
(void) serialize_ratelimit(f, "dump-ratelimit", &m->dump_ratelimit);
|
||||
|
||||
+ (void) serialize_ratelimit(f, "event-loop-ratelimit", &m->event_loop_ratelimit);
|
||||
+
|
||||
bus_track_serialize(m->subscribed, f, "subscribed");
|
||||
|
||||
r = dynamic_user_serialize(m, f, fds);
|
||||
@@ -553,6 +555,8 @@ int manager_deserialize(Manager *m, FILE *f, FDSet *fds) {
|
||||
(void) varlink_server_deserialize_one(m->varlink_server, val, fds);
|
||||
} else if ((val = startswith(l, "dump-ratelimit="))) {
|
||||
deserialize_ratelimit(&m->dump_ratelimit, "dump-ratelimit", val);
|
||||
+ } else if ((val = startswith(l, "event-loop-ratelimit="))) {
|
||||
+ deserialize_ratelimit(&m->event_loop_ratelimit, "event-loop-ratelimit", val);
|
||||
} else {
|
||||
ManagerTimestamp q;
|
||||
|
||||
diff --git a/src/core/manager.c b/src/core/manager.c
|
||||
index 79408b18dc..ebfc4d3a9a 100644
|
||||
--- a/src/core/manager.c
|
||||
+++ b/src/core/manager.c
|
||||
@@ -3024,7 +3024,6 @@ static int manager_dispatch_jobs_in_progress(sd_event_source *source, usec_t use
|
||||
}
|
||||
|
||||
int manager_loop(Manager *m) {
|
||||
- RateLimit rl = { .interval = 1*USEC_PER_SEC, .burst = 50000 };
|
||||
int r;
|
||||
|
||||
assert(m);
|
||||
@@ -3041,7 +3040,7 @@ int manager_loop(Manager *m) {
|
||||
|
||||
(void) watchdog_ping();
|
||||
|
||||
- if (!ratelimit_below(&rl)) {
|
||||
+ if (!ratelimit_below(&m->event_loop_ratelimit)) {
|
||||
/* Yay, something is going seriously wrong, pause a little */
|
||||
log_warning("Looping too fast. Throttling execution a little.");
|
||||
sleep(1);
|
||||
diff --git a/src/core/manager.h b/src/core/manager.h
|
||||
index 4d5b2e0602..b7917732b5 100644
|
||||
--- a/src/core/manager.h
|
||||
+++ b/src/core/manager.h
|
||||
@@ -465,6 +465,9 @@ struct Manager {
|
||||
|
||||
/* Dump*() are slow, so always rate limit them to 10 per 10 minutes */
|
||||
RateLimit dump_ratelimit;
|
||||
+
|
||||
+ /* Rate limit for the manager event loop */
|
||||
+ RateLimit event_loop_ratelimit;
|
||||
};
|
||||
|
||||
static inline usec_t manager_default_timeout_abort_usec(Manager *m) {
|
||||
diff --git a/src/core/system.conf.in b/src/core/system.conf.in
|
||||
index 5d1f6d24f0..31f0f95b7a 100644
|
||||
--- a/src/core/system.conf.in
|
||||
+++ b/src/core/system.conf.in
|
||||
@@ -75,3 +75,5 @@
|
||||
#DefaultLimitRTTIME=
|
||||
#DefaultOOMPolicy=stop
|
||||
#DefaultSmackProcessLabel=
|
||||
+#EventLoopRateLimitIntervalSec=1s
|
||||
+#EventLoopRateLimitBurst=50000
|
||||
diff --git a/src/core/user.conf.in b/src/core/user.conf.in
|
||||
index b69974978e..0da7ae8be3 100644
|
||||
--- a/src/core/user.conf.in
|
||||
+++ b/src/core/user.conf.in
|
||||
@@ -48,3 +48,5 @@
|
||||
#DefaultLimitRTPRIO=
|
||||
#DefaultLimitRTTIME=
|
||||
#DefaultSmackProcessLabel=
|
||||
+#EventLoopRateLimitIntervalSec=1s
|
||||
+#EventLoopRateLimitBurst=50000
|
||||
@ -0,0 +1,53 @@
|
||||
From c34d349f0e6467f06484aa93f4b422437b9ee2ca Mon Sep 17 00:00:00 2001
|
||||
From: Lennart Poettering <lennart@poettering.net>
|
||||
Date: Thu, 19 Oct 2023 17:04:04 +0200
|
||||
Subject: [PATCH] iovec-util: add some useful helpers for dealing with iovecs
|
||||
that refer to dynamic memory
|
||||
|
||||
(cherry picked from commit 3a856171c2dc78f040c560142d3b275de1c1bb0a)
|
||||
|
||||
Related: RHEL-212610
|
||||
---
|
||||
src/basic/io-util.h | 22 ++++++++++++++++++++++
|
||||
1 file changed, 22 insertions(+)
|
||||
|
||||
diff --git a/src/basic/io-util.h b/src/basic/io-util.h
|
||||
index 3afb134266..4646666a99 100644
|
||||
--- a/src/basic/io-util.h
|
||||
+++ b/src/basic/io-util.h
|
||||
@@ -8,6 +8,7 @@
|
||||
#include <sys/types.h>
|
||||
#include <sys/uio.h>
|
||||
|
||||
+#include "alloc-util.h"
|
||||
#include "macro.h"
|
||||
#include "time-util.h"
|
||||
|
||||
@@ -79,6 +80,27 @@ static inline bool FILE_SIZE_VALID_OR_INFINITY(uint64_t l) {
|
||||
#define IOVEC_INIT_STRING(string) IOVEC_INIT((char*) string, strlen(string))
|
||||
#define IOVEC_MAKE_STRING(string) (struct iovec) IOVEC_INIT_STRING(string)
|
||||
|
||||
+#define TAKE_IOVEC(p) TAKE_GENERIC((p), struct iovec, IOVEC_NULL)
|
||||
+
|
||||
+static inline void iovec_done(struct iovec *iovec) {
|
||||
+ /* A _cleanup_() helper that frees the iov_base in the iovec */
|
||||
+ assert(iovec);
|
||||
+
|
||||
+ iovec->iov_base = mfree(iovec->iov_base);
|
||||
+ iovec->iov_len = 0;
|
||||
+}
|
||||
+
|
||||
+static inline void iovec_done_erase(struct iovec *iovec) {
|
||||
+ assert(iovec);
|
||||
+
|
||||
+ iovec->iov_base = erase_and_free(iovec->iov_base);
|
||||
+ iovec->iov_len = 0;
|
||||
+}
|
||||
+
|
||||
+static inline bool iovec_is_set(const struct iovec *iov) {
|
||||
+ return iov && iov->iov_len > 0 && iov->iov_base;
|
||||
+}
|
||||
+
|
||||
char* set_iovec_string_field(struct iovec *iovec, size_t *n_iovec, const char *field, const char *value);
|
||||
char* set_iovec_string_field_free(struct iovec *iovec, size_t *n_iovec, const char *field, char *value);
|
||||
|
||||
78
1367-repart-use-iovec-structure-for-key-file.patch
Normal file
78
1367-repart-use-iovec-structure-for-key-file.patch
Normal file
@ -0,0 +1,78 @@
|
||||
From 8159189ecc79ff507976502620034938da98400d Mon Sep 17 00:00:00 2001
|
||||
From: Emanuele Giuseppe Esposito <eesposit@redhat.com>
|
||||
Date: Mon, 14 Jul 2025 07:56:49 -0400
|
||||
Subject: [PATCH] repart: use iovec structure for --key-file
|
||||
|
||||
Use the iovec structure for --key-file, instead of a char pointer and a size.
|
||||
|
||||
(cherry picked from commit d4397999324c5093380fc1e6c8ce430a58e57145)
|
||||
|
||||
Related: RHEL-212610
|
||||
---
|
||||
src/partition/repart.c | 26 +++++++++++++-------------
|
||||
1 file changed, 13 insertions(+), 13 deletions(-)
|
||||
|
||||
diff --git a/src/partition/repart.c b/src/partition/repart.c
|
||||
index 5db931e7bc..08d43ce6c9 100644
|
||||
--- a/src/partition/repart.c
|
||||
+++ b/src/partition/repart.c
|
||||
@@ -116,8 +116,7 @@ static bool arg_size_auto = false;
|
||||
static JsonFormatFlags arg_json_format_flags = JSON_FORMAT_OFF;
|
||||
static PagerFlags arg_pager_flags = 0;
|
||||
static bool arg_legend = true;
|
||||
-static void *arg_key = NULL;
|
||||
-static size_t arg_key_size = 0;
|
||||
+static struct iovec arg_key = {};
|
||||
static EVP_PKEY *arg_private_key = NULL;
|
||||
static X509 *arg_certificate = NULL;
|
||||
static char *arg_tpm2_device = NULL;
|
||||
@@ -132,7 +131,7 @@ static bool arg_split = false;
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_root, freep);
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_image, freep);
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_definitions, strv_freep);
|
||||
-STATIC_DESTRUCTOR_REGISTER(arg_key, erase_and_freep);
|
||||
+STATIC_DESTRUCTOR_REGISTER(arg_key, iovec_done_erase);
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_private_key, EVP_PKEY_freep);
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_certificate, X509_freep);
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_tpm2_device, freep);
|
||||
@@ -3011,8 +3010,8 @@ static int partition_encrypt(
|
||||
CRYPT_ANY_SLOT,
|
||||
volume_key,
|
||||
volume_key_size,
|
||||
- strempty(arg_key),
|
||||
- arg_key_size);
|
||||
+ strempty(arg_key.iov_base),
|
||||
+ arg_key.iov_len);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to add LUKS2 key: %m");
|
||||
}
|
||||
@@ -5237,20 +5236,21 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
break;
|
||||
|
||||
case ARG_KEY_FILE: {
|
||||
- _cleanup_(erase_and_freep) char *k = NULL;
|
||||
- size_t n = 0;
|
||||
+ struct iovec key = {};
|
||||
|
||||
r = read_full_file_full(
|
||||
- AT_FDCWD, optarg, UINT64_MAX, SIZE_MAX,
|
||||
+ AT_FDCWD, optarg,
|
||||
+ /* offset= */ UINT64_MAX,
|
||||
+ /* size= */ SIZE_MAX,
|
||||
READ_FULL_FILE_SECURE|READ_FULL_FILE_WARN_WORLD_READABLE|READ_FULL_FILE_CONNECT_SOCKET,
|
||||
- NULL,
|
||||
- &k, &n);
|
||||
+ /* bind_name= */ NULL,
|
||||
+ (char **) &key.iov_base,
|
||||
+ &key.iov_len);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to read key file '%s': %m", optarg);
|
||||
|
||||
- erase_and_free(arg_key);
|
||||
- arg_key = TAKE_PTR(k);
|
||||
- arg_key_size = n;
|
||||
+ iovec_done_erase(&arg_key);
|
||||
+ arg_key = key;
|
||||
break;
|
||||
}
|
||||
|
||||
159
1368-repart-make-tpm2-pcrs-also-configurable-in-repart.d.patch
Normal file
159
1368-repart-make-tpm2-pcrs-also-configurable-in-repart.d.patch
Normal file
@ -0,0 +1,159 @@
|
||||
From 53bd7705fa61caef84ac8cbbda27d5b198de9841 Mon Sep 17 00:00:00 2001
|
||||
From: Emanuele Giuseppe Esposito <eesposit@redhat.com>
|
||||
Date: Thu, 3 Jul 2025 08:08:53 -0400
|
||||
Subject: [PATCH] repart: make --tpm2-pcrs also configurable in repart.d/*
|
||||
|
||||
Add repart.d TPM2PCRs= option with the same syntax as --tpm2-pcrs.
|
||||
This allows a per-partition pcr binding, and not rely on a global config
|
||||
applicable to all partitions.
|
||||
|
||||
The global --tpm2-pcrs overrides TPM2PCRs config. If none of them
|
||||
is defined, rely on default.
|
||||
|
||||
(cherry picked from commit 49dcc89ddc15651ebca8da7a13e5c5b08ec247cb)
|
||||
|
||||
Resolves: RHEL-212610
|
||||
---
|
||||
man/repart.d.xml | 12 +++++++++++
|
||||
src/partition/repart.c | 46 ++++++++++++++++++++++++++++++++++++------
|
||||
2 files changed, 52 insertions(+), 6 deletions(-)
|
||||
|
||||
diff --git a/man/repart.d.xml b/man/repart.d.xml
|
||||
index ebbb31cc20..6cc60e53a2 100644
|
||||
--- a/man/repart.d.xml
|
||||
+++ b/man/repart.d.xml
|
||||
@@ -581,6 +581,18 @@
|
||||
below. Defaults to <literal>%t</literal>. To disable split artifact generation for a partition, set
|
||||
<varname>SplitName=</varname> to <literal>-</literal>.</para></listitem>
|
||||
</varlistentry>
|
||||
+
|
||||
+ <varlistentry>
|
||||
+ <term><varname>TPM2PCRs=</varname></term>
|
||||
+
|
||||
+ <listitem><para>Configures the list of PCRs to use for LUKS2 volumes configured with
|
||||
+ the <varname>Encrypt=tpm2</varname> setting in partition files.
|
||||
+ This option take the same parameters as the similary named options to
|
||||
+ <citerefentry><refentrytitle>systemd-cryptenroll</refentrytitle><manvolnum>1</manvolnum></citerefentry>
|
||||
+ and have the same effect on partitions where TPM2 enrollment is requested.
|
||||
+ This option will be overridden by the global <varname>--tpm2-pcrs=</varname> option.</para>
|
||||
+ </listitem>
|
||||
+ </varlistentry>
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
diff --git a/src/partition/repart.c b/src/partition/repart.c
|
||||
index 08d43ce6c9..d3fcf3b86b 100644
|
||||
--- a/src/partition/repart.c
|
||||
+++ b/src/partition/repart.c
|
||||
@@ -198,6 +198,8 @@ struct Partition {
|
||||
char **copy_files;
|
||||
char **make_directories;
|
||||
EncryptMode encrypt;
|
||||
+ Tpm2PCRValue *tpm2_hash_pcr_values;
|
||||
+ size_t tpm2_n_hash_pcr_values;
|
||||
VerityMode verity;
|
||||
char *verity_match_key;
|
||||
|
||||
@@ -328,6 +330,7 @@ static Partition* partition_free(Partition *p) {
|
||||
free(p->format);
|
||||
strv_free(p->copy_files);
|
||||
strv_free(p->make_directories);
|
||||
+ free(p->tpm2_hash_pcr_values);
|
||||
free(p->verity_match_key);
|
||||
|
||||
free(p->roothash);
|
||||
@@ -354,6 +357,7 @@ static void partition_foreignize(Partition *p) {
|
||||
p->format = mfree(p->format);
|
||||
p->copy_files = strv_free(p->copy_files);
|
||||
p->make_directories = strv_free(p->make_directories);
|
||||
+ p->tpm2_hash_pcr_values = mfree(p->tpm2_hash_pcr_values);
|
||||
p->verity_match_key = mfree(p->verity_match_key);
|
||||
|
||||
p->new_uuid = SD_ID128_NULL;
|
||||
@@ -1470,6 +1474,33 @@ static int config_parse_uuid(
|
||||
return 0;
|
||||
}
|
||||
|
||||
+static int config_parse_tpm2_pcrs(
|
||||
+ const char *unit,
|
||||
+ const char *filename,
|
||||
+ unsigned line,
|
||||
+ const char *section,
|
||||
+ unsigned section_line,
|
||||
+ const char *lvalue,
|
||||
+ int ltype,
|
||||
+ const char *rvalue,
|
||||
+ void *data,
|
||||
+ void *userdata) {
|
||||
+
|
||||
+ Partition *partition = ASSERT_PTR(data);
|
||||
+
|
||||
+ assert(rvalue);
|
||||
+
|
||||
+ if (isempty(rvalue)) {
|
||||
+ /* Clear existing PCR values if empty */
|
||||
+ partition->tpm2_hash_pcr_values = mfree(partition->tpm2_hash_pcr_values);
|
||||
+ partition->tpm2_n_hash_pcr_values = 0;
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
+ return tpm2_parse_pcr_argument_append(rvalue, &partition->tpm2_hash_pcr_values,
|
||||
+ &partition->tpm2_n_hash_pcr_values);
|
||||
+}
|
||||
+
|
||||
static DEFINE_CONFIG_PARSE_ENUM_WITH_DEFAULT(config_parse_verity, verity_mode, VerityMode, VERITY_OFF, "Invalid verity mode");
|
||||
|
||||
static int partition_read_definition(Partition *p, const char *path, const char *const *conf_file_dirs) {
|
||||
@@ -1498,6 +1529,7 @@ static int partition_read_definition(Partition *p, const char *path, const char
|
||||
{ "Partition", "NoAuto", config_parse_tristate, 0, &p->no_auto },
|
||||
{ "Partition", "GrowFileSystem", config_parse_tristate, 0, &p->growfs },
|
||||
{ "Partition", "SplitName", config_parse_string, 0, &p->split_name_format },
|
||||
+ { "Partition", "TPM2PCRs", config_parse_tpm2_pcrs, 0, p },
|
||||
{}
|
||||
};
|
||||
int r;
|
||||
@@ -3026,6 +3058,8 @@ static int partition_encrypt(
|
||||
size_t secret_size, blob_size, pubkey_size = 0, srk_buf_size = 0;
|
||||
ssize_t base64_encoded_size;
|
||||
int keyslot;
|
||||
+ Tpm2PCRValue *pcr_values = arg_tpm2_n_hash_pcr_values > 0 ? arg_tpm2_hash_pcr_values : p->tpm2_hash_pcr_values;
|
||||
+ size_t n_pcr_values = arg_tpm2_n_hash_pcr_values > 0 ? arg_tpm2_n_hash_pcr_values : p->tpm2_n_hash_pcr_values;
|
||||
|
||||
if (arg_tpm2_public_key_pcr_mask != 0) {
|
||||
r = tpm2_load_pcr_public_key(arg_tpm2_public_key, &pubkey, &pubkey_size);
|
||||
@@ -3050,29 +3084,29 @@ static int partition_encrypt(
|
||||
return log_error_errno(r, "Could not convert public key to TPM2B_PUBLIC: %m");
|
||||
}
|
||||
|
||||
- r = tpm2_pcr_read_missing_values(tpm2_context, arg_tpm2_hash_pcr_values, arg_tpm2_n_hash_pcr_values);
|
||||
+ r = tpm2_pcr_read_missing_values(tpm2_context, pcr_values, n_pcr_values);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Could not read pcr values: %m");
|
||||
|
||||
uint16_t hash_pcr_bank = 0;
|
||||
uint32_t hash_pcr_mask = 0;
|
||||
- if (arg_tpm2_n_hash_pcr_values > 0) {
|
||||
+ if (n_pcr_values > 0) {
|
||||
size_t hash_count;
|
||||
- r = tpm2_pcr_values_hash_count(arg_tpm2_hash_pcr_values, arg_tpm2_n_hash_pcr_values, &hash_count);
|
||||
+ r = tpm2_pcr_values_hash_count(pcr_values, n_pcr_values, &hash_count);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Could not get hash count: %m");
|
||||
|
||||
if (hash_count > 1)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Multiple PCR banks selected.");
|
||||
|
||||
- hash_pcr_bank = arg_tpm2_hash_pcr_values[0].hash;
|
||||
- r = tpm2_pcr_values_to_mask(arg_tpm2_hash_pcr_values, arg_tpm2_n_hash_pcr_values, hash_pcr_bank, &hash_pcr_mask);
|
||||
+ hash_pcr_bank = pcr_values[0].hash;
|
||||
+ r = tpm2_pcr_values_to_mask(pcr_values, n_pcr_values, hash_pcr_bank, &hash_pcr_mask);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Could not get hash mask: %m");
|
||||
}
|
||||
|
||||
TPM2B_DIGEST policy = TPM2B_DIGEST_MAKE(NULL, TPM2_SHA256_DIGEST_SIZE);
|
||||
- r = tpm2_calculate_sealing_policy(arg_tpm2_hash_pcr_values, arg_tpm2_n_hash_pcr_values, pubkey ? &public : NULL, /* use_pin= */ false, &policy);
|
||||
+ r = tpm2_calculate_sealing_policy(pcr_values, n_pcr_values, pubkey ? &public : NULL, /* use_pin= */ false, &policy);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Could not calculate sealing policy digest: %m");
|
||||
|
||||
196
1369-repart-make-key-file-also-configurable-in-repart.d.patch
Normal file
196
1369-repart-make-key-file-also-configurable-in-repart.d.patch
Normal file
@ -0,0 +1,196 @@
|
||||
From 068788ddbadbfa7fe3583b732a2957dc4bfc60c5 Mon Sep 17 00:00:00 2001
|
||||
From: Emanuele Giuseppe Esposito <eesposit@redhat.com>
|
||||
Date: Mon, 14 Jul 2025 05:51:49 -0400
|
||||
Subject: [PATCH] repart: make --key-file also configurable in repart.d/*
|
||||
|
||||
Add repart.d KeyFile= option with the same syntax as --key-file.
|
||||
This allows a per-partition key file encryption, and not rely on a global key
|
||||
applicable to all partitions.
|
||||
|
||||
The global --key-file overrides KeyFile config. If none of them is
|
||||
defined, rely on default.
|
||||
|
||||
(cherry picked from commit eb44fa4d198d1da11c998f77bc88f95aaf67e186)
|
||||
|
||||
Resolves: RHEL-212610
|
||||
---
|
||||
man/repart.d.xml | 11 +++++++
|
||||
man/systemd-repart.xml | 9 ++---
|
||||
src/partition/repart.c | 74 +++++++++++++++++++++++++++++++++---------
|
||||
3 files changed, 74 insertions(+), 20 deletions(-)
|
||||
|
||||
diff --git a/man/repart.d.xml b/man/repart.d.xml
|
||||
index 6cc60e53a2..a4f49af39b 100644
|
||||
--- a/man/repart.d.xml
|
||||
+++ b/man/repart.d.xml
|
||||
@@ -593,6 +593,17 @@
|
||||
This option will be overridden by the global <varname>--tpm2-pcrs=</varname> option.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
+
|
||||
+ <varlistentry>
|
||||
+ <term><varname>KeyFile=</varname></term>
|
||||
+
|
||||
+ <listitem><para>Takes a file system path. This path must be absolute, otherwise the option is ignored.
|
||||
+ Configures the encryption key to use when setting up LUKS2 volumes configured with the
|
||||
+ <varname>Encrypt=key-file</varname> setting in partition files. Please refer to the documentation of
|
||||
+ <varname>--key-file=</varname> for more details. This option will be overridden by the global
|
||||
+ <varname>--key-file=</varname> option.</para>
|
||||
+ </listitem>
|
||||
+ </varlistentry>
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
diff --git a/man/systemd-repart.xml b/man/systemd-repart.xml
|
||||
index 3585cbf107..f33e2d772a 100644
|
||||
--- a/man/systemd-repart.xml
|
||||
+++ b/man/systemd-repart.xml
|
||||
@@ -306,10 +306,11 @@
|
||||
<listitem><para>Takes a file system path. Configures the encryption key to use when setting up LUKS2
|
||||
volumes configured with the <varname>Encrypt=key-file</varname> setting in partition files. Should
|
||||
refer to a regular file containing the key, or an <constant>AF_UNIX</constant> stream socket in the
|
||||
- file system. In the latter case a connection is made to it and the key read from it. If this switch
|
||||
- is not specified the empty key (i.e. zero length key) is used. This behaviour is useful for setting
|
||||
- up encrypted partitions during early first boot that receive their user-supplied password only in a
|
||||
- later setup step.</para></listitem>
|
||||
+ file system. In the latter case, a connection is made to it and the key read from it. If this switch
|
||||
+ is not specified, and no <varname>KeyFile=</varname> is specified in the partition file, the empty
|
||||
+ key (i.e. zero length key) is used. This behaviour is useful for setting up encrypted partitions during
|
||||
+ early first boot that receive their user-supplied password only in a later setup step.</para>
|
||||
+ </listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
diff --git a/src/partition/repart.c b/src/partition/repart.c
|
||||
index d3fcf3b86b..c2643231c3 100644
|
||||
--- a/src/partition/repart.c
|
||||
+++ b/src/partition/repart.c
|
||||
@@ -198,6 +198,7 @@ struct Partition {
|
||||
char **copy_files;
|
||||
char **make_directories;
|
||||
EncryptMode encrypt;
|
||||
+ struct iovec key;
|
||||
Tpm2PCRValue *tpm2_hash_pcr_values;
|
||||
size_t tpm2_n_hash_pcr_values;
|
||||
VerityMode verity;
|
||||
@@ -333,6 +334,8 @@ static Partition* partition_free(Partition *p) {
|
||||
free(p->tpm2_hash_pcr_values);
|
||||
free(p->verity_match_key);
|
||||
|
||||
+ iovec_done_erase(&p->key);
|
||||
+
|
||||
free(p->roothash);
|
||||
|
||||
free(p->split_name_format);
|
||||
@@ -360,6 +363,8 @@ static void partition_foreignize(Partition *p) {
|
||||
p->tpm2_hash_pcr_values = mfree(p->tpm2_hash_pcr_values);
|
||||
p->verity_match_key = mfree(p->verity_match_key);
|
||||
|
||||
+ iovec_done_erase(&p->key);
|
||||
+
|
||||
p->new_uuid = SD_ID128_NULL;
|
||||
p->new_uuid_is_set = false;
|
||||
p->priority = 0;
|
||||
@@ -1501,6 +1506,51 @@ static int config_parse_tpm2_pcrs(
|
||||
&partition->tpm2_n_hash_pcr_values);
|
||||
}
|
||||
|
||||
+static int parse_key_file(const char *filename, struct iovec *key) {
|
||||
+ _cleanup_(erase_and_freep) char *k = NULL;
|
||||
+ size_t n = 0;
|
||||
+ int r;
|
||||
+
|
||||
+ r = read_full_file_full(
|
||||
+ AT_FDCWD, filename,
|
||||
+ /* offset= */ UINT64_MAX,
|
||||
+ /* size= */ SIZE_MAX,
|
||||
+ READ_FULL_FILE_SECURE|READ_FULL_FILE_WARN_WORLD_READABLE|READ_FULL_FILE_CONNECT_SOCKET,
|
||||
+ /* bind_name= */ NULL,
|
||||
+ &k, &n);
|
||||
+ if (r < 0)
|
||||
+ return log_error_errno(r, "Failed to read key file '%s': %m", filename);
|
||||
+
|
||||
+ iovec_done_erase(key);
|
||||
+ *key = IOVEC_MAKE(TAKE_PTR(k), n);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int config_parse_key_file(
|
||||
+ const char *unit,
|
||||
+ const char *filename,
|
||||
+ unsigned line,
|
||||
+ const char *section,
|
||||
+ unsigned section_line,
|
||||
+ const char *lvalue,
|
||||
+ int ltype,
|
||||
+ const char *rvalue,
|
||||
+ void *data,
|
||||
+ void *userdata) {
|
||||
+
|
||||
+ Partition *partition = ASSERT_PTR(userdata);
|
||||
+
|
||||
+ assert(rvalue);
|
||||
+
|
||||
+ if (isempty(rvalue)) {
|
||||
+ iovec_done_erase(&partition->key);
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
+ return parse_key_file(rvalue, &partition->key);
|
||||
+}
|
||||
+
|
||||
static DEFINE_CONFIG_PARSE_ENUM_WITH_DEFAULT(config_parse_verity, verity_mode, VerityMode, VERITY_OFF, "Invalid verity mode");
|
||||
|
||||
static int partition_read_definition(Partition *p, const char *path, const char *const *conf_file_dirs) {
|
||||
@@ -1530,6 +1580,7 @@ static int partition_read_definition(Partition *p, const char *path, const char
|
||||
{ "Partition", "GrowFileSystem", config_parse_tristate, 0, &p->growfs },
|
||||
{ "Partition", "SplitName", config_parse_string, 0, &p->split_name_format },
|
||||
{ "Partition", "TPM2PCRs", config_parse_tpm2_pcrs, 0, p },
|
||||
+ { "Partition", "KeyFile", config_parse_key_file, 0, p },
|
||||
{}
|
||||
};
|
||||
int r;
|
||||
@@ -3037,13 +3088,16 @@ static int partition_encrypt(
|
||||
return log_error_errno(r, "Failed to LUKS2 format future partition: %m");
|
||||
|
||||
if (IN_SET(p->encrypt, ENCRYPT_KEY_FILE, ENCRYPT_KEY_FILE_TPM2)) {
|
||||
+ /* Use partition-specific key if available, otherwise fall back to global key */
|
||||
+ struct iovec *iovec_key = arg_key.iov_base ? &arg_key : &p->key;
|
||||
+
|
||||
r = sym_crypt_keyslot_add_by_volume_key(
|
||||
cd,
|
||||
CRYPT_ANY_SLOT,
|
||||
volume_key,
|
||||
volume_key_size,
|
||||
- strempty(arg_key.iov_base),
|
||||
- arg_key.iov_len);
|
||||
+ strempty(iovec_key->iov_base),
|
||||
+ iovec_key->iov_len);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to add LUKS2 key: %m");
|
||||
}
|
||||
@@ -5270,21 +5324,9 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
break;
|
||||
|
||||
case ARG_KEY_FILE: {
|
||||
- struct iovec key = {};
|
||||
-
|
||||
- r = read_full_file_full(
|
||||
- AT_FDCWD, optarg,
|
||||
- /* offset= */ UINT64_MAX,
|
||||
- /* size= */ SIZE_MAX,
|
||||
- READ_FULL_FILE_SECURE|READ_FULL_FILE_WARN_WORLD_READABLE|READ_FULL_FILE_CONNECT_SOCKET,
|
||||
- /* bind_name= */ NULL,
|
||||
- (char **) &key.iov_base,
|
||||
- &key.iov_len);
|
||||
+ r = parse_key_file(optarg, &arg_key);
|
||||
if (r < 0)
|
||||
- return log_error_errno(r, "Failed to read key file '%s': %m", optarg);
|
||||
-
|
||||
- iovec_done_erase(&arg_key);
|
||||
- arg_key = key;
|
||||
+ return r;
|
||||
break;
|
||||
}
|
||||
|
||||
27
1370-man-repart-fix-typo.patch
Normal file
27
1370-man-repart-fix-typo.patch
Normal file
@ -0,0 +1,27 @@
|
||||
From 77567a88f1d9767fed57ad520d9ff1956f3401c6 Mon Sep 17 00:00:00 2001
|
||||
From: Yu Watanabe <watanabe.yu+github@gmail.com>
|
||||
Date: Fri, 19 Sep 2025 20:24:06 +0900
|
||||
Subject: [PATCH] man/repart: fix typo
|
||||
|
||||
Follow-up for 49dcc89ddc15651ebca8da7a13e5c5b08ec247cb.
|
||||
|
||||
(cherry picked from commit cbdbf68a7266c515db12c87542483b907fe7becf)
|
||||
|
||||
Related: RHEL-212610
|
||||
---
|
||||
man/repart.d.xml | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/man/repart.d.xml b/man/repart.d.xml
|
||||
index a4f49af39b..6ce2e0eaf4 100644
|
||||
--- a/man/repart.d.xml
|
||||
+++ b/man/repart.d.xml
|
||||
@@ -587,7 +587,7 @@
|
||||
|
||||
<listitem><para>Configures the list of PCRs to use for LUKS2 volumes configured with
|
||||
the <varname>Encrypt=tpm2</varname> setting in partition files.
|
||||
- This option take the same parameters as the similary named options to
|
||||
+ This option take the same parameters as the similarly named options to
|
||||
<citerefentry><refentrytitle>systemd-cryptenroll</refentrytitle><manvolnum>1</manvolnum></citerefentry>
|
||||
and have the same effect on partitions where TPM2 enrollment is requested.
|
||||
This option will be overridden by the global <varname>--tpm2-pcrs=</varname> option.</para>
|
||||
30
systemd.spec
30
systemd.spec
@ -21,7 +21,7 @@
|
||||
Name: systemd
|
||||
Url: https://systemd.io
|
||||
Version: 252
|
||||
Release: 73%{?dist}
|
||||
Release: 76%{?dist}
|
||||
# For a breakdown of the licensing, see README
|
||||
License: LGPLv2+ and MIT and GPLv2+
|
||||
Summary: System and Service Manager
|
||||
@ -1440,6 +1440,19 @@ Patch1354: 1354-ci-bump-super-linter-to-v8.7.0.patch
|
||||
Patch1355: 1355-ci-explicitly-disable-multi-status-for-Super-Linter.patch
|
||||
Patch1356: 1356-github-linter-disable-ENABLE_GITHUB_PULL_REQUEST_SUM.patch
|
||||
Patch1357: 1357-test-install-iscsi-gen-initiatorname-from-iscsi-init.patch
|
||||
Patch1358: 1358-resolved-replace-assert-with-error-return-in-DNSSEC-.patch
|
||||
Patch1359: 1359-pid1-introduce-new-SERVICE_-DEAD-FAILED-_BEFORE_AUTO.patch
|
||||
Patch1360: 1360-service-add-new-RestartMode-option.patch
|
||||
Patch1361: 1361-core-service-drop-unneeded-unit_add_to_gc_queue.patch
|
||||
Patch1362: 1362-core-get-rid-of-unused-Service.will_auto_restart-log.patch
|
||||
Patch1363: 1363-core-drop-UnitNotifyFlags.patch
|
||||
Patch1364: 1364-core-split-out-the-helper-to-serialize-deserialize-r.patch
|
||||
Patch1365: 1365-core-make-manager-event-loop-rate-limit-configurable.patch
|
||||
Patch1366: 1366-iovec-util-add-some-useful-helpers-for-dealing-with-.patch
|
||||
Patch1367: 1367-repart-use-iovec-structure-for-key-file.patch
|
||||
Patch1368: 1368-repart-make-tpm2-pcrs-also-configurable-in-repart.d.patch
|
||||
Patch1369: 1369-repart-make-key-file-also-configurable-in-repart.d.patch
|
||||
Patch1370: 1370-man-repart-fix-typo.patch
|
||||
|
||||
# Downstream-only patches (9000–9999)
|
||||
|
||||
@ -2317,6 +2330,21 @@ systemd-hwdb update &>/dev/null || :
|
||||
%{_prefix}/lib/dracut/modules.d/70rhel-net-naming-sysattrs/*
|
||||
|
||||
%changelog
|
||||
* Wed Aug 05 2026 systemd maintenance team <systemd-maint@redhat.com> - 252-76
|
||||
- resolved: replace assert() with error return in DNSSEC verify functions (RHEL-208860)
|
||||
- pid1: introduce new SERVICE_{DEAD|FAILED}_BEFORE_AUTO_RESTART service substates (RHEL-137251)
|
||||
- service: add new RestartMode option (RHEL-137251)
|
||||
- core/service: drop unneeded unit_add_to_gc_queue() (RHEL-137251)
|
||||
- core: get rid of unused Service.will_auto_restart logic (RHEL-118224)
|
||||
- core: drop UnitNotifyFlags (RHEL-118224)
|
||||
- core: split out the helper to serialize/deserialize ratelimits (RHEL-213655)
|
||||
- core: make manager event loop rate limit configurable (RHEL-213655)
|
||||
- iovec-util: add some useful helpers for dealing with iovecs that refer to dynamic memory (RHEL-212610)
|
||||
- repart: use iovec structure for --key-file (RHEL-212610)
|
||||
- repart: make --tpm2-pcrs also configurable in repart.d/* (RHEL-212610)
|
||||
- repart: make --key-file also configurable in repart.d/* (RHEL-212610)
|
||||
- man/repart: fix typo (RHEL-212610)
|
||||
|
||||
* Tue Jul 21 2026 systemd maintenance team <systemd-maint@redhat.com> - 252-73
|
||||
- hwdb,rules: add 82-net-auto-link-local.{hwdb,rules} to build (RHEL-180938)
|
||||
- test: reenable test for cg_get_keyed_attribute() (RHEL-180940)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user