Skip to content

Commit e39eb04

Browse files
committed
pid1: lookup owning PID of BusName= name of services asynchronously
A first step of removing blocking calls to the D-Bus broker from PID 1. There's a lot more to got (i.e. grep src/core/ for sd_bus_creds basically), but it's a start. Removing blocking calls to D-Bus broker deals systematicallly with deadlocks caused by dbus-daemon blocking on synchronous IPC calls back to PID1 (e.g. Varlink calls through nss-systemd). Bugs such as systemd#15316. Also-see: systemd#22038 (comment)
1 parent 1e8b312 commit e39eb04

File tree

2 files changed

+74
-19
lines changed

2 files changed

+74
-19
lines changed

src/core/service.c

Lines changed: 72 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -398,6 +398,8 @@ static void service_done(Unit *u) {
398398
s->timer_event_source = sd_event_source_disable_unref(s->timer_event_source);
399399
s->exec_fd_event_source = sd_event_source_disable_unref(s->exec_fd_event_source);
400400

401+
s->bus_name_pid_lookup_slot = sd_bus_slot_unref(s->bus_name_pid_lookup_slot);
402+
401403
service_release_resources(u);
402404
}
403405

@@ -4322,6 +4324,60 @@ static int service_get_timeout(Unit *u, usec_t *timeout) {
43224324
return 1;
43234325
}
43244326

4327+
static bool pick_up_pid_from_bus_name(Service *s) {
4328+
assert(s);
4329+
4330+
/* If the service is running but we have no main PID yet, get it from the owner of the D-Bus name */
4331+
4332+
return !pid_is_valid(s->main_pid) &&
4333+
IN_SET(s->state,
4334+
SERVICE_START,
4335+
SERVICE_START_POST,
4336+
SERVICE_RUNNING,
4337+
SERVICE_RELOAD);
4338+
}
4339+
4340+
static int bus_name_pid_lookup_callback(sd_bus_message *reply, void *userdata, sd_bus_error *ret_error) {
4341+
const sd_bus_error *e;
4342+
Unit *u = userdata;
4343+
uint32_t pid;
4344+
Service *s;
4345+
int r;
4346+
4347+
assert(reply);
4348+
assert(u);
4349+
4350+
s = SERVICE(u);
4351+
s->bus_name_pid_lookup_slot = sd_bus_slot_unref(s->bus_name_pid_lookup_slot);
4352+
4353+
if (!s->bus_name || !pick_up_pid_from_bus_name(s))
4354+
return 1;
4355+
4356+
e = sd_bus_message_get_error(reply);
4357+
if (e) {
4358+
r = sd_bus_error_get_errno(e);
4359+
log_warning_errno(r, "GetConnectionUnixProcessID() failed: %s", bus_error_message(e, r));
4360+
return 1;
4361+
}
4362+
4363+
r = sd_bus_message_read(reply, "u", &pid);
4364+
if (r < 0) {
4365+
bus_log_parse_error(r);
4366+
return 1;
4367+
}
4368+
4369+
if (!pid_is_valid(pid)) {
4370+
log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "GetConnectionUnixProcessID() returned invalid PID");
4371+
return 1;
4372+
}
4373+
4374+
log_unit_debug(u, "D-Bus name %s is now owned by process " PID_FMT, s->bus_name, (pid_t) pid);
4375+
4376+
service_set_main_pid(s, pid);
4377+
unit_watch_pid(UNIT(s), pid, false);
4378+
return 1;
4379+
}
4380+
43254381
static void service_bus_name_owner_change(Unit *u, const char *new_owner) {
43264382

43274383
Service *s = SERVICE(u);
@@ -4352,28 +4408,25 @@ static void service_bus_name_owner_change(Unit *u, const char *new_owner) {
43524408
else if (s->state == SERVICE_START && new_owner)
43534409
service_enter_start_post(s);
43544410

4355-
} else if (new_owner &&
4356-
s->main_pid <= 0 &&
4357-
IN_SET(s->state,
4358-
SERVICE_START,
4359-
SERVICE_START_POST,
4360-
SERVICE_RUNNING,
4361-
SERVICE_RELOAD)) {
4362-
4363-
_cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
4364-
pid_t pid;
4411+
} else if (new_owner && pick_up_pid_from_bus_name(s)) {
43654412

43664413
/* Try to acquire PID from bus service */
43674414

4368-
r = sd_bus_get_name_creds(u->manager->api_bus, s->bus_name, SD_BUS_CREDS_PID, &creds);
4369-
if (r >= 0)
4370-
r = sd_bus_creds_get_pid(creds, &pid);
4371-
if (r >= 0) {
4372-
log_unit_debug(u, "D-Bus name %s is now owned by process " PID_FMT, s->bus_name, pid);
4373-
4374-
service_set_main_pid(s, pid);
4375-
unit_watch_pid(UNIT(s), pid, false);
4376-
}
4415+
s->bus_name_pid_lookup_slot = sd_bus_slot_unref(s->bus_name_pid_lookup_slot);
4416+
4417+
r = sd_bus_call_method_async(
4418+
u->manager->api_bus,
4419+
&s->bus_name_pid_lookup_slot,
4420+
"org.freedesktop.DBus",
4421+
"/org/freedesktop/DBus",
4422+
"org.freedesktop.DBus",
4423+
"GetConnectionUnixProcessID",
4424+
bus_name_pid_lookup_callback,
4425+
s,
4426+
"s",
4427+
s->bus_name);
4428+
if (r < 0)
4429+
log_debug_errno(r, "Failed to request owner PID of service name, ignoring: %m");
43774430
}
43784431
}
43794432

src/core/service.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,8 @@ struct Service {
195195
NotifyAccess notify_access;
196196
NotifyState notify_state;
197197

198+
sd_bus_slot *bus_name_pid_lookup_slot;
199+
198200
sd_event_source *exec_fd_event_source;
199201

200202
ServiceFDStore *fd_store;

0 commit comments

Comments
 (0)