Note: This section assumes my patches to 1.4.7
The kernel nfs server maintains a list of file systems that are currently mounted by some client. As clients mount filesystems using the MOUNTD protocol, the MOUNTD server tells the kernel about them.
As the kernel needs to know about all currently mountd filesystems, it
is necessary for this information to be safely stored across
restarts. This is the responsibility of mountd which records all
current mounts in /var/lib/nfs/rmtab and of exportfs
which reminds the kernel of all exports deduced from rmtab.
Each client is known the the kernel by a struct svc_client which
is defined in linux/include/nfsd/export.h to be
struct svc_client {
struct svc_client * cl_next;
char cl_ident[NFSCLNT_IDMAX];
int cl_idlen;
int cl_naddr;
struct in_addr cl_addr[NFSCLNT_ADDRMAX];
struct svc_uidmap * cl_umap;
struct svc_export * cl_export[NFSCLNT_EXPMAX];
};
The cl_ident field stores a string (at most 1023 chars) which is
used as a key when accessing this client information via the
nfs_ctl system call. This is typically the hostname of the
client.
The cl_addr array contains up to 16 internet addresses for the
client, which should all be considered to be equivalent. This is used
as a key to the structure when an NFS request arrives over the
network. The kernel does not check, when a client is created or
change, that the addresses are not already in use by another client,
so there is a possibility for confusion if the user-level processes
allow it. Access checks are always done against the most recently
registered client to have a particular address.
The cl_export array is a hash table (size 16) which stores the
information about the different filesystems which are exported.
The struct svc_export structure is also defined in
linux/include/nfsd/export.h to be
struct svc_export {
struct svc_export * ex_next;
char ex_path[NFS_MAXPATHLEN+1];
struct svc_export * ex_parent;
struct svc_client * ex_client;
int ex_flags;
struct dentry * ex_dentry;
kdev_t ex_dev;
ino_t ex_ino;
uid_t ex_anon_uid;
gid_t ex_anon_gid;
};
The ex_next entry is used to chain together entries in the same
hash bucket. ex_client is simply a pointer back to the client
which owns the export entry, and ex_path, ex_dentry,
ex_dev, and ex_ino simply store different information about
the exported directory.
The ex_parent, if non-NULL, point to another svc_export for
this client that is an ancestor of this directory in the filesystem.
It will always point to the closest such ancestor. Many export
entries will not have a parent.
As far as I can tell, the ex_parent is maintained but never used.
It seems to be related to two checks in exp_export (in
linux/fs/nfsd/export.c) which check two rules about exporting
related directories. They appear to be:
If an ancestor directory of a given directory is exported to a given client, then the given directory can also be exported only if it is on a different filesystem/device.
If any decendant directory of a given directory, which is on the same file system (or a file system where the device has the same hash value!) is already exported to a client, then the given directory cannot also be exported to that client.
These rules are simple inverses of each other and are presumably intended to remove any ambiguity concerning which export attributes (flags and anon ids) should be applied to a given file. If either of there rules were violated then there would be two export points in the one file system with one being a child (Descendant) of the other. This would create ambiguity as to export rules should apply to children of the junior export point.
The cl_uidmap field in each client is currently not used. The
intent seems to be to allow the client and server to use different
uids and gids for the same entity, and the nfs server would do the
appropriate mapping. Presumably this would be a cache which would be
updated by a call-back to a use-space daemon on a cache-miss.
The ex_flags fields can have the following bit-flags set:
All write requests are denied with NFSERR_ROFS.
Requests from insecure ports (1024 or above) are permitted.
All accesses by uid 0 are mapped to appear to be by the uid given in
ex_anon_uid. Similarly accessed by gid 0 are treated as accessed
by gid ex_anon_gid.
All accesses are treated as though they came from uid ex_anon_uid
and gid ex_anon_gid.
This enabled a hack which attempts to allow the underlying filesystem to gather writes together for more efficient use of the lowlevel device. If a write is requested while it appears that another write is pending, the first write sleeps for 10msecs before flushing the write to give the filesystem a chance to have scheduled to two (or more) writes together.
This flags indicates that the currently unimplemented cl_uidmap
map should be used.
This unimplemented option indicates that Kerberos authentication should be used for each request.
This is another unimplemented option. It presumable indicates that SUN's Secure RPC is being used to authenticate requests.
Another unimplemented option. Presumably it is intended that file trees exported with this options allow the client to cross mount mounts.
There is another option that affects exported filesystem behaviour
that is implemented as a compile time option, CONFIG_NFSD_SUN
rather than a runtime option.
Normally, if a directory within an exported filesystem is mounted on,
then that directory and hence everything beneith it is not accessable
via NFS. If CONFIG_NFSD_SUN has been selected at compile time,
then the server acts line SUN Microsystems servers and allows the
entire file system to be viewed, independant of mounts.
There are two user level programs which assist with maintaining the
client and export lists in the kernel. They are mountd and
exportfs, the first is a daemon, the second is an admin tool.
These two programs read the /etc/exports file and maintain
the files xtab, etab and rmtab in
/var/lib/nfs as well as the in kernel client and export
lists.
/etc/exports file
The /etc/exports file lists file trees, clients that that
they can be mounted by, and export flags (such as read-only) that are
imposed on that client for that file tree.
Client names in /etc/export can be:
An empty client name will match any client.
A client name starting with an '@' will match any client host in the netgroup given by the rest of the client name.
If a client name contains '*', '?', or '[', then it is assumed to be a wild carded host name. Any host with a fully qualified domain name which matches the client name using glob matching will match the client.
If a client is a dotted-quod IP address followed by a slash and a
number of bits (e.g. 129.94.0.0/16 then any client with an IP
address in that subnet will match.
Otherwise clients must be host names and a looked up with standard host name resolution procedures.
The /etc/exports file records the default intension of what
should be exported. It is read by exportfs, usually at startup
time, and the information is presented to mountd through the
/var/lib/nfs/etab file. Thus this file is indicative, but
not authorative.
rmtab file
/var/lib/nfs/rmtab contains a list of client hosts and file
trees that have been mounted from them. The format of the file has
one line for each entry, each line being the name of the client, a
colon, and the path to the file tree that was mounted.
The name of the clients will be fully qualified domain names are returned by the resolver, or IP addresses.
Entries are added to this file when mountd replies to a
successful mount request, and are removed when mountd receives an
unmount or and unmountall request. It is used to reply to
the dump mountd request.
rmtab is used by exportfs when exporting filesystems. It
uses the host names to instantiate wild card exports to create specific
host exports to give to the kernel.
etab file
/var/lib/nfs/etab contains a list of currently exported file
trees and their options. It is in a somewhat different format than
the /etc/exports file in that each line lists just one path
and one client, and the client has all export options explicitly
listed.
The etab file will normally contain the same information as
/etc/exports, but it can be given extra information by giving
explicit export arguments to the exportfs program.
The etab file is written by the exportfs program and read by
mountd.
The etab file is the authorative list of what should be exported
to where.
/proc exports file
The file /proc/fs/nfs/exports provides a window in the
kernels table of exported file trees. It lists paths, clients and
options in exactly the same format as etab. While tab may
well have wild card, netgroup, and other non-specific client name, the
exports file in /proc only has explict client host
names.
xtab file
The file /var/lib/nfs/xtab serves much the same purpose as
/proc/fs/nfs/exports in that it records host-specific mounts
that have been given to the kernel.
More precisely, whenever an export request is given to the kernel that
is based on a group export, rather than a host export, in etab,
the host export line is written to xtab.
The xtab file is not necessary if the /proc filesystem
is available.
exportfs tool
exportfs is used to communicate the intention of the system
administrator to the NFSD system. It does that by maintaining the
etab file and playing some part in managing the in-kernel export
table.
exportfs will read file trees to be exported from
/etc/exports or from the command line, and will make
appropriate changes to etab. It can add and remove exports
requests from etab.
exportfs will also make sure that all host exports that are known
to be required (an no others) are know to the kernel. It does this by
telling the kernel about any FQDN export requests that it puts in
etab, and about any mount requests listed in rmtab that can
be validated against group export requests that are in etab.
mountd daemon
When a client wants to mount a filetree, it asks mountd.
mountd check the request against information in etab, and
reponds with file handle information if the mount is permitted. It
also make sure that the kernel knows that the filetree may be exported
to that client. If the file tree is explicitly exported to the client
in etab, then exportfs will have already told the kernel.
If the file tree is exported due to some group export request in
etab, then mountd specialised that export request to the
given client, tells the kernel about this request, and records the
fact in xtab.