Linux的启动过程:
从内核载入到init进程启动-initramfs介绍 - 图1

为什么在init之前kernel要挂载rootfs?

在linux启动的时候,仅仅启动kernel是不行的,还要相应的通过/etc、/sbin,启动一些必须依赖的管理模块比如说systemd,同时,为了考虑到/etc、/sbin都是文件系统,是文件系统就需要将整个系统挂载到/的这个根目录下,因此在启动的时候需要提供**/**目录来方便**/etc****sbin**等启动关键程序和配置,这时候就需要一个专门提供挂载点的fs,这也就是rootfs。

这里引用一些参考[1]中的代码块

  1. start_kernel
  2.   vfs_caches_init
  3.     mnt_init
  4.       init_rootfs //注册rootfs文件系统
  5.       init_mount_tree // 挂载rootfs文件系统
  6.         vfs_kern_mount
  7.           mount_fs
  8.             type->mount // 其实是rootfs_mount
  9.               mount_nodev
  10.                 fill_super 其实是ramfs_fill_super
  11.                   inode = ramfs_get_inode(sb, NULL, S_IFDIR | fsi->mount_opts.mode, 0);
  12.                   sb->s_root = d_make_root(inode);
  13.                     static const struct qstr name = QSTR_INIT("/", 1); // 设置根目录名字为 /
  14.                     __d_alloc(root_inode->i_sb, &name);
  15.           
  16.           mnt->mnt.mnt_root = root; // 目录
  17.           mnt->mnt.mnt_sb = root->d_sb; // 设置超级快
  18.           mnt->mnt_mountpoint = mnt->mnt.mnt_root; // 文件挂载点,因为是/所有自己指向自己
  19.           mnt->mnt_parent = mnt; // 父挂载点也是自己
  20. root.mnt = mnt;
  21.         root.dentry = mnt->mnt_root;
  22.         mnt->mnt_flags |= MNT_LOCKED;
  23.         set_fs_pwd(current->fs, &root);
  24.         set_fs_root(current->fs, &root);
  25.   
  26.   rest_init
  27.   kernel_thread(kernel_init, NULL, CLONE_FS);
  28. ————————————————
  29. 版权声明:本文为CSDN博主「leon1741」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
  30. 原文链接:https://blog.csdn.net/LEON1741/article/details/78159754

由于初始化的时候硬盘并未挂载进来,初始化的rootfs其实是ramfs或者是tmpfs(一般是tmpfs)。

// COPY FROM https://houmin.cc/posts/7c0e6000/
int __init init_rootfs(void)
{
    int err = register_filesystem(&rootfs_fs_type);

    if (err)
        return err;

    if (IS_ENABLED(CONFIG_TMPFS) && !saved_root_name[0] &&
        (!root_fs_names || strstr(root_fs_names, "tmpfs"))) {
        err = shmem_init(); // tmpfs初始化
        is_tmpfs = true;
    } else {
        err = init_ramfs_fs();  // ramfs初始化
    }

    if (err)
        unregister_filesystem(&rootfs_fs_type);

    return err;
}

Q: 读完这里你可以还有疑问为什么/boot可以直接挂载进来?A:因为其本身就可以被Bootloader启动,直接读入内存,是BootLoader先引导这两部分进内存之后,才启动rootfs

df -h
/dev/nvme0n1p2                     976M  221M  688M  25% /boot
/dev/nvme0n1p1                     511M  6.7M  505M   2% /boot/efi

将rootfs挂载之后会如何做呢?

之后的目标就是通过init进程启动整个系统。这个时候就轮到initramfs登场了,在完成rootfs注册之后,kernel会将initramfs复制到rootfs上,然后作为内核初始的根文件系统,它的任务是挂载系统真正的根文件系统。(也就是挂载在/上的物理卷或者虚拟卷,甚至是块存储)。在initramfs中会有init进程,此时,init程序会作为pid为1的进行开始运行,从而启动整个系统。

Q:rootfs跟initramfs是什么关系呢?
A:initramfs是一种rootfs,在rootfs启动后,会删除rootfs的内容,将initramfs挂在进来,然后通过chroot的方式,将initramfs置为/
备注:这里面删除rootfs,那么之前的命令也没了,之后基于busybox使用switch_root的方式去处理这个过程,详细可以看3。

这个还有一个简单的趣闻:
initramfs在/boot里面是以initrd命名的,但是其只是延续了2.6之前内核的命名方式而已,实现方式已经改变了。initramfs是基于ramfs的而之前的initrd是基于ramdisk的。有兴趣的可以接着看

参考: