1、initrd出现的背景
在早期的linux系统中,一般只有硬盘或者软盘被用来作为linux根文件系统的存储设备,因此也就很容易把这些设备的驱动程序集成到内核中。但是现在的嵌入式系统中可能将根文件系统保存到各种存储设备上,包括scsi、sata,u-disk等等。因此把这些设备的驱动代码全部编译到内核中显然就不是很方便。
在内核模块自动加载机制udev中,我们看到利用udevd可以实现内核模块的自动加载,因此我们希望如果存储根文件系统的存储设备的驱动程序也能够实现自动加载,那就好了。但是这里有一个矛盾,udevd是一个可执行文件,在根文件系统被挂载前,是不可能执行udevd的,但是如果udevd没有启动,那就无法自动加载存储根文件系统设备的驱动程序,同时也无法在/dev目录下建立相应的设备节点。
为了解决这一矛盾,于是出现了基于ramdisk的initrd( bootloader initialized RAM disk )。Initrd是一个被压缩过的小型根目录,这个目录中包含了启动阶段中必须的驱动模块,可执行文件和启动脚本,也包括上面提到的udevd(实现udev机制的demon)。当系统启动的时候,bootloader会把initrd文件读到内存中,然后把initrd文件在内存中的起始地址和大小传递给内核。内核在启动初始化过程中会解压缩initrd文件,然后将解压后的initrd挂载为根目录,然后执行根目录中的/init脚本(cpio格式的initrd为/init,而image格式的initrd<也称老式块设备的initrd或传统的文件镜像格式的initrd>为/initrc),就可以在这个脚本中运行initrd文件系统中的udevd,让它来自动加载realfs(真实文件系统)存放设备的驱动程序以及在/dev目录下建立必要的设备节点。在udevd自动加载磁盘驱动程序之后,就可以mount真正的根目录,并切换到这个根目录中来。
2、什么是initrd?
initrd 的英文含义是 boot loader initialized RAM disk,就是由 boot loader 初始化的内存盘。在 linux内核启动前, boot loader会将存储介质中的 initrd 文件加载到内存,内核启动时会在访问真正的根文件系统前先访问该内存中的 initrd 文件系统。在 bootloader 配置了 initrd 的情况下,内核启动被分成了两个阶段,第一阶段先执行 initrd 文件系统中的"某个文件",完成加载驱动模块等任务,第二阶段才会执行真正的根文件系统中的 /sbin/init 进程。
3、initrd的种类
initrd分为两种,image-initrd和cpio-initrd。
2.4内核及以前的版本中的initrd.img的文件需要先用zip方式解压得到 initrd文件。这里获得到的initrd文件已经是个标准的image文件了(这个文件我们称为image-initrd),在linux下需要进行挂载,然后可以直接访问。2.5内核及其以后的版本中的initrd.img文件(这里称为cpio-initrd), initrd.img 是个gz压缩文件,initrd.img改名为initrd.gz能用windows下的winrar或linux下的gunzip解压,解压后会得到一个initrd文件。这个文件就是cpio格式的文件,只能在linux下用cpio命令解压,执行cpio -i < initrd。
注意:这两种格式的initrd不只是打包方式不同,内部文件也有不同!
具体区别如下:
<1> image-initrd
(1) boot loader(一般大家常用的是grub,关于它的介绍可以到网上搜索)把 initrd.img 初始化成一个设备 /dev/intrd。接着bootloader 把内核以及/dev/initrd的内容加载到内存。
(2) 在内核初始化过程中,内核把 /dev/initrd 设备的内容解压缩并拷贝到 /dev/ram0 设备上。
(3) 内核以可读写的方式把 /dev/ram0 设备挂载为原始的根文件系统。
(4) 如果 /dev/ram0 被指定为真正的根文件系统,那么内核不会执行(5)、(6)、(7)的操作,因为这下操作是为了帮内核加载最终的根文件系统做的工作。
(5) 执行 initrd 上的 /linuxrc 文件,linuxrc 通常是一个脚本文件,负责加载内核访问根文件系统必须的驱动, 以及加载根文件系统。
(6) /linuxrc 执行完毕,真正的根文件系统被挂载。
(7) 如果真正的根文件系统存在 /initrd 目录,那么 /dev/ram0 将从 / 移动到 /initrd。否则如果 /initrd 目录不存在, /dev/ram0 将被卸载。
(8) 在真正的根文件系统上进行正常启动过程 ,执行 /sbin/init。
注意:linux2.4内核的 initrd 的执行是作为内核启动的一个中间阶段,也就是说 initrd 的 /linuxrc执行以后,内核会继续执行初始化代码。2.6 内核同时支持 image-initrd 和 cpip-initrd。而且 image-initrd处理流程也是这样的。
<2> cpio-initrd
(1) boot loader 把内核以及 initrd 文件加载到内存的特定位置。
(2) 内核判断initrd的文件格式,如果是cpio格式。
(3) 将initrd的内容释放到/rootfs中。(rootfs本身也是一个基于内存的文件系统。这样就省掉了ramdisk的挂载、卸载等)。
(4) 执行initrd中的/init文件,执行到这一点,内核的工作全部结束,完全交给/init文件处理。也就是其实到了最后一步,内核就已经完成了自己所有的工作,直接移交给initrd 的/init。