Linux 下的磁盘维护(磁盘恢复)

作者:David A. Bandel

这里有一个假设的情况供您思考。您正在您的 Linux 机器上工作,调用一个应用程序或数据文件,Linux 在读取硬盘时犹豫了一下。然后,向上滚动屏幕(或控制台框),您会看到类似这样的内容

Seek error accessing /dev/hdb2 at block 52146,
    IDE reset (successful).

在花费一些时间访问驱动器后,Linux 继续运行。如果您幸运,一切仍然运行良好。如果不幸,您的程序拒绝启动,或者您的数据文件包含垃圾数据。

很有可能,如果您使用的是一块使用了几年的硬盘驱动器,您会开始不时地看到访问磁盘时出现错误。在这一点上,对您的磁盘最好的预后是,随着时间的推移,情况会变得更糟。因此,您需要尽快开始抢救工作。一些磁盘制造商有实用程序可以找到并分配硬盘上的这些坏扇区。不幸的是,这些实用程序也会破坏您磁盘上的信息,并且通常从 DOS 而不是 Linux 运行。

幸运的是,Linux 有一些系统实用程序可以在您处理其(现在)原生的 ext2 格式时为您提供帮助。(也有适用于 minix 的实用程序。如果您需要修复其他非 Linux 文件系统,您应该使用它们自己的原生文件系统实用程序集。)虽然不如 Norton Disk Doctor 或 Microsoft ScanDisk 那样用户友好,但 Linux 磁盘和文件系统实用程序可以完成工作。在本文中,我们将看看一些工具,以帮助我们克服我在开篇段落中描述的那种问题。其他硬盘操作实用程序可以在 /sbin/usr/sbin 中找到,但它们必须等待。现在,让我们先让硬盘正常工作。

在您深入研究之前,如果您使用的是带有 IDE 驱动器的较新的 2.0.x 内核之一,请检查您是否已将适当的错误修复编译到内核中。如果您不确定您的计算机中安装了哪个芯片组,或者无法确定,那么编译 CMD640、RZ1000 和 Intel 82371 选项是安全的。这些选项可以在您的 make config 中的 Floppy、ID 和其他块设备下找到。这可以在将来保存您的数据。这些错误修复可能是您需要的全部,但对您的硬盘进行进一步检查也不会有坏处。

我讨厌陈词滥调,尽管我经常被指责(滥)用它们。如果说我们总是进行系统备份是理所当然的,那么我的收入可能会比现在低一些。对于大多数人来说,事实并非如此。因此,如果您已经忽略这项任务一段时间了,请允许我说 现在 将是进行备份的好时机。我将要告诉您如何做的一些工作可能会意外损坏或破坏您的文件系统或一些重要文件——所以请小心,别说我没有警告您。

准备工作

既然我已经预先发布了必要的法律保护警告,让我们开始吧。最安全的方法是从对文件系统进行相当普通的检查开始。在我的系统上——Red Hat(我喜欢 SYSVinit 风格的启动)、Slackware、Internet tarball 混合物——我有 fsck,一个前端程序,它读取设备上的文件系统类型(来自 /etc/fstab),然后调用适当的 fsck.filesystemtype 检查器——在我的例子中,是 fsck.ext2。您的系统上可能有 e2fsck 而不是 fsck.ext2,或者除了 fsck.ext2 之外还有 e2fsck。不用担心,它们是同一个文件。一个可能是另一个的软链接,但最好将其设为硬链接。

在开始之前,让我们为系统准备好我们要进行的那种工作。每当我对系统执行底层维护时,我都会发现确保我已断开网络连接是明智的。通常这意味着进入单用户模式。您可以选择从 init level 2(没有网络连接)进行其中一些测试,但您需要确保没有太多进程想要写入磁盘,并且没有进程从您需要工作的分区运行。单用户模式就是为此而生的。一个简单的 telinit 1 将使我们进入单用户模式。

如果您不检查根文件系统,请在开始之前卸载您要处理的文件系统。如果您忘记了,您会收到来自 fsck 的提示,告诉您文件系统已挂载,并询问您是否要继续。说“否”——运行底层系统诊断,特别是那些通过直接写入磁盘来更改文件系统的诊断(如 fsck 所做的那样),在磁盘挂载的情况下,是一个非常糟糕的主意。显然,我们无法卸载根文件系统。我们应该能够将其重新挂载为只读,但 mount 中的一个错误并不总是允许此选项。如果您需要检查根文件系统,您可以重新启动到单用户模式,并在 LILO 提示符下发出 -b 开关,使根分区以只读方式挂载。 -b 开关将通过 LILO 传递给 init,并将导致紧急启动,该启动不会运行任何启动脚本。如果您一直想知道为什么要创建多个分区——例如,用于 /usr/home——并限制根分区的大小和范围,那么现在您知道了。

