summaryrefslogtreecommitdiffstats
path: root/contrib/amd/amd/ops_nfs.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/amd/amd/ops_nfs.c')
-rw-r--r--contrib/amd/amd/ops_nfs.c628
1 files changed, 433 insertions, 195 deletions
diff --git a/contrib/amd/amd/ops_nfs.c b/contrib/amd/amd/ops_nfs.c
index 5f6a474..a6a8585 100644
--- a/contrib/amd/amd/ops_nfs.c
+++ b/contrib/amd/amd/ops_nfs.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: ops_nfs.c,v 1.6.2.6 2004/01/06 03:15:16 ezk Exp $
+ * File: am-utils/amd/ops_nfs.c
*
*/
@@ -64,7 +63,7 @@
*/
#define FH_TTL (5 * 60) /* five minutes */
#define FH_TTL_ERROR (30) /* 30 seconds */
-#define FHID_ALLOC(struct) (++fh_id)
+#define FHID_ALLOC() (++fh_id)
/*
* The NFS layer maintains a cache of file handles.
@@ -92,19 +91,26 @@
typedef struct fh_cache fh_cache;
struct fh_cache {
qelem fh_q; /* List header */
- voidp fh_wchan; /* Wait channel */
+ wchan_t fh_wchan; /* Wait channel */
int fh_error; /* Valid data? */
int fh_id; /* Unique id */
int fh_cid; /* Callout id */
u_long fh_nfs_version; /* highest NFS version on host */
am_nfs_handle_t fh_nfs_handle; /* Handle on filesystem */
+ int fh_status; /* Status of last rpc */
struct sockaddr_in fh_sin; /* Address of mountd */
fserver *fh_fs; /* Server holding filesystem */
char *fh_path; /* Filesystem on host */
};
/* forward definitions */
-static int call_mountd(fh_cache *fp, u_long proc, fwd_fun f, voidp wchan);
+static int nfs_init(mntfs *mf);
+static char *nfs_match(am_opts *fo);
+static int nfs_mount(am_node *am, mntfs *mf);
+static int nfs_umount(am_node *am, mntfs *mf);
+static void nfs_umounted(mntfs *mf);
+static int call_mountd(fh_cache *fp, u_long proc, fwd_fun f, wchan_t wchan);
+static int webnfs_lookup(fh_cache *fp, fwd_fun f, wchan_t wchan);
static int fh_id = 0;
/* globals */
@@ -119,25 +125,28 @@ am_ops nfs_ops =
"nfs",
nfs_match,
nfs_init,
- amfs_auto_fmount,
- nfs_fmount,
- amfs_auto_fumount,
- nfs_fumount,
- amfs_error_lookuppn,
+ nfs_mount,
+ nfs_umount,
+ amfs_error_lookup_child,
+ amfs_error_mount_child,
amfs_error_readdir,
0, /* nfs_readlink */
0, /* nfs_mounted */
nfs_umounted,
find_nfs_srvr,
- FS_MKMNT | FS_BACKGROUND | FS_AMQINFO
+ 0, /* nfs_get_wchan */
+ FS_MKMNT | FS_BACKGROUND | FS_AMQINFO, /* nfs_fs_flags */
+#ifdef HAVE_FS_AUTOFS
+ AUTOFS_NFS_FS_FLAGS,
+#endif /* HAVE_FS_AUTOFS */
};
static fh_cache *
-find_nfs_fhandle_cache(voidp idv, int done)
+find_nfs_fhandle_cache(opaque_t arg, int done)
{
fh_cache *fp, *fp2 = 0;
- int id = (long) idv; /* for 64-bit archs */
+ int id = (long) arg; /* for 64-bit archs */
ITER(fp, fh_cache, &fh_head) {
if (fp->fh_id == id) {
@@ -146,13 +155,11 @@ find_nfs_fhandle_cache(voidp idv, int done)
}
}
-#ifdef DEBUG
if (fp2) {
dlog("fh cache gives fp %#lx, fs %s", (unsigned long) fp2, fp2->fh_path);
} else {
dlog("fh cache search failed");
}
-#endif /* DEBUG */
if (fp2 && !done) {
fp2->fh_error = ETIMEDOUT;
@@ -164,14 +171,18 @@ find_nfs_fhandle_cache(voidp idv, int done)
/*
- * Called when a filehandle appears
+ * Called when a filehandle appears via the mount protocol
*/
static void
-got_nfs_fh(voidp pkt, int len, struct sockaddr_in *sa, struct sockaddr_in *ia, voidp idv, int done)
+got_nfs_fh_mount(voidp pkt, int len, struct sockaddr_in *sa, struct sockaddr_in *ia, opaque_t arg, int done)
{
fh_cache *fp;
+ struct fhstatus res;
+#ifdef HAVE_FS_NFS3
+ struct am_mountres3 res3;
+#endif /* HAVE_FS_NFS3 */
- fp = find_nfs_fhandle_cache(idv, done);
+ fp = find_nfs_fhandle_cache(arg, done);
if (!fp)
return;
@@ -180,28 +191,109 @@ got_nfs_fh(voidp pkt, int len, struct sockaddr_in *sa, struct sockaddr_in *ia, v
* NFS protocol version.
*/
#ifdef HAVE_FS_NFS3
- if (fp->fh_nfs_version == NFS_VERSION3)
- fp->fh_error = pickup_rpc_reply(pkt, len, (voidp) &fp->fh_nfs_handle.v3,
- (XDRPROC_T_TYPE) xdr_mountres3);
- else
+ if (fp->fh_nfs_version == NFS_VERSION3) {
+ memset(&res3, 0, sizeof(res3));
+ fp->fh_error = pickup_rpc_reply(pkt, len, (voidp) &res3,
+ (XDRPROC_T_TYPE) xdr_am_mountres3);
+ fp->fh_status = unx_error(res3.fhs_status);
+ memset(&fp->fh_nfs_handle.v3, 0, sizeof(am_nfs_fh3));
+ fp->fh_nfs_handle.v3.am_fh3_length = res3.mountres3_u.mountinfo.fhandle.fhandle3_len;
+ memmove(fp->fh_nfs_handle.v3.am_fh3_data,
+ res3.mountres3_u.mountinfo.fhandle.fhandle3_val,
+ fp->fh_nfs_handle.v3.am_fh3_length);
+ } else {
#endif /* HAVE_FS_NFS3 */
- fp->fh_error = pickup_rpc_reply(pkt, len, (voidp) &fp->fh_nfs_handle.v2,
+ memset(&res, 0, sizeof(res));
+ fp->fh_error = pickup_rpc_reply(pkt, len, (voidp) &res,
(XDRPROC_T_TYPE) xdr_fhstatus);
+ fp->fh_status = unx_error(res.fhs_status);
+ memmove(&fp->fh_nfs_handle.v2, &res.fhs_fh, NFS_FHSIZE);
+#ifdef HAVE_FS_NFS3
+ }
+#endif /* HAVE_FS_NFS3 */
if (!fp->fh_error) {
-#ifdef DEBUG
dlog("got filehandle for %s:%s", fp->fh_fs->fs_host, fp->fh_path);
-#endif /* DEBUG */
+ } else {
+ plog(XLOG_USER, "filehandle denied for %s:%s", fp->fh_fs->fs_host, fp->fh_path);
+ /*
+ * Force the error to be EACCES. It's debatable whether it should be
+ * ENOENT instead, but the server really doesn't give us any clues, and
+ * EACCES is more in line with the "filehandle denied" message.
+ */
+ fp->fh_error = EACCES;
+ }
+
+ /*
+ * Wakeup anything sleeping on this filehandle
+ */
+ if (fp->fh_wchan) {
+ dlog("Calling wakeup on %#lx", (unsigned long) fp->fh_wchan);
+ wakeup(fp->fh_wchan);
+ }
+}
+
+/*
+ * Called when a filehandle appears via WebNFS
+ */
+static void
+got_nfs_fh_webnfs(voidp pkt, int len, struct sockaddr_in *sa, struct sockaddr_in *ia, opaque_t arg, int done)
+{
+ fh_cache *fp;
+ nfsdiropres res;
+#ifdef HAVE_FS_NFS3
+ am_LOOKUP3res res3;
+#endif /* HAVE_FS_NFS3 */
+
+ fp = find_nfs_fhandle_cache(arg, done);
+ if (!fp)
+ return;
+
+ /*
+ * retrieve the correct RPC reply for the file handle, based on the
+ * NFS protocol version.
+ */
+#ifdef HAVE_FS_NFS3
+ if (fp->fh_nfs_version == NFS_VERSION3) {
+ memset(&res3, 0, sizeof(res3));
+ fp->fh_error = pickup_rpc_reply(pkt, len, (voidp) &res3,
+ (XDRPROC_T_TYPE) xdr_am_LOOKUP3res);
+ fp->fh_status = unx_error(res3.status);
+ memset(&fp->fh_nfs_handle.v3, 0, sizeof(am_nfs_fh3));
+ fp->fh_nfs_handle.v3.am_fh3_length = res3.res_u.ok.object.am_fh3_length;
+ memmove(fp->fh_nfs_handle.v3.am_fh3_data,
+ res3.res_u.ok.object.am_fh3_data,
+ fp->fh_nfs_handle.v3.am_fh3_length);
+ } else {
+#endif /* HAVE_FS_NFS3 */
+ memset(&res, 0, sizeof(res));
+ fp->fh_error = pickup_rpc_reply(pkt, len, (voidp) &res,
+ (XDRPROC_T_TYPE) xdr_diropres);
+ fp->fh_status = unx_error(res.dr_status);
+ memmove(&fp->fh_nfs_handle.v2, &res.dr_u.dr_drok_u.drok_fhandle, NFS_FHSIZE);
+#ifdef HAVE_FS_NFS3
+ }
+#endif /* HAVE_FS_NFS3 */
+
+ if (!fp->fh_error) {
+ dlog("got filehandle for %s:%s", fp->fh_fs->fs_host, fp->fh_path);
+ } else {
+ plog(XLOG_USER, "filehandle denied for %s:%s", fp->fh_fs->fs_host, fp->fh_path);
/*
- * Wakeup anything sleeping on this filehandle
+ * Force the error to be EACCES. It's debatable whether it should be
+ * ENOENT instead, but the server really doesn't give us any clues, and
+ * EACCES is more in line with the "filehandle denied" message.
*/
- if (fp->fh_wchan) {
-#ifdef DEBUG
- dlog("Calling wakeup on %#lx", (unsigned long) fp->fh_wchan);
-#endif /* DEBUG */
- wakeup(fp->fh_wchan);
- }
+ fp->fh_error = EACCES;
+ }
+
+ /*
+ * Wakeup anything sleeping on this filehandle
+ */
+ if (fp->fh_wchan) {
+ dlog("Calling wakeup on %#lx", (unsigned long) fp->fh_wchan);
+ wakeup(fp->fh_wchan);
}
}
@@ -212,8 +304,12 @@ flush_nfs_fhandle_cache(fserver *fs)
fh_cache *fp;
ITER(fp, fh_cache, &fh_head) {
- if (fp->fh_fs == fs || fs == 0) {
- fp->fh_sin.sin_port = (u_short) 0;
+ if (fp->fh_fs == fs || fs == NULL) {
+ /*
+ * Only invalidate port info for non-WebNFS servers
+ */
+ if (!(fp->fh_fs->fs_flags & FSF_WEBNFS))
+ fp->fh_sin.sin_port = (u_short) 0;
fp->fh_error = -1;
}
}
@@ -221,15 +317,13 @@ flush_nfs_fhandle_cache(fserver *fs)
static void
-discard_fh(voidp v)
+discard_fh(opaque_t arg)
{
- fh_cache *fp = v;
+ fh_cache *fp = (fh_cache *) arg;
rem_que(&fp->fh_q);
if (fp->fh_fs) {
-#ifdef DEBUG
dlog("Discarding filehandle for %s:%s", fp->fh_fs->fs_host, fp->fh_path);
-#endif /* DEBUG */
free_srvr(fp->fh_fs);
}
if (fp->fh_path)
@@ -242,88 +336,92 @@ discard_fh(voidp v)
* Determine the file handle for a node
*/
static int
-prime_nfs_fhandle_cache(char *path, fserver *fs, am_nfs_handle_t *fhbuf, voidp wchan)
+prime_nfs_fhandle_cache(char *path, fserver *fs, am_nfs_handle_t *fhbuf, mntfs *mf)
{
fh_cache *fp, *fp_save = 0;
int error;
int reuse_id = FALSE;
-#ifdef DEBUG
dlog("Searching cache for %s:%s", fs->fs_host, path);
-#endif /* DEBUG */
/*
* First search the cache
*/
ITER(fp, fh_cache, &fh_head) {
- if (fs == fp->fh_fs && STREQ(path, fp->fh_path)) {
- switch (fp->fh_error) {
- case 0:
- plog(XLOG_INFO, "prime_nfs_fhandle_cache: NFS version %d", (int) fp->fh_nfs_version);
-#ifdef HAVE_FS_NFS3
- if (fp->fh_nfs_version == NFS_VERSION3)
- error = fp->fh_error = unx_error(fp->fh_nfs_handle.v3.fhs_status);
- else
-#endif /* HAVE_FS_NFS3 */
- error = fp->fh_error = unx_error(fp->fh_nfs_handle.v2.fhs_status);
- if (error == 0) {
- if (fhbuf) {
+ if (fs != fp->fh_fs || !STREQ(path, fp->fh_path))
+ continue; /* skip to next ITER item */
+ /* else we got a match */
+ switch (fp->fh_error) {
+ case 0:
+ plog(XLOG_INFO, "prime_nfs_fhandle_cache: NFS version %d", (int) fp->fh_nfs_version);
+
+ error = fp->fh_error = fp->fh_status;
+
+ if (error == 0) {
+ if (mf->mf_flags & MFF_NFS_SCALEDOWN) {
+ fp_save = fp;
+ /* XXX: why reuse the ID? */
+ reuse_id = TRUE;
+ break;
+ }
+
+ if (fhbuf) {
#ifdef HAVE_FS_NFS3
- if (fp->fh_nfs_version == NFS_VERSION3)
- memmove((voidp) &(fhbuf->v3), (voidp) &(fp->fh_nfs_handle.v3),
- sizeof(fp->fh_nfs_handle.v3));
- else
+ if (fp->fh_nfs_version == NFS_VERSION3) {
+ memmove((voidp) &(fhbuf->v3), (voidp) &(fp->fh_nfs_handle.v3),
+ sizeof(fp->fh_nfs_handle.v3));
+ } else
#endif /* HAVE_FS_NFS3 */
+ {
memmove((voidp) &(fhbuf->v2), (voidp) &(fp->fh_nfs_handle.v2),
sizeof(fp->fh_nfs_handle.v2));
- }
- if (fp->fh_cid)
- untimeout(fp->fh_cid);
- fp->fh_cid = timeout(FH_TTL, discard_fh, (voidp) fp);
- } else if (error == EACCES) {
- /*
- * Now decode the file handle return code.
- */
- plog(XLOG_INFO, "Filehandle denied for \"%s:%s\"",
- fs->fs_host, path);
- } else {
- errno = error; /* XXX */
- plog(XLOG_INFO, "Filehandle error for \"%s:%s\": %m",
- fs->fs_host, path);
+ }
}
-
+ if (fp->fh_cid)
+ untimeout(fp->fh_cid);
+ fp->fh_cid = timeout(FH_TTL, discard_fh, (opaque_t) fp);
+ } else if (error == EACCES) {
/*
- * The error was returned from the remote mount daemon.
- * Policy: this error will be cached for now...
+ * Now decode the file handle return code.
*/
- return error;
+ plog(XLOG_INFO, "Filehandle denied for \"%s:%s\"",
+ fs->fs_host, path);
+ } else {
+ errno = error; /* XXX */
+ plog(XLOG_INFO, "Filehandle error for \"%s:%s\": %m",
+ fs->fs_host, path);
+ }
- case -1:
- /*
- * Still thinking about it, but we can re-use.
- */
- fp_save = fp;
- reuse_id = TRUE;
- break;
+ /*
+ * The error was returned from the remote mount daemon.
+ * Policy: this error will be cached for now...
+ */
+ return error;
- default:
- /*
- * Return the error.
- * Policy: make sure we recompute if required again
- * in case this was caused by a network failure.
- * This can thrash mountd's though... If you find
- * your mountd going slowly then:
- * 1. Add a fork() loop to main.
- * 2. Remove the call to innetgr() and don't use
- * netgroups, especially if you don't use YP.
- */
- error = fp->fh_error;
- fp->fh_error = -1;
- return error;
- }
+ case -1:
+ /*
+ * Still thinking about it, but we can re-use.
+ */
+ fp_save = fp;
+ reuse_id = TRUE;
break;
- }
- }
+
+ default:
+ /*
+ * Return the error.
+ * Policy: make sure we recompute if required again
+ * in case this was caused by a network failure.
+ * This can thrash mountd's though... If you find
+ * your mountd going slowly then:
+ * 1. Add a fork() loop to main.
+ * 2. Remove the call to innetgr() and don't use
+ * netgroups, especially if you don't use YP.
+ */
+ error = fp->fh_error;
+ fp->fh_error = -1;
+ return error;
+ } /* end of switch statement */
+ } /* end of ITER loop */
/*
* Not in cache
@@ -342,13 +440,13 @@ prime_nfs_fhandle_cache(char *path, fserver *fs, am_nfs_handle_t *fhbuf, voidp w
ins_que(&fp->fh_q, &fh_head);
}
if (!reuse_id)
- fp->fh_id = FHID_ALLOC(struct );
- fp->fh_wchan = wchan;
+ fp->fh_id = FHID_ALLOC();
+ fp->fh_wchan = get_mntfs_wchan(mf);
fp->fh_error = -1;
- fp->fh_cid = timeout(FH_TTL, discard_fh, (voidp) fp);
+ fp->fh_cid = timeout(FH_TTL, discard_fh, (opaque_t) fp);
/*
- * if fs->fs_ip is null, remote server is probably down.
+ * If fs->fs_ip is null, remote server is probably down.
*/
if (!fs->fs_ip) {
/* Mark the fileserver down and invalid again */
@@ -359,18 +457,25 @@ prime_nfs_fhandle_cache(char *path, fserver *fs, am_nfs_handle_t *fhbuf, voidp w
}
/*
- * If the address has changed then don't try to re-use the
- * port information
+ * Either fp has been freshly allocated or the address has changed.
+ * Initialize address and nfs version. Don't try to re-use the port
+ * information unless using WebNFS where the port is fixed either by
+ * the spec or the "port" mount option.
*/
if (fp->fh_sin.sin_addr.s_addr != fs->fs_ip->sin_addr.s_addr) {
fp->fh_sin = *fs->fs_ip;
- fp->fh_sin.sin_port = 0;
+ if (!(mf->mf_flags & MFF_WEBNFS))
+ fp->fh_sin.sin_port = 0;
fp->fh_nfs_version = fs->fs_version;
}
+
fp->fh_fs = dup_srvr(fs);
fp->fh_path = strdup(path);
- error = call_mountd(fp, MOUNTPROC_MNT, got_nfs_fh, wchan);
+ if (mf->mf_flags & MFF_WEBNFS)
+ error = webnfs_lookup(fp, got_nfs_fh_webnfs, get_mntfs_wchan(mf));
+ else
+ error = call_mountd(fp, MOUNTPROC_MNT, got_nfs_fh_mount, get_mntfs_wchan(mf));
if (error) {
/*
* Local error - cache for a short period
@@ -378,7 +483,7 @@ prime_nfs_fhandle_cache(char *path, fserver *fs, am_nfs_handle_t *fhbuf, voidp w
*/
untimeout(fp->fh_cid);
fp->fh_cid = timeout(error < 0 ? 2 * ALLOWED_MOUNT_TIME : FH_TTL_ERROR,
- discard_fh, (voidp) fp);
+ discard_fh, (opaque_t) fp);
fp->fh_error = error;
} else {
error = fp->fh_error;
@@ -419,11 +524,11 @@ make_nfs_auth(void)
static int
-call_mountd(fh_cache *fp, u_long proc, fwd_fun f, voidp wchan)
+call_mountd(fh_cache *fp, u_long proc, fwd_fun fun, wchan_t wchan)
{
struct rpc_msg mnt_msg;
int len;
- char iobuf[8192];
+ char iobuf[UDPMSGSIZE];
int error;
u_long mnt_version;
@@ -434,17 +539,17 @@ call_mountd(fh_cache *fp, u_long proc, fwd_fun f, voidp wchan)
}
if (fp->fh_sin.sin_port == 0) {
- u_short port;
- error = nfs_srvr_port(fp->fh_fs, &port, wchan);
+ u_short mountd_port;
+ error = get_mountd_port(fp->fh_fs, &mountd_port, wchan);
if (error)
return error;
- fp->fh_sin.sin_port = port;
+ fp->fh_sin.sin_port = mountd_port;
}
/* find the right version of the mount protocol */
#ifdef HAVE_FS_NFS3
if (fp->fh_nfs_version == NFS_VERSION3)
- mnt_version = MOUNTVERS3;
+ mnt_version = AM_MOUNTVERS3;
else
#endif /* HAVE_FS_NFS3 */
mnt_version = MOUNTVERS;
@@ -462,40 +567,128 @@ call_mountd(fh_cache *fp, u_long proc, fwd_fun f, voidp wchan)
if (len > 0) {
error = fwd_packet(MK_RPC_XID(RPC_XID_MOUNTD, fp->fh_id),
- (voidp) iobuf,
+ iobuf,
len,
&fp->fh_sin,
&fp->fh_sin,
- (voidp) ((long) fp->fh_id), /* for 64-bit archs */
- f);
+ (opaque_t) ((long) fp->fh_id), /* cast to long needed for 64-bit archs */
+ fun);
} else {
error = -len;
}
-/*
- * It may be the case that we're sending to the wrong MOUNTD port. This
- * occurs if mountd is restarted on the server after the port has been
- * looked up and stored in the filehandle cache somewhere. The correct
- * solution, if we're going to cache port numbers is to catch the ICMP
- * port unreachable reply from the server and cause the portmap request
- * to be redone. The quick solution here is to invalidate the MOUNTD
- * port.
- */
+ /*
+ * It may be the case that we're sending to the wrong MOUNTD port. This
+ * occurs if mountd is restarted on the server after the port has been
+ * looked up and stored in the filehandle cache somewhere. The correct
+ * solution, if we're going to cache port numbers is to catch the ICMP
+ * port unreachable reply from the server and cause the portmap request
+ * to be redone. The quick solution here is to invalidate the MOUNTD
+ * port.
+ */
fp->fh_sin.sin_port = 0;
return error;
}
+static int
+webnfs_lookup(fh_cache *fp, fwd_fun fun, wchan_t wchan)
+{
+ struct rpc_msg wnfs_msg;
+ int len;
+ char iobuf[UDPMSGSIZE];
+ int error;
+ u_long proc;
+ XDRPROC_T_TYPE xdr_fn;
+ voidp argp;
+ nfsdiropargs args;
+#ifdef HAVE_FS_NFS3
+ am_LOOKUP3args args3;
+#endif
+ char *wnfs_path;
+ size_t l;
+
+ if (!nfs_auth) {
+ error = make_nfs_auth();
+ if (error)
+ return error;
+ }
+
+ if (fp->fh_sin.sin_port == 0) {
+ /* FIXME: wrong, don't discard sin_port in the first place for WebNFS. */
+ plog(XLOG_WARNING, "webnfs_lookup: port == 0 for nfs on %s, fixed",
+ fp->fh_fs->fs_host);
+ fp->fh_sin.sin_port = htons(NFS_PORT);
+ }
+
+ /*
+ * Use native path like the rest of amd (cf. RFC 2054, 6.1).
+ */
+ l = strlen(fp->fh_path) + 2;
+ wnfs_path = (char *) xmalloc(l);
+ wnfs_path[0] = 0x80;
+ xstrlcpy(wnfs_path + 1, fp->fh_path, l - 1);
+
+ /* find the right program and lookup procedure */
+#ifdef HAVE_FS_NFS3
+ if (fp->fh_nfs_version == NFS_VERSION3) {
+ proc = AM_NFSPROC3_LOOKUP;
+ xdr_fn = (XDRPROC_T_TYPE) xdr_am_LOOKUP3args;
+ argp = &args3;
+ /* WebNFS public file handle */
+ args3.what.dir.am_fh3_length = 0;
+ args3.what.name = wnfs_path;
+ } else {
+#endif /* HAVE_FS_NFS3 */
+ proc = NFSPROC_LOOKUP;
+ xdr_fn = (XDRPROC_T_TYPE) xdr_diropargs;
+ argp = &args;
+ /* WebNFS public file handle */
+ memset(&args.da_fhandle, 0, NFS_FHSIZE);
+ args.da_name = wnfs_path;
+#ifdef HAVE_FS_NFS3
+ }
+#endif /* HAVE_FS_NFS3 */
+
+ plog(XLOG_INFO, "webnfs_lookup: NFS version %d", (int) fp->fh_nfs_version);
+
+ rpc_msg_init(&wnfs_msg, NFS_PROGRAM, fp->fh_nfs_version, proc);
+ len = make_rpc_packet(iobuf,
+ sizeof(iobuf),
+ proc,
+ &wnfs_msg,
+ argp,
+ (XDRPROC_T_TYPE) xdr_fn,
+ nfs_auth);
+
+ if (len > 0) {
+ error = fwd_packet(MK_RPC_XID(RPC_XID_WEBNFS, fp->fh_id),
+ iobuf,
+ len,
+ &fp->fh_sin,
+ &fp->fh_sin,
+ (opaque_t) ((long) fp->fh_id), /* cast to long needed for 64-bit archs */
+ fun);
+ } else {
+ error = -len;
+ }
+
+ XFREE(wnfs_path);
+ return error;
+}
+
+
/*
* NFS needs the local filesystem, remote filesystem
* remote hostname.
* Local filesystem defaults to remote and vice-versa.
*/
-char *
+static char *
nfs_match(am_opts *fo)
{
char *xmtab;
+ size_t l;
if (fo->opt_fs && !fo->opt_rfs)
fo->opt_rfs = fo->opt_fs;
@@ -511,12 +704,11 @@ nfs_match(am_opts *fo)
/*
* Determine magic cookie to put in mtab
*/
- xmtab = (char *) xmalloc(strlen(fo->opt_rhost) + strlen(fo->opt_rfs) + 2);
- sprintf(xmtab, "%s:%s", fo->opt_rhost, fo->opt_rfs);
-#ifdef DEBUG
+ l = strlen(fo->opt_rhost) + strlen(fo->opt_rfs) + 2;
+ xmtab = (char *) xmalloc(l);
+ xsnprintf(xmtab, l, "%s:%s", fo->opt_rhost, fo->opt_rfs);
dlog("NFS: mounting remote server \"%s\", remote fs \"%s\" on \"%s\"",
fo->opt_rhost, fo->opt_rfs, fo->opt_fs);
-#endif /* DEBUG */
return xmtab;
}
@@ -525,24 +717,36 @@ nfs_match(am_opts *fo)
/*
* Initialize am structure for nfs
*/
-int
+static int
nfs_init(mntfs *mf)
{
int error;
am_nfs_handle_t fhs;
char *colon;
- if (mf->mf_private)
- return 0;
+ if (mf->mf_private) {
+ if (mf->mf_flags & MFF_NFS_SCALEDOWN) {
+ fserver *fs;
+
+ /* tell remote mountd that we're done with this filehandle */
+ mf->mf_ops->umounted(mf);
+
+ mf->mf_prfree(mf->mf_private);
+ fs = mf->mf_ops->ffserver(mf);
+ free_srvr(mf->mf_server);
+ mf->mf_server = fs;
+ } else
+ return 0;
+ }
colon = strchr(mf->mf_info, ':');
if (colon == 0)
return ENOENT;
- error = prime_nfs_fhandle_cache(colon + 1, mf->mf_server, &fhs, (voidp) mf);
+ error = prime_nfs_fhandle_cache(colon + 1, mf->mf_server, &fhs, mf);
if (!error) {
- mf->mf_private = (voidp) ALLOC(am_nfs_handle_t);
- mf->mf_prfree = (void (*)(voidp)) free;
+ mf->mf_private = (opaque_t) ALLOC(am_nfs_handle_t);
+ mf->mf_prfree = (void (*)(opaque_t)) free;
memmove(mf->mf_private, (voidp) &fhs, sizeof(fhs));
}
return error;
@@ -550,18 +754,20 @@ nfs_init(mntfs *mf)
int
-mount_nfs_fh(am_nfs_handle_t *fhp, char *dir, char *fs_name, char *opts, mntfs *mf)
+mount_nfs_fh(am_nfs_handle_t *fhp, char *mntdir, char *fs_name, mntfs *mf)
{
MTYPE_TYPE type;
char *colon;
- char *xopts;
+ char *xopts=NULL, transp_timeo_opts[40], transp_retrans_opts[40];
char host[MAXHOSTNAMELEN + MAXPATHLEN + 2];
fserver *fs = mf->mf_server;
u_long nfs_version = fs->fs_version;
char *nfs_proto = fs->fs_proto; /* "tcp" or "udp" */
+ int on_autofs = mf->mf_flags & MFF_ON_AUTOFS;
int error;
int genflags;
int retry;
+ int proto = AMU_TYPE_NONE;
mntent_t mnt;
nfs_args_t nfs_args;
@@ -575,26 +781,48 @@ mount_nfs_fh(am_nfs_handle_t *fhp, char *dir, char *fs_name, char *opts, mntfs *
#ifdef MOUNT_TABLE_ON_FILE
*colon = '\0';
#endif /* MOUNT_TABLE_ON_FILE */
- strncpy(host, fs_name, sizeof(host));
+ xstrlcpy(host, fs_name, sizeof(host));
#ifdef MOUNT_TABLE_ON_FILE
*colon = ':';
#endif /* MOUNT_TABLE_ON_FILE */
#ifdef MAXHOSTNAMELEN
/* most kernels have a name length restriction */
if (strlen(host) >= MAXHOSTNAMELEN)
- strcpy(host + MAXHOSTNAMELEN - 3, "..");
+ xstrlcpy(host + MAXHOSTNAMELEN - 3, "..",
+ sizeof(host) - MAXHOSTNAMELEN + 3);
#endif /* MAXHOSTNAMELEN */
+ /*
+ * Create option=VAL for udp/tcp specific timeouts and retrans values, but
+ * only if these options were specified.
+ */
+
+ transp_timeo_opts[0] = transp_retrans_opts[0] = '\0'; /* initialize */
+ if (STREQ(nfs_proto, "udp"))
+ proto = AMU_TYPE_UDP;
+ else if (STREQ(nfs_proto, "tcp"))
+ proto = AMU_TYPE_TCP;
+ if (proto != AMU_TYPE_NONE) {
+ if (gopt.amfs_auto_timeo[proto] > 0)
+ xsnprintf(transp_timeo_opts, sizeof(transp_timeo_opts), "%s=%d,",
+ MNTTAB_OPT_TIMEO, gopt.amfs_auto_timeo[proto]);
+ if (gopt.amfs_auto_retrans[proto] > 0)
+ xsnprintf(transp_retrans_opts, sizeof(transp_retrans_opts), "%s=%d,",
+ MNTTAB_OPT_RETRANS, gopt.amfs_auto_retrans[proto]);
+ }
+
if (mf->mf_remopts && *mf->mf_remopts &&
!islocalnet(fs->fs_ip->sin_addr.s_addr)) {
plog(XLOG_INFO, "Using remopts=\"%s\"", mf->mf_remopts);
- xopts = strdup(mf->mf_remopts);
+ /* use transp_opts first, so map-specific opts will override */
+ xopts = str3cat(xopts, transp_timeo_opts, transp_retrans_opts, mf->mf_remopts);
} else {
- xopts = strdup(opts);
+ /* use transp_opts first, so map-specific opts will override */
+ xopts = str3cat(xopts, transp_timeo_opts, transp_retrans_opts, mf->mf_mopts);
}
memset((voidp) &mnt, 0, sizeof(mnt));
- mnt.mnt_dir = dir;
+ mnt.mnt_dir = mntdir;
mnt.mnt_fsname = fs_name;
mnt.mnt_opts = xopts;
@@ -626,18 +854,19 @@ mount_nfs_fh(am_nfs_handle_t *fhp, char *dir, char *fs_name, char *opts, mntfs *
}
#endif /* HAVE_FS_NFS3 */
plog(XLOG_INFO, "mount_nfs_fh: NFS version %d", (int) nfs_version);
-#if defined(HAVE_FS_NFS3) || defined(HAVE_TRANSPORT_TYPE_TLI)
plog(XLOG_INFO, "mount_nfs_fh: using NFS transport %s", nfs_proto);
-#endif /* defined(HAVE_FS_NFS3) || defined(HAVE_TRANSPORT_TYPE_TLI) */
retry = hasmntval(&mnt, MNTTAB_OPT_RETRY);
if (retry <= 0)
retry = 1; /* XXX */
genflags = compute_mount_flags(&mnt);
+#ifdef HAVE_FS_AUTOFS
+ if (on_autofs)
+ genflags |= autofs_compute_mount_flags(&mnt);
+#endif /* HAVE_FS_AUTOFS */
/* setup the many fields and flags within nfs_args */
-#ifdef HAVE_TRANSPORT_TYPE_TLI
compute_nfs_args(&nfs_args,
&mnt,
genflags,
@@ -648,27 +877,14 @@ mount_nfs_fh(am_nfs_handle_t *fhp, char *dir, char *fs_name, char *opts, mntfs *
fhp,
host,
fs_name);
-#else /* not HAVE_TRANSPORT_TYPE_TLI */
- compute_nfs_args(&nfs_args,
- &mnt,
- genflags,
- fs->fs_ip,
- nfs_version,
- nfs_proto,
- fhp,
- host,
- fs_name);
-#endif /* not HAVE_TRANSPORT_TYPE_TLI */
/* finally call the mounting function */
-#ifdef DEBUG
- amuDebug(D_TRACE) {
+ if (amuDebug(D_TRACE)) {
print_nfs_args(&nfs_args, nfs_version);
plog(XLOG_DEBUG, "Generic mount flags 0x%x used for NFS mount", genflags);
}
-#endif /* DEBUG */
error = mount_fs(&mnt, genflags, (caddr_t) &nfs_args, retry, type,
- nfs_version, nfs_proto, mnttab_file_name);
+ nfs_version, nfs_proto, mnttab_file_name, on_autofs);
XFREE(xopts);
#ifdef HAVE_TRANSPORT_TYPE_TLI
@@ -682,39 +898,62 @@ mount_nfs_fh(am_nfs_handle_t *fhp, char *dir, char *fs_name, char *opts, mntfs *
static int
-mount_nfs(char *dir, char *fs_name, char *opts, mntfs *mf)
+nfs_mount(am_node *am, mntfs *mf)
{
+ int error = 0;
+ mntent_t mnt;
+
if (!mf->mf_private) {
- plog(XLOG_ERROR, "Missing filehandle for %s", fs_name);
+ plog(XLOG_ERROR, "Missing filehandle for %s", mf->mf_info);
return EINVAL;
}
- return mount_nfs_fh((am_nfs_handle_t *) mf->mf_private, dir, fs_name, opts, mf);
-}
+ mnt.mnt_opts = mf->mf_mopts;
+ if (amu_hasmntopt(&mnt, "softlookup") ||
+ (amu_hasmntopt(&mnt, "soft") && !amu_hasmntopt(&mnt, "nosoftlookup")))
+ am->am_flags |= AMF_SOFTLOOKUP;
+ error = mount_nfs_fh((am_nfs_handle_t *) mf->mf_private,
+ mf->mf_mount,
+ mf->mf_info,
+ mf);
-int
-nfs_fmount(mntfs *mf)
-{
- int error = 0;
-
- error = mount_nfs(mf->mf_mount, mf->mf_info, mf->mf_mopts, mf);
-
-#ifdef DEBUG
if (error) {
errno = error;
dlog("mount_nfs: %m");
}
-#endif /* DEBUG */
return error;
}
-int
-nfs_fumount(mntfs *mf)
+static int
+nfs_umount(am_node *am, mntfs *mf)
{
- int error = UMOUNT_FS(mf->mf_mount, mnttab_file_name);
+ int unmount_flags, new_unmount_flags, error;
+
+ unmount_flags = (mf->mf_flags & MFF_ON_AUTOFS) ? AMU_UMOUNT_AUTOFS : 0;
+ error = UMOUNT_FS(mf->mf_mount, mnttab_file_name, unmount_flags);
+
+#if defined(HAVE_UMOUNT2) && (defined(MNT2_GEN_OPT_FORCE) || defined(MNT2_GEN_OPT_DETACH))
+ /*
+ * If the attempt to unmount failed with EBUSY, and this fserver was
+ * marked for forced unmounts, then use forced/lazy unmounts.
+ */
+ if (error == EBUSY &&
+ gopt.flags & CFM_FORCED_UNMOUNTS &&
+ mf->mf_server->fs_flags & FSF_FORCE_UNMOUNT) {
+ plog(XLOG_INFO, "EZK: nfs_umount: trying forced/lazy unmounts");
+ /*
+ * XXX: turning off the FSF_FORCE_UNMOUNT may not be perfectly
+ * incorrect. Multiple nodes may need to be timed out and restarted for
+ * a single hung fserver.
+ */
+ mf->mf_server->fs_flags &= ~FSF_FORCE_UNMOUNT;
+ new_unmount_flags = unmount_flags | AMU_UMOUNT_FORCE | AMU_UMOUNT_DETACH;
+ error = UMOUNT_FS(mf->mf_mount, mnttab_file_name, new_unmount_flags);
+ }
+#endif /* HAVE_UMOUNT2 && (MNT2_GEN_OPT_FORCE || MNT2_GEN_OPT_DETACH) */
/*
* Here is some code to unmount 'restarted' file systems.
@@ -743,12 +982,14 @@ nfs_fumount(mntfs *mf)
if (NSTREQ(mf->mf_mount, new_mf->mf_mount, len) &&
new_mf->mf_mount[len] == '/') {
- UMOUNT_FS(new_mf->mf_mount, mnttab_file_name);
+ new_unmount_flags =
+ (new_mf->mf_flags & MFF_ON_AUTOFS) ? AMU_UMOUNT_AUTOFS : 0;
+ UMOUNT_FS(new_mf->mf_mount, mnttab_file_name, new_unmount_flags);
didsome = 1;
}
}
if (didsome)
- error = UMOUNT_FS(mf->mf_mount, mnttab_file_name);
+ error = UMOUNT_FS(mf->mf_mount, mnttab_file_name, unmount_flags);
}
if (error)
return error;
@@ -757,38 +998,35 @@ nfs_fumount(mntfs *mf)
}
-void
-nfs_umounted(am_node *mp)
+static void
+nfs_umounted(mntfs *mf)
{
- /*
- * Don't bother to inform remote mountd that we are finished. Until a
- * full track of filehandles is maintained the mountd unmount callback
- * cannot be done correctly anyway...
- */
- mntfs *mf = mp->am_mnt;
fserver *fs;
char *colon, *path;
if (mf->mf_error || mf->mf_refc > 1)
return;
- fs = mf->mf_server;
+ /*
+ * No need to inform mountd when WebNFS is in use.
+ */
+ if (mf->mf_flags & MFF_WEBNFS)
+ return;
/*
* Call the mount daemon on the server to announce that we are not using
* the fs any more.
*
- * This is *wrong*. The mountd should be called when the fhandle is
+ * XXX: This is *wrong*. The mountd should be called when the fhandle is
* flushed from the cache, and a reference held to the cached entry while
* the fs is mounted...
*/
+ fs = mf->mf_server;
colon = path = strchr(mf->mf_info, ':');
if (fs && colon) {
fh_cache f;
-#ifdef DEBUG
dlog("calling mountd for %s", mf->mf_info);
-#endif /* DEBUG */
*path++ = '\0';
f.fh_path = path;
f.fh_sin = *fs->fs_ip;
@@ -797,8 +1035,8 @@ nfs_umounted(am_node *mp)
f.fh_fs = fs;
f.fh_id = 0;
f.fh_error = 0;
- prime_nfs_fhandle_cache(colon + 1, mf->mf_server, (am_nfs_handle_t *) 0, (voidp) mf);
- call_mountd(&f, MOUNTPROC_UMNT, (fwd_fun) 0, (voidp) 0);
+ prime_nfs_fhandle_cache(colon + 1, mf->mf_server, (am_nfs_handle_t *) 0, mf);
+ call_mountd(&f, MOUNTPROC_UMNT, (fwd_fun *) 0, (wchan_t) 0);
*colon = ':';
}
}
OpenPOWER on IntegriCloud