Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 16 Sep 2010 01:38:13 +0000 (UTC)
From:      Rick Macklem <rmacklem@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-8@freebsd.org
Subject:   svn commit: r212717 - in stable/8: lib/libstand sys/boot/i386/libi386
Message-ID:  <201009160138.o8G1cDo6057054@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: rmacklem
Date: Thu Sep 16 01:38:13 2010
New Revision: 212717
URL: http://svn.freebsd.org/changeset/base/212717

Log:
  MFC: r212125, r212126
  Modify lib/libstand/nfs.c to use NFSv3 instead of NFSv2.
  This allows the nfs_getrootfh() function to return the
  correct file handle size to pxe.c for pxeboot. It also
  results in NFSv2 no longer being used by default anywhere
  in FreeBSD. If built with OLD_NFSV2 defined, the old
  code that predated this patch will be built and NFSv2
  will be used. pxe.c is also modified to use this version
  of nfs_getrootfh() so that pxeboot will use NFSv3 and
  work for non-FreeBSD as well as FreeBSD NFS servers.

Modified:
  stable/8/lib/libstand/nfs.c
  stable/8/sys/boot/i386/libi386/pxe.c
Directory Properties:
  stable/8/lib/libstand/   (props changed)
  stable/8/sys/   (props changed)
  stable/8/sys/amd64/include/xen/   (props changed)
  stable/8/sys/cddl/contrib/opensolaris/   (props changed)
  stable/8/sys/contrib/dev/acpica/   (props changed)
  stable/8/sys/contrib/pf/   (props changed)
  stable/8/sys/dev/xen/xenpci/   (props changed)

Modified: stable/8/lib/libstand/nfs.c
==============================================================================
--- stable/8/lib/libstand/nfs.c	Thu Sep 16 01:02:53 2010	(r212716)
+++ stable/8/lib/libstand/nfs.c	Thu Sep 16 01:38:13 2010	(r212717)
@@ -50,7 +50,10 @@ __FBSDID("$FreeBSD$");
 
 #define NFS_DEBUGxx
 
+#define NFSREAD_SIZE 1024
+
 /* Define our own NFS attributes without NQNFS stuff. */
