Merge pull request #7352 from eddiejames/master

Add path configuration for hardware watchdog device
This commit is contained in:
Lennart Poettering 2017-12-08 22:22:02 +01:00 committed by GitHub
commit f7757a4993
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 76 additions and 5 deletions

View file

@ -382,6 +382,15 @@
</listitem>
</varlistentry>
<varlistentry>
<term><varname>systemd.watchdog_device=</varname></term>
<listitem>
<para>Overwrites the watchdog device path <varname>WatchdogDevice=</varname>. For details, see
<citerefentry><refentrytitle>systemd-system.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>modules_load=</varname></term>
<term><varname>rd.modules_load=</varname></term>

View file

@ -161,8 +161,10 @@
<literal>d</literal>, <literal>w</literal>). If
<varname>RuntimeWatchdogSec=</varname> is set to a non-zero
value, the watchdog hardware
(<filename>/dev/watchdog</filename>) will be programmed to
automatically reboot the system if it is not contacted within
(<filename>/dev/watchdog</filename> or the path specified with
<varname>WatchdogDevice=</varname> or the kernel option
<varname>systemd.watchdog-device=</varname>) will be programmed
to automatically reboot the system if it is not contacted within
the specified timeout interval. The system manager will ensure
to contact it at least once in half the specified timeout
interval. This feature requires a hardware watchdog device to
@ -179,6 +181,15 @@
available.</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>WatchdogDevice=</varname></term>
<listitem><para>Configure the hardware watchdog device that the
runtime and shutdown watchdog timers will open and use. Defaults
to <filename>/dev/watchdog</filename>. This setting has no
effect if a hardware watchdog is not available.</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>CapabilityBoundingSet=</varname></term>

View file

