diff options
Diffstat (limited to 'amd/amfs_generic.c')
-rw-r--r-- | amd/amfs_generic.c | 243 |
1 files changed, 118 insertions, 125 deletions
diff --git a/amd/amfs_generic.c b/amd/amfs_generic.c index 0d5996969cf87..25d734bbde009 100644 --- a/amd/amfs_generic.c +++ b/amd/amfs_generic.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997-2006 Erez Zadok + * Copyright (c) 1997-2014 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. @@ -16,11 +16,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgment: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * @@ -55,7 +51,7 @@ /**************************************************************************** *** MACROS *** ****************************************************************************/ -#define IN_PROGRESS(cp) ((cp)->mp->am_mnt->mf_flags & MFF_MOUNTING) +#define IN_PROGRESS(cp) ((cp)->mp->am_al->al_mnt->mf_flags & MFF_MOUNTING) /**************************************************************************** @@ -80,7 +76,7 @@ struct continuation { int retry; /* Try again? */ time_t start; /* Time we started this mount */ int callout; /* Callout identifier */ - mntfs **mf; /* Current mntfs */ + am_loc **al; /* Current location */ }; @@ -88,9 +84,9 @@ struct continuation { *** FORWARD DEFINITIONS *** ****************************************************************************/ static am_node *amfs_lookup_node(am_node *mp, char *fname, int *error_return); -static mntfs *amfs_lookup_one_mntfs(am_node *new_mp, mntfs *mf, char *ivec, +static am_loc *amfs_lookup_one_location(am_node *new_mp, mntfs *mf, char *ivec, char *def_opts, char *pfname); -static mntfs **amfs_lookup_mntfs(am_node *new_mp, int *error_return); +static am_loc **amfs_lookup_loc(am_node *new_mp, int *error_return); static void amfs_cont(int rc, int term, opaque_t arg); static void amfs_retry(int rc, int term, opaque_t arg); static void free_continuation(struct continuation *cp); @@ -108,7 +104,7 @@ amfs_lookup_node(am_node *mp, char *fname, int *error_return) int error = 0; /* Error so far */ int in_progress = 0; /* # of (un)mount in progress */ mntfs *mf; - char *expanded_fname = 0; + char *expanded_fname = NULL; dlog("in amfs_lookup_node"); @@ -118,7 +114,7 @@ amfs_lookup_node(am_node *mp, char *fname, int *error_return) * about the mount point. */ if (amd_state == Finishing) { - if (mp->am_mnt == 0 || mp->am_mnt->mf_fsflags & FS_DIRECT) { + if (mp->am_al == NULL || mp->am_al->al_mnt == NULL || mp->am_al->al_mnt->mf_fsflags & FS_DIRECT) { dlog("%s mount ignored - going down", fname); } else { dlog("%s/%s mount ignored - going down", mp->am_path, fname); @@ -170,7 +166,7 @@ amfs_lookup_node(am_node *mp, char *fname, int *error_return) * If the error code is undefined then it must be * in progress. */ - mf = new_mp->am_mnt; + mf = new_mp->am_al->al_mnt; if (mf->mf_error < 0) goto in_progrss; @@ -240,7 +236,7 @@ amfs_lookup_node(am_node *mp, char *fname, int *error_return) */ new_mp = get_ap_child(mp, expanded_fname); XFREE(expanded_fname); - if (new_mp == 0) + if (new_mp == NULL) ereturn(ENOSPC); *error_return = -1; @@ -249,19 +245,25 @@ amfs_lookup_node(am_node *mp, char *fname, int *error_return) -static mntfs * -amfs_lookup_one_mntfs(am_node *new_mp, mntfs *mf, char *ivec, - char *def_opts, char *pfname) +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 = 0; + 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); @@ -269,7 +271,7 @@ amfs_lookup_one_mntfs(am_node *new_mp, mntfs *mf, char *ivec, /* 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) { + 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 @@ -292,6 +294,9 @@ amfs_lookup_one_mntfs(am_node *new_mp, mntfs *mf, char *ivec, /* * 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, @@ -300,6 +305,7 @@ amfs_lookup_one_mntfs(am_node *new_mp, mntfs *mf, char *ivec, fs_opts->opt_opts, fs_opts->opt_remopts); + /* * See whether this is a real filesystem */ @@ -307,10 +313,16 @@ amfs_lookup_one_mntfs(am_node *new_mp, mntfs *mf, char *ivec, 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) { @@ -332,12 +344,12 @@ amfs_lookup_one_mntfs(am_node *new_mp, mntfs *mf, char *ivec, new_mf->mf_flags |= MFF_IS_AUTOFS; #endif /* HAVE_FS_AUTOFS */ - return new_mf; + return new_al; } -static mntfs ** -amfs_lookup_mntfs(am_node *new_mp, int *error_return) +static am_loc ** +amfs_lookup_loc(am_node *new_mp, int *error_return) { am_node *mp; char *info; /* Mount info - where to get the file system */ @@ -348,10 +360,11 @@ amfs_lookup_mntfs(am_node *new_mp, int *error_return) int error = 0; /* Error so far */ char path_name[MAXPATHLEN]; /* General path name buffer */ char *pfname; /* Path for database lookup */ - mntfs *mf, **mf_array; + mntfs* mf; /* The mntfs for the map of our parent */ + am_loc **al_array; /* the generated list of locations */ int count; - dlog("in amfs_lookup_mntfs"); + dlog("in amfs_lookup_loc"); mp = new_mp->am_parent; @@ -369,7 +382,7 @@ amfs_lookup_mntfs(am_node *new_mp, int *error_return) pfname = new_mp->am_name; } - mf = mp->am_mnt; + mf = mp->am_al->al_mnt; dlog("will search map info in %s to find %s", mf->mf_info, pfname); /* @@ -404,8 +417,8 @@ amfs_lookup_mntfs(am_node *new_mp, int *error_return) else def_opts = ""; - orig_def_opts = amfs_parse_defaults(mp, mf, strdup(def_opts)); - def_opts = strdup(orig_def_opts); + orig_def_opts = amfs_parse_defaults(mp, mf, xstrdup(def_opts)); + def_opts = xstrdup(orig_def_opts); /* first build our defaults */ num_ivecs = 0; @@ -423,11 +436,11 @@ amfs_lookup_mntfs(am_node *new_mp, int *error_return) num_ivecs++; } - mf_array = calloc(num_ivecs + 1, sizeof(mntfs *)); + al_array = calloc(num_ivecs + 1, sizeof(am_loc *)); - /* construct the array of struct mntfs for this mount point */ + /* construct the array of struct locations for this key */ for (count = 0, cur_ivec = ivecs; *cur_ivec; cur_ivec++) { - mntfs *new_mf; + am_loc *new_al; if (**cur_ivec == '-') { XFREE(def_opts); @@ -436,18 +449,18 @@ amfs_lookup_mntfs(am_node *new_mp, int *error_return) * If we have a single dash '-' than we need to reset the * default options. */ - def_opts = strdup(orig_def_opts); + def_opts = xstrdup(orig_def_opts); dlog("Resetting the default options, a single dash '-' was found."); } else { /* append options to /default options */ - def_opts = str3cat((char *) 0, orig_def_opts, ";", *cur_ivec + 1); + def_opts = str3cat((char *) NULL, orig_def_opts, ";", *cur_ivec + 1); dlog("Resetting def_opts to \"%s\"", def_opts); } continue; } /* - * If a mntfs has already been found, and we find + * If a loc has already been found, and we find * a cut then don't try any more locations. * * XXX: we do not know when the "/" was added as an equivalent for "||". @@ -455,16 +468,16 @@ amfs_lookup_mntfs(am_node *new_mp, int *error_return) */ if (STREQ(*cur_ivec, "/") || STREQ(*cur_ivec, "||")) { if (count > 0) { - dlog("Cut: not trying any more locations for %s", mp->am_path); + dlog("Cut: not trying any more locations for %s", pfname); break; } continue; } - new_mf = amfs_lookup_one_mntfs(new_mp, mf, *cur_ivec, def_opts, pfname); - if (new_mf == NULL) + new_al = amfs_lookup_one_location(new_mp, mf, *cur_ivec, def_opts, pfname); + if (new_al == NULL) continue; - mf_array[count++] = new_mf; + al_array[count++] = new_al; } /* We're done with ivecs */ @@ -473,11 +486,11 @@ amfs_lookup_mntfs(am_node *new_mp, int *error_return) XFREE(orig_def_opts); XFREE(def_opts); if (count == 0) { /* no match */ - XFREE(mf_array); + XFREE(al_array); ereturn(ENOENT); } - return mf_array; + return al_array; } @@ -491,7 +504,7 @@ amfs_cont(int rc, int term, opaque_t arg) { struct continuation *cp = (struct continuation *) arg; am_node *mp = cp->mp; - mntfs *mf = mp->am_mnt; + mntfs *mf = mp->am_al->al_mnt; dlog("amfs_cont: '%s'", mp->am_path); @@ -556,7 +569,7 @@ amfs_cont(int rc, int term, opaque_t arg) mf->mf_error = rc; mf->mf_flags |= MFF_ERROR; errno = rc; /* XXX */ - if (!STREQ(mp->am_mnt->mf_ops->fs_type, "linkx")) + if (!STREQ(mp->am_al->al_mnt->mf_ops->fs_type, "linkx")) plog(XLOG_ERROR, "%s: mount (amfs_cont): %m", mp->am_path); } } @@ -568,7 +581,7 @@ amfs_cont(int rc, int term, opaque_t arg) * call the background mount routine again */ amd_stats.d_merr++; - cp->mf++; + cp->al++; } amfs_bgmount(cp); if (mp->am_error > 0) @@ -608,13 +621,21 @@ amfs_retry(int rc, int term, opaque_t arg) */ plog(XLOG_INFO, "mount of \"%s\" has timed out", mp->am_path); error = ETIMEDOUT; - while (*cp->mf) - cp->mf++; + while (*cp->al) + cp->al++; /* explicitly forbid further retries after timeout */ cp->retry = FALSE; } if (error || !IN_PROGRESS(cp)) error = amfs_bgmount(cp); + else + /* Normally it's amfs_bgmount() which frees the continuation. However, if + * the mount is already in progress and we're in amfs_retry() for another + * node we don't try mounting the filesystem once again. Still, we have + * to free the continuation as we won't get called again and thus would + * leak the continuation structure and our am_loc references. + */ + free_continuation(cp); reschedule_timeout_mp(); } @@ -626,7 +647,7 @@ amfs_retry(int rc, int term, opaque_t arg) static void free_continuation(struct continuation *cp) { - mntfs **mfp; + am_loc **alp; dlog("free_continuation"); if (cp->callout) @@ -634,13 +655,12 @@ free_continuation(struct continuation *cp) /* * 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); + for (alp = cp->mp->am_alarray; *alp; alp++) { + free_loc(*alp); } - XFREE(cp->mp->am_mfarray); - cp->mp->am_mfarray = 0; + XFREE(cp->mp->am_alarray); + cp->mp->am_alarray = 0; XFREE(cp); } @@ -690,12 +710,13 @@ static int amfs_bgmount(struct continuation *cp) { am_node *mp = cp->mp; - mntfs *mf; /* Current mntfs */ + am_loc *loc; + mntfs *mf; int this_error = -1; /* Per-mount error */ int hard_error = -1; /* Cumulative per-node error */ - if (mp->am_mnt) - free_mntfs(mp->am_mnt); + if (mp->am_al) + free_loc(mp->am_al); /* * Try to mount each location. @@ -704,10 +725,11 @@ amfs_bgmount(struct continuation *cp) * 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) { + for (mp->am_al = *cp->al; *cp->al; cp->al++, mp->am_al = *cp->al) { am_ops *p; - mf = dup_mntfs(mp->am_mnt); + loc = dup_loc(mp->am_al); + mf = loc->al_mnt; p = mf->mf_ops; if (hard_error < 0) @@ -737,12 +759,11 @@ amfs_bgmount(struct continuation *cp) 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); + XFREE(mp->am_link); + mp->am_link = NULL; + + if (loc->al_fo && loc->al_fo->opt_sublink && loc->al_fo->opt_sublink[0]) + mp->am_link = xstrdup(loc->al_fo->opt_sublink); /* * Will usually need to play around with the mount nodes @@ -784,13 +805,13 @@ amfs_bgmount(struct continuation *cp) if (this_error < 0) goto retry; - if (mf->mf_fo && mf->mf_fo->opt_delay) { + if (loc->al_fo && loc->al_fo->opt_delay) { /* - * If there is a delay timer on the mount + * If there is a delay timer on the location * then don't try to mount if the timer * has not expired. */ - int i = atoi(mf->mf_fo->opt_delay); + int i = atoi(loc->al_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)); @@ -866,22 +887,25 @@ amfs_bgmount(struct continuation *cp) return -1; failed: - amd_stats.d_merr++; - mf->mf_error = this_error; - mf->mf_flags |= MFF_ERROR; + if (!FSRV_ISDOWN(mf->mf_server)) { + /* mark the mount as failed unless the server is down */ + 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); + 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; + 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); + free_loc(loc); /* continue */ } @@ -890,7 +914,10 @@ amfs_bgmount(struct continuation *cp) * there is no more mount information available. */ if (this_error) { - mp->am_mnt = mf = new_mntfs(); + if (mp->am_al) + free_loc(mp->am_al); + mp->am_al = loc = new_loc(); + mf = loc->al_mnt; #ifdef HAVE_FS_AUTOFS if (mp->am_flags & AMF_AUTOFS) @@ -920,7 +947,7 @@ amfs_bgmount(struct continuation *cp) } new_ttl(mp); } else { - mf = mp->am_mnt; + mf = loc->al_mnt; /* * Wakeup anything waiting for this mount */ @@ -959,19 +986,10 @@ amfs_parse_defaults(am_node *mp, mntfs *mf, char *def_opts) /* * Find out if amd.conf overrode any map-specific /defaults. - * - * HACK ALERT: there's no easy way to find out what the map mount point is - * at this point, so I am forced to initialize the mnt_map->cfm field here - * for the first time, upon the very first search for a /defaults entry in - * this map. This initialization is much better done in mapc_create(), - * but it's impossible to do that there with the current code structure. */ - if (mm->cfm == NULL) { /* then initialize it for first time */ - mm->cfm = find_cf_map(mf->mf_mount); - } if (mm->cfm && mm->cfm->cfm_defaults) { dlog("map %s map_defaults override: %s", mf->mf_mount, mm->cfm->cfm_defaults); - dflts = strdup(mm->cfm->cfm_defaults); + dflts = xstrdup(mm->cfm->cfm_defaults); } else if (mapc_search(mm, "/defaults", &dflts) == 0) { dlog("/defaults gave %s", dflts); } else { @@ -1009,7 +1027,7 @@ amfs_parse_defaults(am_node *mp, mntfs *mf, char *def_opts) * get expanded to "/defaults" */ pt = ops_match(&ap, *sp, "", mp->am_path, "/defaults", - mp->am_parent->am_mnt->mf_info); + mp->am_parent->am_al->al_mnt->mf_info); free_opts(&ap); /* don't leak */ if (pt == &amfs_error_ops) { plog(XLOG_MAP, "did not match defaults for \"%s\"", *sp); @@ -1076,8 +1094,9 @@ amfs_generic_mount_child(am_node *new_mp, int *error_return) *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; + if (new_mp->am_al) + free_loc(new_mp->am_al); + new_mp->am_al = NULL; /* * Construct a continuation @@ -1087,7 +1106,7 @@ amfs_generic_mount_child(am_node *new_mp, int *error_return) cp->mp = new_mp; cp->retry = TRUE; cp->start = clocktime(NULL); - cp->mf = new_mp->am_mfarray; + cp->al = new_mp->am_alarray; /* * Try and mount the file system. If this succeeds immediately (possible @@ -1101,7 +1120,7 @@ amfs_generic_mount_child(am_node *new_mp, int *error_return) /* * 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 + * transp that's been passed down from nfs_dispatcher() 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 @@ -1113,7 +1132,8 @@ amfs_generic_mount_child(am_node *new_mp, int *error_return) new_mp->am_transp = (SVCXPRT *) xmalloc(sizeof(SVCXPRT)); *(new_mp->am_transp) = *current_transp; } - if (error && new_mp->am_mnt && (new_mp->am_mnt->mf_ops == &amfs_error_ops)) + if (error && new_mp->am_al && new_mp->am_al->al_mnt && + (new_mp->am_al->al_mnt->mf_ops == &amfs_error_ops)) new_mp->am_error = error; if (new_mp->am_error > 0) @@ -1132,7 +1152,7 @@ am_node * amfs_generic_lookup_child(am_node *mp, char *fname, int *error_return, int op) { am_node *new_mp; - mntfs **mf_array; + am_loc **al_array; int mp_error; dlog("in amfs_generic_lookup_child"); @@ -1145,7 +1165,7 @@ amfs_generic_lookup_child(am_node *mp, char *fname, int *error_return, int op) 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)) + if (*error_return == 0 && FSRV_ISUP(new_mp->am_al->al_mnt->mf_server)) return new_mp; switch (op) { @@ -1161,42 +1181,15 @@ amfs_generic_lookup_child(am_node *mp, char *fname, int *error_return, int op) /* 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; + al_array = amfs_lookup_loc(new_mp, error_return); + if (!al_array) { + new_mp->am_error = new_mp->am_al->al_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; + new_mp->am_alarray = al_array; /* * Note: while it might seem like a good idea to prioritize @@ -1258,5 +1251,5 @@ amfs_generic_match(am_opts *fo) /* * mtab entry turns out to be the name of the mount map */ - return strdup(fo->opt_rfs ? fo->opt_rfs : "."); + return xstrdup(fo->opt_rfs ? fo->opt_rfs : "."); } |