图文详解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脚本将完成真实根文件系统挂载。

相关推荐
未来可期LJ4 天前
【Linux 操作系统篇】文件系统 innode的理解
linux·文件系统
_OP_CHEN6 天前
【Linux系统编程】(二十四)深入 Ext2 块组内部:inode、数据块与目录的底层工作机制
linux·操作系统·文件系统·c/c++·inode·块组·数据块映射
_OP_CHEN7 天前
【Linux系统编程】(二十三)从块到块组:Ext2 文件系统核心架构的初步认识
linux·操作系统·文件系统·c/c++·ext2文件系统·磁盘分区·块组
bsauce7 天前
【kernel exploit】CVE-2025-21702-net-sched UAF漏洞分析
linux内核·内核安全·内核漏洞利用
_OP_CHEN8 天前
【Linux系统编程】(二十二)从磁盘物理结构到地址映射:Ext 系列文件系统硬件底层原理深度剖析
linux·操作系统·文件系统·c/c++·计算机硬件·ext文件系统·磁盘寻址
li_wen019 天前
文件系统(八):Linux JFFS2文件系统工作原理、优势与局限
大数据·linux·数据库·文件系统·jffs2
li_wen0110 天前
文件系统(一):存储介质、原理与架构
文件系统·存储介质
物理与数学10 天前
linux内核 struct super_block
linux·linux内核
物理与数学11 天前
Linux 页表映射
linux·linux内核
物理与数学11 天前
linux内核常用hook机制
linux·linux内核