当前位置: 首页 > news >正文

3588 只读根文件系统配置 overlayroot(防掉电损坏)

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、桌面环境和所有用户进程。

它的三种核心拦截动作:

  1. 读(Read):如果读取一个未修改过的原厂文件,视线会穿透玻璃(Upperdir),直接读取底层(Lowerdir)的物理文件。
  2. 写/改(Copy-up):当系统试图修改底包里的某个文件时,OverlayFS 会触发Copy-up(向上复制)机制。它会先把这个文件从底层静默拷贝到上层(玻璃上),然后所有的修改都只发生在玻璃上的这个副本里。底层文件原封不动。
  3. 删(Whiteout):当系统试图删除一个基础文件时,OverlayFS 不会(也不能)去删底层文件。它会在上层(玻璃上)创建一个同名的特殊隐藏文件,叫做Whiteout(涂改液)。系统看到这个涂改液,就会认为该文件已被删除。

0.2 两种模式

  1. 内存只读测试模式(重启即清空),将读写层建立在物理内存(RAM)上,不依赖任何多余的硬盘分区,适合前期验证或绝对的 Kiosk 广告机模式:rootfs(overlayroot)
  2. 只读根文件系统+可读数据分区,将底层系统锁死为只读,并将所有的写入操作全部重定向到一个独立的大分区(名字叫 userdata)。断电不坏系统,且用户数据不丢:rootfs(overlayroot) + userdata(ext4, 可读)

1 获取并准备包含 Overlay 驱动的 initrd 镜像

1.1 为什么需要initrd镜像

疑问:既然 Linux 内核自带 OverlayFS,为什么我不能直接进系统后再用 mount 命令把它挂载上?

答案是:根目录 (/) 是系统的基石,在系统启动后,你无法把正在运行的根目录“凭空抽走”换成一个 Overlay 幻象。

因此,我们必须借助 initramfs。

  1. 内核启动后,首先挂载并运行这个纯内存里的微型系统(initramfs)。
  2. 内存系统里的 overlayroot 脚本在内存里先把 rootfs 分区只读挂载好(作为 Lower),再把 tmpfs 或 userdata 挂载好(作为 Upper),并调用内核的 OverlayFS 把它们拼在一起。
  3. 关键一步(switch_root):拼装完成后,内存系统将系统的控制权彻底移交给这层拼装好的“幻象根目录”。

1.2 initrd 镜像的获取方式

  1. 在开发板当前的 Ubuntu 系统中,通过 apt install overlayroot 安装底层包。
  2. 运行 update-initramfs -c -k $(uname -r),在板子的 /boot/ 目录下生成带有 overlayroot 拦截脚本的内存盘镜像(例如 initrd.img-5.10.160+)。
  3. 将该文件拷贝到 PC 宿主机 RK3588 SDK 的根目录下,并重命名为my_initrd.img
    (注意:需要放在根目录且避开 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中,增加

#overlayfsmount-text4-oremount,ro /dev/disk/by-partlabel/rootfs /media/root-ro

参考《使用overlayroot时root-ro被挂载为ro的bug》

http://www.jsqmd.com/news/997285/

相关文章:

  • 2026年6月服务好的央国企求职辅导机构有哪些,央国企就业培训/国企笔试面试培训,央国企求职辅导公司推荐 - 品牌推荐师
  • 保山市黄金回收白银回收铂金回收彩金回收靠谱门店TOP排行榜及联系方式地址电话+诚信店铺推荐 - 大熊猫898989
  • 3.1.6 B Tree
  • 手势交互视频生成技术:基于自回归框架的创新实现
  • 从BLEST到STMS:手把手拆解MPTCP调度器,看它们如何解决‘队首阻塞’这个老大难问题
  • 综合案例 - AI 智能租房助手 [ 5 ]
  • 【花雕学编程】Arduino BLDC 之UWB与超声波融合的智能避障跟随机器人
  • 2026年6月水质五参数在线监测仪价格:十大国产品牌全维度解析与落地选型指南 - 仪表品牌榜
  • 现代C++张量收缩:从einsum到编译期优化的高性能实现
  • 亲密的网络旅程(四):给网络装上一台“超级电梯”与“贵宾通道”——802.1Q与QoS的魔法
  • EEG癫痫波检测的可解释性AI突破:跨模态语义检索技术
  • 大同人身伤害维权遇到困难?2026年这5位侵权赔偿律师推荐 - 本地品牌推荐
  • Function Calling:大模型结构化调用与API协同执行机制
  • 2026年6月口碑好的焊管制造商推荐,耐高压弯头/大口径不锈钢焊管/薄壁不锈钢焊管/大口径不锈钢管,焊管加工厂推荐 - 品牌推荐师
  • C++版DICOM3.0轻量解析与传输源码包(含完整编译产物和测试工程)
  • 【Android问题分析】Android 安装时报错INSTALL_FAILED_NO_MATCHING_ABIS
  • 2026年大同合同纠纷律师推荐选对=省心 张超律师值得推荐 - 本地品牌推荐
  • 从预测到逻辑思考:开启CPU+GPU的AI新时代
  • P1336 最佳课题选择【洛谷算法习题】
  • 信息学奥赛递推题‘踩方格’的保姆级图解教程:为什么是a[i]=2*a[i-1]+a[i-2]?
  • 手把手教你:在HP服务器上切换RAID卡模式(Smart Array vs HBA/JBOD)
  • 091、动态蛇形卷积 DSConv:管状结构自适应聚焦的几何约束卷积
  • 深度解析 Bun:重新定义 JavaScript 运行时的性能边界
  • MATLAB手写三次样条插值函数:带详细注释+可视化示例脚本
  • Cursor vibe coding:用自然语言驱动前端原型开发
  • 青海彩钢移动厕所技术解析与本土厂家适配指南:西宁楼承板厂家、西宁横挂板价格、西宁横挂板厂、西宁横挂板厂家、西宁琉璃瓦选择指南 - 优质品牌商家
  • 2026年成都商铺装修品牌电话实测:口碑与专业度谁更强? - 优质品牌商家
  • 大模型语义缓存与去重策略:从精确匹配到语义相似度的缓存优化
  • 如何快速下载抖音无水印视频:面向新手的完整实战指南
  • 2026年四川LED显示屏市场格局分析:从户外广告到指挥中心的实力供应商盘点 - 优质品牌商家