From: Rainer Orth Date: Thu, 9 Oct 2003 20:33:44 +0000 (+0000) Subject: Use WebNFS to obtain file handles for mount(2). X-Git-Tag: before-retrans-udp-tcp-split~72 X-Git-Url: https://git.fsl.cs.sunysb.edu/?a=commitdiff_plain;h=1d473a7a60fc2bfe032a29a92da67ec6a2090e86;p=am-utils-6.2.git Use WebNFS to obtain file handles for mount(2). * NEWS: Document WebNFS support. * configure.in: Check for public mount option. * include/am_compat.h (MNTTAB_OPT_PUBLIC): Define if missing. * doc/am-utils.texi (opts Option): Renamed webnfs to public, update description. * amd/amd.h (FSF_WEBNFS): New mntfs flag. * include/am_utils.h (RPC_XID_WEBNFS): New XID type. * amd/amfs_host.c (amfs_host_mount, amfs_host_umounted): Reject WebNFS mount/umount attempts. * amd/ops_nfs.c (got_nfs_fh_mount): Renamed from got_nfs_fh. (got_nfs_fh_webnfs): New function. (flush_nfs_fhandle_cache): Don't invalidate port for WebNFS servers. (prime_nfs_fhandle_cache): Likewise. Remove unconditional return of public file handle for WebNFS, but get NFS file handles via mountd or WebNFS instead. (webnfs_lookup): New function. (nfs_umounted): Don't inform mountd if MFF_WEBNFS. * amd/rpc_fwd.c (fwd_packet, fwd_reply): Send/receive WebNFS packets. * amd/srvr_nfs.c (recompute_portmap): Don't contact portmap for WebNFS servers. Mention host in info message. (find_nfs_srvr): Handle public mount option. Prefer NFSv3/tcp if the client supports it. Allow port mount option to override default or result from portmap lookup. * libamu/xdr_func.c (xdr_diropargs3, xdr_filename3, xdr_LOOKUP3args, xdr_LOOKUP3res, xdr_LOOKUP3resfail, xdr_LOOKUP3resok, xdr_nfs_fh3, xdr_nfsstat3): New functions. * include/am_xdr_func.h: Declare them. * configure.in: Check for them. * conf/nfs_prot/nfs_prot_linux.h: Provide missing NFSv3 definitions and types. --- diff --git a/ChangeLog b/ChangeLog index efb13fb4..cb8fb593 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,45 @@ +2003-10-09 Rainer Orth + + Use WebNFS to obtain file handles for mount(2). + + * NEWS: Document WebNFS support. + + * configure.in: Check for public mount option. + * include/am_compat.h (MNTTAB_OPT_PUBLIC): Define if missing. + * doc/am-utils.texi (opts Option): Renamed webnfs to public, + update description. + + * amd/amd.h (FSF_WEBNFS): New mntfs flag. + * include/am_utils.h (RPC_XID_WEBNFS): New XID type. + + * amd/amfs_host.c (amfs_host_mount, amfs_host_umounted): Reject + WebNFS mount/umount attempts. + * amd/ops_nfs.c (got_nfs_fh_mount): Renamed from got_nfs_fh. + (got_nfs_fh_webnfs): New function. + (flush_nfs_fhandle_cache): Don't invalidate port for WebNFS servers. + (prime_nfs_fhandle_cache): Likewise. + Remove unconditional return of public file handle for WebNFS, but + get NFS file handles via mountd or WebNFS instead. + (webnfs_lookup): New function. + (nfs_umounted): Don't inform mountd if MFF_WEBNFS. + * amd/rpc_fwd.c (fwd_packet, fwd_reply): Send/receive WebNFS + packets. + * amd/srvr_nfs.c (recompute_portmap): Don't contact portmap for + WebNFS servers. + Mention host in info message. + (find_nfs_srvr): Handle public mount option. + Prefer NFSv3/tcp if the client supports it. + Allow port mount option to override default or result from portmap + lookup. + + * libamu/xdr_func.c (xdr_diropargs3, xdr_filename3, + xdr_LOOKUP3args, xdr_LOOKUP3res, xdr_LOOKUP3resfail, + xdr_LOOKUP3resok, xdr_nfs_fh3, xdr_nfsstat3): New functions. + * include/am_xdr_func.h: Declare them. + * configure.in: Check for them. + * conf/nfs_prot/nfs_prot_linux.h: Provide missing NFSv3 + definitions and types. + 2003-10-09 Rainer Orth Support IRIX 6 private mount option. diff --git a/NEWS b/NEWS index dce6ed0a..cb681351 100644 --- a/NEWS +++ b/NEWS @@ -6,6 +6,10 @@ sparc-sun-solaris2.10 x86_64-unknown-linux-rh2.9.5AS +- fully support WebNFS as per RFC 2054. It now tries v3/TCP first, falling + back to v2/UDP if this doesn't work. The "webnfs" pseudo-mount options + has been renamed (again) to "public" to match Solaris 2. + - bugs fixed: * fixed nfsx support * fixed a race involving late replies to mountd, etc queries diff --git a/amd/amd.h b/amd/amd.h index 498b86be..600e445a 100644 --- a/amd/amd.h +++ b/amd/amd.h @@ -37,7 +37,7 @@ * SUCH DAMAGE. * * - * $Id: amd.h,v 1.47 2003/10/09 05:13:58 ib42 Exp $ + * $Id: amd.h,v 1.48 2003/10/09 20:33:45 ro Exp $ * */ @@ -124,6 +124,7 @@ #define FSF_ERROR 0x0004 /* Permanent error has occurred */ #define FSF_WANT 0x0008 /* Want a wakeup call */ #define FSF_PINGING 0x0010 /* Already doing pings */ +#define FSF_WEBNFS 0x0020 /* Don't try to contact portmapper */ #define FSRV_ERROR(fs) ((fs) && (((fs)->fs_flags & FSF_ERROR) == FSF_ERROR)) #define FSRV_ISDOWN(fs) ((fs) && (((fs)->fs_flags & (FSF_DOWN|FSF_VALID)) == (FSF_DOWN|FSF_VALID))) #define FSRV_ISUP(fs) (!(fs) || (((fs)->fs_flags & (FSF_DOWN|FSF_VALID)) == (FSF_VALID))) diff --git a/amd/amfs_host.c b/amd/amfs_host.c index 010f93cd..2969736d 100644 --- a/amd/amfs_host.c +++ b/amd/amfs_host.c @@ -37,7 +37,7 @@ * SUCH DAMAGE. * * - * $Id: amfs_host.c,v 1.24 2003/10/02 16:29:28 ro Exp $ + * $Id: amfs_host.c,v 1.25 2003/10/09 20:33:45 ro Exp $ * */ @@ -316,6 +316,14 @@ amfs_host_mount(am_node *am, mntfs *mf) struct timeval tv; u_long mnt_version; + /* + * WebNFS servers don't necessarily run mountd. + */ + if (mf->mf_flags & MFF_WEBNFS) { + plog(XLOG_ERROR, "amfs_host_mount: cannot support WebNFS"); + return EIO; + } + /* * Read the mount list */ @@ -619,6 +627,14 @@ amfs_host_umounted(mntfs *mf) if (mf->mf_error || mf->mf_refc > 1 || !mf->mf_server) return; + /* + * WebNFS servers shouldn't ever get here. + */ + if (mf->mf_flags & MFF_WEBNFS) { + plog(XLOG_ERROR, "amfs_host_umounted: cannot support WebNFS"); + return; + } + /* * Take a copy of the server hostname, address, and NFS version * to mount version conversion. diff --git a/amd/ops_nfs.c b/amd/ops_nfs.c index 652bfe77..1bd0941f 100644 --- a/amd/ops_nfs.c +++ b/amd/ops_nfs.c @@ -37,7 +37,7 @@ * SUCH DAMAGE. * * - * $Id: ops_nfs.c,v 1.33 2003/10/02 16:29:28 ro Exp $ + * $Id: ops_nfs.c,v 1.34 2003/10/09 20:33:45 ro Exp $ * */ @@ -110,6 +110,7 @@ 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 */ @@ -170,10 +171,10 @@ find_nfs_fhandle_cache(opaque_t arg, 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, opaque_t arg, 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; @@ -233,6 +234,70 @@ got_nfs_fh(voidp pkt, int len, struct sockaddr_in *sa, struct sockaddr_in *ia, o } +/* + * 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 + 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_LOOKUP3res); + fp->fh_status = unx_error(res3.status); + memset(&fp->fh_nfs_handle.v3, 0, sizeof(am_nfs_fh3)); + fp->fh_nfs_handle.v3.fh3_length = res3.res_u.ok.object.fh3_length; + memmove(fp->fh_nfs_handle.v3.fh3_u.data, + res3.res_u.ok.object.fh3_u.data, + fp->fh_nfs_handle.v3.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); + /* + * 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); + } +} + + void flush_nfs_fhandle_cache(fserver *fs) { @@ -240,7 +305,11 @@ flush_nfs_fhandle_cache(fserver *fs) ITER(fp, fh_cache, &fh_head) { if (fp->fh_fs == fs || fs == 0) { - fp->fh_sin.sin_port = (u_short) 0; + /* + * 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; } } @@ -385,36 +454,25 @@ prime_nfs_fhandle_cache(char *path, fserver *fs, am_nfs_handle_t *fhbuf, mntfs * } /* - * 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); - if (mf->mf_flags & MFF_WEBNFS) { - dlog("Using public filehandle for '%s'", mf->mf_info); - memset(&fp->fh_nfs_handle, 0, sizeof(fp->fh_nfs_handle)); - 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 -#endif /* HAVE_FS_NFS3 */ - memmove((voidp) &(fhbuf->v2), (voidp) &(fp->fh_nfs_handle.v2), - sizeof(fp->fh_nfs_handle.v2)); - } - wakeup(get_mntfs_wchan(mf)); - fp->fh_error = 0; - return 0; - } - - error = call_mountd(fp, MOUNTPROC_MNT, got_nfs_fh, get_mntfs_wchan(mf)); + 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 @@ -531,6 +589,91 @@ call_mountd(fh_cache *fp, u_long proc, fwd_fun fun, wchan_t wchan) } +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 + LOOKUP3args args3; +#endif + char *wnfs_path; + + 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). + */ + wnfs_path = (char *) xmalloc(strlen(fp->fh_path) + 2); + wnfs_path[0] = 0x80; + strcpy(wnfs_path + 1, fp->fh_path); + + /* find the right program and lookup procedure */ +#ifdef HAVE_FS_NFS3 + if (fp->fh_nfs_version == NFS_VERSION3) { + proc = NFSPROC3_LOOKUP; + xdr_fn = (XDRPROC_T_TYPE) xdr_LOOKUP3args; + argp = &args3; + /* WebNFS public file handle */ + args3.what.dir.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. @@ -810,6 +953,9 @@ nfs_umounted(mntfs *mf) if (mf->mf_error || mf->mf_refc > 1) return; + /* + * No need to inform mountd when WebNFS is in use. + */ if (mf->mf_flags & MFF_WEBNFS) return; diff --git a/amd/rpc_fwd.c b/amd/rpc_fwd.c index 5f13cf9d..66fbb6ee 100644 --- a/amd/rpc_fwd.c +++ b/amd/rpc_fwd.c @@ -37,7 +37,7 @@ * SUCH DAMAGE. * * - * $Id: rpc_fwd.c,v 1.16 2003/10/02 17:13:22 ro Exp $ + * $Id: rpc_fwd.c,v 1.17 2003/10/09 20:33:46 ro Exp $ * */ @@ -254,6 +254,9 @@ fwd_packet(int type_id, char *pkt, int len, struct sockaddr_in *fwdto, struct so case RPC_XID_NFSPING: dlog("Sending NFS ping %#x", type_id); break; + case RPC_XID_WEBNFS: + dlog("Sending WebNFS lookup %#x", type_id); + break; default: dlog("UNKNOWN RPC XID %#x", type_id); break; @@ -439,6 +442,9 @@ again: case RPC_XID_NFSPING: dlog("Receiving NFS ping %#x", pkt_xid); break; + case RPC_XID_WEBNFS: + dlog("Receiving WebNFS lookup %#x", pkt_xid); + break; default: dlog("UNKNOWN RPC XID %#x", pkt_xid); break; diff --git a/amd/srvr_nfs.c b/amd/srvr_nfs.c index 446a8f65..61e87ceb 100644 --- a/amd/srvr_nfs.c +++ b/amd/srvr_nfs.c @@ -37,7 +37,7 @@ * SUCH DAMAGE. * * - * $Id: srvr_nfs.c,v 1.32 2003/10/01 02:45:12 ib42 Exp $ + * $Id: srvr_nfs.c,v 1.33 2003/10/09 20:33:46 ro Exp $ * */ @@ -272,6 +272,12 @@ recompute_portmap(fserver *fs) int error; u_long mnt_version; + /* + * No portmap calls for pure WebNFS servers. + */ + if (fs->fs_flags & FSF_WEBNFS) + return; + if (nfs_auth) error = 0; else @@ -286,7 +292,8 @@ recompute_portmap(fserver *fs) if (fs->fs_version == 0) plog(XLOG_WARNING, "recompute_portmap: nfs_version = 0 fixed"); - plog(XLOG_INFO, "recompute_portmap: NFS version %d", (int) fs->fs_version); + plog(XLOG_INFO, "recompute_portmap: NFS version %d on %s", + (int) fs->fs_version, fs->fs_host); #ifdef HAVE_FS_NFS3 if (fs->fs_version == NFS_VERSION3) mnt_version = MOUNTVERS3; @@ -618,6 +625,7 @@ find_nfs_srvr(mntfs *mf) u_long best_nfs_version = 0; char *nfs_proto = NULL; /* no IP protocol either */ int nfs_port = 0; + int nfs_port_opt = 0; int fserver_is_down = 0; /* @@ -744,16 +752,33 @@ find_nfs_srvr(mntfs *mf) #endif /* not HAVE_FS_NFS3 */ - if (amu_hasmntopt(&mnt, "webnfs")) { - plog(XLOG_INFO, "webnfs option used, NOT contacting the portmapper on %s", host); + if (amu_hasmntopt(&mnt, MNTTAB_OPT_PUBLIC)) { + /* + * Use WebNFS to obtain file handles. + */ mf->mf_flags |= MFF_WEBNFS; + plog(XLOG_INFO, "%s option used, NOT contacting the portmapper on %s", + MNTTAB_OPT_PUBLIC, host); + /* + * Prefer NFSv3/tcp if the client supports it (cf. RFC 2054, 7). + */ if (!nfs_version) { - plog(XLOG_INFO, "No NFS version specified, will use NFSv2"); +#ifdef HAVE_FS_NFS3 + nfs_version = NFS_VERSION3; +#else /* not HAVE_FS_NFS3 */ nfs_version = NFS_VERSION; +#endif /* not HAVE_FS_NFS3 */ + plog(XLOG_INFO, "No NFS version specified, will use NFSv%d", + (int) nfs_version); } if (!nfs_proto) { - plog(XLOG_INFO, "No NFS protocol transport specified, will use udp"); +#if defined(MNTTAB_OPT_PROTO) || defined(HAVE_FS_NFS3) + nfs_proto = "tcp"; +#else /* not defined(MNTTAB_OPT_PROTO) || defined(HAVE_FS_NFS3) */ nfs_proto = "udp"; +#endif /* not defined(MNTTAB_OPT_PROTO) || defined(HAVE_FS_NFS3) */ + plog(XLOG_INFO, "No NFS protocol transport specified, will use %s", + nfs_proto); } } else { /* @@ -809,8 +834,21 @@ find_nfs_srvr(mntfs *mf) } } + /* + * Determine the NFS port. + * + * A valid "port" mount option overrides anything else. + * If the port has been determined from the portmapper, use that. + * Default to NFS_PORT otherwise (cf. RFC 2054, 3). + */ + nfs_port_opt = hasmntval(&mnt, MNTTAB_OPT_PORT); + if (nfs_port_opt > 0) + nfs_port = htons(nfs_port_opt); if (!nfs_port) nfs_port = htons(NFS_PORT); + + dlog("find_nfs_srvr: using port %d for nfs on %s", + (int) ntohs(nfs_port), host); ip->sin_port = nfs_port; no_dns: @@ -833,6 +871,13 @@ no_dns: if (hp && fs->fs_ip) memmove((voidp) &fs->fs_ip->sin_addr, (voidp) hp->h_addr, sizeof(fs->fs_ip->sin_addr)); + /* + * If the new file systems doesn't use WebNFS, the nfs pings may + * try to contact the portmapper. + */ + if (!(mf->mf_flags & MFF_WEBNFS)) + fs->fs_flags &= ~FSF_WEBNFS; + /* * following if statement from Mike Mitchell * @@ -885,6 +930,8 @@ no_dns: mf->mf_flags |= MFF_ERROR; mf->mf_error = ENOENT; } + if (mf->mf_flags & MFF_WEBNFS) + fs->fs_flags |= FSF_WEBNFS; fs->fs_version = nfs_version; fs->fs_proto = nfs_proto; fs->fs_type = MNTTAB_TYPE_NFS; diff --git a/conf/nfs_prot/nfs_prot_linux.h b/conf/nfs_prot/nfs_prot_linux.h index 7ccd072d..61e0fa5d 100644 --- a/conf/nfs_prot/nfs_prot_linux.h +++ b/conf/nfs_prot/nfs_prot_linux.h @@ -37,7 +37,7 @@ * SUCH DAMAGE. * * - * $Id: nfs_prot_linux.h,v 1.17 2002/12/27 22:44:00 ezk Exp $ + * $Id: nfs_prot_linux.h,v 1.18 2003/10/09 20:33:46 ro Exp $ * */ @@ -258,6 +258,40 @@ struct nfs_args { typedef struct nfs_args nfs_args_t; #ifdef HAVE_FS_NFS3 +#define NFSPROC3_LOOKUP ((u_long) 3) +enum nfsstat3 { + NFS3_OK = 0, + NFS3ERR_PERM = 1, + NFS3ERR_NOENT = 2, + NFS3ERR_IO = 5, + NFS3ERR_NXIO = 6, + NFS3ERR_ACCES = 13, + NFS3ERR_EXIST = 17, + NFS3ERR_XDEV = 18, + NFS3ERR_NODEV = 19, + NFS3ERR_NOTDIR = 20, + NFS3ERR_ISDIR = 21, + NFS3ERR_INVAL = 22, + NFS3ERR_FBIG = 27, + NFS3ERR_NOSPC = 28, + NFS3ERR_ROFS = 30, + NFS3ERR_MLINK = 31, + NFS3ERR_NAMETOOLONG = 63, + NFS3ERR_NOTEMPTY = 66, + NFS3ERR_DQUOT = 69, + NFS3ERR_STALE = 70, + NFS3ERR_REMOTE = 71, + NFS3ERR_BADHANDLE = 10001, + NFS3ERR_NOT_SYNC = 10002, + NFS3ERR_BAD_COOKIE = 10003, + NFS3ERR_NOTSUPP = 10004, + NFS3ERR_TOOSMALL = 10005, + NFS3ERR_SERVERFAULT = 10006, + NFS3ERR_BADTYPE = 10007, + NFS3ERR_JUKEBOX = 10008 +}; +typedef enum nfsstat3 nfsstat3; + typedef struct { u_int fhandle3_len; char *fhandle3_val; @@ -301,6 +335,44 @@ struct nfs_fh3 { } fh3_u; }; typedef struct nfs_fh3 am_nfs_fh3; + +typedef char *filename3; + +struct diropargs3 { + am_nfs_fh3 dir; + filename3 name; +}; +typedef struct diropargs3 diropargs3; + +struct LOOKUP3args { + diropargs3 what; +}; +typedef struct LOOKUP3args LOOKUP3args; + +struct LOOKUP3resok { + am_nfs_fh3 object; +#if 0 + post_op_attr obj_attributes; + post_op_attr dir_attributes; +#endif +}; +typedef struct LOOKUP3resok LOOKUP3resok; + +struct LOOKUP3resfail { +#if 0 + post_op_attr dir_attributes; +#endif +}; +typedef struct LOOKUP3resfail LOOKUP3resfail; + +struct LOOKUP3res { + nfsstat3 status; + union { + LOOKUP3resok ok; + LOOKUP3resfail fail; + } res_u; +}; +typedef struct LOOKUP3res LOOKUP3res; #endif /* HAVE_FS_NFS3 */ /* diff --git a/configure.in b/configure.in index b333406c..1f0ec024 100644 --- a/configure.in +++ b/configure.in @@ -53,7 +53,7 @@ AH_BOTTOM([ dnl dnl AC_CONFIG_AUX_DIR(m4) AC_PREREQ(2.52) -AC_REVISION($Revision: 1.64 $) +AC_REVISION($Revision: 1.65 $) AC_COPYRIGHT([Copyright (c) 1997-2003 Erez Zadok]) dnl find out system type AC_MSG_NOTICE(*** SYSTEM TYPES ***) @@ -342,6 +342,7 @@ AC_CHECK_FUNCS( \ xdr_createargs \ xdr_dirlist \ xdr_diropargs \ + xdr_diropargs3 \ xdr_diropokres \ xdr_diropres \ xdr_dirpath \ @@ -352,18 +353,25 @@ AC_CHECK_FUNCS( \ xdr_fhandle \ xdr_fhstatus \ xdr_filename \ + xdr_filename3 \ xdr_ftype \ xdr_groupnode \ xdr_groups \ xdr_linkargs \ + xdr_LOOKUP3args \ + xdr_LOOKUP3res \ + xdr_LOOKUP3resfail \ + xdr_LOOKUP3resok \ xdr_mountbody \ xdr_mountlist \ xdr_mountres3 \ xdr_name \ xdr_nfs_fh \ + xdr_nfs_fh3 \ xdr_nfscookie \ xdr_nfspath \ xdr_nfsstat \ + xdr_nfsstat3 \ xdr_nfstime \ xdr_pointer \ xdr_readargs \ @@ -948,6 +956,7 @@ AMU_CHECK_MNTTAB_OPTS( \ private \ proplist \ proto \ + public \ retrans \ retry \ ro \ diff --git a/doc/am-utils.texi b/doc/am-utils.texi index 3ec63a6b..d83dab6b 100644 --- a/doc/am-utils.texi +++ b/doc/am-utils.texi @@ -38,7 +38,7 @@ @c @c %W% (Berkeley) %G% @c -@c $Id: am-utils.texi,v 1.74 2003/10/09 19:31:13 ro Exp $ +@c $Id: am-utils.texi,v 1.75 2003/10/09 20:33:47 ro Exp $ @c @setfilename am-utils.info @@ -2217,7 +2217,7 @@ The NFS timeout, in tenth-seconds, before a request is retransmitted. @item vers=@var{n} @cindex Mount flags; vers - Use NFS protocol version number @var{n} (can be 2 or 3). +Use NFS protocol version number @var{n} (can be 2 or 3). @item wsize=@var{n} @cindex Mount flags; wsize @@ -2248,6 +2248,16 @@ interval defaults to 30 seconds. If the ping interval is less than zero, no pings are sent and the host is assumed to be always up, which can cause unmounts to hang. See the @i{softlookup} option for a better alternative. +@item public +@cindex Mount flags; public +Use WebNFS multi-component lookup on the public file handle instead of +the mount protocol to obtain NFS file handles, as documented in the +WebNFS Client Specification, RFC 2054. This means that @i{Amd} will not +attempt to contact the remote portmapper or remote mountd daemon, and +will only connect to the well-known NFS port 2049 or the port specified +with the @i{port} mount option, thus making it easier to use NFS through +a firewall. + @item retry=@var{n} @cindex Mount flags; retry=@var{n} The number of times to retry the mount system call. @@ -2283,26 +2293,6 @@ has failed. In fact the interval is extended before the unmount is attempted, to avoid thrashing. The default value is 120 seconds (two minutes) or as set by the @code{-w} command line option. -@item webnfs -@cindex Mount flags; webnfs -Tells amd to mount the public share from the remote server (rfs is -effectively ignored), using the public filehandle as documented in the -WebNFS RFC. This means that amd will not attempt to contact the remote -portmapper or remote mountd daemon, and will only connect to the -well-known NFS port 2049, thus making it easier to use NFS through a -firewall. - -Caveats: -- since here is only one public filehandle, it necessarily means that -only one share per fileserver can be mounted via WebNFS. This is a -limitation of the WebNFS specification, not of amd itself. - -- since there is no portmapper communication, amd will not attempt any -sort of discovery of remote server capabilities, and will default to -using NFSv2/UDP. It is the admin's responsibility to alter this -behavior by explicitly specifying the desired NFS version and protocol -within the mount options for each webnfs map entry. - @item xlatecookie @cindex Mount flags; xlatecookie Translate directory cookies between 32-long and 64-long lengths. diff --git a/include/am_compat.h b/include/am_compat.h index d0a3bfe8..9bba83c1 100644 --- a/include/am_compat.h +++ b/include/am_compat.h @@ -197,6 +197,10 @@ # define MNTTAB_OPT_PORT "port" #endif /* not MNTTAB_OPT_PORT */ +#ifndef MNTTAB_OPT_PUBLIC +# define MNTTAB_OPT_PUBLIC "public" +#endif /* not MNTTAB_OPT_PUBLIC */ + #ifndef MNTTAB_OPT_RETRANS # define MNTTAB_OPT_RETRANS "retrans" #endif /* not MNTTAB_OPT_RETRANS */ diff --git a/include/am_utils.h b/include/am_utils.h index 73160bf1..7db45795 100644 --- a/include/am_utils.h +++ b/include/am_utils.h @@ -37,7 +37,7 @@ * SUCH DAMAGE. * * - * $Id: am_utils.h,v 1.53 2003/10/02 16:29:29 ro Exp $ + * $Id: am_utils.h,v 1.54 2003/10/09 20:33:48 ro Exp $ * */ @@ -155,6 +155,7 @@ extern int umount_fs(char *mntdir, const char *mnttabname, int on_autofs); #define RPC_XID_PORTMAP 0 #define RPC_XID_MOUNTD 1 #define RPC_XID_NFSPING 2 +#define RPC_XID_WEBNFS 3 #define RPC_XID_MASK (0x0f) /* 16 id's for now */ #define MK_RPC_XID(type_id, uniq) ((type_id) | ((uniq) << 4)) diff --git a/include/am_xdr_func.h b/include/am_xdr_func.h index f44e825a..a300ace5 100644 --- a/include/am_xdr_func.h +++ b/include/am_xdr_func.h @@ -37,7 +37,7 @@ * SUCH DAMAGE. * * - * $Id: am_xdr_func.h,v 1.10 2002/12/27 22:44:09 ezk Exp $ + * $Id: am_xdr_func.h,v 1.11 2003/10/09 20:33:48 ro Exp $ * */ @@ -180,4 +180,34 @@ bool_t xdr_symlinkargs(XDR *xdrs, nfssymlinkargs *objp); #ifndef HAVE_XDR_WRITEARGS bool_t xdr_writeargs(XDR *xdrs, nfswriteargs *objp); #endif /* not HAVE_XDR_WRITEARGS */ + +/* + * NFS3 XDR FUNCTIONS: + */ +#ifdef HAVE_FS_NFS3 +# ifndef HAVE_XDR_DIROPARGS3 +bool_t xdr_diropargs3(XDR *xdrs, diropargs3 *objp); +#endif /* not HAVE_XDR_DIROPARGS3 */ +# ifndef HAVE_XDR_FILENAME3 +bool_t xdr_filename3(XDR *xdrs, filename3 *objp); +# endif /* not HAVE_XDR_FILENAME3 */ +# ifndef HAVE_XDR_LOOKUP3ARGS +bool_t xdr_LOOKUP3args(XDR *xdrs, LOOKUP3args *objp); +# endif /* not HAVE_XDR_LOOKUP3ARGS */ +# ifndef HAVE_XDR_LOOKUP3RES +bool_t xdr_LOOKUP3res(XDR *xdrs, LOOKUP3res *objp); +# endif /* not HAVE_XDR_LOOKUP3RES */ +# ifndef HAVE_XDR_LOOKUP3RESFAIL +bool_t xdr_LOOKUP3resfail(XDR *xdrs, LOOKUP3resfail *objp); +# endif /* not HAVE_XDR_LOOKUP3RESFAIL */ +# ifndef HAVE_XDR_LOOKUP3RESOK +bool_t xdr_LOOKUP3resok(XDR *xdrs, LOOKUP3resok *objp); +# endif /* not HAVE_XDR_LOOKUP3RESOK */ +# ifndef HAVE_XDR_NFS_FH3 +bool_t xdr_nfs_fh3(XDR *xdrs, am_nfs_fh3 *objp); +# endif /* not HAVE_XDR_NFS_FH3 */ +# ifndef HAVE_XDR_NFSSTAT3 +bool_t xdr_nfsstat3(XDR *xdrs, nfsstat3 *objp); +# endif /* not HAVE_XDR_NFSSTAT3 */ +#endif /* HAVE_FS_NFS3 */ #endif /* not _AM_XDR_FUNC_H */ diff --git a/libamu/xdr_func.c b/libamu/xdr_func.c index fefceada..b563c241 100644 --- a/libamu/xdr_func.c +++ b/libamu/xdr_func.c @@ -37,7 +37,7 @@ * SUCH DAMAGE. * * - * $Id: xdr_func.c,v 1.17 2002/12/29 01:09:08 ezk Exp $ + * $Id: xdr_func.c,v 1.18 2003/10/09 20:33:48 ro Exp $ * */ @@ -972,3 +972,156 @@ xdr_writeargs(XDR *xdrs, nfswriteargs *objp) return (TRUE); } #endif /* not HAVE_XDR_WRITEARGS */ + + +/* + * NFS V3 XDR FUNCTIONS: + */ +#ifdef HAVE_FS_NFS3 +# ifndef HAVE_XDR_DIROPARGS3 +bool_t +xdr_diropargs3(XDR *xdrs, diropargs3 *objp) +{ + if (amuDebug(D_XDRTRACE)) + plog(XLOG_DEBUG, "xdr_diropargs3:"); + + if (!xdr_nfs_fh3(xdrs, &objp->dir)) + return (FALSE); + if (!xdr_filename3(xdrs, &objp->name)) + return (FALSE); + return (TRUE); +} +#endif /* not HAVE_XDR_DIROPARGS3 */ + + +# ifndef HAVE_XDR_FILENAME3 +bool_t +xdr_filename3(XDR *xdrs, filename3 *objp) +{ + if (amuDebug(D_XDRTRACE)) + plog(XLOG_DEBUG, "xdr_filename3:"); + + if (!xdr_string(xdrs, objp, ~0)) + return (FALSE); + return (TRUE); +} +# endif /* not HAVE_XDR_FILENAME3 */ + + +# ifndef HAVE_XDR_LOOKUP3ARGS +bool_t +xdr_LOOKUP3args(XDR *xdrs, LOOKUP3args *objp) +{ + if (amuDebug(D_XDRTRACE)) + plog(XLOG_DEBUG, "xdr_LOOKUP3args:"); + + if (!xdr_diropargs3(xdrs, &objp->what)) + return (FALSE); + return (TRUE); +} +# endif /* not HAVE_XDR_LOOKUP3ARGS */ + + +# ifndef HAVE_XDR_LOOKUP3RES +bool_t +xdr_LOOKUP3res(XDR *xdrs, LOOKUP3res *objp) +{ + if (amuDebug(D_XDRTRACE)) + plog(XLOG_DEBUG, "xdr_LOOKUP3res:"); + + if (!xdr_nfsstat3(xdrs, &objp->status)) + return (FALSE); + switch (objp->status) { + case NFS3_OK: + if (!xdr_LOOKUP3resok(xdrs, &objp->res_u.ok)) + return (FALSE); + break; + default: + if (!xdr_LOOKUP3resfail(xdrs, &objp->res_u.fail)) + return (FALSE); + break; + } + return (TRUE); +} +# endif /* not HAVE_XDR_LOOKUP3RES */ + + +# ifndef HAVE_XDR_LOOKUP3RESFAIL +bool_t +xdr_LOOKUP3resfail(XDR *xdrs, LOOKUP3resfail *objp) +{ + if (amuDebug(D_XDRTRACE)) + plog(XLOG_DEBUG, "xdr_LOOKUP3resfail:"); + + /* + * Don't xdr post_op_attr: amd doesn't need them, but they require many + * additional xdr functions. + */ +#if 0 + if (!xdr_post_op_attr(xdrs, &objp->dir_attributes)) + return (FALSE); +#endif + return (TRUE); +} +# endif /* not HAVE_XDR_LOOKUP3RESFAIL */ + + +# ifndef HAVE_XDR_LOOKUP3RESOK +bool_t +xdr_LOOKUP3resok(XDR *xdrs, LOOKUP3resok *objp) +{ + if (amuDebug(D_XDRTRACE)) + plog(XLOG_DEBUG, "xdr_LOOKUP3resok:"); + + if (!xdr_nfs_fh3(xdrs, &objp->object)) + return (FALSE); + /* + * Don't xdr post_op_attr: amd doesn't need them, but they require many + * additional xdr functions. + */ +#if 0 + if (!xdr_post_op_attr(xdrs, &objp->obj_attributes)) + return (FALSE); + if (!xdr_post_op_attr(xdrs, &objp->dir_attributes)) + return (FALSE); +#endif + return (TRUE); +} +# endif /* not HAVE_XDR_LOOKUP3RESOK */ + + +# ifndef HAVE_XDR_NFS_FH3 +bool_t +xdr_nfs_fh3(XDR *xdrs, am_nfs_fh3 *objp) +{ + if (amuDebug(D_XDRTRACE)) + plog(XLOG_DEBUG, "xdr_nfs_fh3:"); + + /* + * nfs_fh3 used by the kernel differs from the definition generated from + * nfs_prot.x, so cannot use the generated xdr_nfs_fh3(). + */ + if (!xdr_u_int(xdrs, &objp->fh3_length)) + return (FALSE); + if (objp->fh3_length > NFS3_FHSIZE) + return (FALSE); + if (!xdr_opaque(xdrs, objp->fh3_u.data, objp->fh3_length)) + return (FALSE); + return (TRUE); +} +# endif /* not HAVE_XDR_NFS_FH3 */ + + +# ifndef HAVE_XDR_NFSSTAT3 +bool_t +xdr_nfsstat3(XDR *xdrs, nfsstat3 *objp) +{ + if (amuDebug(D_XDRTRACE)) + plog(XLOG_DEBUG, "xdr_nfsstat3:"); + + if (!xdr_enum(xdrs, (enum_t *)objp)) + return (FALSE); + return (TRUE); +} +# endif /* not HAVE_XDR_NFSSTAT3 */ +#endif /* not HAVE_FS_NFS3 */