识别损坏的文件
本文详细介绍了如何找出哪个文件拥有给定的磁盘扇区。这样做主要目的是在存储设备出现坏扇区时,找出哪个文件被损坏(这样您就会知道是否丢失了任何重要的东西)。
对于大多数这些命令,您必须是 root 用户或具有直接读取您正在检查的驱动器权限的用户(成为 disk 组的成员应该就足够了)。像往常一样,当前的备份总是一个好主意,特别是如果怀疑即将发生驱动器故障。S.M.A.R.T. 可以帮助确定这一点。
文件系统
btrfs
与其他文件系统类型不同,btrfs 原生支持报告损坏的文件。当清理分区时,btrfs 读取所有数据和元数据块并验证校验和。如果 RAID 配置中有正确的副本可用,它会自动修复损坏的块。btrfs 还会通过系统日志报告任何无法读取的扇区以及受影响的文件。
查找损坏的文件
首先,清理损坏的分区
# btrfs scrub start -Bd /dev/sdxy
挂载时可以通过提供其挂载点来清理同一分区
# btrfs scrub start -Bd /mnt/point
可以使用 status
子命令多次检索清理报告
# btrfs scrub status /mnt/point
scrub status for e11013b3-b244-4d1a-a9c7-3956db1a699c scrub started at Thu Apr 23 19:07:45 2015 and finished after 372 seconds total bytes scrubbed: 301.13GiB with 1 errors error details: read=1 corrected errors: 0, uncorrectable errors: 1, unverified errors: 0
完成后,在内核日志中搜索 I/O 错误
# journalctl --output=cat --grep='BTRFS .* i/o error' | sort | uniq | less
Jan 16 23:14:19 my_server kernel: BTRFS: i/o error at logical 398602014720 on dev /dev/sdxy, sector 4621320, root 5, inode 23839, offset 4378624, length 4096, links 1 (path: my/damaged/file)
上面的输出显示扇区 4621320
无法读取,并且它包含文件 my/damaged/file
的数据。扇区号可以直接与 hdparm 一起使用以重新分配(参见#强制磁盘重新分配坏块)。
Ext2、ext3 和 ext4
调试文件系统
tune2fs 命令将允许您访问任何 ext2/ext3/ext4 文件系统中的所有底层结构。
我们要做的第一件事是从有问题的的文件系统中获取块大小。只需运行
# tune2fs -l /dev/sdxy | grep Block
Block count: 29119820 Block size: 4096
在这种情况下,正在使用的块大小为 4096(这似乎是默认值)。
如果您没有使用文件系统正在使用的块大小运行 badblocks,则需要转换您的块号以匹配它(请记住使用相对于它们所在的分区的块号)。
即,块大小为 1024 字节的块号 100 变为 4096 字节的块号 25。公式是
(original block number) / ((filesystem block size) / (badblocks block size))
现在运行此程序(就本文而言)的全部目的是获取 inode 号。在继续调试之前,卸载分区。然后,运行命令
# debugfs
然后在 debugfs
控制台中,在包含坏扇区的 ext 分区上使用 open
命令
debugfs: open /dev/sdxy
最后,使用 testb
命令获取有关有问题块的信息(在本例中为块 1000)
debugfs: testb blocknumber
debugfs
说该块未使用,则表示该块未分配并用作可用空间。在这种情况下,这是一件好事,因为它意味着没有重要的东西被损坏。如果该块正在使用,则运行此命令以获取 inode 号
icheck blocknumber
这将返回两个数字。块号和 inode 号。
查找损坏的文件
使用 inode 号(来自 icheck
命令的第二个数字)与 ncheck
命令
ncheck inodenumber
debugfs
控制台将为您提供使用坏块的文件的完整路径名。现在您将知道实际损坏了什么。
如果 inode 号非常小,并且 ncheck
未能返回路径,则可能是日志本身已损坏。要删除日志,只需在分区上运行此命令
# tune2fs -O ^has_journal /dev/sdxy
再次从 debugfs
控制台在坏块上运行 testb
命令,如果它确实被日志使用,则不应再标记为已使用。要构建新日志,请运行
# tune2fs -j /dev/sdxy
JFS
调试文件系统
jfs_debugfs 命令将允许您访问任何 JFS 文件系统中的所有底层结构。其他文件系统(如 ext3 和 ext4 文件系统)也有类似的工具。在对其运行此命令之前,卸载任何文件系统可能是一个好主意。要使用它,只需运行
# jfs_debugfs /dev/sdxy
这会将您置于命令控制台中。您应该注意的第一件事是您的聚合块大小。JFS 似乎默认为 4096 字节。
如果您没有使用文件系统正在使用的块大小运行 badblocks,则需要转换您的块号以匹配它(请记住使用相对于它们所在的分区的块号)。
即,块大小为 1024 字节的块号 100 变为 4096 字节的块号 25。公式是
(original block number) / ((filesystem block size) / (badblocks block size))
现在运行此程序(就本文而言)的全部目的是获取 inode 号。为此,运行命令
d blocknumber 0 i
语法是 d
命令用于显示,块号,偏移量(只需将其设置为 0),以及显示格式 i
用于 inode。
di_number
设置的十进制数是我们想要的。从这里,您键入 x
退出显示模式。为您拥有的每个坏块重复显示命令,并记下它们的所有 inode 号。有关 inode 的更多信息,例如权限和文件类型,请键入
i inodenumber
当您拥有所有 inode 号时,键入 q
退出。
查找损坏的文件
最后,要查找损坏的文件,您可以简单地使用 gnu find 实用程序。挂载您的文件系统并运行
# find / -inum inodenumber
将 /
替换为 inode 所属文件系统的挂载点。请记住,inode 仅对其所在的文件系统是唯一的。
XFS
调试文件系统
xfs_info 命令将为您提供有关 XFS 格式化分区的基本信息,而 xfs_db 命令将允许您访问任何 XFS 文件系统中的所有底层结构。
我们要做的第一件事是从有问题的的文件系统中获取块大小。只需运行
# xfs_info /dev/sdxy | grep bsize
data = bsize=4096 blocks=127739, imaxpct=25 naming =version 2 bsize=4096 ascii-ci=0 ftype=1 log =internal bsize=4096 blocks=855, version=2
在这种情况下,正在使用的块大小为 4096(这似乎是默认值)。
如果您没有使用文件系统正在使用的块大小运行 badblocks,则需要转换您的块号以匹配它(请记住使用相对于它们所在的分区的块号)。
即,块大小为 1024 字节的块号 100 变为 4096 字节的块号 25。公式是
(original block number) / ((filesystem block size) / (badblocks block size))
现在运行此程序(就本文而言)的全部目的是获取 inode 号。在继续调试之前,卸载分区。然后,运行命令
# xfs_db -c 'blockget -b blocknumber' /dev/sdxy
您应该获得类似于此的输出
setting block 0/9 to data setting inode to 131 for block 0/9 inode 131 block 9 at offset 0
在此示例中,我们现在知道 inode 为 131,可以继续下一节
如果您在输出中没有获得 inode 号,但看到了单词 free,那么很可能这意味着坏块属于可用空间,并且没有重要的东西被损坏。
查找损坏的文件
最后,要查找损坏的文件,您可以简单地使用 gnu find 实用程序。挂载您的文件系统并运行
# find / -inum inodenumber
将 /
替换为 inode 所属文件系统的挂载点。请记住,inode 仅对其所在的文件系统是唯一的。
blockuse -n
命令可以与 blockget -n -c blocknumber
结合使用,以便打印文件名。测试此方法没有产生预期的结果,但无论如何都值得尝试,因为它比 find 方法更快。# xfs_db -c 'blockget -n -b blocknumber' -c 'blockuse -n' /dev/sdXy
强制磁盘重新分配坏块
首先,您将需要通过 smartctl 命令查看硬盘驱动器知道多少坏块
# smartctl -t long /dev/sdx
等待测试完成,然后
# smartctl -l selftest /dev/sdx
ID# ATTRIBUTE_NAME FLAG VALUE WORST THRESH TYPE UPDATED WHEN_FAILED RAW_VALUE 5 Reallocated_Sector_Ct 0x0033 100 100 005 Pre-fail Always - 0 196 Reallocated_Event_Count 0x0032 100 100 000 Old_age Always - 0 197 Current_Pending_Sector 0x0022 100 100 000 Old_age Always - 0 198 Offline_Uncorrectable 0x0008 100 100 000 Old_age Offline - 0
为了使硬盘驱动器使用备用好扇区透明地映射出坏块,您必须简单地以 root 身份使用 dd 命令将零写入坏块。请记住,使用此命令时,您必须使用与文件系统相同的块大小,并且该块必须相对于文件系统所在的分区,而不是整个硬盘驱动器
# dd if=/dev/zero of=/dev/sdxy bs=4096 count=1 seek=2269012 $ sync
或者,hdparm 提供了一些不错且简单的选项来读取和写入给定的扇区(在以下示例中为 4621327)
# hdparm --read-sector 4621327 /dev/sdxy # hdparm --repair-sector 4621327 --yes-i-know-what-i-am-doing /dev/sdxy
您可以通过使用 smartctl 命令检查并查看重新分配的扇区或事件计数是否增加来查看硬盘驱动器是否确实映射出了额外的坏扇区
# smartctl -A /dev/sdx
ID# ATTRIBUTE_NAME FLAG VALUE WORST THRESH TYPE UPDATED WHEN_FAILED RAW_VALUE 5 Reallocated_Sector_Ct 0x0033 100 100 005 Pre-fail Always - 1 196 Reallocated_Event_Count 0x0032 100 100 000 Old_age Always - 1 197 Current_Pending_Sector 0x0022 100 100 000 Old_age Always - 0 198 Offline_Uncorrectable 0x0008 100 100 000 Old_age Offline - 1
要使 Offline_Uncorrectable
返回 0,您需要运行 SMART 长时间测试和自检
# smartctl -t long /dev/sdx
等待测试完成,然后
# smartctl -l selftest /dev/sdx
参见
- 通过 md 和 LVM 跟踪磁盘扇区号到文件系统,作者为 BitFolk 的 Andy Smith
- EXT2/3 坏块使用指南