4799697 nfs messages could be more useful
authorrobinson
Tue, 10 Jan 2006 08:52:24 -0800
changeset 1232 1a9b1651d839
parent 1231 64215f768e86
child 1233 9123c13d9a7f
4799697 nfs messages could be more useful 6354997 File changes on NFSv4 servers take a long time to be detected 6355634 Client handling of CB_GETATTR fails to set bitmap
usr/src/uts/common/fs/nfs/nfs4_callback.c
usr/src/uts/common/fs/nfs/nfs4_srv_attr.c
usr/src/uts/common/fs/nfs/nfs4_srv_deleg.c
usr/src/uts/common/fs/nfs/nfs4_xdr.c
usr/src/uts/common/fs/nfs/nfs_server.c
usr/src/uts/common/nfs/nfs4.h
usr/src/uts/common/nfs/nfs4_kprot.h
--- a/usr/src/uts/common/fs/nfs/nfs4_callback.c	Tue Jan 10 08:05:23 2006 -0800
+++ b/usr/src/uts/common/fs/nfs/nfs4_callback.c	Tue Jan 10 08:52:24 2006 -0800
@@ -20,7 +20,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -93,8 +93,6 @@
 nfs_space_limit4 nfs4_deleg_space_phony2 = { NFS_LIMIT_BLOCKS, 0 };
 nfs_modified_limit4 nfs4_deleg_space_phonyl = { 8, 512 };
 changeid4 nfs4_deleg_change_phony = 0x7eeeeeee76666660LL;
-/* ignore malformed file handle on recall, bug in linux server */
-int nfs4_linux_bug = 1;
 int nfs4_use_phony_limit;
 int nfs4_use_phony_recall;
 int nfs4_phony_recall_v;
@@ -192,7 +190,7 @@
 	bool_t found = FALSE;
 	struct nfs4_server *sp;
 	struct fattr4 *fap;
-	char *fdata = NULL;
+	rpc_inline_t *fdata;
 	long mapcnt;
 	fattr4_change change;
 	fattr4_size size;
@@ -317,7 +315,7 @@
 
 	fap->attrmask = 0;
 	/* attrlist4_len starts at 0 and increases as attrs are processed */
-	fap->attrlist4 = fdata;
+	fap->attrlist4 = (char *)fdata;
 	fap->attrlist4_len = 0;
 
 	/* don't supply attrs if request was zero */
@@ -359,6 +357,7 @@
 			 */
 			IXDR_PUT_U_HYPER(fdata, change);
 			fap->attrlist4_len += 2 * BYTES_PER_XDR_UNIT;
+			fap->attrmask |= FATTR4_CHANGE_MASK;
 		}
 
 		if (args->attr_request & FATTR4_SIZE_MASK) {
@@ -376,6 +375,7 @@
 			 */
 			IXDR_PUT_U_HYPER(fdata, size);
 			fap->attrlist4_len += 2 * BYTES_PER_XDR_UNIT;
+			fap->attrmask |= FATTR4_SIZE_MASK;
 		}
 	}
 
@@ -457,11 +457,6 @@
 			} else {
 #ifdef	DEBUG
 				CB_WARN("cb_recall: stateid OK, bad fh");
-
-				if (nfs4_linux_bug) {
-					found = TRUE;
-					break;
-				}
 #endif
 			}
 		}
@@ -735,7 +730,7 @@
 		break;
 
 	case CB_COMPOUND:
-		xdr_args = xdr_CB_COMPOUND4args;
+		xdr_args = xdr_CB_COMPOUND4args_clnt;
 		xdr_res = xdr_CB_COMPOUND4res;
 		proc = cb_compound;
 		freeproc = cb_compound_free;
--- a/usr/src/uts/common/fs/nfs/nfs4_srv_attr.c	Tue Jan 10 08:05:23 2006 -0800
+++ b/usr/src/uts/common/fs/nfs/nfs4_srv_attr.c	Tue Jan 10 08:52:24 2006 -0800
@@ -20,7 +20,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -753,19 +753,37 @@
 	return (error);
 }
 
+/*
+ * Server side compare of a filehandle from the wire to a native
+ * server filehandle.
+ */
+static int
+rfs4fhcmp(nfs_fh4 *wirefh, nfs_fh4 *srvfh)
+{
+	nfs_fh4_fmt_t fh;
+
+	ASSERT(IS_P2ALIGNED(wirefh->nfs_fh4_val, sizeof (uint32_t)));
+
+	bzero(&fh, sizeof (nfs_fh4_fmt_t));
+	if (!xdr_inline_decode_nfs_fh4((uint32_t *)wirefh->nfs_fh4_val, &fh,
+	    wirefh->nfs_fh4_len))
+		return (1);
+
+	return (bcmp(srvfh->nfs_fh4_val, &fh, srvfh->nfs_fh4_len));
+}
+
 /* ARGSUSED */
 static int
 rfs4_fattr4_filehandle(nfs4_attr_cmd_t cmd, struct nfs4_svgetit_arg *sarg,
 	union nfs4_attr_u *na)
 {
-	int error = 0;
 	nfs_fh4 *fh;
 
 	switch (cmd) {
 	case NFS4ATTR_SUPPORTED:
 		if (sarg->op == NFS4ATTR_SETIT)
-			error = EINVAL;
-		break;		/* this attr is supported */
+			return (EINVAL);
+		return (0);	/* this attr is supported */
 	case NFS4ATTR_GETIT:
 		/*
 		 * If sarg->cs->fh is all zeros then should makefh a new
@@ -773,42 +791,44 @@
 		 */
 		fh = &sarg->cs->fh;
 		if (sarg->cs->fh.nfs_fh4_len == 0) {
-			if (sarg->rdattr_error && (sarg->cs->vp == NULL)) {
-				error = -1;	/* okay if rdattr_error */
-				break;
-			}
+			if (sarg->rdattr_error && (sarg->cs->vp == NULL))
+				return (-1);	/* okay if rdattr_error */
 			ASSERT(sarg->cs->vp != NULL);
 			na->filehandle.nfs_fh4_val =
-				kmem_alloc(NFS_FH4_LEN, KM_SLEEP);
-			error = makefh4(&na->filehandle, sarg->cs->vp,
-					sarg->cs->exi);
-		} else {
-			na->filehandle.nfs_fh4_val =
-				kmem_alloc(fh->nfs_fh4_len, KM_SLEEP);
-			nfs_fh4_copy(fh, &na->filehandle);
+			    kmem_alloc(NFS_FH4_LEN, KM_SLEEP);
+			return (makefh4(&na->filehandle, sarg->cs->vp,
+			    sarg->cs->exi));
 		}
-		break;
+		na->filehandle.nfs_fh4_val =
+		    kmem_alloc(fh->nfs_fh4_len, KM_SLEEP);
+		nfs_fh4_copy(fh, &na->filehandle);
+		return (0);
 	case NFS4ATTR_SETIT:
 		/*
 		 * read-only attr
 		 */
-		error = EINVAL;
-		break;
+		return (EINVAL);
 	case NFS4ATTR_VERIT:
-		if (nfs4cmpfh(&na->filehandle, &sarg->cs->fh))
-			error = -1;	/* no match */
-		break;
+		/*
+		 * A verify of a filehandle will have the client sending
+		 * the raw format which needs to be compared to the
+		 * native format.
+		 */
+		if (rfs4fhcmp(&na->filehandle, &sarg->cs->fh) == 1)
+			return (-1);	/* no match */
+		return (0);
 	case NFS4ATTR_FREEIT:
-		if (sarg->op == NFS4ATTR_GETIT) {
-			if (na->filehandle.nfs_fh4_val) {
-				kmem_free(na->filehandle.nfs_fh4_val,
-					na->filehandle.nfs_fh4_len);
-				bzero(&na->filehandle, sizeof (na->filehandle));
-			}
-		}
-		break;
+		if (sarg->op != NFS4ATTR_GETIT)
+			return (0);
+		if (na->filehandle.nfs_fh4_val == NULL)
+			return (0);
+		kmem_free(na->filehandle.nfs_fh4_val,
+		    na->filehandle.nfs_fh4_len);
+		na->filehandle.nfs_fh4_val = NULL;
+		na->filehandle.nfs_fh4_len = 0;
+		return (0);
 	}
-	return (error);
+	return (0);
 }
 
 /*
--- a/usr/src/uts/common/fs/nfs/nfs4_srv_deleg.c	Tue Jan 10 08:05:23 2006 -0800
+++ b/usr/src/uts/common/fs/nfs/nfs4_srv_deleg.c	Tue Jan 10 08:52:24 2006 -0800
@@ -20,7 +20,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -833,7 +833,7 @@
 		 */
 		args->callback_ident = cbp->cb_ident;
 
