diff --git a/1284-timer-rebase-the-next-elapse-timestamp-only-if-timer.patch b/1284-timer-rebase-the-next-elapse-timestamp-only-if-timer.patch new file mode 100644 index 0000000..bc3eda2 --- /dev/null +++ b/1284-timer-rebase-the-next-elapse-timestamp-only-if-timer.patch @@ -0,0 +1,131 @@ +From 69c124810e3b4bc4b7aa441cfed65d3d7594d443 Mon Sep 17 00:00:00 2001 +From: Frantisek Sumsal +Date: Mon, 13 Oct 2025 17:36:55 +0200 +Subject: [PATCH] timer: rebase the next elapse timestamp only if timer didn't + already run +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The test added in f4c3c107d9be4e922a080fc292ed3889c4e0f4a5 uncovered a +corner case while recalculating the next elapse timestamp of a timer unit +that uses RandomizedDelaySec= during deserialization. + +If the scheduled time (without RandomizedDelaySec=) already elapsed, +systemd "rebases" the next elapse timestamp to the time when systemd +first started, to make the RandomizedDelaySec= feature work even at +boot. However, since it was done unconditionally, it always overrode the +next elapse timestamp, which could then cause the final next elapse +timestamp to fall out of the expected window. + +With a couple of additional debug logs one of the test fail looks like +this: + +[ 132.129815] TEST-53-TIMER.sh[384]: + : 'Next elapse timestamp after daemon-reload, try #328' +[ 132.129815] TEST-53-TIMER.sh[384]: + systemctl daemon-reload +[ 132.136352] systemd[1]: Reload requested from client PID 16399 ('systemctl') (unit TEST-53-TIMER.service)... +[ 132.136636] systemd[1]: Reloading... +[ 132.446160] systemd[1]: Rebasing next elapse timestamp +[ 132.446168] systemd[1]: v->next_elapse: Tue 2025-10-14 00:10:00 CEST +[ 132.446170] systemd[1]: rebased: Tue 2025-10-14 00:10:56 CEST +[ 132.446172] systemd[1]: v->next_elapse after rebase: Tue 2025-10-14 00:10:56 CEST +[ 132.447361] systemd[1]: Reloading finished in 310 ms. +[ 132.484041] TEST-53-TIMER.sh[384]: + check_elapse_timestamp +[ 132.484041] TEST-53-TIMER.sh[384]: + systemctl status timer-RandomizedDelaySec-16377.timer +[ 132.533657] TEST-53-TIMER.sh[16440]: ● timer-RandomizedDelaySec-16377.timer +[ 132.533657] TEST-53-TIMER.sh[16440]: Loaded: loaded (/run/systemd/system/timer-RandomizedDelaySec-16377.timer; static) +[ 132.533657] TEST-53-TIMER.sh[16440]: Active: active (waiting) since Mon 2025-10-13 23:00:00 CEST; 1h 13min ago +[ 132.533657] TEST-53-TIMER.sh[16440]: Invocation: 5555d4f060114a5493ff228013830d17 +[ 132.533657] TEST-53-TIMER.sh[16440]: Trigger: Tue 2025-10-14 22:10:04 CEST; 21h left +[ 132.533657] TEST-53-TIMER.sh[16440]: Triggers: ● timer-RandomizedDelaySec-16377.service +[ 132.533657] TEST-53-TIMER.sh[16440]: Oct 14 00:13:07 H systemd[1]: timer-RandomizedDelaySec-16377.timer: Changed dead -> waiting +[ 132.533657] TEST-53-TIMER.sh[16440]: Oct 14 00:13:07 H systemd[1]: timer-RandomizedDelaySec-16377.timer: Adding 15h 35min 1.230173s random time. +[ 132.533657] TEST-53-TIMER.sh[16440]: Oct 14 00:13:07 H systemd[1]: timer-RandomizedDelaySec-16377.timer: Realtime timer elapses at Tue 2025-10-14 15:45:58 CEST. +[ 132.533657] TEST-53-TIMER.sh[16440]: Oct 14 00:13:07 H systemd[1]: timer-RandomizedDelaySec-16377.timer: Changed dead -> waiting +[ 132.533657] TEST-53-TIMER.sh[16440]: Oct 14 00:13:08 H systemd[1]: timer-RandomizedDelaySec-16377.timer: Adding 16h 29min 44.084409s random time. +[ 132.533657] TEST-53-TIMER.sh[16440]: Oct 14 00:13:08 H systemd[1]: timer-RandomizedDelaySec-16377.timer: Realtime timer elapses at Tue 2025-10-14 16:40:41 CEST. +[ 132.533657] TEST-53-TIMER.sh[16440]: Oct 14 00:13:08 H systemd[1]: timer-RandomizedDelaySec-16377.timer: Changed dead -> waiting +[ 132.533657] TEST-53-TIMER.sh[16440]: Oct 14 00:13:08 H systemd[1]: timer-RandomizedDelaySec-16377.timer: Adding 21h 59min 7.955828s random time. +[ 132.533657] TEST-53-TIMER.sh[16440]: Oct 14 00:13:08 H systemd[1]: timer-RandomizedDelaySec-16377.timer: Realtime timer elapses at Tue 2025-10-14 22:10:04 CEST. +[ 132.533657] TEST-53-TIMER.sh[16440]: Oct 14 00:13:08 H systemd[1]: timer-RandomizedDelaySec-16377.timer: Changed dead -> waiting +[ 132.535386] TEST-53-TIMER.sh[384]: + systemctl show -p InactiveExitTimestamp timer-RandomizedDelaySec-16377.timer +[ 132.537727] TEST-53-TIMER.sh[16442]: InactiveExitTimestamp=Mon 2025-10-13 23:00:00 CEST +[ 132.540317] TEST-53-TIMER.sh[16444]: ++ systemctl show -P NextElapseUSecRealtime timer-RandomizedDelaySec-16377.timer +[ 132.547745] TEST-53-TIMER.sh[384]: + NEXT_ELAPSE_REALTIME='Tue 2025-10-14 22:10:04 CEST' +[ 132.548020] TEST-53-TIMER.sh[16445]: ++ date '--date=Tue 2025-10-14 22:10:04 CEST' +%s +[ 132.550218] TEST-53-TIMER.sh[384]: + NEXT_ELAPSE_REALTIME_S=1760472604 +[ 132.550218] TEST-53-TIMER.sh[384]: + : 'Next elapse timestamp should be Tue 2025-10-14 00:10:00 CEST <= Tue 2025-10-14 22:10:04 CEST <= Tue 2025-10-14 22:10:00 CEST' +[ 132.550218] TEST-53-TIMER.sh[384]: + assert_ge 1760472604 1760393400 +[ 132.550555] TEST-53-TIMER.sh[16446]: + set +ex +[ 132.550702] TEST-53-TIMER.sh[384]: + assert_le 1760472604 1760472600 +[ 132.550832] TEST-53-TIMER.sh[16447]: + set +ex +[ 132.551091] TEST-53-TIMER.sh[16447]: FAIL: '1760472604' > '1760472600' + +Here the original next elapse timestamp was Tue 2025-10-14 00:10:00 CEST +as expected, but it was overridden by the rebased timestamp: +Tue 2025-10-14 00:10:56 CEST. And when a new randomized delay was added +to it (21h 59min 7.955828s) the final next elapse timestamp fell out of +the expected window, i.e. Tue 2025-10-14 00:10:00 (scheduled time) < +Tue 2025-10-14 22:10:04 CEST (rebased elapse timestamp + randomized +delay) < Tue 2025-10-14 22:10:00 CEST (scheduled time + maximum from +RandomizedDelaySec=, i.e. 22h). + +By limiting the timestamp rebase only the case where the unit hasn't +already run should prevent this from happening during daemon-reload. + +(cherry picked from commit bdb8e584f4509de0daebbe2357d23156160c3a90) + +Related: RHEL-118215 +--- + src/core/timer.c | 25 +++++++++++++++---------- + 1 file changed, 15 insertions(+), 10 deletions(-) + +diff --git a/src/core/timer.c b/src/core/timer.c +index 2eadca4f1a..4b0266bc68 100644 +--- a/src/core/timer.c ++++ b/src/core/timer.c +@@ -392,7 +392,8 @@ static void timer_enter_waiting(Timer *t, bool time_change) { + continue; + + if (v->base == TIMER_CALENDAR) { +- usec_t b, rebased; ++ bool rebase_after_boot_time = false; ++ usec_t b; + + /* If we know the last time this was + * triggered, schedule the job based relative +@@ -403,21 +404,25 @@ static void timer_enter_waiting(Timer *t, bool time_change) { + b = t->last_trigger.realtime; + else if (dual_timestamp_is_set(&UNIT(t)->inactive_exit_timestamp)) + b = UNIT(t)->inactive_exit_timestamp.realtime; +- else ++ else { + b = ts.realtime; ++ rebase_after_boot_time = true; ++ } + + r = calendar_spec_next_usec(v->calendar_spec, b, &v->next_elapse); + if (r < 0) + continue; + +- /* To make the delay due to RandomizedDelaySec= work even at boot, if the scheduled +- * time has already passed, set the time when systemd first started as the scheduled +- * time. Note that we base this on the monotonic timestamp of the boot, not the +- * realtime one, since the wallclock might have been off during boot. */ +- rebased = map_clock_usec(UNIT(t)->manager->timestamps[MANAGER_TIMESTAMP_USERSPACE].monotonic, +- CLOCK_MONOTONIC, CLOCK_REALTIME); +- if (v->next_elapse < rebased) +- v->next_elapse = rebased; ++ if (rebase_after_boot_time) { ++ /* To make the delay due to RandomizedDelaySec= work even at boot, if the scheduled ++ * time has already passed, set the time when systemd first started as the scheduled ++ * time. Note that we base this on the monotonic timestamp of the boot, not the ++ * realtime one, since the wallclock might have been off during boot. */ ++ usec_t rebased = map_clock_usec(UNIT(t)->manager->timestamps[MANAGER_TIMESTAMP_USERSPACE].monotonic, ++ CLOCK_MONOTONIC, CLOCK_REALTIME); ++ if (v->next_elapse < rebased) ++ v->next_elapse = rebased; ++ } + + if (!found_realtime) + t->next_elapse_realtime = v->next_elapse; diff --git a/1285-strv-introduce-string_strv_hashmap_remove.patch b/1285-strv-introduce-string_strv_hashmap_remove.patch new file mode 100644 index 0000000..6d58343 --- /dev/null +++ b/1285-strv-introduce-string_strv_hashmap_remove.patch @@ -0,0 +1,85 @@ +From e16ede11dab405749b776aa6d58a9c7461a0dda5 Mon Sep 17 00:00:00 2001 +From: Yu Watanabe +Date: Tue, 28 Jan 2025 08:50:14 +0900 +Subject: [PATCH] strv: introduce string_strv_hashmap_remove() + +(cherry picked from commit c540875cd3b024f64980966376637ecc284d643c) + +Related: RHEL-14112 +--- + src/basic/strv.c | 17 +++++++++++++++++ + src/basic/strv.h | 5 +++++ + src/test/test-hashmap-plain.c | 16 ++++++++++++++++ + 3 files changed, 38 insertions(+) + +diff --git a/src/basic/strv.c b/src/basic/strv.c +index 66b70befd6..1f5d6f058f 100644 +--- a/src/basic/strv.c ++++ b/src/basic/strv.c +@@ -920,6 +920,23 @@ int fputstrv(FILE *f, char * const *l, const char *separator, bool *space) { + return 0; + } + ++void string_strv_hashmap_remove(Hashmap *h, const char *key, const char *value) { ++ assert(key); ++ ++ if (value) { ++ char **l = hashmap_get(h, key); ++ if (!l) ++ return; ++ ++ strv_remove(l, value); ++ if (!strv_isempty(l)) ++ return; ++ } ++ ++ _unused_ _cleanup_free_ char *key_free = NULL; ++ strv_free(hashmap_remove2(h, key, (void**) &key_free)); ++} ++ + static int string_strv_hashmap_put_internal(Hashmap *h, const char *key, const char *value) { + char **l; + int r; +diff --git a/src/basic/strv.h b/src/basic/strv.h +index 6c9fa47943..9eb685fb86 100644 +--- a/src/basic/strv.h ++++ b/src/basic/strv.h +@@ -261,6 +261,11 @@ int fputstrv(FILE *f, char * const *l, const char *separator, bool *space); + free_and_replace_full(a, b, strv_free) + + extern const struct hash_ops string_strv_hash_ops; ++ ++void string_strv_hashmap_remove(Hashmap *h, const char *key, const char *value); ++static inline void string_strv_ordered_hashmap_remove(OrderedHashmap *h, const char *key, const char *value) { ++ string_strv_hashmap_remove(PLAIN_HASHMAP(h), key, value); ++} + int _string_strv_hashmap_put(Hashmap **h, const char *key, const char *value HASHMAP_DEBUG_PARAMS); + int _string_strv_ordered_hashmap_put(OrderedHashmap **h, const char *key, const char *value HASHMAP_DEBUG_PARAMS); + #define string_strv_hashmap_put(h, k, v) _string_strv_hashmap_put(h, k, v HASHMAP_DEBUG_SRC_ARGS) +diff --git a/src/test/test-hashmap-plain.c b/src/test/test-hashmap-plain.c +index 36a775012b..3bc96fc944 100644 +--- a/src/test/test-hashmap-plain.c ++++ b/src/test/test-hashmap-plain.c +@@ -996,6 +996,22 @@ TEST(string_strv_hashmap) { + + s = hashmap_get(m, "xxx"); + assert_se(strv_equal(s, STRV_MAKE("bar", "BAR"))); ++ ++ string_strv_hashmap_remove(m, "foo", "bar"); ++ ASSERT_NOT_NULL(s = hashmap_get(m, "foo")); ++ ASSERT_TRUE(strv_equal(s, STRV_MAKE("BAR"))); ++ ++ string_strv_hashmap_remove(m, "foo", "BAR"); ++ ASSERT_NULL(hashmap_get(m, "foo")); ++ ++ string_strv_hashmap_remove(m, "xxx", "BAR"); ++ ASSERT_NOT_NULL(s = hashmap_get(m, "xxx")); ++ ASSERT_TRUE(strv_equal(s, STRV_MAKE("bar"))); ++ ++ string_strv_hashmap_remove(m, "xxx", "bar"); ++ ASSERT_NULL(hashmap_get(m, "xxx")); ++ ++ ASSERT_TRUE(hashmap_isempty(m)); + } + + /* Signal to test-hashmap.c that tests from this compilation unit were run. */ diff --git a/1286-unit-file-introduce-unit_file_remove_from_name_map.patch b/1286-unit-file-introduce-unit_file_remove_from_name_map.patch new file mode 100644 index 0000000..80413e8 --- /dev/null +++ b/1286-unit-file-introduce-unit_file_remove_from_name_map.patch @@ -0,0 +1,230 @@ +From fe5bad818a26875914f3b0c59fa3d4f5e6b3a41d Mon Sep 17 00:00:00 2001 +From: Yu Watanabe +Date: Tue, 28 Jan 2025 09:55:12 +0900 +Subject: [PATCH] unit-file: introduce unit_file_remove_from_name_map() + +(cherry picked from commit d8b34aaef24599917d4e7fa04c78fffac3afe7cf) + +Related: RHEL-14112 + +[msekleta: I've backported strv_equal_ignore_order() in the same commit +in order to get this to compile.] +--- + src/basic/strv.c | 20 ++++++++++ + src/basic/strv.h | 1 + + src/basic/unit-file.c | 35 +++++++++++++++++ + src/basic/unit-file.h | 8 ++++ + src/test/test-unit-file.c | 81 +++++++++++++++++++++++++++++++++++++++ + 5 files changed, 145 insertions(+) + +diff --git a/src/basic/strv.c b/src/basic/strv.c +index 1f5d6f058f..47cc6931c1 100644 +--- a/src/basic/strv.c ++++ b/src/basic/strv.c +@@ -775,6 +775,26 @@ int strv_compare(char * const *a, char * const *b) { + return 0; + } + ++bool strv_equal_ignore_order(char **a, char **b) { ++ ++ /* Just like strv_equal(), but doesn't care about the order of elements or about redundant entries ++ * (i.e. it's even ok if the number of entries in the array differ, as long as the difference just ++ * consists of repititions) */ ++ ++ if (a == b) ++ return true; ++ ++ STRV_FOREACH(i, a) ++ if (!strv_contains(b, *i)) ++ return false; ++ ++ STRV_FOREACH(i, b) ++ if (!strv_contains(a, *i)) ++ return false; ++ ++ return true; ++} ++ + void strv_print(char * const *l) { + STRV_FOREACH(s, l) + puts(*s); +diff --git a/src/basic/strv.h b/src/basic/strv.h +index 9eb685fb86..1de3c98e5c 100644 +--- a/src/basic/strv.h ++++ b/src/basic/strv.h +@@ -160,6 +160,7 @@ bool strv_overlap(char * const *a, char * const *b) _pure_; + _STRV_FOREACH_PAIR(x, y, l, UNIQ_T(i, UNIQ)) + + char** strv_sort(char **l); ++bool strv_equal_ignore_order(char **a, char **b); + void strv_print(char * const *l); + + #define strv_from_stdarg_alloca(first) \ +diff --git a/src/basic/unit-file.c b/src/basic/unit-file.c +index c81c69db30..d7d7fd70f6 100644 +--- a/src/basic/unit-file.c ++++ b/src/basic/unit-file.c +@@ -627,6 +627,41 @@ int unit_file_build_name_map( + return 1; + } + ++int unit_file_remove_from_name_map( ++ const LookupPaths *lp, ++ uint64_t *cache_timestamp_hash, ++ Hashmap **unit_ids_map, ++ Hashmap **unit_names_map, ++ Set **path_cache, ++ const char *path) { ++ ++ int r; ++ ++ assert(path); ++ ++ /* This assumes the specified path is already removed, and drops the relevant entries from the maps. */ ++ ++ /* If one of the lookup paths we are monitoring is already changed, let's rebuild the map. Then, the ++ * new map should not contain entries relevant to the specified path. */ ++ r = unit_file_build_name_map(lp, cache_timestamp_hash, unit_ids_map, unit_names_map, path_cache); ++ if (r != 0) ++ return r; ++ ++ /* If not, drop the relevant entries. */ ++ ++ _cleanup_free_ char *name = NULL; ++ r = path_extract_filename(path, &name); ++ if (r < 0) ++ return log_warning_errno(r, "Failed to extract file name from '%s': %m", path); ++ ++ _unused_ _cleanup_free_ char *key = NULL; ++ free(hashmap_remove2(*unit_ids_map, name, (void**) &key)); ++ string_strv_hashmap_remove(*unit_names_map, name, name); ++ free(set_remove(*path_cache, path)); ++ ++ return 0; ++} ++ + static int add_name( + const char *unit_name, + Set **names, +diff --git a/src/basic/unit-file.h b/src/basic/unit-file.h +index 1c43861f00..78f65dbc8e 100644 +--- a/src/basic/unit-file.h ++++ b/src/basic/unit-file.h +@@ -52,6 +52,14 @@ int unit_file_build_name_map( + Hashmap **unit_names_map, + Set **path_cache); + ++int unit_file_remove_from_name_map( ++ const LookupPaths *lp, ++ uint64_t *cache_timestamp_hash, ++ Hashmap **unit_ids_map, ++ Hashmap **unit_names_map, ++ Set **path_cache, ++ const char *path); ++ + int unit_file_find_fragment( + Hashmap *unit_ids_map, + Hashmap *unit_name_map, +diff --git a/src/test/test-unit-file.c b/src/test/test-unit-file.c +index dffa2822e6..389113c336 100644 +--- a/src/test/test-unit-file.c ++++ b/src/test/test-unit-file.c +@@ -1,10 +1,15 @@ + /* SPDX-License-Identifier: LGPL-2.1-or-later */ + ++#include "fileio.h" + #include "path-lookup.h" ++#include "path-util.h" ++#include "random-util.h" ++#include "rm-rf.h" + #include "set.h" + #include "special.h" + #include "strv.h" + #include "tests.h" ++#include "tmpfile-util.h" + #include "unit-file.h" + + TEST(unit_validate_alias_symlink_and_warn) { +@@ -85,6 +90,82 @@ TEST(unit_file_build_name_map) { + } + } + ++static bool test_unit_file_remove_from_name_map_trail(const LookupPaths *lp, size_t trial) { ++ int r; ++ ++ log_debug("/* %s(trial=%zu) */", __func__, trial); ++ ++ _cleanup_hashmap_free_ Hashmap *unit_ids = NULL, *unit_names = NULL; ++ _cleanup_set_free_ Set *path_cache = NULL; ++ assert_se(unit_file_build_name_map(lp, NULL, &unit_ids, &unit_names, &path_cache) > 0); ++ ++ _cleanup_free_ char *name = NULL; ++ for (size_t i = 0; i < 100; i++) { ++ ASSERT_OK(asprintf(&name, "test-unit-file-%"PRIx64".service", random_u64())); ++ if (!hashmap_contains(unit_ids, name)) ++ break; ++ name = mfree(name); ++ } ++ ASSERT_NOT_NULL(name); ++ ++ _cleanup_free_ char *path = path_join(lp->transient, name); ++ ASSERT_NOT_NULL(path); ++ ASSERT_OK(write_string_file(path, "[Unit]\n", WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_MKDIR_0755)); ++ ++ uint64_t cache_timestamp_hash = 0; ++ assert_se(unit_file_build_name_map(lp, &cache_timestamp_hash, &unit_ids, &unit_names, &path_cache) > 0); ++ ++ ASSERT_STREQ(hashmap_get(unit_ids, name), path); ++ ASSERT_TRUE(strv_equal(hashmap_get(unit_names, name), STRV_MAKE(name))); ++ ASSERT_TRUE(set_contains(path_cache, path)); ++ ++ assert_se(unlink(path) >= 0); ++ ++ ASSERT_OK(r = unit_file_remove_from_name_map(lp, &cache_timestamp_hash, &unit_ids, &unit_names, &path_cache, path)); ++ if (r > 0) ++ return false; /* someone touches unit files. Retrying. */ ++ ++ ASSERT_FALSE(hashmap_contains(unit_ids, name)); ++ ASSERT_FALSE(hashmap_contains(unit_names, path)); ++ ASSERT_FALSE(set_contains(path_cache, path)); ++ ++ _cleanup_hashmap_free_ Hashmap *unit_ids_2 = NULL, *unit_names_2 = NULL; ++ _cleanup_set_free_ Set *path_cache_2 = NULL; ++ assert_se(unit_file_build_name_map(lp, NULL, &unit_ids_2, &unit_names_2, &path_cache_2) > 0); ++ ++ if (hashmap_size(unit_ids) != hashmap_size(unit_ids_2) || ++ hashmap_size(unit_names) != hashmap_size(unit_names_2) || ++ !set_equal(path_cache, path_cache_2)) ++ return false; ++ ++ const char *k, *v; ++ HASHMAP_FOREACH_KEY(v, k, unit_ids) ++ if (!streq_ptr(hashmap_get(unit_ids_2, k), v)) ++ return false; ++ ++ char **l; ++ HASHMAP_FOREACH_KEY(l, k, unit_names) ++ if (!strv_equal_ignore_order(hashmap_get(unit_names_2, k), l)) ++ return false; ++ ++ return true; ++} ++ ++ ++TEST(unit_file_remove_from_name_map) { ++ _cleanup_(rm_rf_physical_and_freep) char *d = NULL; ++ ++ _cleanup_(lookup_paths_free) LookupPaths lp = {}; ++ ASSERT_OK(lookup_paths_init(&lp, LOOKUP_SCOPE_SYSTEM, LOOKUP_PATHS_TEMPORARY_GENERATED, NULL)); ++ ASSERT_NOT_NULL(d = strdup(lp.temporary_dir)); ++ ++ for (size_t i = 0; i < 10; i++) ++ if (test_unit_file_remove_from_name_map_trail(&lp, i)) ++ return; ++ ++ assert_not_reached(); ++} ++ + TEST(runlevel_to_target) { + in_initrd_force(false); + assert_se(streq_ptr(runlevel_to_target(NULL), NULL)); diff --git a/1287-core-unit-remove-path-to-transient-unit-file-from-un.patch b/1287-core-unit-remove-path-to-transient-unit-file-from-un.patch new file mode 100644 index 0000000..9fd0e2e --- /dev/null +++ b/1287-core-unit-remove-path-to-transient-unit-file-from-un.patch @@ -0,0 +1,52 @@ +From 4726233b421628eae405b3b3fb08222cf0befae4 Mon Sep 17 00:00:00 2001 +From: Yu Watanabe +Date: Tue, 28 Jan 2025 10:09:32 +0900 +Subject: [PATCH] core/unit: remove path to transient unit file from unit name + maps on stop + +Fixes #35190. + +(cherry picked from commit fce94c5c563b8f6ede2b8f7f283d2d2faff4e062) + +Resolves: RHEL-14112 +--- + src/core/unit.c | 15 ++++++++++++--- + 1 file changed, 12 insertions(+), 3 deletions(-) + +diff --git a/src/core/unit.c b/src/core/unit.c +index 9e349402ff..afe3fdab04 100644 +--- a/src/core/unit.c ++++ b/src/core/unit.c +@@ -598,13 +598,11 @@ static void unit_clear_dependencies(Unit *u) { + + static void unit_remove_transient(Unit *u) { + assert(u); ++ assert(u->manager); + + if (!u->transient) + return; + +- if (u->fragment_path) +- (void) unlink(u->fragment_path); +- + STRV_FOREACH(i, u->dropin_paths) { + _cleanup_free_ char *p = NULL, *pp = NULL; + +@@ -621,6 +619,17 @@ static void unit_remove_transient(Unit *u) { + (void) unlink(*i); + (void) rmdir(p); + } ++ ++ if (u->fragment_path) { ++ (void) unlink(u->fragment_path); ++ (void) unit_file_remove_from_name_map( ++ &u->manager->lookup_paths, ++ &u->manager->unit_cache_timestamp_hash, ++ &u->manager->unit_id_map, ++ &u->manager->unit_name_map, ++ &u->manager->unit_path_cache, ++ u->fragment_path); ++ } + } + + static void unit_free_requires_mounts_for(Unit *u) { diff --git a/1288-TEST-07-PID1-add-reprudcer-for-issue-35190.patch b/1288-TEST-07-PID1-add-reprudcer-for-issue-35190.patch new file mode 100644 index 0000000..2b076f0 --- /dev/null +++ b/1288-TEST-07-PID1-add-reprudcer-for-issue-35190.patch @@ -0,0 +1,33 @@ +From 1aa6c0d3bcac98d3442d07412f4296d5b9b18dc0 Mon Sep 17 00:00:00 2001 +From: Yu Watanabe +Date: Mon, 27 Jan 2025 22:24:16 +0900 +Subject: [PATCH] TEST-07-PID1: add reprudcer for issue #35190 + +(cherry picked from commit 448e99251aa47a5986425a1783da44d1200fe733) + +Related: RHEL-14112 +--- + test/units/testsuite-07.transient.sh | 14 ++++++++++++++ + 1 file changed, 14 insertions(+) + create mode 100755 test/units/testsuite-07.transient.sh + +diff --git a/test/units/testsuite-07.transient.sh b/test/units/testsuite-07.transient.sh +new file mode 100755 +index 0000000000..ae71a38143 +--- /dev/null ++++ b/test/units/testsuite-07.transient.sh +@@ -0,0 +1,14 @@ ++#!/usr/bin/env bash ++# SPDX-License-Identifier: LGPL-2.1-or-later ++set -ex ++set -o pipefail ++ ++journalctl --sync ++TS="$(date '+%H:%M:%S')" ++ ++systemd-run -u hogehoge.service sleep infinity ++systemctl daemon-reload ++systemctl stop hogehoge.service ++ ++journalctl --sync ++[[ -z "$(journalctl -b -q --since "$TS" -u hogehoge.service -p notice)" ]] diff --git a/1289-coredump-handle-ENOBUFS-and-EMSGSIZE-the-same-way.patch b/1289-coredump-handle-ENOBUFS-and-EMSGSIZE-the-same-way.patch new file mode 100644 index 0000000..1b7f6a5 --- /dev/null +++ b/1289-coredump-handle-ENOBUFS-and-EMSGSIZE-the-same-way.patch @@ -0,0 +1,34 @@ +From 2fe492a2f0fefa0f782cb04a248fc9dcd5667bf0 Mon Sep 17 00:00:00 2001 +From: Michal Sekletar +Date: Fri, 24 Oct 2025 12:55:20 +0200 +Subject: [PATCH] coredump: handle ENOBUFS and EMSGSIZE the same way + +Depending on the runtime configuration, e.g. sysctls +net.core.wmem_default= and net.core.rmem_default and on the actual +message size, sendmsg() can fail also with ENOBUFS. E.g. alloc_skb() +failure caused by net.core.[rw]mem_default=64MiB and huge fdinfo list +from process that has 90k opened FDs. + +We should handle this case in the same way as EMSGSIZE and drop part of +the message. + +(cherry picked from commit 28e62e684b631f928f1d857b04f45f0d34441675) + +Resolves: RHEL-103801 +--- + src/coredump/coredump.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/coredump/coredump.c b/src/coredump/coredump.c +index e0aac3c8d0..28dabf017b 100644 +--- a/src/coredump/coredump.c ++++ b/src/coredump/coredump.c +@@ -1273,7 +1273,7 @@ static int send_iovec(const struct iovec_wrapper *iovw, int input_fd, int mntns_ + if (sendmsg(fd, &mh, MSG_NOSIGNAL) >= 0) + break; + +- if (errno == EMSGSIZE && mh.msg_iov[0].iov_len > 0) { ++ if (IN_SET(errno, EMSGSIZE, ENOBUFS) && mh.msg_iov[0].iov_len > 0) { + /* This field didn't fit? That's a pity. Given that this is + * just metadata, let's truncate the field at half, and try + * again. We append three dots, in order to show that this is diff --git a/systemd.spec b/systemd.spec index 50e4e9a..26ba218 100644 --- a/systemd.spec +++ b/systemd.spec @@ -21,7 +21,7 @@ Name: systemd Url: https://systemd.io Version: 252 -Release: 60%{?dist} +Release: 61%{?dist} # For a breakdown of the licensing, see README License: LGPLv2+ and MIT and GPLv2+ Summary: System and Service Manager @@ -1366,6 +1366,12 @@ Patch1280: 1280-coredump-use-d-in-kernel-core-pattern.patch Patch1281: 1281-pidref-add-structure-that-can-reference-a-pid-via-bo.patch Patch1282: 1282-fd-util-introduce-parse_fd.patch Patch1283: 1283-coredump-add-support-for-new-F-PIDFD-specifier.patch +Patch1284: 1284-timer-rebase-the-next-elapse-timestamp-only-if-timer.patch +Patch1285: 1285-strv-introduce-string_strv_hashmap_remove.patch +Patch1286: 1286-unit-file-introduce-unit_file_remove_from_name_map.patch +Patch1287: 1287-core-unit-remove-path-to-transient-unit-file-from-un.patch +Patch1288: 1288-TEST-07-PID1-add-reprudcer-for-issue-35190.patch +Patch1289: 1289-coredump-handle-ENOBUFS-and-EMSGSIZE-the-same-way.patch # Downstream-only patches (9000–9999) @@ -2243,6 +2249,14 @@ systemd-hwdb update &>/dev/null || : %{_prefix}/lib/dracut/modules.d/70rhel-net-naming-sysattrs/* %changelog +* Fri Nov 21 2025 systemd maintenance team - 252-61 +- timer: rebase the next elapse timestamp only if timer didn't already run (RHEL-118215) +- strv: introduce string_strv_hashmap_remove() (RHEL-14112) +- unit-file: introduce unit_file_remove_from_name_map() (RHEL-14112) +- core/unit: remove path to transient unit file from unit name maps on stop (RHEL-14112) +- TEST-07-PID1: add reprudcer for issue #35190 (RHEL-14112) +- coredump: handle ENOBUFS and EMSGSIZE the same way (RHEL-103801) + * Wed Nov 05 2025 systemd maintenance team - 252-60 - man: fix a missing word (RHEL-115182) - cryptsetup: Add optional support for linking volume key in keyring. (RHEL-97175)