From: Linus Torvalds Date: Mon, 9 Feb 2026 21:41:34 +0000 (-0800) Subject: Merge tag 'vfs-7.0-rc1.nullfs' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=c84bb79f70c634a95929f21c14340ab2078d7977;p=thirdparty%2Fkernel%2Flinux.git Merge tag 'vfs-7.0-rc1.nullfs' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs Pull vfs nullfs update from Christian Brauner: "Add a completely catatonic minimal pseudo filesystem called "nullfs" and make pivot_root() work in the initramfs. Currently pivot_root() does not work on the real rootfs because it cannot be unmounted. Userspace has to recursively delete initramfs contents manually before continuing boot, using the fragile switch_root sequence (overmount + chroot). Add nullfs, a minimal immutable filesystem that serves as the true root of the mount hierarchy. The mutable rootfs (tmpfs/ramfs) is mounted on top of it. This allows userspace to simply: chdir(new_root); pivot_root(".", "."); umount2(".", MNT_DETACH); without the traditional switch_root workarounds. systemd already handles this correctly. It tries pivot_root() first and falls back to MS_MOVE only when that fails. This also means rootfs mounts in unprivileged namespaces no longer need MNT_LOCKED, since the immutable nullfs guarantees nothing can be revealed by unmounting the covering mount. nullfs is a single-instance filesystem (get_tree_single()) marked SB_NOUSER | SB_I_NOEXEC | SB_I_NODEV with an immutable empty root directory. This means sooner or later it can be used to overmount other directories to hide their contents without any additional protection needed. We enable it unconditionally. If we see any real regression we'll hide it behind a boot option. nullfs has extensions beyond this in the future. It will serve as a concept to support the creation of completely empty mount namespaces - which is work coming up in the next cycle" * tag 'vfs-7.0-rc1.nullfs' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs: fs: use nullfs unconditionally as the real rootfs docs: mention nullfs fs: add immutable rootfs fs: add init_pivot_root() fs: ensure that internal tmpfs mount gets mount id zero --- c84bb79f70c634a95929f21c14340ab2078d7977 diff --cc fs/Makefile index f238cc5ea2e9d,becf133e4791c..cf4a745e96798 --- a/fs/Makefile +++ b/fs/Makefile @@@ -16,7 -16,7 +16,7 @@@ obj-y := open.o read_write.o file_table stack.o fs_struct.o statfs.o fs_pin.o nsfs.o \ fs_dirent.o fs_context.o fs_parser.o fsopen.o init.o \ kernel_read_file.o mnt_idmapping.o remap_range.o pidfs.o \ - file_attr.o fserror.o - file_attr.o nullfs.o ++ file_attr.o fserror.o nullfs.o obj-$(CONFIG_BUFFER_HEAD) += buffer.o mpage.o obj-$(CONFIG_PROC_FS) += proc_namespace.o diff --cc init/do_mounts.c index 9c8a547075a7b,df6847bcf1f25..55ed3ac0b70fd --- a/init/do_mounts.c +++ b/init/do_mounts.c @@@ -482,9 -490,18 +482,17 @@@ void __init prepare_namespace(void if (root_wait) wait_for_root(saved_root_name); mount_root(saved_root_name); -out: devtmpfs_mount(); - init_mount(".", "/", NULL, MS_MOVE, NULL); - init_chroot("."); + + if (init_pivot_root(".", ".")) { + pr_err("VFS: Failed to pivot into new rootfs\n"); + return; + } + if (init_umount(".", MNT_DETACH)) { + pr_err("VFS: Failed to unmount old rootfs\n"); + return; + } + pr_info("VFS: Pivoted into new rootfs\n"); } static bool is_tmpfs;