在RHEL生产环境里,硬盘故障很少以“直接无法挂载”的方式出现。更常见的情况是smartctl的某个计数器开始缓慢增长,内核日志里偶尔刷出几条I/O error,应用响应时间变得不稳定。坏道这件事需要先分清逻辑坏道和物理损坏:前者通常只是扇区数据校验错误或磁性减弱,借助文件系统标记后还能继续使用;后者则是盘片涂层脱落、磁头划伤或电机异常,任何软件层面的修复都只是延缓,真正的办法是立即备份并更换磁盘。如果把物理损坏当成逻辑坏道反复执行badblocks或写零,每次全盘扫描都会让损伤扩大。

一、从SMART和内核日志确认坏道性质
SMART是硬盘固件层面的自检机制,RHEL安装smartmontools后可以用smartctl读取。整体健康状态可以执行smartctl -H /dev/sda,如果返回结果为FAILED,说明硬盘已经达到厂商设定的故障阈值,不应再作为业务盘使用。但只看整体状态不够,很多物理损伤初期的SMART整体状态仍然显示PASSED,需要关注三个关键计数器:Reallocated_Sector_Ct表示已经被硬盘固件重映射到备用扇区的坏扇区数量,它增长说明盘片表面已经出现物理损伤;Current_Pending_Sector表示读取时发现异常、等待固件进一步判断或重映射的扇区,逻辑坏道和轻微弱扇区也会让这个值上升;Offline_Uncorrectable表示离线扫描中彻底无法纠正的扇区。上面这几个值更适合做趋势判断,而不是只看单次读数。如果每天采集一次,数值持续增加,基本可以判定硬件层不稳定。
下面命令可以一次性抓取这些指标:
smartctl -a /dev/sda | grep -E "Reallocated|Pending|Offline|SMART overall"
内核日志是另一个重要依据。执行dmesg -T | grep -i -E "ata|error|blk_update_request"可以看到SATA链路异常、命令超时以及块层I/O错误。典型记录如blk_update_request: I/O error, dev sda, sector 12345678,表示内核在访问某个具体扇区时失败。配合smartctl可以做一个基本判断:如果只有少数Pending扇区,读取一次后数值清零,说明大部分是弱扇区或逻辑坏道;如果Reallocated_Sector_Ct持续增长,或者硬盘发出咔哒声、系统频繁出现链路复位,那就是物理损坏的表现。
二、逻辑坏道的定位与修复尝试
只有确认不是大范围物理损伤时,才值得对逻辑坏道做标记和修复。处理前必须卸载目标分区,或者至少以只读方式挂载,避免写入操作破坏元数据。使用badblocks可以扫描坏块,命令中-b 4096要跟文件系统块大小保持一致,否则导出的坏块列表交给e2fsck时会标记错位置。只读扫描用badblocks -sv -b 4096 /dev/sda2,其中-s显示进度,-v输出详细信息。为了减少对盘片的压力,可以先从只读模式开始,不要一上来就做写测试。
对于ext3或ext4文件系统,推荐用e2fsck -c -c /dev/sda2自动完成坏块扫描和标记。两个-c分别表示使用非破坏性读写测试并标记坏块到文件系统。也可以先导出坏块列表,再通过e2fsck -l方式导入:
umount /dev/sda2 badblocks -sv -b 4096 /dev/sda2 > /root/badblocks.txt e2fsck -l /root/badblocks.txt /dev/sda2
需要明确一点,e2fsck标记坏块只是让文件系统不再分配这些扇区,并不能修复已经损坏的数据。如果坏道位置正好存放了关键文件,可能仍会出现读取失败。对于xfs文件系统,处理思路不同:xfs没有像ext家族那样完善的用户态坏块列表导入机制,xfs_repair -n主要用于检查元数据一致性,并不能标记盘片坏扇区。因此如果xfs分区出现坏道,更务实的做法是尽快备份数据,然后对磁盘做物理层判断,而不是反复运行修复工具。很多管理员习惯用dd写零来掩盖坏道,但物理坏道不会因为写零而消失,反而会让磁头在坏区反复摩擦,扩大损伤范围。
三、物理损坏时的数据抢救与磁盘替换
一旦SMART计数器持续增长、磁盘异响或整体健康FAILED,就应进入数据抢救流程,而不是继续修复文件系统。此时最核心的原则是减少对原盘的非必要读取。ddrescue比dd更适合坏盘镜像,它支持按扇区复制、跳过错误区域、记录日志文件并支持断点续传。第一次运行建议使用-n参数跳过坏区,先把健康区域快速复制出来,再对错误区域进行重试。操作前准备一个容量不小于原盘的备份盘或镜像目录,执行:
ddrescue -f -n /dev/sda /mnt/rescue.img /mnt/rescue.log ddrescue -f -r2 /dev/sda /mnt/rescue.img /mnt/rescue.log
上述命令中-f允许写入输出文件,-n忽略错误快速复制,-r2对之前跳过的坏区重试两次。日志文件/mnt/rescue.log记录了每个块的复制状态,中断后可以继续执行相同命令恢复进度。镜像完成后,可以把rescue.img挂载为loop设备,或者写入一块新盘再修复文件系统,这样能最大程度避免在原盘上扩大损伤。
如果坏盘是mdadm软RAID的成员,需要先将故障盘从阵列中移除。查看阵列状态用cat /proc/mdstat,然后依次执行:
mdadm --fail /dev/md0 /dev/sdb1 mdadm --remove /dev/md0 /dev/sdb1
更换物理盘后重新分区,再把新盘加入阵列:
mdadm --add /dev/md0 /dev/sdb1
这里要注意,如果坏盘尚在阵列中,不要直接拔出。因为RAID重建需要从其他成员盘读取所有数据,坏盘上的读错误会让重建反复失败,甚至拖垮整个阵列。先使用mdadm标记故障并移除,再插新盘,是更安全的顺序。对于硬件RAID卡,则可以通过厂商管理工具查看单盘状态并执行替换,原理类似。
最后,无论逻辑坏道还是物理损坏,都应建立SMART监控。RHEL的smartd服务可以定期采集磁盘健康数据并在异常时发送邮件。在/etc/smartd.conf中为每块盘配置类似/dev/sda -a -m root的规则,然后启动smartd。监控不能阻止坏道发生,但可以在早期阶段给出告警,为数据备份争取时间。物理损坏的硬盘没有修复价值,完整镜像、更换新盘、恢复数据,才是标准流程。

