Re: [PATCH/RFC] autofs: the documentation I wanted to read

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On 07/28/14 19:00, NeilBrown wrote:
> 
> 
> This documents autofs from the perspective of what the module actually
> supports rather than how automount is expected to use it.
> It is based mostly on code review and very little on testing so it
> may be inaccurate in some places.
> 
> The document assumes the functionality added by the RCU-walk patches
> that I posted recently.
> 
> It is formatted using "markdown" and works best with Markdown.pl
> (markdown_py doesn't like some constructs).
> 
> 
> Signed-off-by: NeilBrown <neilb@xxxxxxx>
> 
> diff --git a/Documentation/filesystems/autofs4.txt b/Documentation/filesystems/autofs4.txt
> new file mode 100644
> index 000000000000..45f67c83d713
> --- /dev/null
> +++ b/Documentation/filesystems/autofs4.txt
> @@ -0,0 +1,503 @@
> +<head>
> +<style> p { max-width:50em} ol, ul {max-width: 40em}</style>
> +</head>
> +
> +autofs - how it works
> +=====================
> +
> +Purpose
> +-------
> +
> +The goal of autofs is to provide on-demand mounting and race free
> +automatic unmounting of various other filesystems.  This provides two
> +key advantages:
> +
> +1. There is no need to delay boot until all filesystems that
> +   might be needed are mounted.  Processes that try to access those
> +   slow filesystems might be delayed but other processes can
> +   continue freely.  This is particularly important for
> +   network filesystems (e.g. NFS) or filesystems stored on
> +   media with a media-changing robot.
> +
> +2. The names and locations of filesystems can be stored in
> +   a remote database and can change at any time.  The content
> +   in that data base at the time of access will be used to provide
> +   a target for the access.  The interpretation of names in the
> +   filesystem can even be programatic rather than database-backed,

                             programmatic

> +   allowing wildcards for example, and can vary based on the user who
> +   first accessed a name.
> +
> +Context
> +-------
> +
> +The "autofs4" filesystem module is only one part of an autofs system.
> +There also needs to be a user-space program which looks up names
> +and mounts filesystems.  This will often be the "automount" program,
> +though other tools including "systemd" can make use of "autofs4".
> +This document describes only the kernel module and the interactions
> +required with any user-space program.  Subsequent text refers to this
> +as the "automount daemon" or simply "the daemon".
> +
> +"autofs4" is a Linux kernel module with provides the "autofs"
> +filesystem type.  Several "autofs" filesystems can be mounted and they
> +can each be managed separately, or all managed by the same daemon.
> +
> +Content
> +-------
> +
> +An autofs filesystem can contain 3 sorts of objects: directories,
> +symbolic links and mount traps.  Mount traps are directories with
> +extra properties as described in the next section.
> +
> +Objects can only be created by the automount daemon: symlinks are
> +created with a regular `symlink` systemcall, while directories and
> +mount traps are created with `mkdir`.  The determination of whether a
> +directory should be a mount trap or not is quite _ad hoc_, largely for
> +historical reasons, and is determined in part the

                                         in part by the

> +*direct*/*indirect*/*offset* mount options, and the *maxproto* mount option.
> +
> +If neither the *direct* or *offset* mount options are given (so the
> +mount is considered to be *indirect*), then the root directory is
> +always a regular directory, otherwise it is a mount trap when it is
> +empty and a regular directory when not empty.  Note that *direct* and
> +*offset* are treated identically so a concise summary is that the root
> +directory is a mount trap only if the filesystem is mounted *direct*
> +and the root is empty.
> +
> +Directories created in the root directory are mount traps only if the
> +filesystem is mounted  *indirect* and they are empty.
> +
> +Directories further down the tree depend on the *max_proto* mount

                                                    max_proto or maxproto?  or either?
check/fix other places also.

> +option and particularly whether it is less than five or not.
> +When *max_proto* is five, no directories further down the
> +tree are ever mount traps, they are always regular directories.  When
> +the *max_proto* is four (or three), these directories are mount traps
> +precisely when they are empty.
> +
> +So: non-empty (i.e. non-leaf) directories are never mount traps. Empty
> +directories are sometimes mount traps, and sometimes not depending on
> +where in the tree they are (root, top level, or lower) the *maxproto*,

                                                or lower), the

