Module 07 · File systems and I/O · Lesson 1 of 8
File system structure
What a file system does: turn a disk's numbered blocks into named, nested files with permissions. Files, directories, paths, the on-disk layout, the page cache in front of it.
Why it matters
Every log line, configuration file, database page and container layer ends up in a file system. Its behaviour explains why writing a file is not the same as storing it safely, why a directory with ten million files is slow, why "disk full" can happen with free space left, and why reading the same file twice is much faster the second time. It is also where the block storage you met in System Design turns into something a program can open by name.
The idea
A disk (or SSD, or cloud volume) is an array of numbered blocks. A file system builds the familiar abstraction on top: files (named sequences of bytes), directories (named containers of files and directories, forming a tree), metadata (size, owner, permissions, timestamps), and the mapping from each file to the blocks that hold its data.
What lives on disk
| Structure | Holds | Why it matters |
|---|---|---|
| Superblock | File system size, block size, counts, state | Read at mount; corruption here is serious, so it is replicated |
| Inode table (or equivalent) | One record per file: metadata and pointers to data blocks | Running out of inodes means 'disk full' with free space left |
| Free space tracking | Bitmaps or trees of free blocks and inodes | Allocation speed and fragmentation |
| Directory data | Name-to-inode entries | Large directories need indexed formats (hashed B-trees) |
| Data blocks | File contents, often allocated in contiguous runs (extents) | Sequential reads are fast when files are contiguous |
| Journal | A log of pending metadata (or data) changes | Fast, consistent recovery after a crash |
The next lessons look at inodes and directories, the journal, and the I/O path in detail.
Paths and open files
A path like /var/log/app.log is resolved component by component: start at the root directory, look up var, then log, then app.log, checking permissions at each step. open returns a file descriptor, and from then on reads and writes go through the descriptor without re-resolving the path; the kernel tracks the current offset per open file. That is why a deleted log file keeps growing (and filling the disk) while a process still has it open: the name is gone, but the inode lives until the last descriptor closes.
The page cache
File data passes through the page cache, the kernel's cache of file pages in otherwise unused RAM. Reads that hit it never touch the disk; writes land in it as dirty pages and are written back later by the kernel (typically within seconds). This is why the second read of a file is fast, why free shows little free memory on a healthy server, and why a successful write does not mean the data is on disk: only fsync (or opening with synchronous flags) forces it out and waits, which the journaling lesson covers.
Mounting and the VFS
Separate file systems are attached into one tree by mounting them at directories. The virtual file system layer gives every type the same interface, so the same open and read work on an ext4 disk, a network file system, a FUSE file system implemented in user space, the overlay file system of a container, or pseudo-file systems like /proc (process information), /sys (kernel and device settings) and tmpfs (files in RAM). "Everything is a file" in Unix is largely the VFS at work.
Choosing a file system
Most Linux servers use ext4 (mature, general purpose) or XFS (strong with large files and parallel I/O, the default on several distributions). btrfs and ZFS add copy-on-write, checksums of all data, snapshots and built-in volume management. Databases often have specific recommendations (XFS is common for Postgres and MongoDB), and container hosts rely on overlayfs for image layers.
Trade-offs
File systems trade raw block access for names, hierarchy, permissions and crash consistency, at the cost of metadata overhead and an extra layer of caching. The page cache makes most I/O fast and makes durability a deliberate act (fsync). Feature-rich copy-on-write file systems add integrity and snapshots at some cost to write performance and predictability.
In an interview
Name the layer that matters: "Logs are written through the page cache and rotated by renaming; we make sure the rotating process reopens the file, or a deleted-but-open log keeps eating disk. Database files sit on XFS on a provisioned-IOPS volume, and the database calls fsync on commit, because a successful write only reaches the page cache."
Check yourself
A disk shows 100 percent full. You delete a 50 GB log file, but df still shows no free space. Why?