From 49427110a00774851c61540267784681a2ffb9a1 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 2 Jun 2023 10:25:19 +0200 Subject: [PATCH 01/12] umount: split out MD detaching code from umount.c umount.c does so much stuff, and MD detaching is relatively separate, hence split it out into its own .c/.h file pair. --- src/shutdown/detach-md.c | 151 +++++++++++++++++++++++++++++++++++++++ src/shutdown/detach-md.h | 10 +++ src/shutdown/meson.build | 1 + src/shutdown/shutdown.c | 3 +- src/shutdown/umount.c | 134 +--------------------------------- src/shutdown/umount.h | 2 +- 6 files changed, 166 insertions(+), 135 deletions(-) create mode 100644 src/shutdown/detach-md.c create mode 100644 src/shutdown/detach-md.h diff --git a/src/shutdown/detach-md.c b/src/shutdown/detach-md.c new file mode 100644 index 0000000000..aff20e5342 --- /dev/null +++ b/src/shutdown/detach-md.c @@ -0,0 +1,151 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/*** + Copyright © 2010 ProFUSION embedded systems +***/ + +#include +#include +#include +#include + +#include "sd-device.h" + +#include "alloc-util.h" +#include "blockdev-util.h" +#include "detach-md.h" +#include "device-util.h" +#include "devnum-util.h" +#include "errno-util.h" +#include "fd-util.h" +#include "string-util.h" +#include "umount.h" + +static int md_list_get(MountPoint **head) { + _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL; + sd_device *d; + int r; + + assert(head); + + r = sd_device_enumerator_new(&e); + if (r < 0) + return r; + + r = sd_device_enumerator_allow_uninitialized(e); + if (r < 0) + return r; + + r = sd_device_enumerator_add_match_subsystem(e, "block", true); + if (r < 0) + return r; + + r = sd_device_enumerator_add_match_sysname(e, "md*"); + if (r < 0) + return r; + + /* Filter out partitions. */ + r = sd_device_enumerator_add_match_property(e, "DEVTYPE", "disk"); + if (r < 0) + return r; + + FOREACH_DEVICE(e, d) { + _cleanup_free_ char *p = NULL; + const char *dn, *md_level; + MountPoint *m; + dev_t devnum; + + if (sd_device_get_devnum(d, &devnum) < 0 || + sd_device_get_devname(d, &dn) < 0) + continue; + + r = sd_device_get_property_value(d, "MD_LEVEL", &md_level); + if (r < 0) { + log_warning_errno(r, "Failed to get MD_LEVEL property for %s, ignoring: %m", dn); + continue; + } + + /* MD "containers" are a special type of MD devices, used for external metadata. Since it + * doesn't provide RAID functionality in itself we don't need to stop it. */ + if (streq(md_level, "container")) + continue; + + p = strdup(dn); + if (!p) + return -ENOMEM; + + m = new(MountPoint, 1); + if (!m) + return -ENOMEM; + + *m = (MountPoint) { + .path = TAKE_PTR(p), + .devnum = devnum, + }; + + LIST_PREPEND(mount_point, *head, m); + } + + return 0; +} + +static int delete_md(MountPoint *m) { + _cleanup_close_ int fd = -EBADF; + + assert(m); + assert(major(m->devnum) != 0); + assert(m->path); + + fd = open(m->path, O_RDONLY|O_CLOEXEC|O_EXCL); + if (fd < 0) + return -errno; + + if (fsync(fd) < 0) + log_debug_errno(errno, "Failed to sync MD block device %s, ignoring: %m", m->path); + + return RET_NERRNO(ioctl(fd, STOP_ARRAY, NULL)); +} + +static int md_points_list_detach(MountPoint **head, bool *changed, bool last_try) { + int n_failed = 0, r; + dev_t rootdev = 0; + + assert(head); + assert(changed); + + (void) get_block_device("/", &rootdev); + + LIST_FOREACH(mount_point, m, *head) { + if (major(rootdev) != 0 && rootdev == m->devnum) { + n_failed ++; + continue; + } + + log_info("Stopping MD %s (" DEVNUM_FORMAT_STR ").", m->path, DEVNUM_FORMAT_VAL(m->devnum)); + r = delete_md(m); + if (r < 0) { + log_full_errno(last_try ? LOG_ERR : LOG_INFO, r, "Could not stop MD %s: %m", m->path); + n_failed++; + continue; + } + + *changed = true; + mount_point_free(head, m); + } + + return n_failed; +} + +int md_detach_all(bool *changed, bool last_try) { + _cleanup_(mount_points_list_free) LIST_HEAD(MountPoint, md_list_head); + int r; + + assert(changed); + + LIST_HEAD_INIT(md_list_head); + + r = md_list_get(&md_list_head); + if (r < 0) + return r; + + return md_points_list_detach(&md_list_head, changed, last_try); +} diff --git a/src/shutdown/detach-md.h b/src/shutdown/detach-md.h new file mode 100644 index 0000000000..3784598208 --- /dev/null +++ b/src/shutdown/detach-md.h @@ -0,0 +1,10 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +#pragma once + +/*** + Copyright © 2010 ProFUSION embedded systems +***/ + +#include + +int md_detach_all(bool *changed, bool last_try); diff --git a/src/shutdown/meson.build b/src/shutdown/meson.build index 1e28528b97..a41dc772b5 100644 --- a/src/shutdown/meson.build +++ b/src/shutdown/meson.build @@ -1,6 +1,7 @@ # SPDX-License-Identifier: LGPL-2.1-or-later systemd_shutdown_sources = files( + 'detach-md.c', 'shutdown.c', 'umount.c', ) diff --git a/src/shutdown/shutdown.c b/src/shutdown/shutdown.c index cf0351cf78..44dd765ad6 100644 --- a/src/shutdown/shutdown.c +++ b/src/shutdown/shutdown.c @@ -21,8 +21,9 @@ #include "binfmt-util.h" #include "cgroup-setup.h" #include "cgroup-util.h" -#include "coredump-util.h" #include "constants.h" +#include "coredump-util.h" +#include "detach-md.h" #include "errno-util.h" #include "exec-util.h" #include "fd-util.h" diff --git a/src/shutdown/umount.c b/src/shutdown/umount.c index 221d29ba6c..17722d7105 100644 --- a/src/shutdown/umount.c +++ b/src/shutdown/umount.c @@ -6,8 +6,6 @@ #include #include #include -#include -#include #include #include #include @@ -50,7 +48,7 @@ #include "umount.h" #include "virt.h" -static void mount_point_free(MountPoint **head, MountPoint *m) { +void mount_point_free(MountPoint **head, MountPoint *m) { assert(head); assert(m); @@ -343,74 +341,6 @@ static int dm_list_get(MountPoint **head) { return 0; } -static int md_list_get(MountPoint **head) { - _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL; - sd_device *d; - int r; - - assert(head); - - r = sd_device_enumerator_new(&e); - if (r < 0) - return r; - - r = sd_device_enumerator_allow_uninitialized(e); - if (r < 0) - return r; - - r = sd_device_enumerator_add_match_subsystem(e, "block", true); - if (r < 0) - return r; - - r = sd_device_enumerator_add_match_sysname(e, "md*"); - if (r < 0) - return r; - - /* Filter out partitions. */ - r = sd_device_enumerator_add_match_property(e, "DEVTYPE", "disk"); - if (r < 0) - return r; - - FOREACH_DEVICE(e, d) { - _cleanup_free_ char *p = NULL; - const char *dn, *md_level; - MountPoint *m; - dev_t devnum; - - if (sd_device_get_devnum(d, &devnum) < 0 || - sd_device_get_devname(d, &dn) < 0) - continue; - - r = sd_device_get_property_value(d, "MD_LEVEL", &md_level); - if (r < 0) { - log_warning_errno(r, "Failed to get MD_LEVEL property for %s, ignoring: %m", dn); - continue; - } - - /* MD "containers" are a special type of MD devices, used for external metadata. Since it - * doesn't provide RAID functionality in itself we don't need to stop it. */ - if (streq(md_level, "container")) - continue; - - p = strdup(dn); - if (!p) - return -ENOMEM; - - m = new(MountPoint, 1); - if (!m) - return -ENOMEM; - - *m = (MountPoint) { - .path = TAKE_PTR(p), - .devnum = devnum, - }; - - LIST_PREPEND(mount_point, *head, m); - } - - return 0; -} - static int delete_loopback(const char *device) { _cleanup_close_ int fd = -EBADF; struct loop_info64 info; @@ -513,23 +443,6 @@ static int delete_dm(MountPoint *m) { })); } -static int delete_md(MountPoint *m) { - _cleanup_close_ int fd = -EBADF; - - assert(m); - assert(major(m->devnum) != 0); - assert(m->path); - - fd = open(m->path, O_RDONLY|O_CLOEXEC|O_EXCL); - if (fd < 0) - return -errno; - - if (fsync(fd) < 0) - log_debug_errno(errno, "Failed to sync MD block device %s, ignoring: %m", m->path); - - return RET_NERRNO(ioctl(fd, STOP_ARRAY, NULL)); -} - static bool nonunmountable_path(const char *path) { return path_equal(path, "/") #if ! HAVE_SPLIT_USR @@ -906,36 +819,6 @@ static int dm_points_list_detach(MountPoint **head, bool *changed, bool last_try return n_failed; } -static int md_points_list_detach(MountPoint **head, bool *changed, bool last_try) { - int n_failed = 0, r; - dev_t rootdev = 0; - - assert(head); - assert(changed); - - (void) get_block_device("/", &rootdev); - - LIST_FOREACH(mount_point, m, *head) { - if (major(rootdev) != 0 && rootdev == m->devnum) { - n_failed ++; - continue; - } - - log_info("Stopping MD %s (" DEVNUM_FORMAT_STR ").", m->path, DEVNUM_FORMAT_VAL(m->devnum)); - r = delete_md(m); - if (r < 0) { - log_full_errno(last_try ? LOG_ERR : LOG_INFO, r, "Could not stop MD %s: %m", m->path); - n_failed++; - continue; - } - - *changed = true; - mount_point_free(head, m); - } - - return n_failed; -} - static int umount_all_once(bool *changed, bool last_try) { _cleanup_(mount_points_list_free) LIST_HEAD(MountPoint, mp_list_head); int r; @@ -1013,18 +896,3 @@ int dm_detach_all(bool *changed, bool last_try) { return dm_points_list_detach(&dm_list_head, changed, last_try); } - -int md_detach_all(bool *changed, bool last_try) { - _cleanup_(mount_points_list_free) LIST_HEAD(MountPoint, md_list_head); - int r; - - assert(changed); - - LIST_HEAD_INIT(md_list_head); - - r = md_list_get(&md_list_head); - if (r < 0) - return r; - - return md_points_list_detach(&md_list_head, changed, last_try); -} diff --git a/src/shutdown/umount.h b/src/shutdown/umount.h index a742ac0af5..0b25a45f5b 100644 --- a/src/shutdown/umount.h +++ b/src/shutdown/umount.h @@ -11,7 +11,6 @@ int umount_all(bool *changed, bool last_try); int swapoff_all(bool *changed); int loopback_detach_all(bool *changed, bool last_try); int dm_detach_all(bool *changed, bool last_try); -int md_detach_all(bool *changed, bool last_try); /* This is exported just for testing */ typedef struct MountPoint { @@ -26,5 +25,6 @@ typedef struct MountPoint { } MountPoint; int mount_points_list_get(const char *mountinfo, MountPoint **head); +void mount_point_free(MountPoint **head, MountPoint *m); void mount_points_list_free(MountPoint **head); int swap_list_get(const char *swaps, MountPoint **head); From b44411c7028dc95eb3fd0745562ddf303a0d3372 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 2 Jun 2023 10:31:55 +0200 Subject: [PATCH 02/12] umount: similar as previous commit, split out DM detaching --- src/shutdown/detach-dm.c | 143 +++++++++++++++++++++++++++++++++++++++ src/shutdown/detach-dm.h | 10 +++ src/shutdown/meson.build | 1 + src/shutdown/shutdown.c | 1 + src/shutdown/umount.c | 124 --------------------------------- src/shutdown/umount.h | 1 - 6 files changed, 155 insertions(+), 125 deletions(-) create mode 100644 src/shutdown/detach-dm.c create mode 100644 src/shutdown/detach-dm.h diff --git a/src/shutdown/detach-dm.c b/src/shutdown/detach-dm.c new file mode 100644 index 0000000000..8a6408e4d2 --- /dev/null +++ b/src/shutdown/detach-dm.c @@ -0,0 +1,143 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/*** + Copyright © 2010 ProFUSION embedded systems +***/ + +#include +#include + +#include "sd-device.h" + +#include "alloc-util.h" +#include "blockdev-util.h" +#include "detach-dm.h" +#include "device-util.h" +#include "devnum-util.h" +#include "errno-util.h" +#include "fd-util.h" +#include "sync-util.h" +#include "umount.h" + +static int dm_list_get(MountPoint **head) { + _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL; + sd_device *d; + int r; + + assert(head); + + r = sd_device_enumerator_new(&e); + if (r < 0) + return r; + + r = sd_device_enumerator_allow_uninitialized(e); + if (r < 0) + return r; + + r = sd_device_enumerator_add_match_subsystem(e, "block", true); + if (r < 0) + return r; + + r = sd_device_enumerator_add_match_sysname(e, "dm-*"); + if (r < 0) + return r; + + FOREACH_DEVICE(e, d) { + _cleanup_free_ char *p = NULL; + const char *dn; + MountPoint *m; + dev_t devnum; + + if (sd_device_get_devnum(d, &devnum) < 0 || + sd_device_get_devname(d, &dn) < 0) + continue; + + p = strdup(dn); + if (!p) + return -ENOMEM; + + m = new(MountPoint, 1); + if (!m) + return -ENOMEM; + + *m = (MountPoint) { + .path = TAKE_PTR(p), + .devnum = devnum, + }; + + LIST_PREPEND(mount_point, *head, m); + } + + return 0; +} + +static int delete_dm(MountPoint *m) { + _cleanup_close_ int fd = -EBADF; + int r; + + assert(m); + assert(major(m->devnum) != 0); + assert(m->path); + + fd = open("/dev/mapper/control", O_RDWR|O_CLOEXEC); + if (fd < 0) + return -errno; + + r = fsync_path_at(AT_FDCWD, m->path); + if (r < 0) + log_debug_errno(r, "Failed to sync DM block device %s, ignoring: %m", m->path); + + return RET_NERRNO(ioctl(fd, DM_DEV_REMOVE, &(struct dm_ioctl) { + .version = { + DM_VERSION_MAJOR, + DM_VERSION_MINOR, + DM_VERSION_PATCHLEVEL + }, + .data_size = sizeof(struct dm_ioctl), + .dev = m->devnum, + })); +} + +static int dm_points_list_detach(MountPoint **head, bool *changed, bool last_try) { + int n_failed = 0, r; + dev_t rootdev = 0; + + assert(head); + assert(changed); + + (void) get_block_device("/", &rootdev); + + LIST_FOREACH(mount_point, m, *head) { + if (major(rootdev) != 0 && rootdev == m->devnum) { + n_failed ++; + continue; + } + + log_info("Detaching DM %s (" DEVNUM_FORMAT_STR ").", m->path, DEVNUM_FORMAT_VAL(m->devnum)); + r = delete_dm(m); + if (r < 0) { + log_full_errno(last_try ? LOG_ERR : LOG_INFO, r, "Could not detach DM %s: %m", m->path); + n_failed++; + continue; + } + + *changed = true; + mount_point_free(head, m); + } + + return n_failed; +} + +int dm_detach_all(bool *changed, bool last_try) { + _cleanup_(mount_points_list_free) LIST_HEAD(MountPoint, dm_list_head); + int r; + + assert(changed); + + LIST_HEAD_INIT(dm_list_head); + + r = dm_list_get(&dm_list_head); + if (r < 0) + return r; + + return dm_points_list_detach(&dm_list_head, changed, last_try); +} diff --git a/src/shutdown/detach-dm.h b/src/shutdown/detach-dm.h new file mode 100644 index 0000000000..b5f50a3bbf --- /dev/null +++ b/src/shutdown/detach-dm.h @@ -0,0 +1,10 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +#pragma once + +/*** + Copyright © 2010 ProFUSION embedded systems +***/ + +#include + +int dm_detach_all(bool *changed, bool last_try); diff --git a/src/shutdown/meson.build b/src/shutdown/meson.build index a41dc772b5..1e30f57cbb 100644 --- a/src/shutdown/meson.build +++ b/src/shutdown/meson.build @@ -1,6 +1,7 @@ # SPDX-License-Identifier: LGPL-2.1-or-later systemd_shutdown_sources = files( + 'detach-dm.c', 'detach-md.c', 'shutdown.c', 'umount.c', diff --git a/src/shutdown/shutdown.c b/src/shutdown/shutdown.c index 44dd765ad6..6fa0107a5d 100644 --- a/src/shutdown/shutdown.c +++ b/src/shutdown/shutdown.c @@ -23,6 +23,7 @@ #include "cgroup-util.h" #include "constants.h" #include "coredump-util.h" +#include "detach-dm.h" #include "detach-md.h" #include "errno-util.h" #include "exec-util.h" diff --git a/src/shutdown/umount.c b/src/shutdown/umount.c index 17722d7105..85f0eb9fe6 100644 --- a/src/shutdown/umount.c +++ b/src/shutdown/umount.c @@ -5,7 +5,6 @@ #include #include -#include #include #include #include @@ -289,57 +288,6 @@ static int loopback_list_get(MountPoint **head) { return 0; } -static int dm_list_get(MountPoint **head) { - _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL; - sd_device *d; - int r; - - assert(head); - - r = sd_device_enumerator_new(&e); - if (r < 0) - return r; - - r = sd_device_enumerator_allow_uninitialized(e); - if (r < 0) - return r; - - r = sd_device_enumerator_add_match_subsystem(e, "block", true); - if (r < 0) - return r; - - r = sd_device_enumerator_add_match_sysname(e, "dm-*"); - if (r < 0) - return r; - - FOREACH_DEVICE(e, d) { - _cleanup_free_ char *p = NULL; - const char *dn; - MountPoint *m; - dev_t devnum; - - if (sd_device_get_devnum(d, &devnum) < 0 || - sd_device_get_devname(d, &dn) < 0) - continue; - - p = strdup(dn); - if (!p) - return -ENOMEM; - - m = new(MountPoint, 1); - if (!m) - return -ENOMEM; - - *m = (MountPoint) { - .path = TAKE_PTR(p), - .devnum = devnum, - }; - - LIST_PREPEND(mount_point, *head, m); - } - - return 0; -} static int delete_loopback(const char *device) { _cleanup_close_ int fd = -EBADF; @@ -416,33 +364,6 @@ static int delete_loopback(const char *device) { return -EBUSY; /* Nothing changed, the device is still attached, hence it apparently is still busy */ } -static int delete_dm(MountPoint *m) { - _cleanup_close_ int fd = -EBADF; - int r; - - assert(m); - assert(major(m->devnum) != 0); - assert(m->path); - - fd = open("/dev/mapper/control", O_RDWR|O_CLOEXEC); - if (fd < 0) - return -errno; - - r = fsync_path_at(AT_FDCWD, m->path); - if (r < 0) - log_debug_errno(r, "Failed to sync DM block device %s, ignoring: %m", m->path); - - return RET_NERRNO(ioctl(fd, DM_DEV_REMOVE, &(struct dm_ioctl) { - .version = { - DM_VERSION_MAJOR, - DM_VERSION_MINOR, - DM_VERSION_PATCHLEVEL - }, - .data_size = sizeof(struct dm_ioctl), - .dev = m->devnum, - })); -} - static bool nonunmountable_path(const char *path) { return path_equal(path, "/") #if ! HAVE_SPLIT_USR @@ -789,36 +710,6 @@ static int loopback_points_list_detach(MountPoint **head, bool *changed, bool la return n_failed; } -static int dm_points_list_detach(MountPoint **head, bool *changed, bool last_try) { - int n_failed = 0, r; - dev_t rootdev = 0; - - assert(head); - assert(changed); - - (void) get_block_device("/", &rootdev); - - LIST_FOREACH(mount_point, m, *head) { - if (major(rootdev) != 0 && rootdev == m->devnum) { - n_failed ++; - continue; - } - - log_info("Detaching DM %s (" DEVNUM_FORMAT_STR ").", m->path, DEVNUM_FORMAT_VAL(m->devnum)); - r = delete_dm(m); - if (r < 0) { - log_full_errno(last_try ? LOG_ERR : LOG_INFO, r, "Could not detach DM %s: %m", m->path); - n_failed++; - continue; - } - - *changed = true; - mount_point_free(head, m); - } - - return n_failed; -} - static int umount_all_once(bool *changed, bool last_try) { _cleanup_(mount_points_list_free) LIST_HEAD(MountPoint, mp_list_head); int r; @@ -881,18 +772,3 @@ int loopback_detach_all(bool *changed, bool last_try) { return loopback_points_list_detach(&loopback_list_head, changed, last_try); } - -int dm_detach_all(bool *changed, bool last_try) { - _cleanup_(mount_points_list_free) LIST_HEAD(MountPoint, dm_list_head); - int r; - - assert(changed); - - LIST_HEAD_INIT(dm_list_head); - - r = dm_list_get(&dm_list_head); - if (r < 0) - return r; - - return dm_points_list_detach(&dm_list_head, changed, last_try); -} diff --git a/src/shutdown/umount.h b/src/shutdown/umount.h index 0b25a45f5b..7a849ca8a6 100644 --- a/src/shutdown/umount.h +++ b/src/shutdown/umount.h @@ -10,7 +10,6 @@ int umount_all(bool *changed, bool last_try); int swapoff_all(bool *changed); int loopback_detach_all(bool *changed, bool last_try); -int dm_detach_all(bool *changed, bool last_try); /* This is exported just for testing */ typedef struct MountPoint { From 2e2c472b1c424e8ae15d4da5a754e1f3b8182a00 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 2 Jun 2023 10:36:39 +0200 Subject: [PATCH 03/12] umount: split out loopback detach code Like the similar commits, no actual code changes, just splitting up large C files. --- src/shutdown/detach-loopback.c | 198 +++++++++++++++++++++++++++++++++ src/shutdown/detach-loopback.h | 10 ++ src/shutdown/meson.build | 1 + src/shutdown/shutdown.c | 1 + src/shutdown/umount.c | 197 +------------------------------- src/shutdown/umount.h | 1 - 6 files changed, 211 insertions(+), 197 deletions(-) create mode 100644 src/shutdown/detach-loopback.c create mode 100644 src/shutdown/detach-loopback.h diff --git a/src/shutdown/detach-loopback.c b/src/shutdown/detach-loopback.c new file mode 100644 index 0000000000..49150077d6 --- /dev/null +++ b/src/shutdown/detach-loopback.c @@ -0,0 +1,198 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/*** + Copyright © 2010 ProFUSION embedded systems +***/ + +#include +#include +#include + +#if HAVE_VALGRIND_MEMCHECK_H +#include +#endif + +#include "sd-device.h" + +#include "alloc-util.h" +#include "blockdev-util.h" +#include "detach-loopback.h" +#include "device-util.h" +#include "fd-util.h" +#include "umount.h" + +static int loopback_list_get(MountPoint **head) { + _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL; + sd_device *d; + int r; + + assert(head); + + r = sd_device_enumerator_new(&e); + if (r < 0) + return r; + + r = sd_device_enumerator_allow_uninitialized(e); + if (r < 0) + return r; + + r = sd_device_enumerator_add_match_subsystem(e, "block", true); + if (r < 0) + return r; + + r = sd_device_enumerator_add_match_sysname(e, "loop*"); + if (r < 0) + return r; + + r = sd_device_enumerator_add_match_sysattr(e, "loop/backing_file", NULL, true); + if (r < 0) + return r; + + FOREACH_DEVICE(e, d) { + _cleanup_free_ char *p = NULL; + const char *dn; + MountPoint *lb; + dev_t devnum; + + if (sd_device_get_devnum(d, &devnum) < 0 || + sd_device_get_devname(d, &dn) < 0) + continue; + + p = strdup(dn); + if (!p) + return -ENOMEM; + + lb = new(MountPoint, 1); + if (!lb) + return -ENOMEM; + + *lb = (MountPoint) { + .path = TAKE_PTR(p), + .devnum = devnum, + }; + + LIST_PREPEND(mount_point, *head, lb); + } + + return 0; +} + +static int delete_loopback(const char *device) { + _cleanup_close_ int fd = -EBADF; + struct loop_info64 info; + + assert(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; + } + + /* Loopback block devices don't sync in-flight blocks when we clear the fd, hence sync explicitly + * first */ + if (fsync(fd) < 0) + log_debug_errno(errno, "Failed to sync loop block device %s, ignoring: %m", device); + + if (ioctl(fd, LOOP_CLR_FD, 0) < 0) { + if (errno == ENXIO) /* Nothing bound, didn't do anything */ + return 0; + + if (errno != EBUSY) + return log_debug_errno(errno, "Failed to clear loopback device %s: %m", device); + + if (ioctl(fd, LOOP_GET_STATUS64, &info) < 0) { + if (errno == ENXIO) /* What? Suddenly detached after all? That's fine by us then. */ + return 1; + + log_debug_errno(errno, "Failed to invoke LOOP_GET_STATUS64 on loopback device %s, ignoring: %m", device); + return -EBUSY; /* propagate original error */ + } + +#if HAVE_VALGRIND_MEMCHECK_H + VALGRIND_MAKE_MEM_DEFINED(&info, sizeof(info)); +#endif + + if (FLAGS_SET(info.lo_flags, LO_FLAGS_AUTOCLEAR)) /* someone else already set LO_FLAGS_AUTOCLEAR for us? fine by us */ + return -EBUSY; /* propagate original error */ + + info.lo_flags |= LO_FLAGS_AUTOCLEAR; + if (ioctl(fd, LOOP_SET_STATUS64, &info) < 0) { + if (errno == ENXIO) /* Suddenly detached after all? Fine by us */ + return 1; + + log_debug_errno(errno, "Failed to set LO_FLAGS_AUTOCLEAR flag for loop device %s, ignoring: %m", device); + } else + log_debug("Successfully set LO_FLAGS_AUTOCLEAR flag for loop device %s.", device); + + return -EBUSY; + } + + if (ioctl(fd, LOOP_GET_STATUS64, &info) < 0) { + /* If the LOOP_CLR_FD above succeeded we'll see ENXIO here. */ + if (errno == ENXIO) + log_debug("Successfully detached loopback device %s.", device); + else + log_debug_errno(errno, "Failed to invoke LOOP_GET_STATUS64 on loopback device %s, ignoring: %m", device); /* the LOOP_CLR_FD at least worked, let's hope for the best */ + + return 1; + } + +#if HAVE_VALGRIND_MEMCHECK_H + VALGRIND_MAKE_MEM_DEFINED(&info, sizeof(info)); +#endif + + /* Linux makes LOOP_CLR_FD succeed whenever LO_FLAGS_AUTOCLEAR is set without actually doing + * anything. Very confusing. Let's hence not claim we did anything in this case. */ + if (FLAGS_SET(info.lo_flags, LO_FLAGS_AUTOCLEAR)) + log_debug("Successfully called LOOP_CLR_FD on a loopback device %s with autoclear set, which is a NOP.", device); + else + log_debug("Weird, LOOP_CLR_FD succeeded but the device is still attached on %s.", device); + + return -EBUSY; /* Nothing changed, the device is still attached, hence it apparently is still busy */ +} + +static int loopback_points_list_detach(MountPoint **head, bool *changed, bool last_try) { + int n_failed = 0, r; + dev_t rootdev = 0; + + assert(head); + assert(changed); + + (void) get_block_device("/", &rootdev); + + LIST_FOREACH(mount_point, m, *head) { + if (major(rootdev) != 0 && rootdev == m->devnum) { + n_failed++; + continue; + } + + log_info("Detaching loopback %s.", m->path); + r = delete_loopback(m->path); + if (r < 0) { + log_full_errno(last_try ? LOG_ERR : LOG_INFO, r, "Could not detach loopback %s: %m", m->path); + n_failed++; + continue; + } + if (r > 0) + *changed = true; + + mount_point_free(head, m); + } + + return n_failed; +} + +int loopback_detach_all(bool *changed, bool last_try) { + _cleanup_(mount_points_list_free) LIST_HEAD(MountPoint, loopback_list_head); + int r; + + assert(changed); + + LIST_HEAD_INIT(loopback_list_head); + + r = loopback_list_get(&loopback_list_head); + if (r < 0) + return r; + + return loopback_points_list_detach(&loopback_list_head, changed, last_try); +} diff --git a/src/shutdown/detach-loopback.h b/src/shutdown/detach-loopback.h new file mode 100644 index 0000000000..d6d73f31af --- /dev/null +++ b/src/shutdown/detach-loopback.h @@ -0,0 +1,10 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +#pragma once + +/*** + Copyright © 2010 ProFUSION embedded systems +***/ + +#include + +int loopback_detach_all(bool *changed, bool last_try); diff --git a/src/shutdown/meson.build b/src/shutdown/meson.build index 1e30f57cbb..fbf0f09795 100644 --- a/src/shutdown/meson.build +++ b/src/shutdown/meson.build @@ -2,6 +2,7 @@ systemd_shutdown_sources = files( 'detach-dm.c', + 'detach-loopback.c', 'detach-md.c', 'shutdown.c', 'umount.c', diff --git a/src/shutdown/shutdown.c b/src/shutdown/shutdown.c index 6fa0107a5d..30b4bdd65a 100644 --- a/src/shutdown/shutdown.c +++ b/src/shutdown/shutdown.c @@ -24,6 +24,7 @@ #include "constants.h" #include "coredump-util.h" #include "detach-dm.h" +#include "detach-loopback.h" #include "detach-md.h" #include "errno-util.h" #include "exec-util.h" diff --git a/src/shutdown/umount.c b/src/shutdown/umount.c index 85f0eb9fe6..8a59efd385 100644 --- a/src/shutdown/umount.c +++ b/src/shutdown/umount.c @@ -5,27 +5,15 @@ #include #include -#include #include -#include #include +#include #include #include -#if HAVE_VALGRIND_MEMCHECK_H -#include -#endif - -#include "sd-device.h" - #include "alloc-util.h" -#include "blockdev-util.h" #include "chase.h" -#include "constants.h" -#include "device-util.h" -#include "devnum-util.h" #include "dirent-util.h" -#include "escape.h" #include "fd-util.h" #include "fileio.h" #include "fs-util.h" @@ -36,14 +24,9 @@ #include "mount-util.h" #include "mountpoint-util.h" #include "parse-util.h" -#include "path-util.h" #include "process-util.h" #include "random-util.h" #include "signal-util.h" -#include "stat-util.h" -#include "string-util.h" -#include "strv.h" -#include "sync-util.h" #include "umount.h" #include "virt.h" @@ -232,138 +215,6 @@ int swap_list_get(const char *swaps, MountPoint **head) { return 0; } -static int loopback_list_get(MountPoint **head) { - _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL; - sd_device *d; - int r; - - assert(head); - - r = sd_device_enumerator_new(&e); - if (r < 0) - return r; - - r = sd_device_enumerator_allow_uninitialized(e); - if (r < 0) - return r; - - r = sd_device_enumerator_add_match_subsystem(e, "block", true); - if (r < 0) - return r; - - r = sd_device_enumerator_add_match_sysname(e, "loop*"); - if (r < 0) - return r; - - r = sd_device_enumerator_add_match_sysattr(e, "loop/backing_file", NULL, true); - if (r < 0) - return r; - - FOREACH_DEVICE(e, d) { - _cleanup_free_ char *p = NULL; - const char *dn; - MountPoint *lb; - dev_t devnum; - - if (sd_device_get_devnum(d, &devnum) < 0 || - sd_device_get_devname(d, &dn) < 0) - continue; - - p = strdup(dn); - if (!p) - return -ENOMEM; - - lb = new(MountPoint, 1); - if (!lb) - return -ENOMEM; - - *lb = (MountPoint) { - .path = TAKE_PTR(p), - .devnum = devnum, - }; - - LIST_PREPEND(mount_point, *head, lb); - } - - return 0; -} - - -static int delete_loopback(const char *device) { - _cleanup_close_ int fd = -EBADF; - struct loop_info64 info; - - assert(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; - } - - /* Loopback block devices don't sync in-flight blocks when we clear the fd, hence sync explicitly - * first */ - if (fsync(fd) < 0) - log_debug_errno(errno, "Failed to sync loop block device %s, ignoring: %m", device); - - if (ioctl(fd, LOOP_CLR_FD, 0) < 0) { - if (errno == ENXIO) /* Nothing bound, didn't do anything */ - return 0; - - if (errno != EBUSY) - return log_debug_errno(errno, "Failed to clear loopback device %s: %m", device); - - if (ioctl(fd, LOOP_GET_STATUS64, &info) < 0) { - if (errno == ENXIO) /* What? Suddenly detached after all? That's fine by us then. */ - return 1; - - log_debug_errno(errno, "Failed to invoke LOOP_GET_STATUS64 on loopback device %s, ignoring: %m", device); - return -EBUSY; /* propagate original error */ - } - -#if HAVE_VALGRIND_MEMCHECK_H - VALGRIND_MAKE_MEM_DEFINED(&info, sizeof(info)); -#endif - - if (FLAGS_SET(info.lo_flags, LO_FLAGS_AUTOCLEAR)) /* someone else already set LO_FLAGS_AUTOCLEAR for us? fine by us */ - return -EBUSY; /* propagate original error */ - - info.lo_flags |= LO_FLAGS_AUTOCLEAR; - if (ioctl(fd, LOOP_SET_STATUS64, &info) < 0) { - if (errno == ENXIO) /* Suddenly detached after all? Fine by us */ - return 1; - - log_debug_errno(errno, "Failed to set LO_FLAGS_AUTOCLEAR flag for loop device %s, ignoring: %m", device); - } else - log_debug("Successfully set LO_FLAGS_AUTOCLEAR flag for loop device %s.", device); - - return -EBUSY; - } - - if (ioctl(fd, LOOP_GET_STATUS64, &info) < 0) { - /* If the LOOP_CLR_FD above succeeded we'll see ENXIO here. */ - if (errno == ENXIO) - log_debug("Successfully detached loopback device %s.", device); - else - log_debug_errno(errno, "Failed to invoke LOOP_GET_STATUS64 on loopback device %s, ignoring: %m", device); /* the LOOP_CLR_FD at least worked, let's hope for the best */ - - return 1; - } - -#if HAVE_VALGRIND_MEMCHECK_H - VALGRIND_MAKE_MEM_DEFINED(&info, sizeof(info)); -#endif - - /* Linux makes LOOP_CLR_FD succeed whenever LO_FLAGS_AUTOCLEAR is set without actually doing - * anything. Very confusing. Let's hence not claim we did anything in this case. */ - if (FLAGS_SET(info.lo_flags, LO_FLAGS_AUTOCLEAR)) - log_debug("Successfully called LOOP_CLR_FD on a loopback device %s with autoclear set, which is a NOP.", device); - else - log_debug("Weird, LOOP_CLR_FD succeeded but the device is still attached on %s.", device); - - return -EBUSY; /* Nothing changed, the device is still attached, hence it apparently is still busy */ -} - static bool nonunmountable_path(const char *path) { return path_equal(path, "/") #if ! HAVE_SPLIT_USR @@ -679,37 +530,6 @@ static int swap_points_list_off(MountPoint **head, bool *changed) { return n_failed; } -static int loopback_points_list_detach(MountPoint **head, bool *changed, bool last_try) { - int n_failed = 0, r; - dev_t rootdev = 0; - - assert(head); - assert(changed); - - (void) get_block_device("/", &rootdev); - - LIST_FOREACH(mount_point, m, *head) { - if (major(rootdev) != 0 && rootdev == m->devnum) { - n_failed++; - continue; - } - - log_info("Detaching loopback %s.", m->path); - r = delete_loopback(m->path); - if (r < 0) { - log_full_errno(last_try ? LOG_ERR : LOG_INFO, r, "Could not detach loopback %s: %m", m->path); - n_failed++; - continue; - } - if (r > 0) - *changed = true; - - mount_point_free(head, m); - } - - return n_failed; -} - static int umount_all_once(bool *changed, bool last_try) { _cleanup_(mount_points_list_free) LIST_HEAD(MountPoint, mp_list_head); int r; @@ -757,18 +577,3 @@ int swapoff_all(bool *changed) { return swap_points_list_off(&swap_list_head, changed); } - -int loopback_detach_all(bool *changed, bool last_try) { - _cleanup_(mount_points_list_free) LIST_HEAD(MountPoint, loopback_list_head); - int r; - - assert(changed); - - LIST_HEAD_INIT(loopback_list_head); - - r = loopback_list_get(&loopback_list_head); - if (r < 0) - return r; - - return loopback_points_list_detach(&loopback_list_head, changed, last_try); -} diff --git a/src/shutdown/umount.h b/src/shutdown/umount.h index 7a849ca8a6..b3a397bddf 100644 --- a/src/shutdown/umount.h +++ b/src/shutdown/umount.h @@ -9,7 +9,6 @@ int umount_all(bool *changed, bool last_try); int swapoff_all(bool *changed); -int loopback_detach_all(bool *changed, bool last_try); /* This is exported just for testing */ typedef struct MountPoint { From 82a1d6d09625b656c991f25e82b5651c74a55945 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 2 Jun 2023 10:46:17 +0200 Subject: [PATCH 04/12] umount: split out swap detachment code too --- src/shutdown/detach-swap.c | 93 ++++++++++++++++++++++++++++++++++++++ src/shutdown/detach-swap.h | 14 ++++++ src/shutdown/meson.build | 2 + src/shutdown/shutdown.c | 1 + src/shutdown/test-umount.c | 1 + src/shutdown/umount.c | 84 ---------------------------------- src/shutdown/umount.h | 2 - 7 files changed, 111 insertions(+), 86 deletions(-) create mode 100644 src/shutdown/detach-swap.c create mode 100644 src/shutdown/detach-swap.h diff --git a/src/shutdown/detach-swap.c b/src/shutdown/detach-swap.c new file mode 100644 index 0000000000..83e428038e --- /dev/null +++ b/src/shutdown/detach-swap.c @@ -0,0 +1,93 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/*** + Copyright © 2010 ProFUSION embedded systems +***/ + +#include + +#include "alloc-util.h" +#include "detach-swap.h" +#include "libmount-util.h" + +int swap_list_get(const char *swaps, MountPoint **head) { + _cleanup_(mnt_free_tablep) struct libmnt_table *t = NULL; + _cleanup_(mnt_free_iterp) struct libmnt_iter *i = NULL; + int r; + + assert(head); + + t = mnt_new_table(); + i = mnt_new_iter(MNT_ITER_FORWARD); + if (!t || !i) + return log_oom(); + + r = mnt_table_parse_swaps(t, swaps); + if (r == -ENOENT) /* no /proc/swaps is fine */ + return 0; + if (r < 0) + return log_error_errno(r, "Failed to parse %s: %m", swaps ?: "/proc/swaps"); + + for (;;) { + struct libmnt_fs *fs; + _cleanup_free_ MountPoint *swap = NULL; + const char *source; + + r = mnt_table_next_fs(t, i, &fs); + if (r == 1) /* EOF */ + break; + if (r < 0) + return log_error_errno(r, "Failed to get next entry from %s: %m", swaps ?: "/proc/swaps"); + + source = mnt_fs_get_source(fs); + if (!source) + continue; + + swap = new0(MountPoint, 1); + if (!swap) + return log_oom(); + + swap->path = strdup(source); + if (!swap->path) + return log_oom(); + + LIST_PREPEND(mount_point, *head, TAKE_PTR(swap)); + } + + return 0; +} + +static int swap_points_list_off(MountPoint **head, bool *changed) { + int n_failed = 0; + + assert(head); + assert(changed); + + LIST_FOREACH(mount_point, 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); + n_failed++; + continue; + } + + *changed = true; + mount_point_free(head, m); + } + + return n_failed; +} + +int swapoff_all(bool *changed) { + _cleanup_(mount_points_list_free) LIST_HEAD(MountPoint, swap_list_head); + int r; + + assert(changed); + + LIST_HEAD_INIT(swap_list_head); + + r = swap_list_get(NULL, &swap_list_head); + if (r < 0) + return r; + + return swap_points_list_off(&swap_list_head, changed); +} diff --git a/src/shutdown/detach-swap.h b/src/shutdown/detach-swap.h new file mode 100644 index 0000000000..7c2b97f773 --- /dev/null +++ b/src/shutdown/detach-swap.h @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +#pragma once + +/*** + Copyright © 2010 ProFUSION embedded systems +***/ + +#include + +#include "umount.h" + +int swapoff_all(bool *changed); + +int swap_list_get(const char *swaps, MountPoint **head); diff --git a/src/shutdown/meson.build b/src/shutdown/meson.build index fbf0f09795..6538882692 100644 --- a/src/shutdown/meson.build +++ b/src/shutdown/meson.build @@ -4,6 +4,7 @@ systemd_shutdown_sources = files( 'detach-dm.c', 'detach-loopback.c', 'detach-md.c', + 'detach-swap.c', 'shutdown.c', 'umount.c', ) @@ -11,6 +12,7 @@ systemd_shutdown_sources = files( tests += [ { 'sources' : files( + 'detach-swap.c', 'test-umount.c', 'umount.c', ), diff --git a/src/shutdown/shutdown.c b/src/shutdown/shutdown.c index 30b4bdd65a..b742732bb1 100644 --- a/src/shutdown/shutdown.c +++ b/src/shutdown/shutdown.c @@ -26,6 +26,7 @@ #include "detach-dm.h" #include "detach-loopback.h" #include "detach-md.h" +#include "detach-swap.h" #include "errno-util.h" #include "exec-util.h" #include "fd-util.h" diff --git a/src/shutdown/test-umount.c b/src/shutdown/test-umount.c index 80ec9b6dd6..36036dd375 100644 --- a/src/shutdown/test-umount.c +++ b/src/shutdown/test-umount.c @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ #include "alloc-util.h" +#include "detach-swap.h" #include "errno-util.h" #include "log.h" #include "path-util.h" diff --git a/src/shutdown/umount.c b/src/shutdown/umount.c index 8a59efd385..05f7b5b513 100644 --- a/src/shutdown/umount.c +++ b/src/shutdown/umount.c @@ -7,7 +7,6 @@ #include #include #include -#include #include #include @@ -168,53 +167,6 @@ int mount_points_list_get(const char *mountinfo, MountPoint **head) { return 0; } -int swap_list_get(const char *swaps, MountPoint **head) { - _cleanup_(mnt_free_tablep) struct libmnt_table *t = NULL; - _cleanup_(mnt_free_iterp) struct libmnt_iter *i = NULL; - int r; - - assert(head); - - t = mnt_new_table(); - i = mnt_new_iter(MNT_ITER_FORWARD); - if (!t || !i) - return log_oom(); - - r = mnt_table_parse_swaps(t, swaps); - if (r == -ENOENT) /* no /proc/swaps is fine */ - return 0; - if (r < 0) - return log_error_errno(r, "Failed to parse %s: %m", swaps ?: "/proc/swaps"); - - for (;;) { - struct libmnt_fs *fs; - _cleanup_free_ MountPoint *swap = NULL; - const char *source; - - r = mnt_table_next_fs(t, i, &fs); - if (r == 1) /* EOF */ - break; - if (r < 0) - return log_error_errno(r, "Failed to get next entry from %s: %m", swaps ?: "/proc/swaps"); - - source = mnt_fs_get_source(fs); - if (!source) - continue; - - swap = new0(MountPoint, 1); - if (!swap) - return log_oom(); - - swap->path = strdup(source); - if (!swap->path) - return log_oom(); - - LIST_PREPEND(mount_point, *head, TAKE_PTR(swap)); - } - - return 0; -} - static bool nonunmountable_path(const char *path) { return path_equal(path, "/") #if ! HAVE_SPLIT_USR @@ -509,27 +461,6 @@ static int mount_points_list_umount(MountPoint **head, bool *changed, bool last_ return n_failed; } -static int swap_points_list_off(MountPoint **head, bool *changed) { - int n_failed = 0; - - assert(head); - assert(changed); - - LIST_FOREACH(mount_point, 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); - n_failed++; - continue; - } - - *changed = true; - mount_point_free(head, m); - } - - return n_failed; -} - static int umount_all_once(bool *changed, bool last_try) { _cleanup_(mount_points_list_free) LIST_HEAD(MountPoint, mp_list_head); int r; @@ -562,18 +493,3 @@ int umount_all(bool *changed, bool last_try) { return r; } - -int swapoff_all(bool *changed) { - _cleanup_(mount_points_list_free) LIST_HEAD(MountPoint, swap_list_head); - int r; - - assert(changed); - - LIST_HEAD_INIT(swap_list_head); - - r = swap_list_get(NULL, &swap_list_head); - if (r < 0) - return r; - - return swap_points_list_off(&swap_list_head, changed); -} diff --git a/src/shutdown/umount.h b/src/shutdown/umount.h index b3a397bddf..eeda7f8ad9 100644 --- a/src/shutdown/umount.h +++ b/src/shutdown/umount.h @@ -8,7 +8,6 @@ #include "list.h" int umount_all(bool *changed, bool last_try); -int swapoff_all(bool *changed); /* This is exported just for testing */ typedef struct MountPoint { @@ -25,4 +24,3 @@ typedef struct MountPoint { int mount_points_list_get(const char *mountinfo, MountPoint **head); void mount_point_free(MountPoint **head, MountPoint *m); void mount_points_list_free(MountPoint **head); -int swap_list_get(const char *swaps, MountPoint **head); From a0fb20672d6bcbee6ee36b679adcbac67e33e799 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 2 Jun 2023 10:51:08 +0200 Subject: [PATCH 05/12] detach-swap: decouple from umount.h So far detach-swap.[ch] were still using the MountPoint structure to store swap device info in. Since it was only using a single field of it sharing the whole structure is kinda pointless. Hence, let's decouple this and only add the field we really need. --- src/shutdown/detach-swap.c | 33 +++++++++++++++++++++++++-------- src/shutdown/detach-swap.h | 11 +++++++++-- src/shutdown/test-umount.c | 15 +++++---------- 3 files changed, 39 insertions(+), 20 deletions(-) diff --git a/src/shutdown/detach-swap.c b/src/shutdown/detach-swap.c index 83e428038e..fd7dcdf943 100644 --- a/src/shutdown/detach-swap.c +++ b/src/shutdown/detach-swap.c @@ -9,7 +9,24 @@ #include "detach-swap.h" #include "libmount-util.h" -int swap_list_get(const char *swaps, MountPoint **head) { +static void swap_device_free(SwapDevice **head, SwapDevice *m) { + assert(head); + assert(m); + + LIST_REMOVE(swap_device, *head, m); + + free(m->path); + free(m); +} + +void swap_devices_list_free(SwapDevice **head) { + assert(head); + + while (*head) + swap_device_free(head, *head); +} + +int swap_list_get(const char *swaps, SwapDevice **head) { _cleanup_(mnt_free_tablep) struct libmnt_table *t = NULL; _cleanup_(mnt_free_iterp) struct libmnt_iter *i = NULL; int r; @@ -29,7 +46,7 @@ int swap_list_get(const char *swaps, MountPoint **head) { for (;;) { struct libmnt_fs *fs; - _cleanup_free_ MountPoint *swap = NULL; + _cleanup_free_ SwapDevice *swap = NULL; const char *source; r = mnt_table_next_fs(t, i, &fs); @@ -42,7 +59,7 @@ int swap_list_get(const char *swaps, MountPoint **head) { if (!source) continue; - swap = new0(MountPoint, 1); + swap = new0(SwapDevice, 1); if (!swap) return log_oom(); @@ -50,19 +67,19 @@ int swap_list_get(const char *swaps, MountPoint **head) { if (!swap->path) return log_oom(); - LIST_PREPEND(mount_point, *head, TAKE_PTR(swap)); + LIST_PREPEND(swap_device, *head, TAKE_PTR(swap)); } return 0; } -static int swap_points_list_off(MountPoint **head, bool *changed) { +static int swap_points_list_off(SwapDevice **head, bool *changed) { int n_failed = 0; assert(head); assert(changed); - LIST_FOREACH(mount_point, m, *head) { + 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); @@ -71,14 +88,14 @@ static int swap_points_list_off(MountPoint **head, bool *changed) { } *changed = true; - mount_point_free(head, m); + swap_device_free(head, m); } return n_failed; } int swapoff_all(bool *changed) { - _cleanup_(mount_points_list_free) LIST_HEAD(MountPoint, swap_list_head); + _cleanup_(swap_devices_list_free) LIST_HEAD(SwapDevice, swap_list_head); int r; assert(changed); diff --git a/src/shutdown/detach-swap.h b/src/shutdown/detach-swap.h index 7c2b97f773..1ebf5eb908 100644 --- a/src/shutdown/detach-swap.h +++ b/src/shutdown/detach-swap.h @@ -7,8 +7,15 @@ #include -#include "umount.h" +#include "list.h" int swapoff_all(bool *changed); -int swap_list_get(const char *swaps, MountPoint **head); +/* This is exported just for testing */ +typedef struct SwapDevice { + char *path; + LIST_FIELDS(struct SwapDevice, swap_device); +} SwapDevice; + +int swap_list_get(const char *swaps, SwapDevice **head); +void swap_devices_list_free(SwapDevice **head); diff --git a/src/shutdown/test-umount.c b/src/shutdown/test-umount.c index 36036dd375..d74cd878c6 100644 --- a/src/shutdown/test-umount.c +++ b/src/shutdown/test-umount.c @@ -40,7 +40,7 @@ TEST(mount_points_list) { } static void test_swap_list_one(const char *fname) { - _cleanup_(mount_points_list_free) LIST_HEAD(MountPoint, mp_list_head); + _cleanup_(swap_devices_list_free) LIST_HEAD(SwapDevice, sd_list_head); _cleanup_free_ char *testdata_fname = NULL; int r; @@ -51,19 +51,14 @@ static void test_swap_list_one(const char *fname) { fname = testdata_fname; } - LIST_HEAD_INIT(mp_list_head); - r = swap_list_get(fname, &mp_list_head); + LIST_HEAD_INIT(sd_list_head); + r = swap_list_get(fname, &sd_list_head); if (ERRNO_IS_PRIVILEGE(r)) return; assert_se(r >= 0); - LIST_FOREACH(mount_point, m, mp_list_head) - log_debug("path=%s o=%s f=0x%lx try-ro=%s dev=%u:%u", - m->path, - strempty(m->remount_options), - m->remount_flags, - yes_no(m->try_remount_ro), - major(m->devnum), minor(m->devnum)); + LIST_FOREACH(swap_device, m, sd_list_head) + log_debug("path=%s", m->path); } TEST(swap_list) { From 015937f901a383c8ff72a2161584fd347d7bea6c Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 2 Jun 2023 10:54:03 +0200 Subject: [PATCH 06/12] detach-dm: decouple from umount.[ch] Let's also define our own little structure here with just the fields we need. --- src/shutdown/detach-dm.c | 44 ++++++++++++++++++++++++++++++---------- 1 file changed, 33 insertions(+), 11 deletions(-) diff --git a/src/shutdown/detach-dm.c b/src/shutdown/detach-dm.c index 8a6408e4d2..bfb591ede5 100644 --- a/src/shutdown/detach-dm.c +++ b/src/shutdown/detach-dm.c @@ -16,9 +16,31 @@ #include "errno-util.h" #include "fd-util.h" #include "sync-util.h" -#include "umount.h" -static int dm_list_get(MountPoint **head) { +typedef struct DeviceMapper { + char *path; + dev_t devnum; + LIST_FIELDS(struct DeviceMapper, device_mapper); +} DeviceMapper; + +static void device_mapper_free(DeviceMapper **head, DeviceMapper *m) { + assert(head); + assert(m); + + LIST_REMOVE(device_mapper, *head, m); + + free(m->path); + free(m); +} + +static void device_mapper_list_free(DeviceMapper **head) { + assert(head); + + while (*head) + device_mapper_free(head, *head); +} + +static int dm_list_get(DeviceMapper **head) { _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL; sd_device *d; int r; @@ -44,7 +66,7 @@ static int dm_list_get(MountPoint **head) { FOREACH_DEVICE(e, d) { _cleanup_free_ char *p = NULL; const char *dn; - MountPoint *m; + DeviceMapper *m; dev_t devnum; if (sd_device_get_devnum(d, &devnum) < 0 || @@ -55,22 +77,22 @@ static int dm_list_get(MountPoint **head) { if (!p) return -ENOMEM; - m = new(MountPoint, 1); + m = new(DeviceMapper, 1); if (!m) return -ENOMEM; - *m = (MountPoint) { + *m = (DeviceMapper) { .path = TAKE_PTR(p), .devnum = devnum, }; - LIST_PREPEND(mount_point, *head, m); + LIST_PREPEND(device_mapper, *head, m); } return 0; } -static int delete_dm(MountPoint *m) { +static int delete_dm(DeviceMapper *m) { _cleanup_close_ int fd = -EBADF; int r; @@ -97,7 +119,7 @@ static int delete_dm(MountPoint *m) { })); } -static int dm_points_list_detach(MountPoint **head, bool *changed, bool last_try) { +static int dm_points_list_detach(DeviceMapper **head, bool *changed, bool last_try) { int n_failed = 0, r; dev_t rootdev = 0; @@ -106,7 +128,7 @@ static int dm_points_list_detach(MountPoint **head, bool *changed, bool last_try (void) get_block_device("/", &rootdev); - LIST_FOREACH(mount_point, m, *head) { + LIST_FOREACH(device_mapper, m, *head) { if (major(rootdev) != 0 && rootdev == m->devnum) { n_failed ++; continue; @@ -121,14 +143,14 @@ static int dm_points_list_detach(MountPoint **head, bool *changed, bool last_try } *changed = true; - mount_point_free(head, m); + device_mapper_free(head, m); } return n_failed; } int dm_detach_all(bool *changed, bool last_try) { - _cleanup_(mount_points_list_free) LIST_HEAD(MountPoint, dm_list_head); + _cleanup_(device_mapper_list_free) LIST_HEAD(DeviceMapper, dm_list_head); int r; assert(changed); From 6514a6fd829fc9aa49db05cc2ffcdf5f197927c9 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 2 Jun 2023 10:57:10 +0200 Subject: [PATCH 07/12] detach-md: also decouple structures from umount.h --- src/shutdown/detach-md.c | 44 ++++++++++++++++++++++++++++++---------- 1 file changed, 33 insertions(+), 11 deletions(-) diff --git a/src/shutdown/detach-md.c b/src/shutdown/detach-md.c index aff20e5342..d5188ea822 100644 --- a/src/shutdown/detach-md.c +++ b/src/shutdown/detach-md.c @@ -18,9 +18,31 @@ #include "errno-util.h" #include "fd-util.h" #include "string-util.h" -#include "umount.h" -static int md_list_get(MountPoint **head) { +typedef struct RaidDevice { + char *path; + dev_t devnum; + LIST_FIELDS(struct RaidDevice, raid_device); +} RaidDevice; + +static void raid_device_free(RaidDevice **head, RaidDevice *m) { + assert(head); + assert(m); + + LIST_REMOVE(raid_device, *head, m); + + free(m->path); + free(m); +} + +static void raid_device_list_free(RaidDevice **head) { + assert(head); + + while (*head) + raid_device_free(head, *head); +} + +static int md_list_get(RaidDevice **head) { _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL; sd_device *d; int r; @@ -51,7 +73,7 @@ static int md_list_get(MountPoint **head) { FOREACH_DEVICE(e, d) { _cleanup_free_ char *p = NULL; const char *dn, *md_level; - MountPoint *m; + RaidDevice *m; dev_t devnum; if (sd_device_get_devnum(d, &devnum) < 0 || @@ -73,22 +95,22 @@ static int md_list_get(MountPoint **head) { if (!p) return -ENOMEM; - m = new(MountPoint, 1); + m = new(RaidDevice, 1); if (!m) return -ENOMEM; - *m = (MountPoint) { + *m = (RaidDevice) { .path = TAKE_PTR(p), .devnum = devnum, }; - LIST_PREPEND(mount_point, *head, m); + LIST_PREPEND(raid_device, *head, m); } return 0; } -static int delete_md(MountPoint *m) { +static int delete_md(RaidDevice *m) { _cleanup_close_ int fd = -EBADF; assert(m); @@ -105,7 +127,7 @@ static int delete_md(MountPoint *m) { return RET_NERRNO(ioctl(fd, STOP_ARRAY, NULL)); } -static int md_points_list_detach(MountPoint **head, bool *changed, bool last_try) { +static int md_points_list_detach(RaidDevice **head, bool *changed, bool last_try) { int n_failed = 0, r; dev_t rootdev = 0; @@ -114,7 +136,7 @@ static int md_points_list_detach(MountPoint **head, bool *changed, bool last_try (void) get_block_device("/", &rootdev); - LIST_FOREACH(mount_point, m, *head) { + LIST_FOREACH(raid_device, m, *head) { if (major(rootdev) != 0 && rootdev == m->devnum) { n_failed ++; continue; @@ -129,14 +151,14 @@ static int md_points_list_detach(MountPoint **head, bool *changed, bool last_try } *changed = true; - mount_point_free(head, m); + raid_device_free(head, m); } return n_failed; } int md_detach_all(bool *changed, bool last_try) { - _cleanup_(mount_points_list_free) LIST_HEAD(MountPoint, md_list_head); + _cleanup_(raid_device_list_free) LIST_HEAD(RaidDevice, md_list_head); int r; assert(changed); From f5fcacdf2cb1dee456f7e5ae698caa3aaa1677b8 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 2 Jun 2023 11:02:16 +0200 Subject: [PATCH 08/12] detach-loopback: also decouple from umount.h Let's introduce LoopbackDevice as replacement for MountPoint, with just the fields we actually need. --- src/shutdown/detach-loopback.c | 42 ++++++++++++++++++++++++++-------- src/shutdown/test-umount.c | 5 ++-- src/shutdown/umount.c | 2 +- src/shutdown/umount.h | 4 ++-- 4 files changed, 37 insertions(+), 16 deletions(-) diff --git a/src/shutdown/detach-loopback.c b/src/shutdown/detach-loopback.c index 49150077d6..ceac74223c 100644 --- a/src/shutdown/detach-loopback.c +++ b/src/shutdown/detach-loopback.c @@ -18,9 +18,31 @@ #include "detach-loopback.h" #include "device-util.h" #include "fd-util.h" -#include "umount.h" -static int loopback_list_get(MountPoint **head) { +typedef struct LoopbackDevice { + char *path; + dev_t devnum; + LIST_FIELDS(struct LoopbackDevice, loopback_device); +} LoopbackDevice; + +static void loopback_device_free(LoopbackDevice **head, LoopbackDevice *m) { + assert(head); + assert(m); + + LIST_REMOVE(loopback_device, *head, m); + + free(m->path); + free(m); +} + +static void loopback_device_list_free(LoopbackDevice **head) { + assert(head); + + while (*head) + loopback_device_free(head, *head); +} + +static int loopback_list_get(LoopbackDevice **head) { _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL; sd_device *d; int r; @@ -50,7 +72,7 @@ static int loopback_list_get(MountPoint **head) { FOREACH_DEVICE(e, d) { _cleanup_free_ char *p = NULL; const char *dn; - MountPoint *lb; + LoopbackDevice *lb; dev_t devnum; if (sd_device_get_devnum(d, &devnum) < 0 || @@ -61,16 +83,16 @@ static int loopback_list_get(MountPoint **head) { if (!p) return -ENOMEM; - lb = new(MountPoint, 1); + lb = new(LoopbackDevice, 1); if (!lb) return -ENOMEM; - *lb = (MountPoint) { + *lb = (LoopbackDevice) { .path = TAKE_PTR(p), .devnum = devnum, }; - LIST_PREPEND(mount_point, *head, lb); + LIST_PREPEND(loopback_device, *head, lb); } return 0; @@ -151,7 +173,7 @@ static int delete_loopback(const char *device) { return -EBUSY; /* Nothing changed, the device is still attached, hence it apparently is still busy */ } -static int loopback_points_list_detach(MountPoint **head, bool *changed, bool last_try) { +static int loopback_points_list_detach(LoopbackDevice **head, bool *changed, bool last_try) { int n_failed = 0, r; dev_t rootdev = 0; @@ -160,7 +182,7 @@ static int loopback_points_list_detach(MountPoint **head, bool *changed, bool la (void) get_block_device("/", &rootdev); - LIST_FOREACH(mount_point, m, *head) { + LIST_FOREACH(loopback_device, m, *head) { if (major(rootdev) != 0 && rootdev == m->devnum) { n_failed++; continue; @@ -176,14 +198,14 @@ static int loopback_points_list_detach(MountPoint **head, bool *changed, bool la if (r > 0) *changed = true; - mount_point_free(head, m); + loopback_device_free(head, m); } return n_failed; } int loopback_detach_all(bool *changed, bool last_try) { - _cleanup_(mount_points_list_free) LIST_HEAD(MountPoint, loopback_list_head); + _cleanup_(loopback_device_list_free) LIST_HEAD(LoopbackDevice, loopback_list_head); int r; assert(changed); diff --git a/src/shutdown/test-umount.c b/src/shutdown/test-umount.c index d74cd878c6..93da2e0fc3 100644 --- a/src/shutdown/test-umount.c +++ b/src/shutdown/test-umount.c @@ -24,12 +24,11 @@ static void test_mount_points_list_one(const char *fname) { assert_se(mount_points_list_get(fname, &mp_list_head) >= 0); LIST_FOREACH(mount_point, m, mp_list_head) - log_debug("path=%s o=%s f=0x%lx try-ro=%s dev=%u:%u", + log_debug("path=%s o=%s f=0x%lx try-ro=%s", m->path, strempty(m->remount_options), m->remount_flags, - yes_no(m->try_remount_ro), - major(m->devnum), minor(m->devnum)); + yes_no(m->try_remount_ro)); } TEST(mount_points_list) { diff --git a/src/shutdown/umount.c b/src/shutdown/umount.c index 05f7b5b513..6cbe2befa2 100644 --- a/src/shutdown/umount.c +++ b/src/shutdown/umount.c @@ -29,7 +29,7 @@ #include "umount.h" #include "virt.h" -void mount_point_free(MountPoint **head, MountPoint *m) { +static void mount_point_free(MountPoint **head, MountPoint *m) { assert(head); assert(m); diff --git a/src/shutdown/umount.h b/src/shutdown/umount.h index eeda7f8ad9..f8f9ae8038 100644 --- a/src/shutdown/umount.h +++ b/src/shutdown/umount.h @@ -5,6 +5,8 @@ Copyright © 2010 ProFUSION embedded systems ***/ +#include + #include "list.h" int umount_all(bool *changed, bool last_try); @@ -17,10 +19,8 @@ typedef struct MountPoint { bool try_remount_ro; bool umount_lazily; bool leaf; - dev_t devnum; LIST_FIELDS(struct MountPoint, mount_point); } MountPoint; int mount_points_list_get(const char *mountinfo, MountPoint **head); -void mount_point_free(MountPoint **head, MountPoint *m); void mount_points_list_free(MountPoint **head); From 31d346206cef3c6b280495fa93310f9790f9ef02 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 2 Jun 2023 11:08:07 +0200 Subject: [PATCH 09/12] shutdown: don't attempt to detach DM volume backing /usr/ Since we run off /usr/ it makes no sense to attempt to try to detach any DM device backing it. Hence skip it just like we skip detaching the DM device backing the root fs. Addresses: https://github.com/systemd/systemd/issues/27682#issuecomment-1573328188 --- src/shutdown/detach-dm.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/shutdown/detach-dm.c b/src/shutdown/detach-dm.c index bfb591ede5..71be74377d 100644 --- a/src/shutdown/detach-dm.c +++ b/src/shutdown/detach-dm.c @@ -121,15 +121,18 @@ static int delete_dm(DeviceMapper *m) { static int dm_points_list_detach(DeviceMapper **head, bool *changed, bool last_try) { int n_failed = 0, r; - dev_t rootdev = 0; + dev_t rootdev = 0, usrdev = 0; assert(head); assert(changed); (void) get_block_device("/", &rootdev); + (void) get_block_device("/usr", &usrdev); LIST_FOREACH(device_mapper, m, *head) { - if (major(rootdev) != 0 && rootdev == m->devnum) { + if ((major(rootdev) != 0 && rootdev == m->devnum) || + (major(usrdev) != 0 && usrdev == m->devnum)) { + log_debug("Not detaching DM %s that backs the OS itself, skipping.", m->path); n_failed ++; continue; } From 2067a7ec7f4c8a353b8e2ece15a6a997e50808b0 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 2 Jun 2023 11:41:40 +0200 Subject: [PATCH 10/12] detach-md: similar to the DM case, also don't try to detach MD device backing /usr/ --- src/shutdown/detach-md.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/shutdown/detach-md.c b/src/shutdown/detach-md.c index d5188ea822..ae592f6f31 100644 --- a/src/shutdown/detach-md.c +++ b/src/shutdown/detach-md.c @@ -129,15 +129,18 @@ static int delete_md(RaidDevice *m) { static int md_points_list_detach(RaidDevice **head, bool *changed, bool last_try) { int n_failed = 0, r; - dev_t rootdev = 0; + dev_t rootdev = 0, usrdev = 0; assert(head); assert(changed); (void) get_block_device("/", &rootdev); + (void) get_block_device("/usr", &usrdev); LIST_FOREACH(raid_device, m, *head) { - if (major(rootdev) != 0 && rootdev == m->devnum) { + if ((major(rootdev) != 0 && rootdev == m->devnum) || + (major(usrdev) != 0 && usrdev == m->devnum)) { + log_debug("Not detaching MD %s that backs the OS itself, skipping.", m->path); n_failed ++; continue; } From 9959797dbf2f14d4c7131e81e748f4081c9bbb9c Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 2 Jun 2023 11:42:08 +0200 Subject: [PATCH 11/12] detach-loopback: also don't bother detaching loopback block device /usr/ is running off While we are at it, let's also clean this up a bit: unlike DM/MD devices loopback devices are likely partitioned, hence trace the block device through the partition layer and LUKS. --- src/shutdown/detach-loopback.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/shutdown/detach-loopback.c b/src/shutdown/detach-loopback.c index ceac74223c..f45960856b 100644 --- a/src/shutdown/detach-loopback.c +++ b/src/shutdown/detach-loopback.c @@ -175,15 +175,21 @@ static int delete_loopback(const char *device) { static int loopback_points_list_detach(LoopbackDevice **head, bool *changed, bool last_try) { int n_failed = 0, r; - dev_t rootdev = 0; + dev_t rootdev = 0, usrdev = 0; assert(head); assert(changed); - (void) get_block_device("/", &rootdev); + (void) get_block_device_harder("/", &rootdev); + (void) block_get_whole_disk(rootdev, &rootdev); + + (void) get_block_device_harder("/usr", &usrdev); + (void) block_get_whole_disk(usrdev, &usrdev); LIST_FOREACH(loopback_device, m, *head) { - if (major(rootdev) != 0 && rootdev == m->devnum) { + if ((major(rootdev) != 0 && rootdev == m->devnum) || + (major(usrdev) != 0 && usrdev == m->devnum)) { + log_debug("Not detaching loopback device %s that backs the OS itself, skipping.", m->path); n_failed++; continue; } From 9dd2da5b720e32933e31b098be45cf52a16acf5f Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 2 Jun 2023 11:20:21 +0200 Subject: [PATCH 12/12] shutdown: tone down failure messages a bit If we are not able to detach all MD/DM/loopback devices this is not necessarily a failure, it's simply because we might be running off them. Hence let's tone down our language a bit, and just say "Unable to" rather than "Failed to". --- src/shutdown/shutdown.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/shutdown/shutdown.c b/src/shutdown/shutdown.c index b742732bb1..08cc114d3a 100644 --- a/src/shutdown/shutdown.c +++ b/src/shutdown/shutdown.c @@ -452,7 +452,7 @@ int main(int argc, char *argv[]) { } else if (r > 0) log_info("Not all file systems unmounted, %d left.", r); else - log_error_errno(r, "Failed to unmount file systems: %m"); + log_error_errno(r, "Unable to unmount file systems: %m"); } if (need_swapoff) { @@ -464,7 +464,7 @@ int main(int argc, char *argv[]) { } else if (r > 0) log_info("Not all swaps deactivated, %d left.", r); else - log_error_errno(r, "Failed to deactivate swaps: %m"); + log_error_errno(r, "Unable to deactivate swaps: %m"); } if (need_loop_detach) { @@ -476,7 +476,7 @@ int main(int argc, char *argv[]) { } else if (r > 0) log_info("Not all loop devices detached, %d left.", r); else - log_error_errno(r, "Failed to detach loop devices: %m"); + log_error_errno(r, "Unable to detach loop devices: %m"); } if (need_md_detach) { @@ -488,7 +488,7 @@ int main(int argc, char *argv[]) { } else if (r > 0) log_info("Not all MD devices stopped, %d left.", r); else - log_error_errno(r, "Failed to stop MD devices: %m"); + log_error_errno(r, "Unable to stop MD devices: %m"); } if (need_dm_detach) { @@ -500,7 +500,7 @@ int main(int argc, char *argv[]) { } else if (r > 0) log_info("Not all DM devices detached, %d left.", r); else - log_error_errno(r, "Failed to detach DM devices: %m"); + log_error_errno(r, "Unable to detach DM devices: %m"); } if (!need_umount && !need_swapoff && !need_loop_detach && !need_dm_detach @@ -567,7 +567,7 @@ int main(int argc, char *argv[]) { } if (need_umount || need_swapoff || need_loop_detach || need_dm_detach || need_md_detach) - log_error("Failed to finalize%s%s%s%s%s ignoring.", + log_error("Unable to finalize remaining%s%s%s%s%s ignoring.", need_umount ? " file systems," : "", need_swapoff ? " swap devices," : "", need_loop_detach ? " loop devices," : "",