Filesystems & Storage

journaling

Renaming a file or growing one is rarely a single write to disk - it touches the inode, a directory entry, and the allocation bitmap, several separate blocks. If the power dies after two of those three writes land, the filesystem is left in a half-finished state: a block marked used by no file, or a directory entry pointing at an inode that says it has no links. To avoid spending minutes after every crash hunting for such damage, modern filesystems first write down what they are about to do, then do it. That write-it-down-first discipline is journaling.

A journaling filesystem keeps a dedicated on-disk area, the journal (a write-ahead log). Before applying a multi-block change to the main filesystem, it bundles the change into a transaction and writes the whole transaction to the journal, ending with a commit record. Only after the commit record is safely on disk does it begin writing those changes to their real home locations (this second step is called checkpointing). If a crash happens mid-update, on the next mount the filesystem replays the journal: any transaction with a complete commit record is reapplied to the main area, and any incomplete transaction (no commit record) is simply discarded. Either way the filesystem returns to a consistent state quickly - seconds of journal replay instead of a full scan.

Why it matters: journaling turned crash recovery from a slow, whole-disk fsck into a fast log replay, which is why large filesystems can mount almost instantly after an unclean shutdown. The crucial honesty point: most filesystems journal only metadata by default, not your file's data. That guarantees the filesystem structure stays consistent after a crash, but it does NOT guarantee that the last bytes you wrote actually reached the disk - for that you still need fsync(). Journaling protects the filesystem, not necessarily your most recent data.

1. write transaction {inode, dir entry, bitmap} to journal 2. write COMMIT record to journal <- transaction now durable 3. checkpoint: write the same blocks to their real locations crash before step 2 -> on remount, discard the incomplete transaction (no damage) crash after step 2 -> on remount, replay it (changes reapplied)

Write the intent to the journal and commit it first; a crash either discards an incomplete transaction or replays a committed one.

Journaling guarantees a consistent filesystem after a crash, NOT that your latest writes survived. By default only metadata is journaled, so without fsync() the data you wrote a moment ago may simply be gone even though the filesystem is intact.

Also called
filesystem journalingjournaled filesystem檔案系統日誌