]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
watchdog: saturate to kernel's max watchdog timeout
authorCurtis Klein <curtistklein@gmail.com>
Sun, 10 Oct 2021 01:18:54 +0000 (18:18 -0700)
committerLennart Poettering <lennart@poettering.net>
Tue, 8 Feb 2022 13:43:12 +0000 (14:43 +0100)
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

index f29d3761b06d1636f506f5c072ce7bc5fdc72e7a..98ef979dbe8af28d261076165695c17325857849 100644 (file)
@@ -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;