图文详解Linux根文件系统

大家好,这里是物联网心球。

本文的主题是Linux根文件系统,在进入正文之前,我们先来思考一个问题:什么是Linux根文件系统?

根文件系统被认为是Linux内核启动后挂载的第一个文件系统,是Linux文件树的根,是所有绝对路径的起点。笔者认为,这种表达并不够精准。接下来,我们从内核视角出发,深入了解Linux根文件系统。

注意:本文基于内核6.10版本讲解。

1.根文件系统从何而来?

Linux用户接触到的根文件系统只是挂载在根目录("/")下的一个真实的文件系统 ,我们习惯把它称为真实根文件系统。内核初始化时,会挂载一个rootfs文件系统(伪文件系统,只存在内存中),rootfs是Linux内核启动后第一个挂载的文件系统,所以它才是Linux的根文件系统。

从rootfs到真实根文件系统需要经历三个环节:

  • 挂载rootfs伪文件系统。
  • 解析initramfs至rootfs。
  • 挂载真实根文件系统(如ext4)。

图1 真实根文件系统挂载流程

真实根文件系统挂载流程如图1所示。

首先,我们来看rootfs伪文件系统的挂载流程,rootfs文件系统定义如下:

复制代码
struct file_system_type rootfs_fs_type = {
    .name = "rootfs",
    .init_fs_context = rootfs_init_fs_context,
    .kill_sb = kill_litter_super,
};

我们展开rootfs_init_fs_context函数:

复制代码
static int rootfs_init_fs_context(struct fs_context *fc)
{
    if (IS_ENABLED(CONFIG_TMPFS) && is_tmpfs)
        return shmem_init_fs_context(fc);

    return ramfs_init_fs_context(fc);
}

发现rootfs实际上是一个**tmpfs** 或**ramfs文件系统** 实例。ramfstmpfs都是 Linux系统中基于内存的文件系统。它们将数据直接存储在RAM(物理内存)中,因此读写速度极快,但数据在系统重启后会丢失。

内核启动过程会调用start_kernel函数,该函数会执行一些列初始化工作,rootfs的初始化路径为:start_kernel()->vfs_caches_init()->mnt_init()->init_mount_tree()。init_mount_tree函数将会创建rootfs挂载实例和rootfs根目录,并将这些信息记录在内核。文件系统挂载过程这里不过多展开,对文件系统挂载感兴趣的同学可以阅读这篇文章:从ext4文件系统到Linux文件树

rootfs解决的是Linux文件树从0到1的问题,rootfs的根目录就是Linux文件树的根,后续的真实根文件系统需要挂载在rootfs的根目录。

有了根文件系统后,接下来,内核会解析initramfs至rootfs。initramfs是Linux启动过程中使用的临时文件系统,在真实根文件系统挂载前提供必要的驱动和工具。initramfs经常被当做Linux文件系统,其实它并不是真正的文件系统,内核中并没有定义该类型的文件系统。initramfs本质是一个cpio归档文件,包含了挂载真实根文件系统需要用到的所有文件。内核会对initramfs进行解析,并将解析出来的文件一个个保存在rootfs文件系统中(注意此处并不是挂载,可以理解为文件拷贝)。initramfs解析对应的初始化路径为:start_kernel()->arch_call_rest_init()->rest_init()->kernel_init()->......->do_populate_rootfs()。

initramfs解析完毕后,rootfs根目录下会有一个init脚本,init脚本将会完成真实文件系统挂载,并将系统运行环境也切换至真实文件系统。对应的初始化路径为:start_kernel()->vfs_caches_init()->rest_init()->kernel_init()->run_init_process("/init")。run_init_process函数将会执行init脚本。

2.initramfs详解

initramfs并不是真正的文件系统,它是压缩(如lz4、gzip、zstd等压缩格式)了的cpio归档文件,cpio(Copy In and Out)是一种在Unix和Linux系统中广泛使用的归档工具,用于将多个文件和目录打包成一个单独的归档文件,同时保留文件的元数据(如权限、所有者、时间戳等)。

cpio支持多种归档格式:bin、odc、newc、crc、tar等。initramfs采用的是newc格式,如图2所示。

图2 initramfs格式

initramfs由一条条文件记录构成,每条文件记录格式为:

  • 文件头(110字节)
  • 文件名
  • 0-3字节填充
  • 文件数据
  • 0-3字节填充

