执行init程序
一、目的
内核加载完initrd文件后,为挂载磁盘文件系统做好了必要的准备工作,包括挂载了sysfs、proc文件系统,加载了磁盘驱动程序驱动程序等。接下来,内核跳转到用户空间的init程序,由init完成创建磁盘设备文件、加载磁盘文件系统、从rootfs切换到磁盘根文件系统等工作。
由于在不同的linux发行版中,init的实现方式差异很大,不能将所有的发行版都分析一遍,因此本文选取ubuntu12.04发行版来描述如何从rootfs切换到磁盘根文件系统。
二、创建磁盘设备文件
init程序使用udev工具动态的创建磁盘设备文件。udev的工作原理是根据sysfs中的设备信息,在/dev目录下创建相应的设备文件,因此需要提前准备好sysfs文件系统。
首先,创建必要的挂载点目录/dev、/root、/sys、/proc等;然后,将VFS中的sysfs挂载到rootfs的/sys目录下,将tmpfs挂载到/dev目录下(/dev的文件系统类型为tmpfs);最后,为了输出打印信息,创建了/dev/console、/dev/null两个特殊的设备文件。
这些必要信息准备好后,就可以启动udev后台进程,由udev根据sysfs动态的创建磁盘设备文件。Udev启动代码在scripts/init-top/udev中。
三、挂载磁盘文件系统
磁盘文件系统的挂载一般有两种方式:本地方式和网络方式。根据BOOT变量的值,init选择执行本地加载或者网络加载,如果是本地加载则执行/scripts/local脚本;如果是网络加载则执行/scripts/nfs脚本。个人pc一般都是本地加载,数据中心的服务器一般是nfs加载。
最后,由init程序调用/scripts/local脚本挂载磁盘文件系统。
四、切换根文件系统
成功挂载磁盘文件系统后,需要将rootfs下的/sys、/proc、/dev等重要的目录都迁移到磁盘文件系统下。
最后,通过调用/sbin/run-init程序将内核的根文件系统从rootfs切换到磁盘文件系统的根目录。
五、最终VFS视图
到此为止,内核文件系统初始化过程就全部完成了,下面给出最终的VFS视图(由于文件系统过大,因此只给出其中关键的拓扑结构):
六、总结
init程序的主要工作就是加载磁盘文件系统,将rootfs下重要的目录迁移到磁盘文件系统下,最后将内核根目录从rootfs切换到磁盘文件系统的根目录。
Linux根文件系统介绍
根文件系统首先是一种文件系统,但是相对于普通的文件系统,它的特殊之处在于,它是内核启动时所mount的第一个文件系统,内核代码映像文件保存在根文件系统中,而系统引导启动程序会在根文件系统挂载之后从中把一些基本的初始化脚本和服务等加载到内存中去运行。
我们首先从主机上所安装的Linux操作系统中了解一些根文件系统的信息。比如在笔者工作的Linux桌面系统中可以得到下面的结果:
# mount
/dev/hda2 on / type ext3 (rw)
none on /proc type proc (rw)
/dev/hda1 on /boot type ext3 (rw)
none on /dev/pts type devpts (rw,gid=5,mode=620)
none on /dev/shm type tmpfs (rw)
# df
Filesystem 1K-blocks Used Available Use% Mounted on
/dev/hda2 16216016 5667* 9724600 37% /
/dev/hda1 101089 9321 8*9 10% /boot
none 63028 0 63028 0% /dev/shm
从上面的mount命令我们可以看到,在桌面Linux中,根文件系统”/”被mount到/dev/hda2设备上,文件系统类型为ext3,属性为rw即可读写。从df命令则可以得到更多根文件系统使用空间的相关信息。
根文件系统一直以来都是所有类Unix操作系统的一个重要组成部分,也可以认为是嵌入式Linux系统区别于其他一些传统嵌入式操作系统的重要特征,它给Linux带来了许多强大和灵活的功能,同时也带来了一些复杂性。我们需要清楚的了解根文件系统的基本结构,以及细心的选择所需要的系统库、内核模块和应用程序等,并配置好各种初始化脚本文件,以及选择合适的文件系统类型并把它放到实际的存储设备的合适位置。
根文件系统的基本目录结构
Linux的根文件系统以树型结构组织,包含内核和系统管理所需要的各种文件和程序,一般说来根目录”/”下的顶层目录都有一些比较固定命名和用途。
下面列出了一个Linux根文件系统中的比较常见的目录结构:
/bin 存放二进制可执行命令的目录
/dev 存放设备文件的目录
/etc 存放系统管理和配置文件的目录
/home 用户主目录,比如用户user的主目录就是/home/user,可以用~user表示
/lib 存放动态链接共享库的目录
/sbin存放系统管理员使用的管理程序的目录
/tmp 公用的临时文件存储点
/root 系统管理员的主目录
/mnt 系统提供这个目录是让用户临时挂载其他的文件系统。
/proc 虚拟文件系统,可直接访问这个目录来获取系统信息。
/var 某些大文件的溢出区
/usr 最庞大的目录,要用到的应用程序和文件几乎都在这个目录。
对于经常使用Linux系统的读者来说,这些目录大部分应该很熟悉了。不过有几个目录对初学者来说容易混淆,如/bin,/sbin,/usr/bin和/usr/sbin。这里简单介绍一下它们的区别:/bin目录一般存放对于用户和系统来说都是必须的二进制文件,而/sbin目录要存放的是只针对系统管理的二进制文件,该目录的文件将不会被普通用户使用。相反,那些不是必要的用户二进制文件存放在/usr/bin下面,那些不是非常必要的系统管理工具放在/usr/sbin下。此外,对于一些本地的库也非常类似,对于那些要求启动系统和运行的必须命令要存放在/lib目录下,而对于其他不是必须的库存放在/usr/lib目录就可以。
对于嵌入式Linux系统的根文件系统来说,一般可能没有上面所列出的那么复杂,比如嵌入式系统通常都不是针对多用户的,所以/home这个目录在一般嵌入式Linux中可能就很少用到,而/boot这个目录则取决于你所使用的BootLoader是否能够重新获得内核映象从你的根文件系统在内核启动之前。一般说来,只有/bin,/dev,/etc,/lib,/proc,/var,/usr这些需要的,而其他都是可选的。
简单的来说,根文件系统包括虚拟根文件系统和真实根文件系统。在Kernel启动的初始阶段,首先去创建虚拟的根文件系统,接下来再去调用do_mount来加载真正的文件系统,并将根文件系统切换到真正的文件系统,也即真实的文件系统。
一.什么是根文件系统
在传统的Windows机器上目录结构中,可能会包括C:或者D:盘,而他们一般就称之为特定逻辑磁盘的根目录。从文件系统的层面来说,每一个分区都包含了一个根目录区,也即系统中存在多个根目录。
但是,在Linux系统中,目录结构与Windows上有较大的不同。系统中只有一个根目录,路径是“/”,而其它的分区只是挂载在根目录中的一个文件夹,如“/proc”和“system”等,这里的“/”就是Linux中的根目录。
对应根目录也就存在一个根目录文件系统的概念,我们可以将某一个分区挂载为根目录文件系统,如6410公版中就将mtdblk2挂载为根目录文件系统。程序中可以通过U-Boot给Kernel指定参数或者编译选项来指定,如目前的开发板中就通过如下的编译选项来制定根目录文件系统:
CONFIG_CMDLINE="console=ttyS0,115200 mem=108M rdinit=/linuxrc root=/dev/mtdblock2" |
简单的来说,根目录文件系统就是一种目录结构,包括了Linux启动的时候所必须的一些目录结构和重要文件。
根文件系统有两种,一种是虚拟根文件系统,另外一种是真实的根文件系统。一般情况下,会首先在虚拟的根文件系统中做一部分工作,然后切换到真实的根文件系统下面。
笼统的来说,虚拟的根文件系统包括三种类型,即Initramfs、cpio-initrd和image-initrd。