]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
watchdog: handle timeout programming errors more safely
authorFranck Bui <fbui@suse.com>
Mon, 27 Sep 2021 08:51:28 +0000 (10:51 +0200)
committerFranck Bui <fbui@suse.com>
Wed, 13 Oct 2021 06:58:36 +0000 (08:58 +0200)
If an error happened while the timeout value was being programmed, the error
was ignored and the watchdog module used the new timeout value whereas the
watchdog device was left with the previous one.

Now in cases of error, the device is now disabled and closed if it wasn't
opened already otherwise the previous timeout value is kept so the device is
still pinged at correct intervals.

src/shared/watchdog.c

index b6fddd193f5690085136d4092a21ed1076e4f81b..4de6003039a4196a40830cae10f202493c4cba0c 100644 (file)
@@ -96,8 +96,8 @@ static int update_timeout(void) {
                 r = watchdog_set_timeout();
                 if (r < 0) {
                         if (!ERRNO_IS_NOT_SUPPORTED(r))
-                                return log_warning_errno(r, "Failed to set timeout to %s, ignoring: %m",
-                                                         FORMAT_TIMESPAN(watchdog_timeout, 0));
+                                return log_error_errno(r, "Failed to set timeout to %s: %m",
+                                                       FORMAT_TIMESPAN(watchdog_timeout, 0));
 
                         log_info("Modifying watchdog timeout is not supported, reusing the programmed timeout.");
                         watchdog_timeout = USEC_INFINITY;
@@ -107,7 +107,7 @@ static int update_timeout(void) {
         if (watchdog_timeout == USEC_INFINITY) {
                 r = watchdog_get_timeout();
                 if (r < 0)
-                        return log_warning_errno(errno, "Failed to query watchdog HW timeout, ignoring: %m");
+                        return log_error_errno(errno, "Failed to query watchdog HW timeout: %m");
         }
 
         r = watchdog_set_enable(true);
@@ -122,6 +122,7 @@ static int update_timeout(void) {
 static int open_watchdog(void) {
         struct watchdog_info ident;
         const char *fn;
+        int r;
 
         if (watchdog_fd >= 0)
                 return 0;
@@ -139,7 +140,11 @@ static int open_watchdog(void) {
                          ident.firmware_version,
                          fn);
 
-        return update_timeout();
+        r = update_timeout();
+        if (r < 0)
+                watchdog_close(true);
+
+        return r;
 }
 
 int watchdog_set_device(const char *path) {
@@ -156,6 +161,8 @@ int watchdog_set_device(const char *path) {
 }
 
 int watchdog_setup(usec_t timeout) {
+        usec_t previous_timeout;
+        int r;
 
         /* timeout=0 closes the device whereas passing timeout=USEC_INFINITY
          * opens it (if needed) without configuring any particular timeout and
@@ -175,12 +182,17 @@ int watchdog_setup(usec_t timeout) {
         /* Initialize the watchdog timeout with the caller value. This value is
          * going to be updated by update_timeout() with the closest value
          * supported by the driver */
+        previous_timeout = watchdog_timeout;
         watchdog_timeout = timeout;
 
         if (watchdog_fd < 0)
                 return open_watchdog();
 
-        return update_timeout();
+        r = update_timeout();
+        if (r < 0)
+                watchdog_timeout = previous_timeout;
+
+        return r;
 }
 
 usec_t watchdog_runtime_wait(void) {