全面解析Linux 内核 3.10.x - initramfs 启动流程

来源:互联网 发布:js购物车结算 编辑:程序博客网 时间:2024/06/10 09:31

这里有一份来自initramfs 合并的邮件请求,请点击。 
我给大家翻译一些小片段(杜撰加翻译)。

————————————–致亲爱的 Linus—————————— 
*亲爱的Linus:*
最近我苦思冥想,有一个想法不吐不快(关于kernel 启动 rootfs的idea)。 
是怎么回事呢?你知道我的,一个重度的最小系统使用着,最近我又在捣鼓完毕了一个新的东西,打算上我的mini system装个逼,让大伙瞅瞅也好继续摸牌我(此处省略1W字+)。可是当我把东西移植完毕后,兴致冲冲的准备让大伙膜拜我的时候(内心已经有点不淡定了),我的mini 突然蹦出一个消息告诉我,找不到文件系统..Oh..shit(当时我的内心是崩溃的),虽然最后问题也被我解决了,但是你知道吗?我的自尊心已经深深受到了伤害。 怎么可以让人看我的笑话?于是我花了一个通宵研究了为何会出现这种错误。并且给出了重新的优化方案。当然我并不是在原先的基本上去添加,而是单独把它拿了出来,起来个名字叫 initramfs ,是不是觉得名字很棒?(得瑟中…) 
下面我简单给您阐述下initramfs 的设计原理以及流程,您看是不是可以拉入主线版本呢?(哈哈,本天才将会被千千万万的程序猿们膜拜,颤抖吧…) 
a.基本设计思路 
将rootfs打包为cpio的压缩文件,并且告诉内核它的起始和大小,当内核启动后在也不需要单独将rootfs做为一个块设备挂载了(因为这样需要内核单独为此种方式写一种驱动来支持)。 
b.与老的initrd方式的几点不同 
老的initrd image方式加载步骤。 
1.boot把Kernel以及initrd文件加载到内存/或者写入Nanflash的特定位置。 
2.Kernel判断initrd的文件格式,如果不是cpio格式,将其作为文件image处理。 
3.Kernel将initrd的内容保存在rootfs下的/initrd.image文件中。 
4.Kernel将/initrd.image的内容读入/dev/ram0设备(虚拟内存盘)中。 
5.Kernel以可读写的方式把/dev/ram0设备挂载为原始的根文件系统。 
6.如果/dev/ram0被指定为真正的根文件系统,那么内核跳至最后一步正常启动。 
7.执行initrd上的/linuxrc文件,linuxrc通常是一个脚本文件,负责加载内核访问根文件系统必须的驱动,以及加载根文件系统。 
8./linuxrc执行完毕,常规根文件系统被挂载。 
9.如果常规根文件系统存在/initrd目录,那么/dev/ram0将从/移动到/initrd。否则如果/initrd目录不存在,/dev/ram0将被卸载。 
10.在常规根文件系统上进行正常启动过程 ,执行/sbin/init。
 
* 问题 * 

/dev/initrd block device 建立的时候有空闲限制,維護繁瑣運作於 initrd 階段,镜像操作实际上是不断將 /dev/initrd 对应到可存取镜像系統的位置,做了不必要的資源消耗。 
initramfs 的加载步骤 
1.boot 把内核以及 rootfs.cpio.gz 文件加载到内存的位置。 
2.Kernel判断文件是否存在,如果存在,解压缩。并且内容释放到rootfs中。 
3.默认执行/init,在执行/sbin/init 启动1号进程,进入文件系统。 

———————————–The End————————————–

initramfs是在一个叫ramfs的cache实现上加了一层很薄的封装,其他内核开发人员编写了一个改进版tmpfs,这个文件系统上的数据可以写出到交换分区,而且可以设定一个tmpfs装载点的最大尺寸以免耗尽内存。initramfs就是tmpfs的一个应用。initramfs与initrd类似,也是将image初始化完毕且存在于ram中的。可以选择压缩。 
目前initramfs只支持cpio包格式,支持主流的压缩方式(gzip,bzip),内核默认支持为gzip压缩的rootfs。

initramfs 的优点:

  1. tmpfs随着其中数据的增减自动增减容量 - 动态分配
  2. 在tmpfs和page cache/dentry cache之间没有重复数据 - 独立空间
  3. tmpfs重复利用了Linux caching的代码, 因此几乎没有增加内核尺寸, 而caching的代码已经经过良好测试, 所以tmpfs的代码质量也有保证.
  4. 不需要额外的文件系统驱动 - 简单明了

initramfs 的启动方式更加适用于嵌入式小系统(被裁剪),因为本质上是一个cpio打包过的文件,本质上打包的时候被将一个单一的文件,目录,node打包进去。

配置支持initramfs

制作initramfs 镜像

上述我们已知内核支持的initramfs 镜像为.cpio格式。 
那么将你已经编译生成的rootfs,通过以下命令打包。

cd rootfs/find ./ -print | cpio -H newc -ov > rootfs.cpio

在3.10.x中。配置下面宏。 
CONFIG_INITRAMFS_SOURCE="/home/XX/rootfs.cpio" 
或者 
`CONFIG_INITRAMFS_SOURCE=”/home/XX/rootfs.cpio.gz” 
这里的区别在于是否加一层压缩,就体积而言,我们当然希望我们的镜像越小越好,所以这里大多都选择.gz/.bz2压缩过的文件。 
然后编译内核即可,内核默认支持的解压缩方式(GZIP)。 
一组压缩的支持必然是由一组对应的解压缩. 
如:

CONFIG_RD_GZIP=y# CONFIG_INITRAMFS_COMPRESSION_GZIP is not setCONFIG_DECOMPRESS_GZIP=y

如果你要配置为bz2 或者 xz等压缩格式的支持。 
还需要打开对BZ2、XZ的支持。

CONFIG_RD_BZIP2=yCONFIG_INITRAMFS_COMPRESSION_BZIP2=yCONFIG_DECOMPRESS_BZIP2=y

initramfs 的的本质

根据上述配置,我们都中断initramfs 本质上是将一个文件(rootfs.cpio.gz)在加载内核的时候,先加载到ram,而后找到位置后跳转进入文件本身,启动1号进程,而后启动文件系统。其的原因就是为了解决initrd

3.10.x中关于initramfs 启动解析流程

vim usr/initramfs_data.S.section .init.ramfs,"a"__irf_start:.incbin __stringify(INIT
0 0