坏道惊魂

天气渐渐热了起来,听着本本风扇狂转的声音,右手感觉到硬盘滚烫的温度,我觉得现有数据很是需要备份一下。

我以前一直觉得坏道什么的太难遇到了,直到去年十二月的一天,类似这样的消息在屏幕出现:

kernel: sd 4:0:0:0: [sda] Unhandled sense code
kernel: sd 4:0:0:0: [sda] Result: hostbyte=0x00 driverbyte=0x08
kernel: sd 4:0:0:0: [sda] Sense Key : 0x3 [current]
kernel: sd 4:0:0:0: [sda] ASC=0x14 ASCQ=0x0
kernel: sd 4:0:0:0: [sda] CDB: cdb[0]=0x28: 28 00 25 42 ea af 00 00 01 00
kernel: end_request: I/O error, dev sda, sector 625142447
kernel: Buffer I/O error on device sda, logical block 78142805

这些消息会反复地出现,持续三分钟左右,在此期间做不得其他事情。这些消息出现在对磁盘执行 mount 或 fsck 之前,也就是说系统刚发现这个硬盘还没有开始挂载的时候,就会僵持三分钟。当然,等到 mount 的时候,又是一个三分钟。换句话说,光是进入 Linux 系统就需要六分多钟。神奇的是 Windows 并不会僵持住 8-O

查阅一些资料之后,排除了是内核 Bug 或者是参数设置不正确,了解到那些稀奇古怪的十六进制数字背后还有一些标准,我终于相信坏道就在眼前。实在忍受不了需要六分钟才能进入 Linux 系统,同时我也担心坏道会扩散,就在第二天去换了一个一样容量的硬盘。

最近,出于备份的需要有把这块硬盘拿出来了,那么怎么处理坏道呢?

传统的方法可能是用 badblocks 这个程序去检测一下坏道在哪里了。badblocks 有两种检查方式,一种是只读的,一种是读写的。一般想要彻底查出来坏道就要选择读写的方法,而 badblocks 在这时会依次填上 0xaa, 0x55, 0xff, 0x00,并分别读一次来确认是否有坏道。 badblocks 没有特别的优化,倘若填写 0xaa 之后检查的时候就发现需要检查的所有区域都已经坏掉了, badblocks 并不会终止检查,而是会傻傻地执行完剩下的所有检查。对于一块 320G 笔记本硬盘来说,全盘的读写检查大概需要 24 个小时。

badblocks 全盘读写检查的第 18 个小时,我不小心一个操作把它终止掉了 :-| 。这么漫长的操作肯定不愿意再来一次了,于是我用了一次 badblocks 全盘只读检查,结果 badblocks 说没有发现坏道 …

查阅相关资料后发现,从一开始就用不到 badblocks。现代硬盘具有自我检查机制,在一个“坏道”彻底坏掉之前的很长时间,它先是在读取的时候变得困难,而不是完全无法读取(希捷官方所言)。这时候,支持 SMART 标准的硬盘(许多年前的有硬盘就都普遍支持了)会防患于未然,把这个 sector 记录成 “Pending”,用 smartctl 命令就可以查看到 Current Pending Sector:

# smartctl -A /dev/sdb
....
... Current_Pending_Sector ... 1
....

这就表明硬盘自己发现了一个不稳定的 sector 了,这时候,如果读写这个 sector 变得正常的话,这个 sector 会被硬盘记录成正常,Current Pending Sector 会减少。如果依然发生了读取困难或者是不能读取的情况,硬盘不会做任何事情。当写入失败的时候,硬盘会自动将这个 sector 映射到它的保留区的一个好的 sector,并把这个 sector 标记成 “remapped”,由于一般坏道在真正坏掉之前还是可以读出内容的,硬盘会自动将读出来的内容复制到保留区,remap 完成之后,Current Pending Sector 也会减少,这一切都是在硬件层面上完成的,如果正常的话,普通软件(比如 badblocks)是根本没法发现这个 sector 是坏掉的,即便它去写那个 sector。

那么问题是不是就变得简单了呢,向标记为 Pending 的 sector 写一点东西就可以让硬件搞定这些问题了?看起来是的。在写之前需要知道有问题的 sector 在哪里,这个在 kernel log 里面已经看到了。现代的硬盘自己也会记录错误的 log,通过 smartctl /dev/sdb -l error 命令就能查看,虽然数量有限(我这里只有最后的 5 条),不一定会看到想要看的错误信息。

通过 fdisk 可以看到一个 sector 的大小:

