引言
笔者有一块 5TB 的西数移动硬盘,型号 WD50NDZW-11A8JS1,属于 Elements/My Passport 这类 2.5 英寸 USB 盘,内部是一块 5400 转的 SMR 硬盘,而且是由固件自己管理叠瓦区的 DM-SMR 类型。前不久笔者在它上面的 Btrfs 分区做了一次去重,之后盘的状态就不对了,写入数据开始报 I/O 错误,读取一部分旧数据也报错。
好在之前笔者已经把重要数据全部转移了出来,所以这件事从头到尾都不涉及数据抢救,要回答的问题只有一个,这块盘本身还能不能修好。
最终的答案是能,而且全程没有一个扇区被重分配。修复的关键是一次曲折的全盘写零,正是它让这块连写入都会报错的盘重新接受了完整写入,之后的收尾便水到渠成。整个过程对理解消费级 DM-SMR 硬盘的行为很有帮助,值得记录。
故障现象
出问题后第一时间看 SMART,关键属性如下。
1 Raw_Read_Error_Rate 0x002f 198 001 051 Pre-fail Always In_the_past 207
5 Reallocated_Sector_Ct 0x0033 200 200 140 Pre-fail Always - 0
9 Power_On_Hours 0x0032 092 092 000 Old_age Always - 6025
194 Temperature_Celsius 0x0022 099 097 000 Old_age Always - 53
197 Current_Pending_Sector 0x0032 198 198 000 Old_age Always - 2097
198 Offline_Uncorrectable 0x0030 100 253 000 Old_age Offline - 0
199 UDMA_CRC_Error_Count 0x0032 200 200 000 Old_age Always - 0
最扎眼的是 197 号属性 Current_Pending_Sector,原始值冲到了 2097。这个属性的含义是,硬盘在读某些扇区时失败了,这些扇区被挂上待处理标记,等下次写入同一个地址时固件再做决断,写得进去就解除标记继续用,写不进去就启用备用扇区替换,也就是重分配。
所以这个属性本身只是读失败的症状记录,并不等于这些扇区已经物理损坏,关键要看 5 号属性 Reallocated_Sector_Ct 的变化。
这里重分配计数是 0,Offline_Uncorrectable 是 0,UDMA_CRC_Error_Count 也是 0,说明接口链路没有问题,也还没有任何扇区被重分配。
SMART 总评仍然是 PASSED,smartctl 只是提醒有厂商属性处于临界状态。1 号属性 Raw_Read_Error_Rate 的 WORST 值曾经跌到 001,低于阈值 051,因此被标记为 In_the_past。这是历史记录,证明读错误确实发生过,它不会自动复位,也不代表当前状态。
扩展自检日志里还有一条更早时候留下的记录。
Num Test_Description Status Remaining LifeTime(hours) LBA_of_first_error
# 1 Extended offline Completed: read failure 90% 5765 1630979768
首次读失败的位置在 LBA 1630979768,换算成字节偏移大约是 835 GB。也就是说,盘上的确存在读不出来的区域,而且不在开头。
初步判断:大概率没有物理损坏
要理解这块盘为什么会被一次去重打垮,需要先知道 DM-SMR 的工作方式。SMR 硬盘的磁道像屋顶瓦片一样相互重叠,写磁头比磁道宽,写入一条磁道时必然覆盖相邻磁道的一部分,因此数据不能就地改写。
固件的做法是把磁道分组管理,随机写先进一块采用传统记录方式的缓存区域,事后再把整组磁道读出来,合并新数据后整组写回。这个读出、合并、重写的过程意味着一次随机写在物理上可能被放大成整组磁道的重写,写放大非常可观。
Btrfs 的去重恰好是对这种盘最不利的负载。去重需要扫描大量数据找出重复的 extent,再修改文件系统的引用关系让重复数据共享同一份物理副本,期间产生的是持续的海量随机读写。缓存区域被随机写迅速塞满,固件被迫在前台整组重写磁道,写延迟从毫秒级膨胀到秒级,主机侧看到的就是 I/O 错误。
而被反复重写、又可能中途失败的磁道组,上面的磁化状态会变得很差,后续读取时纠错码纠不回来,扇区就被挂上待处理标记。连一些很久以前写入的数据也读不出来,正好符合磁道状态退化这个解释,而不是文件系统层面的逻辑错误。
基于这个分析,笔者倾向于认为盘体没有物理损伤,只是磁化状态在异常负载下退化了。支持这个判断的证据有三点,故障紧跟在随机写风暴之后出现,重分配计数是 0,这块盘此前也没有坏道历史。如果这个判断成立,修复思路就很直接,把全盘真正重写一遍,让每条磁道都获得完好的磁化状态。反过来,如果媒体真的损坏了,重写过程中就会看到重分配计数上升。所以修复尝试本身也是一次诊断。
第一次尝试:TRIM 没有作用
这块盘是支持 TRIM 的,lsblk -D 的输出如下。
NAME DISC-ALN DISC-GRAN DISC-MAX DISC-ZERO
sda 0 4K 4G 0
DISC-GRAN 为 4K,DISC-MAX 为 4G,说明可以下发 discard,于是笔者先执行了一次 blkdiscard。结果没有任何变化,待处理扇区数一个都没降。
事后看这个结果是必然的。TRIM 做的事情只是修改固件维护的逻辑地址到物理地址的映射,把一段范围标记为未分配,之后读到这些地址就直接返回零。它从设计上就是为了避免触碰盘片磁道,对 SMR 盘来说,TRIM 的全部意义就在于减少磁道重写。而修复恰恰需要物理上的重写,方向完全相反。
关键的修复:全盘写零
既然判断是磁化状态退化,修复方向就是把全盘真正重写一遍,最直接的手段是用 dd 向整块盘写零。事后看,这一步正是整个修复的转折点,正是它让盘恢复了写入能力。不过过程并不顺利,前后折腾了三轮才写完整。
第一轮不带 oflag=direct,写了一会儿就失败,而且把整个操作系统都拖死了。原因在页缓存,不带 direct 的写入先进入内存,内核接收数据的速度远快于盘实际写入的速度,脏页迅速堆积,等盘因为缓存耗尽而停滞时,回写路径被堵死,所有触及 I/O 和内存分配的进程都跟着卡住。
加上 oflag=direct 之后,每个块都要等盘真正接收之后才写下一个,阻塞只发生在 dd 进程上,系统其他部分不受影响,写入也能长时间持续。
第二轮带上了 oflag=direct,写入可以长时间持续,但这一次仍然没有写完全盘,在大约 4TB 的位置报错中断。此时盘还处于修复早期,盘上状态最差的区域还没有被新数据覆盖,写入推进到这样的位置再次出错并不奇怪。
继续在原地重试意义不大,笔者选择把盘断电放置一段时间再重新连接。断电可以让盘的固件和 USB 桥接芯片彻底复位,清掉之前失败操作留下的内部状态,连续写入导致的高温也能降下来。
重新连接后从失败位置往前回溯几百 MiB 续写,一方面报错点的确切位置难以界定,多覆盖一段可以保证不留空隙,另一方面失败位置附近正是状态最可疑的区域,值得再写一遍。
sudo dd if=/dev/zero of=/dev/sda bs=1M seek=3999000 oflag=direct conv=notrunc status=progress
seek=3999000 表示跳过 3999000 个 1M 块,约 4.19TB。这次顺利写到了设备末尾。
807691878400 bytes (808 GB, 752 GiB) copied, 11907.3 s, 67.8 MB/s
dd: error writing '/dev/sda': No space left on device
末尾的 No space left on device 不是故障,而是写整块设备时的正常结束信号。盘的容量不是 1M 的整数倍,最后不满一个块的部分写不进去,dd 便以 ENOSPC 收尾。
至此整盘已经被完整覆盖了一遍,第二轮写了开头约 4TB,续写完成了剩余部分,衔接处还有几百 MiB 的重叠。第三轮则是从头到尾的完整写零,确保每个 LBA 都再被覆盖一次。
sudo dd if=/dev/zero of=/dev/sda bs=1M oflag=direct conv=fsync status=progress
5000947302400 bytes (5.0 TB, 4.5 TiB) copied, 52733.9 s, 94.8 MB/s
dd: error writing '/dev/sda': No space left on device
5TB 全部写完,耗时约 14.6 小时,平均 94.8 MB/s,全程没有报 I/O 错误。
写零的效果首先体现在写入能力的恢复上。故障之初任何写入都会很快报错,不带 direct 的写零甚至能把系统拖死,而三轮写零下来,整块盘从 0 到末尾的 5TB 写入没有出一个 I/O 错误,94.8 MB/s 也正是 5400 转 2.5 英寸盘持续顺序写入的正常水平。
这个耗时本身就能说明问题,如果固件只是把全零块在映射层登记成未分配就完事,根本不会有逐扇区搬运数据的必要,14.6 小时的持续时间说明盘片确实在承受真实的物理写入。笔者倾向于认为,正是这些物理重写刷新了磁道的磁化状态,读写能力才得以恢复。
待处理扇区数也有呼应,整盘被完整覆盖一遍之后,它从 2097 降到了 1744,有 353 个扇区在写零过程中被重新判定可用。写零之后盘面读扫描不再遇到硬性失败是更直接的证据,这一点放到下一节自检里讲。
不过待处理扇区数到此就定格在了 1744,第三轮从头到尾的完整写零结束后依然是 1744,没有进一步变化,5 也依然是 0。盘面已经能写能读,SMART 里的待处理标记却清不掉,这个看似矛盾的现象先记下,等写入真实数据之后对比着看会更清楚。
插曲:长自检
写零让盘恢复了读写,但 1744 个待处理标记还在,笔者接着跑了一次长自检,想看看盘面读扫描能给出什么信息。
sudo smartctl -t long /dev/sda
Testing has begun.
Please wait 834 minutes for test to complete.
预估 834 分钟,实际慢得多。进度从 90% 到 70% 用了约 7 小时,再到 50%、40% 又过了五六个小时。期间盘还因为 USB 节能挂起过一次,但查询状态显示自检仍在进行,smartctl 一访问盘被唤醒,自检继续。跑到剩余 10% 的时候,已经是第二天上午,复查发现自检被主机重置打断了。
Self-test execution status: ( 33) The self-test routine was interrupted
by the host with a hard or soft reset.
自检日志里新增一条 Interrupted (host reset),没有记录新的读失败 LBA,待处理扇区数则从 1744 微涨到 1770。
这次中断的自检仍然提供了两条信息。其一,扫描覆盖了约 90% 的盘面而没有触发硬性的读失败,早前 835 GB 处的失败点没有再出现。写零之前的自检在 835 GB 处就撞上了读失败,写零之后大半个盘面的扫描一路通过,可以确认读取能力的恢复是写零带来的,盘面的物理状态此时已经基本修复。
其二,读扫描对待处理扇区数毫无影响,反而微涨 26 个,可见在这块盘的固件里,待处理标记只能靠写入来解除,读得再顺利也不会自动清零,多出来的这些则可能来自扫描中遇到的个别仍不稳定的位置。指望自检修复问题是不现实的,它只是诊断工具。
另外这个经历也提醒了一点,通过 USB 连接的盘跑十几个小时的长自检很脆弱,主机的节能挂起和链路重置随时可能让它前功尽弃。
收尾:写入真实数据,待处理扇区归零
盘面状态既然已经修复,剩下的就是让固件重新判定那批待处理扇区。需要指出的是,完整写零结束时待处理扇区数仍有 1744 个,自检之后又增至 1770 个,这些标记的清除全部发生在真实数据写入阶段。
笔者正好需要把数据写回这块盘,于是做了一次 Btrfs receive,把整个备份流接收回来。这次写入结束后复查 SMART,待处理扇区数从 1770 直接掉到 42。此后笔者又用 borg 做了备份,并拷贝了视频和照片的备份,这些连续写入完成后,它才最终降为 0。
5 Reallocated_Sector_Ct 0x0033 200 200 140 Pre-fail Always - 0
9 Power_On_Hours 0x0032 092 092 000 Old_age Always - 6117
194 Temperature_Celsius 0x0022 106 097 000 Old_age Always - 46
197 Current_Pending_Sector 0x0032 200 198 000 Old_age Always - 0
198 Offline_Uncorrectable 0x0030 100 253 000 Old_age Offline - 0
199 UDMA_CRC_Error_Count 0x0032 200 200 000 Old_age Always - 0
值得一提的是,后面这次完整的全盘写入平均速度达到了 97 MB/s,比写零时的 94.8 MB/s 还略高,盘的写入性能已经完全恢复。
待处理扇区数归零的同时,重分配计数从头到尾保持 0,这意味着所有被挂上待处理标记的扇区在重写时都通过了固件的校验,直接回到可用状态,没有一个需要动用备用扇区。物理损坏的假设至此可以彻底排除,最初的判断得到了完整验证。
到这里可以回头解答写零留下的疑问。这次修复其实是分两层完成的,写零修复的是盘面的物理状态,读写能力的恢复都发生在写零阶段,而 SMART 中剩余待处理标记的清除全部发生在真实数据写入阶段。为什么写零治好了盘面却清不掉大部分标记,从外部无法确知固件的实现,只能列举可能的解释。
一种可能是固件对全零的块有特殊处理,这块盘本来就支持 deterministic 的 TRIM,全零数据被识别出来后,即使照常落盘,也不纳入待处理扇区的重新判定。
另一种可能是内部写入路径的差异,DM-SMR 盘一般把随机写和混合负载先导入缓存区域,再迁移回磁道组,而 dd 这样的纯顺序流可能直接写入磁道组,文件系统的写入夹杂着大量元数据操作和缓存刷写,与裸设备顺序写走的不是同一条路径,待处理扇区的重新判定也许只在特定的路径上发生。
相比之下,Btrfs receive 后还剩 42 个就好解释了,文件系统写入只覆盖已分配的区域,剩下的待处理扇区位于尚未写到的位置,随后的 borg 备份和视频、照片拷贝覆盖了这些位置,标记随之清零。
这些推测都无法从外部证实,可以确定的是两条事实,写零让盘重新能写能读,真实数据的写入让待处理扇区数最终归零。
整个过程待处理扇区数的变化可以汇总如下。
| 阶段 | 197 Current_Pending_Sector | 5 Reallocated_Sector_Ct |
|---|---|---|
| 去重后初始状态 | 2097 | 0 |
| 整盘写零后 | 1744 | 0 |
| 再次完整写零后 | 1744 | 0 |
| 长自检中断后 | 1770 | 0 |
| Btrfs receive 后 | 42 | 0 |
| borg 备份与文件拷贝后 | 0 | 0 |
自检日志里仍然保留着早年那条读失败记录和这次的中断记录,Raw_Read_Error_Rate 的 In_the_past 标记也不会消失。这些都是历史记录,不影响盘的当前健康状态。
复盘
把整条因果链串起来。Btrfs 去重制造了持续的随机写风暴,DM-SMR 固件的缓存区域被耗尽,被迫在前台反复整组重写磁道,一部分写入在这个过程中失败,盘面留下了磁化状态不佳的区域,表现为写入报错、读取报错和大量待处理扇区。这不是盘片或磁头的物理损伤,而是异常负载下的状态退化。
修复也相应分成两步,全盘写零通过真实的物理重写刷新磁道状态,让盘重新能写能读,这一步最曲折也最关键。
不过写零并没有清掉 SMART 里的标记,整盘写零后待处理扇区数降到 1744 便不再变化,自检后还微增至 1770 个,让它归零的是随后的真实数据写入,Btrfs receive 后降到 42,随后的 borg 备份和视频、照片拷贝后才降为 0。
这次经历也留下了几条实用经验。不要对 DM-SMR 盘做去重这类随机写密集的操作,SMR 与 Btrfs 这样的 CoW 文件系统搭配使用时要格外控制写入模式。
判断一块盘是物理损坏还是状态退化,可以看 Current_Pending_Sector 与 Reallocated_Sector_Ct 的组合,大量待处理扇区而重分配为零,尤其在故障紧跟异常负载出现时,值得先尝试写零修复。全盘写零对 SMR 盘是有效的修复手段,但要做好反复失败的准备,写入中途失败时断电放置一段时间再从断点续写,比原地反复重试更有效,往整块盘写数据时也要记得加 oflag=direct,否则页缓存会把系统拖死。
修复是否见效不能只看 SMART 属性,写入能否顺利完成、读扫描能否通过,比待处理扇区数更能反映盘面的真实状态。还有,2.5 英寸 USB 硬盘盒没有主动散热,连续十几个小时的满速写入让盘体温度升到了 53°C,长时间大负载操作时最好留意散热。
数据在去重之前就已经安全转移,所以这次的全部工作都是为了硬件本身。一块被误判为将死的 5TB 硬盘因此免于报废,重新投入服役。当然,以后不会再拿它做去重了。
赞赏本文
| 支付宝 | 微信支付 |
|---|---|
![]() |
![]() |

