dbus: make daemon reexecution synchronous

We simply keep open copies of the dbus connections across the
reexecution and close them as last step of it. A client can thus simply
wait until its connection is dropped to know when the reexecution is
finished.

https://bugzilla.redhat.com/show_bug.cgi?id=698198
This commit is contained in:
Lennart Poettering 2011-04-28 22:07:01 +02:00
parent b4bd51448f
commit b23de6af89
7 changed files with 68 additions and 6 deletions

9
TODO
View File

@ -5,6 +5,9 @@ F15:
* 0595f9a1c182a84581749823ef47c5f292e545f9 is borked, freezes shutdown
(path: after installing inotify watches, recheck file again to fix race)
* move systemadm man page to systemd-gtk
https://bugzilla.redhat.com/show_bug.cgi?id=699394
F15 External:
* NFS, networkmanager ordering issue (PENDING)
@ -28,6 +31,10 @@ F15 External:
Features:
* drop /.readahead on bigger upgrades with yum
* add inode stat() check to readahead
* plymouth.enable=0
* introduce dbus calls for enabling/disabling a service
@ -60,8 +67,6 @@ Features:
* rename systemd-logger to systemd-stdio-syslog-bridge
* introduce /usr/lib/binfmt.d/, /usr/lib/tmpfiles.d/
* take BSD file lock on tty devices when using them?
* avoid any flag files, or readahead files in /, we need to support r/o /

View File

@ -922,8 +922,8 @@ static DBusHandlerResult bus_manager_message_handler(DBusConnection *connection,
} else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Reexecute")) {
if (!(reply = dbus_message_new_method_return(message)))
goto oom;
/* We don't send a reply back here, the client should
* just wait for us disconnecting. */
m->exit_code = MANAGER_REEXECUTE;

View File

@ -598,7 +598,12 @@ static void request_name_pending_cb(DBusPendingCall *pending, void *userdata) {
static int request_name(Manager *m) {
const char *name = "org.freedesktop.systemd1";
uint32_t flags = 0;
/* Allow replacing of our name, to ease implementation of
* reexecution, where we keep the old connection open until
* after the new connection is set up and the name installed
* to allow clients to synchronously wait for reexecution to
* finish */
uint32_t flags = DBUS_NAME_FLAG_ALLOW_REPLACEMENT|DBUS_NAME_FLAG_REPLACE_EXISTING;
DBusMessage *message = NULL;
DBusPendingCall *pending = NULL;
@ -1305,3 +1310,42 @@ bool bus_connection_has_subscriber(Manager *m, DBusConnection *c) {
return !set_isempty(BUS_CONNECTION_SUBSCRIBED(m, c));
}
int bus_fdset_add_all(Manager *m, FDSet *fds) {
Iterator i;
DBusConnection *c;
assert(m);
assert(fds);
/* When we are about to reexecute we add all D-Bus fds to the
* set to pass over to the newly executed systemd. They won't
* be used there however, except that they are closed at the
* very end of deserialization, those making it possible for
* clients to synchronously wait for systemd to reexec buy
* simply waiting for disconnection */
SET_FOREACH(c, m->bus_connections_for_dispatch, i) {
int fd;
if (dbus_connection_get_unix_fd(c, &fd)) {
fd = fdset_put_dup(fds, fd);
if (fd < 0)
return fd;
}
}
SET_FOREACH(c, m->bus_connections, i) {
int fd;
if (dbus_connection_get_unix_fd(c, &fd)) {
fd = fdset_put_dup(fds, fd);
if (fd < 0)
return fd;
}
}
return 0;
}

View File

@ -43,6 +43,8 @@ int bus_parse_strv(DBusMessage *m, char ***_l);
bool bus_has_subscriber(Manager *m);
bool bus_connection_has_subscriber(Manager *m, DBusConnection *c);
int bus_fdset_add_all(Manager *m, FDSet *fds);
#define BUS_CONNECTION_SUBSCRIBED(m, c) dbus_connection_get_data((c), (m)->subscribed_data_slot)
#define BUS_PENDING_CALL_NAME(m, p) dbus_pending_call_get_data((p), (m)->name_data_slot)

View File

@ -49,7 +49,7 @@ void fdset_free(FDSet *s) {
* here, so that the EBADFD that valgrind will return
* us on close() doesn't influence us */
/* log_warning("Closing left-over fd %i", PTR_TO_FD(p)); */
log_debug("Closing left-over fd %i", PTR_TO_FD(p));
close_nointr(PTR_TO_FD(p));
}

View File

@ -2688,6 +2688,10 @@ int manager_serialize(Manager *m, FILE *f, FDSet *fds) {
if (ferror(f))
return -EIO;
r = bus_fdset_add_all(m, fds);
if (r < 0)
return r;
return 0;
}

View File

@ -3323,6 +3323,13 @@ static int daemon_reload(DBusConnection *bus, char **args, unsigned n) {
goto finish;
}
if (streq(method, "Reexecute") && dbus_error_has_name(&error, DBUS_ERROR_NO_REPLY)) {
/* On reexecution, we expect a disconnect, not
* a reply */
r = 0;
goto finish;
}
log_error("Failed to issue method call: %s", bus_error_message(&error));
r = -EIO;
goto finish;