OpenWRT(10):OpenWRT下rootfs的cpio/squashfs/ubifs/ext4生成流程
在include/image.mk中定义了initramfs、ubifs、squashfs、ext4等镜像的生成。
OpenWRT提供配置选项入口,借助mkfs.ubifs、mksquashfs4、make_ext4fs创建镜像。
1 ubifs
下面是include/image.mk中生成ubifs镜像的Makefile函数:
define Image/mkfs/ubifs $(STAGING_DIR_HOST)/bin/mkfs.ubifs \ $(UBIFS_OPTS) $(call param_unmangle,$(call param_get,fs,$(1))) \ $(if $(CONFIG_TARGET_UBIFS_FREE_SPACE_FIXUP),--space-fixup) \ $(if $(CONFIG_TARGET_UBIFS_COMPRESSION_NONE),--compr=none) \ $(if $(CONFIG_TARGET_UBIFS_COMPRESSION_LZO),--compr=lzo) \ $(if $(CONFIG_TARGET_UBIFS_COMPRESSION_ZLIB),--compr=zlib) \ $(if $(shell echo $(CONFIG_TARGET_UBIFS_JOURNAL_SIZE)),--jrn-size=$(CONFIG_TARGET_UBIFS_JOURNAL_SIZE)) \ --squash-uids \ -o $@ -d $(call mkfs_target_dir,$(1)) endef
这段脚本定义一个名为`Image/mkfs/ubifs`的函数,它用于创建Ubifs文件系统镜像。Ubifs(Unsorted Block Image File System)是一种针对闪存存储设备优化的文件系统。下面是对脚本中各部分的详细解释:
- define Image/mkfs/ubifs:开始定义一个名为Image/mkfs/ubifs的Makefile函数。
- $(STAGING_DIR_HOST)/bin/mkfs.ubifs:调用mkfs.ubifs工具,这是一个用于创建Ubifs文件系统的命令行工具。
- $(UBIFS_OPTS):包含Ubifs文件系统的通用选项,这些选项可能包括文件系统的大小、块大小等。
- $(call param_unmangle,$(call param_get,fs,$(1))):这部分代码调用了两个函数来处理Ubifs文件系统的参数。`param_get`函数用于获取传递给函数的第一个参数(`$(1)`)的值,`param_unmangle`函数用于处理这个值,可能用于转换或修正参数。
- --space-fixup:如果定义了CONFIG_TARGET_UBIFS_FREE_SPACE_FIXUP,将添加此选项到`mkfs.ubifs`命令中,用于修复Ubifs文件系统中的空闲空间问题。这个选项对于某些NAND闪存设备是必要的,因为它们不能处理文件系统中的“洞”。
- --compr=none,--compr=lzo,--compr=zlib:根据配置选项,选择Ubifs文件系统的压缩算法。如果没有定义压缩算法,使用none;如果定义了CONFIG_TARGET_UBIFS_COMPRESSION_LZO,则使用LZO压缩;如果定义了CONFIG_TARGET_UBIFS_COMPRESSION_ZLIB,则使用ZLIB压缩。
- --jrn-size=$(CONFIG_TARGET_UBIFS_JOURNAL_SIZE):如果定义了CONFIG_TARGET_UBIFS_JOURNAL_SIZE,将设置Ubifs文件系统的日志大小,单位通常是块。
- --squash-uids:此选项用于在创建文件系统时忽略用户ID和组ID,所有文件将使用相同的用户和组权限。
- -o $@:指定输出文件,$@是Makefile中的自动变量,代表当前的规则目标。
- -d $(call mkfs_target_dir,$(1)):指定要包含在Ubifs文件系统中的目录,`$(call mkfs_target_dir,$(1))`调用一个函数来获取目录路径。
mkfs.ubifs其他选项可以通过UBIFS_OPTS传入,还包括:
- -m, --min-io-size:用于设置Ubifs文件系统中的最小I/O单元大小。SIZE参数指定了Ubifs操作的最小数据单元,通常应与底层存储设备的页大小相匹配。
- -e, --leb-size:设置Ubifs文件系统中逻辑擦除块(LEB)的大小。SIZE参数定义了每个LEB的大小,单位是字节。
- -c, --max-leb-cnt:设置Ubifs文件系统中逻辑擦除块(LEB)的最大数量。COUNT参数定义了文件系统中可以拥有的最大LEB数量。
比如:
UBIFS_OPTS = -m 2048 -e 124KiB -c 4096
1.1 ubi镜像
include/image-commands.mk中定义名为Build/append-ubi的 Makefile 函数,用于将文件系统和可选的内核以及环境变量打包成一个 UBI 镜像:
define Build/append-ubi sh $(TOPDIR)/scripts/ubinize-image.sh \ $(if $(UBOOTENV_IN_UBI),--uboot-env) \ $(if $(KERNEL_IN_UBI),--kernel $(IMAGE_KERNEL)) \ $(foreach part,$(UBINIZE_PARTS),--part $(part)) \ --rootfs $(IMAGE_ROOTFS) \ $@.tmp \ -p $(BLOCKSIZE:%k=%KiB) -m $(PAGESIZE) \ $(if $(SUBPAGESIZE),-s $(SUBPAGESIZE)) \ $(if $(VID_HDR_OFFSET),-O $(VID_HDR_OFFSET)) \ $(UBINIZE_OPTS) cat $@.tmp >> $@ rm $@.tmp endef
- sh $(TOPDIR)/scripts/ubinize-image.sh:调用ubinize-image.sh脚本来执行 UBI 镜像的创建。
- $(if $(UBOOTENV_IN_UBI),--uboot-env):如果定义了UBOOTENV_IN_UBI变量,那么添加--uboot-env参数到ubinize-image.sh脚本中,表示将 U-Boot 环境变量包含在 UBI 镜像中。
- $(if $(KERNEL_IN_UBI),--kernel $(IMAGE_KERNEL)):如果定义了KERNEL_IN_UBI变量,那么添加--kernel参数和内核镜像的路径到ubinize-image.sh脚本中,表示将内核包含在 UBI 镜像中。
- $(foreach part,$(UBINIZE_PARTS),--part $(part)):对于UBINIZE_PARTS列表中的每个分区,添加--part参数和分区名称到ubinize-image.sh脚本中。
- --rootfs $(IMAGE_ROOTFS):指定要包含在 UBI 镜像中的根文件系统。
- $@.tmp:指定输出文件的临时名称,$@表示目标文件名。
- -p $(BLOCKSIZE:%k=%KiB):指定 UBI 镜像的块大小,$(BLOCKSIZE) 通常以千字节为单位定义,这里将其转换为 KiB。
- -m $(PAGESIZE):指定 NAND 页大小。
- $(if $(SUBPAGESIZE),-s $(SUBPAGESIZE)):如果定义了SUBPAGESIZE变量,那么添加-s参数和子页大小到ubinize-image.sh脚本中。
- $(if $(VID_HDR_OFFSET),-O $(VID_HDR_OFFSET))`:如果定义了VID_HDR_OFFSET变量,那么添加-O参数和 VID 头偏移量到 ubinize-image.sh脚本中。
- $(UBINIZE_OPTS):添加任何额外的ubinize-image.sh脚本选项。
scripts/ubinize-image.sh根据输入的参数生成ubi镜像:
- ubivol函数:创建一个 UBI 卷的配置块。参数包括卷 ID、名称、镜像路径、自动调整大小标志和大小。
- ubilayout函数:根据提供的参数生成 UBI 布局配置。处理 U-Boot 环境变量、分区、内核和根文件系统的配置。
- [ "$rootfs_type" = "ubifs" ] || ubivol $vol_id rootfs_data "" 1:如果 $rootfs_type 等于 ubifs,则条件为真,不执行任何操作。如果条件为假(即squashfs类型rootfs),则调用 ubivol 函数来创建一个名为rootfs_data 的 UBI 卷,卷 ID 为 $vol_id,没有指定图像,自动调整大小标志为空,大小为1MiB。
- --uboot-env、--kernel--rootfs、--part、--rootfs:为这些参数创建Volume。
2 squashfs
下面是include/image.mk中生成squashfs镜像的Makefile函数:
define Image/mkfs/squashfs $(call Image/mkfs/squashfs-common,$(1)) endef define Image/mkfs/squashfs-common $(STAGING_DIR_HOST)/bin/mksquashfs4 $(call mkfs_target_dir,$(1)) $@ \ -nopad -noappend -root-owned \ -comp $(SQUASHFSCOMP) $(SQUASHFSOPT) endef
在include/image.mk中SQUASHFSOPT默认配置如下:
SQUASHFSOPT := -b $(SQUASHFS_BLOCKSIZE) SQUASHFSOPT += -p '/dev d 755 0 0' -p '/dev/console c 600 0 0 5 1' SQUASHFSOPT += $(if $(CONFIG_SELINUX),-xattrs,-no-xattrs) SQUASHFSCOMP := gzip
这段代码是Makefile的一部分,定义了两个函数:`Image/mkfs/squashfs`和`Image/mkfs/squashfs-common`。下面是对函数的详细分析:
-
define Image/mkfs/squashfs-common:定义了一个名为Image/mkfs/squashfs-common的Makefile函数,这个函数是实际执行创建squashfs文件系统操作的函数。
-
mksquashfs4:调用mksquashfs4工具,这是一个用于创建squashfs文件系统的命令行工具。$(STAGING_DIR_HOST)是一个Makefile变量,通常指向存放编译过程中生成的中间文件的目录。
-
$(call mkfs_target_dir,$(1)):调用`mkfs_target_dir`函数,并将第一个参数`$(1)`传递给它。这个函数用于获取需要被打包进squashfs文件系统的源目录路径。
-
$@:表示当前Makefile规则的目标。在这个上下文中,它指向squashfs文件系统的输出文件。
-
-nopad:mksquashfs的一个选项,用于禁止对文件系统进行填充操作。
-
-noappend:另一个`mksquashfs`的选项,用于禁止创建可追加的squashfs镜像。
-
-root-owned:指定所有文件在squashfs文件系统中都归root用户所有。
-
-comp $(SQUASHFSCOMP):指定squashfs文件系统的压缩算法。$(SQUASHFSCOMP)是一个Makefile变量,包含了压缩算法的名称。
-
$(SQUASHFSOPT):包含squashfs文件系统创建过程中的其他选项,这些选项可能包括压缩级别、文件系统版本等。
这段代码定义了两个Makefile函数,用于创建squashfs文件系统。`Image/mkfs/squashfs`函数是一个简单的包装器,它调用实际执行创建操作的`Image/mkfs/squashfs-common`函数。`Image/mkfs/squashfs-common`函数则包含了创建squashfs文件系统所需的所有命令和选项。通过这种方式,Makefile可以重用创建squashfs文件系统的代码,同时保持代码的清晰和组织性。
/home/al/data/openwrt/openwrt22.03-a53/staging_dir/host/bin/mksquashfs4 \
/home/al/data/openwrt/openwrt22.03-a53/build_dir/target-aarch64_cortex-a53_musl/root-armvirt \
/home/al/data/openwrt/openwrt22.03-a53/build_dir/target-aarch64_cortex-a53_musl/linux-armvirt_64/root.squashfs \
-nopad -noappend -root-owned -comp xz -Xpreset 9 -Xe -Xlc 0 -Xlp 2 -Xpb 2 -b 256k \
-p '/dev d 755 0 0' -p '/dev/console c 600 0 0 5 1' -no-xattrs
3 ext4
下面是include/image.mk中生成ext4镜像的Makefile函数:
define Image/mkfs/ext4 $(STAGING_DIR_HOST)/bin/make_ext4fs -L rootfs \ -l $(ROOTFS_PARTSIZE) -b $(CONFIG_TARGET_EXT4_BLOCKSIZE) \ $(if $(CONFIG_TARGET_EXT4_RESERVED_PCT),-m $(CONFIG_TARGET_EXT4_RESERVED_PCT)) \ $(if $(CONFIG_TARGET_EXT4_JOURNAL),,-J) \ $(if $(SOURCE_DATE_EPOCH),-T $(SOURCE_DATE_EPOCH)) \ $@ $(call mkfs_target_dir,$(1))/ endef
这段代码是Makefile的一部分,定义了一个名为`Image/mkfs/ext4`的函数,用于创建一个ext4文件系统的镜像。下面是对这段代码的解释:
- define Image/mkfs/ext4:开始定义一个Makefile函数,名为`Image/mkfs/ext4`。
- make_ext4fs:调用`make_ext4fs`工具,这是一个用于创建ext4文件系统的命令行工具。`$(STAGING_DIR_HOST)`是一个Makefile变量,指向存放编译过程中生成的中间文件的目录。
- -L rootfs:指定文件系统的标签为`rootfs`。
- -l $(ROOTFS_PARTSIZE):指定文件系统的大小,$(ROOTFS_PARTSIZE)是一个Makefile变量,代表文件系统的分区大小。可以是块的数量或者文件的大小(如果以b、k、m或g结尾)。
- -b $(CONFIG_TARGET_EXT4_BLOCKSIZE):指定文件系统的块大小,$(CONFIG_TARGET_EXT4_BLOCKSIZE)是一个Makefile变量,代表块大小。
- $(if $(CONFIG_TARGET_EXT4_RESERVED_PCT),-m $(CONFIG_TARGET_EXT4_RESERVED_PCT)):如果定义了`CONFIG_TARGET_EXT4_RESERVED_PCT`,则添加`-m`选项,并使用该变量的值作为保留空间的百分比。
- $(if $(CONFIG_TARGET_EXT4_JOURNAL),,-J):如果定义了`CONFIG_TARGET_EXT4_JOURNAL`,则不添加任何选项(因为逗号前的空格表示如果条件为真,则什么也不做)。如果没有定义,则添加`-J`选项,这通常用于禁用日志功能。
- $(if $(SOURCE_DATE_EPOCH),-T $(SOURCE_DATE_EPOCH)):如果定义了`SOURCE_DATE_EPOCH`,则添加`-T`选项,并使用该变量的值作为文件系统的创建时间。
- $@:表示当前Makefile规则的目标。在这个上下文中,它指向创建的ext4文件系统镜像的输出文件。
- $(call mkfs_target_dir,$(1))/:调用`mkfs_target_dir`函数,并将第一个参数`$(1)`传递给它。这个函数用于获取需要被打包进ext4文件系统的源目录路径,并在路径后添加一个斜杠以表示目录。
这段代码定义了一个函数,用于根据一系列的配置选项和参数,创建一个ext4文件系统镜像。这个函数可以被Makefile的其他部分调用,以生成所需的文件系统镜像。通过使用条件语句,它允许用户根据配置选择是否保留空间、是否使用日志以及设置文件系统的创建时间。
/home/al/data/openwrt/openwrt22.03-a53/staging_dir/host/bin/make_ext4fs \
-L rootfs -l 109051904 -b 4096 -m 0 -J -T 1721689001 \
/home/al/data/openwrt/openwrt22.03-a53/build_dir/target-aarch64_cortex-a53_musl/linux-armvirt_64/root.ext4 \
/home/al/data/openwrt/openwrt22.03-a53/build_dir/target-aarch64_cortex-a53_musl/root-armvirt/