-		stat = clnt_call(ch, CB_COMPOUND, xdr_CB_COMPOUND4args,
+		stat = clnt_call(ch, CB_COMPOUND, xdr_CB_COMPOUND4args_srv,
 			(caddr_t)args, xdr_CB_COMPOUND4res,
 			(caddr_t)res, timeout);
 
--- a/usr/src/uts/common/fs/nfs/nfs4_xdr.c	Tue Jan 10 08:05:23 2006 -0800
+++ b/usr/src/uts/common/fs/nfs/nfs4_xdr.c	Tue Jan 10 08:52:24 2006 -0800
@@ -20,7 +20,7 @@
  * CDDL HEADER END
  */
 /*
- *	Copyright 2005 Sun Microsystems, Inc.
+ *	Copyright 2006 Sun Microsystems, Inc.
  *	All rights reserved.  Use is subject to license terms.
  */
 
@@ -149,6 +149,179 @@
 }
 
 /*
+ * XDR_INLINE decode a filehandle.
+ */
+bool_t
+xdr_inline_decode_nfs_fh4(uint32_t *ptr, nfs_fh4_fmt_t *fhp, uint32_t fhsize)
+{
+	uchar_t *bp = (uchar_t *)ptr;
+	uchar_t *cp;
+	uint32_t dsize;
+	uintptr_t resid;
+
+	/*
+	 * Check to see if what the client sent us is bigger or smaller
+	 * than what we can ever possibly send out. NFS_FHMAXDATA is
+	 * unfortunately badly named as it is no longer the max and is
+	 * really the min of what is sent over the wire.
+	 */
+	if (fhsize > sizeof (nfs_fh4_fmt_t) || fhsize < (sizeof (fsid_t) +
+	    sizeof (ushort_t) + NFS_FHMAXDATA +
+	    sizeof (ushort_t) + NFS_FHMAXDATA)) {
+		return (FALSE);
+	}
+
+	/*
+	 * All internal parts of a filehandle are in native byte order.
+	 *
+	 * Decode what should be fh4_fsid, it is aligned.
+	 */
+	fhp->fh4_fsid.val[0] = *(uint32_t *)bp;
+	bp += BYTES_PER_XDR_UNIT;
+	fhp->fh4_fsid.val[1] = *(uint32_t *)bp;
+	bp += BYTES_PER_XDR_UNIT;
+
+	/*
+	 * Decode what should be fh4_len.  fh4_len is two bytes, so we're
+	 * unaligned now.
+	 */
+	cp = (uchar_t *)&fhp->fh4_len;
+	*cp++ = *bp++;
+	*cp++ = *bp++;
+	fhsize -= 2 * BYTES_PER_XDR_UNIT + sizeof (ushort_t);
+
+	/*
+	 * For backwards compatability, the fid length may be less than
+	 * NFS_FHMAXDATA, but it was always encoded as NFS_FHMAXDATA bytes.
+	 */
+	dsize = fhp->fh4_len < NFS_FHMAXDATA ? NFS_FHMAXDATA : fhp->fh4_len;
+
+	/*
+	 * Make sure the client isn't sending us a bogus length for fh4_data.
+	 */
+	if (fhsize < dsize)
+		return (FALSE);
+	bcopy(bp, fhp->fh4_data, dsize);
+	bp += dsize;
+	fhsize -= dsize;
+
+	if (fhsize < sizeof (ushort_t))
+		return (FALSE);
+	cp = (uchar_t *)&fhp->fh4_xlen;
+	*cp++ = *bp++;
+	*cp++ = *bp++;
+	fhsize -= sizeof (ushort_t);
+
+	dsize = fhp->fh4_xlen < NFS_FHMAXDATA ? NFS_FHMAXDATA : fhp->fh4_xlen;
+
+	/*
+	 * Make sure the client isn't sending us a bogus length for fh4_xdata.
+	 */
+	if (fhsize < dsize)
+		return (FALSE);
+	bcopy(bp, fhp->fh4_xdata, dsize);
+	fhsize -= dsize;
+	bp += dsize;
+
+	/*
+	 * We realign things on purpose, so skip any padding
+	 */
+	resid = (uintptr_t)bp % BYTES_PER_XDR_UNIT;
+	if (resid != 0) {
+		if (fhsize < (BYTES_PER_XDR_UNIT - resid))
+			return (FALSE);
+		bp += BYTES_PER_XDR_UNIT - resid;
+		fhsize -= BYTES_PER_XDR_UNIT - resid;
+	}
+
+	if (fhsize < BYTES_PER_XDR_UNIT)
+		return (FALSE);
+	fhp->fh4_flag = *(uint32_t *)bp;
+	bp += BYTES_PER_XDR_UNIT;
+	fhsize -= BYTES_PER_XDR_UNIT;
+
+#ifdef VOLATILE_FH_TEST
+	if (fhsize < BYTES_PER_XDR_UNIT)
+		return (FALSE);
+	fhp->fh4_volatile_id = *(uint32_t *)bp;
+	bp += BYTES_PER_XDR_UNIT;
+	fhsize -= BYTES_PER_XDR_UNIT;
+#endif
+	/*
+	 * Make sure client didn't send extra bytes
+	 */
+	if (fhsize != 0)
+		return (FALSE);
+	return (TRUE);
+}
+
+static bool_t
+xdr_decode_nfs_fh4(XDR *xdrs, nfs_fh4 *objp)
+{
+	uint32_t fhsize;		/* filehandle size */
+	uint32_t bufsize;
+	rpc_inline_t *ptr;
+	uchar_t *buf, *bp;
+
+	ASSERT(xdrs->x_op == XDR_DECODE);
+
+	/*
+	 * Retrieve the filehandle length.
+	 */
+	if (!XDR_GETINT32(xdrs, (int32_t *)&fhsize))
+		return (FALSE);
+
+	objp->nfs_fh4_val = NULL;
+	objp->nfs_fh4_len = 0;
+
+	/*
+	 * Check to see if what the client sent us is bigger or smaller
+	 * than what we can ever possibly send out. NFS_FHMAXDATA is
+	 * unfortunately badly named as it is no longer the max and is
+	 * really the min of what is sent over the wire.
+	 */
+	if (fhsize > sizeof (nfs_fh4_fmt_t) || fhsize < (sizeof (fsid_t) +
+	    sizeof (ushort_t) + NFS_FHMAXDATA +
+	    sizeof (ushort_t) + NFS_FHMAXDATA)) {
+		if (!XDR_CONTROL(xdrs, XDR_SKIPBYTES, &fhsize))
+			return (FALSE);
+		return (TRUE);
+	}
+
+	/*
+	 * bring in fhsize plus any padding
+	 */
+	bufsize = RNDUP(fhsize);
+	ptr = XDR_INLINE(xdrs, bufsize);
+	bp = (uchar_t *)ptr;
+	if (ptr == NULL) {
+		bp = buf = kmem_alloc(bufsize, KM_SLEEP);
+		if (!xdr_opaque(xdrs, (char *)bp, bufsize))
+			return (FALSE);
+	}
+
+	objp->nfs_fh4_val = kmem_zalloc(sizeof (nfs_fh4_fmt_t), KM_SLEEP);
+	objp->nfs_fh4_len = sizeof (nfs_fh4_fmt_t);
+
+	if (xdr_inline_decode_nfs_fh4((uint32_t *)bp,
+	    (nfs_fh4_fmt_t *)objp->nfs_fh4_val, fhsize) == FALSE) {
+		/*
+		 * If in the process of decoding we find the file handle
+		 * is not correctly formed, we need to continue decoding
+		 * and trigger an NFS layer error. Set the nfs_fh4_len to
+		 * zero so it gets caught as a bad length.
+		 */
+		kmem_free(objp->nfs_fh4_val, objp->nfs_fh4_len);
+		objp->nfs_fh4_val = NULL;
+		objp->nfs_fh4_len = 0;
+	}
+
+	if (ptr == NULL)
+		kmem_free(buf, bufsize);
+	return (TRUE);
+}
+
+/*
  * XDR_INLINE encode a filehandle.
  */
 bool_t
