通过 USB 外接硬盘时,如果遇到磁盘看起来一直很忙,但实际吞吐很低,问题不一定出在文件系统或硬盘本体上。一次比较典型的场景是:USB-SATA 桥接芯片声称支持 UAS,但它的固件实现不稳定,Linux 自动启用 UAS 后反而触发命令超时、USB 设备重置,最终表现成系统层面的 I/O 卡顿。

这篇文章记录一次这类问题的现象、原因和处理方式。

问题现象#

故障最直观的表现是:外接硬盘几乎不可用,但监控上又看不出正常的高吞吐。

常见现象包括:

  • iostat 中磁盘 %util 长时间接近或等于 100%
  • 实际 r/sw/srkB/swkB/s 并不高;
  • awaitsvctm 或应用侧读写延迟异常升高;
  • 文件复制、解压、数据库读写、备份任务间歇性卡住;
  • 偶尔出现 Input/output error
  • dmesgjournalctl -k 中反复出现 UAS abort、SCSI timeout、USB reset。

可以先用下面这些命令观察:

iostat -xz 1
dmesg -T | grep -Ei 'uas|usb|reset|abort|I/O error|blk_update_request'
journalctl -k -b | grep -Ei 'uas|usb|reset|abort|I/O error'

比较典型的内核日志类似这样:

uas_eh_abort_handler ...
scsi host... uas_eh_device_reset_handler
usb ... reset SuperSpeed USB device number ...
blk_update_request: I/O error, dev sdX, sector ...

如果这些日志和外接硬盘卡顿时间点高度重合,就要怀疑 USB 存储协议层的问题。

背景:UAS 和 BOT 是什么#

USB 外接硬盘通常不是硬盘直接接入系统,而是经过一个 USB-SATA 桥接芯片。Linux 看到的是一个 USB Mass Storage 设备。

这类设备常见有两种工作模式:

  • BOT:Bulk-Only Transport,传统 USB 存储传输方式,兼容性好,协议相对简单;
  • UAS / UASP:USB Attached SCSI,支持更现代的 SCSI 命令队列,理论上并发能力和性能更好。

Linux 内核会根据 USB 设备上报的能力选择驱动。如果设备声明自己支持 UAS,系统通常会优先使用 uas 驱动,而不是传统的 usb-storage BOT 模式。

问题在于,并不是所有桥接芯片的 UAS 固件实现都可靠。部分 JMicron、Realtek、ASMedia 早期型号或某些硬盘盒固件,在真实负载下会出现命令超时、异常复位、队列阻塞等问题。

为什么会表现为“忙但不快”#

这类问题容易误导排查方向,因为表面上看磁盘很忙:%util 很高,任务卡住,应用阻塞。

但它的本质不是磁盘正在高效工作,而是 I/O 请求卡在队列里等超时、重试、reset。

简化一下链路:

应用读写
  -> 文件系统 / 块设备层
  -> SCSI 命令
  -> uas 驱动
  -> USB-SATA 桥接芯片
  -> SATA 硬盘

当 UAS 这层出现兼容性问题时,请求可能已经提交给内核块层,但桥接芯片没有稳定完成命令。于是内核不断等待、abort、reset,应用侧就看到延迟飙升,监控侧则看到磁盘一直处于繁忙状态。

这也是为什么它和真正的磁盘性能瓶颈不太一样:吞吐并不高,但延迟非常差。

确认当前设备是否使用 UAS#

先查看 USB 设备:

lsusb

输出中会看到类似:

Bus 002 Device 004: ID 152d:0578 JMicron Technology Corp. / JMicron USA Technology Corp. JMS567 SATA 6Gb/s bridge

其中 152d:0578 就是 VendorID:ProductID

再确认这个磁盘绑定的驱动。可以看内核日志:

dmesg -T | grep -Ei 'uas|usb-storage|scsi'

如果看到类似下面的内容,说明设备正在使用 UAS:

usbcore: registered new interface driver uas
scsi host... uas

也可以通过 lsusb -t 查看驱动绑定情况:

lsusb -t

如果某个 USB 存储设备下面显示 Driver=uas,就说明它当前走的是 UAS。

解决方法:对问题设备禁用 UAS#

处理思路不是全局禁用 USB 存储,而是只对有问题的 VendorID:ProductID 加 quirks,让它不要走 UAS,降级为传统 BOT 模式。

假设 lsusb 查到的问题设备是:

ID 152d:0578

那么可以写入 modprobe 配置:

sudo sh -c 'echo "options usb-storage quirks=152d:0578:u" > /etc/modprobe.d/usb-storage-uas-quirks.conf'

这里的 u 表示对该设备禁用 UAS。

然后更新 initramfs 并重启:

sudo update-initramfs -u
sudo reboot

重启后再次检查:

lsusb -t

目标设备如果从:

Driver=uas

变为:

Driver=usb-storage

就说明配置已经生效。

不同发行版的注意点#

Debian、Ubuntu 通常使用:

sudo update-initramfs -u

RHEL、CentOS、Rocky Linux、AlmaLinux 这类系统可能需要使用:

sudo dracut -f

Arch Linux 常见是:

sudo mkinitcpio -P

如果设备不是启动盘,有些情况下重新插拔设备或重新加载模块也可能生效。但对于稳定处理,尤其是服务器或长期运行环境,更新 initramfs 后重启更直接,也更容易验证状态。

性能影响大吗#

对机械硬盘来说,BOT 和 UAS 的性能差异通常不明显。机械盘自身随机读写能力、寻道延迟和盘片吞吐往往才是主要瓶颈。

UAS 的优势更多体现在命令队列和并发能力上,对 SSD 或高负载并发场景更有价值。但如果桥接芯片 UAS 实现不稳定,理论性能没有意义,稳定完成 I/O 才是第一优先级。

所以对于机械硬盘外接盒,降级到 BOT 后通常不会损失可感知性能,反而能明显改善稳定性。

回滚方法#

如果后续更换了硬盘盒、升级了桥接芯片固件,或者确认不是 UAS 问题,可以删除配置并重新生成 initramfs:

sudo rm /etc/modprobe.d/usb-storage-uas-quirks.conf
sudo update-initramfs -u
sudo reboot

重启后再用 lsusb -t 确认设备是否重新绑定到 uas

排查经验总结#

遇到 USB 外接硬盘异常卡顿时,不要只盯着文件系统和硬盘坏道。下面这些信号同时出现时,应该优先检查 UAS 兼容性:

  • 外接 USB 硬盘 %util 长期 100%,但吞吐很低;
  • 应用读写卡顿,偶尔出现 I/O error
  • 内核日志反复出现 uas_eh_abort_handler、SCSI timeout、USB reset;
  • lsusb -t 显示目标设备正在使用 Driver=uas
  • 换线、换 USB 口、换供电后问题仍然存在。

最终解决方案是对具体问题设备禁用 UAS,让它走 usb-storage BOT 模式。对于机械硬盘外接盒,这通常是一个稳定性收益远大于性能损失的选择。