---------------
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.
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:
---------------------
__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);
* 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
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
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;