Merged update from upstream sources
This is an automated DistroBaker update from upstream sources. If you do not know what this is about or would like to opt out, contact the OSCI team. Source: https://src.fedoraproject.org/rpms/dbus-broker.git#c5e28e5aba7bb801d3ebd1a410201eb155ea777c
This commit is contained in:
parent
d90451e203
commit
4d77ffa871
226
41ccab38eae2300e3d6f4e3eac0962ebe6e60ade.patch
Normal file
226
41ccab38eae2300e3d6f4e3eac0962ebe6e60ade.patch
Normal file
@ -0,0 +1,226 @@
|
||||
From 41ccab38eae2300e3d6f4e3eac0962ebe6e60ade Mon Sep 17 00:00:00 2001
|
||||
From: David Rheinsberg <david.rheinsberg@gmail.com>
|
||||
Date: Wed, 17 Feb 2021 12:01:49 +0100
|
||||
Subject: [PATCH] launch/service: track systemd jobs to close a race condition
|
||||
|
||||
Start tracking the `JobRemoved` signal of systemd to know the point at
|
||||
which systemd fully handled our submitted job. There is no other way to
|
||||
reliably know when we can start handling PropertiesChanged signals.
|
||||
systemd does not guarantee any other barrier on the bus but the
|
||||
JobRemoved signal.
|
||||
|
||||
This is unfortunate, since it requires us to watch *all* JobRemoved
|
||||
signals of systemd. However, according to systemd developers, it is the
|
||||
only supported way to track Job submission. Hence, we have to comply.
|
||||
|
||||
Signed-off-by: David Rheinsberg <david.rheinsberg@gmail.com>
|
||||
---
|
||||
src/launch/service.c | 119 ++++++++++++++++++++++++++++++++++++++++++-
|
||||
src/launch/service.h | 2 +
|
||||
2 files changed, 119 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/src/launch/service.c b/src/launch/service.c
|
||||
index ab1a7b8..f23fa2d 100644
|
||||
--- a/src/launch/service.c
|
||||
+++ b/src/launch/service.c
|
||||
@@ -80,6 +80,7 @@ Service *service_free(Service *service) {
|
||||
|
||||
c_rbnode_unlink(&service->rb_by_name);
|
||||
c_rbnode_unlink(&service->rb);
|
||||
+ free(service->job);
|
||||
free(service->user);
|
||||
for (size_t i = 0; i < service->argc; ++i)
|
||||
free(service->argv[i]);
|
||||
@@ -89,6 +90,7 @@ Service *service_free(Service *service) {
|
||||
free(service->path);
|
||||
service->slot_start_unit = sd_bus_slot_unref(service->slot_start_unit);
|
||||
service->slot_watch_unit = sd_bus_slot_unref(service->slot_watch_unit);
|
||||
+ service->slot_watch_jobs = sd_bus_slot_unref(service->slot_watch_jobs);
|
||||
free(service);
|
||||
|
||||
return NULL;
|
||||
@@ -180,8 +182,10 @@ int service_new(Service **servicep,
|
||||
}
|
||||
|
||||
static void service_discard_activation(Service *service) {
|
||||
+ service->job = c_free(service->job);
|
||||
service->slot_start_unit = sd_bus_slot_unref(service->slot_start_unit);
|
||||
service->slot_watch_unit = sd_bus_slot_unref(service->slot_watch_unit);
|
||||
+ service->slot_watch_jobs = sd_bus_slot_unref(service->slot_watch_jobs);
|
||||
}
|
||||
|
||||
static int service_reset_activation(Service *service) {
|
||||
@@ -216,11 +220,97 @@ static int service_reset_activation(Service *service) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
+static int service_watch_jobs_handler(sd_bus_message *message, void *userdata, sd_bus_error *errorp) {
|
||||
+ Service *service = userdata;
|
||||
+ const char *path = NULL, *unit = NULL, *result = NULL;
|
||||
+ uint32_t id;
|
||||
+ int r;
|
||||
+
|
||||
+ /*
|
||||
+ * Whenever we have an activation job queued, we want to know when it
|
||||
+ * is done. We get a `JobRemoved` signal from systemd, which includes
|
||||
+ * the reason why the job is done.
|
||||
+ * We get those signals for all jobs, since we cannot know a job-id to
|
||||
+ * match for before we create job. This is quite unfortunate, but
|
||||
+ * little we can do about it now.
|
||||
+ *
|
||||
+ * We require this signal merely to know when systemd finished handling
|
||||
+ * a job. For properly configured services, this should already tell us
|
||||
+ * whether the startup was successful or failed. But for basic services
|
||||
+ * that use no notify or dbus systemd-startup handling, we have to
|
||||
+ * continue tracking their `ActiveState` to see whether they failed.
|
||||
+ */
|
||||
+
|
||||
+ r = sd_bus_message_read(message, "uoss", &id, &path, &unit, &result);
|
||||
+ if (r < 0)
|
||||
+ return error_origin(r);
|
||||
+
|
||||
+ if (!service->job || strcmp(path, service->job))
|
||||
+ return 0;
|
||||
+
|
||||
+ if (!strcmp(result, "done") || !strcmp(result, "skipped")) {
|
||||
+ /*
|
||||
+ * Our job completed successfully. Make sure to stop watching
|
||||
+ * it so the `ActiveState` handling will take effect.
|
||||
+ */
|
||||
+ service->job = c_free(service->job);
|
||||
+ service->slot_watch_jobs = sd_bus_slot_unref(service->slot_watch_jobs);
|
||||
+ } else {
|
||||
+ /*
|
||||
+ * Our job failed. Forward this information to the broker so it
|
||||
+ * can fail pending activations.
|
||||
+ */
|
||||
+ r = service_reset_activation(service);
|
||||
+ if (r)
|
||||
+ return error_trace(r);
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int service_watch_jobs(Service *service) {
|
||||
+ int r;
|
||||
+
|
||||
+ assert(!service->slot_watch_jobs);
|
||||
+ assert(!service->job);
|
||||
+
|
||||
+ r = sd_bus_match_signal_async(
|
||||
+ service->launcher->bus_regular,
|
||||
+ &service->slot_watch_jobs,
|
||||
+ "org.freedesktop.systemd1",
|
||||
+ "/org/freedesktop/systemd1",
|
||||
+ "org.freedesktop.systemd1.Manager",
|
||||
+ "JobRemoved",
|
||||
+ service_watch_jobs_handler,
|
||||
+ NULL,
|
||||
+ service
|
||||
+ );
|
||||
+ if (r < 0)
|
||||
+ return error_origin(r);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
static int service_watch_unit_handler(sd_bus_message *message, void *userdata, sd_bus_error *errorp) {
|
||||
Service *service = userdata;
|
||||
const char *interface = NULL, *property = NULL, *value = NULL;
|
||||
int r;
|
||||
|
||||
+ /*
|
||||
+ * If we still watch the job-signals it means systemd has not yet fully
|
||||
+ * finished our job. In this case, any errors will be caught by the
|
||||
+ * `JobRemoved` handler and we do not have to track the unit, yet.
|
||||
+ * Moreover, we must not track the unit, since it might still return
|
||||
+ * failures before our job was actually handled by systemd.
|
||||
+ *
|
||||
+ * Hence, simply ignore any PropertiesChanged signals until we got
|
||||
+ * confirmation by systemd that our job finished. Bus ordering will
|
||||
+ * guarantee that we catch unit-failures both before and after the job
|
||||
+ * completion.
|
||||
+ */
|
||||
+ if (service->slot_watch_jobs)
|
||||
+ return 0;
|
||||
+
|
||||
/*
|
||||
* The properties of the bus unit changed. We are only interested in
|
||||
* the "ActiveState" property. We check whether it is included in the
|
||||
@@ -343,14 +433,31 @@ static int service_start_unit_handler(sd_bus_message *message, void *userdata, s
|
||||
Service *service = userdata;
|
||||
Launcher *launcher = service->launcher;
|
||||
const sd_bus_error *error;
|
||||
+ const char *job;
|
||||
int r;
|
||||
|
||||
service->slot_start_unit = sd_bus_slot_unref(service->slot_start_unit);
|
||||
|
||||
error = sd_bus_message_get_error(message);
|
||||
- if (!error)
|
||||
- /* unit queued successfully */
|
||||
+ if (!error) {
|
||||
+ /*
|
||||
+ * We successfully queued the job. Now remember the job path,
|
||||
+ * so we can properly track when it finishes (via the
|
||||
+ * JobRemoved signal).
|
||||
+ */
|
||||
+
|
||||
+ assert(!service->job);
|
||||
+
|
||||
+ r = sd_bus_message_read(message, "o", &job);
|
||||
+ if (r < 0)
|
||||
+ return error_origin(r);
|
||||
+
|
||||
+ service->job = strdup(job);
|
||||
+ if (!service->job)
|
||||
+ return error_origin(-ENOMEM);
|
||||
+
|
||||
return 1;
|
||||
+ }
|
||||
|
||||
/*
|
||||
* We always forward activation failure to the broker, which then
|
||||
@@ -437,6 +544,10 @@ static int service_start_unit(Service *service) {
|
||||
_c_cleanup_(sd_bus_message_unrefp) sd_bus_message *method_call = NULL;
|
||||
int r;
|
||||
|
||||
+ r = service_watch_jobs(service);
|
||||
+ if (r)
|
||||
+ return error_trace(r);
|
||||
+
|
||||
r = service_watch_unit(service, service->unit);
|
||||
if (r)
|
||||
return error_trace(r);
|
||||
@@ -467,6 +578,10 @@ static int service_start_transient_unit(Service *service) {
|
||||
const char *unique_name;
|
||||
int r;
|
||||
|
||||
+ r = service_watch_jobs(service);
|
||||
+ if (r)
|
||||
+ return error_trace(r);
|
||||
+
|
||||
r = sd_bus_get_unique_name(launcher->bus_regular, &unique_name);
|
||||
if (r < 0)
|
||||
return error_origin(r);
|
||||
diff --git a/src/launch/service.h b/src/launch/service.h
|
||||
index fa5bee2..2d3f870 100644
|
||||
--- a/src/launch/service.h
|
||||
+++ b/src/launch/service.h
|
||||
@@ -17,6 +17,7 @@ struct Service {
|
||||
bool not_found;
|
||||
bool running;
|
||||
bool reload_tag;
|
||||
+ sd_bus_slot *slot_watch_jobs;
|
||||
sd_bus_slot *slot_watch_unit;
|
||||
sd_bus_slot *slot_start_unit;
|
||||
CRBNode rb;
|
||||
@@ -32,6 +33,7 @@ struct Service {
|
||||
uint64_t n_missing_unit;
|
||||
uint64_t n_masked_unit;
|
||||
uint64_t last_serial;
|
||||
+ char *job;
|
||||
char id[];
|
||||
};
|
||||
|
||||
207
bd5a227ec6ca25ad7d352c4e2d48a9937b19e2d0.patch
Normal file
207
bd5a227ec6ca25ad7d352c4e2d48a9937b19e2d0.patch
Normal file
@ -0,0 +1,207 @@
|
||||
From bd5a227ec6ca25ad7d352c4e2d48a9937b19e2d0 Mon Sep 17 00:00:00 2001
|
||||
From: David Rheinsberg <david.rheinsberg@gmail.com>
|
||||
Date: Wed, 17 Feb 2021 11:33:27 +0100
|
||||
Subject: [PATCH] launch/service: rely on systemd PropertiesChanged behavior
|
||||
|
||||
The systemd API guarantees that basic properties are always included
|
||||
with value in the PropertiesChanged signals. They are never invalidated.
|
||||
If that was the case, there would be no way to reliably track all state
|
||||
changes of a unit.
|
||||
|
||||
Drop the explicit query behavior and simplify the property handling. We
|
||||
can safely rely on this API behavior.
|
||||
|
||||
Signed-off-by: David Rheinsberg <david.rheinsberg@gmail.com>
|
||||
---
|
||||
src/launch/service.c | 127 +++++++------------------------------------
|
||||
src/launch/service.h | 1 -
|
||||
2 files changed, 21 insertions(+), 107 deletions(-)
|
||||
|
||||
diff --git a/src/launch/service.c b/src/launch/service.c
|
||||
index 3f9d971..ab1a7b8 100644
|
||||
--- a/src/launch/service.c
|
||||
+++ b/src/launch/service.c
|
||||
@@ -88,7 +88,6 @@ Service *service_free(Service *service) {
|
||||
free(service->name);
|
||||
free(service->path);
|
||||
service->slot_start_unit = sd_bus_slot_unref(service->slot_start_unit);
|
||||
- service->slot_query_unit = sd_bus_slot_unref(service->slot_query_unit);
|
||||
service->slot_watch_unit = sd_bus_slot_unref(service->slot_watch_unit);
|
||||
free(service);
|
||||
|
||||
@@ -182,7 +181,6 @@ int service_new(Service **servicep,
|
||||
|
||||
static void service_discard_activation(Service *service) {
|
||||
service->slot_start_unit = sd_bus_slot_unref(service->slot_start_unit);
|
||||
- service->slot_query_unit = sd_bus_slot_unref(service->slot_query_unit);
|
||||
service->slot_watch_unit = sd_bus_slot_unref(service->slot_watch_unit);
|
||||
}
|
||||
|
||||
@@ -218,71 +216,19 @@ static int service_reset_activation(Service *service) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
-static int service_handle_active_state(Service *service, const char *value) {
|
||||
- int r;
|
||||
-
|
||||
- /*
|
||||
- * The possible values of "ActiveState" are:
|
||||
- *
|
||||
- * active, reloading, inactive, failed, activating, deactivating
|
||||
- *
|
||||
- * We are never interested in positive results, because the broker
|
||||
- * already gets those by tracking the name to be acquired. Therefore,
|
||||
- * we only ever track negative results. This means we only ever react
|
||||
- * to "failed".
|
||||
- * We could also react to units entering "inactive", but we cannot know
|
||||
- * upfront whether the unit is just a oneshot unit and thus is expected
|
||||
- * to enter "inactive" when it finished. Hence, we simply require
|
||||
- * anything to explicitly fail if they want to reset the activation.
|
||||
- */
|
||||
-
|
||||
- if (!strcmp(value, "failed")) {
|
||||
- r = service_reset_activation(service);
|
||||
- if (r)
|
||||
- return error_trace(r);
|
||||
- }
|
||||
-
|
||||
- return 0;
|
||||
-}
|
||||
-
|
||||
-static int service_query_unit_handler(sd_bus_message *message, void *userdata, sd_bus_error *errorp) {
|
||||
- Service *service = userdata;
|
||||
- const char *v;
|
||||
- int r;
|
||||
-
|
||||
- service->slot_query_unit = sd_bus_slot_unref(service->slot_query_unit);
|
||||
-
|
||||
- r = sd_bus_message_enter_container(message, 'v', "s");
|
||||
- if (r < 0)
|
||||
- return error_origin(r);
|
||||
-
|
||||
- {
|
||||
- r = sd_bus_message_read(message, "s", &v);
|
||||
- if (r < 0)
|
||||
- return error_origin(r);
|
||||
- }
|
||||
-
|
||||
- r = sd_bus_message_exit_container(message);
|
||||
- if (r < 0)
|
||||
- return error_origin(r);
|
||||
-
|
||||
- r = service_handle_active_state(service, v);
|
||||
- if (r)
|
||||
- return error_trace(r);
|
||||
-
|
||||
- return 0;
|
||||
-}
|
||||
-
|
||||
static int service_watch_unit_handler(sd_bus_message *message, void *userdata, sd_bus_error *errorp) {
|
||||
Service *service = userdata;
|
||||
const char *interface = NULL, *property = NULL, *value = NULL;
|
||||
- bool invalidated = false;
|
||||
int r;
|
||||
|
||||
/*
|
||||
* The properties of the bus unit changed. We are only interested in
|
||||
* the "ActiveState" property. We check whether it is included in the
|
||||
- * payload. If not, we query it, in case it was invalidated.
|
||||
+ * payload. If not, we ignore the signal.
|
||||
+ *
|
||||
+ * Note that we rely on systemd including it with value in the signal.
|
||||
+ * We will not query it, if it was merely invalidated. This is a
|
||||
+ * systemd API guarantee, and we rely on it.
|
||||
*/
|
||||
|
||||
/* Parse: "s" */
|
||||
@@ -339,54 +285,24 @@ static int service_watch_unit_handler(sd_bus_message *message, void *userdata, s
|
||||
return error_origin(r);
|
||||
}
|
||||
|
||||
- /* Parse: "as" */
|
||||
- {
|
||||
- r = sd_bus_message_enter_container(message, 'a', "s");
|
||||
- if (r < 0)
|
||||
- return error_origin(r);
|
||||
-
|
||||
- while (!sd_bus_message_at_end(message, false)) {
|
||||
- r = sd_bus_message_read(message, "s", &property);
|
||||
- if (r < 0)
|
||||
- return error_origin(r);
|
||||
-
|
||||
- if (!strcmp(property, "ActiveState"))
|
||||
- invalidated = true;
|
||||
- }
|
||||
-
|
||||
- r = sd_bus_message_exit_container(message);
|
||||
- if (r < 0)
|
||||
- return error_origin(r);
|
||||
- }
|
||||
-
|
||||
- /* If the value neither changed or was invalidated, discard it. */
|
||||
- if (!value && !invalidated)
|
||||
- return 0;
|
||||
-
|
||||
- service->slot_query_unit = sd_bus_slot_unref(service->slot_query_unit);
|
||||
-
|
||||
- if (value) {
|
||||
- /* We got a new property value, so handle it. */
|
||||
- r = service_handle_active_state(service, value);
|
||||
+ /*
|
||||
+ * The possible values of "ActiveState" are:
|
||||
+ *
|
||||
+ * active, reloading, inactive, failed, activating, deactivating
|
||||
+ *
|
||||
+ * We are never interested in positive results, because the broker
|
||||
+ * already gets those by tracking the name to be acquired. Therefore,
|
||||
+ * we only ever track negative results. This means we only ever react
|
||||
+ * to "failed".
|
||||
+ * We could also react to units entering "inactive", but we cannot know
|
||||
+ * upfront whether the unit is just a oneshot unit and thus is expected
|
||||
+ * to enter "inactive" when it finished. Hence, we simply require
|
||||
+ * anything to explicitly fail if they want to reset the activation.
|
||||
+ */
|
||||
+ if (value && !strcmp(value, "failed")) {
|
||||
+ r = service_reset_activation(service);
|
||||
if (r)
|
||||
return error_trace(r);
|
||||
- } else {
|
||||
- /* The property was invalidated, so query it. */
|
||||
- r = sd_bus_call_method_async(
|
||||
- service->launcher->bus_regular,
|
||||
- &service->slot_query_unit,
|
||||
- "org.freedesktop.systemd1",
|
||||
- sd_bus_message_get_path(message),
|
||||
- "org.freedesktop.DBus.Properties",
|
||||
- "Get",
|
||||
- service_query_unit_handler,
|
||||
- service,
|
||||
- "ss",
|
||||
- "org.freedesktop.systemd1.Unit",
|
||||
- "ActiveState"
|
||||
- );
|
||||
- if (r < 0)
|
||||
- return error_origin(r);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -397,7 +313,6 @@ static int service_watch_unit(Service *service, const char *unit) {
|
||||
int r;
|
||||
|
||||
assert(!service->slot_watch_unit);
|
||||
- assert(!service->slot_query_unit);
|
||||
|
||||
r = sd_bus_path_encode(
|
||||
"/org/freedesktop/systemd1/unit",
|
||||
diff --git a/src/launch/service.h b/src/launch/service.h
|
||||
index ede29ab..fa5bee2 100644
|
||||
--- a/src/launch/service.h
|
||||
+++ b/src/launch/service.h
|
||||
@@ -18,7 +18,6 @@ struct Service {
|
||||
bool running;
|
||||
bool reload_tag;
|
||||
sd_bus_slot *slot_watch_unit;
|
||||
- sd_bus_slot *slot_query_unit;
|
||||
sd_bus_slot *slot_start_unit;
|
||||
CRBNode rb;
|
||||
CRBNode rb_by_name;
|
||||
@ -1,12 +1,14 @@
|
||||
%global dbus_user_id 81
|
||||
|
||||
Name: dbus-broker
|
||||
Version: 26
|
||||
Version: 27
|
||||
Release: 2%{?dist}
|
||||
Summary: Linux D-Bus Message Broker
|
||||
License: ASL 2.0
|
||||
URL: https://github.com/bus1/dbus-broker
|
||||
Source0: https://github.com/bus1/dbus-broker/releases/download/v%{version}/dbus-broker-%{version}.tar.xz
|
||||
Patch0000: https://github.com/bus1/dbus-broker/commit/bd5a227ec6ca25ad7d352c4e2d48a9937b19e2d0.patch
|
||||
Patch0001: https://github.com/bus1/dbus-broker/commit/41ccab38eae2300e3d6f4e3eac0962ebe6e60ade.patch
|
||||
Provides: bundled(c-dvar) = 1
|
||||
Provides: bundled(c-ini) = 1
|
||||
Provides: bundled(c-list) = 3
|
||||
@ -98,6 +100,12 @@ fi
|
||||
%{_userunitdir}/dbus-broker.service
|
||||
|
||||
%changelog
|
||||
* Wed Feb 17 2021 David Rheinsberg <david.rheinsberg@gmail.com> - 27-2
|
||||
- Apply activation-tracking bugfixes from upstream.
|
||||
|
||||
* Mon Feb 15 2021 David Rheinsberg <david.rheinsberg@gmail.com> - 27-1
|
||||
- Update to upstream v27.
|
||||
|
||||
* Tue Jan 26 2021 Fedora Release Engineering <releng@fedoraproject.org> - 26-2
|
||||
- Rebuilt for https://fedoraproject.org/wiki/Fedora_34_Mass_Rebuild
|
||||
|
||||
|
||||
2
sources
2
sources
@ -1 +1 @@
|
||||
SHA512 (dbus-broker-26.tar.xz) = 51062edba619cdd7242c89422cf232f269feda2ad2fa221f66b09a616a3a76b90b25646b9b7f548290cddfbdac0e0da0c7347270ac3807cae2db056a1d4f480d
|
||||
SHA512 (dbus-broker-27.tar.xz) = d3964cd7bc5553924f5786fe1a7f43c4298fa661aa6cde79e98d2aee67ee3e17eb5c689d39228efad905af59296a6ae52485c61d564bb0a35c937573323ea1fb
|
||||
|
||||
Loading…
Reference in New Issue
Block a user