Ejemplo n.º 1
0
/*
 * Convert from automount node to file handle.
 */
void
mp_to_fh(am_node *mp, am_nfs_fh *fhp)
{
  u_int pathlen;
  struct am_fh *fp = (struct am_fh *) fhp;

  memset((char *) fhp, 0, sizeof(am_nfs_fh));

  /* Store the generation number */
  fp->fhh_gen = mp->am_gen;

  pathlen = strlen(mp->am_path);
  if (pathlen <= sizeof(*fhp) - sizeof(fp->fhh_gen)) {
    /* dlog("mp_to_fh: new filehandle: %s", mp->am_path); */

    /*
     * Because fhp is treated as a filehandle we use memcpy instead of
     * xstrlcpy.
     */
    memcpy(fp->u.fhh_path, mp->am_path, pathlen); /* making a filehandle */
  } else {
    /*
     * Take the process id
     */
    fp->u.s.fhh_pid = get_server_pid();

    /*
     * ... the map number
     */
    fp->u.s.fhh_id = mp->am_mapno;

    /*
     * ... and the generation number (previously stored)
     * to make a "unique" triple that will never
     * be reallocated except across reboots (which doesn't matter)
     * or if we are unlucky enough to be given the same
     * pid as a previous amd (very unlikely).
     */
    /* dlog("mp_to_fh: old filehandle: %d", fp->u.s.fhh_id); */
  }
}
Ejemplo n.º 2
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;
}
Ejemplo n.º 3
0
Archivo: autil.c Proyecto: 0mp/freebsd
/*
 * Mount an automounter directory.
 * The automounter is connected into the system
 * as a user-level NFS server.  amfs_mount constructs
 * the necessary NFS parameters to be given to the
 * kernel so that it will talk back to us.
 *
 * NOTE: automounter mounts in themselves are using NFS Version 2 (UDP).
 *
 * NEW: on certain systems, mounting can be done using the
 * kernel-level automount (autofs) support. In that case,
 * we don't need NFS at all here.
 */
