From e73c54b838885237438f776b930e3624f8cb57f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Kl=C3=B6tzke?= Date: Wed, 10 Jan 2018 19:00:20 +0100 Subject: [PATCH] shutdown: make kill timeout configurable (#7835) 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 | 8 ++++---- src/core/killall.h | 4 +++- src/core/main.c | 11 +++++++---- src/core/shutdown.c | 14 ++++++++++++-- 4 files changed, 26 insertions(+), 11 deletions(-) diff --git a/src/core/killall.c b/src/core/killall.c index e77763e161c..daa9c4ea20a 100644 --- a/src/core/killall.c +++ b/src/core/killall.c @@ -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); } diff --git a/src/core/killall.h b/src/core/killall.h index 01bd6e52b30..45e97ab5946 100644 --- a/src/core/killall.h +++ b/src/core/killall.h @@ -20,4 +20,6 @@ along with systemd; If not, see . ***/ -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); diff --git a/src/core/main.c b/src/core/main.c index ef7d7f58dc4..712f1d39b57 100644 --- a/src/core/main.c +++ b/src/core/main.c @@ -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); diff --git a/src/core/shutdown.c b/src/core/shutdown.c index b1f581b5482..da817c898d2 100644 --- a/src/core/shutdown.c +++ b/src/core/shutdown.c @@ -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;