【openwrt】【overlayfs】Openwrt系统overlayfs挂载流程

本文介绍了overlayfs在openwrt系统中的挂载过程。overlayfs是叠加文件系统,可将只读和可写文件系统叠加,修改只存于可写系统。挂载分两部分:只读根文件系统挂载和overlayfs挂载。前者涉及内核层操作,后者需fstools工具,在应用层完成。

overlayfs是一种叠加文件系统,在openwrt和安卓系统中都有很广泛的应用,overlayfs通常用于将只读根文件系统(rootfs)和可写文件系统(jffs2)进行叠加后形成一个新的文件系统,这个新的文件系统“看起来”是可读写的,这种做法的好处是:

  • 对这个新文件系统的修改(删除也属于修改)都只保存在可写文件系统中,只读根文件系统不受任何影响
  • 将可写文件系统格式化后,可以将整个文件系统恢复到初始状态(相当于只有只读根文件系统的状态)
  • 减少flash擦写次数,延长设备使用寿命

下面就开始介绍openwrt系统中的overlayfs是如何挂载的,挂载过程可以分为2个部分:

  • 只读根文件系统(rootfs)挂载过程
  • overlayfs 挂载过程(包括可写文件系统(rootfs_data)挂载过程)

只读根文件系统(rootfs)挂载过程

kernel的启动流程大致如下:
在这里插入图片描述

prepare_namespace

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_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");
	ksys_mount(".", "/", NULL, MS_MOVE, NULL);
	ksys_chroot(".");
}
  • root_delay:如果cmdline中有“rootdelay=xxx”,则调用ssleep延迟xxx秒,例如“rootdelay=10”,则延时10s
  • wait_for_device_probe()是等待所有的设备probe完成,
  • saved_root_name:如果cmdline中有“root=xxx”,则saved_root_name=xxx。在我当前的系统中 root=/dev/mmcblk1p65,所以saved_root_name=/dev/mmcblk1p65
  • mount_block_root: 如果root_device_name前三个字符是“ubi”或者“mtd”,则调用mount_block_root进行挂载根文件系统,这里主要是针对ubifs这一种文件系统进行特殊处理,因为ubifs根文件系统对应cmdline的参数一般是:ubi.mtd=1 root=ubi0:rootfs rootfstype=ubifs ,而其他文件系统一般是root=/dev/xxx.saved_root_name会被赋值给root_device_name
  • ROOT_DEV:root_device_name设备对应的设备号(/dev/mmcblk1p65设备对应主设备号是259,次设备号是0)
  • while (driver_probe_done() != 0): 等待所有saved_root_name设备probe完成(dev/xxx节点被创建)
  • mount_root:开始挂载根文件系统

mount_root(内核层)

void __init mount_root(void)
{
   
   
#ifdef CONFIG_ROOT_NFS
	if (ROOT_DEV == Root_NFS) {
   
   
		if (!mount_nfs_root())
			printk(KERN_ERR "VFS: Unable to mount root fs via NFS.\n");
		return;
	}
#endif
#ifdef CONFIG_CIFS_ROOT
	if (ROOT_DEV == Root_CIFS) {
   
   
		if (!mount_cifs_root())
			printk(KERN_ERR "VFS: Unable to mount root fs via SMB.\n");
		return;
	}
#endif
#ifdef CONFIG_MTD_ROOTFS_ROOT_DEV
	if (!mount_ubi_rootfs())
		return;
#endif
#ifdef CONFIG_BLOCK
	{
   
   
		int err = create_dev("/dev/root", ROOT_DEV);

		if (err < 0)
			pr_emerg("Failed to create /dev/root: %d\n", err);
		mount_block_root("/dev/root", root_mountflags);
	}
#endif
}
  • CONFIG_MTD_ROOTFS_ROOT_DEV 的作用是告诉 Linux 内核在引导过程中从哪个 MTD 设备加载根文件系统,一般支持NANDFlash的设备都会开启这个选项
  • mount_ubi_rootfs() 尝试挂载ubifs,如果挂载成功,则不再继续后续的挂载步骤。
  • CONFIG_BLOCK是开启块设备子系统,对于绝大多数文件系统(EXT4、yaffs2、XFS、FAT等)都需要块设备子系统的支持。
  • create_dev(“/dev/root”, ROOT_DEV) 创建了一个设备节点/dev/root,/dev/root是根文件系统设备的抽象,因为它的设备号也是ROOT_DEV,前面有提到ROOT_DEV就是实际的根文件系统设备节点。这样做的好处是不用关心实际的根文件系统设备是什么,直接对/dev/root进行mount就可以实现根文件系统的挂载。
  • mount_block_root(“/dev/root”, root_mountflags) 挂载/dev/root