@ -120,6 +120,7 @@ static usec_t arg_default_start_limit_interval = DEFAULT_START_LIMIT_INTERVAL;
static unsigned arg_default_start_limit_burst = DEFAULT_START_LIMIT_BURST;
static usec_t arg_runtime_watchdog = 0;
static usec_t arg_shutdown_watchdog = 10 * USEC_PER_MINUTE;
static char *arg_watchdog_device = NULL;
static char **arg_default_environment = NULL;
static struct rlimit *arg_default_rlimit[_RLIMIT_MAX] = {};
static uint64_t arg_capability_bounding_set = CAP_ALL;
@ -461,6 +462,13 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat
if (arg_default_timeout_start_usec <= 0)
arg_default_timeout_start_usec = USEC_INFINITY;
} else if (proc_cmdline_key_streq(key, "systemd.watchdog_device")) {
if (proc_cmdline_value_missing(key, value))
return 0;
parse_path_argument_and_warn(value, false, &arg_watchdog_device);
} else if (streq(key, "quiet") && !value) {
if (arg_show_status == _SHOW_STATUS_UNSET)
@ -751,6 +759,7 @@ static int parse_config_file(void) {
{ "Manager", "JoinControllers", config_parse_join_controllers, 0, &arg_join_controllers },
{ "Manager", "RuntimeWatchdogSec", config_parse_sec, 0, &arg_runtime_watchdog },
{ "Manager", "ShutdownWatchdogSec", config_parse_sec, 0, &arg_shutdown_watchdog },
{ "Manager", "WatchdogDevice", config_parse_path, 0, &arg_watchdog_device },
{ "Manager", "CapabilityBoundingSet", config_parse_capability_set, 0, &arg_capability_bounding_set },
#if HAVE_SECCOMP
{ "Manager", "SystemCallArchitectures", config_parse_syscall_archs, 0, &arg_syscall_archs },
@ -1521,7 +1530,11 @@ static int become_shutdown(
/* Tell the binary how often to ping, ignore failure */
if (asprintf(&e, "WATCHDOG_USEC="USEC_FMT, arg_shutdown_watchdog) > 0)
(void) strv_push(&env_block, e);
(void) strv_consume(&env_block, e);
if (arg_watchdog_device &&
asprintf(&e, "WATCHDOG_DEVICE=%s", arg_watchdog_device) > 0)
(void) strv_consume(&env_block, e);
} else
watchdog_close(true);
@ -1914,6 +1927,13 @@ static int initialize_runtime(
write_container_id();
}
if (arg_system && arg_watchdog_device) {
r = watchdog_set_device(arg_watchdog_device);
if (r < 0)
log_warning_errno(r, "Failed to set watchdog device to %s, ignoring: %m",
arg_watchdog_device);
}
if (arg_system && arg_runtime_watchdog > 0 && arg_runtime_watchdog != USEC_INFINITY)
watchdog_set_timeout(&arg_runtime_watchdog);
@ -2450,8 +2470,13 @@ finish:
* here explicitly. valgrind will only generate nice output on
* exit(), not on exec(), hence let's do the former not the
* latter here. */
if (getpid_cached() == 1 && RUNNING_ON_VALGRIND)
if (getpid_cached() == 1 && RUNNING_ON_VALGRIND) {
/* Cleanup watchdog_device strings for valgrind. We need them
* in become_shutdown() so normally we cannot free them yet. */
watchdog_free_device();
arg_watchdog_device = mfree(arg_watchdog_device);
return 0;
}
#endif
if (shutdown_verb) {
@ -2461,6 +2486,9 @@ finish:
error_message = "Failed to execute shutdown binary";
}
watchdog_free_device();
arg_watchdog_device = mfree(arg_watchdog_device);
if (getpid_cached() == 1) {
if (error_message)
manager_status_printf(NULL, STATUS_TYPE_EMERGENCY,

View file

@ -167,6 +167,7 @@ int main(int argc, char *argv[]) {
unsigned retries;
int cmd, r;
static const char* const dirs[] = {SYSTEM_SHUTDOWN_PATH, NULL};
char *watchdog_device;
log_parse_environment();
r = parse_argv(argc, argv);
@ -207,6 +208,13 @@ int main(int argc, char *argv[]) {
in_container = detect_container() > 0;
use_watchdog = !!getenv("WATCHDOG_USEC");
watchdog_device = getenv("WATCHDOG_DEVICE");
if (watchdog_device) {
r = watchdog_set_device(watchdog_device);
if (r < 0)
log_warning_errno(r, "Failed to set watchdog device to %s, ignoring: %m",
watchdog_device);
}
/* Lock us into memory */
mlockall(MCL_CURRENT|MCL_FUTURE);
@ -320,6 +328,9 @@ int main(int argc, char *argv[]) {
initrd_jump:
/* We're done with the watchdog. */
watchdog_free_device();
arguments[0] = NULL;
arguments[1] = arg_verb;
arguments[2] = NULL;

View file

@ -27,10 +27,12 @@
#include "fd-util.h"
#include "log.h"
#include "string-util.h"
#include "time-util.h"
#include "watchdog.h"
static int watchdog_fd = -1;
static char *watchdog_device = NULL;
static usec_t watchdog_timeout = USEC_INFINITY;
static int update_timeout(void) {
@ -84,7 +86,8 @@ static int open_watchdog(void) {
if (watchdog_fd >= 0)
return 0;
watchdog_fd = open("/dev/watchdog", O_WRONLY|O_CLOEXEC);
watchdog_fd = open(watchdog_device ?: "/dev/watchdog",
O_WRONLY|O_CLOEXEC);
if (watchdog_fd < 0)
return -errno;
@ -96,6 +99,10 @@ static int open_watchdog(void) {
return update_timeout();
}
int watchdog_set_device(char *path) {
return free_and_strdup(&watchdog_device, path);
}
int watchdog_set_timeout(usec_t *usec) {
int r;

View file

@ -25,6 +25,11 @@
#include "time-util.h"
#include "util.h"
int watchdog_set_device(char *path);
int watchdog_set_timeout(usec_t *usec);
int watchdog_ping(void);
void watchdog_close(bool disarm);
static inline void watchdog_free_device(void) {
(void) watchdog_set_device(NULL);
}