From: Lennart Poettering Date: Fri, 2 Jan 2026 15:30:58 +0000 (+0100) Subject: switch-root: don't do rm_rf() of old superblock on switch root if pivot_root() worked X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=82dea1c9254a59fac8f304a262ad086cd51724b8;p=thirdparty%2Fsystemd.git switch-root: don't do rm_rf() of old superblock on switch root if pivot_root() worked We do the rm_rf_children() call only because in some cases we cannot pivot_root() and hence the orginal root superblock stays pinned, and we thus have to empty it to minimize its memory use. But if pivot_root() worked (and the umount() for the old root), then there's really no need to do this work. Dropping this codepath is useful in context of Christian's recent work to make the original initrd tmpfs unmountable, which means pivot_root() will work, and thus there's no need to empty the tmpfs anymore, and we can speed up boot a bit. Fixes: #40250 --- diff --git a/src/shared/switch-root.c b/src/shared/switch-root.c index d5f34c5d37d..6017200d79c 100644 --- a/src/shared/switch-root.c +++ b/src/shared/switch-root.c @@ -54,7 +54,7 @@ int switch_root(const char *new_root, if (new_root_fd < 0) return log_error_errno(errno, "Failed to open target directory '%s': %m", new_root); - r = fds_are_same_mount(old_root_fd, new_root_fd); + r = fds_are_same_mount(old_root_fd, new_root_fd); /* checks if referenced inodes and mounts match */ if (r < 0) return log_error_errno(r, "Failed to check if old and new root directory/mount are the same: %m"); if (r > 0) { @@ -186,18 +186,23 @@ int switch_root(const char *new_root, if (chdir(".") < 0) return log_error_errno(errno, "Failed to change directory: %m"); - } - if (istmp > 0) { - struct stat rb; + /* Now empty the old root superblock */ + if (istmp > 0) { + struct stat rb; - if (fstat(old_root_fd, &rb) < 0) - return log_error_errno(errno, "Failed to stat old root directory: %m"); + if (fstat(old_root_fd, &rb) < 0) + return log_error_errno(errno, "Failed to stat old root directory: %m"); - /* Note: the below won't operate on non-memory file systems (i.e. only on tmpfs, ramfs), and - * it will stop at mount boundaries */ - (void) rm_rf_children(TAKE_FD(old_root_fd), 0, &rb); /* takes possession of the dir fd, even on failure */ - } + /* Note: the below won't operate on non-memory file systems (i.e. only on tmpfs, ramfs), and + * it will stop at mount boundaries */ + (void) rm_rf_children(TAKE_FD(old_root_fd), 0, &rb); /* takes possession of the dir fd, even on failure */ + } + } else + /* NB: we don't bother with emptying the old root superblock here, under the assumption the + * pivot_root() + umount() sufficiently detached from the superblock to the point we don't + * need to empty it anymore */ + log_debug("Pivoting root worked."); return 0; }