shutdown: make kill timeout configurable (#7835)
authorJan Klötzke <jan@kloetzke.net>
Wed, 10 Jan 2018 18:00:20 +0000 (19:00 +0100)
committerLennart Poettering <lennart@poettering.net>
Wed, 10 Jan 2018 18:00:20 +0000 (19:00 +0100)
By default systemd-shutdown will wait for 90s after SIGTERM was sent
for all processes to exit. This is way too long and effectively defeats
an emergency watchdog reboot via "reboot-force" actions. Instead now
use DefaultTimeoutStopSec which is configurable.

src/core/killall.c
src/core/killall.h
src/core/main.c
src/core/shutdown.c

index e77763e..daa9c4e 100644 (file)
@@ -89,7 +89,7 @@ static bool ignore_proc(pid_t pid, bool warn_rootfs) {
         return true;
 }
 
-static void wait_for_children(Set *pids, sigset_t *mask) {
+static void wait_for_children(Set *pids, sigset_t *mask, usec_t timeout) {
         usec_t until;
 
         assert(mask);
@@ -97,7 +97,7 @@ static void wait_for_children(Set *pids, sigset_t *mask) {
         if (set_isempty(pids))
                 return;
 
-        until = now(CLOCK_MONOTONIC) + DEFAULT_TIMEOUT_USEC;
+        until = now(CLOCK_MONOTONIC) + timeout;
         for (;;) {
                 struct timespec ts;
                 int k;
@@ -221,7 +221,7 @@ static int killall(int sig, Set *pids, bool send_sighup) {
         return set_size(pids);
 }
 
-void broadcast_signal(int sig, bool wait_for_exit, bool send_sighup) {
+void broadcast_signal(int sig, bool wait_for_exit, bool send_sighup, usec_t timeout) {
         sigset_t mask, oldmask;
         _cleanup_set_free_ Set *pids = NULL;
 
@@ -241,7 +241,7 @@ void broadcast_signal(int sig, bool wait_for_exit, bool send_sighup) {
                 log_warning_errno(errno, "kill(-1, SIGCONT) failed: %m");
 
         if (wait_for_exit)
-                wait_for_children(pids, &mask);
+                wait_for_children(pids, &mask, timeout);
 
         assert_se(sigprocmask(SIG_SETMASK, &oldmask, NULL) == 0);
 }
index 01bd6e5..45e97ab 100644 (file)
@@ -20,4 +20,6 @@
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
-void broadcast_signal(int sig, bool wait_for_exit, bool send_sighup);
+#include "time-util.h"
+
+void broadcast_signal(int sig, bool wait_for_exit, bool send_sighup, usec_t timeout);
index ef7d7f5..712f1d3 100644 (file)
@@ -1467,17 +1467,19 @@ static int become_shutdown(
                 int retval) {
 
         char log_level[DECIMAL_STR_MAX(int) + 1],
-                exit_code[DECIMAL_STR_MAX(uint8_t) + 1];
+                exit_code[DECIMAL_STR_MAX(uint8_t) + 1],
+                timeout[DECIMAL_STR_MAX(usec_t) + 1];
 
-        const char* command_line[11] = {
+        const char* command_line[13] = {
                 SYSTEMD_SHUTDOWN_BINARY_PATH,
                 shutdown_verb,
+                "--timeout", timeout,
                 "--log-level", log_level,
                 "--log-target",
         };
 
         _cleanup_strv_free_ char **env_block = NULL;
-        size_t pos = 5;
+        size_t pos = 7;
         int r;
 
         assert(shutdown_verb);
@@ -1485,6 +1487,7 @@ static int become_shutdown(
         env_block = strv_copy(environ);
 
         xsprintf(log_level, "%d", log_get_max_level());
+        xsprintf(timeout, "%" PRI_USEC "us", arg_default_timeout_stop_usec);
 
         switch (log_get_target()) {
 
@@ -1640,7 +1643,7 @@ static void do_reexecute(
         if (switch_root_dir) {
                 /* Kill all remaining processes from the initrd, but don't wait for them, so that we can handle the
                  * SIGCHLD for them after deserializing. */
-                broadcast_signal(SIGTERM, false, true);
+                broadcast_signal(SIGTERM, false, true, arg_default_timeout_stop_usec);
 
                 /* And switch root with MS_MOVE, because we remove the old directory afterwards and detach it. */
                 r = switch_root(switch_root_dir, "/mnt", true, MS_MOVE);
index b1f581b..da817c8 100644 (file)
@@ -58,6 +58,7 @@
 
 static char* arg_verb;
 static uint8_t arg_exit_code;
+static usec_t arg_timeout = DEFAULT_TIMEOUT_USEC;
 
 static int parse_argv(int argc, char *argv[]) {
         enum {
@@ -66,6 +67,7 @@ static int parse_argv(int argc, char *argv[]) {
                 ARG_LOG_COLOR,
                 ARG_LOG_LOCATION,
                 ARG_EXIT_CODE,
+                ARG_TIMEOUT,
         };
 
         static const struct option options[] = {
@@ -74,6 +76,7 @@ static int parse_argv(int argc, char *argv[]) {
                 { "log-color",     optional_argument, NULL, ARG_LOG_COLOR    },
                 { "log-location",  optional_argument, NULL, ARG_LOG_LOCATION },
                 { "exit-code",     required_argument, NULL, ARG_EXIT_CODE    },
+                { "timeout",       required_argument, NULL, ARG_TIMEOUT      },
                 {}
         };
 
@@ -129,6 +132,13 @@ static int parse_argv(int argc, char *argv[]) {
 
                         break;
 
+                case ARG_TIMEOUT:
+                        r = parse_sec(optarg, &arg_timeout);
+                        if (r < 0)
+                                log_error("Failed to parse shutdown timeout %s, ignoring", optarg);
+
+                        break;
+
                 case '\001':
                         if (!arg_verb)
                                 arg_verb = optarg;
@@ -327,10 +337,10 @@ int main(int argc, char *argv[]) {
         disable_core_dumps();
 
         log_info("Sending SIGTERM to remaining processes...");
-        broadcast_signal(SIGTERM, true, true);
+        broadcast_signal(SIGTERM, true, true, arg_timeout);
 
         log_info("Sending SIGKILL to remaining processes...");
-        broadcast_signal(SIGKILL, true, false);
+        broadcast_signal(SIGKILL, true, false, arg_timeout);
 
         need_umount = !in_container;
         need_swapoff = !in_container;