ยง49.5โ€“49.6The NFSv2 Protocol and From Protocol to Distributed File System

Part III OSTEP pp. 625โ€“628 ยท ~5 min read

  • file handle
  • generation number

A stateless server needs each request to be self-describing โ€” yet clients still want the ordinary open/read/write/close API. How do we reconcile the two?

The Crux: How To Define A Stateless File Protocol

Stateful calls like open() canโ€™t be part of the wire protocol (theyโ€™d force the server to track open files). So how do we define a protocol that is both stateless and supports the POSIX file API?

49.5 The NFSv2 Protocol

The linchpin is the file handle โ€” a unique id for the file or directory an operation targets, carried in most requests. It has three parts:

file handle โ€” a self-contained unique id for one file/dirvolume idvol = 7inode numberinode = 42generation #gen = 3which file systemwhich file in itstale-handle guardโœ— if inode 42 is freed & reused, the server bumps gen โ†’ 4; the old handle (gen 3) no longer matches โ†’ rejected
A file handle = volume id + inode number + generation number. The volume id picks the exported file system, the inode number the file within it.

The generation number is the subtle part: the server bumps it whenever it reuses an inode number, so a client holding an old handle canโ€™t accidentally read the new file that reused that inode. Here are the key protocol operations:

Figure 49.4: some NFSv2 protocol operations. Every request carries a file handle (and all other needed args) โ€” nothing relies on server-remembered state.
argumentsreturns
LOOKUPdirectory handle, name to look upfile handle + attributes
GETATTRfile handleattributes
SETATTRfile handle, attributesโ€”
READfile handle, offset, countdata, attributes
WRITEfile handle, offset, count, dataattributes
CREATEdirectory handle, file name, attributesโ€”
REMOVEdirectory handle, file nameโ€”
MKDIRdirectory handle, dir name, attributesfile handle
RMDIRdirectory handle, dir nameโ€”
READDIRdirectory handle, count, cookiedirectory entries, cookie
Dotted-underlined cells have explanations โ€” click one.

LOOKUP is how you obtain a handle: pass a directory handle plus a name, get back the handle (and attributes) for that entry. The very first handle โ€” for the root / โ€” comes from the separate mount protocol. Attributes are just the metadata stat() reports (size, owner, permissions, and the last-modified time, which will matter for caching). With a handle in hand, READ and WRITE carry the handle plus an explicit offset and count.

49.6 From Protocol to Distributed File System

Now watch the two halves cooperate on a real open โ†’ read โ†’ read โ†’ read โ†’ close sequence. The key thing to notice: the client holds all the state (the fd โ†’ handle map and the current offset), turning each read() into a self-contained READ(handle, offset, count):

Figure 49.5: reading a file. The client holds all the state (fd โ†’ handle, current offset); each request to the server is self-contained.
Client
Server
open("/foo")
read(fd, buffer, MAX) โ€” three times
close(fd)
step 1 / 9 ยท time flows downward

The client already has the root handle (from the mount protocol).

Three things stand out. First, the client โ€” not the server โ€” tracks the fd โ†’ handle mapping and the file position, which is what lets a stateless server work. Second, server contact happens only where needed: the first open triggers a LOOKUP (and a long path like /home/remzi/foo.txt triggers three โ€” one per component: home in /, remzi in home, foo.txt in remzi), while close is purely local. Third, every server request carries everything needed to complete it โ€” the design point that makes graceful crash recovery possible, which we tackle next.

Check yourself: the NFSv2 protocol

1.An NFS file handle has three parts. What is each for?

2.Why does the file handle include a generation number?

3.What does the LOOKUP protocol operation do, and how does a client get its very first handle?

4.In turning the protocol into a file system, where is the per-open-file state (like the current offset) kept?

5.Why does close(fd) require no message to the server?

6.How does the client resolve a long pathname like /home/remzi/foo.txt?

6 questions