3588 只读根文件系统配置 overlayroot(防掉电损坏)
- 作者:吴思含(Witheart)
- 更新时间:20260522
参考链接:
https://blog.csdn.net/Yongheng6/article/details/145373026
0 overlayfs原理
0.1 原理解析
OverlayFS 是 Linux 内核原生支持的一种联合文件系统(Union Mount File System)。它的核心运作机制可以生动地比喻为“在原画上盖了一层透明玻璃”。
在 OverlayFS 的架构中,根目录(/)不再是一个单一的物理硬盘分区,而是由几个独立的层“叠”在一起合并而成的幻象:
| Lowerdir (下层) | 烧录了 16GB 底包的 rootfs 物理分区 | 绝对只读(Read-Only)。提供所有基础的系统文件和二进制库。一旦挂载,任何程序都无法向其写入哪怕 1 个字节。 |
| Upperdir (上层) | 内存 (tmpfs) 或物理磁盘的 userdata 分区 | 完全可读写(Read-Write)。它是那层“透明玻璃”,专门用来拦截并拦截所有对文件系统的修改。 |
| Merged (合并层) | 操作系统最终看到的 / 根目录 | 合并幻象。把下层的文件和上层的修改无缝拼接到一起,呈现给上层的 DBus、桌面环境和所有用户进程。 |
它的三种核心拦截动作:
0.2 两种模式
1 获取并准备包含 Overlay 驱动的 initrd 镜像
1.1 为什么需要initrd镜像
疑问:既然 Linux 内核自带 OverlayFS,为什么我不能直接进系统后再用 mount 命令把它挂载上?
答案是:根目录 (/) 是系统的基石,在系统启动后,你无法把正在运行的根目录“凭空抽走”换成一个 Overlay 幻象。
因此,我们必须借助 initramfs。
1.2 initrd 镜像的获取方式
(注意:需要放在根目录且避开 ramdisk 关键字,是为了防止触发 RK 构建系统的自动注入冲突,如果名称改为ramdisk.img放在kernel下,直接改boot.its会报错,不改时显示打包了但是实际上又没有正确打包。)
2 修改 FIT 镜像打包配方 (boot.its)
RK3588 采用了高级的 Flattened Image Tree (FIT) 启动架构。我们需要通过修改原厂的 .its 文件,合法地将 my_initrd.img 打包进去。
使用如下代码添加打印,验证使用了FIT启动架构
diff –git a/device/rockchip/common/build.sh b/device/rockchip/common/build.sh
index c85f18cbe..3da4f28be 100755
— a/device/rockchip/common/build.sh
+++ b/device/rockchip/common/build.sh
@@ -650,6 +650,7 @@ function build_kernel(){
echo "TARGET_KERNEL_CONFIG =$RK_KERNEL_DEFCONFIG"
echo "TARGET_KERNEL_DTS =$RK_KERNEL_DTS"
echo "TARGET_KERNEL_CONFIG_FRAGMENT =$RK_KERNEL_DEFCONFIG_FRAGMENT"
+echo "[Witheart] RK_KERNEL_FIT_ITS=$RK_KERNEL_FIT_ITS"
echo "=========================================="
build_check_cross_compile
@@ -658,6 +659,7 @@ function build_kernel(){
make ARCH=$RK_ARCH $RK_KERNEL_DEFCONFIG $RK_KERNEL_DEFCONFIG_FRAGMENT
make ARCH=$RK_ARCH $RK_KERNEL_DTS.img -j$RK_JOBS
if [ -f "$TOP_DIR/device/rockchip/$RK_TARGET_PRODUCT/$RK_KERNEL_FIT_ITS" ]; then
+echo "[Witheart] Rebuild fitImage with $RK_KERNEL_FIT_ITS"
$COMMON_DIR/mk-fitimage.sh $TOP_DIR/kernel/$RK_BOOT_IMG \\
$TOP_DIR/device/rockchip/$RK_TARGET_PRODUCT/$RK_KERNEL_FIT_ITS
fi
找到你板子对应的 .its 文件(如 device/rockchip/RK_TARGET_PRODUCT/boot.its),进行以下修改:
1. 在 images { … } 块的末尾,追加 initrd 节点:
diff –git a/device/rockchip/rk3588/boot.its b/device/rockchip/rk3588/boot.its
index d24396401..6f8d19bee 100644
— a/device/rockchip/rk3588/boot.its
+++ b/device/rockchip/rk3588/boot.its
@@ -45,6 +45,19 @@
algo = "sha256";
};
};
+
+ initrd {
+ description = "Ubuntu overlayroot ramdisk";
+ data = /incbin/("../my_initrd.img");
+ type = "ramdisk";
+ arch = "arm64";
+ os = "linux";
+ compression = "none";
+ load = <0xffffff02>;
+ hash {
+ algo = "sha256";
+ };
+ };
};
configurations {
@@ -55,12 +68,13 @@
fdt = "fdt";
kernel = "kernel";
multi = "resource";
+ ramdisk = "initrd";
signature {
algo = "sha256,rsa2048";
padding = "pss";
key-name-hint = "dev";
– sign-images = "fdt", "kernel", "multi";
+ sign-images = "fdt", "kernel", "multi", "initrd";
};
};
};
3 在内核设备树 (.dts) 中硬编码启动参数
避坑指南: 3588会使用设备树中的 chosen 节点硬编码的 bootargs
打开内核设备树源文件(如 kernel/arch/arm64/boot/dts/rockchip/NK-6A13_V0A.dts),找到 chosen 节点,修改 bootargs。
这里分为“内存验证模式”和“量产数据持久化模式”两种写法,切记必须保留 rw 参数,否则 systemd 会把覆盖层重新锁死为只读,导致桌面崩溃。
选项 A:内存只读测试模式(重启即清空)
将读写层建立在物理内存(RAM)上,不依赖任何多余的硬盘分区。适合前期验证或绝对的 Kiosk 广告机模式:
diff –git a/kernel/arch/arm64/boot/dts/rockchip/NK-6A13_V0A_linux.dtsi b/kernel/arch/arm64/boot/dts/rockchip/NK-6A13_V0A_linux.dtsi
index b1ec42e12..aa85e0554 100755
— a/kernel/arch/arm64/boot/dts/rockchip/NK-6A13_V0A_linux.dtsi
+++ b/kernel/arch/arm64/boot/dts/rockchip/NK-6A13_V0A_linux.dtsi
@@ -12,7 +12,7 @@
};
chosen: chosen {
-bootargs = "earlycon=uart8250,mmio32,0xfeb50000 console=ttyFIQ0 irqchip.gicv3_pseudo_nmi=0 root=PARTUUID=614e0000-0000 rw rootwait net.ifnames=0";
+bootargs = "earlycon=uart8250,mmio32,0xfeb50000 console=ttyFIQ0 irqchip.gicv3_pseudo_nmi=0 root=PARTLABEL=rootfs rootfstype=ext4 rw rootwait overlayroot=tmpfs net.ifnames=0";
};
cspmu: cspmu@fd10c000 {
选项 B:只读根文件系统+可读数据分区
将底层系统锁死为只读,并将所有的写入操作全部重定向到一个独立的大分区(名字叫 userdata)。断电不坏系统,且用户数据不丢:
chosen: chosen {
bootargs = "earlycon=uart8250,mmio32,0xfeb50000 console=ttyFIQ0 irqchip.gicv3_pseudo_nmi=0 root=PARTLABEL=rootfs rootfstype=ext4 rw rootwait overlayroot=device:dev=/dev/disk/by-partlabel/userdata,fstype=ext4,mkfs=1 net.ifnames=0";
};
(注:使用选项 B 前,需确保 parameter.txt 中已实际划分出 userdata 分区,mkfs=1 会在第一次开机时自动帮你格式化它。)
4 parameter.txt 修改
4.1 无userdata情况
diff –git a/device/rockchip/rk3588/parameter.txt b/device/rockchip/rk3588/parameter.txt
index 923da7bad..5d370c883 100644
— a/device/rockchip/rk3588/parameter.txt
+++ b/device/rockchip/rk3588/parameter.txt
@@ -8,6 +8,5 @@ MACHINE: 0xffffffff
CHECK_MASK: 0x80
PWR_HLD: 0,0,A,0,1
TYPE: GPT
-CMDLINE: mtdparts=rk29xxnand:0x00002000@0x00004000(uboot),0x00002000@0x00006000(trust),0x00002000@0x00008000(misc),0x00020000@0x0000a000(boot),0x00040000@0x0002a000(recovery),0x00010000@0x0006a000(baseparameter),-@0x0007a000(rootfs:grow)
-uuid:rootfs=614e0000-0000-4b53-8000-1d28000054a9
-uuid:boot=7A3F0000-0000-446A-8000-702F00006273
+CMDLINE: mtdparts=rk29xxnand:0x00002000@0x00004000(uboot),0x00002000@0x00006000(trust),0x00002000@0x00008000(misc),0x00020000@0x0000a000(boot),0x00040000@0x0002a000(recovery),0x00010000@0x0006a000(baseparameter),-@0x0007a000(rootfs:grow) ro rootwait root=PARTLABEL=rootfs rootfstype=ext4 overlayroot=tmpfs net.ifnames=0
+uuid:boot=7A3F0000-0000-446A-8000-702F00006273
\\ No newline at end of file
4.2 使用userdata的情况
diff –git a/device/rockchip/rk3588/parameter.txt b/device/rockchip/rk3588/parameter.txt
index 923da7bad..68a7f8daf 100644
— a/device/rockchip/rk3588/parameter.txt
+++ b/device/rockchip/rk3588/parameter.txt
@@ -8,6 +8,5 @@ MACHINE: 0xffffffff
CHECK_MASK: 0x80
PWR_HLD: 0,0,A,0,1
TYPE: GPT
-CMDLINE: mtdparts=rk29xxnand:0x00002000@0x00004000(uboot),0x00002000@0x00006000(trust),0x00002000@0x00008000(misc),0x00020000@0x0000a000(boot),0x00040000@0x0002a000(recovery),0x00010000@0x0006a000(baseparameter),-@0x0007a000(rootfs:grow)
-uuid:rootfs=614e0000-0000-4b53-8000-1d28000054a9
-uuid:boot=7A3F0000-0000-446A-8000-702F00006273
+CMDLINE: mtdparts=rk29xxnand:0x00002000@0x00004000(uboot),0x00002000@0x00006000(trust),0x00002000@0x00008000(misc),0x00020000@0x0000a000(boot),0x00040000@0x0002a000(recovery),0x00010000@0x0006a000(baseparameter),0x1400000@0x0007a000(rootfs),-@0x0147a000(userdata:grow)
+uuid:boot=7A3F0000-0000-446A-8000-702F00006273
\\ No newline at end of file
5 内核编译选项
diff –git a/kernel/arch/arm/configs/rockchip_linux_defconfig b/kernel/arch/arm/configs/rockchip_linux_defconfig
index 23ab6955b..fdf947ff4 100644
— a/kernel/arch/arm/configs/rockchip_linux_defconfig
+++ b/kernel/arch/arm/configs/rockchip_linux_defconfig
@@ -523,3 +523,5 @@ CONFIG_FUNCTION_TRACER=y
CONFIG_BLK_DEV_IO_TRACE=y
CONFIG_STRICT_DEVMEM=y
# CONFIG_RUNTIME_TESTING_MENU is not set
+
+CONFIG_OVERLAY_FS=y
6 开机脚本挂载root-ro为ro
/etc/rc.local中,增加
#overlayfs
mount -t ext4 -o remount,ro /dev/disk/by-partlabel/rootfs /media/root-ro
参考《使用overlayroot时root-ro被挂载为ro的bug》




