forked from pool/systemd
62682e6e22
- Fix patch patch handle-numlock-value-in-etc-sysconfig-keyboard.patch that is do not close a file descriptor twice (boo#973907) - Add two patches which address logind/networkd disappearing from dbus (and busctl) even while the units and processes continue running. 0001-core-fix-bus-name-synchronization-after-daemon-reloa.patch 0001-core-re-sync-bus-name-list-after-deserializing-durin.patch - drop all compiler/linker option customizations: - -pipe option is used by default since day 0 - get rid of cflags() function which is not needed - --hash-size has no impact specially in runtime IOW, use the default options for the compiler and the linker, there's no point in making systemd different from other package in this regards. - use %make_build instead of 'make %{?_smp_mflags}' - be more strict on own lib version requirements - systemd should require udev with the exact same version - Modify patch handle-numlock-value-in-etc-sysconfig-keyboard.patch to allow that open, seek, and read of /dev/mem may fail e.g. on XEN based virtual guests (bsc#961120) - require curl and bzip2 to build importd - curl also causes building of journal-upload. That one has rather unusal certificate usage, set it's ca root to /etc/pki/systemd OBS-URL: https://build.opensuse.org/request/show/384339 OBS-URL: https://build.opensuse.org/package/show/openSUSE:Factory/systemd?expand=0&rev=232
194 lines
8.0 KiB
Diff
194 lines
8.0 KiB
Diff
From d8ccf5fdc91c46ab5d0ae86e38c206bc508d4188 Mon Sep 17 00:00:00 2001 [> v228]
|
|
From: Daniel Mack <daniel@zonque.org>
|
|
Date: Fri, 18 Dec 2015 17:28:15 +0100
|
|
Subject: [PATCH] core: fix bus name synchronization after daemon-reload
|
|
|
|
During daemon-reload, PID1 temporarly loses its DBus connection, so there's
|
|
a small window in which all signals sent by dbus-daemon are lost.
|
|
|
|
This is a problem, since we rely on the NameOwnerChanged signals in order to
|
|
consider a service with Type=dbus fully started or terminated, respectively.
|
|
|
|
In order to fix this, a rewrite of bus_list_names() is necessary. We used
|
|
to walk the current list of names on the bus, and blindly triggered the
|
|
bus_name_owner_change() callback on each service, providing the actual name
|
|
as current owner. This implementation has a number of problems:
|
|
|
|
* We cannot detect if the the name was moved from one owner to the other
|
|
while we were reloading
|
|
|
|
* We don't notify services which missed the name loss signal
|
|
|
|
* Providing the actual name as current owner is a hack, as the comment also
|
|
admits.
|
|
|
|
To fix this, this patch carries the following changes:
|
|
|
|
* Track the name of the current bus name owner, and (de-)serialize it
|
|
during reload. This way, we can detect changes.
|
|
|
|
* In bus_list_names(), walk the list of bus names we're interested in
|
|
first, and then see if the name is active on the bus. If it is,
|
|
check it it's still the same as it used to be, and synthesize
|
|
NameOwnerChanged signals for the name add and/or loss.
|
|
|
|
This should fully synchronize the current name list with the internal
|
|
state of all services.
|
|
---
|
|
src/core/dbus.c | 64 +++++++++++++++++++++++++++++++++++++++++++++---------
|
|
src/core/service.c | 14 ++++++++++++
|
|
src/core/service.h | 1 +
|
|
3 files changed, 69 insertions(+), 10 deletions(-)
|
|
|
|
diff --git a/src/core/dbus.c b/src/core/dbus.c
|
|
index e7ee216..58069f5 100644
|
|
--- a/src/core/dbus.c
|
|
+++ b/src/core/dbus.c
|
|
@@ -736,7 +736,9 @@ static int bus_on_connection(sd_event_source *s, int fd, uint32_t revents, void
|
|
|
|
static int bus_list_names(Manager *m, sd_bus *bus) {
|
|
_cleanup_strv_free_ char **names = NULL;
|
|
- char **i;
|
|
+ const char *name;
|
|
+ Iterator i;
|
|
+ Unit *u;
|
|
int r;
|
|
|
|
assert(m);
|
|
@@ -746,15 +748,55 @@ static int bus_list_names(Manager *m, sd_bus *bus) {
|
|
if (r < 0)
|
|
return log_error_errno(r, "Failed to get initial list of names: %m");
|
|
|
|
- /* This is a bit hacky, we say the owner of the name is the
|
|
- * name itself, because we don't want the extra traffic to
|
|
- * figure out the real owner. */
|
|
- STRV_FOREACH(i, names) {
|
|
- Unit *u;
|
|
+ /* We have to synchronize the current bus names with the
|
|
+ * list of active services. To do this, walk the list of
|
|
+ * all units with bus names. */
|
|
+ HASHMAP_FOREACH_KEY(u, name, m->watch_bus, i) {
|
|
+ Service *s = SERVICE(u);
|
|
+
|
|
+ assert(s);
|
|
|
|
- u = hashmap_get(m->watch_bus, *i);
|
|
- if (u)
|
|
- UNIT_VTABLE(u)->bus_name_owner_change(u, *i, NULL, *i);
|
|
+ if (!streq_ptr(s->bus_name, name)) {
|
|
+ log_unit_warning(u, "Bus name has changed from %s → %s, ignoring.", s->bus_name, name);
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ /* Check if a service's bus name is in the list of currently
|
|
+ * active names */
|
|
+ if (strv_contains(names, name)) {
|
|
+ _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
|
|
+ const char *unique;
|
|
+
|
|
+ /* If it is, determine its current owner */
|
|
+ r = sd_bus_get_name_creds(bus, name, SD_BUS_CREDS_UNIQUE_NAME, &creds);
|
|
+ if (r < 0) {
|
|
+ log_error_errno(r, "Failed to get bus name owner %s: %m", name);
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ r = sd_bus_creds_get_unique_name(creds, &unique);
|
|
+ if (r < 0) {
|
|
+ log_error_errno(r, "Failed to get unique name for %s: %m", name);
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ /* Now, let's compare that to the previous bus owner, and
|
|
+ * if it's still the same, all is fine, so just don't
|
|
+ * bother the service. Otherwise, the name has apparently
|
|
+ * changed, so synthesize a name owner changed signal. */
|
|
+
|
|
+ if (!streq_ptr(unique, s->bus_name_owner))
|
|
+ UNIT_VTABLE(u)->bus_name_owner_change(u, name, s->bus_name_owner, unique);
|
|
+ } else {
|
|
+ /* So, the name we're watching is not on the bus.
|
|
+ * This either means it simply hasn't appeared yet,
|
|
+ * or it was lost during the daemon reload.
|
|
+ * Check if the service has a stored name owner,
|
|
+ * and synthesize a name loss signal in this case. */
|
|
+
|
|
+ if (s->bus_name_owner)
|
|
+ UNIT_VTABLE(u)->bus_name_owner_change(u, name, s->bus_name_owner, NULL);
|
|
+ }
|
|
}
|
|
|
|
return 0;
|
|
@@ -808,7 +850,9 @@ static int bus_setup_api(Manager *m, sd_bus *bus) {
|
|
if (r < 0)
|
|
return log_error_errno(r, "Failed to register name: %m");
|
|
|
|
- bus_list_names(m, bus);
|
|
+ r = bus_list_names(m, bus);
|
|
+ if (r < 0)
|
|
+ return r;
|
|
|
|
log_debug("Successfully connected to API bus.");
|
|
return 0;
|
|
diff --git a/src/core/service.c b/src/core/service.c
|
|
index 41a729c..c5b689a 100644
|
|
--- a/src/core/service.c
|
|
+++ b/src/core/service.c
|
|
@@ -323,6 +323,8 @@ static void service_done(Unit *u) {
|
|
s->bus_name = mfree(s->bus_name);
|
|
}
|
|
|
|
+ s->bus_name_owner = mfree(s->bus_name_owner);
|
|
+
|
|
s->bus_endpoint_fd = safe_close(s->bus_endpoint_fd);
|
|
service_close_socket_fd(s);
|
|
service_connection_unref(s);
|
|
@@ -2122,6 +2124,7 @@ static int service_serialize(Unit *u, FILE *f, FDSet *fds) {
|
|
|
|
unit_serialize_item(u, f, "main-pid-known", yes_no(s->main_pid_known));
|
|
unit_serialize_item(u, f, "bus-name-good", yes_no(s->bus_name_good));
|
|
+ unit_serialize_item(u, f, "bus-name-owner", s->bus_name_owner);
|
|
|
|
r = unit_serialize_item_escaped(u, f, "status-text", s->status_text);
|
|
if (r < 0)
|
|
@@ -2249,6 +2252,10 @@ static int service_deserialize_item(Unit *u, const char *key, const char *value,
|
|
log_unit_debug(u, "Failed to parse bus-name-good value: %s", value);
|
|
else
|
|
s->bus_name_good = b;
|
|
+ } else if (streq(key, "bus-name-owner")) {
|
|
+ r = free_and_strdup(&s->bus_name_owner, value);
|
|
+ if (r < 0)
|
|
+ log_unit_error_errno(u, r, "Unable to deserialize current bus owner %s: %m", value);
|
|
} else if (streq(key, "status-text")) {
|
|
char *t;
|
|
|
|
@@ -3134,6 +3141,13 @@ static void service_bus_name_owner_change(
|
|
|
|
s->bus_name_good = !!new_owner;
|
|
|
|
+ /* Track the current owner, so we can reconstruct changes after a daemon reload */
|
|
+ r = free_and_strdup(&s->bus_name_owner, new_owner);
|
|
+ if (r < 0) {
|
|
+ log_unit_error_errno(u, r, "Unable to set new bus name owner %s: %m", new_owner);
|
|
+ return;
|
|
+ }
|
|
+
|
|
if (s->type == SERVICE_DBUS) {
|
|
|
|
/* service_enter_running() will figure out what to
|
|
diff --git a/src/core/service.h b/src/core/service.h
|
|
index d0faad8..19efbcc 100644
|
|
--- a/src/core/service.h
|
|
+++ b/src/core/service.h
|
|
@@ -172,6 +172,7 @@ struct Service {
|
|
bool reset_cpu_usage:1;
|
|
|
|
char *bus_name;
|
|
+ char *bus_name_owner; /* unique name of the current owner */
|
|
|
|
char *status_text;
|
|
int status_errno;
|
|
--
|
|
2.6.2
|
|
|