@@ -240,162 +413,6 @@
 }
 
 static bool_t
-xdr_decode_nfs_fh4(XDR *xdrs, nfs_fh4 *objp)
-{
-	uint32_t fhsize;		/* filehandle size */
-	uint32_t bufsize;
-	uint32_t dsize;
-	nfs_fh4_fmt_t *fh_fmtp;
-	rpc_inline_t *ptr;
-	uintptr_t resid;
-	uchar_t *buf, *bp, *cp;
-
-	ASSERT(xdrs->x_op == XDR_DECODE);
-
-	/*
-	 * Retrieve the filehandle length.
-	 */
-	if (!XDR_GETINT32(xdrs, (int32_t *)&fhsize))
-		return (FALSE);
-
-	objp->nfs_fh4_val = NULL;
-	objp->nfs_fh4_len = 0;
-
-	/*
-	 * Check to see if what the client sent us is bigger or smaller
-	 * than what we can ever possibly send out. NFS_FHMAXDATA is
-	 * unfortunately badly named as it is no longer the max and is
-	 * really the min of what is sent over the wire.
-	 */
-	if (fhsize > sizeof (nfs_fh4_fmt_t) || fhsize < (sizeof (fsid_t) +
-	    sizeof (ushort_t) + NFS_FHMAXDATA +
-	    sizeof (ushort_t) + NFS_FHMAXDATA)) {
-		if (!XDR_CONTROL(xdrs, XDR_SKIPBYTES, &fhsize))
-			return (FALSE);
-		return (TRUE);
-	}
-
-	/*
-	 * bring in fhsize plus any padding
-	 */
-	bufsize = RNDUP(fhsize);
-	ptr = XDR_INLINE(xdrs, bufsize);
-	if (ptr == NULL) {
-		bp = buf = kmem_alloc(bufsize, KM_SLEEP);
-		if (!xdr_opaque(xdrs, (char *)bp, bufsize))
-			return (FALSE);
-	} else {
-		bp = (uchar_t *)ptr;
-	}
-
-	objp->nfs_fh4_val = kmem_zalloc(sizeof (nfs_fh4_fmt_t), KM_SLEEP);
-	objp->nfs_fh4_len = sizeof (nfs_fh4_fmt_t);
-	fh_fmtp = (nfs_fh4_fmt_t *)objp->nfs_fh4_val;
-
-	/*
-	 * All internal parts of a filehandle are in native byte order.
-	 *
-	 * Decode what should be fh4_fsid, it is aligned.
-	 */
-	fh_fmtp->fh4_fsid.val[0] = *(uint32_t *)bp;
-	bp += BYTES_PER_XDR_UNIT;
-	fh_fmtp->fh4_fsid.val[1] = *(uint32_t *)bp;
-	bp += BYTES_PER_XDR_UNIT;
-
-	/*
-	 * Decode what should be fh4_len.  fh4_len is two bytes, so we're
-	 * unaligned now.
-	 */
-	cp = (uchar_t *)&fh_fmtp->fh4_len;
-	*cp++ = *bp++;
-	*cp++ = *bp++;
-	fhsize -= 2 * BYTES_PER_XDR_UNIT + sizeof (ushort_t);
-
-	/*
-	 * For backwards compatability, the fid length may be less than
-	 * NFS_FHMAXDATA, but it was always encoded as NFS_FHMAXDATA bytes.
-	 */
-	dsize = fh_fmtp->fh4_len < NFS_FHMAXDATA ? NFS_FHMAXDATA :
-	    fh_fmtp->fh4_len;
-
-	/*
-	 * Make sure the client isn't sending us a bogus length for fh4_data.
-	 */
-	if (dsize > fhsize)
-		goto badfh;
-	bcopy(bp, fh_fmtp->fh4_data, dsize);
-	bp += dsize;
-	fhsize -= dsize;
-
-	if (fhsize < sizeof (ushort_t))
-		goto badfh;
-	cp = (uchar_t *)&fh_fmtp->fh4_xlen;
-	*cp++ = *bp++;
-	*cp++ = *bp++;
-	fhsize -= sizeof (ushort_t);
-
-	dsize = fh_fmtp->fh4_xlen < NFS_FHMAXDATA ? NFS_FHMAXDATA :
-	    fh_fmtp->fh4_xlen;
-	/*
-	 * Make sure the client isn't sending us a bogus length for fh4_xdata.
-	 */
-	if (dsize > fhsize)
-		goto badfh;
-	bcopy(bp, fh_fmtp->fh4_xdata, dsize);
-	fhsize -= dsize;
-	bp += dsize;
-
-	/*
-	 * We realign things on purpose, so skip any padding
-	 */
-	resid = (uintptr_t)bp % BYTES_PER_XDR_UNIT;
-	if (resid != 0) {
-		if (fhsize < (BYTES_PER_XDR_UNIT - resid))
-			goto badfh;
-		bp += BYTES_PER_XDR_UNIT - resid;
-		fhsize -= BYTES_PER_XDR_UNIT - resid;
-	}
-
-	if (fhsize < BYTES_PER_XDR_UNIT)
-		goto badfh;
-	fh_fmtp->fh4_flag = *(uint32_t *)bp;
-	bp += BYTES_PER_XDR_UNIT;
-	fhsize -= BYTES_PER_XDR_UNIT;
-
-#ifdef VOLATILE_FH_TEST
-	if (fhsize < BYTES_PER_XDR_UNIT)
-		goto badfh;
-	fh_fmtp->fh4_fh4_volatile_id = *(uint32_t *)bp;
-	bp += BYTES_PER_XDR_UNIT;
-	fhsize -= BYTES_PER_XDR_UNIT;
-#endif
-	/*
-	 * Make sure client didn't send extra bytes
-	 */
-	if (fhsize != 0)
-		goto badfh;
-
-	if (ptr == NULL)
-		kmem_free(buf, bufsize);
-	return (TRUE);
-
-badfh:
-	/*
-	 * If in the process of decoding we find the file handle
-	 * is not correctly formed, we need to continue decoding
-	 * and trigger an NFS layer error. Set the nfs_fh4_len to
-	 * zero so it gets caught as a bad length.
-	 */
-	if (objp->nfs_fh4_val != NULL)
-		kmem_free(objp->nfs_fh4_val, objp->nfs_fh4_len);
-	objp->nfs_fh4_val = NULL;
-	objp->nfs_fh4_len = 0;
-	if (ptr == NULL)
-		kmem_free(buf, bufsize);
-	return (TRUE);
-}
-
-static bool_t
 xdr_encode_nfs_fh4(XDR *xdrs, nfs_fh4 *objp)
 {
 	uint_t otw_len, fsize, xsize;   /* otw, file, and export sizes */
@@ -450,20 +467,26 @@
 
 /*
  * XDR a NFSv4 filehandle.
+ * Encoding interprets the contents (server).
+ * Decoding the contents are opaque (client).
  */
 bool_t
 xdr_nfs_fh4(XDR *xdrs, nfs_fh4 *objp)
 {
-	if (xdrs->x_op == XDR_DECODE)
-		return (xdr_decode_nfs_fh4(xdrs, objp));
-	else if (xdrs->x_op == XDR_ENCODE)
+	switch (xdrs->x_op) {
+	case XDR_ENCODE:
 		return (xdr_encode_nfs_fh4(xdrs, objp));
-
-	if (objp->nfs_fh4_val != NULL) {
-		kmem_free(objp->nfs_fh4_val, objp->nfs_fh4_len);
-		objp->nfs_fh4_val = NULL;
+	case XDR_DECODE:
+		return (xdr_bytes(xdrs, (char **)&objp->nfs_fh4_val,
+		    (uint_t *)&objp->nfs_fh4_len, NFS4_FHSIZE));
+	case XDR_FREE:
+		if (objp->nfs_fh4_val != NULL) {
+			kmem_free(objp->nfs_fh4_val, objp->nfs_fh4_len);
+			objp->nfs_fh4_val = NULL;
+		}
+		return (TRUE);
 	}
-	return (TRUE);
+	return (FALSE);
 }
 
 /* Called by xdr_array */
@@ -4397,7 +4420,7 @@
 		if (objp->nfs_resop4_u.opgetfh.status != NFS4_OK)
 			return (TRUE);
 		return (xdr_encode_nfs_fh4(xdrs,
-			&objp->nfs_resop4_u.opgetfh.object));
+		    &objp->nfs_resop4_u.opgetfh.object));
 	default:
 		return (xdr_nfs_resop4(xdrs, objp));
 	}
