summaryrefslogtreecommitdiff
path: root/src/shared
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2023-05-03 17:17:35 +0200
committerLuca Boccassi <luca.boccassi@gmail.com>2023-05-03 20:52:19 +0100
commitea0f3289a288affd5f13c83849b984c8fad63e90 (patch)
treef8e8d64a945e5525053e4fc650b91310f4ab6c72 /src/shared
parent64ff6ad494477e4ad87fb02335db5ff17bd21d07 (diff)
downloadsystemd-ea0f3289a288affd5f13c83849b984c8fad63e90.tar.gz
mount-util: simplify mount_switch_root() a bit
There's no need to fchdir() out of the rootfs and back into it around the umount2(), hence don't. This brings the logic closer to what the pivot_root() man page suggests. While we are at it, always operate based on fds, once we opened the original dir, and pass the path string along only for generating messages (i.e. as "decoration"). Add tests for both code paths: the pivot_root() one and the MS_MOUNT.
Diffstat (limited to 'src/shared')
-rw-r--r--src/shared/mount-util.c69
-rw-r--r--src/shared/mount-util.h5
2 files changed, 37 insertions, 37 deletions
diff --git a/src/shared/mount-util.c b/src/shared/mount-util.c
index f30b5f1a7f..b41672eb92 100644
--- a/src/shared/mount-util.c
+++ b/src/shared/mount-util.c
@@ -431,50 +431,46 @@ int bind_remount_one_with_mountinfo(
return 0;
}
-static int mount_switch_root_pivot(const char *path, int fd_newroot) {
- _cleanup_close_ int fd_oldroot = -EBADF;
+static int mount_switch_root_pivot(int fd_newroot, const char *path) {
+ assert(fd_newroot >= 0);
+ assert(path);
- fd_oldroot = open("/", O_PATH|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW);
- if (fd_oldroot < 0)
- return log_debug_errno(errno, "Failed to open old rootfs");
+ /* Change into the new rootfs. */
+ if (fchdir(fd_newroot) < 0)
+ return log_debug_errno(errno, "Failed to change into new rootfs '%s': %m", path);
/* Let the kernel tuck the new root under the old one. */
if (pivot_root(".", ".") < 0)
return log_debug_errno(errno, "Failed to pivot root to new rootfs '%s': %m", path);
- /* At this point the new root is tucked under the old root. If we want
- * to unmount it we cannot be fchdir()ed into it. So escape back to the
- * old root. */
- if (fchdir(fd_oldroot) < 0)
- return log_debug_errno(errno, "Failed to change back to old rootfs: %m");
-
- /* Note, usually we should set mount propagation up here but we'll
- * assume that the caller has already done that. */
-
- /* Get rid of the old root and reveal our brand new root. */
+ /* Get rid of the old root and reveal our brand new root. (This will always operate on the top-most
+ * mount on our cwd, regardless what our current directory actually points to.) */
if (umount2(".", MNT_DETACH) < 0)
return log_debug_errno(errno, "Failed to unmount old rootfs: %m");
- if (fchdir(fd_newroot) < 0)
- return log_debug_errno(errno, "Failed to switch to new rootfs '%s': %m", path);
-
return 0;
}
-static int mount_switch_root_move(const char *path) {
- if (mount(path, "/", NULL, MS_MOVE, NULL) < 0)
+static int mount_switch_root_move(int fd_newroot, const char *path) {
+ assert(fd_newroot >= 0);
+ assert(path);
+
+ /* Change into the new rootfs. */
+ if (fchdir(fd_newroot) < 0)
+ return log_debug_errno(errno, "Failed to change into new rootfs '%s': %m", path);
+
+ /* Move the new root fs */
+ if (mount(".", "/", NULL, MS_MOVE, NULL) < 0)
return log_debug_errno(errno, "Failed to move new rootfs '%s': %m", path);
+ /* Also change chroot dir */
if (chroot(".") < 0)
return log_debug_errno(errno, "Failed to chroot to new rootfs '%s': %m", path);
- if (chdir("/"))
- return log_debug_errno(errno, "Failed to chdir to new rootfs '%s': %m", path);
-
return 0;
}
-int mount_switch_root(const char *path, unsigned long mount_propagation_flag) {
+int mount_switch_root_full(const char *path, unsigned long mount_propagation_flag, bool force_ms_move) {
_cleanup_close_ int fd_newroot = -EBADF;
int r;
@@ -485,19 +481,20 @@ int mount_switch_root(const char *path, unsigned long mount_propagation_flag) {
if (fd_newroot < 0)
return log_debug_errno(errno, "Failed to open new rootfs '%s': %m", path);
- /* Change into the new rootfs. */
- if (fchdir(fd_newroot) < 0)
- return log_debug_errno(errno, "Failed to change into new rootfs '%s': %m", path);
-
- r = mount_switch_root_pivot(path, fd_newroot);
- if (r < 0) {
- /* Failed to pivot_root() fallback to MS_MOVE. For example, this may happen if the
- * rootfs is an initramfs in which case pivot_root() isn't supported. */
- log_debug_errno(r, "Failed to pivot into new rootfs '%s': %m", path);
- r = mount_switch_root_move(path);
+ if (!force_ms_move) {
+ r = mount_switch_root_pivot(fd_newroot, path);
+ if (r < 0) {
+ log_debug_errno(r, "Failed to pivot into new rootfs '%s', will try to use MS_MOVE instead: %m", path);
+ force_ms_move = true;
+ }
+ }
+ if (force_ms_move) {
+ /* Failed to pivot_root() fallback to MS_MOVE. For example, this may happen if the rootfs is
+ * an initramfs in which case pivot_root() isn't supported. */
+ r = mount_switch_root_move(fd_newroot, path);
+ if (r < 0)
+ return log_debug_errno(r, "Failed to switch to new rootfs '%s' with MS_MOVE: %m", path);
}
- if (r < 0)
- return log_debug_errno(r, "Failed to switch to new rootfs '%s': %m", path);
/* Finally, let's establish the requested propagation flags. */
if (mount_propagation_flag == 0)
diff --git a/src/shared/mount-util.h b/src/shared/mount-util.h
index d1defcd8be..d63fddeb10 100644
--- a/src/shared/mount-util.h
+++ b/src/shared/mount-util.h
@@ -21,7 +21,10 @@ static inline int bind_remount_recursive(const char *prefix, unsigned long new_f
int bind_remount_one_with_mountinfo(const char *path, unsigned long new_flags, unsigned long flags_mask, FILE *proc_self_mountinfo);
-int mount_switch_root(const char *path, unsigned long mount_propagation_flag);
+int mount_switch_root_full(const char *path, unsigned long mount_propagation_flag, bool force_ms_move);
+static inline int mount_switch_root(const char *path, unsigned long mount_propagation_flag) {
+ return mount_switch_root_full(path, mount_propagation_flag, false);
+}
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(FILE*, endmntent, NULL);
#define _cleanup_endmntent_ _cleanup_(endmntentp)