+#ifdef OLD_NFSV2
 struct nfsv2_fattrs {
 	n_long	fa_type;
 	n_long	fa_mode;
@@ -68,7 +71,6 @@ struct nfsv2_fattrs {
 	struct nfsv2_time fa_ctime;
 };
 
-
 struct nfs_read_args {
 	u_char	fh[NFS_FHSIZE];
 	n_long	off;
@@ -77,7 +79,6 @@ struct nfs_read_args {
 };
 
 /* Data part of nfs rpc reply (also the largest thing we receive) */
-#define NFSREAD_SIZE 1024
 struct nfs_read_repl {
 	n_long	errno;
 	struct	nfsv2_fattrs fa;
@@ -116,6 +117,72 @@ struct nfs_iodesc {
 	u_char	fh[NFS_FHSIZE];
 	struct nfsv2_fattrs fa;	/* all in network order */
 };
+#else	/* !OLD_NFSV2 */
+
+/* NFSv3 definitions */
+#define	NFS_V3MAXFHSIZE		64
+#define	NFS_VER3		3
+#define	RPCMNT_VER3		3
+#define	NFSPROCV3_LOOKUP	3
+#define	NFSPROCV3_READLINK	5
+#define	NFSPROCV3_READ		6
+#define	NFSPROCV3_READDIR	16
+
+typedef struct {
+	uint32_t val[2];
+} n_quad;
+
+struct nfsv3_time {
+	uint32_t nfs_sec;
+	uint32_t nfs_nsec;
+};
+
+struct nfsv3_fattrs {
+	uint32_t fa_type;
+	uint32_t fa_mode;
+	uint32_t fa_nlink;
+	uint32_t fa_uid;
+	uint32_t fa_gid;
+	n_quad fa_size;
+	n_quad fa_used;
+	n_quad fa_rdev;
+	n_quad fa_fsid;
+	n_quad fa_fileid;
+	struct nfsv3_time fa_atime;
+	struct nfsv3_time fa_mtime;
+	struct nfsv3_time fa_ctime;
+};
+
+/*
+ * For NFSv3, the file handle is variable in size, so most fixed sized
+ * structures for arguments won't work. For most cases, a structure
+ * that starts with any fixed size section is followed by an array
+ * that covers the maximum size required.
+ */
+struct nfsv3_readdir_repl {
+	uint32_t errno;
+	uint32_t ok;
+	struct nfsv3_fattrs fa;
+	uint32_t cookiev0;
+	uint32_t cookiev1;
+};
+
+struct nfsv3_readdir_entry {
+	uint32_t follows;
+	uint32_t fid0;
+	uint32_t fid1;
+	uint32_t len;
+	uint32_t nameplus[0];
+};
+
+struct nfs_iodesc {
+	struct iodesc *iodesc;
+	off_t off;
+	uint32_t fhsize;
+	u_char fh[NFS_V3MAXFHSIZE];
+	struct nfsv3_fattrs fa;	/* all in network order */
+};
+#endif	/* OLD_NFSV2 */
 
 /*
  * XXX interactions with tftp? See nfswrapper.c for a confusing
@@ -142,6 +209,7 @@ struct fs_ops nfs_fsops = {
 	nfs_readdir
 };
 
+#ifdef	OLD_NFSV2
 /*
  * Fetch the root file handle (call mount daemon)
  * Return zero or error number.
@@ -773,3 +841,675 @@ nfs_readdir(struct open_file *f, struct 
 	cookie = ntohl(roff->cookie);
 	return 0;
 }
+#else	/* !OLD_NFSV2 */
+/*
+ * Fetch the root file handle (call mount daemon)
+ * Return zero or error number.
+ */
+int
+nfs_getrootfh(struct iodesc *d, char *path, uint32_t *fhlenp, u_char *fhp)
+{
+	int len;
+	struct args {
+		uint32_t len;
+		char path[FNAME_SIZE];
+	} *args;
+	struct repl {
+		uint32_t errno;
+		uint32_t fhsize;
+		u_char fh[NFS_V3MAXFHSIZE];
+		uint32_t authcnt;
+		uint32_t auth[7];
+	} *repl;
+	struct {
+		uint32_t h[RPC_HEADER_WORDS];
+		struct args d;
+	} sdata;
+	struct {
+		uint32_t h[RPC_HEADER_WORDS];
+		struct repl d;
+	} rdata;
+	size_t cc;
+
+#ifdef NFS_DEBUG
+	if (debug)
+		printf("nfs_getrootfh: %s\n", path);
+#endif
+
+	args = &sdata.d;
+	repl = &rdata.d;
+
+	bzero(args, sizeof(*args));
+	len = strlen(path);
+	if (len > sizeof(args->path))
+		len = sizeof(args->path);
+	args->len = htonl(len);
+	bcopy(path, args->path, len);
+	len = sizeof(uint32_t) + roundup(len, sizeof(uint32_t));
+
+	cc = rpc_call(d, RPCPROG_MNT, RPCMNT_VER3, RPCMNT_MOUNT,
+	    args, len, repl, sizeof(*repl));
+	if (cc == -1)
+		/* errno was set by rpc_call */
+		return (errno);
+	if (cc < 2 * sizeof (uint32_t))
+		return (EBADRPC);
+	if (repl->errno != 0)
+		return (ntohl(repl->errno));
+	*fhlenp = ntohl(repl->fhsize);
+	bcopy(repl->fh, fhp, *fhlenp);
+	return (0);
+}
+
+/*
+ * Lookup a file.  Store handle and attributes.
+ * Return zero or error number.
+ */
+int
+nfs_lookupfh(struct nfs_iodesc *d, const char *name, struct nfs_iodesc *newfd)
+{
+	int len, rlen, pos;
+	struct args {
+		uint32_t fhsize;
+		uint32_t fhplusname[1 +
+		    (NFS_V3MAXFHSIZE + FNAME_SIZE) / sizeof(uint32_t)];
+	} *args;
+	struct repl {
+		uint32_t errno;
+		uint32_t fhsize;
+		uint32_t fhplusattr[(NFS_V3MAXFHSIZE +
+		    2 * (sizeof(uint32_t) +
+		    sizeof(struct nfsv3_fattrs))) / sizeof(uint32_t)];
+	} *repl;
+	struct {
+		uint32_t h[RPC_HEADER_WORDS];
+		struct args d;
+	} sdata;
+	struct {
+		uint32_t h[RPC_HEADER_WORDS];
+		struct repl d;
+	} rdata;
+	ssize_t cc;
+
+#ifdef NFS_DEBUG
+	if (debug)
+		printf("lookupfh: called\n");
+#endif
+
+	args = &sdata.d;
+	repl = &rdata.d;
+
+	bzero(args, sizeof(*args));
+	args->fhsize = htonl(d->fhsize);
+	bcopy(d->fh, args->fhplusname, d->fhsize);
+	len = strlen(name);
+	if (len > FNAME_SIZE)
+		len = FNAME_SIZE;
+	pos = roundup(d->fhsize, sizeof(uint32_t)) / sizeof(uint32_t);
+	args->fhplusname[pos++] = htonl(len);
+	bcopy(name, &args->fhplusname[pos], len);
+	len = sizeof(uint32_t) + pos * sizeof(uint32_t) +
+	    roundup(len, sizeof(uint32_t));
+
+	rlen = sizeof(*repl);
+
+	cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_LOOKUP,
+	    args, len, repl, rlen);
+	if (cc == -1)
+		return (errno);		/* XXX - from rpc_call */
+	if (cc < 2 * sizeof(uint32_t))
+		return (EIO);
+	if (repl->errno != 0)
+		/* saerrno.h now matches NFS error numbers. */
+		return (ntohl(repl->errno));
+	newfd->fhsize = ntohl(repl->fhsize);
+	bcopy(repl->fhplusattr, &newfd->fh, newfd->fhsize);
+	pos = roundup(newfd->fhsize, sizeof(uint32_t)) / sizeof(uint32_t);
+	if (repl->fhplusattr[pos++] == 0)
+		return (EIO);
+	bcopy(&repl->fhplusattr[pos], &newfd->fa, sizeof(newfd->fa));
+	return (0);
+}
+
+#ifndef NFS_NOSYMLINK
+/*
+ * Get the destination of a symbolic link.
+ */
+int
+nfs_readlink(struct nfs_iodesc *d, char *buf)
+{
+	struct args {
+		uint32_t fhsize;
+		u_char fh[NFS_V3MAXFHSIZE];
+	} *args;
+	struct repl {
+		uint32_t errno;
+		uint32_t ok;
+		struct nfsv3_fattrs fa;
+		uint32_t len;
+		u_char path[NFS_MAXPATHLEN];
+	} *repl;
+	struct {
+		uint32_t h[RPC_HEADER_WORDS];
+		struct args d;
+	} sdata;
+	struct {
+		uint32_t h[RPC_HEADER_WORDS];
+		struct repl d;
+	} rdata;
+	ssize_t cc;
+
+#ifdef NFS_DEBUG
+	if (debug)
+		printf("readlink: called\n");
+#endif
+
+	args = &sdata.d;
+	repl = &rdata.d;
+
+	bzero(args, sizeof(*args));
+	args->fhsize = htonl(d->fhsize);
+	bcopy(d->fh, args->fh, d->fhsize);
+	cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_READLINK,
+	    args, sizeof(uint32_t) + roundup(d->fhsize, sizeof(uint32_t)),
+	    repl, sizeof(*repl));
+	if (cc == -1)
+		return (errno);
+
+	if (cc < 2 * sizeof(uint32_t))
+		return (EIO);
+
+	if (repl->errno != 0)
+		return (ntohl(repl->errno));
+
+	if (repl->ok == 0)
+		return (EIO);
+
+	repl->len = ntohl(repl->len);
+	if (repl->len > NFS_MAXPATHLEN)
+		return (ENAMETOOLONG);
+
+	bcopy(repl->path, buf, repl->len);
+	buf[repl->len] = 0;
+	return (0);
+}
+#endif
+
+/*
+ * Read data from a file.
+ * Return transfer count or -1 (and set errno)
+ */
+ssize_t
+nfs_readdata(struct nfs_iodesc *d, off_t off, void *addr, size_t len)
+{
+	struct args {
+		uint32_t fhsize;
+		uint32_t fhoffcnt[NFS_V3MAXFHSIZE / sizeof(uint32_t) + 3];
+	} *args;
+	struct repl {
+		uint32_t errno;
+		uint32_t ok;
+		struct nfsv3_fattrs fa;
+		uint32_t count;
+		uint32_t eof;
+		uint32_t len;
+		u_char data[NFSREAD_SIZE];
+	} *repl;
+	struct {
+		uint32_t h[RPC_HEADER_WORDS];
+		struct args d;
+	} sdata;
+	struct {
+		uint32_t h[RPC_HEADER_WORDS];
+		struct repl d;
+	} rdata;
+	size_t cc;
+	long x;
+	int hlen, rlen, pos;
+
+	args = &sdata.d;
+	repl = &rdata.d;
+
+	bzero(args, sizeof(*args));
+	args->fhsize = htonl(d->fhsize);
+	bcopy(d->fh, args->fhoffcnt, d->fhsize);
+	pos = roundup(d->fhsize, sizeof(uint32_t)) / sizeof(uint32_t);
+	args->fhoffcnt[pos++] = 0;
+	args->fhoffcnt[pos++] = htonl((uint32_t)off);
+	if (len > NFSREAD_SIZE)
+		len = NFSREAD_SIZE;
+	args->fhoffcnt[pos] = htonl((uint32_t)len);
+	hlen = sizeof(*repl) - NFSREAD_SIZE;
+
+	cc = rpc_call(d->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_READ,
+	    args, 4 * sizeof(uint32_t) + roundup(d->fhsize, sizeof(uint32_t)),
+	    repl, sizeof(*repl));
+	if (cc == -1)
+		/* errno was already set by rpc_call */
+		return (-1);
+	if (cc < hlen) {
+		errno = EBADRPC;
+		return (-1);
+	}
+	if (repl->errno != 0) {
+		errno = ntohl(repl->errno);
+		return (-1);
+	}
+	rlen = cc - hlen;
+	x = ntohl(repl->count);
+	if (rlen < x) {
+		printf("nfsread: short packet, %d < %ld\n", rlen, x);
+		errno = EBADRPC;
+		return (-1);
+	}
+	bcopy(repl->data, addr, x);
+	return (x);
+}
+
+/*
+ * Open a file.
+ * return zero or error number
+ */
+int
+nfs_open(const char *upath, struct open_file *f)
+{
+	struct iodesc *desc;
+	struct nfs_iodesc *currfd;
+	char buf[2 * NFS_V3MAXFHSIZE + 3];
+	u_char *fh;
+	char *cp;
+	int i;
+#ifndef NFS_NOSYMLINK
+	struct nfs_iodesc *newfd;
+	struct nfsv3_fattrs *fa;
+	char *ncp;
+	int c;
+	char namebuf[NFS_MAXPATHLEN + 1];
+	char linkbuf[NFS_MAXPATHLEN + 1];
+	int nlinks = 0;
+#endif
+	int error;
+	char *path;
+
+#ifdef NFS_DEBUG
+ 	if (debug)
+ 	    printf("nfs_open: %s (rootpath=%s)\n", upath, rootpath);
+#endif
+	if (!rootpath[0]) {
+		printf("no rootpath, no nfs\n");
+		return (ENXIO);
+	}
+
+	/*
+	 * This is silly - we should look at dv_type but that value is
+	 * arch dependant and we can't use it here.
+	 */
+#ifndef __i386__
+	if (strcmp(f->f_dev->dv_name, "net") != 0)
+		return (EINVAL);
+#else
+	if (strcmp(f->f_dev->dv_name, "pxe") != 0)
+		return (EINVAL);
+#endif
+
+	if (!(desc = socktodesc(*(int *)(f->f_devdata))))
+		return (EINVAL);
+
+	/* Bind to a reserved port. */
+	desc->myport = htons(--rpc_port);
+	desc->destip = rootip;
+	if ((error = nfs_getrootfh(desc, rootpath, &nfs_root_node.fhsize,
+	    nfs_root_node.fh)))
+		return (error);
+	nfs_root_node.iodesc = desc;
+
+	fh = &nfs_root_node.fh[0];
+	buf[0] = 'X';
+	cp = &buf[1];
+	for (i = 0; i < nfs_root_node.fhsize; i++, cp += 2)
+		sprintf(cp, "%02x", fh[i]);
+	sprintf(cp, "X");
+	setenv("boot.nfsroot.server", inet_ntoa(rootip), 1);
+	setenv("boot.nfsroot.path", rootpath, 1);
+	setenv("boot.nfsroot.nfshandle", buf, 1);
+	sprintf(buf, "%d", nfs_root_node.fhsize);
+	setenv("boot.nfsroot.nfshandlelen", buf, 1);
+
+#ifndef NFS_NOSYMLINK
+	/* Fake up attributes for the root dir. */
+	fa = &nfs_root_node.fa;
+	fa->fa_type  = htonl(NFDIR);
+	fa->fa_mode  = htonl(0755);
+	fa->fa_nlink = htonl(2);
+
+	currfd = &nfs_root_node;
+	newfd = 0;
+
+	cp = path = strdup(upath);
+	if (path == NULL) {
+		error = ENOMEM;
+		goto out;
+	}
+	while (*cp) {
+		/*
+		 * Remove extra separators
+		 */
+		while (*cp == '/')
+			cp++;
+
+		if (*cp == '\0')
+			break;
+		/*
+		 * Check that current node is a directory.
+		 */
+		if (currfd->fa.fa_type != htonl(NFDIR)) {
+			error = ENOTDIR;
+			goto out;
+		}
+
+		/* allocate file system specific data structure */
+		newfd = malloc(sizeof(*newfd));
+		if (newfd == NULL) {
+			error = ENOMEM;
+			goto out;
+		}
+		newfd->iodesc = currfd->iodesc;
+		newfd->off = 0;
+
+		/*
+		 * Get next component of path name.
+		 */
+		{
+			int len = 0;
+
+			ncp = cp;
+			while ((c = *cp) != '\0' && c != '/') {
+				if (++len > NFS_MAXNAMLEN) {
+					error = ENOENT;
+					goto out;
+				}
+				cp++;
+			}
+			*cp = '\0';
+		}
+
+		/* lookup a file handle */
+		error = nfs_lookupfh(currfd, ncp, newfd);
+		*cp = c;
+		if (error)
+			goto out;
+
+		/*
+		 * Check for symbolic link
+		 */
+		if (newfd->fa.fa_type == htonl(NFLNK)) {
+			int link_len, len;
+
+			error = nfs_readlink(newfd, linkbuf);
+			if (error)
+				goto out;
+
+			link_len = strlen(linkbuf);
+			len = strlen(cp);
+
+			if (link_len + len > MAXPATHLEN
+			    || ++nlinks > MAXSYMLINKS) {
+				error = ENOENT;
+				goto out;
+			}
+
+			bcopy(cp, &namebuf[link_len], len + 1);
+			bcopy(linkbuf, namebuf, link_len);
+
+			/*
+			 * If absolute pathname, restart at root.
+			 * If relative pathname, restart at parent directory.
+			 */
+			cp = namebuf;
+			if (*cp == '/') {
+				if (currfd != &nfs_root_node)
+					free(currfd);
+				currfd = &nfs_root_node;
+			}
+
+			free(newfd);
+			newfd = 0;
+
+			continue;
+		}
+
+		if (currfd != &nfs_root_node)
+			free(currfd);
+		currfd = newfd;
+		newfd = 0;
+	}
+
+	error = 0;
+
+out:
+	free(newfd);
+	free(path);
+#else
+	/* allocate file system specific data structure */
+	currfd = malloc(sizeof(*currfd));
+	if (currfd != NULL) {
+		currfd->iodesc = desc;
+		currfd->off = 0;
+
+		error = nfs_lookupfh(&nfs_root_node, upath, currfd);
+	} else
+		error = ENOMEM;
+#endif
+	if (!error) {
+		f->f_fsdata = (void *)currfd;
+		return (0);
+	}
+
+#ifdef NFS_DEBUG
+	if (debug)
+		printf("nfs_open: %s lookupfh failed: %s\n",
+		    path, strerror(error));
+#endif
+#ifndef NFS_NOSYMLINK
+	if (currfd != &nfs_root_node)
+#endif
+		free(currfd);
+
+	return (error);
+}
+
+int
+nfs_close(struct open_file *f)
+{
+	struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
+
+#ifdef NFS_DEBUG
+	if (debug)
+		printf("nfs_close: fp=0x%lx\n", (u_long)fp);
+#endif
+
+	if (fp != &nfs_root_node && fp)
+		free(fp);
+	f->f_fsdata = (void *)0;
+
+	return (0);
+}
+
+/*
+ * read a portion of a file
+ */
+int
+nfs_read(struct open_file *f, void *buf, size_t size, size_t *resid)
+{
+	struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
+	ssize_t cc;
+	char *addr = buf;
+
+#ifdef NFS_DEBUG
+	if (debug)
+		printf("nfs_read: size=%lu off=%d\n", (u_long)size,
+		       (int)fp->off);
+#endif
+	while ((int)size > 0) {
+		twiddle();
+		cc = nfs_readdata(fp, fp->off, (void *)addr, size);
+		/* XXX maybe should retry on certain errors */
+		if (cc == -1) {
+#ifdef NFS_DEBUG
+			if (debug)
+				printf("nfs_read: read: %s", strerror(errno));
+#endif
+			return (errno);	/* XXX - from nfs_readdata */
+		}
+		if (cc == 0) {
+#ifdef NFS_DEBUG
+			if (debug)
+				printf("nfs_read: hit EOF unexpectantly");
+#endif
+			goto ret;
+		}
+		fp->off += cc;
+		addr += cc;
+		size -= cc;
+	}
+ret:
+	if (resid)
+		*resid = size;
+
+	return (0);
+}
+
+/*
+ * Not implemented.
+ */
+int
+nfs_write(struct open_file *f, void *buf, size_t size, size_t *resid)
+{
+	return (EROFS);
+}
+
+off_t
+nfs_seek(struct open_file *f, off_t offset, int where)
+{
+	struct nfs_iodesc *d = (struct nfs_iodesc *)f->f_fsdata;
+	uint32_t size = ntohl(d->fa.fa_size.val[1]);
+
+	switch (where) {
+	case SEEK_SET:
+		d->off = offset;
+		break;
+	case SEEK_CUR:
+		d->off += offset;
+		break;
+	case SEEK_END:
+		d->off = size - offset;
+		break;
+	default:
+		errno = EINVAL;
+		return (-1);
+	}
+
+	return (d->off);
+}
+
+/* NFNON=0, NFREG=1, NFDIR=2, NFBLK=3, NFCHR=4, NFLNK=5, NFSOCK=6, NFFIFO=7 */
+int nfs_stat_types[9] = {
+	0, S_IFREG, S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK, S_IFSOCK, S_IFIFO, 0 };
+
+int
+nfs_stat(struct open_file *f, struct stat *sb)
+{
+	struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
+	uint32_t ftype, mode;
+
+	ftype = ntohl(fp->fa.fa_type);
+	mode  = ntohl(fp->fa.fa_mode);
+	mode |= nfs_stat_types[ftype & 7];
+
+	sb->st_mode  = mode;
+	sb->st_nlink = ntohl(fp->fa.fa_nlink);
+	sb->st_uid   = ntohl(fp->fa.fa_uid);
+	sb->st_gid   = ntohl(fp->fa.fa_gid);
+	sb->st_size  = ntohl(fp->fa.fa_size.val[1]);
+
+	return (0);
+}
+
+static int
+nfs_readdir(struct open_file *f, struct dirent *d)
+{
+	struct nfs_iodesc *fp = (struct nfs_iodesc *)f->f_fsdata;
+	struct nfsv3_readdir_repl *repl;
+	struct nfsv3_readdir_entry *rent;
+	static char *buf;
+	static uint32_t cookie0 = 0;
+	static uint32_t cookie1 = 0;
+	size_t cc;
+	static uint32_t cookieverf0 = 0;
+	static uint32_t cookieverf1 = 0;
+	int pos;
+
+	struct args {
+		uint32_t fhsize;
+		uint32_t fhpluscookie[5 + NFS_V3MAXFHSIZE];
+	} *args;
+	struct {
+		uint32_t h[RPC_HEADER_WORDS];
+		struct args d;
+	} sdata;
+	static struct {
+		uint32_t h[RPC_HEADER_WORDS];
+		u_char d[NFS_READDIRSIZE];
+	} rdata;
+
+	if (cookie0 == 0 && cookie1 == 0) {
+	refill:
+		args = &sdata.d;
+		bzero(args, sizeof(*args));
+
+		args->fhsize = htonl(fp->fhsize);
+		bcopy(fp->fh, args->fhpluscookie, fp->fhsize);
+		pos = roundup(fp->fhsize, sizeof(uint32_t)) / sizeof(uint32_t);
+		args->fhpluscookie[pos++] = cookie0;
+		args->fhpluscookie[pos++] = cookie1;
+		args->fhpluscookie[pos++] = cookieverf0;
+		args->fhpluscookie[pos++] = cookieverf1;
+		args->fhpluscookie[pos] = htonl(NFS_READDIRSIZE);
+
+		cc = rpc_call(fp->iodesc, NFS_PROG, NFS_VER3, NFSPROCV3_READDIR,
+		    args, 6 * sizeof(uint32_t) +
+		    roundup(fp->fhsize, sizeof(uint32_t)),
+		    rdata.d, sizeof(rdata.d));
+		buf  = rdata.d;
+		repl = (struct nfsv3_readdir_repl *)buf;
+		if (repl->errno != 0)
+			return (ntohl(repl->errno));
+		cookieverf0 = repl->cookiev0;
+		cookieverf1 = repl->cookiev1;
+		buf += sizeof (struct nfsv3_readdir_repl);
+	}
+	rent = (struct nfsv3_readdir_entry *)buf;
+
+	if (rent->follows == 0) {
+		/* fid0 is actually eof */
+		if (rent->fid0 != 0) {
+			cookie0 = 0;
+			cookie1 = 0;
+			cookieverf0 = 0;
+			cookieverf1 = 0;
+			return (ENOENT);
+		}
+		goto refill;
+	}
+
+	d->d_namlen = ntohl(rent->len);
+	bcopy(rent->nameplus, d->d_name, d->d_namlen);
+	d->d_name[d->d_namlen] = '\0';
+
+	pos = roundup(d->d_namlen, sizeof(uint32_t)) / sizeof(uint32_t);
+	cookie0 = rent->nameplus[pos++];
+	cookie1 = rent->nameplus[pos++];
+	buf = (u_char *)&rent->nameplus[pos];
+	return (0);
+}
+#endif	/* OLD_NFSV2 */

Modified: stable/8/sys/boot/i386/libi386/pxe.c
==============================================================================
--- stable/8/sys/boot/i386/libi386/pxe.c	Thu Sep 16 01:02:53 2010	(r212716)
+++ stable/8/sys/boot/i386/libi386/pxe.c	Thu Sep 16 01:38:13 2010	(r212717)
@@ -409,6 +409,7 @@ pxe_perror(int err)
  * Reach inside the libstand NFS code and dig out an NFS handle
  * for the root filesystem.
  */
+#ifdef OLD_NFSV2
 struct nfs_iodesc {
 	struct	iodesc	*iodesc;
 	off_t	off;
@@ -456,6 +457,64 @@ pxe_setnfshandle(char *rootpath)
 	sprintf(cp, "X");
 	setenv("boot.nfsroot.nfshandle", buf, 1);
 }
+#else	/* !OLD_NFSV2 */
+
+#define	NFS_V3MAXFHSIZE		64
+
+struct nfs_iodesc {
+	struct iodesc *iodesc;
+	off_t off;
+	uint32_t fhsize;
+	u_char fh[NFS_V3MAXFHSIZE];
+	/* structure truncated */
+};
+extern struct nfs_iodesc nfs_root_node;
+extern int rpc_port;
+
+static void
+pxe_rpcmountcall()
+{
+	struct iodesc *d;
+	int error;
+
+	if (!(d = socktodesc(pxe_sock)))
+		return;
+        d->myport = htons(--rpc_port);
+        d->destip = rootip;
+	if ((error = nfs_getrootfh(d, rootpath, &nfs_root_node.fhsize,
+	    nfs_root_node.fh)) != 0) {
+		printf("NFS MOUNT RPC error: %d\n", error);
+		nfs_root_node.fhsize = 0;
+	}
+	nfs_root_node.iodesc = d;
+}
+
+static void
+pxe_setnfshandle(char *rootpath)
+{
+	int i;
+	u_char *fh;
+	char buf[2 * NFS_V3MAXFHSIZE + 3], *cp;
+
+	/*
+	 * If NFS files were never opened, we need to do mount call
+	 * ourselves. Use nfs_root_node.iodesc as flag indicating
+	 * previous NFS usage.
+	 */
+	if (nfs_root_node.iodesc == NULL)
+		pxe_rpcmountcall();
+
+	fh = &nfs_root_node.fh[0];
+	buf[0] = 'X';
+	cp = &buf[1];
+	for (i = 0; i < nfs_root_node.fhsize; i++, cp += 2)
+		sprintf(cp, "%02x", fh[i]);
+	sprintf(cp, "X");
+	setenv("boot.nfsroot.nfshandle", buf, 1);
+	sprintf(buf, "%d", nfs_root_node.fhsize);
+	setenv("boot.nfsroot.nfshandlelen", buf, 1);
+}
+#endif	/* OLD_NFSV2 */
 
 void
 pxenv_call(int func)



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201009160138.o8G1cDo6057054>