除了基于initramfs的系统(如第四节的minilinux),通常initramfs都是为安装最终的根文件系统做准备工作,它的最后一步需要安装最终的根文件系统,然后切换到新根文件系统上去。以往的基于ramdisk 的initrd使用pivot_root命令切换到新的根文件系统,然后卸载ramdisk。但是initramfs是rootfs,而rootfs既不能pivot_root,也不能umount。为了从initramfs中切换到新根文件系统,需要作如下处理:
(1)删除rootfs的全部内容,释放空间
find -xdev / -exec rm '{}' ';'
(2)安装新的根文件系统,并切换
cd /newmount; mount --move . /; chroot .
(3)把stdin/stdout/stderr 附加到新的/dev/console,然后执行新文件系统的init程序
上述步骤比较麻烦,而且要解决一个重要的问题:第一步删除rootfs的所有内容也删除了所有的命令,那么后续如何再使用这些命令完成其他步骤?busybox的解决方案是,提供了switch_root命令,完成全部的处理过程,使用起来非常方便。
switch_root命令的格式是:
switch_root [-c /dev/console] NEW_ROOT NEW_INIT [ARGUMENTS_TO_INIT]
其中NEW_ROOT是实际的根文件系统的挂载目录,执行switch_root命令前需要挂载到系统中;NEW_INIT是实际根文件系统的init程序的路径,一般是/sbin/init;-c /dev/console是可选参数,用于重定向实际的根文件系统的设备文件,一般情况我们不会使用;而ARGUMENTS_TO_INIT则是传递给实际的根文件系统的init程序的参数,也是可选的。
需要特别注意的是:switch_root命令必须由PID=1的进程调用,也就是必须由initramfs的init程序直接调用,不能由init派生的其他进程调用,否则会出错,提示:
switch_root: not rootfs
也是同样的原因,init脚本调用switch_root命令必须用exec命令调用,否则也会出错,提示:
switch_root: not rootfs
二十一、实践:用initramfs安装CLFS根文件系统
现在实践一下switch_root命令,用它切换一个CLFS的根文件系统硬盘分区。我的CLFS安装在/dev/sda8硬盘分区,我们就以此为例说明。
我们还是在以前的image目录中构建
(1)改写init脚本
#!/bin/sh
mount -t proc proc /proc
mount -t sysfs sysfs /sys
mdev -s
mount /dev/sda8 /mnt (注意:为了简单,我们直接把CLFS分区写死在init脚本中了)
exec switch_root /mnt /sbin/init
(2)生成新的initrd
按上一节“精通initramfs构建step by step (五):initrd”描述的cpio命令生成新的initrd。
(3)把新的initrd拷贝到CLFS分区的/boot目录下,改名为clfs-initrd
(4)在GRUB的menu.lst配置文件中增加一个启动项
#test for initramfs of CLFS
title test for initramfs of CLFS (on /dev/sda8)
root (hd0,7)
kernel /boot/clfskernel-2.6.17.13 (注意:并没有向内核传递root参数信息)
initrd /boot/clfs-initrd
全部做完后,重启机器,选择 test for initramfs of CLFS 启动项,机器顺利进入了CLFS系统,我们构建的initramfs用switch_root命令完成了CLFS实际根文件系统的安装和切换。
---下节预告---
在这节里我们直接使用了CLFS本身的内核,它已经包含了CLFS根文件系统的硬盘驱动和文件系统驱动,所以可以顺利地安装CLFS的根文件系统。实际上,initramfs的最重要的功能就是包含大量的硬盘驱动和文件系统驱动,而不需要把所有的驱动程序编译进内核,减少内核大小。initramfs负责在安装实际根文件系统前根据具体的文件系统设备情况加载合适的驱动到内核中,使系统能够正常安装实际的根文件系统。