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.
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.
Comments
Sign in to comment