一个BTRFS用户的噩梦

发表于:

大概10天前,我在睡觉前跑了一次pacman -Syu,把Linux Kernel更新到了5.16.1.arch1-1

第二天早上起来打开电脑,明显能感觉整个系统都在卡。看下htop,有一个叫btrfs-cleaner的进程吃满了一个cpu核心。我最先想到的是Timeshift在后台存的20多个快照(snapshot)。清理一波之后,从鼠标指针来回跳到大概每15分钟卡几秒,也算是挺大进步。

进一步研究

忍了一阵之后,我打算彻底研究一下这奇怪的btrfs-cleaner进程。 这时我注意到还有一些其他的进程cpu占用异常,例如btrfs-transactionbtrfs-endio。搜索一番之后发现几年前就有类似问题的报告。问题主要集中在磁盘碎片化不平衡(unbalanced)上。既然是长期顽疾就好,总比遇到新问题没有现成解决方案要好,只要之后一个个试就万事大吉。

搜索过程中还在Linux的邮件列表里找到一个相近的问题,标题是「5.16更新后btrfs-cleaner疯狂的IO占用」1。扫读了一下是关于一个在碎片整理代码里的bug,会导致在尝试处理一个1字节文件的时候无限循环。

尝试修复

不知道当时我怎么想的,我决定手动跑一下碎片整理(defrag)。因为自动碎片整理出了问题就是应该手动运行一下。 记得时间大概是晚上9点,我在命令行执行了 btrfs filesystem defragment -rvf /。 这行指令只输出了几个文件的路径之后就没了动静,但还是有少量的cpu占用。这时我还意识到这bug到底会引起什么问题,决定隔夜挂机让他接着跑。

第二天7:30我起来上课。btrfs defrag的进程还没结束。因为整个电脑卡的不行,又着急用,没办法必须停掉。结果ctrl+c再甚至SIGKILL对这进程一点作用没有,最后只好强制关机。重启后卡顿问题也没什么明显改善。下课之后我又跑了下btrfs filesystem balance start -dusage=10 /(文件系统平衡),这次确实有效果,感觉好了一半。用-dusage=15 flag之后卡顿彻底没了。btrfs-cleaner的cpu占用基本低于5%,可以接受但肯定不如之前好,暂且算是性能退化。

惊吓

昨天晚上,1月30号,晚上躺床上刷Reddit,看到u/TueOct5在r/selfhosted发了一个标题为「PSA:Linux 5.16更新导致BTRFS极端IO负载」2的帖子。在帖子里他声称开启了 autodefrag的BTRFS卷(volume)在10天里往他的ssd里写了188 TB的数据。卡顿症状和我这看到的情况基本一致,我心立马凉了一半。想起之前看文档的时候特意把autodefrag打开,又凉了另一半。更难受的是之前还特意跑了手动碎片整理,那小10个小时的暴力写入怕不是已经把ssd快干废了。但是时间已经过了12点,且人已经在床上了,纠结这玩意也没用,干脆睡了。当然最后也没怎么睡好。

时间回到现在,2月1日。早上起来,第一件事就是看一下/etc/fstab

# /etc/fstab: static file system information.
#
# Use 'blkid' to print the universally unique identifier for a device; this may
# be used with UUID= as a more robust way to name devices that works even if
# disks are added and removed. See fstab(5).
#
# <file system>             <mount point>  <type>  <options>  <dump>  <pass>
UUID=2bc561d8-84b3-42b7-acef-b2f826854ffb /              btrfs   subvol=/@,defaults,noatime,space_cache,autodefrag,compress=lzo 0 1

autodefrag肯定是开着呢。删掉并重启之后,卡顿彻底消失,btrfs-cleaner也不吃cpu了。这时候心理准备已经做足了,现在看看我的ssd到底还剩多少寿命。

损失计算

计算SSD总写入量还挺麻烦的. 根据这个StackExchange上的问题, 把Total LBAs Written乘上Logical Block/Sector Size就好。用smartctl -a /dev/sdc可以轻松读出设备的SMART信息。

=== START OF INFORMATION SECTION ===
Sector Size:      512 bytes logical/physical
...

Vendor Specific SMART Attributes with Thresholds:
ID# ATTRIBUTE_NAME          FLAG     VALUE WORST THRESH TYPE      UPDATED  WHEN_FAILED RAW_VALUE
241 Total_LBAs_Written      0x0032   099   099   000    Old_age   Always       -       79405462234

512字节乘上79405462234,结果大概是37878 TB,显然不可能。 最后还是去用了三星的ssd管理软件(AUR),显示的值基本可信。

---------------------------------------------------------------------------------------------------------------------------------------------
| Disk   | Path     | Model                     | Serial               | Firmware | Optionrom | Capacity | Drive  | Total Bytes | NVMe Driver |
| Number |          |                           | Number               |          | Version   |          | Health | Written     |             |
---------------------------------------------------------------------------------------------------------------------------------------------
| 2      | /dev/sdc | Samsung SSD 860 EVO 500GB | S4XDNF0MB39562P      | RVT03B6Q | N/A       |   465 GB | GOOD   | 36.98 TB    | N/A         |
---------------------------------------------------------------------------------------------------------------------------------------------

36 TB写入,对于一块用了小两年的ssd来说,还挺正常的。我一通乱搞竟然还救回了我这块ssd,现在感觉还挺神奇的。

总结

  1. BTRFS绝对不是最稳定的文件系统

    基于玩垃圾arm板子的经验,在稳定性上ext4绝对是第一。如果用RAID的话,ZFS也是一个不错的选择,当然储存池大小改不了挺难受的。不需要花哨功能(COW,快照等)的情况下不建议选择BTRFS。

  2. 前沿(Cutting-edge)更新是稳定的反义词

    受了这么一番惊吓之后,我肯定是要换到LTS kernel了。仔细一想,自己真的没有必要去冒这个风险。如果对安全有特殊需求的还可以用hardened kernel,怎么都比cutting-edge要好。

感谢阅读,祝新春愉快。


  1. 原文 Massive I/O usage from btrfs-cleaner after upgrading to 5.16 ↩︎

  2. 原文 PSA: Linux 5.16 has major regression in btrfs causing extreme IO load ↩︎