Skip to content

第九十八章:fsck

斩灵期

涉及内核源码:

林小源走进一片狼藉的废墟。曾经整齐的目录树倒塌了,inode 散落一地,块分配位图上布满了裂痕。

"这是……文件系统损坏了?"林小源小心翼翼地绕过一块断裂的超级块。

"是的。"一个苍老的声音从废墟深处传来。一个手持扫帚和工具箱的身影缓缓走来——它的衣服上满是修补的痕迹,胸口绣着"fsck"三个字母。"系统崩溃了。可能是意外断电,可能是硬件故障,写入操作被中断,元数据变得不一致。"

"你能修好它?"林小源问。

"我试试。"fsck 打开工具箱,取出一堆工具,"首先检查超级块——它记录了文件系统的大小、块数、inode 数量。如果超级块坏了,什么都没法做。"

它走到一块巨大的石碑前——超级块——仔细检查了一遍:"还好,超级块完好。接下来看 inode。"

fsck 开始遍历每一个 inode,检查链接计数、大小、时间戳。"这个 inode 的链接计数是 2,但只有 1 个目录项指向它。不一致。"它修正了链接计数。

"这个 inode 没有任何目录项指向它——孤立 inode。"fsck 把它放入 lost+found 目录。

林小源帮着 fsck 在废墟中搜索。他注意到,有些区域的损坏程度比其他区域轻得多。

"那里有日志。"fsck 指着一块相对完好的区域说,"有日志的文件系统——比如 ext4——在崩溃后可以快速恢复。日志记录了最近的元数据操作,我只需要重放日志,就能恢复一致性。"

"那没有日志的文件系统呢?"

"那就麻烦了。"fsck 叹了口气,"像 ext2 这样没有日志的文件系统,我需要完整遍历所有元数据结构——超级块、inode、目录、块分配位图——逐一检查一致性。这个过程非常慢,大文件系统可能要几个小时。"

"所以日志是快速恢复的钥匙。"林小源说。

"没错。"fsck 说,"日志的代价是写入性能——每次元数据操作都要先写日志,再写实际数据。但对于需要高可靠性的系统来说,这个代价是值得的。"

林小源看着 fsck 修复了最后一个问题——一个目录的 ... 链接不一致。

"修好了?"他问。

"暂时修好了。"fsck 的语气并不轻松,"但损坏的根本原因——可能是坏块、可能是驱动 bug——我无法修复。我只能修复元数据的不一致,不能修复硬件问题。"

"那怎么预防文件系统损坏?"

"几件事。"fsck 扳着手指数,"第一,使用日志文件系统——ext4 比 ext2 可靠得多。第二,定期备份——再好的文件系统也不能保证万无一失。第三,使用 UPS——防止意外断电。第四,监控磁盘健康——SMART 工具可以提前发现坏块。"

林小源看着修复后的文件系统重新焕发生机,目录树恢复了整齐,inode 重新排列有序。

"你就像一个医生。"林小源说,"文件系统生了病,你来治病。"

fsck 摇了摇头:"我更像一个清洁工。系统崩溃后,满地狼藉,我来收拾残局。真正的医生是日志——它预防疾病,而不是治疗疾病。"

c
/*
 * 文件系统损坏的原因:
 *
 * 1. 系统崩溃
 *    写入操作被中断
 *    元数据不一致
 *
 * 2. 硬件故障
 *    磁盘坏块
 *    数据损坏
 *
 * 3. 意外断电
 *    缓冲区未写回
 *    日志未完成
 *
 * fsck 的检查项目:
 *   - 超级块一致性
 *   - inode 一致性
 *   - 目录结构
 *   - 块分配位图
 *   - 链接计数
 *
 * fsck 的修复策略:
 *   - 修复不一致的元数据
 *   - 恢复孤立的 inode
 *   - 重建损坏的结构
 */

printf("=== fsck — 文件系统检查与修复 ===\n\n");

printf("文件系统损坏的原因:\n");
printf("1. 系统崩溃\n");
printf("   写入操作被中断\n");
printf("   元数据不一致\n\n");
printf("2. 硬件故障\n");
printf("   磁盘坏块\n");
printf("   数据损坏\n\n");
printf("3. 意外断电\n");
printf("   缓冲区未写回\n");
printf("   日志未完成\n\n");

printf("--- fsck 检查项目 ---\n");
printf("1. 超级块一致性\n");
printf("   检查超级块的各个字段\n\n");
printf("2. inode 一致性\n");
printf("   检查 inode 的链接计数\n");
printf("   检查 inode 的大小\n\n");
printf("3. 目录结构\n");
printf("   检查目录项的有效性\n");
printf("   检查 . 和 .. 链接\n\n");
printf("4. 块分配\n");
printf("   检查块分配位图\n");
printf("   检查重复分配\n\n");

printf("--- fsck 命令 ---\n");
printf("检查文件系统:\n");
printf("  fsck /dev/sda1\n\n");
printf("自动修复:\n");
printf("  fsck -y /dev/sda1\n\n");
printf("只检查不修复:\n");
printf("  fsck -n /dev/sda1\n\n");

printf("--- 日志与 fsck ---\n");
printf("有日志的文件系统 (ext4):\n");
printf("  崩溃后重放日志\n");
printf("  fsck 只需检查日志\n");
printf("  速度快\n\n");
printf("无日志的文件系统 (ext2):\n");
printf("  需要完整检查\n");
printf("  速度慢\n\n");

printf("--- 预防措施 ---\n");
printf("1. 使用日志文件系统\n");
printf("2. 定期备份\n");
printf("3. 使用 UPS\n");
printf("4. 监控磁盘健康\n");

道藏笔记

内核启示

fsck 是文件系统的"清洁工"——系统崩溃后满地狼藉,它来收拾残局。

文件系统损坏的原因通常是系统崩溃(写入操作被中断,元数据不一致)、硬件故障(磁盘坏块)或意外断电(缓冲区没写回)。fsck 的工作是检查超级块、inode、目录结构、块分配位图这些元数据的一致性,发现不一致就修正——比如 inode 的链接计数和实际目录项对不上,就修正链接计数;孤立的 inode 放进 lost+found。

有日志的文件系统(比如 ext4)恢复很快——崩溃后重放日志就能恢复一致性。没有日志的文件系统(比如 ext2)就麻烦了,需要完整遍历所有元数据结构逐一检查,大磁盘可能要好几个小时。

预防比治疗重要:用日志文件系统、定期备份、用 UPS 防止意外断电、用 SMART 监控磁盘健康。fsck 能修复元数据的不一致,但修不了硬件问题。


破关试炼

fsck 之试

fsck 检查文件系统一致性时,本章多次追查的文件元数据对象是什么?

答对后才能继续滑动和进入下一章。

以修仙之名,悟内核之道