Linux initramfs深度解析: 从内核启动到根文件系统的桥梁(4)
接前一篇文章:Linux initramfs深度解析: 从内核启动到根文件系统的桥梁(3)
实践示例
1. 实例: 构建一个最小的initramfs
让我们从头开始构建一个最小的initramfs,来深化理解。这个示例使用busybox作为基础工具。
第一步:准备目录结构
#!/bin/bash # 创建 initramfs 工作目录 INITRAMFS_DIR="initramfs" mkdir -p $INITRAMFS_DIR/{bin,sbin,etc,lib,lib64,dev,proc,sys,root,newroot} # 复制必要的工具(使用 busybox) cp /bin/busybox $INITRAMFS_DIR/bin/ # 创建 busybox 的符号链接(模拟各种命令) cd $INITRAMFS_DIR/bin for cmd in sh ls cat mount umount mkdir cp rm; do ln -sf busybox $cmd done cd - # 复制必要的库 cp /lib64/ld-linux-x86-64.so.2 $INITRAMFS_DIR/lib64/ cp /lib64/libc.so.6 $INITRAMFS_DIR/lib64/ cp /lib64/libm.so.6 $INITRAMFS_DIR/lib64/第二步:创建初始化脚本
#!/bin/sh # $INITRAMFS_DIR/init - initramfs 的核心启动脚本 # 挂载必要的伪文件系统 mount -t proc proc /proc mount -t sysfs sysfs /sys mount -t devtmpfs devtmpfs /dev # 尝试挂载根文件系统 # 假设根分区是 /dev/sda1 if ! mount -r /dev/sda1 /newroot; then echo "Failed to mount root filesystem" # 进入应急 shell /bin/sh exit 1 fi # 切换到真实根文件系统 cd /newroot pivot_root . initramfs # 或使用 switch_root 工具 # 卸载 initramfs(现在位于 /initramfs) umount -l /initramfs # 执行真实根中的 init exec /sbin/init第三步:打包成cpio格式
#!/bin/bash # 生成 cpio 格式的 initramfs cd $INITRAMFS_DIR find . -print0 | \ cpio -0 -o -H newc -F ../initramfs.cpio # 压缩 gzip -f ../initramfs.cpio mv ../initramfs.cpio.gz ../initramfs.img echo "initramfs 已生成: initramfs.img"第四步:配置引导加载程序
对于GRUB 2,编辑/etc/default/grub:
# /etc/default/grub GRUB_CMDLINE_LINUX="root=/dev/sda1 ro" # 其他配置...然后在GRUB菜单项中指定 initramfs:
menuentry 'Linux with Custom Initramfs' { search --no-floppy --label --set root mylinux echo 'Loading Linux kernel...' insmod gzio insmod part_msdos insmod ext2 set root='(hd0,msdos1)' linux16 /boot/vmlinuz-5.x.x root=/dev/sda1 ro echo 'Loading initial ramdisk...' initrd16 /boot/initramfs.img }第五步:调试和验证
# 1. 查看 initramfs 内容 gunzip -c initramfs.img | cpio -t # 2. 解压 initramfs 进行检查 mkdir -p extracted cd extracted gunzip -c ../initramfs.img | cpio -idmv ls -la # 3. 检查库依赖 ldd init ldd bin/busybox # 4. 使用 initramfs-tools 的内置验证 lsinitramfs initramfs.img这个例子虽然简化了很多细节(实际的initramfs需要处理多种设备、文件系统等),但展示了 initramfs的核心工作原理。现代工具如dracut本质上就是自动化这些步骤。
工具与调试
工具/命令 | 用途 | 示例 |
|---|---|---|
lsinitramfs | 列出initramfs 内容 | lsinitramfs /boot/initramfs-5.10.0.img |
cpio | 打包/解包cpio归档 | cpio -idmv < initramfs.cpio |
dracut | 生成initramfs | dracut /boot/initramfs-$(uname -r).img |
mkinitramfs | Debian风格的initramfs生成 | mkinitramfs -o /boot/initramfs.img |
gunzip | 解压gzip压缩 | gunzip -c initramfs.img.gz |
file | 识别文件格式 | file initramfs.img |
strings | 提取文本字符串 | strings initramfs.img | grep -i "version" |
strace | 追踪系统调用 | strace -e trace=open,read init |
grub-mkconfig | 自动生成GRUB配置 | grub-mkconfig -o /boot/grub/grub.cfg |
1. 调试技巧
(1)查看initramfs解压过程
在内核启动参数中添加rd.debug,可以看到initramfs解压的详细日志:
# /etc/default/grub GRUB_CMDLINE_LINUX="root=/dev/sda1 rd.debug"(2)进入initramfs调试shell
如果启动失败,可以进入initramfs的调试shell:
# 在内核参数中添加 rd.break这会在initramfs中间断开,打开一个shell供调试使用。此时根文件系统还未挂载或切换,可以手动运行命令来诊断问题。
(3)查看udev事件
# 在 initramfs 中查看 udev 事件(device enumeration) udevadm control --log-priority=debug # 或者查看内核日志 dmesg | grep -i "udev\|device"更多内容请看下回。
