]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
fs: use nullfs unconditionally as the real rootfs
authorChristian Brauner <brauner@kernel.org>
Wed, 14 Jan 2026 10:22:54 +0000 (11:22 +0100)
committerChristian Brauner <brauner@kernel.org>
Wed, 14 Jan 2026 10:23:39 +0000 (11:23 +0100)
Remove the "nullfs_rootfs" boot parameter and simply always use nullfs.
The mutable rootfs will be mounted on top of it. Systems that don't use
pivot_root() to pivot away from the real rootfs will have an additional
mount stick around but that shouldn't be a problem at all. If it is
we'll rever this commit.

This also simplifies the boot process and removes the need for the
traditional switch_root workarounds.

Suggested-by: Jeff Layton <jlayton@kernel.org>
Signed-off-by: Christian Brauner <brauner@kernel.org>
Documentation/filesystems/ramfs-rootfs-initramfs.rst
fs/namespace.c
init/do_mounts.c
init/do_mounts.h

index a8899f849e903bcc7b254c37a0131b277c483b63..165117a721ceeea6461188f15b2e65de85ee04c6 100644 (file)
@@ -76,13 +76,8 @@ What is rootfs?
 ---------------
 
 Rootfs is a special instance of ramfs (or tmpfs, if that's enabled), which is
-always present in 2.6 systems.  Traditionally, you can't unmount rootfs for
-approximately the same reason you can't kill the init process; rather than
-having special code to check for and handle an empty list, it's smaller and
-simpler for the kernel to just make sure certain lists can't become empty.
-
-However, if the kernel is booted with "nullfs_rootfs", an immutable empty
-filesystem called nullfs is used as the true root, with the mutable rootfs
+always present in Linux systems.  The kernel uses an immutable empty filesystem
+called nullfs as the true root of the VFS hierarchy, with the mutable rootfs
 (tmpfs/ramfs) mounted on top of it.  This allows pivot_root() and unmounting
 of the initramfs to work normally.
 
@@ -126,25 +121,14 @@ All this differs from the old initrd in several ways:
     program.  See the switch_root utility, below.)
 
   - When switching another root device, initrd would pivot_root and then
-    umount the ramdisk.  Traditionally, initramfs is rootfs: you can neither
-    pivot_root rootfs, nor unmount it.  Instead delete everything out of
-    rootfs to free up the space (find -xdev / -exec rm '{}' ';'), overmount
-    rootfs with the new root (cd /newmount; mount --move . /; chroot .),
-    attach stdin/stdout/stderr to the new /dev/console, and exec the new init.
-
-    Since this is a remarkably persnickety process (and involves deleting
-    commands before you can run them), the klibc package introduced a helper
-    program (utils/run_init.c) to do all this for you.  Most other packages
-    (such as busybox) have named this command "switch_root".
-
-    However, if the kernel is booted with "nullfs_rootfs", pivot_root() works
+    umount the ramdisk.  With nullfs as the true root, pivot_root() works
     normally from the initramfs.  Userspace can simply do::
 
       chdir(new_root);
       pivot_root(".", ".");
       umount2(".", MNT_DETACH);
 
-    This is the preferred method when nullfs_rootfs is enabled.
+    This is the preferred method for switching root filesystems.
 
 Populating initramfs:
 ---------------------
index a44ebb2f1161d21fe4ece76c4c0d8f0426518a16..53d1055c18257f1f0428bfb8e4e1f6086e51a5ef 100644 (file)
@@ -75,17 +75,6 @@ static int __init initramfs_options_setup(char *str)
 
 __setup("initramfs_options=", initramfs_options_setup);
 
-bool nullfs_rootfs = false;
-
-static int __init nullfs_rootfs_setup(char *str)
-{
-       if (*str)
-               return 0;
-       nullfs_rootfs = true;
-       return 1;
-}
-__setup("nullfs_rootfs", nullfs_rootfs_setup);
-
 static u64 event;
 static DEFINE_XARRAY_FLAGS(mnt_id_xa, XA_FLAGS_ALLOC);
 static DEFINE_IDA(mnt_group_ida);
@@ -4593,10 +4582,9 @@ int path_pivot_root(struct path *new, struct path *old)
  * pointed to by put_old must yield the same directory as new_root. No other
  * file system may be mounted on put_old. After all, new_root is a mountpoint.
  *
- * Also, the current root cannot be on the 'rootfs' (initial ramfs) filesystem
- * unless the kernel was booted with "nullfs_rootfs". See
- * Documentation/filesystems/ramfs-rootfs-initramfs.rst for alternatives
- * in this situation.
+ * The immutable nullfs filesystem is mounted as the true root of the VFS
+ * hierarchy. The mutable rootfs (tmpfs/ramfs) is layered on top of this,
+ * allowing pivot_root() to work normally from initramfs.
  *
  * Notes:
  *  - we don't move root/cwd if they are not at the root (reason: if something
