NFS uses a structure called a file handle to uniquely identify exported files. When a client requests to access a file, the server constructs a file handle that identifies it; from this point on, this identifier will be used in all communications between the server and the client to access that specific file. (Look at the fs_vptofh and fs_fhtovp hooks in NetBSD's VFS layer to see how this mapping works.)

In order to identify a file univocally, you need three things: the file-system identifier (i.e., something unique to each mount point), the node number (e.g., the inode number in FFS terminology) and a generation number. It is clear why the first two are needed, but the generation number may be confusing. In order to explain this last concept, let's see an example:

Suppose you have a file using the 1234 inode of the root file-system; let's call this foo. Now, you delete foo and create a new file, called bar, which ends up reusing the 1234 inode. These two files are clearly different, but they could look the same from the point of view of a file handle if you used the file-system number and the inode number exclusively. Therefore, we need a third component, the generation number, that makes these two files different. This component is incremented each time an inode is reused for a different file.

So far, so good. But now we get to the ugly part: given a file-system number, a node number and a generation number, you can generate a file handle that refers to any file within the exported file-system. If these values were available to everybody, a malicious client could easily generate file handles to access files he is not allowed to touch. This is why the generation number is hidden to user space: if you apply stat(2) to a file, you'll always get a zero value in the st_gen field (some systems may return the correct number if you are root). Similarly, the getfh(2) system call is restricted to the super-user.

But can't a user guess the generation number? Yes, he can. This is why they are often generated based on a random seed, which makes the guessing difficult. See fsirand(8) for more information.

All this explains why there is no such thing as exporting a subtree in the NFS world. When you export a directory from a file-system, you are implicitly exporting the whole mount point because malicious file handles could be used to access files outside the subtree.

Thanks go to William Studenmund for explaining me this during tmpfs development.