While the Linux kernel NFS server maintains an authentication cache , the final authority on what what filesystems are exported to who and with what permissions is
rpc.mountd
. Mountd gets this information from
/var/lib/nfs/etab
, which conveniently is a plain text file. However, mountd reads the information from
etab
into an internal data structure and only re-does this when
etab
's inode number changes. As far as I can tell there's nothing else to it, which means that you can create a new version of
etab
by hand if you want to.
(While
lsof
will tell you that
rpc.mountd
has
etab
open, mountd does this purely so that
etab
's current inode number can't be reused for a new file. It never re-reads the opened file.)
Normally, new versions of
/var/lib/nfs/etab
are created only by
exportfs
(which writes the new version to an '
etab.tmp
' file and then renames it). Because
exportfs
allows you to make NFS export changes through the command line that are not present in
/etc/exports
and
/etc/exports.d/
files, in normal operation
exportfs
determines the new contents of
/var/lib/nfs/etab
in part by merging the current contents in with your new changes. Your new changes can come from the command line, for things like '
exportfs -u <client>:<path>
' and '
exportfs
-i -o <options> <client>:<path>
', or from
/etc/exports
and company for things like '
exportfs -a
'. This behavior of merging in the exports from the current
etab
is why '
exportfs -a
' doesn't remove exports that are no longer in
/etc/exports
.
(A plain '
exportfs -au
' has the obvious behavior of writing an empty
/var/lib/nfs/etab
.)
For exports that exist in both
etab
and
exports
, this merging process will replace export options from the old
etab
with the versions from
/etc/exports
and company, including things like '
ro
' versus '
rw
'. This means that an '
exportfs -a
' will at least update client access permissions for existing exports, even if it won't cut off clients who have been entirely removed from the export permissions.
Exportfs also has a '
-r
' option, which is described by the manpage as:
Reexport all directories, synchronizing
/var/lib/nfs/etabwith/etc/exports. This option removes entries in/var/lib/nfs/etabwhich have been deleted from/etc/exports, and removes any entries from the kernel export table which are no longer valid.
Although the code in exportfs.c is hard to follow, the first part of '
exportfs -r
' is implemented by generating the new
etab
purely from
/etc/exports
and company, without merging in the current contents of
/var/lib/nfs/etab
. This does exactly what you want once the kernel caches are flushed , and does it without un-exporting anything that should stay exported . If something is exported in both the old
etab
and the updated
etab
, obviously
rpc.mountd
will always permit access; there will never be a period where
rpc.mountd
is using an
etab
without it listed.
(The second claim in the description is what I would call not entirely correct. The actual code simply flushes the caches in general. As covered in this entry , in modern kernels any flush is a total flush, which means that '
exportfs -fr
' and '
exportfs -r
' do the same thing in the end. In older kernels, what gets flushed without '
-f
' is somewhat chancy, so I think you probably want to use '
-f
' to be sure.)
Back in January I mentioned '
exportfs -r
' and wondered why our system for ZFS NFS export permissions wasn't using it . Given what I now know about how all of this works, we definitely should be using '
exportfs -r
' instead of our current approach of first un-exporting a filesystem and then re-exporting it (and we'll be changing our scripts to implement this). '
exportfs -r
' does exactly what we want when changing the NFS sharing for an existing NFS export. In general, what you want to do for seamless persistent NFS export changes is to write the new information to
/etc/exports
or some file in
/etc/exports.d
and then run '
exportfs -r
' to resynchronize
/var/lib/nfs/etab
to your new reality.
(I believe that you want to do this even when removing an export entirely, or at least that doing so is the simplest way of un-exporting something.)
To put it another way, consistently using '
exportfs -r
' turns
/var/lib/nfs/etab
into a processed cache instead of another source of truth. That's certainly what we want in general operation (perhaps not in emergencies, but emergencies are special cases).