void __init mount_block_root(char *name, int flags)
{
   
   
	struct page *page = alloc_page(GFP_KERNEL);
	char *fs_names = page_address(page);
	char *p;
	<
OpenWRT中优化Linux文件系统以减少资源占用,主要涉及对文件系统的精简、配置参数调整以及模块化管理,从而在资源受限的嵌入式设备上实现高效运行。 ### 使用最小化文件系统配置 OpenWRT的文件系统具有高度可裁剪性,可以根据设备的实际需求,保留最基础的文件系统结构和必要的服务,剔除冗余组件。例如,系统可以配置为仅加载基础文件系统和网络功能,避免不必要的软件包和配置文件占用内存和存储空间。这种定制化方式能够显著降低系统运行时的内存占用[^1]。 ### 启用只读文件系统根文件系统设置为只读可以减少写操作,降低I/O负载,同时提高系统的稳定性和安全性。可以通过修改`/etc/config/fstab`文件,将根分区挂载选项设置为`ro`(只读): ```bash config 'mount' option 'target' '/overlay' option 'device' '/dev/mtdblock3' option 'fstype' 'jffs2' option 'options' 'ro' option 'enabled' '1' ``` 这种方式减少了系统对Flash的频繁写入,延长存储介质的使用寿命,并优化系统资源的使用[^1]。 ### 优化文件系统挂载参数 通过调整文件系统挂载参数,可以进一步提升性能并减少资源占用。例如,设置`noatime`参数可以避免每次读取文件时更新访问时间戳,从而减少磁盘I/O操作: ```bash mount -o remount,noatime /overlay ``` 此外,合理配置`vm.dirty_background_ratio`参数(例如设置为5),确保系统在后台持续将脏数据写入磁盘,避免前台应用程序因I/O操作而延迟,从而优化内存和磁盘I/O性能[^2]。 ### 使用轻量级文件系统格式 OpenWRT支持多种文件系统格式,包括SquashFS、JFFS2、UBIFS等。其中,SquashFS是一种只读压缩文件系统,适合用于嵌入式设备的固件存储,能够有效减少存储空间占用。而JFFS2和UBIFS则适用于需要频繁写入的场景,具备较好的性能优化空间。根据设备需求选择合适的文件系统格式,可以显著降低资源消耗。 ### 禁用不必要的日志记录 系统日志记录会占用一定的内存和存储资源,对于资源受限的设备,可以适当减少日志级别或禁用非关键日志。编辑`/etc/syslog.conf`文件,调整日志输出级别,或直接关闭日志服务: ```bash /etc/init.d/syslog stop /etc/init.d/syslog disable ``` 这种方式可以减少内存中缓存的日志数据量,从而降低系统资源占用。 ### 使用OverlayFS优化可写层 OpenWRT采用OverlayFS作为默认的文件系统结构,其中只读的SquashFS层与可写的JFFS2层结合,实现了固件的更新与用户数据的分离。可以通过限制可写层的大小或优化其使用方式,减少内存和Flash的消耗。例如,在`/etc/config/fstab`中合理配置可写分区的大小和挂载选项,避免不必要的写入操作。 ### 精简软件包和依赖 使用`opkg`工具卸载不必要的软件包,清理系统中冗余的依赖项,减少文件系统的体积和运行时内存占用: ```bash opkg remove package_name opkg list-installed ``` 通过仅保留核心功能所需的软件包,可以显著降低系统资源的消耗。
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

知否,知否

来一杯冰美式把

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值