int
amfs_mount(am_node *mp, mntfs *mf, char *opts)
{
  char fs_hostname[MAXHOSTNAMELEN + MAXPATHLEN + 1];
  int retry, error = 0, genflags;
  int on_autofs = mf->mf_flags & MFF_ON_AUTOFS;
  char *dir = mf->mf_mount;
  mntent_t mnt;
  MTYPE_TYPE type;
  int forced_unmount = 0;	/* are we using forced unmounts? */
  u_long nfs_version = get_nfs_dispatcher_version(nfs_dispatcher);

  memset(&mnt, 0, sizeof(mnt));
  mnt.mnt_dir = dir;
  mnt.mnt_fsname = pid_fsname;
  mnt.mnt_opts = opts;

#ifdef HAVE_FS_AUTOFS
  if (mf->mf_flags & MFF_IS_AUTOFS) {
    type = MOUNT_TYPE_AUTOFS;
    /*
     * Make sure that amd's top-level autofs mounts are hidden by default
     * from df.
     * XXX: It works ok on Linux, might not work on other systems.
     */
    mnt.mnt_type = "autofs";
  } else
#endif /* HAVE_FS_AUTOFS */
  {
    type = MOUNT_TYPE_NFS;
    /*
     * Make sure that amd's top-level NFS mounts are hidden by default
     * from df.
     * If they don't appear to support the either the "ignore" mnttab
     * option entry, or the "auto" one, set the mount type to "nfs".
     */
    mnt.mnt_type = HIDE_MOUNT_TYPE;
  }

  retry = hasmntval(&mnt, MNTTAB_OPT_RETRY);
  if (retry <= 0)
    retry = 2;			/* XXX: default to 2 retries */

  /*
   * SET MOUNT ARGS
   */

  /*
   * Make a ``hostname'' string for the kernel
   */
  xsnprintf(fs_hostname, sizeof(fs_hostname), "pid%ld@%s:%s",
	    get_server_pid(), am_get_hostname(), dir);
  /*
   * Most kernels have a name length restriction (64 bytes)...
   */
  if (strlen(fs_hostname) >= MAXHOSTNAMELEN)
    xstrlcpy(fs_hostname + MAXHOSTNAMELEN - 3, "..",
	     sizeof(fs_hostname) - MAXHOSTNAMELEN + 3);
#ifdef HOSTNAMESZ
  /*
   * ... and some of these restrictions are 32 bytes (HOSTNAMESZ)
   * If you need to get the definition for HOSTNAMESZ found, you may
   * add the proper header file to the conf/nfs_prot/nfs_prot_*.h file.
   */
  if (strlen(fs_hostname) >= HOSTNAMESZ)
    xstrlcpy(fs_hostname + HOSTNAMESZ - 3, "..",
	     sizeof(fs_hostname) - HOSTNAMESZ + 3);
#endif /* HOSTNAMESZ */

  /*
   * Finally we can compute the mount genflags set above,
   * and add any automounter specific flags.
   */
  genflags = compute_mount_flags(&mnt);
#ifdef HAVE_FS_AUTOFS
  if (on_autofs)
    genflags |= autofs_compute_mount_flags(&mnt);
#endif /* HAVE_FS_AUTOFS */
  genflags |= compute_automounter_mount_flags(&mnt);

again:
  if (!(mf->mf_flags & MFF_IS_AUTOFS)) {
    nfs_args_t nfs_args;
    am_nfs_handle_t *fhp, anh;
#ifndef HAVE_TRANSPORT_TYPE_TLI
    u_short port;
    struct sockaddr_in sin;
#endif /* not HAVE_TRANSPORT_TYPE_TLI */

    /*
     * get fhandle of remote path for automount point
     */
    fhp = get_root_nfs_fh(dir, &anh);
    if (!fhp) {
      plog(XLOG_FATAL, "Can't find root file handle for %s", dir);
      return EINVAL;
    }

#ifndef HAVE_TRANSPORT_TYPE_TLI
    /*
     * Create sockaddr to point to the local machine.
     */
    memset(&sin, 0, sizeof(sin));
    /* as per POSIX, sin_len need not be set (used internally by kernel) */
    sin.sin_family = AF_INET;
    sin.sin_addr = myipaddr;
    port = hasmntval(&mnt, MNTTAB_OPT_PORT);
    if (port) {
      sin.sin_port = htons(port);
    } else {
      plog(XLOG_ERROR, "no port number specified for %s", dir);
      return EINVAL;
    }
#endif /* not HAVE_TRANSPORT_TYPE_TLI */

    /* setup the many fields and flags within nfs_args */
#ifdef HAVE_TRANSPORT_TYPE_TLI
    compute_nfs_args(&nfs_args,
		     &mnt,
		     genflags,
		     nfsncp,
		     NULL,	/* remote host IP addr is set below */
		     nfs_version,
		     "udp",
		     fhp,
		     fs_hostname,
		     pid_fsname);
    /*
     * IMPORTANT: set the correct IP address AFTERWARDS.  It cannot
     * be done using the normal mechanism of compute_nfs_args(), because
     * that one will allocate a new address and use NFS_SA_DREF() to copy
     * parts to it, while assuming that the ip_addr passed is always
     * a "struct sockaddr_in".  That assumption is incorrect on TLI systems,
     * because they define a special macro HOST_SELF which is DIFFERENT
     * than localhost (127.0.0.1)!
     */
    nfs_args.addr = &nfsxprt->xp_ltaddr;
#else /* not HAVE_TRANSPORT_TYPE_TLI */
    compute_nfs_args(&nfs_args,
		     &mnt,
		     genflags,
		     NULL,
		     &sin,
		     nfs_version,
		     "udp",
		     fhp,
		     fs_hostname,
		     pid_fsname);
#endif /* not HAVE_TRANSPORT_TYPE_TLI */

    /*************************************************************************
     * NOTE: while compute_nfs_args() works ok for regular NFS mounts	     *
     * the toplvl one is not quite regular, and so some options must be      *
     * corrected by hand more carefully, *after* compute_nfs_args() runs.    *
     *************************************************************************/
    compute_automounter_nfs_args(&nfs_args, &mnt);

    if (amuDebug(D_TRACE)) {
      print_nfs_args(&nfs_args, 0);
      plog(XLOG_DEBUG, "Generic mount flags 0x%x", genflags);
    }

    /* This is it!  Here we try to mount amd on its mount points */
    error = mount_fs(&mnt, genflags, (caddr_t) &nfs_args,
		     retry, type, 0, NULL, mnttab_file_name, on_autofs);

#ifdef HAVE_TRANSPORT_TYPE_TLI
    free_knetconfig(nfs_args.knconf);
    /*
     * local automounter mounts do not allocate a special address, so
     * no need to XFREE(nfs_args.addr) under TLI.
     */
#endif /* HAVE_TRANSPORT_TYPE_TLI */

#ifdef HAVE_FS_AUTOFS
  } else {
    /* This is it!  Here we try to mount amd on its mount points */
    error = mount_fs(&mnt, genflags, (caddr_t) mp->am_autofs_fh,
		     retry, type, 0, NULL, mnttab_file_name, on_autofs);
#endif /* HAVE_FS_AUTOFS */
  }
  if (error == 0 || forced_unmount)
     return error;

  /*
   * If user wants forced/lazy unmount semantics, then try it iff the
   * current mount failed with EIO or ESTALE.
   */
  if (gopt.flags & CFM_FORCED_UNMOUNTS) {
    switch (errno) {
    case ESTALE:
    case EIO:
      forced_unmount = errno;
      plog(XLOG_WARNING, "Mount %s failed (%m); force unmount.", mp->am_path);
      if ((error = UMOUNT_FS(mp->am_path, mnttab_file_name,
			     AMU_UMOUNT_FORCE | AMU_UMOUNT_DETACH)) < 0) {
	plog(XLOG_WARNING, "Forced umount %s failed: %m.", mp->am_path);
	errno = forced_unmount;
      } else
	goto again;
    default:
      break;
    }
  }

  return error;
}