在最近的在线课程中,一位 RHEL/CentOS 讲师提到了以下内容:
然后引导加载程序执行内核。在内核阶段,内核将 ramdisk 加载到内存中。该 ramdisk 用作临时根文件系统。该文件系统包括内核模块、驱动程序,甚至可能包括启动文件。随后,内核卸载 ramdisk,并将根文件系统挂载到硬盘上。然后,通过执行第一个进程开始初始化阶段。在初始化阶段,祖父进程运行。在旧版本的 Red Hat 中,这是 Init 进程。
这对我来说似乎是倒退的。内核在整个过程中不需要一些可用的文件系统吗?上面突出显示的行表明,有一个短暂的时刻,绝对没有文件系统在运行。
答案1
引导加载程序是否会卸载 ramdisk [...]?
不。
随后,内核卸载 ramdisk,并将根文件系统挂载到硬盘上。然后,通过执行第一个进程开始初始化阶段。
这是错误的。
initramfs 包含一个名为 的程序/init
。该程序被执行,并且是第一个(用户)进程虽然 initramfs 仍然存在。事实上,正是这个程序触发了任何正在进行的卸载。
这是/init
Debian 9 Linux 上使用的程序。费多拉有名为 Dracut 的类似系统。正如您所看到的,该脚本加载模块,运行钩子,安装最终的根文件系统,最后用run-init
klibc-utils 包中的程序覆盖自身。 (早期版本使用run-init
或switch_root
根据可用内容。) Dracut 仍在使用switch_root
。此时的德拉卡特已经产生了一个完整的systemd-udevd
子系统它运行并自动检测设备,并为这些设备运行守护进程并安装卷。 DASD生成的守护进程systemd-udevd
继续与 并行运行switch_root
。
该run-init
程序依次删除 initramfs 的内容,chroot
将其自身添加到新的根文件系统,打开其/dev/console
,并用init
该文件系统上的任何程序覆盖自身init
,它从内核命令行上命名的变量或/init
第一个程序假定的该变量的默认值。 switch_root
尽管有一些细微的差别,但其作用大致相同。 Dracut 向其传递init
程序的名称它同样是从内核命令行获得的。
如你看到的,两者都不内核也不引导加载程序会触发其中任何一个。当程序/init
作为进程 #1 启动时,引导加载程序已经完全脱离了画面,内核只是执行该/init
程序、它生成的挂钩中的程序以及它覆盖自身的另外两个程序,告诉它。
不,有不在此过程中,从进程 #1 使用 initramfs 中的程序启动的那一刻起/init
,可能没有安装任何文件系统。始终至少有一个进程在运行,并且该进程必须有一个工作目录、一个根目录和一个程序映像文件,所有这些都必须引用已安装卷中的 vnode某处。
您会发现,只有当最后一个安装点从其上移走并且最后一个使用它的进程(如每个进程的当前目录、每个进程的根目录或程序映像文件)消失时,原始的 initramfs 才会消失 -或者,asrun-init
和switch_root
do,将工作目录和根目录切换到其他卷,并用来自其他卷的文件中的程序映像覆盖自身。请注意,systemd 人员考虑了 initramfs 实际上根本不会消失的可能性,因为有一个程序从该卷的映像运行,并且在系统的生命周期中仍然存在。
所以实际发生的情况是,原始的 initramfs 和最终的根文件系统都是两个都存在于该过程中的某个时刻,并且实际上可能从那时起。远非有一个点零根文件系统,有一个点多种的root 文件系统,然后(随着对 initramfs 的引用消失)它再次下降到 1。 (请注意/proc
,/sys
、/dev
、/run
、/dev/shm
、 和的文件系统在/运行/dev/pts
时存在,因此run-init
switch_root
全部的在整个引导过程中,已安装文件系统(根文件系统和其他文件系统)的计数始终远高于 2。)
进一步阅读
- 哈拉尔德·霍耶 (2013-10)。德拉库特。 3.0版本。 kernel.org。
- 伦纳特·珀特林等人。 (2013)。 根文件系统的 systemd 和存储守护进程。 freedesktop.org。
答案2
正在运行的内核不会需要安装的文件系统超出了它需要配置的网络接口的范围 - 当然,除非它(或内核下运行的某些代码,例如进程init
)当时正在积极使用它们,而从临时 rootfs 到真实 rootfs。
请记住,从内核首次启动到安装 initrd(或者实际的 rootfs,如果不使用 initrd),内核并没有安装文件系统。这种情况发生在初始硬件探测以及设备和驱动程序初始化之后一段时间。