我的旧电脑(联想拯救者 R720)的做工不怎么样。经过四年的使用,那台电脑换过一块键盘,一块机械硬盘(换成了 SATA 固态硬盘),而且每次拆开电脑后盖时,后盖或者屏轴上都会掉点塑料碎屑或者螺丝下来,让人感觉它的命不久矣。因此趁着打折,我买了一台新的笔记本电脑,并打算把我的数据迁移过去。
我日常使用的 Arch Linux(包括 EFI 分区和 Btrfs 格式的根分区)都单独装在我半年前买的西部数据 SN550 1T 固态硬盘上。一般来说我需要在新电脑上重新装一遍系统,但是我一想,我在系统上也没针对硬件做很多的特殊配置,顶多就是配置了一下触摸板和 NVIDIA 显卡,只要在新电脑上把这些配置删了再调整一下,我的系统就直接能用了,方便省事。
于是我就把这块固态拆下来,插进了新电脑的第二个 M.2 插槽。开机进入启动菜单,BIOS 自动识别到了硬盘上的 EFI 分区。很快我就重新进到了桌面。
作为 Arch Linux 用户,进系统后的第一件事当然是 sudo pacman -Syu
。正当系统顺利更新的时候,突然出现了一个提示:「No space left on device」,然后更新过程就退出了。我 df -h
看了一下,1TB 的固态硬盘我才用了 600GB 左右啊?怎么回事?
我重新运行了一下 sudo pacman -Syu
,结果出现了另一个提示:「Read-only Filesystem」。我 mount
命令看了一下,发现根分区已经变成了 ro
只读状态。
问题有一点大
我看了下 dmesg
,结果出现了一大片 Btrfs 的错误提示,大意是在某个数据块发现数据和校验码对不上。
问题有亿点大
关机,掏出 U 盘启动 Arch Linux 的安装 ISO。先 smartctl -a /dev/nvme0n1
看了下,硬盘健康度(备用闪存空间余量)100%,数据错误 0 次,奇怪。然后 btrfs check /dev/nvme0n1p2
。扫描 10 分钟后,Btrfs 告诉我有三个文件损坏了。其中两个是 pacman
下载的软件包,还有一个是 Java 的 OpenJFX 组件。我记下了这个组件的名字,准备一会重装这个软件包,并删掉了这三个损坏的文件。重新跑了一遍 btrfs check
,一切正常。
问题不大
我一边想着「Btrfs 的数据怎么会莫名其妙坏掉」一边重启,结果这次直接在启动流程 Kernel Panic 了,调用栈上全是 Btrfs 的函数。
问题有一点大
在再次用 U 盘启动的时候,我突然想起了一件事。我确实在旧电脑上针对硬件做了特殊配置,具体来说我用 Intel-Undervolt 把 CPU 的电压降了 0.1V 来省电。对于 Intel 的第七代笔记本 CPU 来说,比如我的旧电脑的 i7-7700HQ,降 0.1V 电压对稳定性没有丝毫影响,但功耗和发热却能降低很多。但是从第八代 Intel 笔记本 CPU 开始,有了 AMD 的竞争,Intel 的笔记本 CPU 都是出厂即灰烬,没什么降压空间。此时我的配置就过度降低了 CPU 电压,导致它运行不稳定。
问题不大
我挂载上 Btrfs 分区,把 Intel-Undervolt 的配置连带它的二进制文件都删了,再次重启。虽然这次没有 Kernel Panic,但是 Btrfs 提示了一堆 Metadata 损坏的信息,然后没能挂载上 /home
的 Subvolume。
问题有亿点大
作为一个长期的 Btrfs 用户,我早就知道 Btrfs 的硬盘分区结构极其复杂,一旦 Metadata 损坏几乎没有找回数据的可能。为了避免这种情况,我前段时间开启了 -m dup
选项,将 Metadata 信息在盘上保存两份。回到安装环境,我再次运行 btrfs check
。它找到了一块损坏的 Metadata,显示它的校验码错误。然后它找到了另一份备用的 Metadata,并显示了一个一模一样的校验码错误。
两块 Metadata 都坏了
我尝试先把数据拷走。我插上了备份数据用的移动硬盘,然后 cp -r /mnt/home /backup_usb/
,结果只看到满屏的「Input/output error」,一个文件也没拷出去。没办法,我运行了 btrfs check --repair
,结果整个 /home
Subvolume 都空了。
完 了
我看了一下备份盘,上次备份是在今年 8 月。不过好在我平时把大部分文件都传到了 GitHub 或者我的私人 Git 服务器上,剩余的文件大都可以从其它地方获取到(比如 Steam 游戏库),所以这 4 个月来的数据损失不大。
接下来就是冗长的重装系统过程了。
回顾
Btrfs 分区的 Metadata 大概率是在第二次尝试进入系统、Btrfs Kernel Panic 的时候损坏的,原因应该是 CPU 过度降压导致与内存或者固态硬盘的通信不稳定,或者校验码计算错误。
只要电脑不完全断电,Intel-Undervolt 的配置都是不会失效的。但因为我每次 U 盘启动前都是长按电源关机,电脑都是冷启动,所以在 U 盘的安装环境里,CPU 的电压是正常的,可以正常稳定地进行操作。
教训
- 重要数据遵循 3-2-1 原则,也就是至少保留 3 份副本,其中 2 份在本地(包括正在使用的一份,和备份的一份),1 份在其它地方(比如网盘或者对象存储)。
- 只要 Btrfs 有任何异常,都要先只读挂载分区,备份剩余的数据,再关闭只读进行下一步的检查和修复。这一点对于其它 CoW 文件系统(例如 ZFS)应该也适用。