From: Lennart Poettering Date: Thu, 17 Apr 2025 12:39:34 +0000 (+0200) Subject: shutdown: handle gracefully if a device disappears while we detach it X-Git-Tag: v256.14~56 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=fc1d80f5b31f629ee03cfd0c0cabaa67aa646dd8;p=thirdparty%2Fsystemd.git shutdown: handle gracefully if a device disappears while we detach it 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) --- diff --git a/src/shutdown/detach-loopback.c b/src/shutdown/detach-loopback.c index 8778a9e0c44..25288af2215 100644 --- a/src/shutdown/detach-loopback.c +++ b/src/shutdown/detach-loopback.c @@ -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 diff --git a/src/shutdown/detach-md.c b/src/shutdown/detach-md.c index b1aad976e57..8b88d9b870c 100644 --- a/src/shutdown/detach-md.c +++ b/src/shutdown/detach-md.c @@ -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); } diff --git a/src/shutdown/detach-swap.c b/src/shutdown/detach-swap.c index fd7dcdf943d..eafdc4341e1 100644 --- a/src/shutdown/detach-swap.c +++ b/src/shutdown/detach-swap.c @@ -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); }