summaryrefslogtreecommitdiffstats
path: root/contrib/amd/amd/autil.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/amd/amd/autil.c')
-rw-r--r--contrib/amd/amd/autil.c619
1 files changed, 487 insertions, 132 deletions
diff --git a/contrib/amd/amd/autil.c b/contrib/amd/amd/autil.c
index bb43918..a5ecd6d 100644
--- a/contrib/amd/amd/autil.c
+++ b/contrib/amd/amd/autil.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: autil.c,v 1.4.2.6 2004/01/06 03:15:16 ezk Exp $
+ * File: am-utils/amd/autil.c
*
*/
@@ -52,100 +51,49 @@
#include <am_defs.h>
#include <amd.h>
-int NumChild = 0; /* number of children of primary amd */
+int NumChildren = 0; /* number of children of primary amd */
static char invalid_keys[] = "\"'!;@ \t\n";
+/****************************************************************************
+ *** MACROS ***
+ ****************************************************************************/
+
#ifdef HAVE_TRANSPORT_TYPE_TLI
# define PARENT_USLEEP_TIME 100000 /* 0.1 seconds */
#endif /* HAVE_TRANSPORT_TYPE_TLI */
+/****************************************************************************
+ *** FORWARD DEFINITIONS ***
+ ****************************************************************************/
+static void domain_strip(char *otherdom, char *localdom);
+static int dofork(void);
+
+
+/****************************************************************************
+ *** FUNCTIONS ***
+ ****************************************************************************/
+
+/*
+ * Copy s into p, reallocating p if necessary
+ */
char *
strealloc(char *p, char *s)
{
- int len = strlen(s) + 1;
+ size_t len = strlen(s) + 1;
p = (char *) xrealloc((voidp) p, len);
- strcpy(p, s);
+ xstrlcpy(p, s, len);
#ifdef DEBUG_MEM
+# if defined(HAVE_MALLINFO) && defined(HAVE_MALLOC_VERIFY)
malloc_verify();
+# endif /* not defined(HAVE_MALLINFO) && defined(HAVE_MALLOC_VERIFY) */
#endif /* DEBUG_MEM */
return p;
}
-char **
-strsplit(char *s, int ch, int qc)
-{
- char **ivec;
- int ic = 0;
- int done = 0;
-
- ivec = (char **) xmalloc((ic + 1) * sizeof(char *));
-
- while (!done) {
- char *v;
-
- /*
- * skip to split char
- */
- while (*s && (ch == ' ' ? (isascii(*s) && isspace((int)*s)) : *s == ch))
- *s++ = '\0';
-
- /*
- * End of string?
- */
- if (!*s)
- break;
-
- /*
- * remember start of string
- */
- v = s;
-
- /*
- * skip to split char
- */
- while (*s && !(ch == ' ' ? (isascii(*s) && isspace((int)*s)) : *s == ch)) {
- if (*s++ == qc) {
- /*
- * Skip past string.
- */
- s++;
- while (*s && *s != qc)
- s++;
- if (*s == qc)
- s++;
- }
- }
-
- if (!*s)
- done = 1;
- *s++ = '\0';
-
- /*
- * save string in new ivec slot
- */
- ivec[ic++] = v;
- ivec = (char **) xrealloc((voidp) ivec, (ic + 1) * sizeof(char *));
-#ifdef DEBUG
- amuDebug(D_STR)
- plog(XLOG_DEBUG, "strsplit saved \"%s\"", v);
-#endif /* DEBUG */
- }
-
-#ifdef DEBUG
- amuDebug(D_STR)
- plog(XLOG_DEBUG, "strsplit saved a total of %d strings", ic);
-#endif /* DEBUG */
-
- ivec[ic] = 0;
-
- return ivec;
-}
-
-
/*
* Strip off the trailing part of a domain
* to produce a short-form domain relative
@@ -170,7 +118,8 @@ domain_strip(char *otherdom, char *localdom)
/*
- * Normalize a host name
+ * Normalize a host name: replace cnames with real names, and decide if to
+ * strip domain name or not.
*/
void
host_normalize(char **chp)
@@ -182,20 +131,18 @@ host_normalize(char **chp)
*/
if (gopt.flags & CFM_NORMALIZE_HOSTNAMES) {
struct hostent *hp;
- clock_valid = 0;
hp = gethostbyname(*chp);
if (hp && hp->h_addrtype == AF_INET) {
-#ifdef DEBUG
dlog("Hostname %s normalized to %s", *chp, hp->h_name);
-#endif /* DEBUG */
*chp = strealloc(*chp, (char *) hp->h_name);
}
}
- domain_strip(*chp, hostd);
+ if (gopt.flags & CFM_DOMAIN_STRIP) {
+ domain_strip(*chp, hostd);
+ }
}
-
/*
* Keys are not allowed to contain " ' ! or ; to avoid
* problems with macro expansions.
@@ -226,14 +173,20 @@ forcibly_timeout_mp(am_node *mp)
} else {
plog(XLOG_INFO, "\"%s\" forcibly timed out", mp->am_path);
mp->am_flags &= ~AMF_NOTIMEOUT;
- mp->am_ttl = clocktime();
+ mp->am_ttl = clocktime(NULL);
+ /*
+ * Force mtime update of parent dir, to prevent DNLC/dcache from caching
+ * the old entry, which could result in ESTALE errors, bad symlinks, and
+ * more.
+ */
+ clocktime(&mp->am_parent->am_fattr.na_mtime);
reschedule_timeout_mp();
}
}
void
-mf_mounted(mntfs *mf)
+mf_mounted(mntfs *mf, bool_t call_free_opts)
{
int quoted;
int wasmounted = mf->mf_flags & MFF_MOUNTED;
@@ -250,10 +203,33 @@ mf_mounted(mntfs *mf)
/*
* Do mounted callback
*/
- if (mf->mf_ops->mounted) {
- (*mf->mf_ops->mounted) (mf);
+ if (mf->mf_ops->mounted)
+ mf->mf_ops->mounted(mf);
+
+ /*
+ * Be careful when calling free_ops and XFREE here. Some pseudo file
+ * systems like nfsx call this function (mf_mounted), even though it
+ * would be called by the lower-level amd file system functions. nfsx
+ * needs to call this function because of the other actions it takes.
+ * So we pass a boolean from the caller (yes, not so clean workaround)
+ * to determine if we should free or not. If we're not freeing (often
+ * because we're called from a callback function), then just to be sure,
+ * we'll zero out the am_opts structure and set the pointer to NULL.
+ * The parent mntfs node owns this memory and is going to free it with a
+ * call to mf_mounted(mntfs,TRUE) (see comment in the am_mounted code).
+ */
+ if (call_free_opts) {
+ free_opts(mf->mf_fo); /* this free is needed to prevent leaks */
+ XFREE(mf->mf_fo); /* (also this one) */
+ } else {
+ memset(mf->mf_fo, 0, sizeof(am_opts));
+ mf->mf_fo = NULL;
}
- mf->mf_fo = 0;
+ }
+
+ if (mf->mf_flags & MFF_RESTART) {
+ mf->mf_flags &= ~MFF_RESTART;
+ dlog("Restarted filesystem %s, flags 0x%x", mf->mf_mount, mf->mf_flags);
}
/*
@@ -272,40 +248,61 @@ mf_mounted(mntfs *mf)
void
am_mounted(am_node *mp)
{
+ int notimeout = 0; /* assume normal timeouts initially */
mntfs *mf = mp->am_mnt;
- mf_mounted(mf);
+ /*
+ * This is the parent mntfs which does the mf->mf_fo (am_opts type), and
+ * we're passing TRUE here to tell mf_mounted to actually free the
+ * am_opts. See a related comment in mf_mounted().
+ */
+ mf_mounted(mf, TRUE);
+
+#ifdef HAVE_FS_AUTOFS
+ if (mf->mf_flags & MFF_IS_AUTOFS)
+ autofs_mounted(mp);
+#endif /* HAVE_FS_AUTOFS */
/*
* Patch up path for direct mounts
*/
- if (mp->am_parent && mp->am_parent->am_mnt->mf_ops == &amfs_direct_ops)
+ if (mp->am_parent && mp->am_parent->am_mnt->mf_fsflags & FS_DIRECT)
mp->am_path = str3cat(mp->am_path, mp->am_parent->am_path, "/", ".");
/*
- * Check whether this mount should be cached permanently
+ * Check whether this mount should be cached permanently or not,
+ * and handle user-requested timeouts.
*/
- if (mf->mf_ops->fs_flags & FS_NOTIMEOUT) {
+ /* first check if file system was set to never timeout */
+ if (mf->mf_fsflags & FS_NOTIMEOUT)
+ notimeout = 1;
+ /* next, alter that decision by map flags */
+ if (mf->mf_mopts) {
mntent_t mnt;
mnt.mnt_opts = mf->mf_mopts;
- if (mf->mf_mopts && hasmntopt(&mnt, "unmount"))
- mp->am_flags &= ~AMF_NOTIMEOUT;
+ /* umount option: user wants to unmount this entry */
+ if (amu_hasmntopt(&mnt, "unmount") || amu_hasmntopt(&mnt, "umount"))
+ notimeout = 0;
+ /* noumount option: user does NOT want to unmount this entry */
+ if (amu_hasmntopt(&mnt, "nounmount") || amu_hasmntopt(&mnt, "noumount"))
+ notimeout = 1;
+ /* utimeout=N option: user wants to unmount this option AND set timeout */
+ if ((mp->am_timeo = hasmntval(&mnt, "utimeout")) == 0)
+ mp->am_timeo = gopt.am_timeo; /* otherwise use default timeout */
else
- mp->am_flags |= AMF_NOTIMEOUT;
- } else if (mf->mf_mount[1] == '\0' && mf->mf_mount[0] == '/') {
+ notimeout = 0;
+ /* special case: don't try to unmount "/" (it can never succeed) */
+ if (mf->mf_mount[0] == '/' && mf->mf_mount[1] == '\0')
+ notimeout = 1;
+ }
+ /* finally set actual flags */
+ if (notimeout) {
mp->am_flags |= AMF_NOTIMEOUT;
+ plog(XLOG_INFO, "%s set to never timeout", mp->am_path);
} else {
- mntent_t mnt;
- if (mf->mf_mopts) {
- mnt.mnt_opts = mf->mf_mopts;
- if (hasmntopt(&mnt, "nounmount"))
- mp->am_flags |= AMF_NOTIMEOUT;
- if (hasmntopt(&mnt, "unmount"))
- mp->am_flags &= ~AMF_NOTIMEOUT;
- if ((mp->am_timeo = hasmntval(&mnt, "utimeout")) == 0)
- mp->am_timeo = gopt.am_timeo;
- }
+ mp->am_flags &= ~AMF_NOTIMEOUT;
+ plog(XLOG_INFO, "%s set to timeout in %d seconds", mp->am_path, mp->am_timeo);
}
/*
@@ -313,25 +310,38 @@ am_mounted(am_node *mp)
* compute the length of the returned string.
*/
if (mp->am_fattr.na_type == NFLNK)
- mp->am_fattr.na_size = strlen(mp->am_link ? mp->am_link : mp->am_mnt->mf_mount);
+ mp->am_fattr.na_size = strlen(mp->am_link ? mp->am_link : mf->mf_mount);
/*
- * Record mount time
+ * Record mount time, and update am_stats at the same time.
*/
- mp->am_fattr.na_mtime.nt_seconds = mp->am_stats.s_mtime = clocktime();
+ mp->am_stats.s_mtime = clocktime(&mp->am_fattr.na_mtime);
new_ttl(mp);
/*
- * Update mtime of parent node
+ * Update mtime of parent node (copying "struct nfstime" in '=' below)
*/
if (mp->am_parent && mp->am_parent->am_mnt)
- mp->am_parent->am_fattr.na_mtime.nt_seconds = mp->am_stats.s_mtime;
+ mp->am_parent->am_fattr.na_mtime = mp->am_fattr.na_mtime;
/*
- * Now, if we can, do a reply to our NFS client here
+ * This is ugly, but essentially unavoidable
+ * Sublinks must be treated separately as type==link
+ * when the base type is different.
+ */
+ if (mp->am_link && mf->mf_ops != &amfs_link_ops)
+ amfs_link_ops.mount_fs(mp, mf);
+
+ /*
+ * Now, if we can, do a reply to our client here
* to speed things up.
*/
- quick_reply(mp, 0);
+#ifdef HAVE_FS_AUTOFS
+ if (mp->am_flags & AMF_AUTOFS)
+ autofs_mount_succeeded(mp);
+ else
+#endif /* HAVE_FS_AUTOFS */
+ nfs_quick_reply(mp, 0);
/*
* Update stats
@@ -340,21 +350,303 @@ am_mounted(am_node *mp)
}
+/*
+ * Replace mount point with a reference to an error filesystem.
+ * The mount point (struct mntfs) is NOT discarded,
+ * the caller must do it if it wants to _before_ calling this function.
+ */
+void
+assign_error_mntfs(am_node *mp)
+{
+ int error;
+ dlog("assign_error_mntfs");
+ /*
+ * Save the old error code
+ */
+ error = mp->am_error;
+ if (error <= 0)
+ error = mp->am_mnt->mf_error;
+ /*
+ * Allocate a new error reference
+ */
+ mp->am_mnt = new_mntfs();
+ /*
+ * Put back the error code
+ */
+ mp->am_mnt->mf_error = error;
+ mp->am_mnt->mf_flags |= MFF_ERROR;
+ /*
+ * Zero the error in the mount point
+ */
+ mp->am_error = 0;
+}
+
+
+/*
+ * Build a new map cache for this node, or re-use
+ * an existing cache for the same map.
+ */
+void
+amfs_mkcacheref(mntfs *mf)
+{
+ char *cache;
+
+ if (mf->mf_fo && mf->mf_fo->opt_cache)
+ cache = mf->mf_fo->opt_cache;
+ else
+ cache = "none";
+ mf->mf_private = (opaque_t) mapc_find(mf->mf_info,
+ cache,
+ (mf->mf_fo ? mf->mf_fo->opt_maptype : NULL));
+ mf->mf_prfree = mapc_free;
+}
+
+
+/*
+ * Locate next node in sibling list which is mounted
+ * and is not an error node.
+ */
+am_node *
+next_nonerror_node(am_node *xp)
+{
+ mntfs *mf;
+
+ /*
+ * Bug report (7/12/89) from Rein Tollevik <rein@ifi.uio.no>
+ * Fixes a race condition when mounting direct automounts.
+ * Also fixes a problem when doing a readdir on a directory
+ * containing hung automounts.
+ */
+ while (xp &&
+ (!(mf = xp->am_mnt) || /* No mounted filesystem */
+ mf->mf_error != 0 || /* There was a mntfs error */
+ xp->am_error != 0 || /* There was a mount error */
+ !(mf->mf_flags & MFF_MOUNTED) || /* The fs is not mounted */
+ (mf->mf_server->fs_flags & FSF_DOWN)) /* The fs may be down */
+ )
+ xp = xp->am_osib;
+
+ return xp;
+}
+
+
+/*
+ * Mount an automounter directory.
+ * The automounter is connected into the system
+ * as a user-level NFS server. amfs_mount 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 (UDP).
+ *
+ * NEW: on certain systems, mounting can be done using the
+ * kernel-level automount (autofs) support. In that case,
+ * we don't need NFS at all here.
+ */
int
-mount_node(am_node *mp)
+amfs_mount(am_node *mp, mntfs *mf, char *opts)
{
- mntfs *mf = mp->am_mnt;
- int error = 0;
+ char fs_hostname[MAXHOSTNAMELEN + MAXPATHLEN + 1];
+ int retry, error = 0, genflags;
+ int on_autofs = mf->mf_flags & MFF_ON_AUTOFS;
+ char *dir = mf->mf_mount;
+ mntent_t mnt;
+ MTYPE_TYPE type;
+ int forced_unmount = 0; /* are we using forced unmounts? */
+
+ memset((voidp) &mnt, 0, sizeof(mnt));
+ mnt.mnt_dir = dir;
+ mnt.mnt_fsname = pid_fsname;
+ mnt.mnt_opts = opts;
+
+#ifdef HAVE_FS_AUTOFS
+ if (mf->mf_flags & MFF_IS_AUTOFS) {
+ type = MOUNT_TYPE_AUTOFS;
+ /*
+ * Make sure that amd's top-level autofs mounts are hidden by default
+ * from df.
+ * XXX: It works ok on Linux, might not work on other systems.
+ */
+ mnt.mnt_type = "autofs";
+ } else
+#endif /* HAVE_FS_AUTOFS */
+ {
+ type = MOUNT_TYPE_NFS;
+ /*
+ * 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;
+ }
- mf->mf_flags |= MFF_MOUNTING;
- error = (*mf->mf_ops->mount_fs) (mp);
+ retry = hasmntval(&mnt, MNTTAB_OPT_RETRY);
+ if (retry <= 0)
+ retry = 2; /* XXX: default to 2 retries */
- mf = mp->am_mnt;
- if (error >= 0)
- mf->mf_flags &= ~MFF_MOUNTING;
- if (!error && !(mf->mf_ops->fs_flags & FS_MBACKGROUND)) {
- /* ...but see ifs_mount */
- am_mounted(mp);
+ /*
+ * SET MOUNT ARGS
+ */
+
+ /*
+ * Make a ``hostname'' string for the kernel
+ */
+ xsnprintf(fs_hostname, sizeof(fs_hostname), "pid%ld@%s:%s",
+ get_server_pid(), am_get_hostname(), dir);
+ /*
+ * Most kernels have a name length restriction (64 bytes)...
+ */
+ if (strlen(fs_hostname) >= MAXHOSTNAMELEN)
+ xstrlcpy(fs_hostname + MAXHOSTNAMELEN - 3, "..",
+ sizeof(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)
+ xstrlcpy(fs_hostname + HOSTNAMESZ - 3, "..",
+ sizeof(fs_hostname) - HOSTNAMESZ + 3);
+#endif /* HOSTNAMESZ */
+
+ /*
+ * Finally we can compute the mount genflags set above,
+ * and add any automounter specific flags.
+ */
+ genflags = compute_mount_flags(&mnt);
+#ifdef HAVE_FS_AUTOFS
+ if (on_autofs)
+ genflags |= autofs_compute_mount_flags(&mnt);
+#endif /* HAVE_FS_AUTOFS */
+ genflags |= compute_automounter_mount_flags(&mnt);
+
+again:
+ if (!(mf->mf_flags & MFF_IS_AUTOFS)) {
+ nfs_args_t nfs_args;
+ am_nfs_fh *fhp;
+ am_nfs_handle_t anh;
+#ifndef HAVE_TRANSPORT_TYPE_TLI
+ u_short port;
+ struct sockaddr_in sin;
+#endif /* not HAVE_TRANSPORT_TYPE_TLI */
+
+ /*
+ * get fhandle of remote path for automount point
+ */
+ fhp = get_root_nfs_fh(dir);
+ if (!fhp) {
+ plog(XLOG_FATAL, "Can't find root file handle for %s", dir);
+ return EINVAL;
+ }
+
+#ifndef HAVE_TRANSPORT_TYPE_TLI
+ /*
+ * Create sockaddr to point to the local machine.
+ */
+ memset((voidp) &sin, 0, sizeof(sin));
+ /* as per POSIX, sin_len need not be set (used internally by kernel) */
+ 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;
+ }
+#endif /* not HAVE_TRANSPORT_TYPE_TLI */
+
+ /* setup the many fields and flags within nfs_args */
+ memmove(&anh.v2, 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,
+ NULL,
+ &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 quite regular, and so some options must be *
+ * corrected by hand more carefully, *after* compute_nfs_args() runs. *
+ *************************************************************************/
+ compute_automounter_nfs_args(&nfs_args, &mnt);
+
+ if (amuDebug(D_TRACE)) {
+ print_nfs_args(&nfs_args, 0);
+ plog(XLOG_DEBUG, "Generic mount flags 0x%x", genflags);
+ }
+
+ /* This is it! Here we try to mount amd on its mount points */
+ error = mount_fs(&mnt, genflags, (caddr_t) &nfs_args,
+ retry, type, 0, NULL, mnttab_file_name, on_autofs);
+
+#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 */
+
+#ifdef HAVE_FS_AUTOFS
+ } else {
+ /* This is it! Here we try to mount amd on its mount points */
+ error = mount_fs(&mnt, genflags, (caddr_t) mp->am_autofs_fh,
+ retry, type, 0, NULL, mnttab_file_name, on_autofs);
+#endif /* HAVE_FS_AUTOFS */
+ }
+ if (error == 0 || forced_unmount)
+ return error;
+
+ /*
+ * If user wants forced/lazy unmount semantics, then try it iff the
+ * current mount failed with EIO or ESTALE.
+ */
+ if (gopt.flags & CFM_FORCED_UNMOUNTS) {
+ switch (errno) {
+ case ESTALE:
+ case EIO:
+ forced_unmount = errno;
+ plog(XLOG_WARNING, "Mount %s failed (%m); force unmount.", mp->am_path);
+ if ((error = UMOUNT_FS(mp->am_path, mnttab_file_name,
+ AMU_UMOUNT_FORCE | AMU_UMOUNT_DETACH)) < 0) {
+ plog(XLOG_WARNING, "Forced umount %s failed: %m.", mp->am_path);
+ errno = forced_unmount;
+ } else
+ goto again;
+ default:
+ break;
+ }
}
return error;
@@ -373,15 +665,79 @@ am_unmounted(am_node *mp)
* Do unmounted callback
*/
if (mf->mf_ops->umounted)
- (*mf->mf_ops->umounted) (mp);
+ mf->mf_ops->umounted(mf);
+
+ /*
+ * This is ugly, but essentially unavoidable.
+ * Sublinks must be treated separately as type==link
+ * when the base type is different.
+ */
+ if (mp->am_link && mf->mf_ops != &amfs_link_ops)
+ amfs_link_ops.umount_fs(mp, mf);
+
+#ifdef HAVE_FS_AUTOFS
+ if (mf->mf_flags & MFF_IS_AUTOFS)
+ autofs_release_fh(mp);
+ if (mp->am_flags & AMF_AUTOFS)
+ autofs_umount_succeeded(mp);
+#endif /* HAVE_FS_AUTOFS */
+
+ /*
+ * Clean up any directories that were made
+ *
+ * If we remove the mount point of a pending mount, any queued access
+ * to it will fail. So don't do it in that case.
+ * Also don't do it if the refcount is > 1.
+ */
+ if (mf->mf_flags & MFF_MKMNT &&
+ mf->mf_refc == 1 &&
+ !(mp->am_flags & AMF_REMOUNT)) {
+ plog(XLOG_INFO, "removing mountpoint directory '%s'", mf->mf_mount);
+ rmdirs(mf->mf_mount);
+ mf->mf_flags &= ~MFF_MKMNT;
+ }
+
+ /*
+ * If this is a pseudo-directory then adjust the link count
+ * in the parent
+ */
+ if (mp->am_parent && mp->am_fattr.na_type == NFDIR)
+ --mp->am_parent->am_fattr.na_nlink;
/*
* Update mtime of parent node
*/
if (mp->am_parent && mp->am_parent->am_mnt)
- mp->am_parent->am_fattr.na_mtime.nt_seconds = clocktime();
-
- free_map(mp);
+ clocktime(&mp->am_parent->am_fattr.na_mtime);
+
+ if (mp->am_parent && (mp->am_flags & AMF_REMOUNT)) {
+ char *fname = strdup(mp->am_name);
+ am_node *mp_parent = mp->am_parent;
+ mntfs *mf_parent = mp_parent->am_mnt;
+ int error = 0;
+
+ free_map(mp);
+ plog(XLOG_INFO, "am_unmounted: remounting %s", fname);
+ mp = mf_parent->mf_ops->lookup_child(mp_parent, fname, &error, VLOOK_CREATE);
+ if (mp && error < 0)
+ mp = mf_parent->mf_ops->mount_child(mp, &error);
+ if (error > 0) {
+ errno = error;
+ plog(XLOG_ERROR, "am_unmounted: could not remount %s: %m", fname);
+ }
+ XFREE(fname);
+ } else
+ /*
+ * We have a race here.
+ * If this node has a pending mount and amd is going down (unmounting
+ * everything in the process), then we could potentially free it here
+ * while a struct continuation still has a reference to it. So when
+ * amfs_cont is called, it blows up.
+ * We avoid the race by refusing to free any nodes that have
+ * pending mounts (defined as having a non-NULL am_mfarray).
+ */
+ if (!mp->am_mfarray)
+ free_map(mp);
}
@@ -406,7 +762,7 @@ top:
am_set_mypid();
foreground = 0;
} else { /* parent process, has one more child */
- NumChild++;
+ NumChildren++;
}
return pid;
@@ -419,10 +775,9 @@ background(void)
int pid = dofork();
if (pid == 0) {
-#ifdef DEBUG
dlog("backgrounded");
-#endif /* DEBUG */
foreground = 0;
- }
+ } else
+ dlog("forked process %d", pid);
return pid;
}
OpenPOWER on IntegriCloud