Linux vfs流程分析 阶段二:安装实际根文件系统

1 安装实际根文件系统整体流程

Linux版本:linux4.14

上篇文章说道:vfs 在初始化阶段安装了一个基于 ramfs 的rootfs,该文件系统仅提供一个作为初始安装点的空目录。

这里有个疑问?为什么内核不怕麻烦,要在安装实际根文件系统之前安装 rootfs 文件系统呢?我们知道, rootfs 文件系统允许内核容易地改变实际根文件系统。事实上,在某些情况下,内核逐个地安装和卸载几个根文件系统。例如,一个发布版的初始启动光盘可能把具有一组最小驱动程序的内核装入RAM中,内核把存放在 ramdisk 中的一个最小的文件系统最为根安装。接下来,在这个初始根文件系统中的程序探测系统的硬件(例如,它们判断硬盘是否是EIDE、SCSI等等),装入所有必须的内核模块,并从物理块设备重新安装根文件系统。ps:摘自深入理解LINUX内核

start_kernel()
|----rest_init()
	|----kernel_thread(kernel_init, NULL, CLONE_FS)
		|----kernel_init()
			|----kernel_init_freeable()
				|----prepare_namespace()
					|----mount_root()
					|----sys_mount()
					|---sys_chroot()

整体流程如上,挂载实际的根文件系统的动作在 prepare_namespace() 函数中,之前的函数暂不分析。

2 prepare_namespace()

void __init prepare_namespace(void)
{
	int is_floppy;

	if (root_delay) {
		printk(KERN_INFO "Waiting %d sec before mounting root device...\n",
		       root_delay);
		ssleep(root_delay);
	}

	/*
	 * wait for the known devices to complete their probing
	 *
	 * Note: this is a potential source of long boot delays.
	 * For example, it is not atypical to wait 5 seconds here
	 * for the touchpad of a laptop to initialize.
	 */
	wait_for_device_probe();

	md_run_setup();

	if (saved_root_name[0]) {
		root_device_name = saved_root_name;
		if (!strncmp(root_device_name, "mtd", 3) ||
		    !strncmp(root_device_name, "ubi", 3)) {
			mount_block_root(root_device_name, root_mountflags);
			goto out;
		}
		ROOT_DEV = name_to_dev_t(root_device_name);
		if (strncmp(root_device_name, "/dev/", 5) == 0)
			root_device_name += 5;
	}

	if (initrd_load())
		goto out;

	/* wait for any asynchronous scanning to complete */
	if ((ROOT_DEV == 0) && root_wait) {
		printk(KERN_INFO "Waiting for root device %s...\n",
			saved_root_name);
		while (driver_probe_done() != 0 ||
			(ROOT_DEV = name_to_dev_t(saved_root_name)) == 0)
			msleep(5);
		async_synchronize_full();
	}

	is_floppy = MAJOR(ROOT_DEV) == FLOPPY_MAJOR;

	if (is_floppy && rd_doload && rd_load_disk(0))
		ROOT_DEV = Root_RAM0;

	mount_root();
out:
	devtmpfs_mount("dev");
	sys_mount(".", "/", NULL, MS_MOVE, NULL);
	sys_chroot(".");
}
  • 把 root_device_name 变量置为从启动参数 “root” 中获取的设备文件名。同样,把 ROOT_DEV 变量置位同一设备文件的主设备号和次设备号。

  • 调用 mount_root() 函数,依次执行如下操作。

    • 根据 ROOT_DEV 在 之前挂载的 rootfs 文件系统中创建设备文件 /dev/root。

    • 调用 mount_block_root() 将实际的根文件系统(/dev/root)挂载到 /root 目录下。

      • 调用 sys_mount() 执行挂载动作。
      • 挂载完成,调用 sys_chdir("/root") 改变进程的当前目录。
  • 调用 sys_mount(".", “/”, NULL, MS_MOVE, NULL) 将实际根文件系统从当前目录("/root")移动到根目录下(“/”)。

  • 调用 sys_chroot(".") 改变进程的根目录为当前目录,也就是 “/” 。

注意:rootfs 特殊文件系统没有被卸载,它只是隐藏在基于磁盘的根文件系统下了。

你可能感兴趣的:(linux)