initramfs 製作方式

Linux kernel在自身初始化完成之后,需要能够找到并运行第一个用户程序(这个程序通常叫做“init”程序)。用户程序存在于文件系统之中,因此,内核必须找到并挂载一个文件系统才可以成功完成系统的引导过程。

在 grub中提供了一个选项“root=”用来指定第一个文件系统,但随着硬件的发展,很多情况下这个文件系统也许是存放在USB设备,SCSI设备等等多 种多样的设备之上,如果需要正确引导,USB或者SCSI驱动模块首先需要运行起来,可是不巧的是,这些驱动程序也是存放在文件系统里,因此会形成一个悖 论。

为 解决此问题,Linux kernel提出了一个RAM disk的解决方案,把一些启动所必须的用户程序和驱动模块放在RAM disk中,这个RAM disk看上去和普通的disk一样,有文件系统,有cache,内核启动时,首先把RAM disk挂载起来,等到init程序和一些必要模块运行起来之后,再切到真正的文件系统之中。

上 面提到的RAM disk的方案实际上就是initrd。 如果仔细考虑一下,initrd虽然解决了问题但并不完美。 比如,disk有cache机制,对于RAM disk来说,这个cache机制就显得很多余且浪费空间;disk需要文件系统,那文件系统(如ext2等)必须被编译进kernel而不能作为模块来 使用。

Linux 2.6 kernel提出了一种新的实现机制,即initramfs。顾名思义,initramfs只是一种RAM filesystem而不是disk。initramfs实际是一个cpio归档,启动所需的用户程序和驱动模块被归档成一个文件。因此,不需要 cache,也不需要文件系统。

 

I. initramfs

详细的initramfs的资料可以参考如下:

(1) 黃敬群先生的blog:深入理解 Linux 2.6 的 initramfs 機制

http://blog.linux.org.tw/~jserv/archives/001954.html

(2) initramfs, a new model for initial RAM

http://www.linuxdevices.com/articles/AT4017834659.html

 

下面是一些使用initramfs的简单帮助

1. 查看initramfs的内容

# mkdir temp ; cd temp # cp /boot/initrd.img-2.6.24-16 initrd.img-2.6.24-16.gz # gunzip initrd.img-2.6.24-16.gz # cpio -i --make-directories < initrd.img-2.6.24-16

2. 创建initramfs

命令:mkinitramfs, update-initramfs

1) mkinitramfs

# mkinitramfs -o /boot/initrd.img 2.6.24-16

Note: 2.6.24-16是需要创建initramfs的kernel版本号,如果是给当前kernel制作initramfs,可以用uname -r查看当前的版本号。提供kernel版本号的主要目的是为了在initramfs中添加指定kernel的驱动模块。mkinitramfs会把 /lib/modules/${kernel_version}/ 目录下的一些启动会用到的模块添加到initramfs中。

2)update-initramfs

更新当前kernel的initramfs

# update-initramfs -u

在添加模块时,initramfs tools只会添加一些必要模块,用户可以通过在/etc/initramfs-tools/modules文件中加入模块名称来指定必须添加的模块。

 

II. initrd

目前还是有不少Linux发行版采用initrd(即RAM disk的方式)来实现引导,所以了解一下mkinitrd这个命令也很有必要。

 

mkinitrd类似于mkinitramfs,是用于生成initrd的一个工具。最基本的用法参考下面:

#mkinitrd /boot/initrd.img $(uname -r)

