From dd01fc11f599dbfe0a1d5a42e60f9364ae991d31 Mon Sep 17 00:00:00 2001 From: Ronan Pigott Date: Fri, 18 Jul 2025 15:10:03 +0200 Subject: [PATCH] dbus: stash the subscriber list when we disconenct from the bus If we unexpectly disconnect from the bus, systemd would end up dropping the list of subscribers, which breaks the ability of clients like logind to monitor the state of units. Stash the list of subscribers into the deserialized state in the event of a disconnect so that when we recover we can renew the broken subscriptions. (cherry picked from commit 8402ca04d1a063c3d8a9e3d5c16df8bb8778ae98) Related: RHEL-75081 --- src/core/dbus.c | 23 ++++++++++++++++------- src/core/dbus.h | 2 +- src/core/manager.c | 5 ++++- src/shared/bus-util.c | 22 ++++++++++++++++++++++ src/shared/bus-util.h | 1 + 5 files changed, 44 insertions(+), 9 deletions(-) diff --git a/src/core/dbus.c b/src/core/dbus.c index ec6c52cb85..1b8bb44eda 100644 --- a/src/core/dbus.c +++ b/src/core/dbus.c @@ -908,6 +908,8 @@ int bus_init_api(Manager *m) { if (r < 0) return log_error_errno(r, "Failed to set up API bus: %m"); + (void) bus_track_coldplug(bus, &m->subscribed, /* recursive= */ false, m->deserialized_subscribed); + m->deserialized_subscribed = strv_free(m->deserialized_subscribed); m->api_bus = TAKE_PTR(bus); r = manager_enqueue_sync_bus_names(m); @@ -1070,8 +1072,17 @@ static void destroy_bus(Manager *m, sd_bus **bus) { } /* Get rid of tracked clients on this bus */ - if (m->subscribed && sd_bus_track_get_bus(m->subscribed) == *bus) + if (m->subscribed && sd_bus_track_get_bus(m->subscribed) == *bus) { + _cleanup_strv_free_ char **subscribed = NULL; + int r; + + r = bus_track_to_strv(m->subscribed, &subscribed); + if (r < 0) + log_warning_errno(r, "Failed to serialize api subscribers, ignoring: %m"); + strv_free_and_replace(m->deserialized_subscribed, subscribed); + m->subscribed = sd_bus_track_unref(m->subscribed); + } HASHMAP_FOREACH(j, m->jobs, i) if (j->bus_track && sd_bus_track_get_bus(j->bus_track) == *bus) @@ -1131,7 +1142,6 @@ void bus_done(Manager *m) { assert(!m->subscribed); - m->deserialized_subscribed = strv_free(m->deserialized_subscribed); bus_verify_polkit_async_registry_free(m->polkit_registry); } @@ -1229,20 +1239,19 @@ void bus_track_serialize(sd_bus_track *t, FILE *f, const char *prefix) { } } -int bus_track_coldplug(Manager *m, sd_bus_track **t, bool recursive, char **l) { - int r = 0; +int bus_track_coldplug(sd_bus *bus, sd_bus_track **t, bool recursive, char **l) { + int r; - assert(m); assert(t); if (strv_isempty(l)) return 0; - if (!m->api_bus) + if (!bus) return 0; if (!*t) { - r = sd_bus_track_new(m->api_bus, t, NULL, NULL); + r = sd_bus_track_new(bus, t, NULL, NULL); if (r < 0) return r; } diff --git a/src/core/dbus.h b/src/core/dbus.h index f1c0fa86c0..402c970d74 100644 --- a/src/core/dbus.h +++ b/src/core/dbus.h @@ -19,7 +19,7 @@ void bus_done(Manager *m); int bus_fdset_add_all(Manager *m, FDSet *fds); void bus_track_serialize(sd_bus_track *t, FILE *f, const char *prefix); -int bus_track_coldplug(Manager *m, sd_bus_track **t, bool recursive, char **l); +int bus_track_coldplug(sd_bus *bus, sd_bus_track **t, bool recursive, char **l); int manager_enqueue_sync_bus_names(Manager *m); diff --git a/src/core/manager.c b/src/core/manager.c index e09227d5ac..c5d906e42e 100644 --- a/src/core/manager.c +++ b/src/core/manager.c @@ -1348,6 +1348,9 @@ Manager* manager_free(Manager *m) { free(m->switch_root); free(m->switch_root_init); + sd_bus_track_unref(m->subscribed); + strv_free(m->deserialized_subscribed); + rlimit_free_all(m->rlimit); assert(hashmap_isempty(m->units_requiring_mounts_for)); @@ -1656,7 +1659,7 @@ int manager_startup(Manager *m, FILE *serialization, FDSet *fds) { manager_setup_bus(m); /* Now that we are connected to all possible busses, let's deserialize who is tracking us. */ - (void) bus_track_coldplug(m, &m->subscribed, false, m->deserialized_subscribed); + (void) bus_track_coldplug(m->api_bus, &m->subscribed, false, m->deserialized_subscribed); m->deserialized_subscribed = strv_free(m->deserialized_subscribed); /* Third, fire things up! */ diff --git a/src/shared/bus-util.c b/src/shared/bus-util.c index ff0e800347..5ce4613262 100644 --- a/src/shared/bus-util.c +++ b/src/shared/bus-util.c @@ -1694,6 +1694,28 @@ int bus_track_add_name_many(sd_bus_track *t, char **l) { return r; } +int bus_track_to_strv(sd_bus_track *t, char ***ret) { + _cleanup_strv_free_ char **subscribed = NULL; + int r = 0; + + assert(ret); + + for (const char *n = sd_bus_track_first(t); n; n = sd_bus_track_next(t)) { + r = sd_bus_track_count_name(t, n); + if (r < 0) + return r; + + for (int j = 0; j < r; j++) { + r = strv_extend(&subscribed, n); + if (r < 0) + return r; + } + } + + *ret = TAKE_PTR(subscribed); + return r; +} + int bus_open_system_watch_bind_with_description(sd_bus **ret, const char *description) { _cleanup_(sd_bus_unrefp) sd_bus *bus = NULL; const char *e; diff --git a/src/shared/bus-util.h b/src/shared/bus-util.h index b400eb81e2..b3aa62e6e5 100644 --- a/src/shared/bus-util.h +++ b/src/shared/bus-util.h @@ -171,6 +171,7 @@ int bus_path_decode_unique(const char *path, const char *prefix, char **ret_send int bus_property_get_rlimit(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *error); int bus_track_add_name_many(sd_bus_track *t, char **l); +int bus_track_to_strv(sd_bus_track *t, char ***ret); int bus_open_system_watch_bind_with_description(sd_bus **ret, const char *description); static inline int bus_open_system_watch_bind(sd_bus **ret) {