@@ -4715,35 +4738,78 @@
 				    objp->array_len, objp->array_len));
 }
 
+/*
+ * NFS server side callback, initiating the callback request so it
+ * is the RPC client. Must convert from server's internal filehandle
+ * format to wire format.
+ */
 static bool_t
-xdr_nfs_cb_argop4(XDR *xdrs, nfs_cb_argop4 *objp)
+xdr_snfs_cb_argop4(XDR *xdrs, nfs_cb_argop4 *objp)
 {
+	CB_GETATTR4args *gargs;
+	CB_RECALL4args *rargs;
+
+	ASSERT(xdrs->x_op == XDR_ENCODE);
+
+	if (!XDR_PUTINT32(xdrs, (int32_t *)&objp->argop))
+		return (FALSE);
+
+	switch (objp->argop) {
+	case OP_CB_GETATTR:
+		gargs = &objp->nfs_cb_argop4_u.opcbgetattr;
+
+		if (!xdr_encode_nfs_fh4(xdrs, &gargs->fh))
+			return (FALSE);
+		return (xdr_bitmap4(xdrs, &gargs->attr_request));
+	case OP_CB_RECALL:
+		rargs = &objp->nfs_cb_argop4_u.opcbrecall;
+
+		if (!XDR_PUTINT32(xdrs, (int32_t *)&rargs->stateid.seqid))
+			return (FALSE);
+		if (!xdr_opaque(xdrs, rargs->stateid.other, 12))
+			return (FALSE);
+		if (!XDR_PUTINT32(xdrs, (int32_t *)&rargs->truncate))
+			return (FALSE);
+		return (xdr_encode_nfs_fh4(xdrs, &rargs->fh));
+	case OP_CB_ILLEGAL:
+		return (TRUE);
+	}
+	return (FALSE);
+}
+
+/*
+ * NFS client side callback, receiving the callback request so it
+ * is the RPC server. Must treat the file handles as opaque.
+ */
+static bool_t
+xdr_cnfs_cb_argop4(XDR *xdrs, nfs_cb_argop4 *objp)
+{
+	CB_GETATTR4args *gargs;
+	CB_RECALL4args *rargs;
+
+	ASSERT(xdrs->x_op != XDR_ENCODE);
+
 	if (!xdr_u_int(xdrs, &objp->argop))
 		return (FALSE);
 	switch (objp->argop) {
 	case OP_CB_GETATTR:
-		if (!xdr_bytes(xdrs,
-		    (char **)&objp->nfs_cb_argop4_u.opcbgetattr.fh.nfs_fh4_val,
-		    (uint_t *)&objp->nfs_cb_argop4_u.opcbgetattr.fh.nfs_fh4_len,
-		    NFS4_FHSIZE))
-			return (FALSE);
-		return (xdr_bitmap4(xdrs,
-			&objp->nfs_cb_argop4_u.opcbgetattr.attr_request));
-	case OP_CB_RECALL:
-		if (!xdr_u_int(xdrs,
-			    &objp->nfs_cb_argop4_u.opcbrecall.stateid.seqid))
+		gargs = &objp->nfs_cb_argop4_u.opcbgetattr;
+
+		if (!xdr_bytes(xdrs, (char **)&gargs->fh.nfs_fh4_val,
+		    (uint_t *)&gargs->fh.nfs_fh4_len, NFS4_FHSIZE))
 			return (FALSE);
-		if (!xdr_opaque(xdrs,
-			    objp->nfs_cb_argop4_u.opcbrecall.stateid.other,
-			    12))
+		return (xdr_bitmap4(xdrs, &gargs->attr_request));
+	case OP_CB_RECALL:
+		rargs = &objp->nfs_cb_argop4_u.opcbrecall;
+
+		if (!xdr_u_int(xdrs, &rargs->stateid.seqid))
 			return (FALSE);
-		if (!xdr_bool(xdrs,
-				&objp->nfs_cb_argop4_u.opcbrecall.truncate))
+		if (!xdr_opaque(xdrs, rargs->stateid.other, 12))
 			return (FALSE);
-		return (xdr_bytes(xdrs,
-		    (char **)&objp->nfs_cb_argop4_u.opcbrecall.fh.nfs_fh4_val,
-		    (uint_t *)&objp->nfs_cb_argop4_u.opcbrecall.fh.nfs_fh4_len,
-		    NFS4_FHSIZE));
+		if (!xdr_bool(xdrs, &rargs->truncate))
+			return (FALSE);
+		return (xdr_bytes(xdrs, (char **)&rargs->fh.nfs_fh4_val,
+		    (uint_t *)&rargs->fh.nfs_fh4_len, NFS4_FHSIZE));
 	case OP_CB_ILLEGAL:
 		return (TRUE);
 	}
@@ -4776,8 +4842,11 @@
 	return (FALSE);
 }
 