文件头包含文件的元数据,固定大小为110字节,其格式见表1。

表1 newc文件头

为了加深大家对newc格式的理解,我们创建一个最小initramfs并打包成newc格式,测试脚本如下:

bash 复制代码
#!/bin/bash

#创建文件树
mkdir bin conf etc lib
touch etc/test.txt
#创建init脚本
echo "#!/bin/sh" > init
#打包为newc格式
find bin conf etc lib init -depth | cpio -o -H newc > initramfs.cpio

执行测试脚本后将生成一个initramfs.cpio归档文件,执行以下命令验证文件清单:

复制代码
cpio -t < demo.cpio

文件清单如下:

复制代码
# cpio -t < initramfs.cpio
bin
conf
etc/test.txt
etc
lib
init

执行hexdump -C initramfs.cpio查看归档文件记录,输出结果如下: 最终cpio中的文件记录将一条条被解析,并存储在rootfs文件系统中。

3./init脚本

/init脚本是initramfs的核心,它将完成以下关键任务:

  • 挂载/proc, /sys, /dev等虚拟文件系统,并创建必要的设备节点。
  • 加载访问存储设备和文件系统所需的内核模块。
  • 挂载真实根文件系统。
  • 将系统根目录切换到真实根文件系统,并启动/sbin/init进程(1号进程)。

实际的/init脚本一般都比较复杂,为了便于讲解,我们只关注根文件系统挂载相关的内容,如图3所示。

图3 /init脚本工作原理

内核调用run_init_process("/init")函数将会执行init脚本,run_init_process函数主要任务是执行用户空间的第一个进程,从而完成从内核态到用户态的切换。

真实根文件系统(如ext4)未挂载之前,系统执行文件相关的操作都是在rootfs文件系统中进行。/init脚本首先会挂载伪文件系统(proc、sysfs、devtmpfs等)至rootfs。接着,内核会读取块设备,并挂载块设备中的真实根文件系统挂载至rootfs(挂载点由用户自行定义)。最后,将已挂载的伪文件系统移动至真实根文件系统,以及执行initramfs中的switch_root命令将运行环境切换至真实根文件系统。

switch_root 命令的核心功能包括:

  • 将新根目录设置为系统的根文件系统。
  • 执行新根文件系统中的init程序(通常是 /sbin/init)。
  • 清理并释放initramfs占用的内存空间。

switch_root语法格式如下:

复制代码
switch_root [-c /dev/console] NEW_ROOT NEW_INIT [ARGUMENTS_TO_INIT]
  • NEW_ROOT:已经挂载好的真正根文件系统挂载点,例如 /newroot。

  • NEW_INIT:真正根文件系统中的init程序路径,通常是/sbin/init(软链接,指向init或systemd)。

  • -c:可选,重定向新系统的控制台设备。

总结:

真实根文件系统启动流程分为三步:首先,挂载rootfs文件系统,创建根目录,解决文件系统从0到1的问题;接着,解析initramfs并将initramfs中的文件保存至rootfs文件系统;最后,执行initramfs中的init脚本,init脚本将完成真实根文件系统挂载。

相关推荐
Trouvaille ~19 小时前
【Linux】从磁盘到文件系统:深入理解Ext2文件系统
linux·运维·网络·c++·磁盘·文件系统·inode
Trouvaille ~2 天前
【Linux】目录、路径与软硬链接:Linux文件组织的奥秘
linux·运维·服务器·chrome·文件系统·软硬链接·路径缓存
加勒比之杰克5 天前
【操作系统原理】重定向和文件系统
文件系统·os·重定向
列逍9 天前
Linux文件(二)
linux·磁盘·文件系统·挂载·软硬链接·缓冲区
_OP_CHEN9 天前
【Linux系统编程】(十四)深入 Linux 内核:进程优先级调度与切换的底层逻辑全解析
linux·运维·linux内核·进程·进程切换·进程优先级·调度算法
物联网心球11 天前
从ext4文件系统到Linux文件树
linux·linux内核·文件系统
边疆.17 天前
【Linux】文件系统
linux·运维·服务器·磁盘·文件系统·软硬链接
J2虾虾17 天前
华为 Obs 的使用
文件系统·华为obs
做人不要太理性20 天前
【Linux系统】ext2文件系统
大数据·linux·操作系统·文件系统