Two loose ends remain: how good NFSβs caching really is, and a subtle server-side correctness rule.
49.10 Assessing NFS Cache Consistency
NFSβs cache consistency is an engineering solution, and it shows. Flush-on-close does the right thing but over-works: a short-lived temp file, created and quickly deleted, is still forced all the way to the server. And the attribute cache means you sometimes get the latest version and sometimes a stale one β depending only on whether a timeout has elapsed. Itβs a striking case where the details of an implementation end up defining the user-observable semantics, rather than the other way around.
49.11 Implications on Server-Side Write Buffering
Clients arenβt the only ones that cache β servers do too. Reads are easy to cache.
Writes are the trap: a server must not report a WRITE as successful until
the data is on stable storage. Watch what happens if it acks from memory instead:
1Start: a 3-block file
The file holds x's, y's, z's. A client issues three writes: block 0 β a's, block 1 β b's, block 2 β c's. Expected result: aaa / bbb / ccc.
Because the client treats βsuccessβ as βpersistedβ, it never retries the lost middle write β leaving a silent hole. So NFS servers force each write to disk before replying. That made write speed a bottleneck, which spawned an industry: NetApp and others built fast NFS servers using battery-backed memory (so a reply is safe without an immediate disk write) plus an LFS-style file system tuned to write quickly.
Aside: Innovation Breeds Innovation β the VFS/vnode Interface
Bringing NFS into the OS required another lasting invention: the virtual file system virtual file system The VFS / vnode interface, introduced by Sun to support NFS, that lets multiple file-system implementations plug into a single operating system. VFS-level operations act on a whole file system (mount, unmount, sync all dirty writes); vnode-level operations act on a single file (open, close, read, write). A new file system just implements these methods; the framework connects system calls to it and handles generic functions like caching. Some form of it now exists in Linux, the BSDs, macOS, and Windows. defined in ch. 49 β open in glossary (VFS/vnode) interface. VFS operations act on a whole file system (mount, unmount, sync all dirty writes); vnode operations act on one file (open, close, read, write). Implement those methods and the framework connects system calls to your file system and handles generic work like caching β letting many file systems coexist. Some form now lives in Linux, the BSDs, macOS, and Windows.49.12 Summary
NFS is built around simple, fast crash recovery, achieved through careful protocol design. The whole chapter in one table:
| idea | what it does | |
|---|---|---|
| stateless | stateless protocol | the server tracks nothing about clients β after a crash it just restarts and serves; the client, at worst, retries |
| idempotent | idempotent operations | repeating an op equals doing it once β a client can safely retry, unifying lost-message and server-crash recovery |
| caching | client caching + write buffering | cache data/metadata for performance β but this introduces the cache consistency problem |
| consistency | flush-on-close + attribute cache | engineering fixes: flush dirty pages on close; a GETATTR check softened by a ~3 s attribute-cache timeout |
| server-writes | server forces writes to stable storage | never ack a WRITE until it is persisted β otherwise a crash silently loses acknowledged data |
| vfs | VFS / vnode interface | the pluggable file-system layer Sun added so many file systems can coexist in one OS |
A stateless protocol plus idempotent operations means recovery is just βrestart and retryβ. Caching is essential for performance but brings the cache consistency problem, which NFS solves in a slightly ad hoc way β occasionally producing observably weird behavior. Server writes must reach stable storage before success is reported. One thing we glossed over is security: early NFS was famously lax (any user could masquerade as another), later shored up with services like Kerberos. Next, AFS takes a very different approach to the same problems.
Check yourself: server write buffering, VFS, and the NFS recap
1.Why must an NFS server force a WRITE to stable storage BEFORE replying success?
2.In the a/b/c example (three writes overwriting three blocks), the server buffers the 2nd write, acks it, then crashes. What's the final file?
3.Forcing writes to disk before acking made write performance a bottleneck. How did vendors like NetApp address it?
4.What's a downside of flush-on-close, and what does the attribute cache reveal about NFS semantics?
5.What is the VFS/vnode interface, introduced by Sun to support NFS?
6.Which pair of ideas is the core of NFS's fast, simple crash recovery?