这两天我顶着毕设中期的事情, 在某人的怂恿下重装了我的台式机, 把 3 年多的 Linux Mint 给扬了 (它实在是太脏了… 里面是沉重的历史x). 我当时确信我备份过数据, 于是把我的数据盘都格式化了, 重新组了 RAIDz1. 前天我要找东西的时候, 突然发现, 我的备份机器上缺少一些 zfs dataset. 我的备份呢?

于是前天我四处翻找, 最终恢复了大概 2025 年 5 月之前和 2025 年 11 月之后的大部分数据. 我甚至不知道我是否丢了数据 / 丢了多少数据 — 我完全不记得那个加密的 dataset 里面有什么了. 于是就有了这个事故复盘让大家笑一笑.

错误的备份

当时我台式机上面的备份策略是这样的: 我有两块 2T 盘, 一块是 ext4, 里面有一个叫 ajax 的目录是 ecryptfs, 有一个 timeshift 目录来存当时 / 的快照; 另一块是 zfs, root dataset 里面有一坨东西, 还有一个叫 sec 的加密 dataset, 是我的科研数据.

我的服务器 上面的阵列建好之后, 我第一时间对这两块盘做了备份 (问 GPT 和 GLM 确认参数的... 都是他们的锅 x), 但是两个备份其实都是错误的x

对于 ext4 的盘, 考虑到 timeshift 里面都是史, 而且又臭又长, 全是小文件, 我当时让 GLM 生成了 rsync 的备份命令, 排除了 timeshift 目录:

1
rsync -aHAXz --compress-level=6 --numeric-ids --info=progress2 --exclude='timeshift/' /data/ r.aajax.top:/tank/pc-packup/data/

(你别问为啥是 packup… 我当时 zfs 写错了)

其带来的副作用是, /data/ajax 文件夹当时是解密状态, 因此在备份时 rsync 直接把加密的文件当作普通文件处理, 在备份机器上不再加密了. /data/.secret 是实际的 ecryptfs 的加密文件, rsync 也同时备份了一份. 结果: 原本加密的数据在备份之后变成了明文 + 加密两份, 失去了部分安全性.

而对于 zfs 的盘, 我生成了一个递归快照:

1
zfs snapshot -r data2@260301

我当时 以为 这个快照的意义是, data2@260301 会包含 data2 以及它下面的所有 dataset 的数据. 但是实际上, 这个快照只包含了 data2 dataset 的数据, 这个命令 同时创建data2/sec@260301 快照.

基于这样的误解, 我在要求 GLM 生成备份命令的时候, 只让它备份了 data2@260301 这个快照. 同时, 由于我不想备份 zfs 的整个历史记录 (auto-snapshot 里面有一坨大的), 我要求 GLM 仅备份这一个快照, 不要备份整个历史记录.

1
sudo zfs send data2@260301 | pv | ssh -C r.aajax.top "sudo zfs receive -uFd -x mountpoint tank/pc-packup/data2"

其结果是, data2/sec 这个 dataset 的数据 没有被备份, 而我并不知道.

正确的备份方式应该是:

1
sudo zfs send -Rw data2@260301

重装系统

在重装系统的时候, 我 认为 我已经备份了所有数据, 我找了第三个 2T 的机械盘做 RAIDz1, 于是把之前的两块盘都格式化了. 由于 zfs 的加密 dataset 默认不会挂载, 我当时 并没有检查 data2/sec 在我的备份机器上是否存在. 于是, 我清除了这两块盘的分区表, 重新创建了 zpool. 此时 data2/sec 中的数据应该已经遭到了一定的破坏.

在重装系统之后, 这个新的 zpool 被挂载了 /home, 随着系统使用, 新的数据被写入了这个 zpool, 进一步覆盖了之前 data2/sec 中的数据.

重装系统的时候我并没有抹掉原来的 / 分区, 只是缩小了 50G 做 zfs metadata dev, 因此我现在还能翻找当时的历史记录, 总结经验教训x

发现问题

前天我做中期 PPT 到一半突然需要一些数据, 于是打开备份机器, zfs load-key, 提示我没有对应的 dataset. 我一脸问号敲了 zfs list, 发现 tank/pc-backup/data2 里面没有 sec 这个 dataset. 为什么呢? 经过了 5s 的思考, 我觉得应该是备份的时候 subdataset 没有正确上传 sec 子卷. 又经过了 1s 的思考, 我觉得恢复数据的可能性几乎为 0, 且不值得折腾, 应当迅速从可能的其它位置恢复数据.

恢复数据

我在 data 的备份中找到了 2025 年 5 月 7 日的备份. 当时还没有 data2/sec 这个 dataset, 所有数据是明文存储的, 我打了一个 tar.

6 - 8 月我主要在折腾保研的一堆事情, 似乎没有什么很多的数据在里面; 后来 8 月左右给学姐的论文画图, 大部分数据都在课题组的服务器上有一份, 这个加密卷里面是服务器的备份. 这些数据从服务器上找回.

9 月我给另一篇学长的论文画图, 基本复用了 8 月这些图的代码; 另一部分代码也在服务器上, 加密卷里面是服务器的备份. 这些数据从服务器上找回. 此外, 我更新了一版 mobileinsight 代码, 其已经推到 GitHub, 且在我的笔记本上有一份备份. 这些数据从笔记本重新上传.

10 - 11 月因为超算的事情 + 还有课没怎么干活. 超算不属于课题组的数据, 因此不在此加密卷内.

12 月主要干的是逆向的活, 由于还没干完 (至今依然在干), 因此在笔记本上仍有最新数据, 加密卷上是备份. 这些数据从笔记本重新上传.

1 月在折腾测绘的项目. 项目结束后我把数据都打包上传到了加密卷, 但是由于其实刚结束不久, 这些数据尚未从我的笔记本中删除. 这些数据从笔记本重新上传.

2 月又在逆向; 加上过年, 其实没啥更新. 3 月就更近了, 这些东西都还在笔记本上.

而我当时要找的那个东西… 由于其比较敏感, 我在一块 U 盘上离线仍有一份备份. 这些数据从 U 盘重新上传.

综上, 我基本恢复了意外丢失的加密卷中的数据. 恢复率有多少呢? 我其实不知道 — 毕竟我记不得那里面还有什么了.

事后处理

我在我的服务器的阵列上重新创建了一个加密卷, 将这些恢复的数据重新传了回去. 同时, 我在新建的 PC 的 zfs 上进行了备份. 这次没有子卷了! 总不能爆炸了吧…x

经验教训

  1. 记得 Dry Run!!! 备份之后一定要检查是不是真的备份了.
  2. 删之前不要想当然觉得自己 “一定备份了”…
  3. 硬盘阵列不是备份
  4. ZFS Encryption 在备份情况下或许会有坑…
  5. 少折腾些有的没的…