The last section left us with a crux: even simple operations trigger many scattered I/Os. The first line of defense is memory.
40.7 Caching and Buffering
Caching reads. Without a cache, every open costs at least two reads per
directory level β a path like /1/2/β¦/100/file.txt would trigger hundreds
of reads. So file systems cache popular blocks in DRAM. Early systems used a
fixed-size cache (~10% of memory, LRU-managed); modern systems instead fold
file-system blocks and virtual-memory pages into one unified
page cache page cache Linux's unified in-memory cache of memory-mapped files, file data/metadata, and anonymous (heap/stack) memory, kept in a hash table with clean/dirty tracking; pdflush threads write dirty pages back in the background.
defined in ch. 23 β open in glossary
, partitioned dynamically:
Tip: Understand Static vs Dynamic Partitioning
When splitting a resource among users, you can divide it once (static) or flex the division over time (dynamic). Static is predictable and simple but can waste idle capacity; dynamic uses resources better but is more complex. Neither is always best β match the approach to the problem.| static partitioning | dynamic partitioning | |
|---|---|---|
| How | fix the split once (e.g. 10% to the FS cache at boot) | shift the split over time as needs change |
| Upside | predictable performance; simple to build | better utilization |
| Downside | wasteful β idle FS-cache pages can't be repurposed | more complex; a user's reclaimed memory may be slow to get back |
Buffering writes. Caching filters reads (a hit avoids the disk entirely), but writes must eventually reach disk to be durable β a cache canβt filter them away. What it can do is delay them: write buffering write buffering Delaying writes in memory (typically 5β30 s) before committing them to disk. It lets the file system batch updates, schedule them efficiently, and even cancel them (create-then-delete). The cost is the durability/performance trade-off: buffered writes are lost if the system crashes first. defined in ch. 40 β open in glossary holds writes in memory for 5β30 seconds before committing:
1Writes land in the buffer, not on disk
A write() returns as soon as the data sits in the in-memory buffer; the disk write happens later. The application sees fast writes β but the data is not yet durable.
Tip: The Durability / Performance Trade-off
Buffering makes writes feel instant and enables batching, scheduling, and cancellation β but buffered writes are lost if the machine crashes first. Applications that canβt tolerate this (databases) opt out by callingfsync(), using direct I/O, or writing to the raw disk. Match the
guarantee to what the data is worth: a lost browser thumbnail is fine; a lost
bank transaction is not.40.8 Summary
Weβve built the basic machinery of a file system: inodes hold each fileβs metadata and block pointers; directories are just files mapping names to inode numbers; bitmaps track which inodes and blocks are free; and the access paths show how opens, reads, and writes turn into scattered disk I/Os β which caching and write buffering then work to reduce.
The beauty of file-system design is its freedom: every structure and policy here can be changed. The chapters ahead exploit exactly that β FFS adds a locality policy, journaling makes the 5-I/O allocating write crash-safe, and LFS turns all those scattered writes into one big sequential stream.
Check yourself: caching and write buffering
1.Why do file systems cache blocks in memory?
2.What is the modern approach to the file-system cache?
3.Why doesn't caching reduce WRITE traffic the way it reduces read traffic?
4.Which are genuine benefits of delaying writes (write buffering)?
5.What is the durability/performance trade-off of write buffering?
6.How can an application that can't tolerate buffering loss (e.g. a database) force durability?