Esempio n. 1
0
/*
 * Retry a mount
 */
static void
amfs_retry(int rc, int term, opaque_t arg)
{
  struct continuation *cp = (struct continuation *) arg;
  am_node *mp = cp->mp;
  int error = 0;

  dlog("Commencing retry for mount of %s", mp->am_path);

  new_ttl(mp);

  if ((cp->start + ALLOWED_MOUNT_TIME) < clocktime(NULL)) {
    /*
     * The entire mount has timed out.  Set the error code and skip past all
     * the mntfs's so that amfs_bgmount will not have any more
     * ways to try the mount, thus causing an error.
     */
    plog(XLOG_INFO, "mount of \"%s\" has timed out", mp->am_path);
    error = ETIMEDOUT;
    while (*cp->mf)
      cp->mf++;
    /* explicitly forbid further retries after timeout */
    cp->retry = FALSE;
  }
  if (error || !IN_PROGRESS(cp))
    error = amfs_bgmount(cp);

  reschedule_timeout_mp();
}
Esempio n. 2
0
/*
 * Initialize an allocated mount node.
 * It is assumed that the mount node was b-zero'd
 * before getting here so anything that would
 * be set to zero isn't done here.
 */
void
init_map(am_node *mp, char *dir)
{
  /*
   * mp->am_mapno is initialized by exported_ap_alloc
   * other fields don't need to be set to zero.
   */
  mp->am_mnt = new_mntfs();
  mp->am_mfarray = 0;
  mp->am_name = strdup(dir);
  mp->am_path = strdup(dir);
  mp->am_gen = new_gen();
#ifdef HAVE_FS_AUTOFS
  mp->am_autofs_fh = 0;
#endif /* HAVE_FS_AUTOFS */

  mp->am_timeo = gopt.am_timeo;
  mp->am_attr.ns_status = NFS_OK;
  mp->am_fattr = gen_fattr;
  mp->am_fattr.na_fsid = 42;
  mp->am_fattr.na_fileid = mp->am_gen;
  clocktime(&mp->am_fattr.na_atime);
  /* next line copies a "struct nfstime" among several fields */
  mp->am_fattr.na_mtime = mp->am_fattr.na_ctime = mp->am_fattr.na_atime;

  new_ttl(mp);
  mp->am_stats.s_mtime = mp->am_fattr.na_atime.nt_seconds;
  mp->am_dev = -1;
  mp->am_rdev = -1;
}
Esempio n. 3
0
static am_node *
amfs_direct_readlink(am_node *mp, int *error_return)
{
  am_node *xp;
  int rc = 0;

  xp = next_nonerror_node(mp->am_child);
  if (!xp) {
    if (!mp->am_al->al_mnt->mf_private)
      amfs_mkcacheref(mp->am_al->al_mnt);
    xp = amfs_generic_lookup_child(mp, mp->am_path + 1, &rc, VLOOK_CREATE);
    if (xp && rc < 0)
      xp = amfs_generic_mount_child(xp, &rc);
  }
  if (xp) {
    new_ttl(xp);		/* (7/12/89) from Rein Tollevik */
    return xp;
  }
  if (amd_state == Finishing)
    rc = ENOENT;
  *error_return = rc;
  return 0;
}
Esempio n. 4
0
/*
 * Retry a mount
 */
