工控机 SSD 的 TRIM 缺陷引发 fnOS 高 IO 等待的排查与解决
设备硬件环境
| 项目 |
详情 |
| NAS 系统 |
飞牛私有云 fnOS |
| 内核版本 |
6.18.18-trim |
| CPU |
双核 x86_64 |
| 系统盘 (SSD) |
SSD64G(59GB SATA SSD,工控机自带杂牌盘) |
| 数据盘 (HDD) |
465.8GB 机械硬盘 |
| 存储布局 |
/vol1(Btrfs)位于 SSD,承载系统及 Docker;/vol2(Btrfs)位于 HDD |
磁盘具体分配情况(lsblk -o NAME,TYPE,SIZE,ROTA,MOUNTPOINT 摘要):
NAME TYPE SIZE ROTA MOUNTPOINT
sda disk 465.8G 1
**─sda1 part 465.8G 1
**─md1 raid1 465.6G 1
**─trim_...-0 lvm 465.6G 1 /vol2
sdb disk 59G 0
**─sdb1 part 94M 0 /boot/efi
**─sdb2 part 31.9G 0 /
**─sdb3 part 27G 0
**─md0 linear 27G 0
**─trim_...-0 lvm 27G 0 /vol1
一句话结论
工控机自带的 SSD(型号 SSD64G)固件存在 TRIM 指令处理缺陷,飞牛系统默认开启的在线 discard 触发了硬件错误,内核反复重试导致 IO 等待飙高。
下面详细记录排查过程和解决方法。
问题现象
近期发现 NAS 操作响应变慢,Web 界面偶尔卡顿。用 top 观察,CPU iowait 经常在 50%~90% 之间波动。使用 iostat -x 1 5 进一步查看,发现系统盘 sdb 及其映射设备存在大量 discard 操作:
iostat -x 1 5
典型输出:
Device ... d/s dkB/s %util
dm-0 ... 32.00 2097152.00 99.60
md0 ... 32.00 2097152.00 99.60
sdb ... 32.00 2097152.00 92.40
d/s 每秒约 30 次 discard 请求
dkB/s 接近 2GB/s
%util 打满到 90%+
- CPU
%iowait 在 60%~80%
而机械盘 sda 的 d/s 为 0,问题明显集中在 SSD 上。重启后暂时缓解,但一天左右又会复发。
排查过程:从软件到硬件
1. 检查挂载选项
mount | grep vol1
输出包含 discard=async,表明飞牛对 SSD 上的 Btrfs 默认开启了在线丢弃。这本身是合理的设计——SSD 开启在线 TRIM 有助于性能维护。但在我的设备上,这恰恰触发了问题。
2. 尝试关闭在线 discard
先后试了三种方法:
- 修改
/etc/fstab 添加 nodiscard:IO 风暴停止,但 fstrim 也失败了,说明 nodiscard 把 TRIM 通道全关了。
- 将
discard_max_bytes 设为 0:风暴停止,但 fstrim 仍然失败,且重启前无法恢复。
- 修改
/etc/mountmgr/mount_info.json:文件中根本没有 discard 字段,飞牛是动态追加的。
三种方法都能停掉风暴,但 fstrim 始终报错,这提示问题可能不在软件配置层面。
3. 内核日志发现真相
查看内核日志:
sudo dmesg | tail -30
发现了关键错误:
ata2.00: failed command: DATA SET MANAGEMENT
sd 1:0:0:0: [sdb] tag#11 Sense Key : Medium Error [current]
sd 1:0:0:0: [sdb] tag#11 Add. Sense: Address mark not found for data field
I/O error, dev sdb, sector 92387328 op 0x3:(DISCARD) flags 0x800
op 0x3:(DISCARD) 明确指示这是 TRIM 指令触发的错误。Sense Key 为 Medium Error,说明 SSD 的固件在处理 DISCARD 命令时直接返回了介质错误。
至此确认:这块工控机自带的 SSD64G 固件存在 TRIM 指令处理缺陷,一收到 DISCARD 命令就报错。 飞牛的 discard=async 让内核不断发送 TRIM 请求,SSD 每次都报错,内核反复重试,最终形成 discard 风暴。
关于这块 SSD
SSD64G 常见于工控机、软路由、部分国产迷你主机自带的 SATA 固态硬盘,多采用慧荣(SM2258XT)或联芸主控搭配低端闪存颗粒。网上也能搜到类似型号在 Linux 下执行 TRIM 时报 Medium Error 的讨论,并非个例。
这类盘的 TRIM 问题属于硬件层面的缺陷,无法通过固件升级或软件配置修复。唯一的根本解决方式是更换一块主流品牌的 SSD。
解决方案:内核参数禁止在线 discard
既然硬件不支持 TRIM,就需要从内核层面阻止 Btrfs 发出任何 discard 请求。Linux 内核提供了 btrfs.discard=0 参数,它会忽略所有挂载选项中的 discard,但不影响用户态 fstrim(正常 SSD 仍可手动回收)。
操作步骤:
-
编辑 GRUB 配置文件:
sudo nano /etc/default/grub
在 GRUB_CMDLINE_LINUX_DEFAULT 行末尾添加 btrfs.discard=0:
GRUB_CMDLINE_LINUX_DEFAULT="quiet splash btrfs.discard=0"
-
更新 GRUB 并重启:
sudo update-grub
sudo reboot
-
重启后验证:
iostat -x 1 5 中 d/s 归零,%iowait 回到正常水平。
mount | grep vol1 仍显示 discard=async(飞牛自动添加),但内核已忽略。
- 由于硬件缺陷,
fstrim 仍会失败。
-
禁用系统自带的每周 TRIM 定时器(避免无意义报错):
sudo systemctl disable --now fstrim.timer
效果对比
| 指标 |
修复前 |
修复后 |
| CPU iowait |
50%~90% |
0%~10% |
| discard d/s |
30+ |
0 |
| %util |
90%+ |
正常 |
| 重启后是否失效 |
会复发 |
永久生效 |
其他可能导致 IO 高的情况
如果排查了 discard 问题后 IO 仍然偏高,可以检查:
- 迅雷 / 网心云插件:有用户反映禁用插件后恢复正常。
- upload 上传服务:Web 上传后可能触发 iowait 飙升。
- 相册同步 / USB 外接硬盘:后台同步或易驱线连接可能导致异常 IO。
- Docker 容器:运行
sudo iotop -o 查看高 IO 进程。
小结与建议
这次问题的核心是工控机自带的杂牌 SSD 固件存在 TRIM 指令处理缺陷,而飞牛默认对 SSD 开启在线 discard 恰好触发了这个硬件问题。排查过程中的几点体会:
- 高 iowait 时先看
iostat 的 d/s 列,如果异常高,很可能与 discard 有关。
dmesg 中的 op 0x3:(DISCARD) 是判断硬件 TRIM 兼容性的关键线索。
- 内核参数
btrfs.discard=0 可以在不破坏 fstrim 能力的前提下关闭在线 discard。
- 如果条件允许,更换一块可靠品牌的 SSD 是更彻底的解决方案。
给飞牛团队的建议:能否在挂载 SSD 时先发送测试 discard 请求检测硬件是否支持,再决定是否添加 discard=async?或者提供图形化的在线 TRIM 开关。
免责提醒:本文涉及修改内核启动参数等系统级操作,请确保已备份重要数据,谨慎执行。不同硬件环境、系统版本可能存在差异,文中方法仅供参考。本文内容由 AI 辅助生成,如有不当之处欢迎指正。