switch_root 命令

在之前讨论过的,当内核初始化完成后会在 initramfs 根目录下查找 init 脚本,这个脚本将会依次执行initramfs根目录下的 hook 中脚本对应函数,这块详细流程已经在 [init脚本] 中说明,这里做一下过程小结(从Linux内核被引导完成开始说起):

  1. 当内核引导完成,此时内核解压缩initramfs,并在其根文件系统中找到init脚本,并运行它。

  2. init脚本首先在initramfs文件系统中挂载内核虚拟文件系统 procsysdev,并设置 dev/ 下软连接

  3. init脚本接下来会解析命令行参数,这个命令行参数是由引导器从linux内核传入的,根据参数设置指定参数

  4. init脚本根据内核参数禁用一些Hook脚本

  5. init脚本执行initramfs根目录hook文件夹中脚本的 run_earlyhook 函数

  6. init脚本根据配置加载指定模块

  7. init脚本执行initramfs根目录hook文件夹中脚本的 run_hook 函数

  8. init脚本开始获取实际文件系统所在的设备UUID

  9. init脚本调用 fsck 检查实际根文件系统是否有损坏,有则修复(这个过程不是必须的,如果内核传入参数希望快速启动则忽略此过程)

  10. init脚本挂载实际根文件系统到 initramfs 中的 /new_root

  11. init脚本执行initramfs根目录hook文件夹中脚本的 run_latehook 函数

  12. init脚本执行initramfs根目录hook文件夹中脚本的 run_cleanuphook 函数

  13. init脚本检测实际根文件系统是否正常挂载到 /new_root

  14. init脚本开始执行switch_root命令,将根文件系统切换到实际根文件系统,并删除initramfs中的根文件系统。

switch_root 程序

switch_root 是一个二进制文件,其接收三个命令行参数,分别是:

  1. 根文件系统路径

  2. init程序

  3. 命令行其它参数

switch_root 命令来自于 util-linux 软件包,具体功能如下:

  1. 从initramfs中卸载内核虚拟文件系统procdevsys

  2. 在新的根目录中挂载内核虚拟文件系统procdevsys

  3. 运行 chdir(newroot) 将运行时路径切换到新的根文件系统中

  4. 调用 mount(newroot, "/", NULL, MS_MOVE, NULL) 将旧的根切到新的根中

  5. 执行 chroot (".")chdir("/") 完成根目录切换

  6. 调用 fork() ,在子程序中判断以前旧的根目录是否是initramfs,如果使得话就删除掉就的文件系统,执行完后子进程退出。

  7. 检查传入 switch_root 中的 init 程序是否存在且可执行(现代系统中这个命令是指向systemd的软连接),可以执行则调用execv执行它,并把传入的命令行参数传入到 init 程序中。

至此,整个系统控制权完全交到了 init 进程中。