Β§43.9–43.13LFS Garbage Collection, Recovery, and Summary

Part III OSTEP pp. 555–559 Β· ~9 min read

  • cleaning
  • segment summary block
  • versioning file system
  • roll forward

Efficient sequential writes have a cost: LFS keeps writing new versions and leaves the old ones behind as garbage.

43.9 A New Problem: Garbage

Because LFS never overwrites in place, old versions of blocks and inodes pile up across the disk. Whether an old block is dead depends on the operation:

Never overwriting in place leaves old versions behind as garbage β€” but whether the OLD data is garbage depends on the operation. (Green = live, red dashed = dead garbage.)
D0A0garbageI[k]A1garbageD0'A4liveb0:A4I[k]A5liveupdate: old inode + old data both dead

1Update a block β†’ old inode AND old data die

File k's block D0 is at A0. We overwrite it: LFS writes a NEW data block and a NEW inode (at A4/A5). Now BOTH the old data D0 and the old inode at A0/A1 are garbage β€” nothing points to them.

step 1 / 2

You could keep the old versions and let users restore them β€” that’s a versioning file system (NetApp’s WAFL does this via snapshots). But LFS keeps only the latest live version, so a background cleaner must reclaim the dead space. Crucially, cleaning works segment-by-segment β€” freeing whole segments so there’s always a big contiguous region for the next sequential write:

LFS cleaning works segment-by-segment (not block-by-block, which would leave scattered holes). It reads M partly-dead segments, keeps the live blocks, and writes N < M compact segments.
seg 1seg 2seg 3β–  live β–  dead β–‘ freeM = 3 segments, ~half dead

1Three partly-dead segments

Over time, segments accumulate a mix of live and dead blocks. Cleaning single blocks would leave a disk full of small holes β€” no room for the big sequential writes LFS needs.

step 1 / 3

This cleaning raises two questions: a mechanism (which blocks are live?) and a policy (when and what to clean?).

43.10 Mechanism: Determining Liveness

To tell live from dead, LFS records β€” at the head of each segment, in a segment summary block β€” the (inode number, offset) of every data block. A block at address A is live iff, following that inode through the imap, the inode’s pointer still equals A:

(N, T) = SegmentSummary[A];   // block at A belongs to file N, offset T
inode  = Read(imap[N]);        // find that file's current inode
if (inode[T] == A)
    // block at A is LIVE  (the inode still points here)
else
    // block at A is dead  (the inode moved on)

(A shortcut: on truncate/delete, LFS bumps a version number in the imap and records it in the segment, so a version mismatch flags whole dead blocks without the full check.)

43.11 Policy: When and What To Clean

When is easy β€” periodically, when idle, or when the disk fills. What is harder: the original paper segregates hot segments (rapidly over-written β€” wait, since more blocks will soon die on their own) from cold ones (mostly stable β€” clean sooner). Getting this right has been the subject of much research.

43.12 Crash Recovery

What if a crash hits mid-write? LFS organizes its segments as a log, with the checkpoint region pointing at the log’s head and tail. Two hazards:

  • A torn CR write. LFS keeps two checkpoint regions (one at each end of the disk), written alternately, each with a timestamped header and footer. A crash mid-update leaves mismatched timestamps, so recovery just uses the most recent consistent CR.
  • Lost recent writes. Since the CR is only written ~every 30 s, a plain recovery would lose the last many seconds. So LFS rolls forward:
the log (segments)CRCRcopy 1copy 2roll forwardtwo CRs (written alternately, timestamp-guarded) β†’ use the newest consistent one, then scan forward past it

Roll forward starts from the last checkpoint, finds the end of the log it recorded, and scans forward through the following segments, applying any valid updates β€” recovering most of the data written since the last checkpoint.

43.13 Summary

LFS never overwrites in place: it gathers updates into large in-memory segments and writes them sequentially to unused space β€” a form of copy-on-write (shadow paging). This makes writes excellent on disks, on parity RAID (it sidesteps the small-write problem entirely), and even on flash SSDs. The price is garbage and the complexity of cleaning β€” which limited LFS’s initial impact, but whose ideas live on in WAFL, ZFS, and btrfs.

Tip: Turn Flaws Into Virtues

When a system has a fundamental flaw, see if you can turn it into a feature. NetApp’s WAFL turned LFS’s leftover old versions β€” the cleaning headache β€” into user-visible snapshots for restoring accidentally deleted files. One twist removed a problem and added a beloved feature.

Check yourself: LFS cleaning and recovery

1.Why does LFS generate garbage, and when is an OLD data block actually dead?

2.Why does the LFS cleaner work segment-by-segment instead of freeing individual dead blocks?

3.How does LFS determine whether the block at address A is live?

4.What is a versioning file system, and how does WAFL relate to it?

5.How does LFS recover from a crash?

6.What is LFS's key idea, and where does its legacy live on?

6 questions