fsck——文件系统检查器

从命令行在任何给定分区上调用 fsck 可能不会导致运行检查,因为您尚未达到预定的最大挂载计数;因此,系统认为文件系统是干净的,不需要检查。要强制检查,请使用 -f 调用 fsck。

此时,会发生以下两种情况之一:fsck 将开始正确运行并检查您的磁盘分区(可能会在磁盘上的坏点处犹豫并发出适当的错误消息,然后再继续),或者它将终止而不运行,留下错误消息。如果 fsck 没有运行,您将必须根据错误消息中的指示向程序提供其他信息。您可能需要传递给 e2fsck 的最常见信息可能是备用超级块的地址或块大小,以便 e2fsck 可以计算备用超级块的位置。 -b 开关将告诉 e2fsck 使用备用超级块,但我们将不得不告诉 e2fsck 在哪里找到一个。在 ext2 文件系统上,超级块通常位于 8193、16385 和 8192+1 的更高倍数处(请参阅下面的 dumpe2fs 说明)。作为替代方案,我们可以使用 -B 开关(一旦我们获得该信息)将块大小传递给 e2fsck,以允许 e2fsck 计算备用超级块位置。稍后我将告诉您在哪里获取块大小值,以防您需要它。

此时,值得一提的是 fsck 和 e2fsck 可用的另外两个互斥开关。第一个是 -n 开关,它告诉 fsck 对所有查询回答否,并将文件系统保持在原始状态,不进行任何修复。第二个是 -y 开关,它会自动更正它发现的任何错误。通常,为了加快速度,您可能希望使用 -y 开关运行 fsck。那么,为什么我们不一直使用此选项呢?如果您怀疑文件系统有问题,我强烈建议不要这样做。虽然 fsck 通常不会遇到问题,但键入 fsck -y 然后去喝杯咖啡,让机器自行处理并不是特别明智的。如果为了速度,您使用自动回答是开关来进行例行检查,请务必不时列出您的 lost+found 目录。此外,您真的会想要注意 fsck 运行时出现的块或 inode 编号,以便您稍后可以检查它们是否已分配给文件。

fsck 和 e2fsck 的其他可用选项可以在手册页中找到。我认为 fsck 和 e2fsck 手册页写得相当好,考虑到这些实用程序对您的文件系统健康的重要性,这是合适的。

一些常见的 fsck 消息

您可能会遇到消息询问您是否希望 fsck 更正错误。回答否通常会终止程序,以便您可以修复问题并重新运行 fsck。但是,您可能遇到的大多数错误消息都是相当例行的,您可以安全地对它们回答是。如果您看到诸如 inode 1234 unattached 之类的消息,则表示 inode(信息节点)1234 指向的文件由于某种原因丢失了其文件名。这可能是由于多种原因造成的,包括电源故障或在没有正确磁盘同步的情况下计算机重置。

其他常见错误包括零时间 inode,这也是由于磁盘在关机前未正确同步造成的。如果您经常看到这些错误,并且您一直在正确关闭系统,那么您可能还有许多其他问题。在这种情况下,您可以从检查电源和数据连接以及电源的波动或通过过多噪声开始。最后,检查您的硬盘参数。我必须警告您,更改默认硬盘参数可能会严重损坏您的文件系统或损坏您的文件——请小心。

lost+found 目录

每个文件系统的根分区中都应该有一个 lost+found 目录。例如,如果您有两个挂载的文件系统,/usr/home,您应该有三个 lost+found 目录。这些目录将包含 inode 已与其文件名断开连接的文件。这些目录中的文件将具有 ./#nnnn 的形式,其中 nnnn 是用作文件名的 inode 编号。您可以通过使用 cat 检查文件来确定文件是什么。如果 cat 返回的似乎是垃圾数据,您可能有一个二进制文件。在这种情况下,您可以执行 chmod +x #nnnn,然后运行该文件。这些步骤应该为您提供足够的信息来了解文件是什么。如果文件很重要,可以重命名并移动到其原始位置;否则,可以删除它。

深入了解 Dumps

我们将要看的下一个实用程序是 dumpe2fs。要调用此实用程序,请键入 dumpe2fs 设备,以获取特定设备的块组信息。实际上,您将获得比您可能使用的更多的信息,但如果您了解物理文件系统结构,则输出对您来说将是可理解的。示例输出如清单 1 所示。

来自 dumpe2fs 的输出

我们实际上只需要前 22 行输出。(带有版本号的第一行不是输出表的一部分。)这些行中的大多数都是不言自明的;但是,其中一两个可能需要进一步解释。第一行告诉我们文件系统的幻数。对于 ext2 文件系统,此数字不是随机的——它始终是 0xEF530x 前缀将此数字标识为十六进制。 EF53 大概表示扩展文件系统 (EF) 版本和模数 53。但是,我不清楚 53 的背景。(原始 ext2fs 版本的最后一位数字为 51,并且与当前版本不兼容。)第二行指示文件系统是干净的还是不干净的。已正确同步和卸载的文件系统将被标记为 clean。当前以读写方式挂载或在关机前未正确同步(例如,突然断电或计算机硬重置)的文件系统将被标记为 not cleannot clean 指示将在正常系统启动时触发自动 fsck。

对我们来说,另一条重要的行是块计数(我们稍后会用到它),它告诉我们分区上有多少个块。我们将在必要时将此数字与 e2fsck 和 badblocks 一起使用。但是,我已经知道我的分区上有多少个块;每次我调用 df 来检查我的硬盘磁盘使用情况时都会看到它。(如果这是一个游戏节目,会发出覆盆子声。)将 df 的输出与 dumpe2fs 进行比较——它们不一样。 dumpe2fs 中的块计数是我们需要的。 df 给我们的数字经过调整,仅向我们显示我们可以以某种形式实际访问的 1024k 块的数量。例如,超级块不计算在内。您是否还注意到“已用”和“可用”数字加起来不等于 1024k 块的数量?这种差异的发生是因为,默认情况下,系统已保留了大约百分之五的这些块。可以更改此百分比,以及 dumpe2fs 读数的前 22 行中列出的许多其他参数;但是,除非您知道自己在做什么,否则我强烈建议不要这样做。

顺便说一句,您在 dumpe2fs 中读取的信息是将块一中列出的分区超级块信息翻译成英文的结果。超级块的副本也保存在每个组边界处以进行备份。 每组块数 值告诉我们每个超级块的偏移量。第一个从一开始,随后的位于 每组块数 值加上 1 的倍数处。

虽然我们实际上只需要使用前 22 行信息,但快速浏览一下列表的其余部分可能会很有用。这些信息按块分组,反映了您的磁盘如何组织以存储数据。超级块没有被明确提及,但它们是每个组开头明显缺失的前两个块。块位图是一个简单的地图,显示组中块的使用情况。此地图包含一个 1 或 0,分别对应于组中已使用或空闲的块。 inode(信息节点)位图类似于块位图,但对应于组中的 inode。 inode 表是 inode 列表。下一行是空闲块的数量。请注意,虽然有些组没有空闲块,但它们都有空闲 inode。这些 inode 将不会被使用——它们是额外的。有些文件使用多个块来存储信息,但只需要一个 inode 来引用该文件,这解释了未使用的 inode。

badblocks

现在我们已经获得了我们需要的信息(终于),我们可以运行 badblocks 了。此实用程序执行表面扫描以查找缺陷,并且通过键入以下内容来调用,至少

badblocks /dev/

设备 是我们需要检查的设备(hda1、sda1 等),块计数 是我们在运行 dumpe2fs 后记下的值(如上所述)。

badblocks 有四个选项可用。第一个选项是 -b,其参数为块大小。仅当 fsck 不会运行或对块大小感到困惑时才需要此选项。第二个选项 -o,它有一个文件名参数,会将 badblocks 认为坏的块号保存到文件中。如果未指定此选项,badblocks 会将所有输出发送到屏幕 (stdout)。第三个选项是 -v,用于 verbose(不言自明)。最后一个选项是 -w,它将破坏您磁盘上的所有数据,方法是将新数据写入每个块并验证写入。(再次,您已被警告。)