# fdisk -lu /dev/sdb
 
Disk /dev/sdb: 320.1 GB, 320072933376 bytes
255 heads, 63 sectors/track, 38913 cylinders, total 625142448 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
....

按照文章开头处 kernel log 中提到的 625142447,向这个地方写一点东西,让硬盘立即 remap 这个 Pending Sector:

# dd if=/dev/zero of=/dev/sdb bs=512 count=1 seek=625142447
dd: writing `/dev/sdb': Input/output error
1+0 records in
0+0 records out
0 bytes (0 B) copied, 7.26951 s, 0.0 kB/s

有的朋友可能读到这里就发现我悲剧了,因为如果硬件正常的话,它会进行 remap,然后就能写成功了,但显然事与愿违,硬盘没有进行 remap,这时用 badblocks 也能发现这个坏道:

# badblocks -svw -b 512 /dev/sdb 625142447 625142447
Checking for bad blocks in read-write mode
From block 625142447 to 625142447
Testing with pattern 0xaa: done
625142447
Reading and comparing: done
Testing with pattern 0x55: done
Reading and comparing: done
Testing with pattern 0xff: done
Reading and comparing: done
Testing with pattern 0x00: done
Reading and comparing: done
Pass completed, 1 bad blocks found.

smartctl 可以验证 Current Pending Sector 还是 1,并没有变成 0。一切都没有改变,所有的硬盘 SMART 自检都会失败,kernel 还是会产生那样的 log,并持续几十秒挡住你,不让用这块硬盘。

这时候我突然想到了这块希捷硬盘可能还在保修期 8-O

厂商保修信息:
    * 该商品保修期为36个月。
    * 3 年有限责任质保(第一年免费包换,第二,三年保修)

看起来只能换不能修了,早知道在刚出问题的时候就去换一个了 :( 想到 Windows 下使用没有问题,说清楚问题所在还是挺麻烦的。并且邮寄费用并不便宜,寄来寄去说不定还会导致彻底坏掉了,还是不要修了 ….

绝望中突然看到了希望,那就是希捷硬盘可以使用的 SeaTools 。它有两个版本,Windows 版能做的事情比 smartctl 命令还要少,真的没啥用,而且把希捷自家的硬盘放到外面的盒子里就认不出来是希捷的了。不过官方说 DOS 版本能修复坏道,这应该是最后的希望了。

于是赶紧下载,刻录成光盘,由于 SeaTools for DOS 不支持移动硬盘,就把现在用的硬盘换下来,用光盘启动,见到了久违的 FreeDOS 。SeaTools for DOS 的坏道修复功能不依靠 SMART 信息,需要执行一次全盘扫描,扫描用了两个小时,接着果然提供了一个 Repair 选项,果断使用,成功了 :) 在此之后这快硬盘用起来完全正常,即便查看 SMART 信息也看不出来有一个坏道被映射了。SeaTools for DOS 还提供了设置硬盘容量的功能,实际上这次有问题的 sector 就是整个硬盘有效 sector 的倒数第二个,修改硬盘容量,减少 1 MB,也应该是解决问题的不错办法。

总结起来,这次这个事情之后有一些经验:

  1. 对于硬盘健康情况的检测,badblocks 这种东西太旧了,而且对现代硬盘也不一定有效。smartctl 可以多快好省地完成许多相关事情。
  2. 虽然 SMART 是存在好多年的标准,但硬件不一定完全遵守它。厂商自己提供的工具才是最靠谱的!更广泛一点,软件和标准也是这样。
  3. palimpsest 用来查看 SMART 信息和做硬盘自检很不错,如果不喜欢命令行的 smartctl 就可以用它。而 gparted 则侧重于做编辑分区的工作。

    用 Palimpsest 查看硬盘的 SMART 信息

  4. Linux 可以早于 Windows 发现磁盘可疑坏道,可疑坏道出现后的很长一段时间内还是可以读取的,只是硬盘要多用一点力气。
  5. 发现硬盘问题时应该立即换下可疑硬盘,备份数据到可靠的硬盘里,再考虑修复。除非很了解正在使用的 FS,掌握 debugfs 等的用法,否则不要直接尝试在线修复坏道。
  6. 定期使用如 rsync 的软件备份数据到别的地方,硬盘数据,正如国歌中的中华民族,到了最危险的时候。
  7. 有时候见到把硬盘的最后 8 MB 空出来,不分到任何分区去,也许是有一定道理的。

18 thoughts on “坏道惊魂

Leave a Reply to 君临天下 Cancel reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>