> +and whether the mount was *indirect* or not.
> +
> +Mount Traps
> +---------------
> +
> +A core element of the implementation of autofs is the Mount Traps
> +which are provided by the Linux VFS.  Any directory provided by a
> +filesystem can be designated as a trap.  This involves two separate
> +features that work together to allow autofs to do its job.
> +
> +**DCACHE_NEED_AUTOMOUNT**
> +
> +If a dentry has the DCACHE_NEED_AUTOMOUNT flag set (which gets set if
> +the inode has S_AUTOMOUNT set, or can be set directly) then it is
> +(potentially) a mount trap.  Any access to this directory beyond a
> +"`stat`" will (normally) cause the `d_op->d_automount()` dentry operation
> +to be called. The task of this method is to find the filesystem that
> +should be mounted on the directory and to return it.  The VFS is
> +responsibly for actually mounting the root of this filesystem on the

   responsible

> +directory.
> +
> +autofs doesn't find the filesystem itself but sends a message to the
> +automount daemon asking it to find and mount the filesystem.  The
> +autofs `d_automount` method then waits for the daemon to report that
> +everything is ready.  It will then return "`NULL`" indicating that the
> +mount has already happened.  The VFS doesn't try to mount anything but
> +follows down the mount that is already there.
> +
> +This functionality is sufficient for some users of mount traps such
> +as NFS which creates traps so that mountpoints on the server can be
> +reflected on the client.  However it is not sufficient for autofs.  As
> +mounting onto a directory is considered to be "beyond a `stat`", the
> +automount daemon would not be able to mount a filesystem on the 'trap'
> +directory without some way to avoid getting caught in the trap.  For
> +that purpose there is another flag.
> +
> +**DCACHE_MANAGE_TRANSIT**
> +
> +If a dentry has DCACHE_MANAGE_TRANSIT set then two very different but
> +related behaviors are invoked, both using the `d_op->d_manage()`
> +dentry operation.
> +
> +Firstly, before checking to see if any filesystem is mounted on the
> +directory, d_manage() will be called with the `rcu_walk` parameter set
> +to `false`.  It may return one of three things:
> +
> +-  A return value of zero indicates that there is nothing special
> +   about this dentry and normal checks for mounts and automounts
> +   should proceed.
> +
> +   autofs normally returns zero, but first waits for any
> +   expiry (automatic unmounting of the mounted filesystem) to
> +   complete.  This avoids races.
> +
> +-  A return value of `-EISDIR` tells the VFS to ignore any mounts
> +   on the directory and to not consider calling `->d_automount()`.
> +   This effectively disables the **DCACHE_NEED_AUTOMOUNT** flag
> +   causing the directory not be a mount trap after all.
> +
> +   autofs returns this if it detects that the process performing the
> +   lookup is the automount daemon and that the mount has been
> +   requested but has not yet completed.  How it determines this is
> +   discussed later.  This allows the automount daemon not to get
> +   caught in the mount trap.
> +
> +   There is a subtlety here.  It is possibly that a second autofs

                                       possible

> +   filesystem can be mounted below the first and for both of them to
> +   be managed by the same daemon.  For the daemon to be able to mount
> +   something on the second it must be able to "walk" down past the
> +   first.  This means that d_manage cannot *always* return -EISDIR for
> +   the automount daemon.  It must only return it when a mount has
> +   been requested, but has not yet completed.
> +
> +   `d_manage` also returns `-EISDIR` if the dentry shouldn't be a
> +   mount trap, either because it is a symbolic link or because it is
> +   not empty.
> +
> +-  Any other negative value is treated as an error and returned
> +   to the caller.
> +
> +   autofs can return
> +
> +   - -ENOENT if the automount daemon failed to mount anything,
> +   - -ENOMEM if it ran out of memory,
> +   - -EINTR if a signal arrived while waiting for expiry to
> +     complete
> +   - or any other error sent down by the automount daemon.
> +
> +
> +The second use case only occurs during an "RCU-walk" and so `rcu_walk`
> +will be set.
> +
> +An RCU-walk is a fast and light weight process for walking down a

                             lightweight