@@ -5993,49 +5981,39 @@ static void __init init_mount_tree(void)
        struct path root;
 
        /*
-        * When nullfs is used, we create two mounts:
+        * We create two mounts:
         *
         * (1) nullfs with mount id 1
         * (2) mutable rootfs with mount id 2
         *
         * with (2) mounted on top of (1).
         */
-       if (nullfs_rootfs) {
-               nullfs_mnt = vfs_kern_mount(&nullfs_fs_type, 0, "nullfs", NULL);
-               if (IS_ERR(nullfs_mnt))
-                       panic("VFS: Failed to create nullfs");
-       }
+       nullfs_mnt = vfs_kern_mount(&nullfs_fs_type, 0, "nullfs", NULL);
+       if (IS_ERR(nullfs_mnt))
+               panic("VFS: Failed to create nullfs");
 
        mnt = vfs_kern_mount(&rootfs_fs_type, 0, "rootfs", initramfs_options);
        if (IS_ERR(mnt))
                panic("Can't create rootfs");
 
-       if (nullfs_rootfs) {
-               VFS_WARN_ON_ONCE(real_mount(nullfs_mnt)->mnt_id != 1);
-               VFS_WARN_ON_ONCE(real_mount(mnt)->mnt_id != 2);
+       VFS_WARN_ON_ONCE(real_mount(nullfs_mnt)->mnt_id != 1);
+       VFS_WARN_ON_ONCE(real_mount(mnt)->mnt_id != 2);
 
-               /* The namespace root is the nullfs mnt. */
-               mnt_root                = real_mount(nullfs_mnt);
-               init_mnt_ns.root        = mnt_root;
+       /* The namespace root is the nullfs mnt. */
+       mnt_root                = real_mount(nullfs_mnt);
+       init_mnt_ns.root        = mnt_root;
 
-               /* Mount mutable rootfs on top of nullfs. */
-               root.mnt                = nullfs_mnt;
-               root.dentry             = nullfs_mnt->mnt_root;
+       /* Mount mutable rootfs on top of nullfs. */
+       root.mnt                = nullfs_mnt;
+       root.dentry             = nullfs_mnt->mnt_root;
 
-               LOCK_MOUNT_EXACT(mp, &root);
-               if (unlikely(IS_ERR(mp.parent)))
-                       panic("VFS: Failed to mount rootfs on nullfs");
-               scoped_guard(mount_writer)
-                       attach_mnt(real_mount(mnt), mp.parent, mp.mp);
+       LOCK_MOUNT_EXACT(mp, &root);
+       if (unlikely(IS_ERR(mp.parent)))
+               panic("VFS: Failed to mount rootfs on nullfs");
+       scoped_guard(mount_writer)
+               attach_mnt(real_mount(mnt), mp.parent, mp.mp);
 
-               pr_info("VFS: Finished mounting rootfs on nullfs\n");
-       } else {
-               VFS_WARN_ON_ONCE(real_mount(mnt)->mnt_id != 1);
-
-               /* The namespace root is the mutable rootfs. */
-               mnt_root                = real_mount(mnt);
-               init_mnt_ns.root        = mnt_root;
-       }
+       pr_info("VFS: Finished mounting rootfs on nullfs\n");
 
        /*
         * We've dropped all locks here but that's fine. Not just are we
index 675397c8a7a4a1a28f7dd7d33371a175a6b8dd76..df6847bcf1f25a05fc5ec26839187e39fcde0ab3 100644 (file)
@@ -493,21 +493,15 @@ void __init prepare_namespace(void)
 out:
        devtmpfs_mount();
 
-       if (nullfs_rootfs) {
-               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");
+       if (init_pivot_root(".", ".")) {
+               pr_err("VFS: Failed to pivot into new rootfs\n");
                return;
        }
-
-       init_mount(".", "/", NULL, MS_MOVE, NULL);
-       init_chroot(".");
+       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;
index fbfee810aa89e00112ae5a8281527b094860fd32..6069ea3eb80d70106d6a8d8b3515d50176353206 100644 (file)
@@ -15,7 +15,6 @@
 void  mount_root_generic(char *name, char *pretty_name, int flags);
 void  mount_root(char *root_device_name);
 extern int root_mountflags;
-extern bool nullfs_rootfs;
 
 static inline __init int create_dev(char *name, dev_t dev)
 {