JA EN
LearnOS & Runtime
·★ MEMBER·9 min read

File Systems from Scratch — What Does "Saved" Actually Guarantee?

If the power dies half a second after your editor says "Saved," is the file still there? Starting from a library card catalogue, this builds up blocks, inodes, directories, journaling and fsync from zero — and ends with why databases refuse to trust the file system, and which knobs turn a quiet setting into a production incident.

ModalitytextTasksystems

Pull the plug right after "Saved"

Your editor flashes "Saved" in the corner. Two hundred milliseconds later the power goes out. Is the paragraph you just wrote still on disk?

The honest answer is "probably, but nothing guarantees it." And the thing deciding it isn't your editor. Between the application and the platter sits a stack of layers — the page cache, the file system, the drive's own cache — every one of which is willing to say "written" about something it has not yet written, because saying so is faster. Learning file systems means learning exactly where those lies live.

The analogy: card catalogue and stacks

Picture a large library. The books themselves live in the stacks at the back, on shelves that carry nothing but numbers. Separately there is a catalogue card saying "this book occupies seven slots starting at shelf 3, position 12," how many pages it has, and who is allowed to read it. The card does not carry the title.

Titles live in a third ledger, the name list, which holds nothing but pairs: "The Hitchhiker's Guide to the Galaxy → card 8123."

Those three layers are very nearly the whole of a file system. The stacks are data blocks, the catalogue card is the inode, the name list is the directory. The split looks fussy until you notice what it buys: giving one book two titles, or renaming a book without moving it a single millimetre, both become instantaneous.

Disks can't be written a byte at a time

Start with the physics. Storage cannot rewrite one byte. The smallest unit a device handles is a sector — 512 bytes historically, 4096 on modern drives — and the file system manages bundles of those called blocks (4 KiB on most Linux setups).

So a one-byte file still occupies 4 KiB on disk. That is internal fragmentation, and it's why the size in ls -l and the usage reported by du disagree. As files grow, recording where their blocks live becomes expensive in itself, so modern ext4 and XFS record extents — ranges, as in "2048 consecutive blocks starting at 45000" — instead of block-by-block lists.

The inode — the file itself, with no name

The catalogue card is the inode (index node): file type and permissions, owner, size, timestamps, and the location of the data. stat shows you almost the raw thing.

$ stat notes.txt
  Size: 1240      Blocks: 8     IO Block: 4096   regular file
Device: 259,2  Inode: 8123      Links: 2
Access: (0644/-rw-r--r--)  Uid: (1000/k)  Gid: (1000/k)

The line that matters is Links: 2. That is how many names point at this inode. Run ln notes.txt memo.txt and it becomes 3, and every one of those names is equally the real file — not a copy, so editing through one changes all of them.

Which is why the system call for deletion is not delete but unlink. All it does is detach one name and decrement the count. The blocks are freed only when the count hits zero and nobody still has the file open. That "and" comes back later as a production incident.

A directory is only a table

A directory isn't magic. It is an ordinary file holding a list of name → inode-number pairs. The table always opens with . pointing at itself and .. pointing at its parent, which is why every directory starts life with a link count of 2.

Built naively, that table can only be scanned from the top. With 100,000 files, finding one costs 50,000 comparisons on average. So ext4 uses dir_index (an htree — a hashed B-tree) and XFS uses a B+ tree, so a name resolves in one short descent. The gap here isn't a factor of two; it's orders of magnitude.

FIG 1Lookup cost against the number of files n in one directory. Put linear scanning O(n) next to an indexed lookup O(log n) and drag n rightward — the gap opens up by orders of magnitude, not percentages

Break down "append one block to the end of a file." (1) Flip one bit in the free-block bitmap to "in use." (2) Write the data into that block. (3) Update the size and block pointers in the inode. That's three writes to three different places, and the disk is under no obligation to perform them in the order you issued t

What's behind this

§

Members-only from here

371 walkthroughs, 26 textbook chapters, 48 student units and 6 close readings — all included for $4.99/mo, with three new explainers every day. Cancel any time; access runs to the end of the period.

Already a member? Sign in to keep reading

Comments

Sign in to comment