1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  24  * Use is subject to license terms.
  25  */
  26 
  27 #ifndef _LX_AUTOFS_H
  28 #define _LX_AUTOFS_H
  29 
  30 #pragma ident   "%Z%%M% %I%     %E% SMI"
  31 
  32 /*
  33  * The lx_autofs filesystem exists to emulate the Linux autofs filesystem
  34  * and provide support for the Linux "automount" automounter.
  35  *
  36  *
  37  *
  38  * +++ Linux automounter background.
  39  *
  40  * Linux has two automounters: "amd" and "automount"
  41  *
  42  * 1) "amd" is a userland NFS server.  It basically mounts an NFS filesystem
  43  * at an automount point, and it acts as the NFS server for the mount.  When
  44  * an access is done to that NFS filesystem, the access is redirected by the
  45  * kernel to the "amd" process via rpc.  "amd" then looks up any information
  46  * required to resolve the requests, mounts real NFS filesystems if
  47  * necessary, and returns.  "amd" has it's own strange configuration
  48  * mechanism that doesn't seem to be very compatabile with Solaris's network
  49  * based automounter map support.
  50  *
  51  * 2) "automount" is the other Linux automounter.  It utilizes a kernel
  52  * filesystem (autofs) to provide it's functionality.  Basically, it mounts
  53  * the autofs filesystem at any automounter controlled mount point.  This
  54  * filesystem then intercepts and redirects lookup operations (and only
  55  * lookup ops) to the userland automounter process via a pipe.  (The
  56  * pipe to the automounter is establised via mount options when the autofs
  57  * filesystem is mounted.)  When the automounter recieves a request via this
  58  * pipe, it does lookups to whatever backing store it's configured to use,
  59  * does mkdir operations on the autofs filesystem, mounts remote NFS
  60  * filesystems on any leaf directories it just created, and signals the
  61  * autofs filesystem via an ioctl to let it know that the lookup can
  62  * continue.
  63  *
  64  *
  65  *
  66  * +++ Linux autofs (and automount daemon) notes
  67  *
  68  * Since we're mimicking the behavior of the Linux autofs filesystem it's
  69  * important to document some of it's observed behavior here since there's
  70  * no doubt that in the future this behavior will change.  These comments
  71  * apply to the behavior of the automounter as observed on a system
  72  * running Linux v2.4.21 (autofs is bundled with the Linux kernel).
  73  *
  74  * A) Autofs allows root owned, non-automounter processes to create
  75  * directories in the autofs filesystem.  The autofs filesystem treats the
  76  * automounter's process group as special, but it doesn't prevent root
  77  * processes outside of the automounter's process group from creating new
  78  * directories in the autofs filesystem.
  79  *
  80  * B) Autofs doesn't allow creation of any non-directory entries in the
  81  * autofs filesystem.  No entity can create files (e.g. /bin/touch or
  82  * VOP_CREATE/VOP_SYMLINK/etc.)  The only entries that can exist within
  83  * the autofs filesystem are directories.
  84  *
  85  * C) Autofs only intercepts vop lookup operations.  Notably, it does _not_
  86  * intercept and re-direct vop readdir operations.  This means that the
  87  * observed behavior of the Linux automounter can be considerably different
  88  * from that of the Solaris automounter.  Specifically, on Solaris if autofs
  89  * mount point is mounted _without_ the -nobrowse option then if a user does
  90  * an ls operation (which translates into a vop readdir operation) then the
  91  * automounter will intercept that operation and list all the possible
  92  * directories and mount points without actually mounting any filesystems.
  93  * Essentially, all automounter managed mount points on Linux will behave
  94  * like "-nobrowse" mount points on Solaris.  Here's an example to
  95  * illustrate this.  If /ws was mounted on Solaris without the -nobrowse
  96  * option and an auto_ws yp map was setup as the backing store for this
  97  * mount point, then an "ls /ws" would list all the keys in the map as
  98  * valid directories, but an "ls /ws" on Linux would list an emptry
  99  * directory.
 100  *
 101  * D) NFS mounts are performed by the automount process.  When the automount
 102  * process gets a redirected lookup request, it determines _all_ the
 103  * possible remote mount points for that request, creates directory paths
 104  * via mkdir, and mounts the remote filesystems on the newly created paths.
 105  * So for example, if a machine called mcescher exported /var/crash and
 106  * /var/core, an "ls /net/mcescher" would result in the following actions
 107  * being done by the automounter:
 108  *      mkdir /net/mcescher
 109  *      mkdir /net/mcescher/var
 110  *      mkdir /net/mcescher/var/crash
 111  *      mkdir /net/mcescher/var/core
 112  *      mount mcescher:/var/crash /var/crash
 113  *      mount mcescher:/var/crash /var/core
 114  * once the automounter compleated the work above it would signal the autofs
 115  * filesystem (via an ioctl) that the lookup could continue.
 116  *
 117  * E.1) Autofs only redirects vop lookup operations for path entries that
 118  * don't already exist in the autofs filesystem.  So for the example above,
 119  * an initial (after the start of the automounter) "ls /net/mcescher" would
 120  * result in a request to the automounter.  A subsequest "ls /net/mcescher"
 121  * would not result in a request to the automounter.  Even if
 122  * /net/mcescher/var/crash and /net/mcescher/var/core were manually unmounted
 123  * after the initial "ls /net/mcescher", a subsequest "ls /net/mcescher"
 124  * would not result in a new request to the automounter.
 125  *
 126  * E.2) Autofs lookup requests that are sent to the automounter only include
 127  * the root directory path component.  So for example, after starting up
 128  * the automounter if a user were to do a "ls /net/mcescher/var/crash", the
 129  * lookup request actually sent to the automounter would just be for
 130  * "mcescher".  (The same request as if the user had done "ls /net/mcescher".)
 131  *
 132  * E.3) The two statements above aren't entirely entirely true.  The Linux
 133  * autofs filesystem will also redirect lookup operations for leaf
 134  * directories that don't have a filesystem mounted on them.  Using the
 135  * example above, if a user did a "ls /net/mcescher", then manually
 136  * unmounted /net/mcescher/var/crash, and then did an "ls
 137  * /net/mcescher/var/crash", this would result in a request for
 138  * "mcescher/var/crash" being sent to the automounter.  The strange thing
 139  * (a Linux bug perhaps) is that the automounter won't do anything with this
 140  * request and the lookup will fail.
 141  *
 142  * F) The autofs filesystem communication protocol (what ioctls it supports
 143  * and what data it passes to the automount process) are versioned.  The
 144  * source for the userland automount daemon (i looked at version v3.1.7)
 145  * seemed to support two versions of the Linux kernel autofs implementation.
 146  * Both versions supported communiciation with a pipe and the format of the
 147  * structure passed via this pipe was the same.  The difference between the
 148  * two versions was in the functionality supported.  (The v3 version has
 149  * additional ioctls to support automount timeouts.)
 150  *
 151  *
 152  *
 153  * +++ lx_autofs notes
 154  *
 155  * 1) In general, the lx_autofs filesystem tries to mimic the behavior of the
 156  * Linux autofs filesystem with the following exceptions:
 157  *
 158  *      1.1) We don't bother to implement the E.3 functionality listed above
 159  *      since it doesn't appear to be of any use.
 160  *
 161  *      1.2) We only implement v2 of the automounter protocol since
 162  *      implementing v3 would take a _lot_ more work.  If this proves to be a
 163  *      problem we can re-visit this decision later.  (More details about v3
 164  *      support are included in comments below.)
 165  *
 166  * 2) In general, the approach taken for lx_autofs is to keep it as simple
 167  * as possible and to minimize it's memory usage.  To do this all information
 168  * about the contents of the lx_autofs filesystem are mirrored in the
 169  * underlying filesystem that lx_autofs is mounted on and most vop operations
 170  * are simply passed onto this underlying filesystem.  This means we don't
 171  * have to implement most the complex operations that a full filesystem
 172  * normally has to implement.  It also means that most of our filesystem state
 173  * (wrt the contents of the filesystem) doesn't actually have to be stored
 174  * in memory, we can simply go to the underlying filesystem to get it when
 175  * it's requested.  For the purposes of discussion, we'll call the underlying
 176  * filesystem the "backing store."
 177  *
 178  * The backing store is actually directory called ".lx_afs" which is created in
 179  * the directory where the lx_autofs filesystem is mounted.  When the lx_autofs
 180  * filesystem is unmounted this backing store directory is deleted.  If this
 181  * directory exists at mount time (perhaps the system crashed while a previous
 182  * lx_autofs instance was mounted at the same location) it will be deleted.
 183  * There are a few implications of using a backing store worth mentioning.
 184  *
 185  *      2.1) lx_autofs can't be mounted on a read only filesystem.  If this
 186  *      proves to be a problem we can probably move the location of the
 187  *      backing store.
 188  *
 189  *      2.2) If the backing store filesystem runs out of space then the
 190  *      automounter process won't be able to create more directories and mount
 191  *      new filesystems.  Of course, strange failures usually happen when
 192  *      filesystems run out of space.
 193  *
 194  * 3) Why aren't we using gfs?  gfs has two different usage models.
 195  *
 196  *      3.1) I'm my own filesystem but i'm using gfs to help with managing
 197  *      readdir operations.
 198  *
 199  *      3.2) I'm a gfs filesystem and gfs is managing all my vnodes
 200  *
 201  * We're not using the 3.1 interfaces because we don't implement readdir
 202  * ourselves.  We pass all readdir operations onto the backing store
 203  * filesystem and utilize its readdir implementation.
 204  *
 205  * We're not using the 3.2 interfaces because they are really designed for
 206  * in memory filesystems where all of the filesystem state is stored in
 207  * memory.  They don't lend themselves to filesystems where part of the
 208  * state is in memory and part of the state is on disk.
 209  *
 210  * For more information on gfs take a look at the block comments in the
 211  * top of gfs.c
 212  */
 213 
 214 #ifdef  __cplusplus
 215 extern "C" {
 216 #endif
 217 
 218 /*
 219  * Note that the name of the actual Solaris filesystem is lx_afs and not
 220  * lx_autofs.  This is becase filesystem names are stupidly limited to 8
 221  * characters.
 222  */
 223 #define LX_AUTOFS_NAME                  "lx_afs"
 224 
 225 /*
 226  * Mount options supported.
 227  */
 228 #define LX_MNTOPT_FD                    "fd"
 229 #define LX_MNTOPT_PGRP                  "pgrp"
 230 #define LX_MNTOPT_MINPROTO              "minproto"
 231 #define LX_MNTOPT_MAXPROTO              "maxproto"
 232 
 233 /* Version of the Linux kernel automount protocol we support. */
 234 #define LX_AUTOFS_PROTO_VERSION         2
 235 
 236 /*
 237  * Command structure sent to automount process from lx_autofs via a pipe.
 238  * This structure is the same for v2 and v3 of the automount protocol
 239  * (the communication pipe is established at mount time).
 240  */
 241 typedef struct lx_autofs_pkt {
 242         int     lap_protover;   /* protocol version number */
 243         int     lap_constant;   /* always set to 0 */
 244         int     lap_id;         /* every pkt must have a unique id */
 245         int     lap_name_len;   /* don't include newline or NULL */
 246         char    lap_name[256];  /* path component to lookup */
 247 } lx_autofs_pkt_t;
 248 
 249 /*
 250  * Ioctls supprted (v2 protocol).
 251  */
 252 #define LX_AUTOFS_IOC_READY             0x00009360 /* arg: int */
 253 #define LX_AUTOFS_IOC_FAIL              0x00009361 /* arg: int */
 254 #define LX_AUTOFS_IOC_CATATONIC         0x00009362 /* arg: <none> */
 255 
 256 /*
 257  * Ioctls not supported (v3 protocol).
 258  *
 259  * Initially we're only going to support v2 of the Linux kernel automount
 260  * protocol.  This means that we don't support the following ioctls.
 261  *
 262  * 1) The protocol version ioctl (by not supporting it the automounter
 263  * will assume version 2).
 264  *
 265  * 2) Automounter timeout ioctls.  For v3 and later the automounter can
 266  * be started with a timeout option.  It will notify the filesystem of
 267  * this timeout and, if any automounter filesystem root directory entry
 268  * is not in use, it will notify the automounter via the LX_AUTOFS_IOC_EXPIRE
 269  * ioctl.  For example, if the timeout is 60 seconds, the Linux
 270  * automounter will use the LX_AUTOFS_IOC_EXPIRE ioctl to query for
 271  * timeouts more often than that.  (v3.1.7 of the automount daemon would
 272  * perform this ioctl every <timeout>/4 seconds.)  Then, if the autofs
 273  * filesystem will
 274  * report top level directories that aren't in use to the automounter
 275  * via this ioctl.  If /net was managed by the automounter and
 276  * there were the following mount points:
 277  *      /net/jurassic/var/crash
 278  *      /net/mcescher/var/crash
 279  * and no one was looking at any crash dumps on mcescher but someone
 280  * was analyzing a crash dump on jurassic, then after <timeout> seconds
 281  * had passed the autofs filesystem would let the automounter know that
 282  * "mcescher" could be unmounted.  (Note the granularity of notification
 283  * is directories in the root of the autofs filesystem.)  Here's two
 284  * ideas for how this functionality could be implemented on Solaris:
 285  *
 286  * 2.1) The easy incomplete way.  Don't do any in-use detection.  Simply
 287  * tell the automounter it can try to unmount the filesystem every time
 288  * the specified timeout passes.  If the filesystem is in use then the
 289  * unmount will fail.  This would break down for remote hosts with multiple
 290  * mounts.  For example, if the automounter had mounted the following
 291  * filesystems:
 292  *      /net/jurassic/var/crash
 293  *      /net/jurassic/var/core
 294  * and the user was looking at a core file, and the timeout expired, the
 295  * automounter would recieve notification to unmount "jurassic".  Then
 296  * it would unmount crash (which would succeed) and then to try unmount
 297  * core (which would fail).  After that (since the automounter only
 298  * performs mounts for failed lookups in the root autofs directory)
 299  * future access to /net/jurassic/var/crash would result to access
 300  * to an empty autofs directory.  We might be able to work around
 301  * this by caching which root autofs directories we've timed out,
 302  * then any access to paths that contain those directories could be
 303  * stalled and we could resend another request to the automounter.
 304  * This could work if the automounter ignores mount failures.
 305  *
 306  * 2.2) The hard correct way.  The real difficulty here is detecting
 307  * files in use on other filesystems (say NFS) that have been mounted
 308  * on top of autofs.  (Detecting in use autofs vnodes should be easy.)
 309  * to do this we would probably have to create a new brand op to intercept
 310  * mount/umount filesystem operations.  Then using this entry point we
 311  * could detect mounts of other filesystems on top of lx_autofs.  When
 312  * a successful mount finishes we would use the FEM (file event
 313  * monitoring) framework to push a module onto that filesystem and
 314  * intercept VOP operations that allocate/free vnodes in that filesystem.
 315  * (We would also then have to track mount operations on top of that
 316  * filesystem, etc.)  this would allow us to properly detect any
 317  * usage of subdirectories of an autofs directory.
 318  */
 319 #define LX_AUTOFS_IOC_PROTOVER          0x80049363 /* arg: int */
 320 #define LX_AUTOFS_IOC_EXPIRE            0x81109365 /* arg: lx_autofs_expire * */
 321 #define LX_AUTOFS_IOC_SETTIMEOUT        0xc0049364 /* arg: ulong_t */
 322 
 323 typedef struct lx_autofs_expire {
 324         int     lap_protover;   /* protol version number */
 325         int     lap_constant;   /* always set to 1 */
 326         int     lap_name_len;   /* don't include newline or NULL */
 327         char    lap_name[256];  /* path component that has timed out */
 328 } lx_autofs_expire_t;
 329 
 330 #ifdef  __cplusplus
 331 }
 332 #endif
 333 
 334 #endif  /* _LX_AUTOFS_H */