最近研究lkml上的fastboot patch,再次意识到自己对initrd一直很迷茫 ,就大概花了天时间看了看这方面的文档和代码,备忘总结下。
不想长篇大论 ,简单的说,主要有4种情况。1。无initrd 2。cpio initrd,于内核编在一起。 3。cpio initrd于内核分开编 4。 ramdisk initrd。
1。对于无initrd的情况,会先在initcall中调用default_rootfs(),随后在prepare_namespace()中调用
mount_root挂载真实的文件系统 ,最后在init_post()中通过kernel_execve执行根文件系统中的 /sbin/init。
2。对于后面3种,会调用initcall中的populate_rootfs() 函数来填充 rootfs。对于2,3的情况,是把initrd来填充rootfs,只不过,对2而言,原来的initrd和内核编在一起,在.init.ramfs段中,其中全局变量__initramfs_start和__initramfs_end分别指向这个数据段的起始地址和结束地址。如果.init.ramfs数据段大小不为0(initramfs_end - initramfs_start
!=
0),就说明这是initrd集成在内核数据段中。并且是cpio的initrd。而对于3,initrd是由bootloader加载到内存中的,这时
bootloader会把起始地址和结束地址传递给内核,内核中的全局initrd_start和initrd_end分别指向initrd的起始地址和
结束地址。对于4,则把 initrd 保存到 rootfs 的 /initrd.image
这个文件里。在后面,4会在prepare_namespace先挂载这个initrd,然后执行里面的linuxrc,然后再挂载真实的文件系统。后面
的步骤2,3会在init_post()中调用/init,一般的发行版本的Linux中,initrd中的/init脚本会启动udevd,加载必要的
设备驱动程序,然后挂载真正的根文件系统,最后再执行真正的根文件系统上的initrd,这样就这个启动过程就顺利的交接了。而对于4,则会调用根文件系
统上的/sbin/init(同1)。
所有的函数都在kernel_init中,从do_basic_setup()中的do_init_calls()到
prepare_namespace()(只有1,4要执行此函数)最后到init_post()。(有关临时根目录的挂载并未在本文中包含,请参阅参考
文献)总的来说,为了提高启动速度,应该尽量避免使用initrd,而如果非要使用initrd,则应该使用cpio
initrd,因为ramdisk initrd不仅使用不方便,而且在内核中的处理过程也更加复杂,不推荐使用。
参考文献:
1 Linux内核Ramdisk(initrd)机制
http://www./modules/article/view.article.php?9/c2#heading2
2 initrd 流程分析
http://hi.baidu.com/mczyh/blog/item/86153139527ed422b8998f17.html
3 解析linux根文件系统的挂载过程
http://bbs./viewthread.php?tid=306225
|