/* * 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(); }
/* * 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; }
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; }
/* * 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(); }
/* * 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; }
/* * 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; }
/* * 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(); }
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++; }
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++; }
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++; }