146 / 163 · C11 · 8 min
Crash Consistency: FSCK and Journaling
File systems keep inodes, bitmaps and data blocks on disk; one operation often needs several writes. A crash can leave a partial update and inconsistency. This chapter originally explains fsck-style later scanning plus journaling (write-ahead logging) that recovers quickly with modest extra work.
In this lesson
The Problem of Crashes During Persistent Updates
A disk finishes only one write at a time. Appending a block requires changing the inode, the data bitmap and the new data block. A crash between those writes can leave a bitmap-inode mismatch, a leaked block or garbage contents. Ideally the whole operation would finish atomically, moving the on-disk image from one consistent picture to another.
Repairing After the Fact with a Checker
Early designs let inconsistencies happen and ran a tool such as fsck at reboot. The checker walks every inode, bitmap and directory, finds mismatches and repairs them. The method is easy to implement, yet a full scan of a large disk takes a long time and the file system stays unavailable during recovery.
Journaling: Record Intent Before Real Updates
Journaling first appends the complete intent of an operation into a dedicated log and forces it to disk, then updates the real inodes, bitmaps and data. After a crash the system only scans the log, replays committed transactions or discards uncommitted ones, restoring consistency quickly without a full-disk walk.
Common Journaling Modes
Data journaling puts both user data and metadata into the log, giving the strongest guarantees at the cost of extra writes. Metadata journaling logs only metadata while data goes straight to its final location, so a crash may expose stale contents. Ordered mode forces data to disk before the matching metadata. Implementations trade performance, space and safety.
Pitfalls
- Believing the disk can atomically finish several writes
- Not forcing the journal to stable storage before the commit record, leaving a torn log
- Fixing only metadata while users can still read garbage data
Run an example
Minimum C11 · complete program · Download .c
#include <stdio.h>
int main(void) {
printf("Tiny file-system crash-consistency demo\n");
printf("Operation: append one data block (update inode, bitmap, data)\n\n");
printf("Crash after 1 write:\n");
printf(" data only -> write lost, still consistent\n");
printf(" inode only -> pointer to garbage, bitmap mismatch\n");
printf(" bitmap only -> leaked block, no owner\n\n");
printf("Crash after 2 writes:\n");
printf(" inode+bitmap -> metadata OK, garbage data\n");
printf(" inode+data -> bitmap mismatch\n");
printf(" bitmap+data -> leaked block\n\n");
printf("Journaling solution: write transaction to log, commit, then checkpoint.\n");
printf("Recovery: replay committed transactions only.\n");
return 0;
}
Compile locally
gcc -std=c11 -Wall -Wextra -Wpedantic -Werror ostep-42-journaling.c -o example && ./exampleExpected result
Tiny file-system crash-consistency demo
Operation: append one data block (update inode, bitmap, data)
Crash after 1 write:
data only -> write lost, still consistent
inode only -> pointer to garbage, bitmap mismatch
bitmap only -> leaked block, no owner
Crash after 2 writes:
inode+bitmap -> metadata OK, garbage data
inode+data -> bitmap mismatch
bitmap+data -> leaked block
Journaling solution: write transaction to log, commit, then checkpoint.
Recovery: replay committed transactions only.
CHECK YOUR UNDERSTANDING
Close the answer. Explain it.
If an append writes the inode and the data block but not the bitmap, what inconsistency appears on disk? How would fsck versus journaling handle it?
Show a reference answer
The inode claims a block that the bitmap still marks free. fsck would scan and set the bitmap bit to match the inode. Journaling recorded the whole transaction first, so recovery either replays all three updates together or rolls them all back, never leaving that half-done state.
Check the sources
Drafts and official chapters change. The version mark is only the example’s minimum.