+/*
+ * The NFS client side callback, RPC server
+ */
 bool_t
-xdr_CB_COMPOUND4args(XDR *xdrs, CB_COMPOUND4args *objp)
+xdr_CB_COMPOUND4args_clnt(XDR *xdrs, CB_COMPOUND4args *objp)
 {
 	if (!xdr_bytes(xdrs, (char **)&objp->tag.utf8string_val,
 			(uint_t *)&objp->tag.utf8string_len,
@@ -4789,7 +4858,26 @@
 		return (FALSE);
 	return (xdr_array(xdrs, (char **)&objp->array,
 			(uint_t *)&objp->array_len, NFS4_COMPOUND_LIMIT,
-			sizeof (nfs_cb_argop4), (xdrproc_t)xdr_nfs_cb_argop4));
+			sizeof (nfs_cb_argop4), (xdrproc_t)xdr_cnfs_cb_argop4));
+}
+
+/*
+ * The NFS server side callback, RPC client
+ */
+bool_t
+xdr_CB_COMPOUND4args_srv(XDR *xdrs, CB_COMPOUND4args *objp)
+{
+	if (!xdr_bytes(xdrs, (char **)&objp->tag.utf8string_val,
+			(uint_t *)&objp->tag.utf8string_len,
+			NFS4_MAX_UTF8STRING))
+		return (FALSE);
+	if (!xdr_u_int(xdrs, &objp->minorversion))
+		return (FALSE);
+	if (!xdr_u_int(xdrs, &objp->callback_ident))
+		return (FALSE);
+	return (xdr_array(xdrs, (char **)&objp->array,
+			(uint_t *)&objp->array_len, NFS4_COMPOUND_LIMIT,
+			sizeof (nfs_cb_argop4), (xdrproc_t)xdr_snfs_cb_argop4));
 }
 
 bool_t
