Part 4 · 2 chapters · ~12 min

File Systems

Files, directories and inodes, hard and symbolic links, the VFS, the page cache and writeback, fsync and durability (with measured costs), journaling and crash consistency, file descriptors and their limits, and the rename trick for atomic file updates.

9

The write path

code
ls -i report.pdf             # the inode number
stat report.pdf              # size, blocks, link count, timestamps
ln report.pdf hard.pdf       # hard link: another name for the same inode
ln -s report.pdf soft.pdf    # symbolic link: a file containing a path
FROM write() TO THE DISK
the layers a file write passes through
VFSone API for every file system: open, read, write, fsyncpage cachewrites land here first; reads served from herefile systemext4, XFS, APFS: inodes, directories, extents, journalblock layerIO scheduling, merging, queuesdriver + deviceNVMe queue, SSD firmware, flash
swipe the figure sideways, or tap expand for full screen
1/5
VFS
The virtual file system gives one interface over every file system and many things that are not disks (/proc, sockets, pipes): "everything is a file".
one API over many file systemseverything is a file
10

Atomic updates and descriptor limits

code
// atomically replace a config file: readers see the old file or the new one, never half
const tmp = `${path}.tmp-${process.pid}`;
const fh = await fs.open(tmp, 'w'); await fh.writeFile(data); await fh.sync(); await fh.close();   // data durable
await fs.rename(tmp, path);                                                                       // atomic on POSIX
const dir = await fs.open(dirname(path), 'r'); await dir.sync(); await dir.close();               // make the rename durable

File descriptors are small integers indexing a per-process table of open files, sockets and pipes. Every process has a limit (ulimit -n); leaking descriptors ends in EMFILE (Backend Debugging part 1).