在Kernel启动的初始阶段,首先去创建虚拟的根文件系统,接下来再去调用do_mount来加载真正的文件系统,并将根文件系统切换到真正的文件系统,也即真实的文件系统。笼统的来说,虚拟的根文件系统包括三种类型,即Initramfs、cpio-initrd和image-initrd。
Initrd是在Linux中普遍采用的一种技术,就是由Bootloader加载的内存盘。在系统启动的过程中,首先会执行Initrd中的“某一个文件” 来完成驱动模块加载的任务,第二阶段才会执行真正的根文件系统中的/sbin/init。这里提到的第一阶段是为第二阶段服务的,主要是用来加载根文件系统以及根文件系统存储介质的驱动程序。 资料中提到,存在多种类型的Initrd,实际应用中包括无Initrd、Linux Kernel和Initrd打包、Linux Kernel和Initrd分离以及RAMDisk Initrd(在系统启动的时候,U-Boot会将Linux Kernel和Rootfs加载到内存,并跳转到Linux Kernel的入口地址执行程序)。
为什么不直接把真实的文件系统配置为根文件系统? 答案很简单,内核中没有根文件系统的设备驱动,如USB等存放根文件系统的设备驱动,而且即便你将根文件系统的设备驱动编译到内核中,此时它们还尚未加载,其实所有的Driver是由在后面的Kernel_Init线程进行加载。所以需要CPIO Initrd、Initrd和RAMDisk Initrd。另外,我们的Root设备都是以设备文件的方式指定的,如果没有根文件系统,设备文件怎么可能存在呢?
什么是 Initrd:initrd 的英文含义是 bootloader initialized RAM disk,就是由 bootloader 初始化的内存盘。在 linux内核启动前, bootloader 会将存储介质中的 initrd 文件加载到内存,内核启动时会在访问真正的根文件系统前先访问该内存中的 initrd 文件系统。在 bootloader 配置了 initrd 的情况下,内核启动被分成了两个阶段,第一阶段先执行 initrd 文件系统中的”某个文件”,完成加载驱动模块等任务,第二阶段才会执行真正的根文件系统中的 /sbin/init 进程。
rootfs: 一个基于内存的文件系统,是linux在初始化时加载的第一个文件系统,。
initramfs: Initramfs是在 kernel 2.5中引入的技术,实际上它的含义就是:在内核镜像中附加一个cpio包,这个cpio包中包含了一个小型的文件系统,当内核启动时,内核将这个cpio包解开,并且将其中包含的文件系统释放到rootfs中,内核中的一部分初始化代码会放到这个文件系统中,作为用户层进程来执行。这样带来的明显的好处是精简了内核的初始化代码,而且使得内核的初始化过程更容易定制。Linux 2.6.12内核的 initramfs还没有什么实质性的东西。 cpio-initrd: 指linux2.6内核使用的cpio格式的initrd。 image-initrd: 专指传统的文件镜像格式的initrd。 realfs: 用户最终使用的真正的文件系统。
linux2.6 内核对 cpio-initrd和 image-initrd 这两种格式的 initrd 均支持,但对其处理流程有着显著的区别,下面分别介绍 linux2.6 内核对这两种 initrd 的处理流程。 cpio-initrd 的处理流程 1. boot loader 把内核以及 initrd 文件加载到内存的特定位置。 2. 内核判断initrd的文件格式,如果是cpio格式。 3. 将initrd的内容释放到rootfs中。 4. 执行initrd中的/init文件,执行到这一点,内核的工作全部结束,完全交给/init文件处理。
image-initrd的处理流程 1. bootloader把内核以及initrd文件加载到内存的特定位置 2. 内核判断initrd的文件格式,如果不是cpio格式,将其作为image-initrd处理。 3. 内核将initrd的内容保存在rootfs下的/initrd.image文件中。 4. 内核将/initrd.image的内容读入/dev/ram0设备中,也就是读入了一个内存盘中。 5. 接着内核以可读写的方式把/dev/ram0设备挂载为原始的根文件系统。 6. .如果/dev/ram0被指定为真正的根文件系统,那么内核跳至最后一步正常启动。 7. 执行initrd上的/linuxrc文件,linuxrc通常是一个脚本文件,负责加载内核访问根文件系统必须的驱动, 以及加载根文件系统。 8. /linuxrc执行完毕,常规根文件系统被挂载 9. 如果常规根文件系统存在/initrd目录,那么/dev/ram0将从/移动到/initrd。否则如果/initrd目录不存在, /dev/ram0将被卸载。 10. 在常规根文件系统上进行正常启动过程 ,执行/sbin/init。
Linux内核加载根文件系统执行/sbin/init程序前,需要找到根设备位置,如果根设备需要驱动的支持,内核有可能无能为力,通过提供一个过渡的临时根文件系统可以使得内核的设计更灵活简单.通常过渡的临时根文件系统基本上是内存文件系统.
常见的内存文件系统有:
rootfs,ramfs(initramfs),ramdisk(initrd),tmpfs
-
rootfs:内核启动的初始始根文件系统,大部分linux系统正常运行后都会安装另外的文件系统,然后忽略rootfs
-
ramfs:基于内存的文件系统.ramfs文件系统没有容量大小的限制,它可以根据需要动态增加容量.直接利用了内核的磁盘高速缓存
-
ramdisk:基于ram的块设备,占据一块固定的内存,事先要使用特定的工具比如mke2fs格式化,还需要一个文件系统驱动来读写其上的文件空间固定导致容量有限,要想装入更多的文件需要重新格式化.Linux的块设备缓冲特性, ram disk上的数据被拷贝到page cache(对于文件数据)和dentry cache(对于目录项),导致内存浪费,它可能不停的动态增长直到耗尽系统的全部内存,所以只有root或授权用户允许使用ramfs
-
tmpfs:增加了容量大小的限制 + 允许把数据写入交换分区.由于增加了这两个特性,tmpfs允许普通用户使用
过渡根文件系统机制:将加载真正的根文件系统需要的设备驱动、工具以及初始化程序先加载到内存运行.
-
initrd: initial Ramdisk /linuxrc文件,基于ramdisk技术,文件系统(ext2等)镜像文件 ————> cpio格式镜像文件 在内核启动完成后把它复制到/dev/ram块设备中, 作为内核加载真正根文件系统的过渡根文件系统
-
initramfs: initial RAM file system init文件,cpio格式镜像文件 在内核启动完成后把它复制到rootfs中,作为内核初始的根文件系统,完成挂载系统真正的根文件系统
内核文件和根文件系统在Flash 中的放置,可以根据系统设计需要适当选择:
模式选择 | 优点 | 缺点 |
内核和根文件系统放在固定偏移地址单元(单独分区) | 适用于主要系统成员地址单元固定,易于引导程序( Bootloader)加载和分别升级内核和根文件系统 | 在内核和根文件系统之间不可避免要浪费Flash 空间 |
根文件系统紧跟内核放置(不单独分区) | 节省Flash 存储空间 | 内核文件和根文件系统合二为 一,单独升级不够方便 |
内核和根文件系统压缩放置 | 节省大量的Flash 存储空间,可选择压缩放置内核或根文件系统 | 系统需要引导程序(Bootloader)和RAM 支持 |