> +filename path (i.e. it is like running on tip-toes).  RCU-walk cannot
> +cope with all situations so when it finds a difficulty it falls back
> +to "REF-walk", which is slower but more robust.
> +
> +RCU-walk will never call `->d_automount`, the filesystems must already

                            `->d_automount`; the

> +be mounted or RCU-walk cannot handle the path.
> +To determine if a mount-trap is safe for RCU-walk mode it calls
> +`->d_manage()` with `rcu_walk` set to `true`.
> +
> +In this case `d_manage()` must avoid blocking and should avoid taking
> +spinlocks if at all possible.  Its sole purpose is to determine if it
> +would be safe to follow down into any mounted directory and the only
> +reason that it might not be is if an expiry of the mount is
> +underway.
> +
> +In the `rcu_walk` case, `d_manage()` cannot return -EISDIR to tell the
> +VFS that this is a directory that doesn't require d_automount.  If
> +`rcu_walk` sees a dentry with DCACHE_NEED_AUTOMOUNT set but nothing
> +mounted, it *will* fall back to REF-walk.  `d_manage()` cannot make the
> +VFS remain in RCU-walk mode, but can only tell it to get out of
> +RCU-walk mode by returning `-ECHILD`.
> +
> +So `d_manage()`, when called with `rcu_walk` set, should either return
> +-ECHILD if there is any reason to believe it is unsafe to end the
> +mounted filesystem, and otherwise should return 0.
> +
> +autofs will return `-ECHILD` if an expiry of the filesystem has been
> +initiated or is being considered, otherwise it returns 0.
> +
> +
> +Mountpoint expiry
> +-----------------
> +
> +The VFS has a mechansim for automatically expiring unused mounts,
> +much as it can expire any unused dentry information from the dcache.
> +This is guided by the MNT_SHRINKABLE flag.  This  only applies to
> +mounts that were created by `d_automount()` returning a filesystem to be
> +mounted.  As autofs doesn't return such a filesystem be leaves the

                                                        but ??

> +mounting to the automount daemon, it must involve the automount daemon
> +in unmounting as well.  This also means that autofs has more control
> +of expiry.
> +
> +The VFS also supports "expiry" of mounts using the MNT_EXPIRE flag to
> +the `umount` systemcall.  Unmounting with MNT_EXPIRE will fail unless

I would spell:  system call.

> +a previous attempt had been made, and the filesystem was been inactive

                                                        has

