From d6463a399de848b7d09681d72a478ec28e3189a5 Mon Sep 17 00:00:00 2001 From: Curtis Klein Date: Sat, 9 Oct 2021 18:18:54 -0700 Subject: [PATCH] watchdog: saturate to kernel's max watchdog timeout Since version 4.5, the max possible timeout is UINT_MAX / 1000 since it does calculations in milliseconds. A small helper function is added to make this conversion and saturation and will be used more in the next commit. Also document the usage of signed integers by the kernel userspace API. --- src/shared/watchdog.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/src/shared/watchdog.c b/src/shared/watchdog.c index f29d3761b0..98ef979dbe 100644 --- a/src/shared/watchdog.c +++ b/src/shared/watchdog.c @@ -20,6 +20,20 @@ static char *watchdog_device; static usec_t watchdog_timeout; /* 0 → close device and USEC_INFINITY → don't change timeout */ static usec_t watchdog_last_ping = USEC_INFINITY; +/* Starting from kernel version 4.5, the maximum allowable watchdog timeout is + * UINT_MAX/1000U seconds (since internal calculations are done in milliseconds + * using unsigned integers. However, the kernel's userspace API for the watchdog + * uses signed integers for its ioctl parameters (even for timeout values and + * bit flags) so this is why we must consider the maximum signed integer value + * as well. + */ +#define WATCHDOG_TIMEOUT_MAX_SEC (CONST_MIN(UINT_MAX/1000U, (unsigned)INT_MAX)) + +static int saturated_usec_to_sec(usec_t val) { + usec_t t = DIV_ROUND_UP(val, USEC_PER_SEC); + return MIN(t, (usec_t) WATCHDOG_TIMEOUT_MAX_SEC); /* Saturate to watchdog max */ +} + static int watchdog_set_enable(bool enable) { int flags = enable ? WDIOS_ENABLECARD : WDIOS_DISABLECARD; @@ -54,14 +68,12 @@ static int watchdog_get_timeout(void) { } static int watchdog_set_timeout(void) { - usec_t t; int sec; assert(watchdog_fd >= 0); assert(timestamp_is_set(watchdog_timeout)); - t = DIV_ROUND_UP(watchdog_timeout, USEC_PER_SEC); - sec = MIN(t, (usec_t) INT_MAX); /* Saturate */ + sec = saturated_usec_to_sec(watchdog_timeout); if (ioctl(watchdog_fd, WDIOC_SETTIMEOUT, &sec) < 0) return -errno;