Linux内核学习(2)启动文件系统

Linux内核学习(2)启动文件系统

参考书籍:《深入理解Linux内核》

(一)文件系统简介
1.文件系统是一个比较广泛的称呼,我们经常把三类不怎么相关但都属于文件系统技术的文件系统弄混淆。
(1)ext1-4 ,jffs1-2 ,yaffs1-2,ubifs,logfs
这一类文件系统描述的是数据在物理设备上存储的机制,比如磁盘中块组的结构。
(2)initrd,initramfs
这一类文件系统描述的是文件系统的装载方式,是装载磁盘上还是内存上。
(3)rootfs,tmpfs,proc
这一类是特殊文件系统的名字,所谓特殊文件系统就是内核将内核中的一种数据结构以文件的方式显示出来,它们是虚拟的没有物理设备与之对应的文件系统。
2.第二个比较容易混淆的是rootfs和根文件系统。
(1)很多人会说rootfs就是根文件系统,但这样说明显是不准确的,根据《深入理解Linux内核》一书中的如下描述,Linux安装根文件系统分为两个步骤,首先安装特殊文件系统rootfs,再在rootfs提供的空目录上安装实际根文件系统。
Linux内核学习(2)启动文件系统
(2)这里有两个关键词,特殊和实际,我们常称呼的根文件系统是实际根文件系统,也就是我们在用户层看得到的根目录所在的文件系统,而且还包括执行应用层程序所需的其它进程、配置,库等等,也即包括/bin,/etc,/lib等等基本目录。而rootfs的根目录不一定会包含这些基本目录,这样我们就可以理清rootfs和根文件系统的关系:rootfs创建的目录作为根文件系统目录时它就是根文件系统,但是rootfs创建的目录还有可能不是根文件系统的目录,当实际根目录文件不是解压到rootfs目录(/),而是rootfs的子目录(/root/),这时我们不能将rootfs叫做根文件系统。之所以用户再看不到rootfs文件系统目录是因为在init阶段执行了chroot操作,也就是rootfs被隐藏了。
(3)还有一些术语也要区分,ramdisk,ramfs,initrd,initramfs。
① ramdisk是一种将内存看成磁盘设备的技术,当我们在linux内核源码里make menuconfig选择支持ramdisk后启动。在/dev下可以看到设备/dev/ram,这时将一块内存区域当做磁盘设备,我们可以通过mount命令将这个磁盘上的文件系统安装到指定目录中。
② initrd是init ramdisk的简称,就是在启动阶段使用此功能,将启动阶段需要的相关驱动和脚本打包到单个文件中,这样能够分离启动环境和运行环境。所以此功能需要支持ramfs(如下图目前的内核4.4.15中已经将这些功能合成了一项)。initrd主要在kernel2.6版本以前的版本使用,编译后会除了vmlinux外还有initrd.img,然后linux启动后会将镜像拷贝到内存中当做一块磁盘。然后将磁盘里面的内容拷贝到rootfs文件系统中执行相关其中的脚本。
③ ramfs是一种和ramdisk类似的技术,同样可以生成处于内存的文件系统。但是ramfs仅处于VFS,也就是没有实际文件系统格式(例如ext)的数据保存在内存上,所以ramfs进行umount后数据会自动删掉,再mount不会看到原数据,而ram disk umount后再mount数据还在。
④ initramfs也就是init ramfs的简称,功能和initrd一样,他们之间的主要区别是initramfs编译后和内核打包在一块,也就是只有一个zImage文件。然后initramfs的压缩格式和initrd不同。
Linux内核学习(2)启动文件系统
3.还有一个术语需要说明一下,我们平常称“从Flash启动设备”、“从网络启动设备”等等,并不是处理器直接从那里读取第一条命令进行启动,而是在内核初始化完毕后执行init程序时从对应设备执行而已。

(二)安装根文件系统
这里可以通过函数调用层次来描述

start_kernel()–>vfs_caches_init()–>init_rootfs() | |
| |–>init_mount_tree()–>set_fs_root() | |
|–>rootfs_initcall()–>populate_rootfs()–>unpack_to_rootfs() |
|–>ramdisk_execute_command() | /prepare_namespace()–>set_fs_root()

1.第一阶段,安装rootfs文件系统,创建根目录(/),创建特殊文件系统rootfs。
2.第二阶段,初始化内核,拷贝initramfs中的文件到rootfs根目录,安装实际根文件系统。
(1)这里populate_rootfs()函数会判断当前目录下是否有init文件,如果没有则将实际根文件系统按照到/root目录,在进入该目录执行set_fs_root使系统根目录改为当前目录。