Visual walkthrough — Journaling — why, how it works
We will follow one tiny operation — appending one block to a file — through the journal, and then deliberately crash the computer at every dangerous moment to watch what happens.
Step 1 — What "the disk" actually is
WHAT. Before any journal exists, we must agree on the playground. A disk is just a long row of numbered boxes called sectors (or blocks). Each box holds a fixed chunk of bytes.
WHY start here. Every claim later ("this write is atomic", "this one isn't") is a claim about these boxes. If we don't picture them, words like "in-place" and "journal" mean nothing.
PICTURE. Look at the figure. The grey strip is the disk. Most boxes hold the real filesystem: the data blocks (your file's bytes), the inode (a small record storing a file's size and where its blocks live), and the bitmap (a row of yes/no bits marking which blocks are in use). One small region on the right — coloured blue — is set aside as the journal.

The one hardware fact we are handed, and the only one:
Step 2 — Why one operation needs many writes (the danger)
WHAT. Our single "append" is really three separate box-writes: inode, bitmap, data block.
WHY it's dangerous. From Step 1, only one box at a time is safe. So a crash can happen between the three writes, leaving a mismatched combination.
PICTURE. The figure shows the three writes as three arrows landing at three different times . The red lightning bolt marks a crash that struck after the bitmap write but before the inode write.

Read the wreckage the crash left:
- The bitmap says block 50 is taken.
- No inode points to it.
- → block 50 is a lost block — space that is neither free nor reachable. Corruption.
This is the crash-consistency problem. Journaling exists purely to kill it. Notice we can't fix it by "just ordering the writes better" — any order has a fatal in-between moment.
Step 3 — The one rule: write the plan first (WAL)
WHAT. We introduce a rule so strong it removes every fatal in-between: write your full intent into the journal before touching a single real box. This is Write-Ahead Logging (see Write-Ahead Logging).
WHY. If the real structures are untouched until the plan is safe, then a crash "before the plan is safe" leaves the real filesystem exactly as it was — perfectly valid. We move the danger into a throwaway region.
PICTURE. The figure splits the disk vertically. The rule is drawn as the barrier : everything on the journal side must finish before anything on the real side may begin.

The same idea guards a database, where it enforces Atomicity of transactions — journaling is the filesystem's version.
Step 4 — The transaction: descriptor → data → COMMIT
WHAT. Inside the journal we don't dump one blob. We write, in strict order, three kinds of record: a descriptor, the new block copies, and finally a COMMIT block.
WHY this exact order. Each part answers a recovery question:
- The descriptor says which real boxes this transaction will eventually touch (its scope).
- The new-block copies hold the intended final contents.
- The COMMIT, written dead last and being a single sector (Step 1: single sector = atomic!), is a one-bit "the whole plan above me is complete."
PICTURE. The journal region is drawn left-to-right in write order. The COMMIT is the orange box at the far right — the last thing to land.

Because COMMIT is a single sector, it is itself all-or-nothing. So after a crash the COMMIT is either fully there or fully absent — never half. That crisp yes/no is the pivot the whole design turns on.
Step 5 — Checkpoint: only now touch the real boxes
WHAT. After COMMIT is safely down, we checkpoint: copy each journal payload block to its real in-place home. Then we advance the circular journal so its space can be reused.
WHY afterwards. By the WAL rule (Step 3) the real boxes were forbidden until the plan was durable. COMMIT proves the plan is durable, so — and only so — the real writes may begin.
PICTURE. Green arrows carry the payload from the blue journal into the real inode/bitmap/data boxes. The journal is a ring: after checkpoint its slot is freed and reused by the next transaction (this is why it stays small).

