识别损坏的文件

来自 ArchWiki

本文详细介绍了如何找出哪个文件拥有给定的磁盘扇区。这样做主要目的是在存储设备出现坏扇区时,找出哪个文件被损坏(这样您就会知道是否丢失了任何重要的东西)。

对于大多数这些命令,您必须是 root 用户或具有直接读取您正在检查的驱动器权限的用户(成为 disk 组的成员应该就足够了)。像往常一样,当前的备份总是一个好主意,特别是如果怀疑即将发生驱动器故障。S.M.A.R.T. 可以帮助确定这一点。

文件系统

btrfs

与其他文件系统类型不同,btrfs 原生支持报告损坏的文件。当清理分区时,btrfs 读取所有数据和元数据块并验证校验和。如果 RAID 配置中有正确的副本可用,它会自动修复损坏的块。btrfs 还会通过系统日志报告任何无法读取的扇区以及受影响的文件。

查找损坏的文件

提示: 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 错误

本文或本节的事实准确性存在争议。

原因: 扇区仍然包含在内吗?(在Talk:Identify damaged files#Btrfs section may need updating中讨论)
# 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 文件系统中的所有底层结构。其他文件系统(如 ext3ext4 文件系统)也有类似的工具。在对其运行此命令之前,卸载任何文件系统可能是一个好主意。要使用它,只需运行

# 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 仅对其所在的文件系统是唯一的。

注意: 根据 xfs_db(8)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

参见