[linux kernel] how does the linux kernel mount the root file system

How does the linux kernel finally mount the root file system

1, Past life and present life

In kernel_ Kernel will be called in init thread function_ init_ Freeable() function, in the kernel_init_ Prepare will be called in the freeable function_ The namespace () function mounts the root file system.

[it's a long way to go, mounting begins!!!]

2, kernel_init thread entry

kernel_ The init() function is as follows (/ init/main.c):

static int __ref kernel_init(void *unused)
{
	int ret;

	kernel_init_freeable();
    
	async_synchronize_full();
	free_initmem();
	mark_rodata_ro();
	system_state = SYSTEM_RUNNING;
	numa_default_policy();

	flush_delayed_fput();

	if (ramdisk_execute_command) {
		ret = run_init_process(ramdisk_execute_command);
		if (!ret)
			return 0;
		pr_err("Failed to execute %s (error %d)\n",
		       ramdisk_execute_command, ret);
	}

	if (execute_command) {
		ret = run_init_process(execute_command);
		if (!ret)
			return 0;
		panic("Requested init %s failed (error %d).",
		      execute_command, ret);
	}
	if (!try_to_run_init_process("/sbin/init") ||
	    !try_to_run_init_process("/etc/init") ||
	    !try_to_run_init_process("/bin/init") ||
	    !try_to_run_init_process("/bin/sh"))
		return 0;

	panic("No working init found.  Try passing init= option to kernel. "
	      "See Linux Documentation/init.txt for guidance.");
}

When the execution of line 5 of the above code is completed, the root file system is mounted successfully. The specific execution function is prepared_ The namespace () function is implemented. This function is analyzed below.

Lines 7-8 are used to release the memory allocated during the initialization function call, async_ synchronize_ The full() function is used to synchronize all asynchronous function calls. free_ The initmem() function is used to free the initialized memory space.

3, Heavy character - prepare_namespace

prepare_ The namespace function is defined in the (/ init/do_mounts.c) file as follows:

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 detection of known devices to complete
	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 all asynchronous scan operations 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(100);
		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(".");
}

The above code is essentially three program operation modes:

(1) [method 1]: if root_ device_ If name is the root device of mtd or ubi type, run mount_block_root() mounts the file system.

(2) [method 2]: call initrd_load() mounts the early root file system. If it is mount_ When initrd is true, the root file system mount operation will be performed. The linux kernel contains two mechanisms for mounting the early root file system. Initializing RAM disk (initrd) is an old-fashioned mechanism. Initramfs is a new mechanism for mounting early root file systems. The purpose of initrd and initramfs mechanisms: to execute early user space programs; Load some necessary device drivers before mounting the true (last) root file system.

(3) [method 3]: call mount_ The root () function mounts the file system. This mode is commonly used in the linux kernel. There are three file system mounting modes under this mode: 1. nfs. 2. Floppy mode. 3. block mode. In normal development, nfs is often used to mount the file system on the network for development and debugging.

In the above three ways, in the actual linux startup process, the linux kernel automatically selects one way to mount the root file system.

These three approaches are analyzed below:

[method 1] mount_ block_ The root () function will call do_mount_root() mounts the file system. As shown in the figure below:

[mode 2] file system mount in initrd mode.

[method 3]

For mode 3, mount is called_ The root() function mounts the root file system. The function is defined as follows (/ init/do_mounts.c):

void __init mount_root(void)
{
#ifdef CONFIG_ROOT_NFS
	if (ROOT_DEV == Root_NFS) {
		if (mount_nfs_root())
			return;

		printk(KERN_ERR "VFS: Unable to mount root fs via NFS, trying floppy.\n");
		ROOT_DEV = Root_FD0;
	}
#endif
#ifdef CONFIG_BLK_DEV_FD
	if (MAJOR(ROOT_DEV) == FLOPPY_MAJOR) {
		/* rd_doload is 2 for a dual initrd/ramload setup */
		if (rd_doload==2) {
			if (rd_load_disk(1)) {
				ROOT_DEV = Root_RAM1;
				root_device_name = NULL;
			}
		} else
			change_floppy("root floppy");
	}
#endif
#ifdef CONFIG_BLOCK
	create_dev("/dev/root", ROOT_DEV);
	mount_block_root("/dev/root", root_mountflags);
#endif
}

As can be seen from the above code snippet: mount is in progress_ There are also three methods for root () operation:

(1) NFS mode

adopt mount_nfs_root()Function complete.

(2) ramload mode

adopt rd_load_disk()Function complete.

(3) BLOCK mode

adopt create_dev()and mount_block_root()Two functions complete.

mount_nfs_root () and mount_ block_ Both root () functions call a core function: do_mount_root(),

The function is defined as follows:

static int __init do_mount_root(char *name, char *fs, int flags, void *data)
{
	struct super_block *s;
	int err = sys_mount(name, "/root", fs, flags, data);
	if (err)
		return err;

	sys_chdir("/root");
	s = current->fs->pwd.dentry->d_sb;
	ROOT_DEV = s->s_dev;
	printk(KERN_INFO
	       "VFS: Mounted root (%s filesystem)%s on device %u:%u.\n",
	       s->s_type->name,
	       s->s_flags & MS_RDONLY ?  " readonly" : "",
	       MAJOR(ROOT_DEV), MINOR(ROOT_DEV));
	return 0;
}

In the above code, Sys is called_ Mount() and sys_chdir() system call function.

System call to linux again, Sys_ For mount system call, please refer to this article:
https://blog.csdn.net/kai_ding/article/details/9050429

Xiaosheng has limited knowledge and energy. If there is anything wrong with the article, you are welcome to criticize it or discuss it with Xiaosheng( iriczhao@163.com ). ha-ha!

Keywords: C Linux

Added by markc1 on Thu, 27 Jan 2022 13:11:45 +0200