--- a/usr/src/uts/common/fs/nfs/nfs_server.c	Tue Jan 10 08:05:23 2006 -0800
+++ b/usr/src/uts/common/fs/nfs/nfs_server.c	Tue Jan 10 08:52:24 2006 -0800
@@ -20,7 +20,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -1426,6 +1426,8 @@
 	struct netbuf	nb;
 	bool_t logging_enabled = FALSE;
 	struct exportinfo *nfslog_exi = NULL;
+	char **procnames;
+	char cbuf[INET6_ADDRSTRLEN];	/* to hold both IPv4 and IPv6 addr */
 
 	vers = req->rq_vers;
 
@@ -1447,12 +1449,13 @@
 	(*(disptable[(int)vers].dis_proccntp))[which].value.ui64++;
 
 	disp = &disptable[(int)vers].dis_table[which];
+	procnames = disptable[(int)vers].dis_procnames;
 
 	auth_flavor = req->rq_cred.oa_flavor;
+
 	/*
 	 * Deserialize into the args struct.
 	 */
-
 	args = (char *)&args_buf;
 
 #ifdef DEBUG
@@ -1468,8 +1471,11 @@
 		if (!SVC_GETARGS(xprt, disp->dis_xdrargs, args)) {
 			svcerr_decode(xprt);
 			error++;
-			cmn_err(CE_NOTE, "%s: bad getargs for %u/%d",
-			    pgmname, vers + min_vers, which);
+			cmn_err(CE_NOTE,
+			    "Failed to decode arguments for %s version %u "
+			    "procedure %s client %s%s",
+			    pgmname, vers + min_vers, procnames[which],
+			    client_name(req), client_addr(req, cbuf));
 			goto done;
 		}
 	}
