Here is a fact that quietly runs your whole machine: free RAM is wasted RAM, so Linux
spends nearly all of it caching file data. Every byte you read from or write to a file passes through the
page cache — a pool of RAM pages holding recently-touched file contents. The first read
of a file pays the full
The page cache is where the OS decides two hard questions. On reads: should I fetch more than you asked for, betting you'll want it? (read-ahead). On writes: can I lie that your data is saved, keep it in RAM, and flush it to disk later? (writeback). Both bets usually win big — and both have a sharp edge (data loss on crash, cache pollution) that this lesson makes precise.
A cached page is in one of two states. A clean page's contents are identical to what is on disk — it can be dropped and reclaimed instantly, because the disk still has a good copy. A dirty page has been written by a program but not yet persisted — RAM holds the only up-to-date copy, so it must be written back to disk before its memory can be reused.
This clean/dirty split is the join between two subsystems you already know. Reclaiming clean pages
is free, so the page cache interlocks with
When you read the first few blocks of a file in order, the kernel notices the pattern and
reads ahead — prefetching the next chunk before you ask, so by the time your next
The model below streams through a file with a read-ahead window. Sequential access turns almost every request into a cache hit; the one-time misses are the prefetches themselves.
When a program writes, the kernel copies the data into a page, marks it dirty, and returns success immediately — the data is still only in RAM. This write-back caching (as opposed to write-through, which would wait for the disk) is what makes writes feel instant and lets the kernel batch, merge, and reorder many small writes into efficient large ones. A family of kernel flusher threads later walks the dirty pages and writes them to disk, governed by tunables:
dirty_background_ratio — once this fraction of RAM is dirty, flushers start working in the
background;dirty_ratio — a hard ceiling: once this fraction is dirty, writers themselves are
throttled (made to flush synchronously) so dirty data can't grow without bound;dirty_expire_centisecs — a dirty page older than this is flushed regardless, so nothing
lingers unsaved forever (typically ~30 s).It sounds perverse — turn off the free speed-up? But a database like PostgreSQL or Oracle already keeps its own finely-tuned buffer pool in user space, with knowledge the kernel lacks: which pages are hot, which must hit disk before a commit, exactly when to flush for durability. If the kernel also caches every block, you get double buffering — the same data cached twice, wasting RAM — and the kernel's generic read-ahead and writeback heuristics fight the database's careful ones. O_DIRECT lets the application say "move these bytes straight between my buffer and the device by DMA; do not touch the page cache." The app trades away the kernel's help for total control and predictable latency. It's a recurring theme: the smartest cache is sometimes no cache, when someone above knows better.
The most dangerous illusion the page cache sells: a 0 (success) has, by default, only copied your bytes into a dirty RAM page.
If the machine loses power in the next few seconds — before the flusher threads run — that data is simply
gone, even though your program was told it succeeded. To actually guarantee persistence
you must call O_SYNC), which blocks
until the dirty pages and the file's metadata are truly on stable storage. This is why databases