现象
Kernel挂载自定义的文件系统后似乎没有任何提示,不知文件系统制作是否成功。
背景
Linux的根文件系统调试方式有很多种,uboot传递相应参数告知从Kernel从哪里挂载根文件系统: MTD、硬盘、NFS、SD卡、initramfs。这里我选择的是initramfs的方式挂载,目的是尽可能 排除其他环境因素影响文件系统测试,包括:NFS root没有执行权限;uboot的NAND纠错算法(ECC)和 Kernel的不一致导致MTD数据载入错误。
initramfs是直接和Kernel绑定在一起,同时解压到内存,踩坑的概率要小很多,保证文件系统 足够小、内存足够大,基本不会遇到问题。
之所以写这篇文章是没仔细读取Kernel官方文档:
Documentation/filesystems/ramfs-rootfs-initramfs.rst。
1. 制作方式
上文说了initramfs要保证文件系统足够小、内存足够大。没有什么比一句话代码的容量更小。 万能的儿童版Hello world教程,这个例位于linux源码 Documentation 目录下,注意后面的休眠2秒,
为什么休眠2秒,这里先埋个包袱。
源码最好静态编译,避免遗漏拷贝 .so 影响测试。
配置内核填入initramfs的根目录
uboot传递启动参数:setenv bootargs ‘console=ttyAM0,115200n8 rdinit=/sbin/init’。
Kernel的ramdisk_execute_command字符串接受这个参数,rdinit是initramfs执行的第一个程序位置, 进程的PID是1。
console这么传递请参考上一篇文章《uboot传递console究竟怎么填?ttyX傻傻分不清》。
Kernel最后加载文件系统阶段首先检查是否存在rdinit所指的文件,不存在则从其他媒介设备 挂载文件系统。从Kernel角度来说,无论是rdinit和其他媒介设备的文件系统内核都同等对待, 只是找到谁就执行谁而已。
相关源码位于init/main.c
走你,咦!内核启动结束后没看到期待的 “Hello world”。
2. 提出排查方向
起初怀疑3个方向:
- 文件没有找到
- 文件找到了,却没执行权限
- 文件找到了,也执行了,但没找到stdout
3. 排除设想1、2
从输出结果怀疑方向,首先最先排除的是“设想1”,肯定是找到/sbin/init,否则不会出现倒数第二行 “CPU 0执行的init进程PID 1 退出”,没执行哪来的退出,于是排除“设想2”。
验证方案也很简单,删除/work/ramfs/sbin/init再测试一次。
输出内容有明显差异,输出意思:rdinit所指文件不存在,尝试从其他媒体设备挂载文件系统,而其他媒体 设备位置却没有传递,请纠正 “root=” 参数。
5. 确认设想3
回头看 Warning: unable to open an initial console。某个console没有打开?会不会是 “设想3”的stdout呢?
该字符串出现在源码 init/main.c。尝试打开/dev/console作为标准输入/输出/错误,节点的信息照抄 本地PC的 “ls -l /dev/console”。照葫芦画瓢创建节点。
sudo mknod -m 622 console c 5 1
再次上电测试成功看到 “Hello world”
为什么延时2秒
延时2秒是为了看效果,系统正常运行时是不允许PID 1退出,它很特殊起到脱孤进程的作用,一旦退出系统认为出大事咯,立即打印出堆栈信息,并停止运行。