> +and untouched since that previous attempt.  autofs4 does not depend on
> +this but has its own internal tracking of whether filesystems were
> +recently used.  This allows individual names in the autofs directory
> +to expire separately.
> +
> +With version 4 of the protocol, the automount daemon can try to
> +unmount any filesystems mounted on the autofs filesystem or remove any
> +symbolic links or empty directories any time it likes.  If the unmount
> +or removal is successful the filesystem will be returned to the state
> +it was before the mount or creation, so that any access of the name
> +will trigger normal auto-mount processing.  In particlar, `rmdir` and
> +`unlink` do not leave negative entries in the dcache as a normal
> +filesystem would, so an attempt to access a recently-removed object is
> +passed to autofs for handling.
> +
> +With version 5, this is not safe except for unmounting from top-level
> +directories.  As lower-level directories are never mount traps, other
> +processes will see an empty directory as soon as the filesystem is
> +unmounted.  So it is generally safest to use the autofs expiry
> +protocol described below.
> +
> +Normally the daemon only wants to remove entries which haven't been
> +used for a while.  For this purpose autofs maintains a "`last_used`"
> +time stamp on each directory or symlink.  For symlinks it genuinely
> +does record the last time the symlink was "used" or followed to find
> +out where it points to.  For directories the field is a slight
> +misnomer.  It actually records the last time that autofs checked if
> +the directory or one of its descendents was busy and found that it
> +was.  This is just as useful and doesn't require updating the field so
> +often.
> +
> +The daemon is able to ask autofs if anything is due to be expired,
> +using an `ioctl` as discussed later.  For a *direct* mount, autofs
> +considers if the entire mount-tree can be unmounted or not.  For an
> +*indirect* mount, autofs considers each of the names in the top level
> +directory to determine if any of those can be unmounted and cleaned
> +up.
> +
> +There is an option with indirect mounts to consider each of the leaves
> +that has been mounted on instead of considering the top-level names.
> +This is intended for compatability with version 4 of autofs and should
> +be considered as deprecated.
> +
> +When autofs considers a directory it checks the `last_used` time and
> +compares it with the "timeout" value set when the filesystem was
> +mounted, though this check is ignored in some cases. It also checks if
> +the directory or anything below it is in use.  For symbolic links,
> +only the `last_used` time is ever considered.
> +
> +If both appear to support expiring the directory or symlink, an action
> +is taken.
> +
> +There are two ways to ask autofs to consider expiry.  The first is to
> +use the **AUTOFS_IOC_EXPIRE** ioctl.  This only works for indirect
> +mounts.  If it finds something in the root directory to expire it will
> +return the name of that thing.  Once a name has been returned the
> +automount daemon needs to unmount any filesystems mounted below the
> +name normally.  As described above, this is unsafe for non-toplevel
> +mounts in a version-5 autofs.  For this reason the current `automountd`
> +does not use this ioctl.
> +
> +The second mechanism uses either the **AUTOFS_DEV_IOCTL_EXPIRE_CMD** or
> +the **AUTOFS_IOC_EXPIRE_MULTI** ioctl.  This will work for both direct and
> +indirect mounts.  If it selects an object to expire, it will notify
> +the daemon using the notification mechanism described below.  This
> +will block until the daemon acknowledges the expiry notification.
> +This implies that the "`EXPIRE`" ioctl must be sent from a different
> +thread than the one which handles notification.
> +
> +While the ioctl is blocking, the entry is marked as "expiring" and
> +`d_manage` will block until the daemon affirms that the unmount has
> +completed (together with removing any directories that might have been
> +necessary), or has been aborted.
> +
> +Communicating with autofs: detecting the daemon
> +-----------------------------------------------
> +
> +There are several forms of communication between the automount daemon
> +and the filesystem.  As we have already seen, the daemon can create and
> +remove directories and symlinks using normal filesystem operations.
> +autofs knows whether a process requesting some operation is the daemon
> +or not based on it's process-group id number (see getpgid(1)).

                   its

> +
> +When an autofs filesystem it mounted the pgid of the mounting
> +processes is recorded unless that "pgrp=" option is given, in which

                                 the

