From: Mike Yuan Date: Sat, 4 Oct 2025 23:07:48 +0000 (+0200) Subject: core: record transactions that have seen ordering cycles X-Git-Tag: v259-rc1~68^2~2 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=d3da74696bf03df821c1d9bf20cfdee893437fbe;p=thirdparty%2Fsystemd.git core: record transactions that have seen ordering cycles --- diff --git a/catalog/systemd.catalog.in b/catalog/systemd.catalog.in index 4152112078c..8172a6128ac 100644 --- a/catalog/systemd.catalog.in +++ b/catalog/systemd.catalog.in @@ -938,11 +938,12 @@ Defined-By: systemd Support: %SUPPORT_URL% Documentation: man:systemd(1) -A unit transaction was initiated that contains an ordering cycle, i.e. some -unit that was requested to be started (either directly, or indirectly due to a -requirement dependency such as Wants= or Requires=) is ordered before some -other unit (via After=/Before=), but that latter unit is also ordered before -the former by some dependency (either directly or indirectly). +A unit transaction (with ID @TRANSACTION_ID@) was initiated that contains +an ordering cycle, i.e. some unit that was requested to be started +(either directly, or indirectly due to a requirement dependency such as +Wants= or Requires=) is ordered before some other unit (via After=/Before=), +but that latter unit is also ordered before the former by some dependency +(either directly or indirectly). Ordering cycles consist of at least two units, but might involve many more. They generally indicate a bug in the unit definitions, as a unit diff --git a/src/core/manager.c b/src/core/manager.c index bb2c1bece13..0a6ea1658f1 100644 --- a/src/core/manager.c +++ b/src/core/manager.c @@ -1659,6 +1659,8 @@ static void manager_clear_jobs_and_units(Manager *m) { m->n_running_jobs = 0; m->n_installed_jobs = 0; m->n_failed_jobs = 0; + + m->transactions_with_cycle = set_free(m->transactions_with_cycle); } Manager* manager_free(Manager *m) { diff --git a/src/core/manager.h b/src/core/manager.h index d0855260bfc..980aaab5f63 100644 --- a/src/core/manager.h +++ b/src/core/manager.h @@ -238,6 +238,9 @@ typedef struct Manager { uint64_t last_transaction_id; + /* IDs of transactions that once encountered ordering cycle */ + Set *transactions_with_cycle; + sd_event_source *run_queue_event_source; char *notify_socket; diff --git a/src/core/transaction.c b/src/core/transaction.c index 34a0faf5568..536f9d78c30 100644 --- a/src/core/transaction.c +++ b/src/core/transaction.c @@ -8,6 +8,7 @@ #include "bus-common-errors.h" #include "bus-error.h" #include "dbus-unit.h" +#include "hash-funcs.h" #include "manager.h" #include "set.h" #include "slice.h" @@ -15,6 +16,8 @@ #include "strv.h" #include "transaction.h" +#define CYCLIC_TRANSACTIONS_MAX 4096U + static bool job_matters_to_anchor(Job *job); static void transaction_unlink_job(Transaction *tr, Job *j, bool delete_dependencies); @@ -399,6 +402,16 @@ static int transaction_verify_order_one(Transaction *tr, Job *j, Job *from, unsi LOG_MESSAGE_ID(SD_MESSAGE_UNIT_ORDERING_CYCLE_STR), LOG_ITEM("%s", strempty(unit_ids))); + if (set_size(j->manager->transactions_with_cycle) >= CYCLIC_TRANSACTIONS_MAX) + log_warning("Too many transactions with ordering cycle, suppressing record."); + else { + uint64_t *id_buf = newdup(uint64_t, &tr->id, 1); + if (!id_buf) + log_oom_warning(); + else + (void) set_ensure_consume(&j->manager->transactions_with_cycle, &uint64_hash_ops_value_free, id_buf); + } + if (delete) { const char *status; /* logging for j not k here to provide a consistent narrative */