这两天我把系统换成了Archlinux,在用livecd引导启动准备安装时就遇到了问题——启动过程极其漫长;而在安装软件包、高强度读写硬盘时,也出现了假死问题。

类似的问题在进行了系统升级后仍然存在,具体表现为:启动、编译软件、使用hdparm等高强度I/O时,系统假死,在/var/log/errors.log中可以看到以下记录:

1
2
3
4
5
Jan 20 15:41:01 localhost kernel: [   34.400019] ata1.00: exception Emask 0x0 SAct 0x1 SErr 0x0 action 0x6 frozen
Jan 20 15:41:01 localhost kernel: [   34.400044] ata1.00: failed command: READ FPDMA QUEUED
Jan 20 15:41:01 localhost kernel: [   34.400064] ata1.00: cmd 60/08:00:a0:5e:38/00:00:3a:00:00/40 tag 0 ncq 4096 in
Jan 20 15:41:01 localhost kernel: [   34.400066]          res 40/00:01:00:00:00/00:00:00:00:00/00 Emask 0x4 (timeout)
Jan 20 15:41:01 localhost kernel: [   34.400103] ata1.00: status: { DRDY }

(另外几次假死有的是WRITE FPDMA QUEUED。)

可以看到在假死的时候出现了ata frozen,ncq错误,无法完成读/写队列。上网查询,发现论坛、bug tracker、Q&A上有大量相关的信息,错误日志与此类似,可是大都没法彻底解决——归根究底是以上的日志信息太少,只说明了是ata错误,读取超时。通过其他多方面测试、尝试最终可以知道,这些大都是硬件软件配合问题造成的——对于某些控制器、驱动器,内核ata模块的acpi、ncq等功能无法正常工作,导致I/O错误。解决方法有的需要更换硬件,有的需要更新固件,还有的需要使用内核参数,禁用某些功能或是限制SATA速度。

其中数量比较多的一种就是libata的acpi节能功能有问题,导致硬盘供电不足。根据网络上的说法,在大容量硬盘上这个bug也更容易出现。我的这个硬盘就是新买的500GB 7200转,功率比较大,经过尝试,确实是这个bug导致的。

截止发文之时,没有找到相关补丁,只有一个简单直接的workaround:禁用libata的acpi功能。方法很简单,也没有太多副作用,只要添加内核参数(写入GRUB的启动参数即可):

1
libata.noacpi=1

PS1:不建议直接禁用全部的acpi功能(即使用 noacpi 参数),此将禁用所有的高级电源管理功能,可能导致休眠、挂起以及笔记本亮度调节失效等等副作用。

PS2:ACPI是Advanced Configuration and Power Interface(高级配置与电源接口)的缩写。而与之相似的APIC是Advanced Programmable Interrupt Controller(高级可编程中断控制器)的缩写,与扩充硬件中断有关,与引起Linux诸多问题的ACPI基本毫无关系,请不要混为一谈,随意禁用APIC。