Step 6 — Recovery when COMMIT is MISSING (crash before Step 4 finished)
WHAT. Reboot. Scan the journal. Find TX7 with no COMMIT block. Decision: discard it.
WHY it's safe. Checkpoint (Step 5) never ran — it only runs after COMMIT. So not a single real box was touched. The filesystem is byte-for-byte in its pre-append state: valid.
PICTURE. The red bolt strikes mid-journal, before the orange COMMIT lands. Recovery sees the gap where COMMIT should be, throws the partial transaction away (grey cross-out), and the real side is untouched (green check).

The append simply "never happened." That is exactly the outcome we wanted from Step 2's disaster — no lost block, no dangling pointer.
Step 7 — Recovery when COMMIT is PRESENT (crash during checkpoint)
WHAT. Now the nastier case: crash during Step 5 — the real inode got written, but the real bitmap did not. On reboot, TX7 has its COMMIT. Decision: replay — re-copy all of TX7's payload to their homes.
WHY re-writing the already-written inode is harmless. Replay writes the same final values the payload holds. Writing the same value a second time equals writing it once — this is idempotency.
PICTURE. Left half: the crash caught checkpoint half-done (inode ✓, bitmap ✗). Right half: replay re-copies both; the inode is simply overwritten with the identical value, the bitmap is finally filled in. End state = fully applied, consistent.

Step 8 — The degenerate & edge cases (so nothing surprises you)
WHAT. We tick off the corners the smart reader will ask about.
WHY. A rule you can't fully trust is worthless. Each case below must land in one of the two branches of Step 7's rule.
PICTURE. A small case-table figure maps every crash moment onto its outcome.

| Crash moment | COMMIT state | Action | Result |
|---|---|---|---|
| Nothing written yet | absent | discard (nothing to do) | pre-state, valid |
| Mid-payload (Step 4) | absent | discard | pre-state, valid |
| The instant COMMIT is landing | atomic ⇒ fully there or fully gone | replay or discard | never "half" |
| After COMMIT, before checkpoint | present | replay whole TX | applied, valid |
| Mid-checkpoint (Step 7) | present | replay whole TX | applied, valid |
| After checkpoint, before free | present | replay (idempotent, no harm) | applied, valid |
Recall Does journaling save your
unflushed data? No. It guarantees consistency, not durability of writes still sitting in RAM. For that you need fsync. A crash can lose the last seconds of writes — but never leave the filesystem corrupt.
The one-picture summary
Everything above collapses into a single timeline: journal fills → COMMIT lands → real boxes get written → journal freed, with the recovery rule reading off whether COMMIT crossed the line.

- Before the orange COMMIT line: a crash means discard, real side untouched.
- After it: a crash means replay, idempotency makes it safe.
- The COMMIT line is the all-or-nothing boundary — the whole derivation in one vertical stroke.
A neighbouring design, Copy-on-Write Filesystems, reaches the same guarantee differently — by never overwriting in place at all — but the question it answers is identical: never let a crash catch you mid-change.
Recall Feynman: the whole walkthrough in plain words
The disk can only change one little box safely at a time, but saving a file needs three boxes changed. If lightning hits between them, you get a broken file. So the computer first scribbles the entire plan — "change these three boxes to these values" — into a small scratchpad and stamps it DONE at the very end with one quick pen-stroke (that stroke is so short it either happens or it doesn't). Only after the DONE stamp does it change the real boxes. If lightning hits before the stamp, the plan is thrown away and the real file is untouched — the save just didn't happen. If lightning hits after the stamp, on reboot the computer sees the DONE stamp, re-does the whole plan from the scratchpad, and re-writing the same values a second time changes nothing. So the file is never left half-broken. That's it.
Recall Quick self-test
Which single write decides replay vs discard? ::: The COMMIT block — present ⇒ replay, absent ⇒ discard. Why is discarding a non-committed transaction safe? ::: Checkpoint never ran, so the real in-place structures were never touched. Why is a crash during the COMMIT write not dangerous? ::: COMMIT is one sector; single-sector writes are atomic, so it's fully present or fully absent. What property lets replay re-copy already-written blocks harmlessly? ::: Idempotency — writing the same final value twice equals writing it once.