badblocks
badblocks 是一个用于测试存储设备坏块的程序。
在现代 HDD 和 SSD 中,固件会自动检测缺陷扇区,并在可能的情况下采取措施纠正情况。但是,固件只有在尝试使用损坏的扇区时才会意识到它的存在。Badblocks 可用于一次性测试整个设备。
安装
请参阅 badblocks(8) 以了解用法。
存储设备保真度
虽然没有明确的规则,但普遍认为新驱动器应该没有坏扇区。随着时间的推移,坏扇区会发展,虽然它们可以被定义到文件系统中以避免使用,但持续使用驱动器通常会导致形成更多的坏扇区,这通常是其最终死亡的预兆。建议更换设备。
与其他程序的比较
测试存储设备坏扇区的典型推荐做法是使用制造商的测试程序。大多数制造商都有执行此操作的程序。这样做的主要原因是制造商通常将其标准内置于测试程序中,这将告诉您驱动器是否需要更换。这里的注意事项是,一些制造商的测试程序不打印完整的测试结果,并且允许一定数量的坏扇区,只说明它们是否通过。然而,制造商的程序通常比 badblocks 快,有时快很多。
测试坏扇区
要在 Linux 中测试坏扇区,通常使用程序 badblocks。badblocks 有几种不同的模式来检测坏扇区。
只读测试
此测试检查设备上的所有扇区是否可读。该操作是非破坏性的,可以在实时系统上安全执行。但是,扩展的 S.M.A.R.T. 自检 提供了相同的信息,同时完全在固件中完成。主要区别在于自检在第一个错误时停止,而 badblocks 继续并报告所有不可读的扇区。
写入模式测试(警告:破坏性操作)
此测试主要用于测试新驱动器,是一种读写测试。由于模式被写入每个可访问的块,因此设备的内容会丢失。默认情况下,这是一个包含四个通道的广泛测试,使用四种不同的模式:0xaa (10101010)、0x55 (01010101)、0xff (11111111) 和 0x00 (00000000)。对于某些设备,这将需要几天时间才能完成。
# badblocks -wsv /dev/device
Checking for bad blocks in read-write mode From block 0 to 488386583 Testing with pattern 0xaa: done Reading and comparing: done Testing with pattern 0x55: done Reading and comparing: done Testing with pattern 0xff: 22.93% done, 4:09:55 elapsed. (0/0/0 errors) [...] Testing with pattern 0x00: done Reading and comparing: done Pass completed, 0 bad blocks found. (0/0/0 errors)
选项
-w
:执行破坏性写入测试-s
:显示进度-v
: “verbose”(详细)并输出检测到的坏扇区到 stdout
您可能需要考虑的其他选项
-b number
:指定硬盘的块大小,可以显着缩短测试时间。(tune2fs -l partition | grep 'Block size'
以 root 用户身份运行)-p number
:运行广泛的四通道测试 number 次连续迭代-o /path/to/output-file
:将坏扇区输出到 output-file 而不是 stdout-t test_pattern
:指定模式。请参阅下文。
定义特定测试模式
来自手册页: “test_pattern 可以是介于 0 和 ULONG_MAX-1 之间的数值 [...]。”
随机模式
Badblocks 可以通过 -t random
选项重复写入单个“随机模式”。
# badblocks -wsv -t random /dev/device
Checking for bad blocks in read-write mode From block 0 to 488386583 Testing with random pattern: done Reading and comparing: done Pass completed, 0 bad blocks found. (0/0/0 errors)
读写测试(非破坏性)
此测试专为已包含数据的设备设计。非破坏性读写测试会在使用单个随机模式进行测试之前备份扇区的原始内容,然后从备份中恢复内容。这是一个单通道测试,可用作常规维护测试。
# badblocks -nsv /dev/device
Checking for bad blocks in non-destructive read-write mode From block 0 to 488386583 Checking for bad blocks (non-destructive read-write test) Testing with random pattern: done Pass completed, 0 bad blocks found. (0/0/0 errors)
-n
选项表示非破坏性读写测试。
让文件系统包含坏扇区
为了不使用坏扇区,文件系统必须知道它们。
在文件系统检查期间
可以使用文件系统检查实用程序 (fsck
) 合并坏扇区。可以告知 fsck
在检查期间使用 badblocks。要执行读写(非破坏性)测试并使文件系统知道坏扇区,请运行
# fsck -vcck /dev/device-PARTITION
-cc
选项告诉 fsck
在非破坏性测试模式下运行,-v
告诉 fsck
显示其输出,-k
选项保留检测到的旧坏扇区。
要执行只读测试(不推荐)
# fsck -vck /dev/device-PARTITION
在文件系统创建之前
或者,这可以在文件系统创建之前完成。
如果运行 badblocks 时没有 -o
选项,则坏扇区将仅输出到 stdout。
磁盘开始处读取错误的示例输出
# badblocks -wsv /dev/drive
[...] Testing with pattern 0xff: done Reading and comparing: [...] 37584 37585 0.84% done, 7:31:08 elapsed. (0/0/527405 errors) 37586 [...] done Testing with pattern 0x00: Reading and comparing: [...] 37584 37585 [...] done Pass completed, 527405 bad blocks found. (0/0/527405 errors)
为了方便地将 badblocks 错误输出传递给文件系统,必须将其写入文件。
# badblocks -wsv -o /root/badblocks.txt /dev/device
Checking for bad blocks in read-write mode From block 0 to 488386583 Testing with pattern 0xaa: done Reading and comparing: 6.36% done, 0:51 elapsed. (0/0/14713 errors) [...] Testing with pattern 0x00: done Reading and comparing: done Pass completed, 527405 bad blocks found. (0/0/527405 errors)
然后使用该信息(重新)创建文件系统
# mke2fs -t filesystem-type -l /root/badblocks.txt /dev/device
0/0/527405
错误的含义是number_of_read_errors / number_of_write_errors / number_of_corruption_errors(读取错误数/写入错误数/损坏错误数)。Ext4
来自 mke2fs(8) 手册页
- 请注意,坏块列表中的块号必须使用与 mke2fs 相同的块大小生成。因此,mke2fs 的
-c
选项是检查磁盘坏块然后再格式化它的更简单且不易出错的方法。
因此,推荐的方法是使用
# mkfs.ext4 -c /dev/device
使用 -cc
执行读写坏块测试。
块大小
首先,找到文件系统的块大小。例如,对于 ext# 文件系统
# dumpe2fs /dev/device-PARTITION | grep 'Block size'
将其提供给 badblocks
# badblocks -b block size
查找坏扇区
您可以使用 badblock 来查找坏扇区。请注意,badblocks 将扇区称为“块”。它支持几种扫描模式。有只读模式(默认),它是最不准确的。有破坏性写入模式(-w
选项),它是最准确的,但需要更长的时间,并且(显然)会破坏驱动器上的所有数据,因此使其对于将扇区与文件匹配起来几乎没有用处。最后是非破坏性读写模式,它可能与破坏性模式一样准确,唯一的真正缺点是它可能是最慢的。但是,如果已知驱动器正在发生故障,那么只读模式可能仍然是最安全的。
要执行详细(-v
选项),只读扫描,请运行以下命令之一(其中 x
是驱动器盘符,y
是您要扫描的分区号)
全盘扫描
# badblocks -v /dev/sdx
单分区扫描
# badblocks -v /dev/sdxy
将驱动器作为一个整体扫描的缺点是,每个文件系统都将相对于其所在的分区开始其块计数。这意味着,如果您有一个坏块恰好位于第二个分区上,并且该分区从块 1000 开始,那么您将必须从块号中减去 1000 才能获得您想要的数字。因此,如果从磁盘开始处的扫描导致块号 1005 损坏,那么您实际使用的将是第二个分区的块 5。
否则,如果您在执行完整扫描后发现了坏块,您可以简单地找出它们所在的哪个分区,并重新扫描这些分区以获得块号,而不是进行任何块数学运算。
另请注意,badblocks 默认为 1024 字节块,因此您要么必须使用 -b
选项更改默认大小以匹配您的文件系统,要么稍后手动转换块号。
如果您需要找出分区开始和结束的位置,请运行 fdisk。确保记下 fdisk 使用的块大小,以便您可以转换块计数以匹配您的扫描。
# fdisk -l /dev/sdx
Disk /dev/sdx: 149.05 GiB, 160041885696 bytes, 312581808 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
完成所有这些操作后,您应该拥有坏块的块号,相对于它们所在的分区。
与重映射的交互
具有 SMART 的 HDD 控制器通常能够重映射坏扇区。它们仍然会浪费时间在坏扇区上重试读取,但在写入时,它们要么设法修复它(当错误是“软”错误,即 ECC 故障时),要么将其重映射到备用扇区,只要备用扇区没有耗尽。
- 在非破坏性 RW 模式下,badblocks 首先尝试读取扇区。因此,“软”坏扇区和“硬”坏扇区都被认为是坏的,不再进一步测试。您应该看到 SMART 中的挂起计数不变或增加。
- 在破坏性 RW 模式下,badblocks 首先执行写入。因此,应该触发重映射,并且扇区应该在可访问性方面被“修复”。您应该看到 SMART 中的挂起扇区计数下降,而重新分配的计数保持不变(如果为“软”错误)或上升(如果为“硬”错误)。badblocks 将继续测试扇区是否忠实地保留了数据,正如它最初设计的那样。
可以强制使用来自非破坏性测试的 badblocks 列表进行写入。需要计算 LBA 范围,使用 hdparm --read-sector
将其缩小到单个扇区,最后使用 hdparm --write-sector
[1] 来触发写入。您将放弃在该扇区上任何可能的未来重试,但至少不会再发生读取挂起。
替代方案
由于 badblocks 最初是为验证软盘而编写的,因此其设计并非针对现代 HDD。对于 18 TB 驱动器等大小,即使是使用 -b 4096 的常规技巧 也无济于事。这是一个替代方案
- 在设备上方跨越一个加密层:
cryptsetup open /dev/device name --type plain --cipher aes-xts-plain64
- 用零填充现在打开的解密层,这些零将作为加密数据写入:
shred -v -n 0 -z /dev/mapper/name
- 比较全新的零数据与解密层:
cmp -b /dev/zero /dev/mapper/name
。如果命令仅以文件结束消息停止,则驱动器是正常的。这种方法比即使只运行一次 badblocks 也要快得多。由于此命令执行完全写入,任何坏扇区(如磁盘控制器所知)也应该被消除。
在 btrfs 和 ZFS 文件系统中,设计者认为不再需要软盘时代的坏块列表。只要您覆盖缺陷(如上所述),他们的观点通常是正确的。读取操作仍然会因重试而挂起。如果您想像过去那样“隔离”坏块,请使用更底层的解决方案,例如分区或 LVM。
在现代机械硬盘上,smartctl -t long /dev/device
命令(参见 S.M.A.R.T.)执行完整的只读测试。一旦发现故障,它将立即停止,并将其记录为 “LBA_of_first_error” 数据条目,然后您可以使用 hdparm 覆盖它(如上所述)。您可以使用后续的选择性测试来跳过故障。