Linux rootfs挂载过程

本文详细介绍了Linux内核在启动过程中如何挂载rootfs,包括initrd、initramfs和default三种方式。通过u-boot加载ramdisk.cpio.gz,内核解压并执行启动脚本,挂载真实rootfs。同时讲解了内核如何处理内嵌的ramfs.cpio,并挂载磁盘上的rootfs。整个过程涉及解压、注册rootfs、挂载等关键步骤。
摘要由CSDN通过智能技术生成

Linux内核如何挂载rootfs,取决于u-boot的环境变量:

u-boot先load一个ramdisk.cpio.gz

initrd=${ramdisk_addr} root=/dev/ram rw rdinit=/etc/init.sh 

kernel解压内嵌的.cpio

root=/dev/mmcblk1p2 rw rootfstype=ext4 

总得来说,有3种挂载方式:

1 、initrd (CONFIG_BLK_DEV=y)有 rdinit

u-boot先从SD卡或EMMC load一个ramdisk.cpio.gz压缩包,内核启动时解压它,把它释放到rootfs(已注册)作为 / ,根据"rdinit="执行启动脚本。启动脚本会指引如何挂载真实的rootfs(在EMMC上的)。

2 、initramfs (CONFIG_BLK_DEV=y)无 /init

kernel启动时解压__initramfs_start段的.cpio压缩包(内核自动生成,只包含 / ,/dev , /root ,/dev/console),因为无/init,会执行挂载EMMC上的真实rootfs。

3 、default (CONFIG_BLK_DEV=n)

kernel 调用default_rootfs创建(/ , /dev , /root , /dev/console), 不解压.cpio

挂载流程

start_kernel()->

在RAM上建立 / ,挂载rootfs

vfs_caches_init()->

sysfs_init();

init_rootfs();

这一步会注册rootfs(如指定"root="则为ramfs)

init_mount_tree()->

mnt = vfs_kern_mount(&rootfs_fs_type, 0, “rootfs”, NULL);

set_fs_pwd(current->fs, &root);

set_fs_root(current->fs, &root);

释放内核中的ramfs.cpio到 /

内核在编译时会生产一个ramfs的压缩包,这个压缩包中包含 / /dev /root /dev/console,由默认gen_initramfs.sh文件生成,生成的 .cpio为 initramfs_data.cpio 。具体操作:

1 、从__initramfs_start段读出initramfs_data.cpio,释放到rootfs

2 、该压缩包已经包含 /dev /dev/console /root,由 default_cpio_list 配置

static int __init populate_rootfs(void)
{
	/* Load the built in initramfs */
	char *err = unpack_to_rootfs(__initramfs_start, __initramfs_size);
	if (err)
		panic("%s", err); /* Failed to decompress INTERNAL initramfs */

	if (!initrd_start || IS_ENABLED(CONFIG_INITRAMFS_FORCE))
		goto done;

	if (IS_ENABLED(CONFIG_BLK_DEV_RAM))
		printk(KERN_INFO "Trying to unpack rootfs image as initramfs...\n");
	else
		printk(KERN_INFO "Unpacking initramfs...\n");

	err = unpack_to_rootfs((char *)initrd_start, initrd_end - initrd_start);
	if (err) {

		printk(KERN_EMERG "Initramfs unpacking failed: %s\n", err);
#endif
	}

done:
	/*
	 * If the initrd region is overlapped with crashkernel reserved region,
	 * free only memory that is not part of crashkernel region.
	 */
	if (!do_retain_initrd && initrd_start && !kexec_free_initrd())
		free_initrd_mem(initrd_start, initrd_end);
	initrd_start = 0;
	initrd_end = 0;

	flush_delayed_fput();
	return 0;
} 

以上代码含两次 unpack_to_rootfs,第一次解压kernel内嵌的.cpio,第二次判断initrd_start是否为0,不为0则表示u-boot load了ramdisk,则会进行解压。

挂载磁盘(EMMC)上的rootfs

kernel_init_freeable->

如果 /init 不存在,执行prepare_namespace

if (init_eaccess(ramdisk_execute_command) != 0) {

	ramdisk_execute_command = NULL;
	
	prepare_namespace();

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

	wait_for_device_probe();
	md_run_setup();
       //root=是否mtd开头
	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;
	}
        //mount_initrd = 0 不执行
	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();
	}
        //进行实际文件系统挂载
	mount_root();
out:
	devtmpfs_mount();                          //<1>                                                 
	init_mount(".", "/", NULL, MS_MOVE, NULL); //<2>                                               
	init_chroot(".");                          //<3>                                                
}

<1>挂载devtmpfs到 实际文件系统的/dev下(上面已切换至/root下,因此填dev,磁盘rootfs必有dev目录)

<2>将磁盘rootfs挂载至/下,相当于/root下的磁盘rootfs将RAM里的/覆盖

<3>将init进程的根目录切换至实际根文件系统的/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值