Linux Internals / Under the Hood

Linux Page Cache and Writeback: When Does a Write Reach Storage?

Follow buffered reads and writes through the Linux page cache, dirty-page accounting, writeback, and synchronization. Measure useful work without confusing RAM speed with durability.

Palash Vij / Published / 3 min read
Source-backed explainer Linux Page cache Writeback Storage

A file write finishes quickly, but storage continues working afterward. That is often the normal behavior of buffered I/O: the application changed cached pages, and the kernel still has dirty data to write back.

The page cache is not a trick that makes a disk faster. It changes when storage access is needed and which work an application waits for. A benchmark must name those boundaries before its throughput numbers mean anything.

Read hits and write completion answer different questions

A cached read can copy data from memory without another device read. Repeating the same workload therefore changes its conditions: the second pass may measure memory access and copying rather than the original storage path.

A buffered write generally updates cached pages and marks them dirty. The kernel can write them back later, and the application may eventually be throttled when dirty memory or backing-device pressure grows. A short run can finish before steady-state writeback becomes the dominant constraint.

application write -> dirty cached pages -> writeback -> filesystem/device
application fsync ---------------------> required synchronization boundary

This is a conceptual path. Filesystems, direct I/O, network filesystems, and storage hardware have different implementation details and guarantees.

Dirty-page controls are policies, not throughput multipliers

Linux exposes byte- and ratio-based dirty thresholds, including background writeback and thresholds that can involve writing tasks in writeback. A byte threshold and its corresponding ratio are alternative forms, not independent limits to maximize together.

The denominator for a dirty ratio is not simply all installed RAM. Available memory and kernel accounting matter. Kernel documentation should be consulted for the running version; a value copied from another machine can represent a very different absolute commitment.

Allowing more dirty data can absorb a burst while increasing later stalls, memory pressure, and the amount of data awaiting persistence. Reducing it can make backpressure appear sooner. Neither direction is universally an optimization.

Observe the phases without dropping global caches

On an authorized Linux host:

grep -E '^(Cached|Dirty|Writeback|MemAvailable):' /proc/meminfo
vmstat 1 5
sysctl vm.dirty_background_bytes vm.dirty_background_ratio
sysctl vm.dirty_bytes vm.dirty_ratio

These are host observations, not attribution to one process. The first vmstat line and later interval samples have different timing meaning. Pair them with application timestamps and device or filesystem measurements.

For a lab experiment, use disposable data and record dataset size relative to memory. Compare buffered completion with explicit synchronization as separate measurements. Do not flush caches system-wide on a shared host merely to label a run “cold.”

Synchronization belongs in the application contract

fsync requests synchronization of file data and relevant metadata according to filesystem semantics. Durably creating a directory entry may additionally require synchronizing the containing directory. Correct ordering depends on the operation being implemented.

Check return values: errors from earlier buffered work can surface at a later synchronization point. A successful write does not promise that a power failure immediately afterward preserves the bytes.

For NFS, client caching and the server’s stable-write or commit behavior add another boundary. A local page-cache observation is not proof of remote durable storage.

Report what the benchmark actually measured

Record filesystem, mount options, device, OS/kernel, dataset, access pattern, concurrency, duration, synchronization policy, warmup, and run count. Report sustained behavior long enough to encounter writeback, not just a cache-absorbed burst.

Use those boundaries to ask a sharper question: did the change improve application-visible latency, durable throughput, or the amount of work absorbed by memory? Those can move in different directions.

Further reading

Primary references behind this explanation. Consult documentation for the version and environment you actually run.

  1. Linux kernel: virtual memory sysctls
  2. Linux fsync(2)
  3. Linux write(2)
Follow the thread

Related reading

Search the notebook

Search articles, projects, and experiments. Everything stays on your device.

palash / notebook

A small doorway into the site. No shell, no remote execution.

Welcome. Type help to find your way around.

lab →experience →contact →Ctrl / Cmd + K