]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
core: record transactions that have seen ordering cycles
authorMike Yuan <me@yhndnzj.com>
Sat, 4 Oct 2025 23:07:48 +0000 (01:07 +0200)
committerMike Yuan <me@yhndnzj.com>
Wed, 12 Nov 2025 22:47:39 +0000 (23:47 +0100)
catalog/systemd.catalog.in
src/core/manager.c
src/core/manager.h
src/core/transaction.c

index 4152112078c630ba853b8b4467d0756be11af039..8172a6128ac114b1d6b2008cb967e7dc8d493613 100644 (file)
@@ -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
index bb2c1bece13de52506b2c5122335b7a13637b9ba..0a6ea1658f15b4dc4764132e6491257ab7074f6d 100644 (file)
@@ -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) {
index d0855260bfcd3dc96ea2cc585bdc728fce3657e7..980aaab5f630539fe7f79670c78ab4add54718e6 100644 (file)
@@ -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;
index 34a0faf5568baab46b65686030fb4dae6e32acda..536f9d78c306da36a1ae3fd9c199331fde8b42c4 100644 (file)
@@ -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 */