static void
amfs_retry(int rc, int term, opaque_t arg)
{
  struct continuation *cp = (struct continuation *) arg;
  am_node *mp = cp->mp;
  int error = 0;

  dlog("Commencing retry for mount of %s", mp->am_path);

  new_ttl(mp);

  if ((cp->start + ALLOWED_MOUNT_TIME) < clocktime(NULL)) {
    /*
     * The entire mount has timed out.  Set the error code and skip past all
     * the mntfs's so that amfs_bgmount will not have any more
     * ways to try the mount, thus causing an error.
     */
    plog(XLOG_INFO, "mount of \"%s\" has timed out", mp->am_path);
    error = ETIMEDOUT;
    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();
}
Esempio n. 5
0
/*
 * Convert from file handle to automount node.
 */
static am_node *
fh_to_mp3(am_nfs_fh *fhp, int *rp, int vop)
{
  struct am_fh *fp = (struct am_fh *) fhp;
  am_node *ap = NULL;

  if (fp->u.s.fhh_type != 0) {
    /* New filehandle type */
    int len = sizeof(*fhp) - sizeof(fp->fhh_gen);
    char *path = xmalloc(len+1);
    /*
     * Because fhp is treated as a filehandle we use memcpy
     * instead of xstrlcpy.
     */
    memcpy(path, (char *) fp->u.fhh_path, len);
    path[len] = '\0';
    /* dlog("fh_to_mp3: new filehandle: %s", path); */

    ap = path_to_exported_ap(path);
    XFREE(path);
  } else {
    /* dlog("fh_to_mp3: old filehandle: %d", fp->u.s.fhh_id); */
    /*
     * Check process id matches
     * If it doesn't then it is probably
     * from an old kernel-cached filehandle
     * which is now out of date.
     */
    if (fp->u.s.fhh_pid != get_server_pid()) {
      dlog("fh_to_mp3: wrong pid %ld != my pid %ld",
	   (long) fp->u.s.fhh_pid, get_server_pid());
      goto drop;
    }

    /*
     * Get hold of the supposed mount node
     */
    ap = get_exported_ap(fp->u.s.fhh_id);
  }

  /*
   * Check the generation number in the node
   * matches the one from the kernel.  If not
   * then the old node has been timed out and
   * a new one allocated.
   */
  if (ap != NULL && ap->am_gen != fp->fhh_gen)
    ap = NULL;

  /*
   * If it doesn't exists then drop the request
   */
  if (!ap)
    goto drop;

#if 0
  /*
   * If the node is hung then locate a new node
   * for it.  This implements the replicated filesystem
   * retries.
   */
  if (ap->am_al->al_mnt && FSRV_ISDOWN(ap->am_al->al_mnt->mf_server) && ap->am_parent) {
    int error;
    am_node *orig_ap = ap;

    dlog("fh_to_mp3: %s (%s) is hung: lookup alternative file server",
	 orig_ap->am_path, orig_ap->am_al->al_mnt->mf_info);

    /*
     * Update modify time of parent node.
     * With any luck the kernel will re-stat
     * the child node and get new information.
     */
    clocktime(&orig_ap->am_fattr.na_mtime);

    /*
     * Call the parent's lookup routine for an object
     * with the same name.  This may return -1 in error
     * if a mount is in progress.  In any case, if no
     * mount node is returned the error code is propagated
     * to the caller.
     */
    if (vop == VLOOK_CREATE) {
      ap = orig_ap->am_parent->am_al->al_mnt->mf_ops->lookup_child(orig_ap->am_parent, orig_ap->am_name, &error, vop);
      if (ap && error < 0)
	ap = orig_ap->am_parent->am_al->al_mnt->mf_ops->mount_child(ap, &error);
    } else {
      ap = NULL;
      error = ESTALE;
    }
    if (ap == 0) {
      if (error < 0 && amd_state == Finishing)
	error = ENOENT;
      *rp = error;
      return 0;
    }

    /*
     * Update last access to original node.  This
     * avoids timing it out and so sending ESTALE
     * back to the kernel.
     * XXX - Not sure we need this anymore (jsp, 90/10/6).
     */
    new_ttl(orig_ap);

  }
#endif /* 0 */

  /*
   * Disallow references to objects being unmounted, unless
   * they are automount points.
   */
  if (ap->am_al->al_mnt && (ap->am_al->al_mnt->mf_flags & MFF_UNMOUNTING) &&
      !(ap->am_flags & AMF_ROOT)) {
    if (amd_state == Finishing)
      *rp = ENOENT;
    else
      *rp = -1;
    return 0;
  }
  new_ttl(ap);

drop:
  if (!ap || !ap->am_al->al_mnt) {
    /*
     * If we are shutting down then it is likely
     * that this node has disappeared because of
     * a fast timeout.  To avoid things thrashing
     * just pretend it doesn't exist at all.  If
     * ESTALE is returned, some NFS clients just
     * keep retrying (stupid or what - if it's
     * stale now, what's it going to be in 5 minutes?)
     */
    if (amd_state == Finishing)
      *rp = ENOENT;
    else {
      *rp = ESTALE;
      amd_stats.d_stale++;
    }
  }

  return ap;
}
Esempio n. 6
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;
  am_loc *loc;
  mntfs *mf;
  int this_error = -1;		/* Per-mount error */
  int hard_error = -1;		/* Cumulative per-node error */

  if (mp->am_al)
    free_loc(mp->am_al);

  /*
   * 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_al = *cp->al; *cp->al; cp->al++, mp->am_al = *cp->al) {
    am_ops *p;

    loc = dup_loc(mp->am_al);
    mf = loc->al_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;
    }

    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
     * 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 (loc->al_fo && loc->al_fo->opt_delay) {
      /*
       * If there is a delay timer on the location
       * then don't try to mount if the timer
       * has not expired.
       */
      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));
	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:
    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);
