1. 写在前面:这块板子到底折腾的是什么
几年前我第一次拿到一块工控单板,板载 eMMC 只有 8GB,跑的还是个精简版 Linux,当时第一反应是“这不就是台小电脑嘛”。结果真正去配存储、刷系统、做恢复出厂的时候才发现,工控单板和普通 PC 完全是两套玩法。普通 PC 你装个系统、分个区、引导坏了拿 U 盘修就行;工控单板一旦 rootfs 写坏了,轻则返厂重烧,重则整个产线停摆。
这篇文章我想把工控单板上最常见的三件事串起来讲透:存储配置、系统升级、以及基于 OverlayFS 的恢复出厂机制。这三件事表面上是三个独立操作,实际在工控场景里是一条完整的运维链路——你先把存储规划好,才能让升级变得安全;而升级方案一旦选定,恢复出厂就成了最关键的兜底手段。文章里的命令和路径我都按常见 RK/Rockchip、全志等平台的 Linux 系统来写,理论部分也是通用的,你手里的板子只要跑的是标准 Linux 内核,基本都能直接对照着实践。
需要先说明一下,这不是一篇“从零教你看懂 Linux”的基础教程,而是面向已经能把系统跑起来、想进一步搞懂“这板子坏了怎么救、空间满了怎么加、系统怎么安全升级”的工程师和爱好者。如果你是刚接触嵌入式 Linux,读起来可能有几个术语需要额外查一下,但我尽量把原理讲得生活化,把命令的每个参数也解释清楚。这篇文章是系列的第一篇,重点放在存储布局和 OverlayFS 的原理与实操,升级部分会先给一个总览,具体到 A/B 分区和整镜像刷写的细节,后面单独展开。
2. 存储配置:先把这块板子的“家底”摸清楚
2.1 工控单板上有哪些存储介质
工控单板上的存储和 PC 不太一样,常见的就三类:eMMC、SD/TF 卡、Nor/NAND Flash。大部分商业级工控板出厂时主系统是烧在 eMMC 里的,容量从 4GB 到 64GB 不等,比 PC 的硬盘小得多,但胜在稳定、抗震动、断电不掉数据。SD 卡则通常被用作扩展存储、日志存储或者特殊场景下的启动介质。Nor Flash 容量最小,但启动速度极快,一般只放 bootloader 或者关键参数。
我实际遇到最多的情况是这样的:板子 eMMC 上烧了一个只读的 rootfs,再叠一层 OverlayFS 用于运行时写入;SD 卡则被格式化成 ext4 或 vfat,用来存日志、配置文件或者作为数据交换区。这个结构本身就是一种存储配置策略,核心目的是“系统层不被写坏,数据层可以随便折腾”,后面讲 OverlayFS 恢复出厂时你会看到这套设计是怎么闭环的。
2.2 上手第一步:查看存储拓扑
拿到板子先别急着改东西,第一件事是看清存储拓扑。我常用的三条命令,缺一不可:
lsblk df -hT cat /proc/cmdlinelsblk能看到块设备树状结构,比如mmcblk0是 eMMC、mmcblk1是 SD 卡、nvme0n1是 NVMe 盘。df -hT能看清每个挂载点的文件系统类型和占用率。而cat /proc/cmdline这条很容易被忽略,但它恰恰是最关键的——内核启动参数里如果出现了root=UUID=xxx或root=/dev/mmcblk0p7,你就能立刻判断系统真正从哪个分区启动,以及有没有挂载 OverlayFS 的相关参数。
我之前调试一块板子,lsblk 看一切正常,df 也显示有 overlay 挂在根目录,但就是没法恢复出厂,后来一查 cmdline 才发现内核压根没带 overlay 参数,系统是把 rootfs 当成普通读写分区挂载的。所以记住,不看 cmdline 就动分区,等于闭着眼改电路。
2.3 分区方案怎么规划才合理
规划分区不是越大越好,而是“每一块都用途明确”。我在实际项目中比较推荐的分区套路是:
| 分区 | 文件系统 | 典型大小 | 挂载点 | 用途 |
|---|---|---|---|---|
| bootloader | 裸分区 | 4-8MB | 无 | U-Boot 等引导程序,单独放避免干扰 |
| boot | vfat/ext4 | 128-256MB | /boot | 内核、设备树、initrd |
| rootfs | ext4/erofs | 1-4GB | / | 系统根文件系统,尽量只读 |
| data | ext4 | 剩余全部 | /data | 业务数据、日志、可写内容 |
| backup | ext4 | 256-512MB | 可挂可卸 | 系统备份或恢复出厂用的镜像 |
这个方案的优点非常明显:bootloader 和内核、rootfs 物理隔离,互不干扰;rootfs 可以做只读挂载,配合 OverlayFS 实现“假可写”,也就为恢复出厂打好了底子;data 独立分区,即使系统坏了,数据还在,重刷系统也不会影响业务数据。如果你用的是全志或者 Rockchip 的板子,SDK 里通常有现成的分区表模板,但默认模板里 data 分区经常被划得特别小,拿到手之后第一步就是按实际需求重新调整。
我个人不推荐一股脑把所有空间都塞给 rootfs,因为工控场景里“备份系统”和“保存数据”这两个需求永远比“系统又多装了几个软件包”更刚性。
2.4 修改分区后如何正确处理文件系统
分区方案定下来之后,实际操作上很多新手会在这里翻车。用fdisk或parted修改分区表只是第一步,接下来还要让内核重新读取分区表:
partprobe /dev/mmcblk0然后对新分区做格式化:
mkfs.ext4 /dev/mmcblk0p4这两条命令看似简单,但有个很隐蔽的坑:如果你修改的分区正在被系统挂载使用,partprobe会报Device or resource busy。这时候最稳妥的办法是进入 recovery 模式或者从 SD 卡启动系统再操作 eMMC 分区表。你千万不要想着“我直接 umount 掉再重新挂载就完事”,因为 rootfs 通常无法被卸载,强行操作极易把正在运行的系统搞崩。
还有一个小习惯我非常推荐:格式化 ext4 的时候加上-L指定卷标,比如mkfs.ext4 -L data /dev/mmcblk0p4。之后写/etc/fstab时用LABEL=data而不是/dev/mmcblk0p4来挂载,这样即使设备节点因为插入了 SD 卡而变化,挂载关系依然稳定。
2.5 fstab 的写法与常见错误
/etc/fstab是存储配置的收尾环节。我的典型写法如下:
LABEL=boot /boot vfat defaults,ro 0 0 LABEL=rootfs / ext4 defaults,ro,noatime 0 1 LABEL=data /data ext4 defaults,noatime 0 2 tmpfs /tmp tmpfs defaults,size=128M 0 0这里有几个值得展开讲的细节。rootfs 挂载成ro是工控系统安全性的基础,配合 OverlayFS 后既能满足运行时写入需求,又能让系统重启后自动回到“出厂状态”,这一点后面的章节会详细讲。noatime能减少大量无意义的写操作,尤其对 eMMC 这种有擦写寿命的存储来说,积少成多,能有效延长寿命。tmpfs挂到/tmp或/var/log的某个子目录,可以让系统把高频日志写在内存里,而不是疯狂闪存盘。
踩坑最多的就是0 1和0 2这两个数字的语义。第一个数字是是否需要 dump 备份,第二个是fsck检查顺序——根文件系统必须是 1,其他统一 2,如果都在同一块磁盘上,fsck顺序没必要区分太细,但千万不要让根目录的检查顺序变成 0,否则系统启动时不会自动修复文件系统错误,细微的坏块会越积越多。
3. 系统升级:先看全局,再动手实践
3.1 升级工控系统为什么要慎之又慎
普通 Linux 用户升级系统就是跑一下apt upgrade或者yum update,但工控系统完全不是这个操作逻辑。工控板上的系统往往是一个深度裁剪过的镜像,内核和根文件系统的版本绑定很严密;SDK 里编出来的根文件系统和内核如果版本不匹配,轻则某些外设模块加载失败,重则系统起不来。加上很多工控板出厂时跑的还是只读 rootfs,常规的包管理器制度根本没法直接操作。
所以工控系统升级,本质上是“整机版本升级”而非“增量补丁升级”。升级之前你必须回答三个问题:现在的版本是什么?升级包从哪里来?升级失败怎么回滚?
3.2 升级的三种常规路线
从操作路径上分,我见过的主流升级方式有三种:
第一种是包管理器升级路线,适用于开发板形态的产品或原型验证阶段。系统跑的是可读写 rootfs,直接apt、opkg或yum在线安装。这种方式开发调试很省事,但量产设备上很少采用,因为网络环境、包源稳定性和依赖关系都很不可控。
第二种是整镜像刷写路线,就是把整套系统做成一个完整的镜像文件(通常是.img或厂商自定义格式),通过烧录工具、dd命令或厂商专用刷机脚本写入 eMMC。这个方式最直接,恢复出厂也是同一套流程换一个镜像而已。缺点是你得停机刷写,而且一旦中途断电,板子就可能变砖。
第三种是 A/B 双分区升级路线,这是工业级产品最推荐的模式。板子上同时存在两个 rootfs 分区,系统总是从标记为 active 的那一个启动。升级时把新系统写入另一个分区,写入完成后把启动标志切换过去。这种方式的好处是“升级失败可以秒回滚”,代价是存储空间翻倍,对 eMMC 容量小于 8GB 的板子来说比较紧张。
这三种方式各有适用的场景,没有绝对的好坏。我自己的习惯是:研发阶段用第一种,小批量试产用第二种,正式稳定交付的项目用第三种。
3.3 升级前必不可少的备份动作
不管选哪种升级路线,备份这一步都不能省。很多人觉得“系统不是我做的,我没法备份”,其实工控系统备份没那么玄乎,关键分区抓下来就行。
先查看分区编号,再把关键分区备份成镜像:
cat /proc/cmdline dd if=/dev/mmcblk0p7 of=/data/backup/rootfs_before_upgrade.img bs=4M status=progress如果板子在运行,dd 线上备份正在使用的 rootfs 会有文件系统不一致的风险,更稳的做法是让系统先进入 recovery 模式,或者从 SD 卡启动一个最小系统再对 eMMC 做备份。我自己的习惯是备三样:bootloader 分区、boot 分区、rootfs 分区。这三个东西加起来一般不到 2GB,存到 U 盘或者 SD 卡里,升级真出了问题,十分钟就能回来。
这里要特别强调一个经验:备份的时候要在镜像文件名里写清楚版本号和时间,比如rootfs_v1.2.3_20250101.img。我曾经遇到过同事把两个版本的镜像放同一个目录,文件名只差一个字符,结果恢复的时候刷错了版本,在现场折腾了大半天才把系统找回来。
3.4 升级失败的现场救援思路
即使准备做得很充分,升级也还是有翻车的可能。真到这一步的时候,第一反应应该是保持冷静,然后按优先级处理:先确认硬件有没有彻底损坏,再看 bootloader 能不能进入恢复模式,最后才考虑重新刷写整个镜像。
大部分工控板 U-Boot 都内置了一个按键进入的恢复模式:按住特定按键上电,系统会进入 USB 烧录或 SD 卡启动模式。这种情况下你只需要一个烧录工具和一份原始镜像,就能把板子救回来。真正麻烦的是 eMMC 的 bootloader 区域也写坏了,这时候就只能用串口、JTAG 或者拆芯片重新烧,这个级别的维修一般只能找厂商或专业人员处理。所以我才一直强调升级动作要保守、方案要带备份和回滚,任何“刷完再看能不能开机”的做法在产线上都是拿设备寿命开玩笑。
4. OverlayFS 恢复出厂:原理与实操,一次讲明白
4.1 OverlayFS 是怎么“变出”一个可写文件系统的
OverlayFS 是 Linux 内核自带的联合文件系统,它把一个或多个只读目录和一个可写目录“叠加”成一个看起来完全可写的目录。你可以把它想象成一张贴在墙上的便利贴:墙上的内容永远不变,便利贴上写的东西随意涂改;把便利贴撕掉之后,墙还是原来的墙。
具体到工控系统上,挂载关系通常是这样的:
- lowerdir:只读的 rootfs 分区,比如
/dev/mmcblk0p7 - upperdir:一个可写的存储区域,通常是 data 分区里的一个目录,比如
/data/overlay/upper - workdir:OverlayFS 内部用于元数据管理的目录,比如
/data/overlay/work
系统启动时,把三部分联合挂载到/,应用层看到的是一份“可写”的完整系统。所有对系统的修改(新增文件、修改配置、安装软件)都写进 upperdir,而 lowerdir 里的原始系统文件始终保持原样。
恢复出厂的原理也就在这:把 upperdir 清空,重启之后系统就回到了和刚烧录时一模一样的状态。这比重新刷写镜像快得多,也不需要停机断网,非常适合产线和远程运维场景。
4.2 先用 mount 看清当前状态
开始操作之前,先用mount | grep overlay看看当前系统是不是真的跑在 OverlayFS 上。典型的输出大概长这样:
overlay on / type overlay (rw,relatime,lowerdir=/mnt/rootfs-ro,upperdir=/data/overlay/upper,workdir=/data/overlay/work)看到这行说明系统已经按预期用上了 OverlayFS。如果输出的挂载点不是/,或者完全没有 overlay 输出,那说明你的系统没启用 OverlayFS,恢复出厂也就无从谈起——你面临的是另一个问题,可能需要对 rootfs 做只读化改造,这属于进阶内容,这里先按下不表。
还有一个细节,很多人在df -h里看到根目录显示overlay而不是/dev/mmcblk0pX,就开始担心系统是不是坏了。这不是异常,OverlayFS 挂载的根目录在df里的显示就是 overlay。真正要关注的是/data/overlay/upper所在分区的剩余空间,因为所有的运行时写入都在消耗它。
4.3 恢复出厂的三种实现方式
恢复出厂的实现方式没有唯一标准,我根据自己的项目经验整理成表格,你可以按场景选用:
| 实现方式 | 操作复杂度 | 恢复速度 | 适用场景 |
|---|---|---|---|
| 清空 upperdir 后重启 | 低 | 中 | 现场运维、远程恢复 |
| 用脚本封装备份镜像到独立分区再恢复 | 中 | 高 | 量产设备、定时自动恢复 |
| 利用 u-boot 环境变量触发恢复 | 高 | 高 | 设备频繁被误改配置的场景 |
最简单直接的方式是清空 upperdir:
rm -rf /data/overlay/upper/* rm -rf /data/overlay/work/* sync reboot但注意,如果系统当前正在运行,直接rm -rfupperdir 里的文件会存在正在占用的情况,效果不一定干净。所以更稳妥的做法是:先切换到单用户模式或进入一个临时的 initramfs 环境,再执行清理。如果你对系统掌控力比较强,也可以写一个 systemd 服务,让系统在重启前自动完成清理动作。
我实际项目里用的是一套“双重保险”方案:一份恢复出厂脚本放在 data 分区,一份放在 boot 分区。正常情况下用脚本恢复;万一 data 分区都出问题了,就从 boot 分区加载恢复脚本,用只读镜像里的备份数据重建整个 upperdir。
4.4 实操演示:完整跑一遍恢复出厂
下面是一个可直接参考的恢复出厂脚本,我没有用生产环境的完整代码,但保留核心逻辑,关键是让你看懂顺序和判断逻辑:
#!/bin/bash # factory_reset.sh OVERLAY_DIR="/data/overlay" FACTORY_ROOTFS_IMG="/data/backup/rootfs_factory.img" log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $@" } # 1. 检查当前挂载 mount | grep "overlay on / " || { log "overlay not found, exit" exit 1 } # 2. 配置需要保留的数据,比如业务证书、校准参数等 PRESERVE_LIST="/data/overlay/etc/ssl /data/overlay/etc/calibration" # 3. 把需要保留的数据临时移到安全位置 for item in $PRESERVE_LIST; do if [ -d "$item" ]; then cp -a "$item" /data/preserve_tmp/ 2>/dev/null || true fi done # 4. 重建 upper 与 work 目录 rm -rf "$OVERLAY_DIR/upper" rm -rf "$OVERLAY_DIR/work" mkdir -p "$OVERLAY_DIR/upper" mkdir -p "$OVERLAY_DIR/work" sync # 5. 从备份镜像恢复 rootfs(可选) if [ -f "$FACTORY_ROOTFS_IMG" ]; then dd if="$FACTORY_ROOTFS_IMG" of=/dev/mmcblk0p7 bs=4M status=progress sync fi # 6. 把保留数据放回去 for item in $PRESERVE_LIST; do cp -a /data/preserve_tmp/$(basename "$item") "$item" 2>/dev/null || true done log "factory reset done, reboot now" reboot这个脚本的执行顺序是精心排过的:先检查系统确实是 OverlayFS(避免误操作普通系统),再把需要保留的关键配置抽出来,然后彻底清空 upper 和 work,如果有更底层的出厂镜像也顺带刷回去,最后把保留数据放回,重启生效。
有读者可能问:upper 都清空了,保留的数据放回还有意义吗?有。工控设备往往有设备证书、Calibration 参数、序列号等属于“产品个体”的数据,真正的恢复出厂不能把这类数据一起抹掉。所以恢复出厂脚本的核心不是“全删”,而是“该删的删、不该删的留”。
4.5 恢复出厂后如何验证系统“真的干净了”
恢复出厂后不要急着下结论,一定要验证。我的验证清单有三条:
# 1. 确认 overlay 挂载正常 mount | grep overlay # 2. 确认关键配置确实回到了出厂版本 cat /etc/os-release cat /etc/version # 某些厂商的自定义版本文件 # 3. 确认业务关键服务自动起来了 systemctl status your-app如果系统里有多个配置版本历史,也可以在恢复前用快照方式留个存档,比如:
tar czf /data/backup/etc_before_reset_$(date +%Y%m%d_%H%M%S).tar.gz /data/overlay/upper/etc这样即使恢复出厂后又发现问题,你也能回头查之前改过什么配置,而不是两眼一抹黑。
5. 常见问题与排查技巧实录
5.1 OverlayFS 挂载失败排查
系统启动到一半就卡住,或者 shell 里发现根目录变成了/dev/mmcblk0p7而不是 overlay,这种情况往往不是 OverlayFS 配置写错了,而是挂载顺序出了问题。内核启动时 rootfs 先以 ro 方式挂载到临时目录,然后 init 脚本再把 overlay 联合挂载到/。如果 init 脚本里执行组合挂载时upperdir对应的分区还没有挂载好,OverlayFS 就会失败。
这类问题的排查思路是从dmesg入手:
dmesg | grep -i overlay看有没有明确的错误信息,比如file system on /dev/mmcblk0p4 is not supported或者No such file or directory。前者表示 data 分区的文件系统格式有问题,后者表示 upper 目录没创建成功。你也可以检查/etc/fstab里 data 分区的挂载顺序,确保它在 overlay 挂载之前就已经 ready。
5.2 dd 刷机后系统起不来
拿到一块新板子,很多人喜欢直接dd把镜像写到整块 eMMC,然后发现系统起不来。这种情况十有八九是镜像本身没问题,但 eMMC 的 boot 区域需要单独处理。很多工控芯片(Rockchip、Amlogic 等)都有专门的 bootloader 烧录流程,不能用通用的dd覆盖整块盘,必须用厂商烧录工具先烧 bootloader,再用dd写 rootfs。
如果你只能拿到一个完整的.img镜像文件,先不要急着dd,用fdisk -l 镜像文件看看里面的分区偏移,再用dd按偏移写入对应分区,别整盘覆盖。
5.3 升级后软件包与内核版本不匹配
这是我最常被问到的问题之一。现象是你通过包管理器升级了一个库或者驱动模块,重启后某个外设不工作了,查内核日志大概率是 module 版本不匹配。原因在于,工控板的内核通常不是发行版内核,而是厂商 SDK 深度定制过的,模块和内核的编译依赖很强,单纯升级用户态软件不会出问题,一旦动了内核模块,前后版本必须严格对应。
所以我的建议是:如果产品已经进入稳定交付阶段,不要用包管理器大版本升级内核模块;所有涉及内核的变更走厂商 SDK 重新编译,走整机镜像升级路线,这样虽然动作重一点,但可控性最强。
5.4 常见问题速查表
为了方便现场排查,我把遇到过的典型问题整理成一个速查表:
| 现象 | 大概率原因 | 处理建议 |
|---|---|---|
| 系统启动后根目录不是 overlay | init 脚本挂载顺序错误 | 检查 fstab 与 init 脚本 |
| 修改 fstab 后无法开机 | UUID/卷标不对或 fsck 顺序错 | 进入救援模式修正 fstab |
| df 显示 overlay 空间变小 | upperdir 所在分区被写满 | 清理 /data,或加大 data 分区 |
| dd 刷机后启动卡在 bootloader | bootloader 区域被覆盖 | 用厂商工具重新烧写 bootloader |
| 升级后某外设失效 | 内核模块版本不匹配 | 回到 SDK 重新编译内核与驱动 |
6. 最后说一点我的实际体会
做了这么久工控 Linux,最深的感触是:这些板子看着像 Linux,实际上和通用 Linux 系统是两个世界。通用 Linux 崇尚灵活,依赖包管理器随时可以升级;工控 Linux 崇尚稳定,哪怕损失一点便利性,也要确保设备在恶劣环境下长期可靠运行。存储配置、升级、恢复出厂这三件事,说到底都是在“稳定”和“可维护”之间找平衡。
我个人在配置一台新工控板时,一定会在第一时间做三件事:把 rootfs 挂成只读并启用 OverlayFS,给 data 分区留足余量,写一个经过现场验证的恢复出厂脚本并和镜像一起备份到多个存储位置。这三件事做完,后面不管怎么折腾设备,心里都有底。另外建议你把 reset 脚本、镜像文件、烧录工具这三样东西放到一个固定目录,并写一页 README 记录操作顺序,因为你永远不知道下一次需要它的时候,是不是正在产线现场、满手是灰、网络还连不上。
关于 OverlayFS 的更多细节(比如多层 lowerdir、灵活使用 workdir 的权限设计),以及 A/B 分区升级的完整操作流程,我在系列后续文章里再展开聊。这篇先到这里,希望对正在跟工控板较劲的朋友有帮助。