###1. initrd

initrd(initialized ram disk)是一个被压缩的小型根文件系统,包含各种可执行程序和驱动程序,它们可以用来挂载实际的根文件系统,然后再将这个 initrd RAM磁盘卸载,并释放内存。initrd 是一个临时的文件系统。其生存周期很短,只会用作到真实文件系统的一个桥梁。对于一些没有存储设备的嵌入式系统中,也会使用initrd作为永久的根文件系统。

###2. initrd出现的背景

initrd 的英文含义是 boot loader initialized RAM disk,就是由 boot loader 初始化的内存盘。在 linux内核启动前, boot loader 会将存储介质中的 initrd 文件加载到内存,内核启动时会在访问真正的根文件系统前先访问该内存中的 initrd 文件系统。

initrd的最初的目的是为了把kernel的启动分成两个阶段:

1.第一阶段先执行 initrd 文件系统中的”某个文件”,完成加载驱动模块等任务;
2.第二阶段才会执行真正的根文件系统中的 /sbin/init 进程;

第一阶段启动的目的是为第二阶段的启动扫清一切障碍,最主要的是加载根文件系统存储介质的驱动模块。我们知道根文件系统可以存储在包括IDE、SCSI、USB在内的多种介质上,如果将这些设备的驱动都编译进内核,可以想象内核会多么庞大、臃肿, 有了intrd,就可以在kernel中保留最少最基本的启动代码,然后把对各种各样硬件设备的支持以模块的方式放在initrd中,这样,只需要修改initrd,就可以支持多种硬件。

###3. inird的用途

1.linux 发行版的必备部件

  • linux 发行版必须适应各种不同的硬件架构,将所有的驱动编译进内核是不现实的,initrd 技术是解决该问题的关键技术。Linux 发行版在内核中只编译了基本的硬件驱动,在安装过程中通过检测系统硬件,生成包含安装系统硬件驱动的 initrd,无非是一种即可行又灵活的解决方案
    2.livecd 的必备部件
  • 同 linux 发行版相比,livecd 可能会面对更加复杂的硬件环境,所以也必须使用 initrd。
    3.制作 Linux usb 启动盘必须使用 initrd
  • usb 设备是启动比较慢的设备,从驱动加载到设备真正可用大概需要几秒钟时间。如果将 usb 驱动编译进内核,内核通常不能成功访问 usb 设备中的文件系统。因为在内核访问 usb 设备时, usb 设备通常没有初始化完毕。所以常规的做法是,在 initrd 中加载 usb 驱动,然后休眠几秒中,等待 usb设备初始化完毕后再挂载 usb 设备中的文件系统。
    4.在 linuxrc 脚本中可以很方便地启用个性化 bootsplash

###4. initrd是必须的吗

不是, 我们必须认识到,initrd只是作为临时根文件系统的载体,使用临时根文件系统,目的是为了insmod 设备驱动挂载正真的根文件系统,完全可以将设备驱动编译进内核,直接来挂载根文件系统。这样,就不需要使用initrd, 只是不够灵活。

###5. initrd的版本演变

####5.1 image-initrd

在linux2.4时代, 流行image-initrd, 它将所需的根文件做成一个文件系统镜像,然后在boot的时候,加载到ramdisk里面。

image-initrd的制作:

dd if=/dev/zero of=initrd.img bs=4k count=1024
mkfs.ext2 -F –m 0 initrd.img
sudo mkdir /mnt/ramdisk
mount -o loop initrd.img /mnt/ramdisk
cp -r /opt/filesystem /mnt/ramdisk
umount /mnt
gzip -9 initrd.img  

通过上面的命令,制作了一个大小为4M, 基于ext2文件系统的image-initrd的压缩文件。

image-initrd的大小固定(dd命令指定), 若需要改变大小, 需要使用上述命令重新制作

image-initrd是一个虚拟的块设备,可以使用fdisk命令进行分区,它加载到内存后, 在进行读写时, 还是需要经过高速缓冲,因此, 在内存中存在两份.

####5.2 initramfs

在linux2.5时代, 出现了initramfs, 它的作用和image-initrd相似,但是, 它是将根目录制作成一个cpio(一种简单的文件格式, 通过一个文件头,将所有文件依次组织成一个大文件)文件, 然后使用gzip压缩, 并将压缩后的文件链接进内核中特殊的数据段“.init.ramfs”, 其中全局变量__initramfs_start和__initramfs_end分别指向这个数据段的起始地址和结束地址。内核启动时会对.init.ramfs段中的数据进行解压,然后使用它作为临时的根文件系统。

要制作使用initramfs的内核需要进行配置:

General setup ---> 
[*] Initial RAM filesystem and RAM disk (initramfs/initrd) support 
(/opt/filesystem) Initramfs source file(s) 

其中”/opt/filesystem”就是我们使用的小型根目录的路径其中/opt/filesystem就是我们的小型根目录,这里可以使一个现成的gzip压缩的cpio文件,也可以使一个目录,更可以是txt格式的配置文件,如下面的实例:

dir /dev 755 0 0
nod /dev/console 644 0 0 c 5 1
nod /dev/loop0 644 0 0 b 7 0
dir /bin 755 1000 1000
slink /bin/sh busybox 777 0 0
file /bin/busybox initramfs/busybox 755 0 0
dir /proc 755 0 0
dir /sys 755 0 0
dir /mnt 755 0 0
file /init initramfs/init.sh 755 0 0

如果指定的是一个目录而不是一个像这样的配置文件,内核在编译的时候会从指定的目录创建一个配置文件(usr/Makefile调用scripts/gen_initramfs_list.sh来生成),作为usr/gen_init_cpio.c文件的输入,最后生成一个usr/initramfs_data.cpio.gz文件,通过usr/initramfs_data.S包含到.init.ramfs段中去,最后生成zImage。

####5.3 cpio-initrd

到linux2.6的内核支持两种格式的initrd,即image-initrd和cpio-initrd,此时的cpio-initrd文件已不再编译进内核而单独成一文件,使用cpio工具生成.这里所说的initrd格式和编译进内核的initramfs格式是一样的,都是cpio,也被称为外部initramfs,它是独立存在的,需要bootloader将其加载进内存特定地址,然后将地址和大小传递给内核,在内核的初始化阶段来进行相应的处理。这种initrd可以使用cpio命令来实现,如下:

sudo find /opt/filesystem/ -depth | cpio -c -o > initrd.img 
gzip -9 initrd.img 

这样得到的initrd就是cpio格式的,而且这个文件的大小是可变的,意思就是根据你的filesystem的大小而变化,不会像前面的image格式的initrd那样大小固定了。当然我觉得前面的initramfs的大小也是可变的了