From: Tollef Fog Heen <tfheen@err.no>
Date: Tue, 16 Oct 2012 18:39:27 +0200
Subject: Avoid reloading services when shutting down

Doing so won't work and makes no sense.  Thanks to Michael Stapelberg
for the patch.  Closes: #624599.
---
 src/core/manager.c | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)

diff --git a/src/core/manager.c b/src/core/manager.c
index 0508628..3996309 100644
--- a/src/core/manager.c
+++ b/src/core/manager.c
@@ -874,6 +874,8 @@ int manager_startup(Manager *m, FILE *serialization, FDSet *fds) {
 int manager_add_job(Manager *m, JobType type, Unit *unit, JobMode mode, bool override, DBusError *e, Job **_ret) {
         int r;
         Transaction *tr;
+        Job *j;
+        Iterator i;
 
         assert(m);
         assert(type < _JOB_TYPE_MAX);
@@ -885,6 +887,29 @@ int manager_add_job(Manager *m, JobType type, Unit *unit, JobMode mode, bool ove
                 return -EINVAL;
         }
 
+        if (type == JOB_RELOAD || type == JOB_RELOAD_OR_START || type == JOB_RESTART || type == JOB_TRY_RESTART) {
+                /* If final.target is queued (happens on poweroff, reboot and
+                 * halt), we will not accept new reload jobs. They would not be
+                 * executed ever anyways (since the shutdown comes first), but
+                 * they block the shutdown process: when systemd tries to stop
+                 * a unit such as ifup@eth0.service, that unit might invoke a
+                 * systemctl reload command, which blockingly waits (but only
+                 * gets executed after all other queued units for the shutdown
+                 * have been executed).
+                 *
+                 * See http://bugs.debian.org/624599 and
+                 *     http://bugs.debian.org/635777 */
+                HASHMAP_FOREACH(j, m->jobs, i) {
+                        assert(j->installed);
+
+                        if (strcmp(j->unit->id, "final.target") == 0) {
+                                log_debug("final.target is queued, ignoring %s request for unit %s", job_type_to_string(type), unit->id);
+                                dbus_set_error(e, BUS_ERROR_INVALID_JOB_MODE, "final.target is queued, ignoring %s request for unit %s", job_type_to_string(type), unit->id);
+                                return -EINVAL;
+                        }
+                }
+        }
+
         if (mode == JOB_ISOLATE && !unit->allow_isolate) {
                 dbus_set_error(e, BUS_ERROR_NO_ISOLATION, "Operation refused, unit may not be isolated.");
                 return -EPERM;
