Linux Page Cache and Dirty-Page Writeback
Linux’s page cache is the kernel’s in-memory cache of file data. It lets repeated reads avoid storage access and lets writes complete in memory before Linux sends them to the storage device.
The cache is not just an optional performance feature. It is the normal path for most file I/O on Linux, and it explains familiar observations such as a fast second read, memory reported as “cache,” and data that survives a process but is not yet safe after a power failure.
The problem the page cache solves
Storage is much slower than RAM, especially for small or repeated operations. Without a cache, every file read would need to wait for the storage device, even when another process had recently read the same bytes. Every small write would also need to wait for the device to update its persistent media.
Linux instead keeps recently used file data in memory. The kernel divides the file into fixed-size regions, traditionally called pages; a page is commonly 4 KiB, although the exact size depends on the system. Each cached page is associated with a file and a range of offsets within that file.
The cache uses otherwise available RAM, but it is reclaimable: under memory pressure, Linux can discard clean cached pages and use that memory for applications. “Free memory” tools often show this cached memory separately because it can be recovered without terminating a process.
How a read uses cached pages
Suppose an application calls read for bytes from a file. The kernel first checks whether the required pages are already in the page cache.
- On a cache hit, Linux copies the requested bytes from the cached page into the application’s buffer. No storage read is needed.
- On a cache miss, Linux asks the filesystem and storage stack to obtain the page. Once the data arrives, Linux places it in the page cache and copies the requested portion to the application.
The cache works in page-sized units even when the application asks for a few bytes. A read of 20 bytes can therefore cause Linux to fetch a whole page. Linux may also perform read-ahead, fetching nearby pages before the application asks for them because sequential access makes that likely.
The same cached page can satisfy reads from multiple processes. The processes may have separate application buffers, but they share the kernel’s cached copy of the file data.
A cache hit avoids device latency, but it is not necessarily a zero-cost operation: data still has to cross from kernel memory into the application’s memory, and the kernel must check permissions and file state. The major saving is avoiding the storage request.
How a write enters the cache
For ordinary buffered file I/O, an application’s write usually updates a cached page rather than immediately updating the storage device. Linux copies the new bytes into the page-cache page and marks that page dirty. Dirty means the in-memory copy differs from the copy currently held by storage.
The write call can then return without waiting for the device to finish. This combines nearby changes, turns many small writes into more efficient larger operations, and allows the device to schedule requests more effectively. It also means the application can observe a successful write before the data is durable.
If another process reads the file immediately, Linux normally serves the read from the updated cached page. Both readers and writers therefore see the kernel’s current in-memory version, even while the older version may still exist on storage.
A write can also cause a page-cache miss first. If the application changes only part of a page, Linux generally needs to obtain the existing page contents before modifying that portion. This preserves the bytes the application did not overwrite.
Dirty-page writeback
Linux cannot keep dirty pages indefinitely. Writeback is the process of sending dirty cached data to storage so the cache and storage become consistent again. Kernel background workers gradually write dirty pages, often grouping adjacent data into larger operations.
Writeback can begin because:
- a background threshold says too much memory is dirty;
- dirty data has been waiting for a configured amount of time;
- memory pressure requires reclaiming pages; or
- an operation explicitly requests flushing.
When writeback completes, the page becomes clean. Linux can then discard it if memory is needed, because the storage copy is current. If a dirty page cannot be written—for example, because the device reports an error—the writeback error must eventually be reported to an application, though the exact point at which an application notices it can be surprising.
Linux also applies writeback throttling: when an application creates dirty data faster than storage can absorb it, writes can be slowed or blocked. This prevents unlimited dirty memory from accumulating and makes the storage bottleneck visible to the writer instead of allowing a later, sudden stall.
Writeback is not the same as durability
A successful ordinary write means Linux accepted the data into its file-I/O path. It does not by itself mean the data will survive a kernel crash or power loss. Background writeback improves the chance that it is on storage, but the timing is controlled by the kernel.
An application that needs a durability boundary uses fsync on the file descriptor, or fdatasync when it needs the file’s data and only the metadata required to retrieve it. These operations request that Linux flush relevant dirty data through the storage stack before returning. The filesystem and device must honor the request, and hardware with a volatile write cache must correctly support durable flushes; otherwise even a successful synchronization request may not provide the intended power-loss guarantee.
This distinction appears in databases, editors, and incident reports: data may be visible after a process exits, yet still be lost if the machine loses power before the required synchronization completes. Closing a file is useful resource management, but it is not generally a substitute for an explicit durability operation.
Other paths
Linux also provides modes such as direct I/O, commonly requested with O_DIRECT, that can avoid the page cache for particular reads and writes. These are specialized tools and impose alignment and performance constraints. Most applications—including ordinary command-line tools, web servers, and database files unless configured otherwise—use the page cache.
The practical model is therefore: reads consult cached pages; writes modify and dirty them; background writeback sends them to storage; explicit synchronization establishes a stronger durability point.