如 果需要指定哪些module在启动时必须load,需要加上--preload=module或者 --with=module这样的选项。 这两者的区别在于--preload指定的module会在/etc/modprobe.d/* 里声明的任何SCSI模块之前被加载,--with指定的module会在/etc/modprobe.d/* 里声明的任何SCSI模块之后被加载。

另 外还有一个选项需要被注意,即--builtin=module。在manual里这个选项的解释是:Act as if module is built into the kernel being used. mkinitrd will not look for this module, and will not emit an error if it does not exist. This option may be used multiple times.

根 据上面的解释,可以看出builtin选项另外还有一个取巧的用处。以我所用的平台Acer Aspire One为例, 我在用mkinitrd制作RAM disk镜像是出现一个错误“No module ohci-hcd found ...”,遇到这个情况,builtin选项就起作用了,用--builtin=ohci-hcd, mkinitrd就可以忽略ohci-hcd不存在这个事实了。


Linus 本人在 Linux 2.6 時代所提出的 "initramfs" 是一種更好的 "root=" 做法。在這裡先不對 initramfs 做詳細介紹與原由說明,不過,簡單來說,initramfs 就是「kernel 2.6 的 initrd」。Initrd(initial ramdisk)即 /dev/ram0,是一種普遍使用在 embedded Linux 的觀念;embedded Linux 利用 initrd 來載入 root filesystem(或是 bootstrap root filesystem 後再以 NFS 掛進完整 RFS)。

本日記介紹製作 Linux 2.6 的 initramfs 簡易方法。假設 RFS 的目錄為 /home/rootfs,則製作 initramfs 的指令為:

# cd /home/rootfs
# find . | cpio -o -H newc | gzip -9 >../cramfs.gz

更 明確地說,initramfs 是 "compressed" ramfs(ram filesystem),ramfs 並不等於傳統的 ramdisk;像是以 "genext2fs" 工具所製作的 initrd(ext2 格式的 image file)才是基於 ramdisk 的傳統做法,也就是說,initramfs 並不等於傳統上的 initrd,這點要請大家多留意。



我 们知道:boot loader装入kernel,然后kernel需要执行/sbin/init,读取这个文件就必须先mount根文件系统,早期是通过启动时的 root="参数"告诉内核根文件系统在哪个设备上,随着硬件和技术的发展,现在根文件系统可能位于一个网络存储如NFS上,可能由于RAID而散布于多 个设备上,可能位于一个加密设备上需要提供用户名和密码,这时root="参数"就显得不够了。为了应付这种局面,先后出现两种机制来作为boot loader装载kernel到真正的/sbin/init执行这个启动过程的桥梁: initrd和nitramfs

我们在一天一点学习Linux之RHEL6的开机流程分析(http://www.opsers.org/2010_12_1518.html)中讲到,RHEL6已经启用了新的模式:用initramfs代替了initrd。下面我们就来了解一下这两个的区别:

initrd: 
ram disk是一个基于ram的块设备,因此它占据了一块固定的内存,而且事先要使用特定的工具比如mke2fs格式化,还需要一个文件系统驱动来读写其上的 文件。如果这个disk上的空间没有用完,这些未用的内存就浪费掉了,并且这个disk的空间固定导致容量有限,要想装入更多的文件就需要重新格式化。由 于Linux的块设备缓冲特性,ram disk上的数据被拷贝到page cache(对于文件数据)和dentry cache(对于目录项),这个也导致内存浪费。 
initramfs: 
最 初的想法是Linus提出的: 把cache当作文件系统装载。 他在一个叫ramfs的cache实现上加了一层很薄的封装,其它内核开发人员编写了一个改进版tmpfs, 这个文件系统上的数据可以写出到交换分区,而且可以设定一个tmpfs装载点的最大尺寸以免耗尽内存。initramfs就是tmpfs的一个应用。 Linux 2.6 kernel提出了这种新的实现机制,即initramfs。顾名思义,initramfs只是一种RAM filesystem而不是disk。

initramfs的优点: 
      (1)tmpfs随着其中数据的增减自动增减容量。 
      (2)在tmpfs和page cache/dentry cache之间没有重复数据。 
      (3)tmpfs重复利用了Linux caching的代码,因此几乎没有增加内核尺寸,而caching的代码         已经经过良好测试,所以tmpfs的代码质量也有保证。 
      (4)不需要额外的文件系统驱动。 
另 外,initrd机制被设计为旧的"root="机制的前端,而非其替代物,它假设真正的根设备是一个块设备,而且也假设了自己不是真正的根设备,这样不 便将NFS等作为根文件系统,最后/linuxrc不是以PID=1执行的,因为1这个进程ID是给/sbin/init保留的。initrd机制找到真 正的根设备后将其设备号写入/proc/sys/kernel/real-root-dev,然后控制转移到内核由其装载根文件系统并启动/sbin /init.initramfs则去掉了上述假设,而且/init以PID=1执行,由init装载根文件系统并用exec转到真正的/sbin /init,这样也导致一个更为干净漂亮的设计。

你可能感兴趣的:(initramfs 製作方式)