Beispiel #1
0
/*
 * 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);
}
Beispiel #2
0
/*
 * 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);
}
Beispiel #3
0
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);
}
Beispiel #4
0
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);
	}
}
Beispiel #5
0
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);
}
Beispiel #6
0
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);
}
Beispiel #7
0
/*
 * 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);
}
Beispiel #8
0
/*
 * 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);
}
Beispiel #9
0
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;
}
Beispiel #10
0
/*
 * 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;
}
Beispiel #11
0
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;
}
Beispiel #12
0
/*
 * 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;
}
Beispiel #13
0
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);
}
Beispiel #14
0
/*
 * 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;
}