initrd遇到的问题及initramfs相关
initrd遇到的问题及initramfs相关
问题背景
最新在升级新驱动时遇到了一个很奇葩的问题:在客户某个版本的系统下,不管是将核外驱动包以前的老版本卸载后再安装新版本,还是直接升级该核外驱动包的新版本,从加载的驱动中读出的驱动版本一直是老的,甚至将该驱动包卸载后驱动还会加载,且为老版本,查找了一圈发现连KO都已经不存在了,奇了怪了,最后就把目光怀疑到了 **initrd**,果然在initrd里面有这个wifi驱动。
那它是怎么进去的呢?默认的initrd是没有将该wifi驱动放在里面的,后来发现居然是其他驱动的dkms包hooks脚本暴力将整个updates/dkms目录拉进了initrd ~~
下面,我们来看看这个 initrd 与 initramfs, 以下主要以 Debian/Ubuntu 系的发行版为例。
initrd与initramfs
initramfs 和 initrd 都是 Linux 启动过程中用于临时根文件系统(initial root filesystem)的机制,目的是在挂载真正的根文件系统之前加载必要的驱动、模块和工具。虽然它们目标一致,但在实现方式、历史演进和现代使用上存在关键区别。
一、基本概念对比
| 特性 | initrd(Initial RAM Disk) | initramfs(Initial RAM File System) |
|---|---|---|
| 出现时间 | 较早(Linux 2.4 时代) | 较新(Linux 2.6 起成为主流) |
| 技术基础 | 块设备镜像(模拟磁盘),需格式化为 ext2 等文件系统 | cpio 归档 + tmpfs,直接作为内存中的文件系统 |
| 加载方式 | 内核将其当作一个 RAM disk 挂载 | 内核直接解压 cpio 到 tmpfs 中 |
| 内存效率 | 较低(固定大小,即使未用满也占用内存) | 较高(按需分配,动态增长/收缩) |
| 复杂度 | 需要文件系统驱动支持(如 ext2) | 无需额外文件系统,内核原生支持 cpio |
| 现代使用 | ❌ 已基本被 initramfs 取代 | ✅ 当前所有主流发行版默认使用 |
二、技术细节差异
1. initrd 的工作流程
- Bootloader(如 GRUB)将
vmlinuz(内核)和initrd.img加载到内存。 - 内核创建一个 RAM disk 设备(如
/dev/ram0)。 - 将
initrd.img解压并挂载为一个块设备上的文件系统(通常是 ext2)。 - 执行其中的
/linuxrc脚本。 - 脚本完成后,卸载 initrd,挂载真正的根文件系统。
⚠️ 缺点: 需要内核内置对应文件系统的驱动(如 ext2),且内存浪费大。
2. initramfs 的工作流程
- Bootloader 加载内核和
initramfs(通常也是叫initrd.img,但内容是 cpio 格式)。 - 内核将 cpio 归档直接解压到 tmpfs(基于内存的临时文件系统)中。
- 执行
/init脚本(不再是/linuxrc)。 - 脚本完成必要操作(如加载加密/LVM/RAID 驱动)后,通过
switch_root切换到真正的根文件系统。
✅ 优点:
- 不依赖特定文件系统;
- 内存使用更高效;
- 实现更简洁,集成度更高。
三、文件命名的“混淆”
尽管现代系统几乎都使用 initramfs 技术,但出于兼容性和习惯,生成的文件仍常命名为:
/boot/initrd.img-<kernel-version>(Debian/Ubuntu)
🔍 如何判断实际类型?
file /boot/initrd.img-$(uname -r)
initramfs会输出类似结果:initrd.img-5.4.18-142-generic: ASCII cpio archive (SVR4 with no CRC)
✅ 注:
在今天谈论 “initrd” 时,绝大多数情况下实际指的是 initramfs,通常仍叫initrd.img,但内容是 initramfs。
真正的 initrd 已成为历史,仅在非常老的系统或特殊嵌入式场景中存在。
initramfs 管理
Debian/Ubuntu 系的发行版中主要使用 initramfs-tools 来生成和管理 initramfs 。
它在系统安装、内核更新或手动配置时自动构建 /boot/initrd.img-* 文件,确保系统启动时能加载必要的驱动。
一、核心组件
| 组件 | 说明 |
|---|---|
/usr/sbin/update-initramfs |
主命令行工具,用于创建/更新/删除 initramfs |
/etc/initramfs-tools/ |
配置目录,控制 initramfs 内容 |
/usr/share/initramfs-tools/ |
脚本和模块模板(hooks、scripts 等) |
二、常用命令:update-initramfs
基本语法
sudo update-initramfs -[c|u|d] -k <kernel-version>
| 选项 | 含义 |
|---|---|
-c |
create:为指定内核创建新的 initramfs |
-u |
update:更新现有 initramfs(最常用) |
-d |
delete:删除指定内核的 initramfs |
-k all |
对所有已安装内核操作 |
-k $(uname -r) |
仅对当前运行内核操作(默认行为) |
常用示例
1. 更新当前内核的 initramfs(最常见)
sudo update-initramfs -u
# 等价于
sudo update-initramfs -u -k $(uname -r)
2. 为所有内核更新 initramfs
sudo update-initramfs -u -k all
3. 手动为内核创建 initramfs
sudo update-initramfs -c -k 6.8.0-40-generic
三、关键配置目录:/etc/initramfs-tools/
1. /etc/initramfs-tools/modules
显式指定要包含的内核模块(每行一个):
# 示例:强制包含 USB 存储和 NVMe 驱动
usb_storage
nvme
⚠️ 仅当自动依赖分析未包含必要模块时才需手动添加。
2. /etc/initramfs-tools/conf.d/
存放配置片段文件(如 modules, compress, cryptroot 等)。
3. /etc/initramfs-tools/scripts/
自定义启动脚本目录,分阶段执行:
| 子目录 | 执行时机 |
|---|---|
init-top/ |
最早执行(挂载根文件系统前) |
init-premount/ |
挂载根文件系统前 |
local-top/ |
根设备已发现但未挂载 |
local-bottom/ |
根文件系统已挂载,即将 switch_root |
4. /etc/modprobe.d/
虽然不属于 initramfs-tools 直接管理,但其中的 blacklist 规则会影响模块是否被包含:
# /etc/modprobe.d/blacklist-mydriver.conf
blacklist problematic_driver
配合 update-initramfs -u 可从 initramfs 中移除该驱动。
initramfs 调试与验证
1. 查看 initramfs 内容
# 列出文件(无需解压)
lsinitramfs /boot/initrd.img-$(uname -r)
# 或传统方式
zcat /boot/initrd.img-$(uname -r) | cpio -it
2. 解包 initramfs(用于调试)
mkdir /tmp/initrd && cd /tmp/initrd
zcat /boot/initrd.img-$(uname -r) | cpio -idmv
initramfs 典型使用场景
场景 1:添加缺失的存储驱动
系统无法识别 NVMe 硬盘?
→ 编辑 /etc/initramfs-tools/modules 添加 nvme
→ 运行 sudo update-initramfs -u
场景 2:排除有问题的驱动
某个驱动导致启动卡死?
→ 在 /etc/modprobe.d/blacklist.conf 中加入 blacklist bad_driver
→ 运行 sudo update-initramfs -u
场景 3:自定义启动逻辑
需要在挂载根分区前执行脚本?
→ 将脚本放入 /etc/initramfs-tools/scripts/local-top/
→ 设为可执行:chmod +x script.sh
→ 运行 sudo update-initramfs -u
initramfs 注意事项
- 不要随意删除 initramfs,否则系统可能无法启动。
- 修改配置后必须运行
update-initramfs -u才能生效。 - 自动更新:通过
apt upgrade安装新内核时,系统会自动调用update-initramfs -c为新内核生成镜像。 - initramfs 大小:包含过多模块会增大镜像,延长启动时间,建议仅保留必要驱动。