> +case that number is recorded instead.  Any request arriving from a
> +process in that process group is considered to come from the daemon.
> +If the daemon ever has to be stopped and restarted a new pgid can be
> +provided through an ioctl as will be described below.
> +
> +Communicating with autofs: the event pipe
> +-----------------------------------------
> +
> +When an autofs filesystem is mounted, the 'write' end of a pipe must
> +be passed using the 'fd=' mount option.  autofs will write
> +notification messages to this pipe for the daemon to respond to.
> +For version 5, the format of the message is:
> +
> +	struct autofs_v5_packet {
> +		int proto_version;		/* Protocol version */
> +		int type;			/* Type of packet */
> +		autofs_wqt_t wait_queue_token;
> +		__u32 dev;
> +		__u64 ino;
> +		__u32 uid;
> +		__u32 gid;
> +		__u32 pid;
> +		__u32 tgid;
> +		__u32 len;
> +		char name[NAME_MAX+1];
> +	};
> +
> +where the type is one of
> +
> +	autofs_ptype_missing_indirect
> +	autofs_ptype_expire_indirect
> +	autofs_ptype_missing_direct
> +	autofs_ptype_expire_direct
> +
> +so messages can indicate that a name is missing (something tried to
> +access it but it isn't there) or that it has been selected for expiry.
> +
> +The pipe will be set to "packet mode" (equivalent to passing
> +`O_DIRECT`) to _pipe2(2)_ so that a read from the pipe will return at
> +most one packet, and any unread portion of a packet will be discarded.
> +
> +The `wait_queue_token` is a unique number which can identify a
> +particular request to be acknowledged.  When a message is sent over
> +the pipe the affected dentry is marked as either "active" or
> +"expiring" and other accesses to it block until the messages is

                                                       message

> +acknowledged using one of the ioctls below and the relevant
> +`wait_queue_token`.
> +
> +Communicating with autofs: root directory ioctls
> +------------------------------------------------
> +
> +The root directory of an autofs filesystem will respond to a number of
> +ioctls.   The process issuing the ioctl must have the CAP_SYS_ADMIN
> +capability, or must be the automount daemon.
> +
> +The available ioctl commands are:
> +
> +- **AUTOFS_IOC_READY**: a notification has been handled.  The argument
> +    to the ioctl command is the "wait_queue_token" number
> +    corresponding to the notification being acknowledged.
> +- **AUTOFS_IOC_FAIL**: similar to above, but indicates failure with
> +    the error code `ENOENT`.
> +- **AUTOFS_IOC_CATATONIC**: Causes the autofs to enter "catatonic"
> +    mode meaning that it stops sending notifications to the daemon.
> +    This mode is also entered if a write to the pipe fails.
> +- **AUTOFS_IOC_PROTOVER**:  This returns the protocol version in use.
> +- **AUTOFS_IOC_PROTOSUBVER**: Returns the protocol sub-version which
> +    is really a version number for the implementation.  It is
> +    currently 2.
> +- **AUTOFS_IOC_SETTIMEOUT**:  This passes a pointer to an unsigned
> +    long.  The value is used to set the timeout for expiry, and
> +    the current timeout value is stored back through the pointer.
> +- **AUTOFS_IOC_ASKUMOUNT**:  Returns, in the pointed-to `int`, 1 if
> +    the filesystem could be unmounted.  This is only a hint as
> +    the situation could change at any instant.  This call can be
> +    use to avoid a more expensive full unmount attempt.
> +- **AUTOFS_IOC_EXPIRE**: as described above, this asks if there is
> +    anything suitable to expire.  A pointer to a packet:
> +
> +        struct autofs_packet_expire_multi {
> +        	int proto_version;              /* Protocol version */
> +        	int type;                       /* Type of packet */
> +        	autofs_wqt_t wait_queue_token;
> +        	int len;
> +        	char name[NAME_MAX+1];
> +        };
> +
> +     is required.  This is filled in with the name of something
> +     that can be unmounted or removed.  If nothing can be expired,
> +     `errno` is set to `EAGAIN`.  Even though a `wait_queue_token`
> +     is present in the structure, not "wait queue" is established

                                     no

> +     and no acknowledgment is needed.
> +- **AUTOFS_IOC_EXPIRE_MULTI**:  This is similar to
> +     **AUTOFS_IOC_EXPIRE** except that it causes notification to be
> +     sent to the daemon, and it blocks until the daemon acknowledges.
> +     The argument is an integer which can contain two different flags.
> +
> +     **AUTOFS_EXP_IMMEDIATE** causes `last_used` time to be ignored
> +     and objects are expired if the are not in use.
> +
> +     **AUTOFS_EXP_LEAVES** will select a leaf rather than a top-level
> +     name to expire.  This is only safe when *maxproto* is 4.
> +
> +Communicating with autofs: char-device ioctls
> +---------------------------------------------
> +
> +It is not always possible to open the root of an autofs filesystem,
> +particularly a *direct* mounted filesystem.  If the automount daemon
> +is restarted there is no way for it to regain control of existing
> +mounts using any of the above communication channels.  To address this
> +need there is a "miscellaneous" character device (major 10, minor 235)
> +which can be used to communicate directly with the autofs filesystem.
> +It requires CAP_SYS_ADMIN for access.
> +
> +The `ioctl`s that can be used on this device a described in a separate

                                                are

> +document `autofs4-mount-control.txt`, and are summarized briefly here.
> +Each ioctl is passed a pointer to an `autofs_dev_ioctl` structure:
> +
> +	struct autofs_dev_ioctl {
> +		__u32 ver_major;
> +		__u32 ver_minor;
> +		__u32 size;             /* total size of data passed in
> +		                         * including this struct */
> +		__s32 ioctlfd;          /* automount command fd */
> +
> +		__u32 arg1;             /* Command parameters */
> +		__u32 arg2;
> +
> +		char path[0];
> +	};
> +
> +For the **OPEN_MOUNT** and **IS_MOUNTPOINT** commands, the target
> +filesystem is identified by the `path`.  All other commands identify
> +the filesystem by the `ioctlfd` which is a file descriptor open on the
> +root, and which can be returned by **OPEN_MOUNT**.
> +
> +The `ver_major` and `ver_minor` are in/out parameters which check that
> +the requested version is supported, and report the maximum version
> +that the kernel module can support.
> +
> +Commands are:
> +
> +- **AUTOFS_DEV_IOCTL_VERSION_CMD**: does nothing, except validate and
> +    set version numbers.
> +- **AUTOFS_DEV_IOCTL_OPENMOUNT_CMD**: return an open file descriptor
> +    on the root of an autofs filesystem.  The filesystem is identified
> +    by name a device number, which is stored in `arg1`.  Device

               and ??

> +    numbers for existing filesystems can be found in
> +    `/proc/self/mountinfo`.
> +- **AUTOFS_DEV_IOCTL_CLOSEMOUNT_CMD**: same as `close(ioctlfd)`.
> +- **AUTOFS_DEV_IOCTL_SETPIPEFD_CMD**: if the  filesystem is in
> +    catatonic mode, this can provide the write end of a new pipe
> +    in `arg1` to re-establish communication with a daemon.  The
> +    process group of the calling process is used to identify the
> +    daemon.
> +- **AUTOFS_DEV_IOCTL_REQUESTER_CMD**: `path` should be a
> +    name within the filesystem that as been auto-mounted on.

                                       has

> +    arg1 is the dev number of the underlying autofs.  On successful
> +    return, `arg1` and `arg2` will be the UID and GID of the process
> +    which triggered that mount.
> +
> +- **AUTOFS_DEV_IOCTL_ISMOUNTPOINT_CMD**: Check if path is a
> +    mountpoint of a particular type - see separate documentation for
> +    details.
> +
> +- **AUTOFS_DEV_IOCTL_PROTOVER_CMD**:
> +- **AUTOFS_DEV_IOCTL_PROTOSUBVER_CMD**:
> +- **AUTOFS_DEV_IOCTL_READY_CMD**:
> +- **AUTOFS_DEV_IOCTL_FAIL_CMD**:
> +- **AUTOFS_DEV_IOCTL_CATATONIC_CMD**:
> +- **AUTOFS_DEV_IOCTL_TIMEOUT_CMD**:
> +- **AUTOFS_DEV_IOCTL_EXPIRE_CMD**:
> +- **AUTOFS_DEV_IOCTL_ASKUMOUNT_CMD**:  These all have the same
> +    function as the similarly named **AUTOFS_IOC** ioctls, except
> +    that **FAIL** can be given an explicit error number in `arg1`
> +    instead of assuming `ENOENT`, and this **EXPIRE** command
> +    corresponds to **AUTOFS_IOC_EXPIRE_MULTI**.
> +
> +Catatonic mode
> +--------------
> +
> +As mentioned, an autofs mount can enter "catatonic" mode.  This
> +happens if a write to the notification pipe fails, or if it is
> +explicitly requested by an `ioctl`.
> +
> +When entering catatonic mode, the pipe is closed and any pending
> +notifications are acknowledged with the error `ENOENT`.
> +
> +Once in catatonic mode attempts to access non-existing names will
> +result in `ENOENT` while attempts to access existing directories will
> +be treated in the same way is if they came from the daemon, so mount

                              as

> +traps will not fire.
> +
> +When the filesystem is mounted a _uid_ and _gid_ can be given which
> +set the ownership of directories and symbolic links.  When the
> +filesystem is in catatonic mode, any process with a matching UID can
> +create directories or symlink in the root directory, but not in other

                         symlinks

> +directories.
> +
> +Catatonic mode can only be left via the
> +**AUTOFS_DEV_IOCTL_OPENMOUNT_CMD** ioctl on the `/dev/autofs`.
> 

Thanks.  Nice job.

-- 
~Randy
--
To unsubscribe from this list: send the line "unsubscribe autofs" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Linux Filesystem Development]     [Linux Ext4]     [Linux ARM Kernel]     [Linux ARM]     [Linux Omap]     [Fedora ARM]     [IETF Annouce]     [Security]     [Bugtraq]     [Linux]     [Linux OMAP]     [Linux MIPS]     [ECOS]     [Asterisk Internet PBX]     [Linux API]

  Powered by Linux