Next Previous Contents

3. Exporting file trees

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:

Rule 2

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.

Rule 3

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.

3.1 Other export details

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:

READONLY

All write requests are denied with NFSERR_ROFS.

INSECURE_PORT

Requests from insecure ports (1024 or above) are permitted.

ROOTSQUASH

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.

ALLSQUASH

All accesses are treated as though they came from uid ex_anon_uid and gid ex_anon_gid.

GATHERED_WRITES

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.

UIDMAP

This flags indicates that the currently unimplemented cl_uidmap map should be used.

KERBEROS

This unimplemented option indicates that Kerberos authentication should be used for each request.

SUNSECURE

This is another unimplemented option. It presumable indicates that SUN's Secure RPC is being used to authenticate requests.

CROSSMNT

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.

3.2 User level assistants

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.

The /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:

ANONYMOUS

An empty client name will match any client.

NETGROUP

A client name starting with an '@' will match any client host in the netgroup given by the rest of the client name.

WILDCARD

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.

SUBNETWORK

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.

FQDN

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.

The 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.

The 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.

The /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.

The 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.

The 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.

The 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.


Next Previous Contents