1
0
mirror of https://github.com/systemd/systemd.git synced 2025-03-22 06:50:18 +03:00

Merge pull request #28793 from poettering/switch-root-flags-tweak

various switch-root tweaks/fixes
This commit is contained in:
Mike Yuan 2023-09-03 11:18:18 +08:00 committed by GitHub
commit 62f643a34d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 29 additions and 26 deletions

View File

@ -1891,7 +1891,7 @@ static int do_reexecute(
r = switch_root(/* new_root= */ switch_root_dir,
/* old_root_after= */ NULL,
/* flags= */ (objective == MANAGER_SWITCH_ROOT ? SWITCH_ROOT_DESTROY_OLD_ROOT : 0) |
(objective == MANAGER_SOFT_REBOOT ? SWITCH_ROOT_SKIP_RECURSIVE_RUN : 0));
(objective == MANAGER_SOFT_REBOOT ? 0 : SWITCH_ROOT_RECURSIVE_RUN));
if (r < 0)
log_error_errno(r, "Failed to switch root, trying to continue: %m");
}

View File

@ -30,23 +30,22 @@ int switch_root(const char *new_root,
const char *old_root_after, /* path below the new root, where to place the old root after the transition; may be NULL to unmount it */
SwitchRootFlags flags) {
/* Stuff mounted below /run we don't save on soft reboot, as it might have lost its relevance, i.e.
* credentials, removable media and such, we rather want that the new boot mounts this fresh.
* But on the switch from initrd we do use MS_REC, as it is expected that mounts set up in /run
* are maintained. */
unsigned long run_mount_flags = MS_BIND|(!FLAGS_SET(flags, SWITCH_ROOT_SKIP_RECURSIVE_RUN) ? MS_REC : 0);
struct {
/* Stuff mounted below /run/ we don't save on soft reboot, as it might have lost its relevance, i.e.
* credentials, removable media and such, we rather want that the new boot mounts this fresh. But on
* the switch from initrd we do use MS_REC, as it is expected that mounts set up in /run/ are
* maintained. */
static const struct {
const char *path;
unsigned long mount_flags;
bool skip_if_run_is_rec; /* For child mounts of /run, if it's moved recursively no need to handle */
unsigned long mount_flags; /* Flags to apply if SWITCH_ROOT_RECURSIVE_RUN is unset */
unsigned long mount_flags_recursive_run; /* Flags to apply if SWITCH_ROOT_RECURSIVE_RUN is set (0 if shall be skipped) */
} transfer_table[] = {
{ "/dev", MS_BIND|MS_REC, false }, /* Recursive, because we want to save the original /dev/shm + /dev/pts and similar */
{ "/sys", MS_BIND|MS_REC, false }, /* Similar, we want to retain various API VFS, or the cgroupv1 /sys/fs/cgroup/ tree */
{ "/proc", MS_BIND|MS_REC, false }, /* Similar */
{ "/run", run_mount_flags, false }, /* Recursive except on soft reboot, see above */
{ SYSTEM_CREDENTIALS_DIRECTORY, MS_BIND, true }, /* Credentials passed into the system should survive */
{ ENCRYPTED_SYSTEM_CREDENTIALS_DIRECTORY, MS_BIND, true }, /* Similar */
{ "/run/host", MS_BIND|MS_REC, true }, /* Host supplied hierarchy should also survive */
{ "/dev", MS_BIND|MS_REC, MS_BIND|MS_REC }, /* Recursive, because we want to save the original /dev/shm/ + /dev/pts/ and similar */
{ "/sys", MS_BIND|MS_REC, MS_BIND|MS_REC }, /* Similar, we want to retain various API VFS, or the cgroupv1 /sys/fs/cgroup/ tree */
{ "/proc", MS_BIND|MS_REC, MS_BIND|MS_REC }, /* Similar */
{ "/run", MS_BIND, MS_BIND|MS_REC }, /* Recursive except on soft reboot, see above */
{ SYSTEM_CREDENTIALS_DIRECTORY, MS_BIND, 0 /* skip! */ }, /* Credentials passed into the system should survive */
{ ENCRYPTED_SYSTEM_CREDENTIALS_DIRECTORY, MS_BIND, 0 /* skip! */ }, /* Similar */
{ "/run/host", MS_BIND|MS_REC, 0 /* skip! */ }, /* Host supplied hierarchy should also survive */
};
_cleanup_close_ int old_root_fd = -EBADF, new_root_fd = -EBADF;
@ -129,8 +128,10 @@ int switch_root(const char *new_root,
FOREACH_ARRAY(transfer, transfer_table, ELEMENTSOF(transfer_table)) {
_cleanup_free_ char *chased = NULL;
unsigned long mount_flags;
if (transfer->skip_if_run_is_rec && !FLAGS_SET(flags, SWITCH_ROOT_SKIP_RECURSIVE_RUN))
mount_flags = FLAGS_SET(flags, SWITCH_ROOT_RECURSIVE_RUN) ? transfer->mount_flags_recursive_run : transfer->mount_flags;
if (mount_flags == 0) /* skip if zero */
continue;
if (access(transfer->path, F_OK) < 0) {
@ -149,7 +150,7 @@ int switch_root(const char *new_root,
if (r > 0) /* If it is already mounted, then do nothing */
continue;
r = mount_nofollow_verbose(LOG_ERR, transfer->path, chased, NULL, transfer->mount_flags, NULL);
r = mount_nofollow_verbose(LOG_ERR, transfer->path, chased, NULL, mount_flags, NULL);
if (r < 0)
return r;
}
@ -172,14 +173,19 @@ int switch_root(const char *new_root,
if (r < 0) {
log_debug_errno(r, "Pivoting root file system failed, moving mounts instead: %m");
if (resolved_old_root_after) {
r = mount_nofollow_verbose(LOG_ERR, "/", resolved_old_root_after, NULL, MS_BIND|MS_REC, NULL);
if (r < 0)
return r;
}
/* If we have to use MS_MOVE let's first try to get rid of *all* mounts we can, with the
* exception of the path we want to switch to, plus everything leading to it and within
* it. This is necessary because unlike pivot_root() just moving the mount to the root via
* MS_MOVE won't magically unmount anything below it. Once the chroot() succeeds the mounts
* below would still be around but invisible to us, because not accessible via
* /proc/self/mountinfo. Hence, let's clean everything up first, as long as we still can. */
if (!FLAGS_SET(flags, SWITCH_ROOT_SKIP_RECURSIVE_UMOUNT))
(void) umount_recursive_full(NULL, MNT_DETACH, STRV_MAKE(new_root));
(void) umount_recursive_full(NULL, MNT_DETACH, STRV_MAKE(new_root));
if (mount(".", "/", NULL, MS_MOVE, NULL) < 0)
return log_error_errno(errno, "Failed to move %s to /: %m", new_root);

View File

@ -7,8 +7,7 @@ typedef enum SwitchRootFlags {
SWITCH_ROOT_DESTROY_OLD_ROOT = 1 << 0, /* rm -rf old root when switching under the condition
* that it is backed by non-persistent tmpfs/ramfs/ */
SWITCH_ROOT_DONT_SYNC = 1 << 1, /* don't call sync() immediately before switching root */
SWITCH_ROOT_SKIP_RECURSIVE_RUN = 1 << 2, /* move /run without MS_REC */
SWITCH_ROOT_SKIP_RECURSIVE_UMOUNT = 1 << 3, /* do not umount recursively on move */
SWITCH_ROOT_RECURSIVE_RUN = 1 << 2, /* move /run/ with MS_REC from old to new root */
} SwitchRootFlags;
int switch_root(const char *new_root, const char *old_root_after, SwitchRootFlags flags);

View File

@ -169,13 +169,11 @@ static int switch_root_initramfs(void) {
* Disable sync() during switch-root, we after all sync'ed here plenty, and a dumb sync (as opposed
* to the "smart" sync() we did here that looks at progress parameters) would defeat much of our
* efforts here. As the new root will be /run/initramfs/, it is not necessary to mount /run/
* recursively. Also, do not umount filesystems before MS_MOVE, as that should be done by ourself. */
* recursively. */
return switch_root(
/* new_root= */ "/run/initramfs",
/* old_root_after= */ "/oldroot",
/* flags= */ SWITCH_ROOT_DONT_SYNC |
SWITCH_ROOT_SKIP_RECURSIVE_RUN |
SWITCH_ROOT_SKIP_RECURSIVE_UMOUNT);
/* flags= */ SWITCH_ROOT_DONT_SYNC);
}
/* Read the following fields from /proc/meminfo: