为什么需要虚拟根文件系统:
Linux内核加载真正根文件系统执行/sbin/init程序前,需要找到根设备位置,如果根文件系统所在设备需要驱动的支持,内核有可能无能为力,通过提供一个过渡的临时根文件系统可以使得内核的设计更灵活简单.通常过渡的临时根文件系统基本上是内存文件系统.
内核总是能安装ramdisk的(注:这是因为ramdisk临时文件系统和内核一样,也是由bootloader通过低级读写命令(如uboot用nand read,而不用通过文件系统层提供的高级读写接口)加载进内存,因此内核可以挂载内存里ramdisk文件系统),然后把所有可能需要的驱动/模块都放在ramdisk上,首先,让内核将ramdisk当作根文件系统来安装,然后再用这个根文件系统上的驱动来安装真正的根文件系统,就将这个矛盾问题解决了 。
【开辟一块内存作为块设备,并在此块设备被存放虚拟根文件系统,虚拟根文件系统包含:设备驱动、工具、初始化程序等】
作用是完善内核的模块机制,让内核的初始化流程更具弹性;内核以及initrd,都由bootloader在机子启动后被加载至内存的指定位置,主要功能为按需加载模块以及按需改变根文件系统。
【注释】即便你将根文件系统的设备驱动编译到内核中,此时它们还尚未加载,其实所有的Driver是由在后面的Kernel_Init线程进行加载,rootfs文件系统中的初始化函数也再此期间被调用。
虚拟文件系统的种类:
笼统的来说,虚拟的根文件系统包括三种类型,即Initramfs、cpio-initrd和image-initrd。
- Initrd(init ramdisk)一个独立于内核的镜像,uboot加载到内存中,地址:initrd_start;包括cpio-initrd和image-initrd两种。
- Initramfs:和内核编译在一起,通过链接脚本arch/arm/kernel/vmlinux.lds指定,编译到地址区间:__initramfs_start~__initramfs_end。Initramfs也是压缩过后的CPIO文件。资料中提到,Linux2.5中开始引入initramfs,在Linux2.6中一定存在,而且编译的时候通过连接脚本arch/arm/kernel/vmlinux.lds将其编译到__initramfs_start~__initramfs_end,执行完unpack_to_rootfs后将被拷贝到根目录。
【Initrd注释】
Initrd(init ramdisk)文件中包含了各种可执行程序和驱动程序,它们可以用来挂载实际的根文件系统,然后再将这个 initrd RAM磁盘卸载,并释放内存。在很多嵌入式Linux系统中,initrd 就是最终的根文件系统。【百度百科】
内核在运行过程中会解压initrd,然后把 initrd挂载为根目录,然后执行根目录中的/initrc脚本,您可以在这个脚本中运行initrd中的udevd,让它来自动加载设备驱动程序以及 在/dev目录下建立必要的设备节点。在udevd自动加载磁盘驱动程序之后,就可以mount真正的根目录,并切换到这个根目录中。
initrd是一个虚拟的块设备,在上面的例子中,您可是使用fdisk对这个虚拟块设备进行分区。在内核中,对块设备的读写还要经过缓冲区管理模块,也 就是说,当内核读取initrd中的文件内容时,缓冲区管理层会认为下层的块设备速度比较慢,因此会启用预读和缓存功能。这样initrd本身就在内存 中,同时块设备缓冲区管理层还会保存一部分内容。 为了避免上述缺点,于是出现了initramfs,它的作用和initrd类似。
Initrd是在Linux中普遍采用的一种技术,就是由Bootloader加载到内存。在系统启动的过程中,首先会执行Initrd中的“某一个文件” 来完成驱动模块加载的任务,第二阶段才会执行真正的根文件系统中的/sbin/init。这里提到的第一阶段是为第二阶段服务的,主要是用来加载根文件系统以及根文件系统存储介质的驱动程序。
拷贝initrd内容到/dev/ram0 上时文件系统已经被加载,只是没有设置根文件系统,内核的初始化流程还没有进入用户层而已,我们当然不能知道是否有这个设备,但的确是存在的。