autofs4.txt 23.4 KB
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529
<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 programmatic rather than database-backed,
   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` system call, 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 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 *maxproto* mount
option and particularly whether it is less than five or not.
When *maxproto* is five, no directories further down the
tree are ever mount traps, they are always regular directories.  When
the *maxproto* 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*,
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
responsible for actually mounting the root of this filesystem on the
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 possible that a second autofs
   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 lightweight process for walking down a
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
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 mechanism 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 but leaves the
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` system call.  Unmounting with MNT_EXPIRE will fail unless
a previous attempt had been made, and the filesystem has been inactive
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 its process-group id number (see getpgid(1)).

When an autofs filesystem is mounted the pgid of the mounting
processes is recorded unless the "pgrp=" option is given, in which
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 message is
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, no "wait queue" is established
     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 are described in a separate
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 */

		/* Command parameters */
		union {
			struct args_protover		protover;
			struct args_protosubver		protosubver;
			struct args_openmount		openmount;
			struct args_ready		ready;
			struct args_fail		fail;
			struct args_setpipefd		setpipefd;
			struct args_timeout		timeout;
			struct args_requester		requester;
			struct args_expire		expire;
			struct args_askumount		askumount;
			struct args_ismountpoint	ismountpoint;
		};

                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 and device number, which is stored in `openmount.devid`.
    Device 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 `setpipefd.pipefd` 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 has been auto-mounted on.
    On successful return, `requester.uid` and `requester.gid` 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 `fail.status`
    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 as if they came from the daemon, so mount
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 symlinks in the root directory, but not in other
directories.

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

autofs, name spaces, and shared mounts
--------------------------------------

With bind mounts and name spaces it is possible for an autofs
filesystem to appear at multiple places in one or more filesystem
name spaces.  For this to work sensibly, the autofs filesystem should
always be mounted "shared". e.g.

> `mount --make-shared /autofs/mount/point`

The automount daemon is only able to manage a single mount location for
an autofs filesystem and if mounts on that are not 'shared', other
locations will not behave as expected.  In particular access to those
other locations will likely result in the `ELOOP` error

> Too many levels of symbolic links