]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
core: postpone D-Bus queue dispatch until the API bus is set up
authorr-vdp <ramses@well-founded.dev>
Wed, 29 Jul 2026 07:52:57 +0000 (09:52 +0200)
committerr-vdp <ramses@well-founded.dev>
Wed, 29 Jul 2026 07:52:57 +0000 (09:52 +0200)
Since 1166f4472d ("core/dbus: do not block the manager on GetId during
bus (re-)connection") the API bus setup and the subscriber coldplug
happen only once the asynchronous GetId reply is processed by the
event loop. After a daemon-reexec, manager_dispatch_dbus_queue() runs
before subscribers were re-added, so bus_foreach_bus() skipped the
API bus and queued messages were lost for subscribers. In particular
the one-shot Reloading(false) signal was never sent, and clients that
wait for it to detect that a reexec finished timed out.

Track whether bus_setup_api() has run for the current API bus
connection, and postpone dispatching the queue until then.

src/core/dbus.c
src/core/manager.c
src/core/manager.h

index 5e5c3ccf1bfa0e5ea7b64941cfdd5de792681bbc..83a4e8912e091216955aab60125d248d1e30f9f0 100644 (file)
@@ -812,6 +812,8 @@ static int bus_setup_api(Manager *m, sd_bus *bus) {
         if (r < 0)
                 log_warning_errno(r, "Failed to register MemoryAllocation1, ignoring: %m");
 
+        m->api_bus_ready = true;
+
         log_debug("Successfully connected to API bus.");
 
         return 0;
@@ -1104,6 +1106,8 @@ static void destroy_bus(Manager *m, sd_bus **bus) {
 
 void bus_done_api(Manager *m) {
         destroy_bus(m, &m->api_bus);
+
+        m->api_bus_ready = false;
 }
 
 void bus_done_system(Manager *m) {
index ad525539ce59ef28a39c02ba6553e66d05024acd..e82ba36fd50e0960a0ba68a6e6c19bef6b16e104 100644 (file)
@@ -2892,6 +2892,14 @@ static unsigned manager_dispatch_dbus_queue(Manager *m) {
 
         assert(m);
 
+        /* If the API bus is connected but not fully set up yet (see bus_init_api()), postpone
+         * dispatching the queue, otherwise subscribers restored from a previous reexec would miss
+         * messages. The pending Varlink reload reply does not depend on the API bus, but it is held
+         * back too, so that the order between D-Bus messages and Varlink replies is preserved for
+         * clients that monitor both. */
+        if (m->api_bus && !m->api_bus_ready)
+                return 0;
+
         /* When we are reloading, let's not wait with generating signals, since we need to exit the manager as quickly
          * as we can. There's no point in throttling generation of signals in that case. */
         if (MANAGER_IS_RELOADING(m) || m->send_reloading_done || m->pending_reload_message_dbus || m->pending_reload_message_vl)
index 12d6cf44709d5a4fc99856d055768b61e20c3ce1..453ae74668ee4353e0490ef70eb8ef81b826e922 100644 (file)
@@ -341,6 +341,11 @@ typedef struct Manager {
         sd_bus_track *subscribed;
         char **subscribed_as_strv;
 
+        /* Set once bus_setup_api() succeeded for the current API bus connection, i.e. after any
+         * subscriptions deserialized from a previous reload/reexec were coldplugged. Unset when the
+         * connection is torn down. */
+        bool api_bus_ready;
+
         /* The bus id of API bus acquired through org.freedesktop.DBus.GetId, which before deserializing
          * subscriptions we'd use to verify the bus is still the same instance as before. */
         sd_id128_t bus_id, deserialized_bus_id;