summaryrefslogtreecommitdiffstats
path: root/contrib/amd/amd/nfs_subr.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/amd/amd/nfs_subr.c')
-rw-r--r--contrib/amd/amd/nfs_subr.c359
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); */
+ }
+}
OpenPOWER on IntegriCloud