summaryrefslogtreecommitdiffstats
path: root/contrib/amd/amd/amfs_toplvl.c
diff options
context:
space:
mode:
authorobrien <obrien@FreeBSD.org>2007-12-05 15:48:03 +0000
committerobrien <obrien@FreeBSD.org>2007-12-05 15:48:03 +0000
commitea691ecd980d2860f0b39e9e504de4da404806fd (patch)
treefa83b3bb0660890a21b550fa1f334b151bf098f9 /contrib/amd/amd/amfs_toplvl.c
parentc06a2e613662fc6ce10145b41762be8f8ab22ba4 (diff)
downloadFreeBSD-src-ea691ecd980d2860f0b39e9e504de4da404806fd.zip
FreeBSD-src-ea691ecd980d2860f0b39e9e504de4da404806fd.tar.gz
Virgin import of AMD (am-utils) v6.1.5
Sponsored by: Juniper Networks
Diffstat (limited to 'contrib/amd/amd/amfs_toplvl.c')
-rw-r--r--contrib/amd/amd/amfs_toplvl.c363
1 files changed, 161 insertions, 202 deletions
diff --git a/contrib/amd/amd/amfs_toplvl.c b/contrib/amd/amd/amfs_toplvl.c
index c0e7604..1b968f1 100644
--- a/contrib/amd/amd/amfs_toplvl.c
+++ b/contrib/amd/amd/amfs_toplvl.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997-2004 Erez Zadok
+ * Copyright (c) 1997-2006 Erez Zadok
* Copyright (c) 1990 Jan-Simon Pendry
* Copyright (c) 1990 Imperial College of Science, Technology & Medicine
* Copyright (c) 1990 The Regents of the University of California.
@@ -36,9 +36,8 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * %W% (Berkeley) %G%
*
- * $Id: amfs_toplvl.c,v 1.7.2.5 2004/01/06 03:15:16 ezk Exp $
+ * File: am-utils/amd/amfs_toplvl.c
*
*/
@@ -55,7 +54,7 @@
/****************************************************************************
*** FORWARD DEFINITIONS ***
****************************************************************************/
-
+static int amfs_toplvl_init(mntfs *mf);
/****************************************************************************
*** OPS STRUCTURES ***
@@ -63,19 +62,23 @@
am_ops amfs_toplvl_ops =
{
"toplvl",
- amfs_auto_match,
- 0, /* amfs_auto_init */
+ amfs_generic_match,
+ amfs_toplvl_init, /* amfs_toplvl_init */
amfs_toplvl_mount,
- 0,
amfs_toplvl_umount,
- 0,
- amfs_auto_lookuppn,
- amfs_auto_readdir, /* browsable version of readdir() */
+ amfs_generic_lookup_child,
+ amfs_generic_mount_child,
+ amfs_generic_readdir,
0, /* amfs_toplvl_readlink */
- amfs_toplvl_mounted,
+ amfs_generic_mounted,
0, /* amfs_toplvl_umounted */
- find_amfs_auto_srvr,
- FS_MKMNT | FS_NOTIMEOUT | FS_BACKGROUND | FS_AMQINFO | FS_DIRECTORY
+ amfs_generic_find_srvr,
+ 0, /* amfs_toplvl_get_wchan */
+ FS_MKMNT | FS_NOTIMEOUT | FS_BACKGROUND |
+ FS_AMQINFO | FS_DIRECTORY, /* nfs_fs_flags */
+#ifdef HAVE_FS_AUTOFS
+ AUTOFS_TOPLVL_FS_FLAGS,
+#endif /* HAVE_FS_AUTOFS */
};
@@ -83,166 +86,79 @@ am_ops amfs_toplvl_ops =
*** FUNCTIONS ***
****************************************************************************/
-/*
- * Mount an automounter directory.
- * The automounter is connected into the system
- * as a user-level NFS server. mount_amfs_toplvl constructs
- * the necessary NFS parameters to be given to the
- * kernel so that it will talk back to us.
- *
- * NOTE: automounter mounts in themselves are using NFS Version 2.
- */
-static int
-mount_amfs_toplvl(char *dir, char *opts)
+static void
+set_auto_attrcache_timeout(char *preopts, char *opts, size_t l)
{
- char fs_hostname[MAXHOSTNAMELEN + MAXPATHLEN + 1];
- int retry, error, genflags;
- mntent_t mnt;
- nfs_args_t nfs_args;
- am_nfs_fh *fhp;
- am_nfs_handle_t anh;
- MTYPE_TYPE type = MOUNT_TYPE_NFS;
-#ifndef HAVE_TRANSPORT_TYPE_TLI
- u_short port;
- struct sockaddr_in sin;
-#endif /* not HAVE_TRANSPORT_TYPE_TLI */
-
- memset((voidp) &mnt, 0, sizeof(mnt));
- mnt.mnt_dir = dir;
- mnt.mnt_fsname = pid_fsname;
- mnt.mnt_opts = opts;
-
- /*
- * Make sure that amd's top-level NFS mounts are hidden by default
- * from df.
- * If they don't appear to support the either the "ignore" mnttab
- * option entry, or the "auto" one, set the mount type to "nfs".
- */
- mnt.mnt_type = HIDE_MOUNT_TYPE;
-
- retry = hasmntval(&mnt, MNTTAB_OPT_RETRY);
- if (retry <= 0)
- retry = 2; /* XXX */
-
- /*
- * SET MOUNT ARGS
- */
- /*
- * get fhandle of remote path for automount point
- */
- fhp = root_fh(dir);
- if (!fhp) {
- plog(XLOG_FATAL, "Can't find root file handle for %s", dir);
- return EINVAL;
- }
-#ifndef HAVE_TRANSPORT_TYPE_TLI
+#ifdef MNTTAB_OPT_NOAC
/*
- * Create sockaddr to point to the local machine. 127.0.0.1
- * is not used since that will not work in HP-UX clusters and
- * this is no more expensive.
+ * Don't cache attributes - they are changing under the kernel's feet.
+ * For example, IRIX5.2 will dispense with nfs lookup calls and hand stale
+ * filehandles to getattr unless we disable attribute caching on the
+ * automount points.
*/
- memset((voidp) &sin, 0, sizeof(sin));
- sin.sin_family = AF_INET;
- sin.sin_addr = myipaddr;
- port = hasmntval(&mnt, MNTTAB_OPT_PORT);
- if (port) {
- sin.sin_port = htons(port);
- } else {
- plog(XLOG_ERROR, "no port number specified for %s", dir);
- return EINVAL;
+ if (gopt.auto_attrcache == 0) {
+ xsnprintf(preopts, l, ",%s", MNTTAB_OPT_NOAC);
+ xstrlcat(opts, preopts, l);
}
-#endif /* not HAVE_TRANSPORT_TYPE_TLI */
+#endif /* MNTTAB_OPT_NOAC */
/*
- * Make a ``hostname'' string for the kernel
- */
- sprintf(fs_hostname, "pid%ld@%s:%s",
- (long) (foreground ? am_mypid : getppid()),
- am_get_hostname(),
- dir);
- /*
- * Most kernels have a name length restriction (64 bytes)...
+ * XXX: note that setting these to 0 in the past resulted in an error on
+ * some systems, which is why it's better to use "noac" if possible. For
+ * now, we're setting everything possible, but if this will cause trouble,
+ * then we'll have to condition the remainder of this on OPT_NOAC.
*/
- if (strlen(fs_hostname) >= MAXHOSTNAMELEN)
- strcpy(fs_hostname + MAXHOSTNAMELEN - 3, "..");
-#ifdef HOSTNAMESZ
- /*
- * ... and some of these restrictions are 32 bytes (HOSTNAMESZ)
- * If you need to get the definition for HOSTNAMESZ found, you may
- * add the proper header file to the conf/nfs_prot/nfs_prot_*.h file.
- */
- if (strlen(fs_hostname) >= HOSTNAMESZ)
- strcpy(fs_hostname + HOSTNAMESZ - 3, "..");
-#endif /* HOSTNAMESZ */
+#ifdef MNTTAB_OPT_ACTIMEO
+ xsnprintf(preopts, l, ",%s=%d", MNTTAB_OPT_ACTIMEO, gopt.auto_attrcache);
+ xstrlcat(opts, preopts, l);
+#else /* MNTTAB_OPT_ACTIMEO */
+# ifdef MNTTAB_OPT_ACDIRMIN
+ xsnprintf(preopts, l, ",%s=%d", MNTTAB_OPT_ACTDIRMIN, gopt.auto_attrcache);
+ xstrlcat(opts, preopts, l);
+# endif /* MNTTAB_OPT_ACDIRMIN */
+# ifdef MNTTAB_OPT_ACDIRMAX
+ xsnprintf(preopts, l, ",%s=%d", MNTTAB_OPT_ACTDIRMAX, gopt.auto_attrcache);
+ xstrlcat(opts, preopts, l);
+# endif /* MNTTAB_OPT_ACDIRMAX */
+# ifdef MNTTAB_OPT_ACREGMIN
+ xsnprintf(preopts, l, ",%s=%d", MNTTAB_OPT_ACTREGMIN, gopt.auto_attrcache);
+ xstrlcat(opts, preopts, l);
+# endif /* MNTTAB_OPT_ACREGMIN */
+# ifdef MNTTAB_OPT_ACREGMAX
+ xsnprintf(preopts, l, ",%s=%d", MNTTAB_OPT_ACTREGMAX, gopt.auto_attrcache);
+ xstrlcat(opts, preopts, l);
+# endif /* MNTTAB_OPT_ACREGMAX */
+#endif /* MNTTAB_OPT_ACTIMEO */
+}
- /*
- * Finally we can compute the mount genflags set above,
- * and add any automounter specific flags.
- */
- genflags = compute_mount_flags(&mnt);
- genflags |= compute_automounter_mount_flags(&mnt);
- /* setup the many fields and flags within nfs_args */
- memmove(&anh.v2.fhs_fh, fhp, sizeof(*fhp));
-#ifdef HAVE_TRANSPORT_TYPE_TLI
- compute_nfs_args(&nfs_args,
- &mnt,
- genflags,
- nfsncp,
- NULL, /* remote host IP addr is set below */
- NFS_VERSION, /* version 2 */
- "udp",
- &anh,
- fs_hostname,
- pid_fsname);
- /*
- * IMPORTANT: set the correct IP address AFTERWARDS. It cannot
- * be done using the normal mechanism of compute_nfs_args(), because
- * that one will allocate a new address and use NFS_SA_DREF() to copy
- * parts to it, while assuming that the ip_addr passed is always
- * a "struct sockaddr_in". That assumption is incorrect on TLI systems,
- * because they define a special macro HOST_SELF which is DIFFERENT
- * than localhost (127.0.0.1)!
- */
- nfs_args.addr = &nfsxprt->xp_ltaddr;
-#else /* not HAVE_TRANSPORT_TYPE_TLI */
- compute_nfs_args(&nfs_args,
- &mnt,
- genflags,
- &sin,
- NFS_VERSION, /* version 2 */
- "udp",
- &anh,
- fs_hostname,
- pid_fsname);
-#endif /* not HAVE_TRANSPORT_TYPE_TLI */
-
- /*************************************************************************
- * NOTE: while compute_nfs_args() works ok for regular NFS mounts *
- * the toplvl one is not, and so some options must be corrected by hand *
- * more carefully, *after* compute_nfs_args() runs. *
- *************************************************************************/
- compute_automounter_nfs_args(&nfs_args, &mnt);
+/*
+ * Initialize a top-level mount. In our case, if the user asked for
+ * forced_unmounts, and the OS supports it, then we try forced/lazy unmounts
+ * on any previous toplvl mounts. This is useful if a previous Amd died and
+ * left behind toplvl mount points (this Amd will clean them up).
+ *
+ * WARNING: Don't use forced/lazy unmounts if you have another valid Amd
+ * running, because this code WILL force those valid toplvl mount points to
+ * be detached as well!
+ */
+static int
+amfs_toplvl_init(mntfs *mf)
+{
+ int error = 0;
- /* This is it! Here we try to mount amd on its mount points */
-#ifdef DEBUG
- amuDebug(D_TRACE) {
- print_nfs_args(&nfs_args, 0);
- plog(XLOG_DEBUG, "Generic mount flags 0x%x", genflags);
+#if defined(MNT2_GEN_OPT_FORCE) || defined(MNT2_GEN_OPT_DETACH)
+ if (gopt.flags & CFM_FORCED_UNMOUNTS) {
+ plog(XLOG_INFO, "amfs_toplvl_init: trying forced/lazy unmount of %s",
+ mf->mf_mount);
+ error = umount2_fs(mf->mf_mount, AMU_UMOUNT_FORCE | AMU_UMOUNT_DETACH);
+ if (error)
+ plog(XLOG_INFO, "amfs_toplvl_init: forced/lazy unmount failed: %m");
+ else
+ dlog("amfs_toplvl_init: forced/lazy unmount succeeded");
}
-#endif /* DEBUG */
- error = mount_fs(&mnt, genflags, (caddr_t) &nfs_args, retry, type,
- 0, NULL, mnttab_file_name);
-
-#ifdef HAVE_TRANSPORT_TYPE_TLI
- free_knetconfig(nfs_args.knconf);
- /*
- * local automounter mounts do not allocate a special address, so
- * no need to XFREE(nfs_args.addr) under TLI.
- */
-#endif /* HAVE_TRANSPORT_TYPE_TLI */
-
+#endif /* MNT2_GEN_OPT_FORCE || MNT2_GEN_OPT_DETACH */
return error;
}
@@ -251,13 +167,11 @@ mount_amfs_toplvl(char *dir, char *opts)
* Mount the top-level
*/
int
-amfs_toplvl_mount(am_node *mp)
+amfs_toplvl_mount(am_node *mp, mntfs *mf)
{
- mntfs *mf = mp->am_mnt;
struct stat stb;
- char opts[256], preopts[256];
+ char opts[SIZEOF_OPTS], preopts[SIZEOF_OPTS], toplvl_opts[40];
int error;
- char *mnttype;
/*
* Mounting the automounter.
@@ -271,16 +185,6 @@ amfs_toplvl_mount(am_node *mp)
plog(XLOG_WARNING, "%s is not a directory", mp->am_path);
return ENOTDIR;
}
- if (mf->mf_ops == &amfs_toplvl_ops)
- mnttype = "indirect";
- else if (mf->mf_ops == &amfs_direct_ops)
- mnttype = "direct";
-#ifdef HAVE_AMU_FS_UNION
- else if (mf->mf_ops == &amfs_union_ops)
- mnttype = "union";
-#endif /* HAVE_AMU_FS_UNION */
- else
- mnttype = "auto";
/*
* Construct some mount options:
@@ -288,49 +192,71 @@ amfs_toplvl_mount(am_node *mp)
* Tack on magic map=<mapname> option in mtab to emulate
* SunOS automounter behavior.
*/
- preopts[0] = '\0';
+
+#ifdef HAVE_FS_AUTOFS
+ if (mf->mf_flags & MFF_IS_AUTOFS) {
+ autofs_get_opts(opts, sizeof(opts), mp->am_autofs_fh);
+ } else
+#endif /* HAVE_FS_AUTOFS */
+ {
+ preopts[0] = '\0';
#ifdef MNTTAB_OPT_INTR
- strcat(preopts, MNTTAB_OPT_INTR);
- strcat(preopts, ",");
+ xstrlcat(preopts, MNTTAB_OPT_INTR, sizeof(preopts));
+ xstrlcat(preopts, ",", sizeof(preopts));
#endif /* MNTTAB_OPT_INTR */
#ifdef MNTTAB_OPT_IGNORE
- strcat(preopts, MNTTAB_OPT_IGNORE);
- strcat(preopts, ",");
+ xstrlcat(preopts, MNTTAB_OPT_IGNORE, sizeof(preopts));
+ xstrlcat(preopts, ",", sizeof(preopts));
#endif /* MNTTAB_OPT_IGNORE */
- sprintf(opts, "%s%s,%s=%d,%s=%d,%s=%d,%s,map=%s",
- preopts,
- MNTTAB_OPT_RW,
- MNTTAB_OPT_PORT, nfs_port,
- MNTTAB_OPT_TIMEO, gopt.amfs_auto_timeo,
- MNTTAB_OPT_RETRANS, gopt.amfs_auto_retrans,
- mnttype, mf->mf_info);
+ /* write most of the initial options + preopts */
+ xsnprintf(opts, sizeof(opts), "%s%s,%s=%d,%s,map=%s",
+ preopts,
+ MNTTAB_OPT_RW,
+ MNTTAB_OPT_PORT, nfs_port,
+ mf->mf_ops->fs_type, mf->mf_info);
+
+ /* process toplvl timeo/retrans options, if any */
+ if (gopt.amfs_auto_timeo[AMU_TYPE_TOPLVL] > 0) {
+ xsnprintf(toplvl_opts, sizeof(toplvl_opts), ",%s=%d",
+ MNTTAB_OPT_TIMEO, gopt.amfs_auto_timeo[AMU_TYPE_TOPLVL]);
+ xstrlcat(opts, toplvl_opts, sizeof(opts));
+ }
+ if (gopt.amfs_auto_retrans[AMU_TYPE_TOPLVL] > 0) {
+ xsnprintf(toplvl_opts, sizeof(toplvl_opts), ",%s=%d",
+ MNTTAB_OPT_RETRANS, gopt.amfs_auto_retrans[AMU_TYPE_TOPLVL]);
+ xstrlcat(opts, toplvl_opts, sizeof(opts));
+ }
+
+#ifdef MNTTAB_OPT_NOAC
+ if (gopt.auto_attrcache == 0) {
+ xstrlcat(opts, ",", sizeof(opts));
+ xstrlcat(opts, MNTTAB_OPT_NOAC, sizeof(opts));
+ } else
+#endif /* MNTTAB_OPT_NOAC */
+ set_auto_attrcache_timeout(preopts, opts, sizeof(preopts));
+ }
/* now do the mount */
- error = mount_amfs_toplvl(mf->mf_mount, opts);
+ error = amfs_mount(mp, mf, opts);
if (error) {
errno = error;
- plog(XLOG_FATAL, "amfs_toplvl_mount: mount_amfs_toplvl failed: %m");
+ plog(XLOG_FATAL, "amfs_toplvl_mount: amfs_mount failed: %m");
return error;
}
return 0;
}
-void
-amfs_toplvl_mounted(mntfs *mf)
-{
- amfs_auto_mkcacheref(mf);
-}
-
-
/*
* Unmount a top-level automount node
*/
int
-amfs_toplvl_umount(am_node *mp)
+amfs_toplvl_umount(am_node *mp, mntfs *mf)
{
- int error;
struct stat stb;
+ int unmount_flags = (mf->mf_flags & MFF_ON_AUTOFS) ? AMU_UMOUNT_AUTOFS : 0;
+ int error;
+ int count = 0; /* how many times did we try to unmount? */
again:
/*
@@ -345,15 +271,48 @@ again:
* actually fixed the problem - so simulate an ls -ld here.
*/
if (lstat(mp->am_path, &stb) < 0) {
-#ifdef DEBUG
+ error = errno;
dlog("lstat(%s): %m", mp->am_path);
-#endif /* DEBUG */
+ goto out;
}
- error = UMOUNT_FS(mp->am_path, mnttab_file_name);
+ if ((stb.st_mode & S_IFMT) != S_IFDIR) {
+ plog(XLOG_ERROR, "amfs_toplvl_umount: %s is not a directory, aborting.", mp->am_path);
+ error = ENOTDIR;
+ goto out;
+ }
+
+ error = UMOUNT_FS(mp->am_path, mnttab_file_name, unmount_flags);
if (error == EBUSY) {
+#ifdef HAVE_FS_AUTOFS
+ /*
+ * autofs mounts are "in place", so it is possible
+ * that we can't just unmount our mount points and go away.
+ * If that's the case, just give up.
+ */
+ if (mf->mf_flags & MFF_IS_AUTOFS)
+ return error;
+#endif /* HAVE_FS_AUTOFS */
plog(XLOG_WARNING, "amfs_toplvl_unmount retrying %s in 1s", mp->am_path);
- sleep(1); /* XXX */
+ count++;
+ sleep(1);
+ /*
+ * If user wants forced/lazy unmount semantics, then set those flags,
+ * but only after we've tried normal lstat/umount a few times --
+ * otherwise forced unmounts may hang this very same Amd (by preventing
+ * it from achieving a clean unmount).
+ */
+ if (gopt.flags & CFM_FORCED_UNMOUNTS) {
+ if (count == 5) { /* after 5 seconds, try MNT_FORCE */
+ dlog("enabling forced unmounts for toplvl node %s", mp->am_path);
+ unmount_flags |= AMU_UMOUNT_FORCE;
+ }
+ if (count == 10) { /* after 10 seconds, try MNT_DETACH */
+ dlog("enabling detached unmounts for toplvl node %s", mp->am_path);
+ unmount_flags |= AMU_UMOUNT_DETACH;
+ }
+ }
goto again;
}
+out:
return error;
}
OpenPOWER on IntegriCloud