/* * Free a mount node. * The node must be already unmounted. */ void free_map(am_node *mp) { remove_am(mp); if (mp->am_link) XFREE(mp->am_link); if (mp->am_name) XFREE(mp->am_name); if (mp->am_path) XFREE(mp->am_path); if (mp->am_pref) XFREE(mp->am_pref); if (mp->am_transp) XFREE(mp->am_transp); if (mp->am_mnt) free_mntfs(mp->am_mnt); if (mp->am_mfarray) { mntfs **temp_mf; for (temp_mf = mp->am_mfarray; *temp_mf; temp_mf++) free_mntfs(*temp_mf); XFREE(mp->am_mfarray); } #ifdef HAVE_FS_AUTOFS if (mp->am_autofs_fh) autofs_release_fh(mp); #endif /* HAVE_FS_AUTOFS */ exported_ap_free(mp); }
/* * Construct top-level node */ void make_root_node(void) { mntfs *root_mnt; char *rootmap = ROOT_MAP; root_node = exported_ap_alloc(); /* * Allocate a new map */ init_map(root_node, ""); /* * Allocate a new mounted filesystem */ root_mnt = find_mntfs(&amfs_root_ops, (am_opts *) 0, "", rootmap, "", "", ""); /* * Replace the initial null reference */ free_mntfs(root_node->am_mnt); root_node->am_mnt = root_mnt; /* * Initialize the root */ if (root_mnt->mf_ops->fs_init) (*root_mnt->mf_ops->fs_init) (root_mnt); /* * Mount the root */ root_mnt->mf_error = root_mnt->mf_ops->mount_fs(root_node, root_mnt); }
am_node * amfs_generic_mount_child(am_node *new_mp, int *error_return) { int error; struct continuation *cp; /* Continuation structure if need to mount */ dlog("in amfs_generic_mount_child"); *error_return = error = 0; /* Error so far */ /* we have an errorfs attached to the am_node, free it */ free_mntfs(new_mp->am_mnt); new_mp->am_mnt = 0; /* * Construct a continuation */ cp = ALLOC(struct continuation); cp->callout = 0; cp->mp = new_mp; cp->retry = TRUE; cp->start = clocktime(NULL); cp->mf = new_mp->am_mfarray; /* * Try and mount the file system. If this succeeds immediately (possible * for a ufs file system) then return the attributes, otherwise just * return an error. */ error = amfs_bgmount(cp); reschedule_timeout_mp(); if (!error) return new_mp; /* * Code for quick reply. If current_transp is set, then it's the * transp that's been passed down from nfs_program_2() or from * autofs_program_[123](). * If new_mp->am_transp is not already set, set it by copying in * current_transp. Once am_transp is set, nfs_quick_reply() and * autofs_mount_succeeded() can use it to send a reply to the * client that requested this mount. */ if (current_transp && !new_mp->am_transp) { dlog("Saving RPC transport for %s", new_mp->am_path); new_mp->am_transp = (SVCXPRT *) xmalloc(sizeof(SVCXPRT)); *(new_mp->am_transp) = *current_transp; } if (error && (new_mp->am_mnt->mf_ops == &amfs_error_ops)) new_mp->am_error = error; if (new_mp->am_error > 0) assign_error_mntfs(new_mp); ereturn(error); }
static void nfsx_cont(int rc, int term, void *closure) { mntfs *mf = (mntfs *) closure; struct nfsx *nx = (struct nfsx *) mf->mf_private; nfsx_mnt *n = nx->nx_try; n->n_mnt->mf_flags &= ~(MFF_ERROR|MFF_MOUNTING); mf->mf_flags &= ~MFF_ERROR; /* * Wakeup anything waiting for this mount */ wakeup(n->n_mnt); if (rc || term) { if (term) { /* * Not sure what to do for an error code. */ plog(XLOG_ERROR, "mount for %s got signal %d", n->n_mnt->mf_mount, term); n->n_error = EIO; } else { /* * Check for exit status */ errno = rc; /* XXX */ plog(XLOG_ERROR, "%s: mount (nfsx_cont): %m", n->n_mnt->mf_mount); n->n_error = rc; } free_mntfs(n->n_mnt); n->n_mnt = new_mntfs(); n->n_mnt->mf_error = n->n_error; n->n_mnt->mf_flags |= MFF_ERROR; } else { /* * The mount worked. */ mf_mounted(n->n_mnt); n->n_error = 0; } /* * Do the remaining bits */ if (nfsx_fmount(mf) >= 0) { wakeup(mf); mf->mf_flags &= ~MFF_MOUNTING; mf_mounted(mf); } }
static void amfs_nfsx_prfree(opaque_t vp) { struct amfs_nfsx *nx = (struct amfs_nfsx *) vp; int i; for (i = 0; i < nx->nx_c; i++) { mntfs *m = nx->nx_v[i].n_mnt; if (m) free_mntfs(m); } XFREE(nx->nx_v); XFREE(nx); }
static void nfsx_prfree(void *vp) { struct nfsx *nx = (struct nfsx *) vp; int i; for (i = 0; i < nx->nx_c; i++) { mntfs *m = nx->nx_v[i].n_mnt; if (m) free_mntfs(m); } free(nx->nx_v); free(nx); }
/* * Discard an old continuation */ static void free_continuation(struct continuation *cp) { mntfs **mfp; dlog("free_continuation"); if (cp->callout) untimeout(cp->callout); /* * we must free the mntfs's in the list. * so free all of them if there was an error, * or free all but the used one, if the mount succeeded. */ for (mfp = cp->mp->am_mfarray; *mfp; mfp++) { free_mntfs(*mfp); } XFREE(cp->mp->am_mfarray); cp->mp->am_mfarray = 0; XFREE(cp); }
/* * Handle an amd restart. * * Scan through the mount list finding all "interesting" mount points. * Next hack up partial data structures and add the mounted file * system to the list of known filesystems. This will leave a * dangling reference to that filesystems, so when the filesystem is * finally inherited, an extra "free" must be done on it. * * This module relies on internal details of other components. If * you change something else make *sure* restart() still works. */ void restart(void) { /* * Read the existing mount table */ mntlist *ml, *mlp; /* * For each entry, find nfs, ufs or auto mounts * and create a partial am_node to represent it. */ for (mlp = ml = read_mtab("restart", mnttab_file_name); mlp; mlp = mlp->mnext) { mntent_t *me = mlp->mnt; am_ops *fs_ops = 0; if (STREQ(me->mnt_type, MNTTAB_TYPE_UFS)) { /* * UFS entry */ fs_ops = &ufs_ops; } else if (STREQ(me->mnt_type, MNTTAB_TYPE_NFS)) { /* * NFS entry, or possibly an Amd entry... * The mnt_fsname for daemon mount points is * host:(pidXXX) * or (seen on Solaris) * host:daemon(pidXXX) */ char *colon = strchr(me->mnt_fsname, ':'); if (colon && strstr(colon, "(pid")) { plog(XLOG_WARNING, "%s is an existing automount point", me->mnt_dir); fs_ops = &amfs_link_ops; } else { fs_ops = &nfs_ops; } #ifdef MNTTAB_TYPE_NFS3 } else if (STREQ(me->mnt_type, MNTTAB_TYPE_NFS3)) { fs_ops = &nfs_ops; #endif /* MNTTAB_TYPE_NFS3 */ #ifdef MNTTAB_TYPE_LOFS } else if (STREQ(me->mnt_type, MNTTAB_TYPE_LOFS)) { fs_ops = &lofs_ops; #endif /* MNTTAB_TYPE_LOFS */ #ifdef MNTTAB_TYPE_CDFS } else if (STREQ(me->mnt_type, MNTTAB_TYPE_CDFS)) { fs_ops = &cdfs_ops; #endif /* MNTTAB_TYPE_CDFS */ #ifdef MNTTAB_TYPE_PCFS } else if (STREQ(me->mnt_type, MNTTAB_TYPE_PCFS)) { fs_ops = &pcfs_ops; #endif /* MNTTAB_TYPE_PCFS */ #ifdef MNTTAB_TYPE_MFS } else if (STREQ(me->mnt_type, MNTTAB_TYPE_MFS)) { /* * MFS entry. Fake with a symlink. */ fs_ops = &amfs_link_ops; #endif /* MNTTAB_TYPE_MFS */ } else { /* * Catch everything else with symlinks to * avoid recursive mounts. This is debatable... */ fs_ops = &amfs_link_ops; } /* * If we found something to do */ if (fs_ops) { mntfs *mf; am_opts mo; char *cp; cp = strchr(me->mnt_fsname, ':'); /* * Partially fake up an opts structure */ memset(&mo, 0, sizeof(mo)); mo.opt_rhost = 0; mo.opt_rfs = 0; if (cp) { *cp = '\0'; mo.opt_rhost = strdup(me->mnt_fsname); mo.opt_rfs = strdup(cp + 1); *cp = ':'; } else if (fs_ops->ffserver == find_nfs_srvr) { /* * Prototype 4.4 BSD used to end up here - * might as well keep the workaround for now */ plog(XLOG_WARNING, "NFS server entry assumed to be %s:/", me->mnt_fsname); mo.opt_rhost = strdup(me->mnt_fsname); mo.opt_rfs = strdup("/"); me->mnt_fsname = str3cat(me->mnt_fsname, mo.opt_rhost, ":", "/"); } mo.opt_fs = me->mnt_dir; mo.opt_opts = me->mnt_opts; /* * Make a new mounted filesystem */ mf = find_mntfs(fs_ops, &mo, me->mnt_dir, me->mnt_fsname, "", me->mnt_opts, ""); if (mf->mf_refc == 1) { mf->mf_flags |= MFF_RESTART | MFF_MOUNTED; mf->mf_error = 0; /* Already mounted correctly */ mf->mf_fo = 0; /* * If the restarted type is a link then * don't time out. */ if (fs_ops == &amfs_link_ops || fs_ops == &ufs_ops) mf->mf_flags |= MFF_RSTKEEP; if (fs_ops->fs_init) { /* * Don't care whether this worked since * it is checked again when the fs is * inherited. */ (void) (*fs_ops->fs_init) (mf); } plog(XLOG_INFO, "%s restarted fstype %s on %s", me->mnt_fsname, fs_ops->fs_type, me->mnt_dir); } else { /* Something strange happened - two mounts at the same place! */ free_mntfs(mf); } /* * Clean up mo */ if (mo.opt_rhost) XFREE(mo.opt_rhost); if (mo.opt_rfs) XFREE(mo.opt_rfs); } } /* * Free the mount list */ free_mntlist(ml); }
static am_loc * amfs_lookup_one_location(am_node *new_mp, mntfs *mf, char *ivec, char *def_opts, char *pfname) { am_ops *p; am_opts *fs_opts; am_loc *new_al; mntfs *new_mf; char *mp_dir = NULL; #ifdef HAVE_FS_AUTOFS int on_autofs = 1; #endif /* HAVE_FS_AUTOFS */ /* match the operators */ /* * although we alloc the fs_opts here, the pointer is 'owned' by the am_loc and will * be free'd on destruction of the am_loc. If we don't allocate a loc, then we need * to free this. */ fs_opts = CALLOC(am_opts); p = ops_match(fs_opts, ivec, def_opts, new_mp->am_path, pfname, mf->mf_info); #ifdef HAVE_FS_AUTOFS /* XXX: this should be factored out into an autofs-specific function */ if (new_mp->am_flags & AMF_AUTOFS) { /* ignore user-provided fs if we're using autofs */ if (fs_opts->opt_sublink && fs_opts->opt_sublink[0]) { /* * For sublinks we need to use a hack with autofs: * mount the filesystem on the original opt_fs (which is NOT an * autofs mountpoint) and symlink (or lofs-mount) to it from * the autofs mountpoint. */ on_autofs = 0; mp_dir = fs_opts->opt_fs; } else { if (p->autofs_fs_flags & FS_ON_AUTOFS) { mp_dir = new_mp->am_path; } else { mp_dir = fs_opts->opt_fs; on_autofs = 0; } } } else #endif /* HAVE_FS_AUTOFS */ mp_dir = fs_opts->opt_fs; /* * Find or allocate a filesystem for this node. * we search for a matching backend share, since * we will construct our own al_loc to handle * any customisations for this usage. */ new_mf = find_mntfs(p, fs_opts, mp_dir, fs_opts->fs_mtab, def_opts, fs_opts->opt_opts, fs_opts->opt_remopts); /* * See whether this is a real filesystem */ p = new_mf->mf_ops; if (p == &amfs_error_ops) { plog(XLOG_MAP, "Map entry %s for %s did not match", ivec, new_mp->am_path); free_mntfs(new_mf); free_opts(fs_opts); XFREE(fs_opts); return NULL; } dlog("Got a hit with %s", p->fs_type); new_al = new_loc(); free_mntfs(new_al->al_mnt); new_al->al_mnt = new_mf; new_al->al_fo = fs_opts; /* now the loc is in charge of free'ing this mem */ #ifdef HAVE_FS_AUTOFS if (new_mp->am_flags & AMF_AUTOFS && on_autofs) { new_mf->mf_flags |= MFF_ON_AUTOFS; new_mf->mf_fsflags = new_mf->mf_ops->autofs_fs_flags; } /* * A new filesystem is an autofs filesystems if: * 1. it claims it can be one (has the FS_AUTOFS flag) * 2. autofs is enabled system-wide * 3. either has an autofs parent, * or it is explicitly requested to be autofs. */ if (new_mf->mf_ops->autofs_fs_flags & FS_AUTOFS && amd_use_autofs && ((mf->mf_flags & MFF_IS_AUTOFS) || (new_mf->mf_fo && new_mf->mf_fo->opt_mount_type && STREQ(new_mf->mf_fo->opt_mount_type, "autofs")))) new_mf->mf_flags |= MFF_IS_AUTOFS; #endif /* HAVE_FS_AUTOFS */ return new_al; }
/* * Pick a file system to try mounting and * do that in the background if necessary * For each location: discard previous mount location if required fetch next mount location if the filesystem failed to be mounted then this_error = error from filesystem goto failed if the filesystem is mounting or unmounting then goto retry; if the fileserver is down then this_error = EIO continue; if the filesystem is already mounted break fi this_error = initialize mount point if no error on this mount and mount is delayed then this_error = -1 fi if this_error < 0 then retry = true fi if no error on this mount then if mount in background then run mount in background return -1 else this_error = mount in foreground fi fi if an error occurred on this mount then update stats save error in mount point fi endfor */ static int amfs_bgmount(struct continuation *cp) { am_node *mp = cp->mp; mntfs *mf; /* Current mntfs */ int this_error = -1; /* Per-mount error */ int hard_error = -1; /* Cumulative per-node error */ if (mp->am_mnt) free_mntfs(mp->am_mnt); /* * Try to mount each location. * At the end: * hard_error == 0 indicates something was mounted. * hard_error > 0 indicates everything failed with a hard error * hard_error < 0 indicates nothing could be mounted now */ for (mp->am_mnt = *cp->mf; *cp->mf; cp->mf++, mp->am_mnt = *cp->mf) { am_ops *p; mf = dup_mntfs(mp->am_mnt); p = mf->mf_ops; if (hard_error < 0) hard_error = this_error; this_error = 0; if (mf->mf_error > 0) { this_error = mf->mf_error; goto failed; } if (mf->mf_flags & (MFF_MOUNTING | MFF_UNMOUNTING)) { /* * Still mounting - retry later */ dlog("mount of \"%s\" already pending", mf->mf_info); goto retry; } if (FSRV_ISDOWN(mf->mf_server)) { /* * Would just mount from the same place * as a hung mount - so give up */ dlog("%s is already hung - giving up", mf->mf_server->fs_host); this_error = EIO; goto failed; } if (mp->am_link) { XFREE(mp->am_link); mp->am_link = NULL; } if (mf->mf_fo && mf->mf_fo->opt_sublink) mp->am_link = strdup(mf->mf_fo->opt_sublink); /* * Will usually need to play around with the mount nodes * file attribute structure. This must be done here. * Try and get things initialized, even if the fileserver * is not known to be up. In the common case this will * progress things faster. */ /* * Fill in attribute fields. */ if (mf->mf_fsflags & FS_DIRECTORY) mk_fattr(&mp->am_fattr, NFDIR); else mk_fattr(&mp->am_fattr, NFLNK); if (mf->mf_flags & MFF_MOUNTED) { dlog("duplicate mount of \"%s\" ...", mf->mf_info); /* * Skip initial processing of the mountpoint if already mounted. * This could happen if we have multiple sublinks into the same f/s, * or if we are restarting an already-mounted filesystem. */ goto already_mounted; } if (mf->mf_fo && mf->mf_fo->fs_mtab) { plog(XLOG_MAP, "Trying mount of %s on %s fstype %s mount_type %s", mf->mf_fo->fs_mtab, mf->mf_mount, p->fs_type, mp->am_flags & AMF_AUTOFS ? "autofs" : "non-autofs"); } if (p->fs_init && !(mf->mf_flags & MFF_RESTART)) this_error = p->fs_init(mf); if (this_error > 0) goto failed; if (this_error < 0) goto retry; if (mf->mf_fo && mf->mf_fo->opt_delay) { /* * If there is a delay timer on the mount * then don't try to mount if the timer * has not expired. */ int i = atoi(mf->mf_fo->opt_delay); time_t now = clocktime(NULL); if (i > 0 && now < (cp->start + i)) { dlog("Mount of %s delayed by %lds", mf->mf_mount, (long) (i - now + cp->start)); goto retry; } } /* * If the directory is not yet made and it needs to be made, then make it! */ if (!(mf->mf_flags & MFF_MKMNT) && mf->mf_fsflags & FS_MKMNT) { plog(XLOG_INFO, "creating mountpoint directory '%s'", mf->mf_mount); this_error = mkdirs(mf->mf_mount, 0555); if (this_error) { plog(XLOG_ERROR, "mkdirs failed: %s", strerror(this_error)); goto failed; } mf->mf_flags |= MFF_MKMNT; } #ifdef HAVE_FS_AUTOFS if (mf->mf_flags & MFF_IS_AUTOFS) if ((this_error = autofs_get_fh(mp))) goto failed; #endif /* HAVE_FS_AUTOFS */ already_mounted: mf->mf_flags |= MFF_MOUNTING; if (mf->mf_fsflags & FS_MBACKGROUND) { dlog("backgrounding mount of \"%s\"", mf->mf_mount); if (cp->callout) { untimeout(cp->callout); cp->callout = 0; } /* actually run the task, backgrounding as necessary */ run_task(mount_node, (opaque_t) mp, amfs_cont, (opaque_t) cp); return -1; } else { dlog("foreground mount of \"%s\" ...", mf->mf_mount); this_error = mount_node((opaque_t) mp); } mf->mf_flags &= ~MFF_MOUNTING; if (this_error > 0) goto failed; if (this_error == 0) { am_mounted(mp); break; /* Success */ } retry: if (!cp->retry) continue; dlog("will retry ...\n"); /* * Arrange that amfs_bgmount is called * after anything else happens. */ dlog("Arranging to retry mount of %s", mp->am_path); sched_task(amfs_retry, (opaque_t) cp, get_mntfs_wchan(mf)); if (cp->callout) untimeout(cp->callout); cp->callout = timeout(RETRY_INTERVAL, wakeup, (opaque_t) get_mntfs_wchan(mf)); mp->am_ttl = clocktime(NULL) + RETRY_INTERVAL; /* * Not done yet - so don't return anything */ return -1; failed: amd_stats.d_merr++; mf->mf_error = this_error; mf->mf_flags |= MFF_ERROR; #ifdef HAVE_FS_AUTOFS if (mp->am_autofs_fh) autofs_release_fh(mp); #endif /* HAVE_FS_AUTOFS */ if (mf->mf_flags & MFF_MKMNT) { rmdirs(mf->mf_mount); mf->mf_flags &= ~MFF_MKMNT; } /* * Wakeup anything waiting for this mount */ wakeup(get_mntfs_wchan(mf)); free_mntfs(mf); /* continue */ } /* * If we get here, then either the mount succeeded or * there is no more mount information available. */ if (this_error) { mp->am_mnt = mf = new_mntfs(); #ifdef HAVE_FS_AUTOFS if (mp->am_flags & AMF_AUTOFS) autofs_mount_failed(mp); else #endif /* HAVE_FS_AUTOFS */ nfs_quick_reply(mp, this_error); if (hard_error <= 0) hard_error = this_error; if (hard_error < 0) hard_error = ETIMEDOUT; /* * Set a small(ish) timeout on an error node if * the error was not a time out. */ switch (hard_error) { case ETIMEDOUT: case EWOULDBLOCK: case EIO: mp->am_timeo = 17; break; default: mp->am_timeo = 5; break; } new_ttl(mp); } else { mf = mp->am_mnt; /* * Wakeup anything waiting for this mount */ wakeup(get_mntfs_wchan(mf)); hard_error = 0; } /* * Make sure that the error value in the mntfs has a * reasonable value. */ if (mf->mf_error < 0) { mf->mf_error = hard_error; if (hard_error) mf->mf_flags |= MFF_ERROR; } /* * In any case we don't need the continuation any more */ free_continuation(cp); return hard_error; }
static mntfs * amfs_lookup_one_mntfs(am_node *new_mp, mntfs *mf, char *ivec, char *def_opts, char *pfname) { am_ops *p; am_opts *fs_opts; mntfs *new_mf; char *mp_dir = 0; #ifdef HAVE_FS_AUTOFS int on_autofs = 1; #endif /* HAVE_FS_AUTOFS */ /* match the operators */ fs_opts = CALLOC(am_opts); p = ops_match(fs_opts, ivec, def_opts, new_mp->am_path, pfname, mf->mf_info); #ifdef HAVE_FS_AUTOFS /* XXX: this should be factored out into an autofs-specific function */ if (new_mp->am_flags & AMF_AUTOFS) { /* ignore user-provided fs if we're using autofs */ if (fs_opts->opt_sublink) { /* * For sublinks we need to use a hack with autofs: * mount the filesystem on the original opt_fs (which is NOT an * autofs mountpoint) and symlink (or lofs-mount) to it from * the autofs mountpoint. */ on_autofs = 0; mp_dir = fs_opts->opt_fs; } else { if (p->autofs_fs_flags & FS_ON_AUTOFS) { mp_dir = new_mp->am_path; } else { mp_dir = fs_opts->opt_fs; on_autofs = 0; } } } else #endif /* HAVE_FS_AUTOFS */ mp_dir = fs_opts->opt_fs; /* * Find or allocate a filesystem for this node. */ new_mf = find_mntfs(p, fs_opts, mp_dir, fs_opts->fs_mtab, def_opts, fs_opts->opt_opts, fs_opts->opt_remopts); /* * See whether this is a real filesystem */ p = new_mf->mf_ops; if (p == &amfs_error_ops) { plog(XLOG_MAP, "Map entry %s for %s did not match", ivec, new_mp->am_path); free_mntfs(new_mf); return NULL; } dlog("Got a hit with %s", p->fs_type); #ifdef HAVE_FS_AUTOFS if (new_mp->am_flags & AMF_AUTOFS && on_autofs) { new_mf->mf_flags |= MFF_ON_AUTOFS; new_mf->mf_fsflags = new_mf->mf_ops->autofs_fs_flags; } /* * A new filesystem is an autofs filesystems if: * 1. it claims it can be one (has the FS_AUTOFS flag) * 2. autofs is enabled system-wide * 3. either has an autofs parent, * or it is explicitly requested to be autofs. */ if (new_mf->mf_ops->autofs_fs_flags & FS_AUTOFS && amd_use_autofs && ((mf->mf_flags & MFF_IS_AUTOFS) || (new_mf->mf_fo && new_mf->mf_fo->opt_mount_type && STREQ(new_mf->mf_fo->opt_mount_type, "autofs")))) new_mf->mf_flags |= MFF_IS_AUTOFS; #endif /* HAVE_FS_AUTOFS */ return new_mf; }
/* * Automount interface to RPC lookup routine * Find the corresponding entry and return * the file handle for it. */ am_node * amfs_generic_lookup_child(am_node *mp, char *fname, int *error_return, int op) { am_node *new_mp; mntfs **mf_array; int mp_error; dlog("in amfs_generic_lookup_child"); *error_return = 0; new_mp = amfs_lookup_node(mp, fname, error_return); /* return if we got an error */ if (!new_mp || *error_return > 0) return new_mp; /* also return if it's already mounted and known to be up */ if (*error_return == 0 && FSRV_ISUP(new_mp->am_mnt->mf_server)) return new_mp; switch (op) { case VLOOK_DELETE: /* * If doing a delete then don't create again! */ ereturn(ENOENT); case VLOOK_LOOKUP: return new_mp; } /* save error_return */ mp_error = *error_return; mf_array = amfs_lookup_mntfs(new_mp, error_return); if (!mf_array) { new_mp->am_error = new_mp->am_mnt->mf_error = *error_return; free_map(new_mp); return NULL; } /* * Already mounted but known to be down: * check if we have any alternatives to mount */ if (mp_error == 0) { mntfs **mfp; for (mfp = mf_array; *mfp; mfp++) if (*mfp != new_mp->am_mnt) break; if (*mfp != NULL) { /* * we found an alternative, so try mounting again. */ *error_return = -1; } else { for (mfp = mf_array; *mfp; mfp++) free_mntfs(*mfp); XFREE(mf_array); if (new_mp->am_flags & AMF_SOFTLOOKUP) { ereturn(EIO); } else { *error_return = 0; return new_mp; } } } /* store the array inside the am_node */ new_mp->am_mfarray = mf_array; /* * Note: while it might seem like a good idea to prioritize * the list of mntfs's we got here, it probably isn't. * It would ignore the ordering of entries specified by the user, * which is counterintuitive and confusing. */ return new_mp; }
static void restart_fake_mntfs(mntent_t *me, am_ops *fs_ops) { mntfs *mf; am_opts mo; char *cp; /* * Partially fake up an opts structure */ memset(&mo, 0, sizeof(mo)); mo.opt_rhost = NULL; mo.opt_rfs = NULL; cp = strchr(me->mnt_fsname, ':'); if (cp) { *cp = '\0'; mo.opt_rhost = xstrdup(me->mnt_fsname); mo.opt_rfs = xstrdup(cp + 1); *cp = ':'; } else if (STREQ(me->mnt_type, MNTTAB_TYPE_NFS)) { /* * Hacky workaround for mnttab NFS entries that only list the server */ plog(XLOG_WARNING, "NFS server entry assumed to be %s:/", me->mnt_fsname); mo.opt_rhost = xstrdup(me->mnt_fsname); mo.opt_rfs = xstrdup("/"); me->mnt_fsname = str3cat(me->mnt_fsname, mo.opt_rhost, ":", "/"); } mo.opt_fs = me->mnt_dir; mo.opt_opts = me->mnt_opts; /* * Make a new mounted filesystem */ mf = find_mntfs(fs_ops, &mo, me->mnt_dir, me->mnt_fsname, "", me->mnt_opts, ""); if (mf->mf_refc == 1) { mf->mf_flags |= MFF_RESTART | MFF_MOUNTED; mf->mf_error = 0; /* Already mounted correctly */ /* * Only timeout non-NFS entries */ if (!STREQ(me->mnt_type, MNTTAB_TYPE_NFS)) mf->mf_flags |= MFF_RSTKEEP; if (fs_ops->fs_init) { /* * Don't care whether this worked since * it is checked again when the fs is * inherited. */ (void) (*fs_ops->fs_init) (mf); } plog(XLOG_INFO, "%s restarted fstype %s on %s, flags 0x%x", me->mnt_fsname, fs_ops->fs_type, me->mnt_dir, mf->mf_flags); } else { /* Something strange happened - two mounts at the same place! */ free_mntfs(mf); } /* * Clean up mo */ XFREE(mo.opt_rhost); XFREE(mo.opt_rfs); }
/* * Unmount an NFS hierarchy. * Note that this is called in the foreground * and so may hang under extremely rare conditions. */ static int nfsx_fumount(mntfs *mf) { struct nfsx *nx = (struct nfsx *) mf->mf_private; nfsx_mnt *n; int glob_error = 0; /* * Iterate in reverse through the mntfs's and unmount each filesystem * which is mounted. */ for (n = nx->nx_v + nx->nx_c - 1; n >= nx->nx_v; --n) { mntfs *m = n->n_mnt; /* * If this node has not been messed with * and there has been no error so far * then try and unmount. * If an error had occured then zero * the error code so that the remount * only tries to unmount those nodes * which had been successfully unmounted. */ if (n->n_error == 0) { #ifdef DEBUG dlog("calling underlying fumount on %s", m->mf_mount); #endif n->n_error = (*m->mf_ops->fumount_fs)(m); if (n->n_error) { glob_error = n->n_error; n->n_error = 0; } else { /* * Make sure remount gets this node */ n->n_error = -1; } } } /* * If any unmounts failed then remount the * whole lot... */ if (glob_error) { glob_error = nfsx_remount(mf, TRUE); if (glob_error) { errno = glob_error; /* XXX */ plog(XLOG_USER, "nfsx: remount of %s failed: %m", mf->mf_mount); } glob_error = EBUSY; } else { /* * Remove all the mount points */ for (n = nx->nx_v; n < nx->nx_v + nx->nx_c; n++) { mntfs *m = n->n_mnt; if (n->n_error < 0) { if (m->mf_ops->fs_flags & FS_MKMNT) { (void) rmdirs(m->mf_mount); m->mf_flags &= ~MFF_MKMNT; } } free_mntfs(m); n->n_mnt = 0; n->n_error = -1; } } return glob_error; }