]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
shutdown: handle gracefully if a device disappears while we detach it
authorLennart Poettering <lennart@poettering.net>
Thu, 17 Apr 2025 12:39:34 +0000 (14:39 +0200)
committerLuca Boccassi <luca.boccassi@gmail.com>
Sat, 17 May 2025 11:43:20 +0000 (12:43 +0100)
Let's gracefully handle cases where a device disappears in the time we
between our discovery and when we want to detach it, due to "auto-clear"
or a similar logic.

The loopback case already handled this quite OK, do the same for MD and
swap too.

Switch to ERRNO_IS_DEVICE_ABSENT() for all checks, just in case.

Also improve debug logging for all these cases, so we know exactly what
is going on.

This is inspired by #37160, but shouldn't really fix anything there, I
am pretty sure the ENODEV seen in that output stems from the STOP_ARRAY
call, not from the open().

Note that this does not change anything for the device mapper case,
because the DM subsystem does not return useful error codes to
userspace, hence everything is a complete mess there.

(cherry picked from commit 2791b2bc3d84efe674d05e45fa85333eea05ad6f)
(cherry picked from commit 4f0a4976dfe64399bc5a3c6b8f00675e2548b067)

src/shutdown/detach-loopback.c
src/shutdown/detach-md.c
src/shutdown/detach-swap.c

index 8778a9e0c441843a5168b3f60185f8435d721f29..25288af2215f2aa7d154f741b4356310cbaf28df 100644 (file)
@@ -17,6 +17,7 @@
 #include "blockdev-util.h"
 #include "detach-loopback.h"
 #include "device-util.h"
+#include "errno-util.h"
 #include "fd-util.h"
 #include "shutdown.h"
 
@@ -106,8 +107,12 @@ static int delete_loopback(const char *device) {
 
         fd = open(device, O_RDONLY|O_CLOEXEC);
         if (fd < 0) {
-                log_debug_errno(errno, "Failed to open loopback device %s: %m", device);
-                return errno == ENOENT ? 0 : -errno;
+                if (ERRNO_IS_DEVICE_ABSENT(errno)) {
+                        log_debug_errno(errno, "Tried to open loopback device '%s', but device disappeared by now, ignoring: %m", device);
+                        return 0;
+                }
+
+                return log_debug_errno(errno, "Failed to open loopback device '%s': %m", device);
         }
 
         /* Loopback block devices don't sync in-flight blocks when we clear the fd, hence sync explicitly
index b1aad976e575e0ccaf9aa962a24aa5cb133d8d83..8b88d9b870cd2a1deb9d1b8866dabc0b53a88b29 100644 (file)
@@ -131,12 +131,21 @@ static int delete_md(RaidDevice *m) {
         assert(m->path);
 
         fd = open(m->path, O_RDONLY|O_CLOEXEC|O_EXCL);
-        if (fd < 0)
-                return -errno;
+        if (fd < 0) {
+                if (ERRNO_IS_DEVICE_ABSENT(errno)) {
+                        log_debug_errno(errno, "Tried to open MD device '%s', but device disappeared by now, ignoring: %m", m->path);
+                        return 0;
+                }
+
+                return log_debug_errno(errno, "Failed to open MD device '%s': %m", m->path);
+        }
 
         (void) sync_with_progress(fd);
 
-        return RET_NERRNO(ioctl(fd, STOP_ARRAY, NULL));
+        if (ioctl(fd, STOP_ARRAY, NULL) < 0)
+                return log_debug_errno(errno, "Failed to issue STOP_ARRAY on MD device '%s': %m", m->path);
+
+        return 1;
 }
 
 static int md_points_list_detach(RaidDevice **head, bool *changed, bool last_try) {
@@ -164,8 +173,9 @@ static int md_points_list_detach(RaidDevice **head, bool *changed, bool last_try
                         n_failed++;
                         continue;
                 }
+                if (r > 0)
+                        *changed = true;
 
-                *changed = true;
                 raid_device_free(head, m);
         }
 
index fd7dcdf943d15b5a6429e2d59bb037881938d77f..eafdc4341e18ce7908339429961c2af20cc71600 100644 (file)
@@ -7,6 +7,7 @@
 
 #include "alloc-util.h"
 #include "detach-swap.h"
+#include "errno-util.h"
 #include "libmount-util.h"
 
 static void swap_device_free(SwapDevice **head, SwapDevice *m) {
@@ -74,20 +75,23 @@ int swap_list_get(const char *swaps, SwapDevice **head) {
 }
 
 static int swap_points_list_off(SwapDevice **head, bool *changed) {
-        int n_failed = 0;
+        int n_failed = 0, r;
 
         assert(head);
         assert(changed);
 
         LIST_FOREACH(swap_device, m, *head) {
                 log_info("Deactivating swap %s.", m->path);
-                if (swapoff(m->path) < 0) {
-                        log_warning_errno(errno, "Could not deactivate swap %s: %m", m->path);
+                r = RET_NERRNO(swapoff(m->path));
+                if (ERRNO_IS_NEG_DEVICE_ABSENT(r))
+                        log_debug_errno(r, "Tried to deactivate swap '%s', but swap disappeared by now, ignoring: %m", m->path);
+                else if (r < 0) {
+                        log_warning_errno(r, "Could not deactivate swap %s: %m", m->path);
                         n_failed++;
                         continue;
-                }
+                } else
+                        *changed = true;
 
-                *changed = true;
                 swap_device_free(head, m);
         }