外观
用救援系统抢救数据
OMV 起不来了,或者磁盘、文件系统、RAID 出了问题,第一反应往往是赶紧「修」。但修复命令会改写原来的磁盘,修坏了,还能读出来的数据也没了。读完这一篇,你能用 Live 救援系统以只读方式读出数据,把数据复制到安全的地方,再考虑修复。
开始之前
- 一条总原则:先只读、先复制,再修复。 数据复制出来之前,不要运行任何会写入原盘的命令,包括
fsck、btrfs check这类检查修复工具的修复模式。 - 遇到具体症状,先看故障排查:磁盘或文件系统不见了、文件系统变成只读、RAID 降级,它们帮你判断要不要动用救援系统。本文用在磁盘有故障、系统起不来、阵列无法启动,需要先把数据读出来的时候。
- 命令在救援系统的 shell(root 身份)里执行,不是在 OMV 里。
- 你需要:一个救援系统 U 盘,和一个容量足够、状态健康的目的地存储(另一块硬盘,或者网络上的另一台机器)。
- 本文按各工具的官方手册整理,没有在实机上验证。拿不准的时候,先停下来,不要继续写入。
这些命令会改写原盘,数据复制出来之前不要运行
影响范围:下面这些常见的「修复」命令都会写入磁盘,用错场合会让还能读出来的数据变成不可读:fsck 或 e2fsck 带 -y、xfs_repair(不带 -n)、btrfs check --repair、mdadm --create、mdadm --assemble --force(对元数据已经过期的成员盘)、zpool import -f -F、对磁盘的任何格式化、初始化。
前置条件:先确认哪块是哪块盘(型号和序列号);先只读挂载并复制;磁盘本身有故障(I/O 错误、S.M.A.R.T. 失败)时,先用 ddrescue 做映像,所有后续操作都在映像上进行。
怎么回退:这些写入操作没有回退。所以先复制。数据特别重要又拿不准时,停止一切写入,把盘交给专业的数据恢复公司。
第一步:启动救援系统
- SystemRescue:一个专门为救援设计的 Live 系统,带有 mdadm、LVM、cryptsetup、btrfs-progs 和常见文件系统工具,从官网下载并写入 U 盘,写盘方法同 下载、校验并制作安装 U 盘。它是否带 ZFS 支持,以你下载版本的说明为准。
- Debian Live:同样可以,需要自己
apt install缺少的工具,要联网。 - OMV 系统盘还能启动 GRUB 的情况:omv-extras 的 kernel 插件可以把救援 ISO(Clonezilla、Finnix、GParted Live、SystemRescue)安装进 GRUB 菜单,见 内核插件:切换内核与 Proxmox 内核。
用救援 U 盘启动 NAS,进入命令行。接着认清每块盘:
sh
lsblk -o NAME,SIZE,MODEL,SERIAL,FSTYPE,LABEL,UUID,MOUNTPOINTS
smartctl -H -A /dev/<磁盘>按型号、序列号和容量,写下哪块是系统盘,哪几块是数据盘,哪块是准备拿来存救出来的数据的。/dev/sdX 的字母每次启动都可能变,不要凭字母判断。
第二步:选择策略
| 情况 | 做法 |
|---|---|
| 磁盘有 I/O 错误或 S.M.A.R.T. 失败 | 先用 ddrescue 把整盘做成映像,之后所有操作都在映像上做,见「第三步」 |
| 磁盘本身没问题,只是文件系统损坏或系统无法启动 | 只读挂载,直接复制 |
| RAID 缺了盘 | 先看成员盘的元数据,只读组装,见下面的表 |
| 文件系统挂不上 | 用只读的特殊挂载选项,或者用不需要挂载的 btrfs restore |
| 加密盘 | 用只读方式解锁,再挂载 |
第三步:磁盘有故障时,先做映像
磁盘已经出现读错误时,每多读一次都有可能让它变得更糟。GNU ddrescue 会先拷贝容易读的部分,把有问题的部分放到后面,并且用映射文件(mapfile)记录进度,可以中断续传。
目的地是另一块健康硬盘上的一个文件系统,剩余空间要大于整块故障盘。映像文件放在那里,命令里不要加 -f:ddrescue 在输出目标是磁盘设备时,不加 -f 会拒绝运行,这是防止写反的保险。
sh
mkdir -p /mnt/target
mount /dev/<目的地分区> /mnt/target
# 第一遍:先拷贝容易读的部分,跳过精细扫描
ddrescue -n /dev/<故障磁盘> /mnt/target/disk.img /mnt/target/disk.map
# 第二遍:直接访问磁盘,对坏区域重试 3 轮,用同一个映射文件接着做
ddrescue -d -r3 /dev/<故障磁盘> /mnt/target/disk.img /mnt/target/disk.mapddrescue 的参数顺序是「输入、输出、映射文件」,别写反。映射文件一定要保留,丢了就无法续传。
做好映像之后,把它以只读方式挂成一个设备,后面的操作就在这个设备上做:
sh
losetup --read-only --find --show --partscan /mnt/target/disk.img命令会打印出设备名,例如 /dev/loop0,分区是 /dev/loop0p1 之类。
第四步:按类型只读访问
下面每一行都是只读的做法。挂载点都用 /mnt/rescue:
sh
mkdir -p /mnt/rescue| 类型 | 命令 | 说明 |
|---|---|---|
| EXT4 | mount -o ro,noload /dev/<分区> /mnt/rescue | noload 不重放日志,避免写入。没有正常卸载过的文件系统可能有少量数据不一致 |
| XFS | mount -o ro,norecovery /dev/<分区> /mnt/rescue | norecovery 不做日志恢复,只能和 ro 一起用 |
| Btrfs | mount -o ro,rescue=nologreplay /dev/<分区> /mnt/rescue | Btrfs 的 ro 挂载默认仍会重放日志,要加上 nologreplay 才完全避免 |
| Btrfs,挂载失败 | mount -o ro,rescue=all /dev/<分区> /mnt/rescue | rescue=all 启用所有救援选项,要求内核 5.9 以上,且只能只读 |
| Btrfs,仍然失败 | btrfs restore -D /dev/<分区> /mnt/target/ | 不挂载,直接把文件从损坏的文件系统里捞出来。-D 是试运行,只列出会恢复的文件;确认后去掉 -D,常用 -v -i -m -x。它不会修改源设备 |
| LUKS | cryptsetup open --readonly /dev/<分区> rescue-crypt | 只读映射,再挂载 /dev/mapper/rescue-crypt |
| LVM | vgscan 然后 vgchange -ay,再 lvs 看逻辑卷 | 激活之后挂载 /dev/<卷组>/<逻辑卷>,同样带 ro |
| ZFS | zpool import 列出池,再 zpool import -o readonly=on -R /mnt/rescue <池名> | 不带参数的 zpool import 只列出,不导入。不要使用 -f 和 -F,除非你确切地知道后果 |
软 RAID(md)
如果阵列只是降级,盘和阵列都还在运行,不需要救援系统:在界面里换盘,用 存储器 → RAID 管理(Storage → Multiple Device)的恢复(Recover)把新盘加进阵列。降级的阵列上,新增(Add)和移除(Remove)可能是灰的,这是预期现象,以界面上的显示为准。步骤见 RAID 降级 和 软件 RAID 维护:换盘、扩容与重建。
下面的做法针对阵列无法启动、需要先把数据读出来的情况。先用只读命令看成员盘上记录的状态:
sh
mdadm --examine /dev/<成员分区> # 看这块盘上的元数据:阵列 UUID、级别、事件计数、成员状态
cat /proc/mdstat # 救援系统可能已经自动识别了一部分阵列然后只读组装。--readonly 让阵列以只读方式启动,不允许任何写入,也不会触发重建:
sh
mdadm --assemble --scan --readonly
cat /proc/mdstat缺了成员盘、阵列没有自动启动时,可以加 --run,让它以降级状态只读启动。不要加 --force 去强制组装:mdadm 手册说,需要强制才能启动的阵列「可能包含数据损坏」,强制组装还会把记录为故障或已过期的成员盘标记为可用。没有把握时,先对每块成员盘做映像,把 mdadm --examine 的输出保存下来,带着输出去求助,见 如何有效求助。
绝不要用 mdadm --create 重新创建阵列,它会写入新的元数据,除非你的参数与原来完全一致,否则会让原来的数据无法访问。
第五步:复制数据
只读挂载成功之后,立刻把数据复制到目的地:
sh
rsync -rltD --info=progress2 /mnt/rescue/<目录>/ /mnt/target/<目录>/- 参数含义和注意事项同 从群晖、TrueNAS 迁移到 OMV:源路径末尾的
/、不要加--delete、先用-n试运行。 - 优先复制最重要的数据,不要一上来就复制整盘。
- 读到坏文件时 rsync 会报错并继续,最后会列出失败的文件。把失败列表保存下来。
- 目的地在另一台机器上时,用
rsync -e ssh。
复制完成后,抽样打开几个文件确认可用。
第六步:收尾
按相反的顺序卸载,释放设备:
sh
umount /mnt/rescue
vgchange -an # 用了 LVM 才需要
cryptsetup close rescue-crypt # 用了加密才需要
mdadm --stop /dev/<阵列> # 用了软 RAID 才需要
zpool export <池名> # 用了 ZFS 才需要
losetup -d /dev/<loop 设备> # 用了映像才需要然后才是修复,而且只在数据已经复制出来、你也确认复制的数据可用之后。修复是另一个主题,从只读的检查开始:fsck.ext4 -n、xfs_repair -n、btrfs check --readonly 都只报告问题,不修改。对症的做法见 文件系统变成只读、RAID 降级 和 磁盘或文件系统不见了。如果是在映像上修复,成功之后再考虑把结果写回真实的磁盘。
最后,重启回到 OMV,新建文件系统并从备份恢复,原来的盘坏了就换新盘,见 系统盘坏了:重装并接回数据盘 和 恢复演练。阵列降级之后换盘,用 RAID 管理 里的恢复把新盘加进阵列,见 软件 RAID 维护:换盘、扩容与重建。
检查结果
- 救援系统里能看到目的地存储里复制出来的数据,文件数和大小符合预期,抽样能打开。
- 全程没有对原盘运行过会写入的命令。
- 原盘如果做了映像,映像文件和映射文件都妥善保存,直到确认数据没问题。
- 所有挂载都已卸载,映射设备已关闭,再关机。
常见问题
挂载报错 wrong fs type, bad option, bad superblock。 文件系统类型不对,或者元数据损坏。先 blkid /dev/<分区> 确认类型,再用对应的只读选项;仍然不行,对 EXT4 可以在映像上尝试用备份超级块,对 Btrfs 用 rescue=all 或 btrfs restore。
Btrfs 挂载提示 parent transid verify failed。 元数据已经不一致。先试 rescue=all 的只读挂载,不行就用 btrfs restore。
阵列提示只有一部分成员盘。 先检查线缆和供电,用 mdadm --examine 对比各成员盘的事件计数和阵列 UUID,找出落后或缺失的盘。事件计数落后很多的盘,数据可能已经过期,不要随便强制加入。
加密盘解锁失败。 确认密码或者密钥文件,注意键盘布局在救援系统里可能和平时不同。
盘根本识别不出来。 换线缆、换接口、换电源再试。仍然不行,不要自己拆盘,找专业的数据恢复服务。
我只想把 OMV 系统救活,不关心数据盘。 不在本文范围,见 系统无法启动 和 系统盘坏了:重装并接回数据盘。
参考资料
- Btrfs 官方文档:btrfs(5) 里的
rescue=挂载选项、btrfs-restore - Debian 手册:mdadm(8)、ddrescue(1)、zpool-import(8)
- SystemRescue