Openwrt完整备份以及exroot挂载/overlay的思考

openwrt

OpenWrt项目是一个针对嵌入式设备的Linux操作系统。OpenWrt不是一个单一且不可更改的固件,而是提供了具有软件包管理功能的完全可写的文件系统。这使您可以从供应商提供的应用范围和配置中解脱出来,并且让您通过使用适配任何应用的软件包来定制设备。对于开发人员来说,OpenWrt是一个无需围绕它构建完整固件就能开发应用程序的框架; 对于普通用户来说,这意味着拥有了完全定制的能力,能以意想不到的方式使用该设备。

项目地址

openwrt.org

为什么要完整备份openwrt?

为了无缝升级!为了能在升级的同时不丢失配置文件及软件包

总所周知,openwrt的文件系统的精华思想是overlay

/overlay 是什么意思呢?

OpenWRT 一般使用的文件系统是 SquashFS ,这个文件系统的特点就是:只读。
那,一个只读的文件系统,是怎么做到保存设置和安装软件的呢?
这里就是使用一个 /overlay 的分区,overlay顾名思义就是覆盖在上面一层的意思。
虽然原来的文件不能修改,但我们把修改的部分放在 overlay 分区上,然后映射到原来的位置,读取的时候就可以读到我们修改过的文件了。
但为什么要用这么复杂的方法呢? OpenWRT 当然也可以使用 EXT4 文件系统,但使用 SquashFS + overlay 的方式有一定的优点。
首先 SquashFS 是经过压缩的,在路由器这种小型 ROM 的设备可以放下更多的东西。
然后 OpenWRT 的恢复出厂设置也要依赖于这个方式。在你捅 Reset 重置的时候,它只需要把 overlay 分区清空就可以了,一切都回到了刚刷进去的样子。
如果是 EXT4 文件系统,就只能够备份每个修改的文件,在恢复出厂设置的时候复制回来,十分复杂。
当然,SquashFS + overlay 也有它的缺点,修改文件的时候会占用更多的空间。
首先你不能够删除文件,因为删除文件实际上是在 overlay 分区中写入一个删除的标识,反而占用更多的空间。
另外在修改文件的时候相当于增加了一份文件的副本,占用了双份的空间。

总结来说,overlay文件系统的优点在于只记录修改量,类似于增量更新,非常适合路由器这类小ROM和RAM的嵌入式设备

网上的备份方法遇到的问题

目前网上主要有两种完整备份openwrt的方法,

MTD(Memory Technology Device)备份

查看 firmware 所对应的 mtd 编号

1
2
3
4
5
6
7
8
root@EBIN:~# cat /proc/mtd
dev: size erasesize name
mtd0: 00020000 00010000 "u-boot"
mtd1: 000e43ec 00010000 "kernel"
mtd2: 00eebc14 00010000 "rootfs"
mtd3: 004c0000 00010000 "rootfs_data"
mtd4: 00010000 00010000 "art"
mtd5: 00fd0000 00010000 "firmware"

使用Linux的 dd命令备份完整固件

1
dd if=/dev/mtd5 of=/tmp/firmware_backup.bin

连上SSH,比如刷一个新固件,将 firmware_backup.bin 上传到 /tmp 下,利用 mtd 命令恢复

1
mtd -r write /tmp/firmware_backup.bin firmware

仅对 /overlay 打包备份

1
tar -czvf /tmp/overlay_backup.tar.gz /overlay

需要恢复的时候将 overlay_backup.tar.gz 上传至 /tmp ,然后清空 /overlay 并恢复备份:

1
2
3
rm -rvf /overlay/* 
cd /
tar -xzvf /tmp/overlay_backup.tar.gz

稳妥的办法:只保留设置升级,备份软件包列表,opkg恢复软件包

What to do:

备份软件包列表

Make a LIST of all currently install packages:

1
opkg list-installed > /etc/config/my_installed_packages

将备份脚本放到CRONTAB 里面定期执行

You might want to put the command into a CRON … depending on how much you keep changing the packages on your router:

EDIT this file, which keeps track of what to SAVE during image upgrades:
/etc/sysupgrade.conf

AFTER an upgrade run this command:

勾选保留设置升级(只备份/overlay/upper/etc文件夹的内容(openwrt默认备份内容))之后,用opkg命令恢复已安装的软件包

1
opkg update && opkg list-installed | cut -f 1 -d ' ' | sort -u > /tmp/currentpkg && cat /etc/config/my_installed_packages | cut -f 1 -d ' ' | sort -u > /tmp/oldpkg && grep -v -F -x -f /tmp/currentpkg /tmp/oldpkg > /tmp/inst && opkg install $(cat /tmp/inst | sort -u) && rm /tmp/currentpkg /tmp/oldpkg /tmp/inst

This will compare your current (after upgrade)

exroot挂载/overlay的一些bug

严格意义上来说不算bug,不过如果你遇到的话,或许这里的解决方法能提供一些帮助

openwrt的路由器或者主机,在挂载外置SD/TF/U盘为/overlay后,如果遇到升级或者/overlay文件系统UUID不一致无法启动
原因是升级21.0.1 -> 21.0.2的openwrt后,原本作为/overlay的外置SD无法启动了,拔掉SD卡正常

分析kernel.log内核日志,其中有这么一行:
“block: extroot: UUID mismatch”

UUID和系统/etc/fstab的UUID不一致,导致无法正确挂载SD卡

原来解决了一下午找不到原因,后来查阅openwrt官方文档:

If you receive a “block: extroot: UUID mismatch” error in your logs after upgrading, remove .extroot-uuid from the volume:

1
2
3
mount /dev/sda1 /mnt
rm -f /mnt/.extroot-uuid /mnt/etc/.extroot-uuid
umount /mnt

官方的建议是把exroot的etc/.exroot-uuid删掉,因为这个可能是升级备份前的UUID,与现在挂载的UUID不一致

顺利解决!!!

有什么问题还是多看看官方的文档吧,从原理上解决问题,而不是把报错的Log随便扔到google/百度/stackoverflow上面一搜(简单问题除外),这样不利于解决问题,也没法学习到一些系统的底层框架的原理。