您最好的选择是在使用 -o filename 选项的情况下运行 badblocks。当遇到坏块时,它们将作为数字写入文件,每行一个。这将在稍后非常有用。为了以这种方式运行 badblocks,您要写入文件的文件系统必须以读写方式挂载。作为 root 用户——您应该是 root 用户才能进行此维护——您可以切换到您的主目录,该目录应位于根分区中的某个位置。 badblocks 会将文件保存在当前目录中,除非您使用完整路径名限定文件名。如果您需要以读写方式挂载根分区来写入文件,只需键入:mount -n -o remount,rw /

获得坏块号列表后,您需要检查这些块是否在使用中,如果不是,则将它们设置为在使用中。如果一个块已经标记为在使用中,我们可能需要清除该块(因为其中的数据可能已损坏),并将其重置为已分配。打印坏块列表——您稍后会用到它。

进入 debugfs

我们将讨论的最后一个实用程序可能是最强大和最危险的。使用 debugfs,您可以使用直接磁盘写入修改磁盘。由于此实用程序非常强大,因此通常您会希望以只读模式调用它,直到您准备好实际进行更改并将它们写入磁盘。要以只读模式调用 debugfs,请不要使用任何开关。要以读写模式打开,请添加 -w 开关。您可能还希望在命令行中包含您要处理的设备,例如 /dev/hda1/dev/sda1 等。一旦调用它,您应该会看到 debugfs 提示符。

出于本文的目的,我们将仅查看一组有限的命令。我会将您推荐到手册页,但我系统上的 debugfs 页面已过时,并且不能准确反映 debugfs 的命令。要在 debugfs 提示符下获取列表(如果不是解释),请键入 ?lrlist_requests

您可以尝试的第一个命令是 params,以显示模式(只读或读写)和当前文件系统。如果您在未打开文件系统的情况下运行此命令,它几乎肯定会转储核心并退出。

如果您要检查多个文件系统,则另外两个命令 openclose 可能会引起您的兴趣。 Close 不带任何参数,并且顾名思义,它会关闭当前打开的文件系统。 Open 将设备名称作为参数。

如果您希望查看来自超级块的磁盘统计信息,命令 stats 将按组显示信息。

既然您已经有机会了解 debugfs 的一些功能,让我们开始修复硬盘吧。从打印的坏块列表中,我们需要查看哪些块正在使用中以及哪些文件正在使用它们。为此,我们将对每个块号使用 testb

如果测试表明该块未使用,我们知道我们尚未在此处丢失任何数据。

icheck

如果该块标记为正在使用,您将需要找出哪个文件正在使用此块。我们可以通过使用以下命令找到 inode

ncheck

这将返回指向该块的 inode。从这里,我们可以使用

cleari

以获取与 inode 相对应的文件名。现在我们终于得到了一些可以处理的东西。您可能想尝试保存该文件,但如果该块确实是坏的,您最好从备份磁盘重新安装此文件。要释放该块,您可以使用多个命令之一;我推荐的一个是

这将取消分配 inode 及其对应的块。请记住,您必须处于读写模式才能执行此操作。请注意,这些命令在读写模式下是不可撤销的。

setb

一旦坏块被取消分配,您可以使用

永久分配该块,从空闲 inode 池中删除指向它的 inode。

就是这样。一旦对块进行了适当的更改,您就可以退出 debugfs 并重新启动。除非您遗漏了一个块(或坏块增多),否则您不应该看到更多问题。

总结

良好的磁盘维护需要定期磁盘检查。您最好的工具是 fsck,应该至少每月运行一次。默认检查通常会在系统重启 20 次后运行,但如果您的系统像我的系统一样经常保持运行数周,您会希望不时强制进行检查。您最好的选择是执行例行系统备份并时不时检查您的 lost+found 目录。 dumpe2fs 实用程序将提供有关超级块中找到的硬盘操作参数的重要信息,而 badblocks 将执行表面检查。最后,可以使用 debugfs 完成外科手术程序,以删除磁盘上变得糟糕的区域。

David Bandel 是一名计算机网络顾问,专门研究 Linux,但他很不情愿地与 Windows 和那些“真正的”Unix 机器(如 DEC 5000 和 Suns)合作。当他不工作时,他可以被发现入侵自己的系统,或者在飞机上从 2,500 英尺高处欣赏西雅图的景色。他欢迎您的评论、批评、俏皮话,并将很乐意进一步混淆这个问题。您可以通过电子邮件 dbandel@ix.netcom.com 或通过蜗牛邮件 c/o Linux Journal 与他联系。