diff options
Diffstat (limited to 'contrib/amd/amd/nfs_subr.c')
-rw-r--r-- | contrib/amd/amd/nfs_subr.c | 359 |
1 files changed, 278 insertions, 81 deletions
diff --git a/contrib/amd/amd/nfs_subr.c b/contrib/amd/amd/nfs_subr.c index c216b3e..80d3ca8 100644 --- a/contrib/amd/amd/nfs_subr.c +++ b/contrib/amd/amd/nfs_subr.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997-2004 Erez Zadok + * Copyright (c) 1997-2006 Erez Zadok * Copyright (c) 1990 Jan-Simon Pendry * Copyright (c) 1990 Imperial College of Science, Technology & Medicine * Copyright (c) 1990 The Regents of the University of California. @@ -36,9 +36,8 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * %W% (Berkeley) %G% * - * $Id: nfs_subr.c,v 1.6.2.6 2004/01/06 03:15:16 ezk Exp $ + * File: am-utils/amd/nfs_subr.c * */ @@ -57,19 +56,45 @@ # define nfs_error(e) ((nfsstat)(e)) #endif /* nfs_error */ +/* + * File Handle structure + * + * This is interpreted by indexing the exported array + * by fhh_id (for old-style filehandles), or by retrieving + * the node name from fhh_path (for new-style filehandles). + * + * The whole structure is mapped onto a standard fhandle_t + * when transmitted. + */ +struct am_fh { + u_int fhh_gen; /* generation number */ + union { + struct { + int fhh_type; /* old or new am_fh */ + pid_t fhh_pid; /* process id */ + int fhh_id; /* map id */ + } s; + char fhh_path[NFS_FHSIZE-sizeof(u_int)]; /* path to am_node */ + } u; +}; + + /* forward declarations */ +/* converting am-filehandles to mount-points */ +static am_node *fh_to_mp3(am_nfs_fh *fhp, int *rp, int vop); +static am_node *fh_to_mp(am_nfs_fh *fhp); static void count_map_entries(const am_node *mp, u_int *out_blocks, u_int *out_bfree, u_int *out_bavail); static char * -do_readlink(am_node *mp, int *error_return, nfsattrstat **attrpp) +do_readlink(am_node *mp, int *error_return) { char *ln; /* - * If there is a readlink method, then use - * that, otherwise if a link exists use - * that, otherwise use the mount point. + * If there is a readlink method then use it, + * otherwise if a link exists use that, + * otherwise use the mount point. */ if (mp->am_mnt->mf_ops->readlink) { int retry = 0; @@ -86,8 +111,6 @@ do_readlink(am_node *mp, int *error_return, nfsattrstat **attrpp) } else { ln = mp->am_mnt->mf_mount; } - if (attrpp) - *attrpp = &mp->am_attr; return ln; } @@ -108,46 +131,38 @@ nfsproc_getattr_2_svc(am_nfs_fh *argp, struct svc_req *rqstp) static nfsattrstat res; am_node *mp; int retry; - time_t now = clocktime(); + time_t now = clocktime(NULL); -#ifdef DEBUG - amuDebug(D_TRACE) + if (amuDebug(D_TRACE)) plog(XLOG_DEBUG, "getattr:"); -#endif /* DEBUG */ - mp = fh_to_mp2(argp, &retry); + mp = fh_to_mp3(argp, &retry, VLOOK_CREATE); if (mp == 0) { - -#ifdef DEBUG - amuDebug(D_TRACE) + if (amuDebug(D_TRACE)) plog(XLOG_DEBUG, "\tretry=%d", retry); -#endif /* DEBUG */ if (retry < 0) { amd_stats.d_drops++; return 0; } res.ns_status = nfs_error(retry); - } else { - nfsattrstat *attrp = &mp->am_attr; - -#ifdef DEBUG - amuDebug(D_TRACE) - plog(XLOG_DEBUG, "\tstat(%s), size = %d, mtime=%ld", - mp->am_path, - (int) attrp->ns_u.ns_attr_u.na_size, - (long) attrp->ns_u.ns_attr_u.na_mtime.nt_seconds); -#endif /* DEBUG */ - - /* Delay unmount of what was looked up */ - if (mp->am_timeo_w < 4 * gopt.am_timeo_w) - mp->am_timeo_w += gopt.am_timeo_w; - mp->am_ttl = now + mp->am_timeo_w; - - mp->am_stats.s_getattr++; - return attrp; + return &res; } + res = mp->am_attr; + if (amuDebug(D_TRACE)) + plog(XLOG_DEBUG, "\tstat(%s), size = %d, mtime=%ld.%ld", + mp->am_path, + (int) res.ns_u.ns_attr_u.na_size, + (long) res.ns_u.ns_attr_u.na_mtime.nt_seconds, + (long) res.ns_u.ns_attr_u.na_mtime.nt_useconds); + + /* Delay unmount of what was looked up */ + if (mp->am_timeo_w < 4 * gopt.am_timeo_w) + mp->am_timeo_w += gopt.am_timeo_w; + mp->am_ttl = now + mp->am_timeo_w; + + mp->am_stats.s_getattr++; return &res; } @@ -184,18 +199,16 @@ nfsproc_lookup_2_svc(nfsdiropargs *argp, struct svc_req *rqstp) uid_t uid; gid_t gid; -#ifdef DEBUG - amuDebug(D_TRACE) + if (amuDebug(D_TRACE)) plog(XLOG_DEBUG, "lookup:"); -#endif /* DEBUG */ /* finally, find the effective uid/gid from RPC request */ if (getcreds(rqstp, &uid, &gid, nfsxprt) < 0) plog(XLOG_ERROR, "cannot get uid/gid from RPC credentials"); - sprintf(opt_uid, "%d", (int) uid); - sprintf(opt_gid, "%d", (int) gid); + xsnprintf(opt_uid, sizeof(uid_str), "%d", (int) uid); + xsnprintf(opt_gid, sizeof(gid_str), "%d", (int) gid); - mp = fh_to_mp2(&argp->da_fhandle, &retry); + mp = fh_to_mp3(&argp->da_fhandle, &retry, VLOOK_CREATE); if (mp == 0) { if (retry < 0) { amd_stats.d_drops++; @@ -205,11 +218,11 @@ nfsproc_lookup_2_svc(nfsdiropargs *argp, struct svc_req *rqstp) } else { int error; am_node *ap; -#ifdef DEBUG - amuDebug(D_TRACE) - plog(XLOG_DEBUG, "\tlookuppn(%s, %s)", mp->am_path, argp->da_name); -#endif /* DEBUG */ - ap = (*mp->am_mnt->mf_ops->lookuppn) (mp, argp->da_name, &error, VLOOK_CREATE); + if (amuDebug(D_TRACE)) + plog(XLOG_DEBUG, "\tlookup(%s, %s)", mp->am_path, argp->da_name); + ap = mp->am_mnt->mf_ops->lookup_child(mp, argp->da_name, &error, VLOOK_CREATE); + if (ap && error < 0) + ap = mp->am_mnt->mf_ops->mount_child(ap, &error); if (ap == 0) { if (error < 0) { amd_stats.d_drops++; @@ -237,7 +250,7 @@ nfsproc_lookup_2_svc(nfsdiropargs *argp, struct svc_req *rqstp) void -quick_reply(am_node *mp, int error) +nfs_quick_reply(am_node *mp, int error) { SVCXPRT *transp = mp->am_transp; nfsdiropres res; @@ -271,11 +284,8 @@ quick_reply(am_node *mp, int error) /* * Free up transp. It's only used for one reply. */ - XFREE(transp); - mp->am_transp = NULL; -#ifdef DEBUG + XFREE(mp->am_transp); dlog("Quick reply sent for %s", mp->am_mnt->mf_mount); -#endif /* DEBUG */ } } @@ -287,12 +297,10 @@ nfsproc_readlink_2_svc(am_nfs_fh *argp, struct svc_req *rqstp) am_node *mp; int retry; -#ifdef DEBUG - amuDebug(D_TRACE) + if (amuDebug(D_TRACE)) plog(XLOG_DEBUG, "readlink:"); -#endif /* DEBUG */ - mp = fh_to_mp2(argp, &retry); + mp = fh_to_mp3(argp, &retry, VLOOK_CREATE); if (mp == 0) { readlink_retry: if (retry < 0) { @@ -301,15 +309,12 @@ nfsproc_readlink_2_svc(am_nfs_fh *argp, struct svc_req *rqstp) } res.rlr_status = nfs_error(retry); } else { - char *ln = do_readlink(mp, &retry, (nfsattrstat **) 0); + char *ln = do_readlink(mp, &retry); if (ln == 0) goto readlink_retry; res.rlr_status = NFS_OK; -#ifdef DEBUG - amuDebug(D_TRACE) - if (ln) - plog(XLOG_DEBUG, "\treadlink(%s) = %s", mp->am_path, ln); -#endif /* DEBUG */ + if (amuDebug(D_TRACE) && ln) + plog(XLOG_DEBUG, "\treadlink(%s) = %s", mp->am_path, ln); res.rlr_u.rlr_data_u = ln; mp->am_stats.s_readlink++; } @@ -388,12 +393,10 @@ unlink_or_rmdir(nfsdiropargs *argp, struct svc_req *rqstp, int unlinkp) goto out; } -#ifdef DEBUG - amuDebug(D_TRACE) + if (amuDebug(D_TRACE)) plog(XLOG_DEBUG, "\tremove(%s, %s)", mp->am_path, argp->da_name); -#endif /* DEBUG */ - mp = (*mp->am_mnt->mf_ops->lookuppn) (mp, argp->da_name, &retry, VLOOK_DELETE); + mp = mp->am_mnt->mf_ops->lookup_child(mp, argp->da_name, &retry, VLOOK_DELETE); if (mp == 0) { /* * Ignore retries... @@ -503,12 +506,10 @@ nfsproc_readdir_2_svc(nfsreaddirargs *argp, struct svc_req *rqstp) am_node *mp; int retry; -#ifdef DEBUG - amuDebug(D_TRACE) + if (amuDebug(D_TRACE)) plog(XLOG_DEBUG, "readdir:"); -#endif /* DEBUG */ - mp = fh_to_mp2(&argp->rda_fhandle, &retry); + mp = fh_to_mp3(&argp->rda_fhandle, &retry, VLOOK_CREATE); if (mp == 0) { if (retry < 0) { amd_stats.d_drops++; @@ -516,10 +517,8 @@ nfsproc_readdir_2_svc(nfsreaddirargs *argp, struct svc_req *rqstp) } res.rdr_status = nfs_error(retry); } else { -#ifdef DEBUG - amuDebug(D_TRACE) + if (amuDebug(D_TRACE)) plog(XLOG_DEBUG, "\treaddir(%s)", mp->am_path); -#endif /* DEBUG */ res.rdr_status = nfs_error((*mp->am_mnt->mf_ops->readdir) (mp, argp->rda_cookie, &res.rdr_u.rdr_reply_u, e_res, argp->rda_count)); @@ -538,12 +537,10 @@ nfsproc_statfs_2_svc(am_nfs_fh *argp, struct svc_req *rqstp) int retry; mntent_t mnt; -#ifdef DEBUG - amuDebug(D_TRACE) + if (amuDebug(D_TRACE)) plog(XLOG_DEBUG, "statfs:"); -#endif /* DEBUG */ - mp = fh_to_mp2(argp, &retry); + mp = fh_to_mp3(argp, &retry, VLOOK_CREATE); if (mp == 0) { if (retry < 0) { amd_stats.d_drops++; @@ -552,10 +549,8 @@ nfsproc_statfs_2_svc(am_nfs_fh *argp, struct svc_req *rqstp) res.sfr_status = nfs_error(retry); } else { nfsstatfsokres *fp; -#ifdef DEBUG - amuDebug(D_TRACE) + if (amuDebug(D_TRACE)) plog(XLOG_DEBUG, "\tstat_fs(%s)", mp->am_path); -#endif /* DEBUG */ /* * just return faked up file system information @@ -569,7 +564,7 @@ nfsproc_statfs_2_svc(am_nfs_fh *argp, struct svc_req *rqstp) if ((gopt.flags & CFM_SHOW_STATFS_ENTRIES) && mp->am_mnt && mp->am_mnt->mf_mopts) { mnt.mnt_opts = mp->am_mnt->mf_mopts; - if (hasmntopt(&mnt, "browsable")) { + if (amu_hasmntopt(&mnt, "browsable")) { count_map_entries(mp, &fp->sfrok_blocks, &fp->sfrok_bfree, @@ -629,3 +624,205 @@ out: *out_bfree = bfree; *out_bavail = bavail; } + + +/* + * 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 = 0; + + 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 = 0; + + /* + * 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_mnt && FSRV_ISDOWN(ap->am_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_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_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_mnt->mf_ops->mount_child(ap, &error); + } else { + ap = 0; + 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 + + /* + * Disallow references to objects being unmounted, unless + * they are automount points. + */ + if (ap->am_mnt && (ap->am_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_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; +} + + +static am_node * +fh_to_mp(am_nfs_fh *fhp) +{ + int dummy; + + return fh_to_mp3(fhp, &dummy, VLOOK_CREATE); +} + + +/* + * 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); */ + } +} |