From: Lennart Poettering Date: Thu, 28 Apr 2011 20:07:01 +0000 (+0200) Subject: dbus: make daemon reexecution synchronous X-Git-Tag: v26~5 X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=b23de6af893c11da4286bc416455cd0926d1532e;p=systemd 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 --- diff --git a/TODO b/TODO index be964623..3f26e2ea 100644 --- a/TODO +++ b/TODO @@ -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 / diff --git a/src/dbus-manager.c b/src/dbus-manager.c index 9776b0b9..797e53d1 100644 --- a/src/dbus-manager.c +++ b/src/dbus-manager.c @@ -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; diff --git a/src/dbus.c b/src/dbus.c index 1907560b..8ea768c5 100644 --- a/src/dbus.c +++ b/src/dbus.c @@ -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; +} diff --git a/src/dbus.h b/src/dbus.h index 57a2b388..8387ffaa 100644 --- a/src/dbus.h +++ b/src/dbus.h @@ -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) diff --git a/src/fdset.c b/src/fdset.c index 29e75a03..9bf37888 100644 --- a/src/fdset.c +++ b/src/fdset.c @@ -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)); } diff --git a/src/manager.c b/src/manager.c index 084b41f1..68d43ada 100644 --- a/src/manager.c +++ b/src/manager.c @@ -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; } diff --git a/src/systemctl.c b/src/systemctl.c index 10c6319b..99ada383 100644 --- a/src/systemctl.c +++ b/src/systemctl.c @@ -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;