@@ -1741,7 +1747,7 @@
 rfs_dispatch(struct svc_req *req, SVCXPRT *xprt)
 {
 	common_dispatch(req, xprt, NFS_VERSMIN, NFS_VERSMAX,
-		"nfs_server", rfs_disptable);
+		"NFS", rfs_disptable);
 }
 
 static char *aclcallnames_v2[] = {
@@ -1867,7 +1873,7 @@
 acl_dispatch(struct svc_req *req, SVCXPRT *xprt)
 {
 	common_dispatch(req, xprt, NFS_ACL_VERSMIN, NFS_ACL_VERSMAX,
-		"acl_server", acl_disptable);
+		"ACL", acl_disptable);
 }
 
 int
--- a/usr/src/uts/common/nfs/nfs4.h	Tue Jan 10 08:05:23 2006 -0800
+++ b/usr/src/uts/common/nfs/nfs4.h	Tue Jan 10 08:52:24 2006 -0800
@@ -20,7 +20,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -1286,6 +1286,8 @@
 extern uint_t nfs4_tsize(struct knetconfig *);
 extern uint_t rfs4_tsize(struct svc_req *);
 
+extern bool_t	xdr_inline_decode_nfs_fh4(uint32_t *, nfs_fh4_fmt_t *,
+			uint32_t);
 extern bool_t	xdr_inline_encode_nfs_fh4(uint32_t **, uint32_t *,
 			nfs_fh4_fmt_t *);
 
--- a/usr/src/uts/common/nfs/nfs4_kprot.h	Tue Jan 10 08:05:23 2006 -0800
+++ b/usr/src/uts/common/nfs/nfs4_kprot.h	Tue Jan 10 08:52:24 2006 -0800
@@ -20,7 +20,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -1621,7 +1621,8 @@
 extern  bool_t xdr_COMPOUND4args_srv(XDR *, COMPOUND4args *);
 extern  bool_t xdr_COMPOUND4res_clnt(XDR *, COMPOUND4res_clnt *);
 extern  bool_t xdr_COMPOUND4res_srv(XDR *, COMPOUND4res *);
-extern  bool_t xdr_CB_COMPOUND4args(XDR *, CB_COMPOUND4args *);
+extern  bool_t xdr_CB_COMPOUND4args_clnt(XDR *, CB_COMPOUND4args *);
+extern  bool_t xdr_CB_COMPOUND4args_srv(XDR *, CB_COMPOUND4args *);
 extern  bool_t xdr_CB_COMPOUND4res(XDR *, CB_COMPOUND4res *);