Esempio n. 1
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. 2
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);
	}
}
Esempio n. 3
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;
}