第九十八章: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 摇了摇头:"我更像一个清洁工。系统崩溃后,满地狼藉,我来收拾残局。真正的医生是日志——它预防疾病,而不是治疗疾病。"
/*
* 文件系统损坏的原因:
*
* 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");#include <stdio.h>
/*
* 文件系统损坏的原因:
*
* 1. 系统崩溃
* 写入操作被中断
* 元数据不一致
*
* 2. 硬件故障
* 磁盘坏块
* 数据损坏
*
* 3. 意外断电
* 缓冲区未写回
* 日志未完成
*
* fsck 的检查项目:
* - 超级块一致性
* - inode 一致性
* - 目录结构
* - 块分配位图
* - 链接计数
*
* fsck 的修复策略:
* - 修复不一致的元数据
* - 恢复孤立的 inode
* - 重建损坏的结构
*/
int main() {
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");
return 0;
}道藏笔记
内核启示
fsck 是文件系统的"清洁工"——系统崩溃后满地狼藉,它来收拾残局。
文件系统损坏的原因通常是系统崩溃(写入操作被中断,元数据不一致)、硬件故障(磁盘坏块)或意外断电(缓冲区没写回)。fsck 的工作是检查超级块、inode、目录结构、块分配位图这些元数据的一致性,发现不一致就修正——比如 inode 的链接计数和实际目录项对不上,就修正链接计数;孤立的 inode 放进 lost+found。
有日志的文件系统(比如 ext4)恢复很快——崩溃后重放日志就能恢复一致性。没有日志的文件系统(比如 ext2)就麻烦了,需要完整遍历所有元数据结构逐一检查,大磁盘可能要好几个小时。
预防比治疗重要:用日志文件系统、定期备份、用 UPS 防止意外断电、用 SMART 监控磁盘健康。fsck 能修复元数据的不一致,但修不了硬件问题。
fsck 之试
fsck 检查文件系统一致性时,本章多次追查的文件元数据对象是什么?