From 82d69edaf98fff2c09767a29452cbc0fb622363d Mon Sep 17 00:00:00 2001 From: AlmaLinux RelEng Bot Date: Tue, 16 Jun 2026 12:28:44 -0400 Subject: [PATCH] import CS git systemd-239-82.el8_10.17 --- ...ree-to-follow-our-usual-return-NULL-.patch | 48 ++++++ ...-jobs-finishing-during-reload-explic.patch | 135 +++++++++++++++++ ...ful-when-removing-job-object-from-jo.patch | 34 +++++ ...-core-rework-how-we-deserialize-jobs.patch | 142 ++++++++++++++++++ ...-state-changes-only-propagate-to-job.patch | 72 +++++++++ ...ments-regarding-coldplug-vs.-catchup.patch | 36 +++++ SPECS/systemd.spec | 16 +- 7 files changed, 482 insertions(+), 1 deletion(-) create mode 100644 SOURCES/1076-job-update-job_free-to-follow-our-usual-return-NULL-.patch create mode 100644 SOURCES/1077-core-don-t-track-jobs-finishing-during-reload-explic.patch create mode 100644 SOURCES/1078-job-be-more-careful-when-removing-job-object-from-jo.patch create mode 100644 SOURCES/1079-core-rework-how-we-deserialize-jobs.patch create mode 100644 SOURCES/1080-core-when-a-unit-state-changes-only-propagate-to-job.patch create mode 100644 SOURCES/1081-core-extend-comments-regarding-coldplug-vs.-catchup.patch diff --git a/SOURCES/1076-job-update-job_free-to-follow-our-usual-return-NULL-.patch b/SOURCES/1076-job-update-job_free-to-follow-our-usual-return-NULL-.patch new file mode 100644 index 0000000..ac5958a --- /dev/null +++ b/SOURCES/1076-job-update-job_free-to-follow-our-usual-return-NULL-.patch @@ -0,0 +1,48 @@ +From a403a9f149773b8c7900e9b32f72949e023b8e99 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Mon, 10 Dec 2018 18:52:11 +0100 +Subject: [PATCH] job: update job_free() to follow our usual return-NULL style + +(cherry picked from commit 728ba51e98959dfd9ad9f70cf6526b0a84b529a0) + +Related: RHEL-168671 +--- + src/core/job.c | 4 ++-- + src/core/job.h | 2 +- + 2 files changed, 3 insertions(+), 3 deletions(-) + +diff --git a/src/core/job.c b/src/core/job.c +index 55f36b928f..9e6756caa2 100644 +--- a/src/core/job.c ++++ b/src/core/job.c +@@ -87,7 +87,7 @@ void job_unlink(Job *j) { + j->timer_event_source = sd_event_source_unref(j->timer_event_source); + } + +-void job_free(Job *j) { ++Job* job_free(Job *j) { + assert(j); + assert(!j->installed); + assert(!j->transaction_prev); +@@ -100,7 +100,7 @@ void job_free(Job *j) { + sd_bus_track_unref(j->bus_track); + strv_free(j->deserialized_clients); + +- free(j); ++ return mfree(j); + } + + static void job_set_state(Job *j, JobState state) { +diff --git a/src/core/job.h b/src/core/job.h +index 189fea20ca..7b4d2e7317 100644 +--- a/src/core/job.h ++++ b/src/core/job.h +@@ -162,7 +162,7 @@ struct Job { + Job* job_new(Unit *unit, JobType type); + Job* job_new_raw(Unit *unit); + void job_unlink(Job *job); +-void job_free(Job *job); ++Job* job_free(Job *job); + Job* job_install(Job *j); + int job_install_deserialized(Job *j); + void job_uninstall(Job *j); diff --git a/SOURCES/1077-core-don-t-track-jobs-finishing-during-reload-explic.patch b/SOURCES/1077-core-don-t-track-jobs-finishing-during-reload-explic.patch new file mode 100644 index 0000000..dfa511e --- /dev/null +++ b/SOURCES/1077-core-don-t-track-jobs-finishing-during-reload-explic.patch @@ -0,0 +1,135 @@ +From c9a7e899240de5af6c5756065b7c8ba38719bfd9 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Mon, 10 Dec 2018 18:52:28 +0100 +Subject: [PATCH] core: don't track jobs-finishing-during-reload explicitly + +Memory management is borked for this, and moreover this is unnecessary +since f0831ed2a03, i.e. since coldplug() and catchup() are two different +concepts: the former restoring the state from before a reload, the +latter than adjusting it again to the actual status in effect after the +reload. + +Fixes: #10716 +Mostly reverts: #8803 + +(cherry picked from commit 4a53080be637f6dad91515fc896d9f77fbc17f0c) + +Related: RHEL-168671 +--- + src/core/job.c | 21 +-------------------- + src/core/job.h | 1 - + src/core/manager.c | 14 -------------- + src/core/manager.h | 3 --- + 4 files changed, 1 insertion(+), 38 deletions(-) + +diff --git a/src/core/job.c b/src/core/job.c +index 9e6756caa2..30a0c8cd68 100644 +--- a/src/core/job.c ++++ b/src/core/job.c +@@ -39,7 +39,6 @@ Job* job_new_raw(Unit *unit) { + j->manager = unit->manager; + j->unit = unit; + j->type = _JOB_TYPE_INVALID; +- j->reloaded = false; + + return j; + } +@@ -255,7 +254,6 @@ int job_install_deserialized(Job *j) { + + *pj = j; + j->installed = true; +- j->reloaded = true; + + if (j->state == JOB_RUNNING) + j->unit->manager->n_running_jobs++; +@@ -959,19 +957,6 @@ static void job_fail_dependencies(Unit *u, UnitDependency d) { + } + } + +-static int job_save_pending_finished_job(Job *j) { +- int r; +- +- assert(j); +- +- r = set_ensure_allocated(&j->manager->pending_finished_jobs, NULL); +- if (r < 0) +- return r; +- +- job_unlink(j); +- return set_put(j->manager->pending_finished_jobs, j); +-} +- + int job_finish_and_invalidate(Job *j, JobResult result, bool recursive, bool already) { + Unit *u; + Unit *other; +@@ -1011,11 +996,7 @@ int job_finish_and_invalidate(Job *j, JobResult result, bool recursive, bool alr + j->manager->n_failed_jobs++; + + job_uninstall(j); +- /* Keep jobs started before the reload to send singal later, free all others */ +- if (!MANAGER_IS_RELOADING(j->manager) || +- !j->reloaded || +- job_save_pending_finished_job(j) < 0) +- job_free(j); ++ job_free(j); + + /* Fail depending jobs on failure */ + if (result != JOB_DONE && recursive) { +diff --git a/src/core/job.h b/src/core/job.h +index 7b4d2e7317..f40010f38d 100644 +--- a/src/core/job.h ++++ b/src/core/job.h +@@ -156,7 +156,6 @@ struct Job { + bool irreversible:1; + bool in_gc_queue:1; + bool ref_by_private_bus:1; +- bool reloaded:1; + }; + + Job* job_new(Unit *unit, JobType type); +diff --git a/src/core/manager.c b/src/core/manager.c +index 51325f0212..f242f0cc00 100644 +--- a/src/core/manager.c ++++ b/src/core/manager.c +@@ -3450,17 +3450,6 @@ finish: + return r; + } + +-static void manager_flush_finished_jobs(Manager *m) { +- Job *j; +- +- while ((j = set_steal_first(m->pending_finished_jobs))) { +- bus_job_send_removed_signal(j); +- job_free(j); +- } +- +- m->pending_finished_jobs = set_free(m->pending_finished_jobs); +-} +- + int manager_reload(Manager *m) { + int r, q; + _cleanup_fclose_ FILE *f = NULL; +@@ -3582,9 +3571,6 @@ int manager_reload(Manager *m) { + if (q < 0 && r >= 0) + r = q; + +- if (!MANAGER_IS_RELOADING(m)) +- manager_flush_finished_jobs(m); +- + m->send_reloading_done = true; + + return r; +diff --git a/src/core/manager.h b/src/core/manager.h +index e713250238..a043a469a2 100644 +--- a/src/core/manager.h ++++ b/src/core/manager.h +@@ -310,9 +310,6 @@ struct Manager { + + /* non-zero if we are reloading or reexecuting, */ + int n_reloading; +- /* A set which contains all jobs that started before reload and finished +- * during it */ +- Set *pending_finished_jobs; + + unsigned n_installed_jobs; + unsigned n_failed_jobs; diff --git a/SOURCES/1078-job-be-more-careful-when-removing-job-object-from-jo.patch b/SOURCES/1078-job-be-more-careful-when-removing-job-object-from-jo.patch new file mode 100644 index 0000000..cd48902 --- /dev/null +++ b/SOURCES/1078-job-be-more-careful-when-removing-job-object-from-jo.patch @@ -0,0 +1,34 @@ +From ee856def59ca099ed0477d66538493ccfed51f46 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Mon, 10 Dec 2018 19:38:38 +0100 +Subject: [PATCH] job: be more careful when removing job object from jobs hash + table + +Let's validate that the ID is actually allocated to us before remove a +job. + +This is relevant as various bits of code will call job_free() on +partially set up Job objects, and we really shouldn't remove another job +object accidentally from the hash table, when the set up didn't +complete. + +(cherry picked from commit 48235ad6b7ef168e029d48701a08b62b616bcdd2) + +Related: RHEL-168671 +--- + src/core/job.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/core/job.c b/src/core/job.c +index 30a0c8cd68..9f9396312f 100644 +--- a/src/core/job.c ++++ b/src/core/job.c +@@ -148,7 +148,7 @@ void job_uninstall(Job *j) { + + unit_add_to_gc_queue(j->unit); + +- hashmap_remove(j->manager->jobs, UINT32_TO_PTR(j->id)); ++ hashmap_remove_value(j->manager->jobs, UINT32_TO_PTR(j->id), j); + j->installed = false; + } + diff --git a/SOURCES/1079-core-rework-how-we-deserialize-jobs.patch b/SOURCES/1079-core-rework-how-we-deserialize-jobs.patch new file mode 100644 index 0000000..f4a83f2 --- /dev/null +++ b/SOURCES/1079-core-rework-how-we-deserialize-jobs.patch @@ -0,0 +1,142 @@ +From 2710b77aad881e18166dac0899431506cf364ca3 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Mon, 10 Dec 2018 19:40:37 +0100 +Subject: [PATCH] core: rework how we deserialize jobs + +Let's add a helper call unit_deserialize_job() for this purpose, and +let's move registration in the global jobs hash table into +job_install_deserialized() so that it it is done after all superficial +checks are done, and before transitioning into installed states, so that +rollback code is not necessary anymore. + +(cherry picked from commit b17c9620c87a1d8117da72b30a2e096df02a2bb5) + +Related: RHEL-168671 +--- + src/core/job.c | 22 +++++++++++++-------- + src/core/job.h | 2 ++ + src/core/unit.c | 52 +++++++++++++++++++++++++------------------------ + 3 files changed, 43 insertions(+), 33 deletions(-) + +diff --git a/src/core/job.c b/src/core/job.c +index 9f9396312f..9b0c260f4f 100644 +--- a/src/core/job.c ++++ b/src/core/job.c +@@ -238,19 +238,25 @@ Job* job_install(Job *j) { + + int job_install_deserialized(Job *j) { + Job **pj; ++ int r; + + assert(!j->installed); + +- if (j->type < 0 || j->type >= _JOB_TYPE_MAX_IN_TRANSACTION) { +- log_debug("Invalid job type %s in deserialization.", strna(job_type_to_string(j->type))); +- return -EINVAL; +- } ++ if (j->type < 0 || j->type >= _JOB_TYPE_MAX_IN_TRANSACTION) ++ return log_unit_debug_errno(j->unit, -EINVAL, ++ "Invalid job type %s in deserialization.", ++ strna(job_type_to_string(j->type))); + + pj = (j->type == JOB_NOP) ? &j->unit->nop_job : &j->unit->job; +- if (*pj) { +- log_unit_debug(j->unit, "Unit already has a job installed. Not installing deserialized job."); +- return -EEXIST; +- } ++ if (*pj) ++ return log_unit_debug_errno(j->unit, -EEXIST, ++ "Unit already has a job installed. Not installing deserialized job."); ++ ++ r = hashmap_put(j->manager->jobs, UINT32_TO_PTR(j->id), j); ++ if (r == -EEXIST) ++ return log_unit_debug_errno(j->unit, r, "Job ID %" PRIu32 " already used, cannot deserialize job.", j->id); ++ if (r < 0) ++ return log_unit_debug_errno(j->unit, r, "Failed to insert job into jobs hash table: %m"); + + *pj = j; + j->installed = true; +diff --git a/src/core/job.h b/src/core/job.h +index f40010f38d..0dccc4225b 100644 +--- a/src/core/job.h ++++ b/src/core/job.h +@@ -222,6 +222,8 @@ void job_add_to_gc_queue(Job *j); + int job_get_before(Job *j, Job*** ret); + int job_get_after(Job *j, Job*** ret); + ++DEFINE_TRIVIAL_CLEANUP_FUNC(Job*, job_free); ++ + const char* job_type_to_string(JobType t) _const_; + JobType job_type_from_string(const char *s) _pure_; + +diff --git a/src/core/unit.c b/src/core/unit.c +index 70e1d68ea4..9dada18378 100644 +--- a/src/core/unit.c ++++ b/src/core/unit.c +@@ -3440,6 +3440,29 @@ void unit_serialize_item_format(Unit *u, FILE *f, const char *key, const char *f + fputc('\n', f); + } + ++static int unit_deserialize_job(Unit *u, FILE *f) { ++ _cleanup_(job_freep) Job *j = NULL; ++ int r; ++ ++ assert(u); ++ assert(f); ++ ++ j = job_new_raw(u); ++ if (!j) ++ return log_oom(); ++ ++ r = job_deserialize(j, f); ++ if (r < 0) ++ return r; ++ ++ r = job_install_deserialized(j); ++ if (r < 0) ++ return r; ++ ++ TAKE_PTR(j); ++ return 0; ++} ++ + int unit_deserialize(Unit *u, FILE *f, FDSet *fds) { + int r; + +@@ -3473,32 +3496,11 @@ int unit_deserialize(Unit *u, FILE *f, FDSet *fds) { + + if (streq(l, "job")) { + if (v[0] == '\0') { +- /* new-style serialized job */ +- Job *j; +- +- j = job_new_raw(u); +- if (!j) +- return log_oom(); +- +- r = job_deserialize(j, f); +- if (r < 0) { +- job_free(j); +- return r; +- } +- +- r = hashmap_put(u->manager->jobs, UINT32_TO_PTR(j->id), j); +- if (r < 0) { +- job_free(j); +- return r; +- } +- +- r = job_install_deserialized(j); +- if (r < 0) { +- hashmap_remove(u->manager->jobs, UINT32_TO_PTR(j->id)); +- job_free(j); ++ /* New-style serialized job */ ++ r = unit_deserialize_job(u, f); ++ if (r < 0) + return r; +- } +- } else /* legacy for pre-44 */ ++ } else /* Legacy for pre-44 */ + log_unit_warning(u, "Update from too old systemd versions are unsupported, cannot deserialize job: %s", v); + continue; + } else if (streq(l, "state-change-timestamp")) { diff --git a/SOURCES/1080-core-when-a-unit-state-changes-only-propagate-to-job.patch b/SOURCES/1080-core-when-a-unit-state-changes-only-propagate-to-job.patch new file mode 100644 index 0000000..23655cb --- /dev/null +++ b/SOURCES/1080-core-when-a-unit-state-changes-only-propagate-to-job.patch @@ -0,0 +1,72 @@ +From cd6e9c951e745fce3e1b8bf5ddae551276ea564c Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Tue, 11 Dec 2018 11:59:39 +0100 +Subject: [PATCH] core: when a unit state changes only propagate to jobs after + reloading is complete + +Previously, we'd immediately propagate unit state changes into any jobs +pending for them, always. With this we only do this if the manager is +out of the "reload" state. This fixes the problem #8803 tried to +address, by simply not completing jobs until after the reload (and thus +reestablishment of the dbus connection) is complete. + +Note that there's no need to later on explicitly catch up with the +missed job state changes (i.e. there's no need to call +unit_process_job() later one explicitly). That's because for jobs in +JOB_WAITING state on deserialization all jobs are requeued into the run +queue anyway, and thus checked again if they can complete now. And for +JOB_RUNNING jobs unit_catchup() phase is going to trigger missed out +state changes *after* the reload complete anyway (after all that's what +distinguishes from unit_coldplug()). + +Replaces: #8803 +(cherry picked from commit a1c7334b619de28ec20392628db3a0f46b5f0bdc) + +Related: RHEL-168671 +--- + src/core/unit.c | 23 ++++++++++------------- + 1 file changed, 10 insertions(+), 13 deletions(-) + +diff --git a/src/core/unit.c b/src/core/unit.c +index 9dada18378..29dea1f6db 100644 +--- a/src/core/unit.c ++++ b/src/core/unit.c +@@ -2379,7 +2379,6 @@ static bool unit_process_job(Job *j, UnitActiveState ns, UnitNotifyFlags flags) + } + + void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, UnitNotifyFlags flags) { +- bool unexpected; + Manager *m; + + assert(u); +@@ -2418,20 +2417,18 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, UnitNotifyFlag + + unit_update_on_console(u); + +- /* Let's propagate state changes to the job */ +- if (u->job) +- unexpected = unit_process_job(u->job, ns, flags); +- else +- unexpected = true; +- + if (!MANAGER_IS_RELOADING(m)) { ++ bool unexpected; ++ ++ /* Let's propagate state changes to the job */ ++ if (u->job) ++ unexpected = unit_process_job(u->job, ns, flags); ++ else ++ unexpected = true; + +- /* If this state change happened without being +- * requested by a job, then let's retroactively start +- * or stop dependencies. We skip that step when +- * deserializing, since we don't want to create any +- * additional jobs just because something is already +- * activated. */ ++ /* If this state change happened without being requested by a job, then let's retroactively start or ++ * stop dependencies. We skip that step when deserializing, since we don't want to create any ++ * additional jobs just because something is already activated. */ + + if (unexpected) { + if (UNIT_IS_INACTIVE_OR_FAILED(os) && UNIT_IS_ACTIVE_OR_ACTIVATING(ns)) diff --git a/SOURCES/1081-core-extend-comments-regarding-coldplug-vs.-catchup.patch b/SOURCES/1081-core-extend-comments-regarding-coldplug-vs.-catchup.patch new file mode 100644 index 0000000..3f25eba --- /dev/null +++ b/SOURCES/1081-core-extend-comments-regarding-coldplug-vs.-catchup.patch @@ -0,0 +1,36 @@ +From dd0c1ce0eec10226da5789c43ba4b3f5305ea012 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Tue, 11 Dec 2018 15:22:10 +0100 +Subject: [PATCH] core: extend comments regarding coldplug() vs. catchup() + +(cherry picked from commit a95c0505ad89b77878ed05192fe91175cf42e8b5) + +Related: RHEL-168671 +--- + src/core/unit.h | 11 ++++++++--- + 1 file changed, 8 insertions(+), 3 deletions(-) + +diff --git a/src/core/unit.h b/src/core/unit.h +index e2dd7949e5..914035d55c 100644 +--- a/src/core/unit.h ++++ b/src/core/unit.h +@@ -446,11 +446,16 @@ typedef struct UnitVTable { + int (*load)(Unit *u); + + /* During deserialization we only record the intended state to return to. With coldplug() we actually put the +- * deserialized state in effect. This is where unit_notify() should be called to start things up. */ ++ * deserialized state in effect. This is where unit_notify() should be called to start things up. Note that ++ * this callback is invoked *before* we leave the reloading state of the manager, i.e. *before* we consider the ++ * reloading to be complete. Thus, this callback should just restore the exact same state for any unit that was ++ * in effect before the reload, i.e. units should not catch up with changes happened during the reload. That's ++ * what catchup() below is for. */ + int (*coldplug)(Unit *u); + +- /* This is called shortly after all units' coldplug() call was invoked. It's supposed to catch up state changes +- * we missed so far (for example because they took place while we were reloading/reexecing) */ ++ /* This is called shortly after all units' coldplug() call was invoked, and *after* the manager left the ++ * reloading state. It's supposed to catch up with state changes due to external events we missed so far (for ++ * example because they took place while we were reloading/reexecing) */ + void (*catchup)(Unit *u); + + void (*dump)(Unit *u, FILE *f, const char *prefix); diff --git a/SPECS/systemd.spec b/SPECS/systemd.spec index 1d0bb32..3ad97f4 100644 --- a/SPECS/systemd.spec +++ b/SPECS/systemd.spec @@ -13,7 +13,7 @@ Name: systemd Url: http://www.freedesktop.org/wiki/Software/systemd Version: 239 -Release: 82%{?dist}.16 +Release: 82%{?dist}.17 # For a breakdown of the licensing, see README License: LGPLv2+ and MIT and GPLv2+ Summary: System and Service Manager @@ -1125,6 +1125,12 @@ Patch1072: 1072-udev-check-for-invalid-chars-in-various-fields-recei.patch Patch1073: 1073-udev-fix-review-mixup.patch Patch1074: 1074-udev-scsi-id-check-for-invalid-chars-in-various-fiel.patch Patch1075: 1075-core-manager-fix-memory-leak.patch +Patch1076: 1076-job-update-job_free-to-follow-our-usual-return-NULL-.patch +Patch1077: 1077-core-don-t-track-jobs-finishing-during-reload-explic.patch +Patch1078: 1078-job-be-more-careful-when-removing-job-object-from-jo.patch +Patch1079: 1079-core-rework-how-we-deserialize-jobs.patch +Patch1080: 1080-core-when-a-unit-state-changes-only-propagate-to-job.patch +Patch1081: 1081-core-extend-comments-regarding-coldplug-vs.-catchup.patch %ifarch %{ix86} x86_64 aarch64 %global have_gnu_efi 1 @@ -1751,6 +1757,14 @@ fi %files tests -f .file-list-tests %changelog +* Mon May 25 2026 systemd maintenance team - 239-82.17 +- job: update job_free() to follow our usual return-NULL style (RHEL-168671) +- core: don't track jobs-finishing-during-reload explicitly (RHEL-168671) +- job: be more careful when removing job object from jobs hash table (RHEL-168671) +- core: rework how we deserialize jobs (RHEL-168671) +- core: when a unit state changes only propagate to jobs after reloading is complete (RHEL-168671) +- core: extend comments regarding coldplug() vs. catchup() (RHEL-168671) + * Thu Apr 16 2026 systemd maintenance team - 239-82.16 - core: validate input cgroup path more prudently (RHEL-152085) - nspawn: normalize pivot_root paths (RHEL-163868)