#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_loc(loc);
    /* continue */
  }

  /*
   * If we get here, then either the mount succeeded or
   * there is no more mount information available.
   */
  if (this_error) {
    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)
      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 = loc->al_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;
}
Esempio n. 7
0
/*
 * The continuation function.  This is called by
 * the task notifier when a background mount attempt
 * completes.
 */
static void
amfs_cont(int rc, int term, opaque_t arg)
{
  struct continuation *cp = (struct continuation *) arg;
  am_node *mp = cp->mp;
  mntfs *mf = mp->am_al->al_mnt;

  dlog("amfs_cont: '%s'", mp->am_path);

  /*
   * Definitely not trying to mount at the moment
   */
  mf->mf_flags &= ~MFF_MOUNTING;

  /*
   * While we are mounting - try to avoid race conditions
   */
  new_ttl(mp);

  /*
   * Wakeup anything waiting for this mount
   */
  wakeup(get_mntfs_wchan(mf));

  /*
   * Check for termination signal or exit status...
   */
  if (rc || term) {
#ifdef HAVE_FS_AUTOFS
    if (mf->mf_flags & MFF_IS_AUTOFS &&
	!(mf->mf_flags & MFF_MOUNTED))
      autofs_release_fh(mp);
#endif /* HAVE_FS_AUTOFS */

    if (term) {
      /*
       * Not sure what to do for an error code.
       */
      mf->mf_error = EIO;	/* XXX ? */
      mf->mf_flags |= MFF_ERROR;
      plog(XLOG_ERROR, "mount for %s got signal %d", mp->am_path, term);
    } else {
      /*
       * Check for exit status...
       */
#ifdef __linux__
      /*
       * HACK ALERT!
       *
       * On Linux (and maybe not only) it's possible to run
       * an amd which "knows" how to mount certain combinations
       * of nfs_proto/nfs_version which the kernel doesn't grok.
       * So if we got an EINVAL and we have a server that's not
       * using NFSv2/UDP, try again with NFSv2/UDP.
       *
       * Too bad that there is no way to dynamically determine
       * what combinations the _client_ supports, as opposed to
       * what the _server_ supports...
       */
      if (rc == EINVAL &&
	  mf->mf_server &&
	  (mf->mf_server->fs_version != 2 ||
	   !STREQ(mf->mf_server->fs_proto, "udp")))
	mf->mf_flags |= MFF_NFS_SCALEDOWN;
      else
#endif /* __linux__ */
      {
	mf->mf_error = rc;
	mf->mf_flags |= MFF_ERROR;
	errno = rc;		/* XXX */
	if (!STREQ(mp->am_al->al_mnt->mf_ops->fs_type, "linkx"))
	  plog(XLOG_ERROR, "%s: mount (amfs_cont): %m", mp->am_path);
      }
    }

    if (!(mf->mf_flags & MFF_NFS_SCALEDOWN)) {
      /*
       * If we get here then that attempt didn't work, so
       * move the info vector pointer along by one and
       * call the background mount routine again
       */
      amd_stats.d_merr++;
      cp->al++;
    }
    amfs_bgmount(cp);
    if (mp->am_error > 0)
      assign_error_mntfs(mp);
  } else {
    /*
     * The mount worked.
     */
    dlog("Mounting %s returned success", cp->mp->am_path);
    am_mounted(cp->mp);
    free_continuation(cp);
  }

  reschedule_timeout_mp();
}
Esempio n. 8
0
void
am_mounted(am_node *mp)
{
  mntfs *mf = mp->am_mnt;

  mf_mounted(mf);

  /*
   * Patch up path for direct mounts
   */
  if (mp->am_parent && mp->am_parent->am_mnt->mf_ops == &amfs_direct_ops)
    mp->am_path = str3cat(mp->am_path, mp->am_parent->am_path, "/", ".");

  /*
   * Check whether this mount should be cached permanently
   */
  if (mf->mf_ops->fs_flags & FS_NOTIMEOUT) {
    mp->am_flags |= AMF_NOTIMEOUT;
  } else if (mf->mf_mount[1] == '\0' && mf->mf_mount[0] == '/') {
    mp->am_flags |= AMF_NOTIMEOUT;
  } else {
    mntent_t mnt;
    if (mf->mf_mopts) {
      mnt.mnt_opts = mf->mf_mopts;
      if (hasmntopt(&mnt, "nounmount"))
	mp->am_flags |= AMF_NOTIMEOUT;
      if ((mp->am_timeo = hasmntval(&mnt, "utimeout")) == 0)
	mp->am_timeo = gopt.am_timeo;
    }
  }

  /*
   * If this node is a symlink then
   * 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);

  /*
   * Record mount time
   */
  mp->am_fattr.na_mtime.nt_seconds = mp->am_stats.s_mtime = clocktime();
  new_ttl(mp);

  /*
   * Update mtime of parent node
   */
  if (mp->am_parent && mp->am_parent->am_mnt)
    mp->am_parent->am_fattr.na_mtime.nt_seconds = mp->am_stats.s_mtime;

  /*
   * Now, if we can, do a reply to our NFS client here
   * to speed things up.
   */
  quick_reply(mp, 0);

  /*
   * Update stats
   */
  amd_stats.d_mok++;
}
Esempio n. 9
0
void
am_mounted(am_node *mp)
{
  mntfs *mf = mp->am_mnt;

  mf_mounted(mf);

#ifdef HAVE_FS_AUTOFS
  if (mf->mf_flags & MFF_AUTOFS)
    autofs_mounted(mp);
#endif /* HAVE_FS_AUTOFS */

  /*
   * Patch up path for direct mounts
   */
  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
   */
  if (mf->mf_fsflags & FS_NOTIMEOUT) {
    mp->am_flags |= AMF_NOTIMEOUT;
  } else if (mf->mf_mount[1] == '\0' && mf->mf_mount[0] == '/') {
    mp->am_flags |= AMF_NOTIMEOUT;
  } else {
    mntent_t mnt;
    if (mf->mf_mopts) {
      mnt.mnt_opts = mf->mf_mopts;
      if (hasmntopt(&mnt, "nounmount"))
	mp->am_flags |= AMF_NOTIMEOUT;
      if ((mp->am_timeo = hasmntval(&mnt, "utimeout")) == 0)
	mp->am_timeo = gopt.am_timeo;
    }
  }

  /*
   * If this node is a symlink then
   * 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);

  /*
   * Record mount time
   */
  mp->am_fattr.na_mtime.nt_seconds = mp->am_stats.s_mtime = clocktime();
  new_ttl(mp);

  /*
   * Update mtime of parent node
   */
  if (mp->am_parent && mp->am_parent->am_mnt)
    mp->am_parent->am_fattr.na_mtime.nt_seconds = mp->am_stats.s_mtime;

  /*
   * This is ugly, but essentially unavoidable
   * Sublinks must be treated separately as type==link
   * when the base type is different.
   */
  if (mp->am_link && mp->am_mnt->mf_ops != &amfs_link_ops)
    amfs_link_ops.mount_fs(mp, mp->am_mnt);

#ifdef HAVE_FS_AUTOFS
  if (mp->am_flags & AMF_AUTOFS)
    autofs_mount_succeeded(mp);
  else
#endif /* HAVE_FS_AUTOFS */
    /*
     * Now, if we can, do a reply to our NFS client here
     * to speed things up.
     */
    nfs_quick_reply(mp, 0);

  /*
   * Update stats
   */
  amd_stats.d_mok++;
}
Esempio n. 10
0
File: autil.c Progetto: 0mp/freebsd
void
am_mounted(am_node *mp)
{
  int notimeout = 0;		/* assume normal timeouts initially */
  mntfs *mf = mp->am_al->al_mnt;

  /*
   * 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_al->al_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 or not,
   * and handle user-requested timeouts.
   */
  /* 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;

    /* 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
      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 {
    mp->am_flags &= ~AMF_NOTIMEOUT;
    plog(XLOG_INFO, "%s set to timeout in %d seconds", mp->am_path, mp->am_timeo);
  }

  /*
   * If this node is a symlink then
   * 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 : mf->mf_mount);

  /*
   * Record mount time, and update am_stats at the same time.
   */
  mp->am_stats.s_mtime = clocktime(&mp->am_fattr.na_mtime);
  new_ttl(mp);

  /*
   * Update mtime of parent node (copying "struct nfstime" in '=' below)
   */
  if (mp->am_parent && mp->am_parent->am_al->al_mnt)
    mp->am_parent->am_fattr.na_mtime = mp->am_fattr.na_mtime;

  /*
   * 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.
   */
#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
   */
  amd_stats.d_mok++;
}