找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

2282

积分

0

好友

330

主题
发表于 2025-12-24 21:49:38 | 查看: 28| 回复: 0

本文旨在深入探讨Linux根文件系统的本质与启动流程。一个常见的理解是,根文件系统是内核启动后挂载的第一个文件系统,是文件树的根。然而,从内核的视角来看,这个说法可以进一步精确。我们将基于Linux内核6.10版本,剖析根文件系统的真实构成。

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

用户通常接触到的“根文件系统”,实际上是挂载在根目录 (/) 下的一个真实的文件系统,如 ext4 或 xfs,我们可称之为真实根文件系统。然而,在内核初始化时,首先挂载的是一个名为 rootfs 的文件系统。rootfs 是一个伪文件系统,仅存在于内存中,它才是Linux启动后第一个被挂载的文件系统,是真正的“根”。

从内存中的 rootfs 过渡到磁盘上的真实根文件系统,主要经历三个步骤:

  1. 挂载 rootfs 伪文件系统。
  2. 解析 initramfsrootfs
  3. 挂载真实根文件系统(如ext4)。

图片
图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 本质上是一个 tmpfsramfs 文件系统的实例。这两者都是基于内存的文件系统,数据存储在RAM中,读写速度快,但系统重启后数据会丢失。

内核启动函数 start_kernel() 会执行一系列初始化,其中 rootfs 的初始化路径为:start_kernel() -> vfs_caches_init() -> mnt_init() -> init_mount_tree()init_mount_tree 函数会创建 rootfs 的挂载实例和根目录,并将信息记录在内核。这解决了Linux文件树“从0到1”的问题,rootfs 的根目录即是文件树的起点,后续的真实文件系统都将挂载于此。

有了 rootfs 之后,内核便会解析 initramfs 到其中。initramfs 常被误认为是一种文件系统,实则不然。它是一个经过压缩(如lz4, gzip, zstd)的cpio归档文件,包含了挂载真实根文件系统所需的所有驱动和工具。内核会解析这个归档包,并将其中的文件逐一“填充”到 rootfs 中(可理解为文件拷贝)。解析 initramfs 的路径大致为:start_kernel() -> ... -> do_populate_rootfs()

解析完成后,rootfs 的根目录下会出现一个关键的 init 脚本。该脚本将负责挂载真实根文件系统,并完成运行环境的切换。执行该脚本的路径为:start_kernel() -> ... -> run_init_process(“/init”)

2. initramfs详解

initramfs 本质上是 newc 格式的cpio归档文件。cpio是一种用于打包文件和目录并保留元数据(权限、时间戳等)的工具。initramfs 由一条条文件记录构成,每条记录的格式为:

  • 文件头(110字节)
  • 文件名
  • 0-3字节填充(用于4字节对齐)
  • 文件数据
  • 0-3字节填充(用于4字节对齐)

其中,文件头包含了文件的元数据,其固定格式如下表所示:
表1: newc格式文件头
图片

为了更直观地理解,我们可以创建一个最小化的 initramfs。测试脚本如下:

#!/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 < initramfs.cpio 查看文件列表,或用 hexdump -C 查看其二进制格式。最终,cpio归档中的这些文件记录会被内核解析并存入 rootfs

3. /init脚本

/init 脚本是 initramfs 的核心,它承担着承上启下的关键任务:

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

内核调用 run_init_process(“/init”) 执行此脚本,该函数的主要作用是启动用户空间的第一个进程,完成内核态到用户态的切换。

在真实根文件系统(如 ext4)挂载前,所有文件操作都在 rootfs 中进行。/init 脚本首先将 proc、sysfs 等伪文件系统挂载到 rootfs 下。接着,读取块设备,并将设备中的真实根文件系统挂载到 rootfs 的某个目录(例如 /newroot)。最后,将已挂载的伪文件系统移动到新的根目录下,并执行 switch_root 命令彻底切换到真实根文件系统环境。

switch_root 命令的核心功能包括:

  1. 将指定的目录(已挂载的真实根文件系统)设置为新的根文件系统。
  2. 执行新根文件系统中的 init 程序(通常是 /sbin/init,可能指向 systemdinit)。
  3. 清理并释放 initramfs 占用的内存空间。

其语法格式如下:

switch_root [-c /dev/console] NEW_ROOT NEW_INIT [ARGUMENTS_TO_INIT]
  • NEW_ROOT: 已挂载的真实根文件系统路径,如 /newroot
  • NEW_INIT: 真实根文件系统中的 init 程序路径,如 /sbin/init
  • -c: 可选参数,用于重定向控制台设备。

总结

完整的 Linux 根文件系统启动流程可归纳为三步:首先,挂载内存中的 rootfs 文件系统,建立文件树的初始根目录;其次,解析 initramfs 归档,将其中的工具和驱动文件填充到 rootfs;最后,执行 initramfs 提供的 /init 脚本,由该脚本完成真实根文件系统的挂载与系统运行环境的最终切换。




上一篇:微服务Api网关框架视频课程 Nginx+Lua构建微服务API网关实战
下一篇:Go微服务gRPC性能优化实战:从HTTP迁移到双协议架构解析
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-1-10 08:51 , Processed in 0.282889 second(s), 39 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2025 云栈社区.

快速回复 返回顶部 返回列表