diff options
Diffstat (limited to 'contrib/amd/amd/autil.c')
-rw-r--r-- | contrib/amd/amd/autil.c | 619 |
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; } |