From: Trond Myklebust <trond.myklebust@fys.uio.no>

Actually upon re-checking your broken-out directory, I found I'd sent fewer
patches than I originally thought.  Patch is attached, and should be
incremental w.r.t.  what's already in -mm3...

Full broken out list of patches + description can be found on

 http://www.fys.uio.no/~trondmy/src/Linux-2.6.x/2.6.5-rc2/

or on

 http://client.linux-nfs.org/Linux-2.6.x/2.6.5-rc2/



---

 25-akpm/fs/nfs/direct.c                |    7 
 25-akpm/fs/nfs/inode.c                 |   23 
 25-akpm/fs/nfs/nfs2xdr.c               |    6 
 25-akpm/fs/nfs/nfs3xdr.c               |    6 
 25-akpm/fs/nfs/nfs4proc.c              | 1013 ++++--------
 25-akpm/fs/nfs/nfs4xdr.c               | 2648 ++++++++++++++++++++-------------
 25-akpm/fs/nfs/nfsroot.c               |  214 +-
 25-akpm/fs/nfs/write.c                 |    4 
 25-akpm/include/linux/nfs4.h           |  131 -
 25-akpm/include/linux/nfs_fs.h         |    1 
 25-akpm/include/linux/nfs_fs_sb.h      |   11 
 25-akpm/include/linux/nfs_xdr.h        |  266 +--
 25-akpm/include/linux/sunrpc/xdr.h     |   91 -
 25-akpm/include/linux/sunrpc/xprt.h    |    2 
 25-akpm/net/sunrpc/auth_gss/auth_gss.c |    7 
 25-akpm/net/sunrpc/clnt.c              |   10 
 25-akpm/net/sunrpc/sunrpc_syms.c       |    3 
 25-akpm/net/sunrpc/xdr.c               |  204 ++
 25-akpm/net/sunrpc/xprt.c              |    6 
 19 files changed, 2583 insertions(+), 2070 deletions(-)

diff -puN fs/nfs/direct.c~nfsv4-updates fs/nfs/direct.c
--- 25/fs/nfs/direct.c~nfsv4-updates	2004-04-03 15:03:11.242759992 -0800
+++ 25-akpm/fs/nfs/direct.c	2004-04-03 15:03:11.280754216 -0800
@@ -337,8 +337,7 @@ retry:
 						VERF_SIZE) != 0)
 			goto sync_retry;
 	}
-	nfs_end_data_update(inode);
-	NFS_FLAGS(inode) |= NFS_INO_INVALID_DATA;
+	nfs_end_data_update_defer(inode);
 
 	return tot_bytes;
 
@@ -397,10 +396,6 @@ nfs_direct_write(struct inode *inode, st
 		if (result < size)
 			break;
 	}
-	/* Zap the page cache if we managed to write */
-	if (tot_bytes > 0)
-		invalidate_remote_inode(inode);
-
 	return tot_bytes;
 }
 
diff -puN fs/nfs/inode.c~nfsv4-updates fs/nfs/inode.c
--- 25/fs/nfs/inode.c~nfsv4-updates	2004-04-03 15:03:11.243759840 -0800
+++ 25-akpm/fs/nfs/inode.c	2004-04-03 15:03:11.282753912 -0800
@@ -1012,6 +1012,8 @@ void nfs_begin_data_update(struct inode 
  * nfs_end_data_update
  * @inode - pointer to inode
  * Declare end of the operations that will update file data
+ * This will mark the inode as immediately needing revalidation
+ * of its attribute cache.
  */
 void nfs_end_data_update(struct inode *inode)
 {
@@ -1027,6 +1029,27 @@ void nfs_end_data_update(struct inode *i
 }
 
 /**
+ * nfs_end_data_update_defer
+ * @inode - pointer to inode
+ * Declare end of the operations that will update file data
+ * This will defer marking the inode as needing revalidation
+ * unless there are no other pending updates.
+ */
+void nfs_end_data_update_defer(struct inode *inode)
+{
+	struct nfs_inode *nfsi = NFS_I(inode);
+
+	if (atomic_dec_and_test(&nfsi->data_updates)) {
+		/* Mark the attribute cache for revalidation */
+		nfsi->flags |= NFS_INO_INVALID_ATTR;
+		/* Directories and symlinks: invalidate page cache too */
+		if (S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode))
+			nfsi->flags |= NFS_INO_INVALID_DATA;
+		nfsi->cache_change_attribute ++;
+	}
+}
+
+/**
  * nfs_refresh_inode - verify consistency of the inode attribute cache
  * @inode - pointer to inode
  * @fattr - updated attributes
diff -puN fs/nfs/nfs2xdr.c~nfsv4-updates fs/nfs/nfs2xdr.c
--- 25/fs/nfs/nfs2xdr.c~nfsv4-updates	2004-04-03 15:03:11.244759688 -0800
+++ 25-akpm/fs/nfs/nfs2xdr.c	2004-04-03 15:03:11.283753760 -0800
@@ -231,7 +231,7 @@ nfs_xdr_readargs(struct rpc_rqst *req, u
 static int
 nfs_xdr_readres(struct rpc_rqst *req, u32 *p, struct nfs_readres *res)
 {
-	struct iovec *iov = req->rq_rvec;
+	struct iovec *iov = req->rq_rcv_buf.head;
 	int	status, count, recvd, hdrlen;
 
 	if ((status = ntohl(*p++)))
@@ -250,7 +250,7 @@ nfs_xdr_readres(struct rpc_rqst *req, u3
 		xdr_shift_buf(&req->rq_rcv_buf, iov->iov_len - hdrlen);
 	}
 
-	recvd = req->rq_received - hdrlen;
+	recvd = req->rq_rcv_buf.len - hdrlen;
 	if (count > recvd) {
 		printk(KERN_WARNING "NFS: server cheating in read reply: "
 			"count %d > recvd %d\n", count, recvd);
@@ -396,7 +396,7 @@ nfs_xdr_readdirres(struct rpc_rqst *req,
 	}
 
 	pglen = rcvbuf->page_len;
-	recvd = req->rq_received - hdrlen;
+	recvd = rcvbuf->len - hdrlen;
 	if (pglen > recvd)
 		pglen = recvd;
 	page = rcvbuf->pages;
diff -puN fs/nfs/nfs3xdr.c~nfsv4-updates fs/nfs/nfs3xdr.c
--- 25/fs/nfs/nfs3xdr.c~nfsv4-updates	2004-04-03 15:03:11.246759384 -0800
+++ 25-akpm/fs/nfs/nfs3xdr.c	2004-04-03 15:03:11.284753608 -0800
@@ -515,7 +515,7 @@ nfs3_xdr_readdirres(struct rpc_rqst *req
 	}
 
 	pglen = rcvbuf->page_len;
-	recvd = req->rq_received - hdrlen;
+	recvd = rcvbuf->len - hdrlen;
 	if (pglen > recvd)
 		pglen = recvd;
 	page = rcvbuf->pages;
@@ -758,7 +758,7 @@ nfs3_xdr_readlinkres(struct rpc_rqst *re
 static int
 nfs3_xdr_readres(struct rpc_rqst *req, u32 *p, struct nfs_readres *res)
 {
-	struct iovec *iov = req->rq_rvec;
+	struct iovec *iov = req->rq_rcv_buf.head;
 	int	status, count, ocount, recvd, hdrlen;
 
 	status = ntohl(*p++);
@@ -789,7 +789,7 @@ nfs3_xdr_readres(struct rpc_rqst *req, u
 		xdr_shift_buf(&req->rq_rcv_buf, iov->iov_len - hdrlen);
 	}
 
-	recvd = req->rq_received - hdrlen;
+	recvd = req->rq_rcv_buf.len - hdrlen;
 	if (count > recvd) {
 		printk(KERN_WARNING "NFS: server cheating in read reply: "
 			"count %d > recvd %d\n", count, recvd);
diff -puN fs/nfs/nfs4proc.c~nfsv4-updates fs/nfs/nfs4proc.c
--- 25/fs/nfs/nfs4proc.c~nfsv4-updates	2004-04-03 15:03:11.247759232 -0800
+++ 25-akpm/fs/nfs/nfs4proc.c	2004-04-03 15:03:11.292752392 -0800
@@ -51,10 +51,7 @@
 
 #define NFS4_POLL_RETRY_TIME	(15*HZ)
 
-#define GET_OP(cp,name)		&cp->ops[cp->req_nops].u.name
-#define OPNUM(cp)		cp->ops[cp->req_nops].opnum
-
-static int nfs4_proc_fsinfo(struct nfs_server *, struct nfs_fh *, struct nfs_fsinfo *);
+static int nfs4_do_fsinfo(struct nfs_server *, struct nfs_fh *, struct nfs_fsinfo *);
 static int nfs4_async_handle_error(struct rpc_task *, struct nfs_server *);
 extern u32 *nfs4_decode_dirent(u32 *p, struct nfs_entry *entry, int plus);
 extern struct rpc_procinfo nfs4_procedures[];
@@ -72,102 +69,10 @@ static inline int nfs4_map_errors(int er
 	return err;
 }
 
-static void
-nfs4_setup_compound(struct nfs4_compound *cp, struct nfs4_op *ops,
-		    struct nfs_server *server, char *tag)
-{
-	memset(cp, 0, sizeof(*cp));
-	cp->ops = ops;
-	cp->server = server;
-}
-
-static void
-nfs4_setup_access(struct nfs4_compound *cp, u32 req_access, u32 *resp_supported, u32 *resp_access)
-{
-	struct nfs4_access *access = GET_OP(cp, access);
-	
-	access->ac_req_access = req_access;
-	access->ac_resp_supported = resp_supported;
-	access->ac_resp_access = resp_access;
-	
-	OPNUM(cp) = OP_ACCESS;
-	cp->req_nops++;
-}
-
-static void
-nfs4_setup_create_dir(struct nfs4_compound *cp, struct qstr *name,
-		      struct iattr *sattr, struct nfs4_change_info *info)
-{
-	struct nfs4_create *create = GET_OP(cp, create);
-	
-	create->cr_ftype = NF4DIR;
-	create->cr_namelen = name->len;
-	create->cr_name = name->name;
-	create->cr_attrs = sattr;
-	create->cr_cinfo = info;
-	
-	OPNUM(cp) = OP_CREATE;
-	cp->req_nops++;
-}
-
-static void
-nfs4_setup_create_symlink(struct nfs4_compound *cp, struct qstr *name,
-			  struct qstr *linktext, struct iattr *sattr,
-			  struct nfs4_change_info *info)
-{
-	struct nfs4_create *create = GET_OP(cp, create);
-
-	create->cr_ftype = NF4LNK;
-	create->cr_textlen = linktext->len;
-	create->cr_text = linktext->name;
-	create->cr_namelen = name->len;
-	create->cr_name = name->name;
-	create->cr_attrs = sattr;
-	create->cr_cinfo = info;
-
-	OPNUM(cp) = OP_CREATE;
-	cp->req_nops++;
-}
-
-static void
-nfs4_setup_create_special(struct nfs4_compound *cp, struct qstr *name,
-			    dev_t dev, struct iattr *sattr,
-			    struct nfs4_change_info *info)
-{
-	int mode = sattr->ia_mode;
-	struct nfs4_create *create = GET_OP(cp, create);
-
-	BUG_ON(!(sattr->ia_valid & ATTR_MODE));
-	BUG_ON(!S_ISFIFO(mode) && !S_ISBLK(mode) && !S_ISCHR(mode) && !S_ISSOCK(mode));
-	
-	if (S_ISFIFO(mode))
-		create->cr_ftype = NF4FIFO;
-	else if (S_ISBLK(mode)) {
-		create->cr_ftype = NF4BLK;
-		create->cr_specdata1 = MAJOR(dev);
-		create->cr_specdata2 = MINOR(dev);
-	}
-	else if (S_ISCHR(mode)) {
-		create->cr_ftype = NF4CHR;
-		create->cr_specdata1 = MAJOR(dev);
-		create->cr_specdata2 = MINOR(dev);
-	}
-	else
-		create->cr_ftype = NF4SOCK;
-	
-	create->cr_namelen = name->len;
-	create->cr_name = name->name;
-	create->cr_attrs = sattr;
-	create->cr_cinfo = info;
-
-	OPNUM(cp) = OP_CREATE;
-	cp->req_nops++;
-}
-
 /*
  * This is our standard bitmap for GETATTR requests.
  */
-u32 nfs4_fattr_bitmap[2] = {
+const u32 nfs4_fattr_bitmap[2] = {
 	FATTR4_WORD0_TYPE
 	| FATTR4_WORD0_CHANGE
 	| FATTR4_WORD0_SIZE
@@ -184,7 +89,7 @@ u32 nfs4_fattr_bitmap[2] = {
 	| FATTR4_WORD1_TIME_MODIFY
 };
 
-u32 nfs4_statfs_bitmap[2] = {
+const u32 nfs4_statfs_bitmap[2] = {
 	FATTR4_WORD0_FILES_AVAIL
 	| FATTR4_WORD0_FILES_FREE
 	| FATTR4_WORD0_FILES_TOTAL,
@@ -199,121 +104,28 @@ u32 nfs4_pathconf_bitmap[2] = {
 	0
 };
 
-static inline void
-__nfs4_setup_getattr(struct nfs4_compound *cp, u32 *bitmap,
-		     struct nfs_fattr *fattr,
-		     struct nfs_fsstat *fsstat,
-		     struct nfs_pathconf *pathconf)
-{
-        struct nfs4_getattr *getattr = GET_OP(cp, getattr);
-
-        getattr->gt_bmval = bitmap;
-        getattr->gt_attrs = fattr;
-	getattr->gt_fsstat = fsstat;
-	getattr->gt_pathconf = pathconf;
-
-        OPNUM(cp) = OP_GETATTR;
-        cp->req_nops++;
-}
-
-static void
-nfs4_setup_getattr(struct nfs4_compound *cp,
-		struct nfs_fattr *fattr)
-{
-	__nfs4_setup_getattr(cp, nfs4_fattr_bitmap, fattr,
-			NULL, NULL);
-}
-
-static void
-nfs4_setup_statfs(struct nfs4_compound *cp,
-		struct nfs_fsstat *fsstat)
-{
-	__nfs4_setup_getattr(cp, nfs4_statfs_bitmap,
-			NULL, fsstat, NULL);
-}
-
-static void
-nfs4_setup_pathconf(struct nfs4_compound *cp,
-		struct nfs_pathconf *pathconf)
-{
-	__nfs4_setup_getattr(cp, nfs4_pathconf_bitmap,
-			NULL, NULL, pathconf);
-}
-
-static void
-nfs4_setup_getfh(struct nfs4_compound *cp, struct nfs_fh *fhandle)
-{
-	struct nfs4_getfh *getfh = GET_OP(cp, getfh);
-
-	getfh->gf_fhandle = fhandle;
-
-	OPNUM(cp) = OP_GETFH;
-	cp->req_nops++;
-}
-
-static void
-nfs4_setup_link(struct nfs4_compound *cp, struct qstr *name,
-		struct nfs4_change_info *info)
-{
-	struct nfs4_link *link = GET_OP(cp, link);
-
-	link->ln_namelen = name->len;
-	link->ln_name = name->name;
-	link->ln_cinfo = info;
-
-	OPNUM(cp) = OP_LINK;
-	cp->req_nops++;
-}
-
-static void
-nfs4_setup_lookup(struct nfs4_compound *cp, struct qstr *q)
-{
-	struct nfs4_lookup *lookup = GET_OP(cp, lookup);
-
-	lookup->lo_name = q;
-
-	OPNUM(cp) = OP_LOOKUP;
-	cp->req_nops++;
-}
-
-static void
-nfs4_setup_putfh(struct nfs4_compound *cp, struct nfs_fh *fhandle)
-{
-	struct nfs4_putfh *putfh = GET_OP(cp, putfh);
-
-	putfh->pf_fhandle = fhandle;
-
-	OPNUM(cp) = OP_PUTFH;
-	cp->req_nops++;
-}
-
-static void
-nfs4_setup_putrootfh(struct nfs4_compound *cp)
-{
-        OPNUM(cp) = OP_PUTROOTFH;
-        cp->req_nops++;
-}
+const u32 nfs4_fsinfo_bitmap[2] = { FATTR4_WORD0_MAXFILESIZE
+			| FATTR4_WORD0_MAXREAD
+			| FATTR4_WORD0_MAXWRITE
+			| FATTR4_WORD0_LEASE_TIME,
+			0
+};
 
-static void
-nfs4_setup_readdir(struct nfs4_compound *cp, u64 cookie, u32 *verifier,
-		     struct page **pages, unsigned int bufsize, struct dentry *dentry)
+static void nfs4_setup_readdir(u64 cookie, u32 *verifier, struct dentry *dentry,
+		struct nfs4_readdir_arg *readdir)
 {
 	u32 *start, *p;
-	struct nfs4_readdir *readdir = GET_OP(cp, readdir);
 
-	BUG_ON(bufsize < 80);
-	readdir->rd_cookie = (cookie > 2) ? cookie : 0;
-	memcpy(&readdir->rd_req_verifier, verifier, sizeof(readdir->rd_req_verifier));
-	readdir->rd_count = bufsize;
-	readdir->rd_bmval[0] = FATTR4_WORD0_FILEID;
-	readdir->rd_bmval[1] = 0;
-	readdir->rd_pages = pages;
-	readdir->rd_pgbase = 0;
-	
-	OPNUM(cp) = OP_READDIR;
-	cp->req_nops++;
+	BUG_ON(readdir->count < 80);
+	if (cookie > 2) {
+		readdir->cookie = (cookie > 2) ? cookie : 0;
+		memcpy(&readdir->verifier, verifier, sizeof(readdir->verifier));
+		return;
+	}
 
-	if (cookie >= 2)
+	readdir->cookie = 0;
+	memset(&readdir->verifier, 0, sizeof(readdir->verifier));
+	if (cookie == 2)
 		return;
 	
 	/*
@@ -323,7 +135,7 @@ nfs4_setup_readdir(struct nfs4_compound 
 	 * when talking to the server, we always send cookie 0
 	 * instead of 1 or 2.
 	 */
-	start = p = (u32 *)kmap_atomic(*pages, KM_USER0);
+	start = p = (u32 *)kmap_atomic(*readdir->pages, KM_USER0);
 	
 	if (cookie == 0) {
 		*p++ = xdr_one;                                  /* next */
@@ -335,7 +147,7 @@ nfs4_setup_readdir(struct nfs4_compound 
 		*p++ = xdr_one;                         /* bitmap length */
 		*p++ = htonl(FATTR4_WORD0_FILEID);             /* bitmap */
 		*p++ = htonl(8);              /* attribute buffer length */
-		p = xdr_encode_hyper(p, NFS_FILEID(dentry->d_inode));
+		p = xdr_encode_hyper(p, dentry->d_inode->i_ino);
 	}
 	
 	*p++ = xdr_one;                                  /* next */
@@ -347,70 +159,14 @@ nfs4_setup_readdir(struct nfs4_compound 
 	*p++ = xdr_one;                         /* bitmap length */
 	*p++ = htonl(FATTR4_WORD0_FILEID);             /* bitmap */
 	*p++ = htonl(8);              /* attribute buffer length */
-	p = xdr_encode_hyper(p, NFS_FILEID(dentry->d_parent->d_inode));
+	p = xdr_encode_hyper(p, dentry->d_parent->d_inode->i_ino);
 
-	readdir->rd_pgbase = (char *)p - (char *)start;
-	readdir->rd_count -= readdir->rd_pgbase;
+	readdir->pgbase = (char *)p - (char *)start;
+	readdir->count -= readdir->pgbase;
 	kunmap_atomic(start, KM_USER0);
 }
 
 static void
-nfs4_setup_readlink(struct nfs4_compound *cp, int count, struct page **pages)
-{
-	struct nfs4_readlink *readlink = GET_OP(cp, readlink);
-
-	readlink->rl_count = count;
-	readlink->rl_pages = pages;
-
-	OPNUM(cp) = OP_READLINK;
-	cp->req_nops++;
-}
-
-static void
-nfs4_setup_remove(struct nfs4_compound *cp, struct qstr *name, struct nfs4_change_info *cinfo)
-{
-	struct nfs4_remove *remove = GET_OP(cp, remove);
-
-	remove->rm_namelen = name->len;
-	remove->rm_name = name->name;
-	remove->rm_cinfo = cinfo;
-
-	OPNUM(cp) = OP_REMOVE;
-	cp->req_nops++;
-}
-
-static void
-nfs4_setup_rename(struct nfs4_compound *cp, struct qstr *old, struct qstr *new,
-		  struct nfs4_change_info *old_cinfo, struct nfs4_change_info *new_cinfo)
-{
-	struct nfs4_rename *rename = GET_OP(cp, rename);
-
-	rename->rn_oldnamelen = old->len;
-	rename->rn_oldname = old->name;
-	rename->rn_newnamelen = new->len;
-	rename->rn_newname = new->name;
-	rename->rn_src_cinfo = old_cinfo;
-	rename->rn_dst_cinfo = new_cinfo;
-
-	OPNUM(cp) = OP_RENAME;
-	cp->req_nops++;
-}
-
-static void
-nfs4_setup_restorefh(struct nfs4_compound *cp)
-{
-        OPNUM(cp) = OP_RESTOREFH;
-        cp->req_nops++;
-}
-
-static void
-nfs4_setup_savefh(struct nfs4_compound *cp)
-{
-        OPNUM(cp) = OP_SAVEFH;
-        cp->req_nops++;
-}
-
-static void
 renew_lease(struct nfs_server *server, unsigned long timestamp)
 {
 	struct nfs4_client *clp = server->nfs4_state;
@@ -420,58 +176,12 @@ renew_lease(struct nfs_server *server, u
 	spin_unlock(&clp->cl_lock);
 }
 
-static inline void
-process_lease(struct nfs4_compound *cp)
+static void update_changeattr(struct inode *inode, struct nfs4_change_info *cinfo)
 {
-        /*
-         * Generic lease processing: If this operation contains a
-	 * lease-renewing operation, and it succeeded, update the RENEW time
-	 * in the superblock.  Instead of the current time, we use the time
-	 * when the request was sent out.  (All we know is that the lease was
-	 * renewed sometime between then and now, and we have to assume the
-	 * worst case.)
-	 *
-	 * Notes:
-	 *   (1) renewd doesn't acquire the spinlock when messing with
-	 *     server->last_renewal; this is OK since rpciod always runs
-	 *     under the BKL.
-	 *   (2) cp->timestamp was set at the end of XDR encode.
-         */
-	if (!cp->renew_index)
-		return;
-	if (!cp->toplevel_status || cp->resp_nops > cp->renew_index)
-		renew_lease(cp->server, cp->timestamp);
-}
+	struct nfs_inode *nfsi = NFS_I(inode);
 
-static int
-nfs4_call_compound(struct nfs4_compound *cp, struct rpc_cred *cred, int flags)
-{
-	int status;
-	struct rpc_message msg = {
-		.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_COMPOUND],
-		.rpc_argp = cp,
-		.rpc_resp = cp,
-		.rpc_cred = cred,
-	};
-
-	status = rpc_call_sync(cp->server->client, &msg, flags);
-	if (!status)
-		process_lease(cp);
-	
-	return status;
-}
-
-static inline void
-process_cinfo(struct nfs4_change_info *info, struct nfs_fattr *fattr)
-{
-	BUG_ON((fattr->valid & NFS_ATTR_FATTR) == 0);
-	BUG_ON((fattr->valid & NFS_ATTR_FATTR_V4) == 0);
-	
-	if (fattr->change_attr == info->after) {
-		fattr->pre_change_attr = info->before;
-		fattr->valid |= NFS_ATTR_PRE_CHANGE;
-		fattr->timestamp = jiffies;
-	}
+	if (cinfo->before == nfsi->change_attr && cinfo->atomic)
+		nfsi->change_attr = cinfo->after;
 }
 
 /*
@@ -487,12 +197,6 @@ nfs4_open_reclaim(struct nfs4_state_owne
 	struct nfs_fattr fattr = {
 		.valid = 0,
 	};
-	struct nfs4_change_info d_cinfo;
-	struct nfs4_getattr     f_getattr = {
-		.gt_bmval       = nfs4_fattr_bitmap,
-		.gt_attrs       = &fattr,
-	};
-
 	struct nfs_open_reclaimargs o_arg = {
 		.fh = NFS_FH(inode),
 		.seqid = sp->so_seqid,
@@ -500,11 +204,10 @@ nfs4_open_reclaim(struct nfs4_state_owne
 		.share_access = state->state,
 		.clientid = server->nfs4_state->cl_clientid,
 		.claim = NFS4_OPEN_CLAIM_PREVIOUS,
-		.f_getattr = &f_getattr,
+		.bitmask = server->attr_bitmask,
 	};
 	struct nfs_openres o_res = {
-		.cinfo = &d_cinfo,
-		.f_getattr = &f_getattr,
+		.f_attr = &fattr,
 		.server = server,	/* Grrr */
 	};
 	struct rpc_message msg = {
@@ -534,36 +237,21 @@ nfs4_do_open(struct inode *dir, struct q
 	struct nfs4_state     *state = NULL;
 	struct nfs_server       *server = NFS_SERVER(dir);
 	struct inode *inode = NULL;
-	struct nfs4_change_info d_cinfo;
 	int                     status;
-	struct nfs_fattr        d_attr = {
-		.valid          = 0,
-	};
 	struct nfs_fattr        f_attr = {
 		.valid          = 0,
 	};
-	struct nfs4_getattr     f_getattr = {
-		.gt_bmval       = nfs4_fattr_bitmap,
-		.gt_attrs       = &f_attr,
-	};
-	struct nfs4_getattr     d_getattr = {
-		.gt_bmval       = nfs4_fattr_bitmap,
-		.gt_attrs       = &d_attr,
-	};
 	struct nfs_openargs o_arg = {
 		.fh             = NFS_FH(dir),
 		.share_access   = flags & (FMODE_READ|FMODE_WRITE),
 		.opentype       = (flags & O_CREAT) ? NFS4_OPEN_CREATE : NFS4_OPEN_NOCREATE,
 		.createmode     = (flags & O_EXCL) ? NFS4_CREATE_EXCLUSIVE : NFS4_CREATE_UNCHECKED,
 		.name           = name,
-		.f_getattr      = &f_getattr,
-		.d_getattr      = &d_getattr,
 		.server         = server,
+		.bitmask = server->attr_bitmask,
 	};
 	struct nfs_openres o_res = {
-		.cinfo          = &d_cinfo,
-		.f_getattr      = &f_getattr,
-		.d_getattr      = &d_getattr,
+		.f_attr         = &f_attr,
 		.server         = server,
 	};
 	struct rpc_message msg = {
@@ -596,8 +284,7 @@ retry:
 	nfs4_increment_seqid(status, sp);
 	if (status)
 		goto out_up;
-	process_cinfo(&d_cinfo, &d_attr);
-	nfs_refresh_inode(dir, &d_attr);
+	update_changeattr(dir, &o_res.cinfo);
 
 	status = -ENOMEM;
 	inode = nfs_fhget(dir->i_sb, &o_res.fh, &f_attr);
@@ -679,18 +366,14 @@ nfs4_do_setattr(struct nfs_server *serve
                 struct nfs_fh *fhandle, struct iattr *sattr,
                 struct nfs4_state *state)
 {
-        struct nfs4_getattr     getattr = {
-                .gt_bmval       = nfs4_fattr_bitmap,
-                .gt_attrs       = fattr,
-        };
         struct nfs_setattrargs  arg = {
                 .fh             = fhandle,
                 .iap            = sattr,
-                .attr           = &getattr,
 		.server		= server,
+		.bitmask = server->attr_bitmask,
         };
         struct nfs_setattrres  res = {
-                .attr           = &getattr,
+		.fattr		= fattr,
 		.server		= server,
         };
         struct rpc_message msg = {
@@ -834,30 +517,85 @@ nfs4_open_revalidate(struct inode *dir, 
 	return 0;
 }
 
-static int
-nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle,
-		   struct nfs_fsinfo *info)
+
+static int nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle)
+{
+	struct nfs4_server_caps_res res = {};
+	struct rpc_message msg = {
+		.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SERVER_CAPS],
+		.rpc_argp = fhandle,
+		.rpc_resp = &res,
+	};
+	int status;
+
+	status = rpc_call_sync(server->client, &msg, 0);
+	if (status == 0) {
+		memcpy(server->attr_bitmask, res.attr_bitmask, sizeof(server->attr_bitmask));
+		if (res.attr_bitmask[0] & FATTR4_WORD0_ACL)
+			server->caps |= NFS_CAP_ACLS;
+		if (res.has_links != 0)
+			server->caps |= NFS_CAP_HARDLINKS;
+		if (res.has_symlinks != 0)
+			server->caps |= NFS_CAP_SYMLINKS;
+		server->acl_bitmask = res.acl_bitmask;
+	}
+	return status;
+}
+
+static int nfs4_lookup_root(struct nfs_server *server, struct nfs_fh *fhandle,
+		struct nfs_fsinfo *info)
+{
+	struct nfs_fattr *	fattr = info->fattr;
+	struct nfs4_lookup_root_arg args = {
+		.bitmask = nfs4_fattr_bitmap,
+	};
+	struct nfs4_lookup_res res = {
+		.server = server,
+		.fattr = fattr,
+		.fh = fhandle,
+	};
+	struct rpc_message msg = {
+		.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LOOKUP_ROOT],
+		.rpc_argp = &args,
+		.rpc_resp = &res,
+	};
+	fattr->valid = 0;
+	return rpc_call_sync(server->client, &msg, 0);
+}
+
+static int nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle,
+		struct nfs_fsinfo *info)
 {
-	struct nfs4_compound	compound;
-	struct nfs4_op		ops[4];
 	struct nfs_fattr *	fattr = info->fattr;
 	unsigned char *		p;
 	struct qstr		q;
-	int			status;
+	struct nfs4_lookup_arg args = {
+		.dir_fh = fhandle,
+		.name = &q,
+		.bitmask = nfs4_fattr_bitmap,
+	};
+	struct nfs4_lookup_res res = {
+		.server = server,
+		.fattr = fattr,
+		.fh = fhandle,
+	};
+	struct rpc_message msg = {
+		.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LOOKUP],
+		.rpc_argp = &args,
+		.rpc_resp = &res,
+	};
+	int status;
 
 	/*
 	 * Now we do a separate LOOKUP for each component of the mount path.
 	 * The LOOKUPs are done separately so that we can conveniently
 	 * catch an ERR_WRONGSEC if it occurs along the way...
 	 */
-	p = server->mnt_path;
-	fattr->valid = 0;
-	nfs4_setup_compound(&compound, ops, server, "getrootfh");
-	nfs4_setup_putrootfh(&compound);
-	nfs4_setup_getattr(&compound, fattr);
-	nfs4_setup_getfh(&compound, fhandle);
-	if ((status = nfs4_call_compound(&compound, NULL, 0)))
+	status = nfs4_lookup_root(server, fhandle, info);
+	if (status)
 		goto out;
+
+	p = server->mnt_path;
 	for (;;) {
 		while (*p == '/')
 			p++;
@@ -869,12 +607,7 @@ nfs4_proc_get_root(struct nfs_server *se
 		q.len = p - q.name;
 
 		fattr->valid = 0;
-		nfs4_setup_compound(&compound, ops, server, "mount");
-		nfs4_setup_putfh(&compound, fhandle);
-		nfs4_setup_lookup(&compound, &q);
-		nfs4_setup_getattr(&compound, fattr);
-		nfs4_setup_getfh(&compound, fhandle);
-		status = nfs4_call_compound(&compound, NULL, 0);
+		status = rpc_call_sync(server->client, &msg, 0);
 		if (!status)
 			continue;
 		if (status == -ENOENT) {
@@ -883,24 +616,34 @@ nfs4_proc_get_root(struct nfs_server *se
 		}
 		break;
 	}
+	if (status == 0)
+		status = nfs4_server_capabilities(server, fhandle);
+	if (status == 0)
+		status = nfs4_do_fsinfo(server, fhandle, info);
 out:
-	if (status)
-		return nfs4_map_errors(status);
-	return nfs4_proc_fsinfo(server, fhandle, info);
+	return nfs4_map_errors(status);
 }
 
-static int
-nfs4_proc_getattr(struct inode *inode, struct nfs_fattr *fattr)
+static int nfs4_proc_getattr(struct inode *inode, struct nfs_fattr *fattr)
 {
-	struct nfs4_compound compound;
-	struct nfs4_op ops[2];
+	struct nfs_server *server = NFS_SERVER(inode);
+	struct nfs4_getattr_arg args = {
+		.fh = NFS_FH(inode),
+		.bitmask = server->attr_bitmask,
+	};
+	struct nfs4_getattr_res res = {
+		.fattr = fattr,
+		.server = server,
+	};
+	struct rpc_message msg = {
+		.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_GETATTR],
+		.rpc_argp = &args,
+		.rpc_resp = &res,
+	};
 
 	fattr->valid = 0;
 
-	nfs4_setup_compound(&compound, ops, NFS_SERVER(inode), "getattr");
-	nfs4_setup_putfh(&compound, NFS_FH(inode));
-	nfs4_setup_getattr(&compound, fattr);
-	return nfs4_map_errors(nfs4_call_compound(&compound, NULL, 0));
+	return nfs4_map_errors(rpc_call_sync(NFS_CLIENT(inode), &msg, 0));
 }
 
 /* 
@@ -962,75 +705,72 @@ out:
 	return status;
 }
 
-static int
-nfs4_proc_lookup(struct inode *dir, struct qstr *name,
-		 struct nfs_fh *fhandle, struct nfs_fattr *fattr)
+static int nfs4_proc_lookup(struct inode *dir, struct qstr *name,
+		struct nfs_fh *fhandle, struct nfs_fattr *fattr)
 {
-	struct nfs4_compound	compound;
-	struct nfs4_op		ops[5];
-	struct nfs_fattr	dir_attr;
-	int			status;
+	int		       status;
+	struct nfs_server *server = NFS_SERVER(dir);
+	struct nfs4_lookup_arg args = {
+		.bitmask = server->attr_bitmask,
+		.dir_fh = NFS_FH(dir),
+		.name = name,
+	};
+	struct nfs4_lookup_res res = {
+		.server = server,
+		.fattr = fattr,
+		.fh = fhandle,
+	};
+	struct rpc_message msg = {
+		.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LOOKUP],
+		.rpc_argp = &args,
+		.rpc_resp = &res,
+	};
 
-	dir_attr.valid = 0;
 	fattr->valid = 0;
 	
 	dprintk("NFS call  lookup %s\n", name->name);
-	nfs4_setup_compound(&compound, ops, NFS_SERVER(dir), "lookup");
-	nfs4_setup_putfh(&compound, NFS_FH(dir));
-	nfs4_setup_getattr(&compound, &dir_attr);
-	nfs4_setup_lookup(&compound, name);
-	nfs4_setup_getattr(&compound, fattr);
-	nfs4_setup_getfh(&compound, fhandle);
-	status = nfs4_call_compound(&compound, NULL, 0);
+	status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
 	dprintk("NFS reply lookup: %d\n", status);
-
-	if (status >= 0)
-		status = nfs_refresh_inode(dir, &dir_attr);
 	return nfs4_map_errors(status);
 }
 
-static int
-nfs4_proc_access(struct inode *inode, struct rpc_cred *cred, int mode)
+static int nfs4_proc_access(struct inode *inode, struct rpc_cred *cred, int mode)
 {
-	struct nfs4_compound	compound;
-	struct nfs4_op		ops[3];
-	struct nfs_fattr	fattr;
-	u32			req_access = 0, resp_supported, resp_access;
 	int			status;
-
-	fattr.valid = 0;
+	struct nfs4_accessargs args = {
+		.fh = NFS_FH(inode),
+	};
+	struct nfs4_accessres res = { 0 };
+	struct rpc_message msg = {
+		.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_ACCESS],
+		.rpc_argp = &args,
+		.rpc_resp = &res,
+		.rpc_cred = cred,
+	};
 
 	/*
 	 * Determine which access bits we want to ask for...
 	 */
 	if (mode & MAY_READ)
-		req_access |= NFS4_ACCESS_READ;
+		args.access |= NFS4_ACCESS_READ;
 	if (S_ISDIR(inode->i_mode)) {
 		if (mode & MAY_WRITE)
-			req_access |= NFS4_ACCESS_MODIFY | NFS4_ACCESS_EXTEND | NFS4_ACCESS_DELETE;
+			args.access |= NFS4_ACCESS_MODIFY | NFS4_ACCESS_EXTEND | NFS4_ACCESS_DELETE;
 		if (mode & MAY_EXEC)
-			req_access |= NFS4_ACCESS_LOOKUP;
+			args.access |= NFS4_ACCESS_LOOKUP;
 	}
 	else {
 		if (mode & MAY_WRITE)
-			req_access |= NFS4_ACCESS_MODIFY | NFS4_ACCESS_EXTEND;
+			args.access |= NFS4_ACCESS_MODIFY | NFS4_ACCESS_EXTEND;
 		if (mode & MAY_EXEC)
-			req_access |= NFS4_ACCESS_EXECUTE;
+			args.access |= NFS4_ACCESS_EXECUTE;
 	}
-
-	nfs4_setup_compound(&compound, ops, NFS_SERVER(inode), "access");
-	nfs4_setup_putfh(&compound, NFS_FH(inode));
-	nfs4_setup_getattr(&compound, &fattr);
-	nfs4_setup_access(&compound, req_access, &resp_supported, &resp_access);
-	status = nfs4_call_compound(&compound, cred, 0);
-	nfs_refresh_inode(inode, &fattr);
-
+	status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0);
 	if (!status) {
-		if (req_access != resp_supported) {
+		if (args.access != res.supported) {
 			printk(KERN_NOTICE "NFS: server didn't support all access bits!\n");
 			status = -ENOTSUPP;
-		}
-		else if (req_access != resp_access)
+		} else if ((args.access & res.access) != args.access)
 			status = -EACCES;
 	}
 	return nfs4_map_errors(status);
@@ -1060,16 +800,20 @@ nfs4_proc_access(struct inode *inode, st
  * Both of these changes to the XDR layer would in fact be quite
  * minor, but I decided to leave them for a subsequent patch.
  */
-static int
-nfs4_proc_readlink(struct inode *inode, struct page *page)
+static int nfs4_proc_readlink(struct inode *inode, struct page *page)
 {
-	struct nfs4_compound	compound;
-	struct nfs4_op		ops[2];
+	struct nfs4_readlink args = {
+		.fh       = NFS_FH(inode),
+		.count    = PAGE_CACHE_SIZE,
+		.pages    = &page,
+	};
+	struct rpc_message msg = {
+		.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_READLINK],
+		.rpc_argp = &args,
+		.rpc_resp = NULL,
+	};
 
-	nfs4_setup_compound(&compound, ops, NFS_SERVER(inode), "readlink");
-	nfs4_setup_putfh(&compound, NFS_FH(inode));
-	nfs4_setup_readlink(&compound, PAGE_CACHE_SIZE, &page);
-	return nfs4_map_errors(nfs4_call_compound(&compound, NULL, 0));
+	return nfs4_map_errors(rpc_call_sync(NFS_CLIENT(inode), &msg, 0));
 }
 
 static int
@@ -1221,287 +965,318 @@ nfs4_proc_create(struct inode *dir, stru
 	return inode;
 }
 
-static int
-nfs4_proc_remove(struct inode *dir, struct qstr *name)
+static int nfs4_proc_remove(struct inode *dir, struct qstr *name)
 {
-	struct nfs4_compound	compound;
-	struct nfs4_op		ops[3];
-	struct nfs4_change_info	dir_cinfo;
-	struct nfs_fattr	dir_attr;
+	struct nfs4_remove_arg args = {
+		.fh = NFS_FH(dir),
+		.name = name,
+	};
+	struct nfs4_change_info	res;
+	struct rpc_message msg = {
+		.rpc_proc	= &nfs4_procedures[NFSPROC4_CLNT_REMOVE],
+		.rpc_argp	= &args,
+		.rpc_resp	= &res,
+	};
 	int			status;
 
-	dir_attr.valid = 0;
-	nfs4_setup_compound(&compound, ops, NFS_SERVER(dir), "remove");
-	nfs4_setup_putfh(&compound, NFS_FH(dir));
-	nfs4_setup_remove(&compound, name, &dir_cinfo);
-	nfs4_setup_getattr(&compound, &dir_attr);
-	status = nfs4_call_compound(&compound, NULL, 0);
-
-	if (!status) {
-		process_cinfo(&dir_cinfo, &dir_attr);
-		nfs_refresh_inode(dir, &dir_attr);
-	}
+	status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
+	if (status == 0)
+		update_changeattr(dir, &res);
 	return nfs4_map_errors(status);
 }
 
 struct unlink_desc {
-	struct nfs4_compound	compound;
-	struct nfs4_op		ops[3];
-	struct nfs4_change_info	cinfo;
-	struct nfs_fattr	attrs;
+	struct nfs4_remove_arg	args;
+	struct nfs4_change_info	res;
 };
 
-static int
-nfs4_proc_unlink_setup(struct rpc_message *msg, struct dentry *dir, struct qstr *name)
+static int nfs4_proc_unlink_setup(struct rpc_message *msg, struct dentry *dir,
+		struct qstr *name)
 {
-	struct unlink_desc *	up;
-	struct nfs4_compound *	cp;
+	struct unlink_desc *up;
 
 	up = (struct unlink_desc *) kmalloc(sizeof(*up), GFP_KERNEL);
 	if (!up)
 		return -ENOMEM;
-	cp = &up->compound;
 	
-	nfs4_setup_compound(cp, up->ops, NFS_SERVER(dir->d_inode), "unlink_setup");
-	nfs4_setup_putfh(cp, NFS_FH(dir->d_inode));
-	nfs4_setup_remove(cp, name, &up->cinfo);
-	nfs4_setup_getattr(cp, &up->attrs);
+	up->args.fh = NFS_FH(dir->d_inode);
+	up->args.name = name;
 	
-	msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_COMPOUND];
-	msg->rpc_argp = cp;
-	msg->rpc_resp = cp;
+	msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_REMOVE];
+	msg->rpc_argp = &up->args;
+	msg->rpc_resp = &up->res;
 	return 0;
 }
 
-static int
-nfs4_proc_unlink_done(struct dentry *dir, struct rpc_task *task)
+static int nfs4_proc_unlink_done(struct dentry *dir, struct rpc_task *task)
 {
 	struct rpc_message *msg = &task->tk_msg;
 	struct unlink_desc *up;
 	
-	if (msg->rpc_argp) {
-		up = (struct unlink_desc *) msg->rpc_argp;
-		process_lease(&up->compound);
-		process_cinfo(&up->cinfo, &up->attrs);
-		nfs_refresh_inode(dir->d_inode, &up->attrs);
+	if (msg->rpc_resp != NULL) {
+		up = container_of(msg->rpc_resp, struct unlink_desc, res);
+		update_changeattr(dir->d_inode, &up->res);
 		kfree(up);
+		msg->rpc_resp = NULL;
 		msg->rpc_argp = NULL;
 	}
 	return 0;
 }
 
-static int
-nfs4_proc_rename(struct inode *old_dir, struct qstr *old_name,
-		 struct inode *new_dir, struct qstr *new_name)
+static int nfs4_proc_rename(struct inode *old_dir, struct qstr *old_name,
+		struct inode *new_dir, struct qstr *new_name)
 {
-	struct nfs4_compound	compound;
-	struct nfs4_op		ops[7];
-	struct nfs4_change_info	old_cinfo, new_cinfo;
-	struct nfs_fattr	old_dir_attr, new_dir_attr;
+	struct nfs4_rename_arg arg = {
+		.old_dir = NFS_FH(old_dir),
+		.new_dir = NFS_FH(new_dir),
+		.old_name = old_name,
+		.new_name = new_name,
+	};
+	struct nfs4_rename_res res = { };
+	struct rpc_message msg = {
+		.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_RENAME],
+		.rpc_argp = &arg,
+		.rpc_resp = &res,
+	};
 	int			status;
-
-	old_dir_attr.valid = 0;
-	new_dir_attr.valid = 0;
 	
-	nfs4_setup_compound(&compound, ops, NFS_SERVER(old_dir), "rename");
-	nfs4_setup_putfh(&compound, NFS_FH(old_dir));
-	nfs4_setup_savefh(&compound);
-	nfs4_setup_putfh(&compound, NFS_FH(new_dir));
-	nfs4_setup_rename(&compound, old_name, new_name, &old_cinfo, &new_cinfo);
-	nfs4_setup_getattr(&compound, &new_dir_attr);
-	nfs4_setup_restorefh(&compound);
-	nfs4_setup_getattr(&compound, &old_dir_attr);
-	status = nfs4_call_compound(&compound, NULL, 0);
+	status = rpc_call_sync(NFS_CLIENT(old_dir), &msg, 0);
 
 	if (!status) {
-		process_cinfo(&old_cinfo, &old_dir_attr);
-		process_cinfo(&new_cinfo, &new_dir_attr);
-		nfs_refresh_inode(old_dir, &old_dir_attr);
-		nfs_refresh_inode(new_dir, &new_dir_attr);
+		update_changeattr(old_dir, &res.old_cinfo);
+		update_changeattr(new_dir, &res.new_cinfo);
 	}
 	return nfs4_map_errors(status);
 }
 
-static int
-nfs4_proc_link(struct inode *inode, struct inode *dir, struct qstr *name)
+static int nfs4_proc_link(struct inode *inode, struct inode *dir, struct qstr *name)
 {
-	struct nfs4_compound	compound;
-	struct nfs4_op		ops[7];
-	struct nfs4_change_info	dir_cinfo;
-	struct nfs_fattr	dir_attr, fattr;
+	struct nfs4_link_arg arg = {
+		.fh     = NFS_FH(inode),
+		.dir_fh = NFS_FH(dir),
+		.name   = name,
+	};
+	struct nfs4_change_info	cinfo = { };
+	struct rpc_message msg = {
+		.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LINK],
+		.rpc_argp = &arg,
+		.rpc_resp = &cinfo,
+	};
 	int			status;
-	
-	dir_attr.valid = 0;
-	fattr.valid = 0;
-	
-	nfs4_setup_compound(&compound, ops, NFS_SERVER(inode), "link");
-	nfs4_setup_putfh(&compound, NFS_FH(inode));
-	nfs4_setup_savefh(&compound);
-	nfs4_setup_putfh(&compound, NFS_FH(dir));
-	nfs4_setup_link(&compound, name, &dir_cinfo);
-	nfs4_setup_getattr(&compound, &dir_attr);
-	nfs4_setup_restorefh(&compound);
-	nfs4_setup_getattr(&compound, &fattr);
-	status = nfs4_call_compound(&compound, NULL, 0);
 
-	if (!status) {
-		process_cinfo(&dir_cinfo, &dir_attr);
-		nfs_refresh_inode(dir, &dir_attr);
-		nfs_refresh_inode(inode, &fattr);
-	}
+	status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0);
+	if (!status)
+		update_changeattr(dir, &cinfo);
+
 	return nfs4_map_errors(status);
 }
 
-static int
-nfs4_proc_symlink(struct inode *dir, struct qstr *name, struct qstr *path,
-		  struct iattr *sattr, struct nfs_fh *fhandle,
-		  struct nfs_fattr *fattr)
-{
-	struct nfs4_compound	compound;
-	struct nfs4_op		ops[7];
-	struct nfs_fattr	dir_attr;
-	struct nfs4_change_info	dir_cinfo;
+static int nfs4_proc_symlink(struct inode *dir, struct qstr *name,
+		struct qstr *path, struct iattr *sattr, struct nfs_fh *fhandle,
+		struct nfs_fattr *fattr)
+{
+	struct nfs_server *server = NFS_SERVER(dir);
+	struct nfs4_create_arg arg = {
+		.dir_fh = NFS_FH(dir),
+		.server = server,
+		.name = name,
+		.attrs = sattr,
+		.ftype = NF4LNK,
+		.bitmask = server->attr_bitmask,
+	};
+	struct nfs4_create_res res = {
+		.server = server,
+		.fh = fhandle,
+		.fattr = fattr,
+	};
+	struct rpc_message msg = {
+		.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CREATE],
+		.rpc_argp = &arg,
+		.rpc_resp = &res,
+	};
 	int			status;
 
-	dir_attr.valid = 0;
+	arg.u.symlink = path;
 	fattr->valid = 0;
 	
-	nfs4_setup_compound(&compound, ops, NFS_SERVER(dir), "symlink");
-	nfs4_setup_putfh(&compound, NFS_FH(dir));
-	nfs4_setup_savefh(&compound);
-	nfs4_setup_create_symlink(&compound, name, path, sattr, &dir_cinfo);
-	nfs4_setup_getattr(&compound, fattr);
-	nfs4_setup_getfh(&compound, fhandle);
-	nfs4_setup_restorefh(&compound);
-	nfs4_setup_getattr(&compound, &dir_attr);
-	status = nfs4_call_compound(&compound, NULL, 0);
-
-	if (!status) {
-		process_cinfo(&dir_cinfo, &dir_attr);
-		nfs_refresh_inode(dir, &dir_attr);
-	}
+	status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
+	if (!status)
+		update_changeattr(dir, &res.dir_cinfo);
 	return nfs4_map_errors(status);
 }
 
-static int
-nfs4_proc_mkdir(struct inode *dir, struct qstr *name, struct iattr *sattr,
-		struct nfs_fh *fhandle, struct nfs_fattr *fattr)
+static int nfs4_proc_mkdir(struct inode *dir, struct qstr *name,
+		struct iattr *sattr, struct nfs_fh *fhandle,
+		struct nfs_fattr *fattr)
 {
-	struct nfs4_compound	compound;
-	struct nfs4_op		ops[7];
-	struct nfs_fattr	dir_attr;
-	struct nfs4_change_info	dir_cinfo;
+	struct nfs_server *server = NFS_SERVER(dir);
+	struct nfs4_create_arg arg = {
+		.dir_fh = NFS_FH(dir),
+		.server = server,
+		.name = name,
+		.attrs = sattr,
+		.ftype = NF4DIR,
+		.bitmask = server->attr_bitmask,
+	};
+	struct nfs4_create_res res = {
+		.server = server,
+		.fh = fhandle,
+		.fattr = fattr,
+	};
+	struct rpc_message msg = {
+		.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CREATE],
+		.rpc_argp = &arg,
+		.rpc_resp = &res,
+	};
 	int			status;
 
-	dir_attr.valid = 0;
 	fattr->valid = 0;
 	
-	nfs4_setup_compound(&compound, ops, NFS_SERVER(dir), "mkdir");
-	nfs4_setup_putfh(&compound, NFS_FH(dir));
-	nfs4_setup_savefh(&compound);
-	nfs4_setup_create_dir(&compound, name, sattr, &dir_cinfo);
-	nfs4_setup_getattr(&compound, fattr);
-	nfs4_setup_getfh(&compound, fhandle);
-	nfs4_setup_restorefh(&compound);
-	nfs4_setup_getattr(&compound, &dir_attr);
-	status = nfs4_call_compound(&compound, NULL, 0);
-
-	if (!status) {
-		process_cinfo(&dir_cinfo, &dir_attr);
-		nfs_refresh_inode(dir, &dir_attr);
-	}
+	status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
+	if (!status)
+		update_changeattr(dir, &res.dir_cinfo);
 	return nfs4_map_errors(status);
 }
 
-static int
-nfs4_proc_readdir(struct dentry *dentry, struct rpc_cred *cred,
+static int nfs4_proc_readdir(struct dentry *dentry, struct rpc_cred *cred,
                   u64 cookie, struct page *page, unsigned int count, int plus)
 {
 	struct inode		*dir = dentry->d_inode;
-	struct nfs4_compound	compound;
-	struct nfs4_op		ops[2];
+	struct nfs4_readdir_arg args = {
+		.fh = NFS_FH(dir),
+		.pages = &page,
+		.pgbase = 0,
+		.count = count,
+	};
+	struct nfs4_readdir_res res;
+	struct rpc_message msg = {
+		.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_READDIR],
+		.rpc_argp = &args,
+		.rpc_resp = &res,
+		.rpc_cred = cred,
+	};
 	int			status;
 
 	lock_kernel();
-
-	nfs4_setup_compound(&compound, ops, NFS_SERVER(dir), "readdir");
-	nfs4_setup_putfh(&compound, NFS_FH(dir));
-	nfs4_setup_readdir(&compound, cookie, NFS_COOKIEVERF(dir), &page, count, dentry);
-	status = nfs4_call_compound(&compound, cred, 0);
+	nfs4_setup_readdir(cookie, NFS_COOKIEVERF(dir), dentry, &args);
+	res.pgbase = args.pgbase;
+	status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
 	if (status == 0)
-		memcpy(NFS_COOKIEVERF(dir), ops[1].u.readdir.rd_resp_verifier.data, NFS4_VERIFIER_SIZE);
-
+		memcpy(NFS_COOKIEVERF(dir), res.verifier.data, NFS4_VERIFIER_SIZE);
 	unlock_kernel();
 	return nfs4_map_errors(status);
 }
 
-static int
-nfs4_proc_mknod(struct inode *dir, struct qstr *name, struct iattr *sattr,
-		dev_t rdev, struct nfs_fh *fh, struct nfs_fattr *fattr)
+static int nfs4_proc_mknod(struct inode *dir, struct qstr *name,
+		struct iattr *sattr, dev_t rdev, struct nfs_fh *fh,
+		struct nfs_fattr *fattr)
 {
-	struct nfs4_compound	compound;
-	struct nfs4_op		ops[7];
-	struct nfs_fattr	dir_attr;
-	struct nfs4_change_info	dir_cinfo;
+	struct nfs_server *server = NFS_SERVER(dir);
+	struct nfs4_create_arg arg = {
+		.dir_fh = NFS_FH(dir),
+		.server = server,
+		.name = name,
+		.attrs = sattr,
+		.bitmask = server->attr_bitmask,
+	};
+	struct nfs4_create_res res = {
+		.server = server,
+		.fh = fh,
+		.fattr = fattr,
+	};
+	struct rpc_message msg = {
+		.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CREATE],
+		.rpc_argp = &arg,
+		.rpc_resp = &res,
+	};
 	int			status;
+	int                     mode = sattr->ia_mode;
 
-	dir_attr.valid = 0;
 	fattr->valid = 0;
-	
-	nfs4_setup_compound(&compound, ops, NFS_SERVER(dir), "mknod");
-	nfs4_setup_putfh(&compound, NFS_FH(dir));
-	nfs4_setup_savefh(&compound);
-	nfs4_setup_create_special(&compound, name, rdev,sattr, &dir_cinfo);
-	nfs4_setup_getattr(&compound, fattr);
-	nfs4_setup_getfh(&compound, fh);
-	nfs4_setup_restorefh(&compound);
-	nfs4_setup_getattr(&compound, &dir_attr);
-	status = nfs4_call_compound(&compound, NULL, 0);
 
-	if (!status) {
-		process_cinfo(&dir_cinfo, &dir_attr);
-		nfs_refresh_inode(dir, &dir_attr);
+	BUG_ON(!(sattr->ia_valid & ATTR_MODE));
+	BUG_ON(!S_ISFIFO(mode) && !S_ISBLK(mode) && !S_ISCHR(mode) && !S_ISSOCK(mode));
+	if (S_ISFIFO(mode))
+		arg.ftype = NF4FIFO;
+	else if (S_ISBLK(mode)) {
+		arg.ftype = NF4BLK;
+		arg.u.device.specdata1 = MAJOR(rdev);
+		arg.u.device.specdata2 = MINOR(rdev);
+	}
+	else if (S_ISCHR(mode)) {
+		arg.ftype = NF4CHR;
+		arg.u.device.specdata1 = MAJOR(rdev);
+		arg.u.device.specdata2 = MINOR(rdev);
 	}
+	else
+		arg.ftype = NF4SOCK;
+
+	status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
+	if (!status)
+		update_changeattr(dir, &res.dir_cinfo);
 	return nfs4_map_errors(status);
 }
 
-static int
-nfs4_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle,
+static int nfs4_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle,
 		 struct nfs_fsstat *fsstat)
 {
-	struct nfs4_compound compound;
-	struct nfs4_op ops[2];
+	struct nfs4_statfs_arg args = {
+		.fh = fhandle,
+		.bitmask = server->attr_bitmask,
+	};
+	struct rpc_message msg = {
+		.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_STATFS],
+		.rpc_argp = &args,
+		.rpc_resp = fsstat,
+	};
 
-	nfs4_setup_compound(&compound, ops, server, "statfs");
-	nfs4_setup_putfh(&compound, fhandle);
-	nfs4_setup_statfs(&compound, fsstat);
-	return nfs4_map_errors(nfs4_call_compound(&compound, NULL, 0));
+	fsstat->fattr->valid = 0;
+	return nfs4_map_errors(rpc_call_sync(server->client, &msg, 0));
 }
 
-static int
-nfs4_proc_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle,
-		 struct nfs_fsinfo *fsinfo)
+static int nfs4_do_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle,
+		struct nfs_fsinfo *fsinfo)
 {
+	struct nfs4_fsinfo_arg args = {
+		.fh = fhandle,
+		.bitmask = server->attr_bitmask,
+	};
 	struct rpc_message msg = {
 		.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_FSINFO],
-		.rpc_argp = fhandle,
+		.rpc_argp = &args,
 		.rpc_resp = fsinfo,
 	};
 
 	return nfs4_map_errors(rpc_call_sync(server->client, &msg, 0));
 }
 
-static int
-nfs4_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle,
-		   struct nfs_pathconf *pathconf)
+static int nfs4_proc_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fsinfo *fsinfo)
 {
-	struct nfs4_compound compound;
-	struct nfs4_op ops[2];
+	fsinfo->fattr->valid = 0;
+	return nfs4_map_errors(nfs4_do_fsinfo(server, fhandle, fsinfo));
+}
 
-	nfs4_setup_compound(&compound, ops, server, "statfs");
-	nfs4_setup_putfh(&compound, fhandle);
-	nfs4_setup_pathconf(&compound, pathconf);
-	return nfs4_map_errors(nfs4_call_compound(&compound, NULL, 0));
+static int nfs4_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle,
+		struct nfs_pathconf *pathconf)
+{
+	struct nfs4_pathconf_arg args = {
+		.fh = fhandle,
+		.bitmask = server->attr_bitmask,
+	};
+	struct rpc_message msg = {
+		.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_PATHCONF],
+		.rpc_argp = &args,
+		.rpc_resp = pathconf,
+	};
+
+	/* None of the pathconf attributes are mandatory to implement */
+	if ((args.bitmask[0] & nfs4_pathconf_bitmap[0]) == 0) {
+		memset(pathconf, 0, sizeof(*pathconf));
+		return 0;
+	}
+
+	pathconf->fattr->valid = 0;
+	return nfs4_map_errors(rpc_call_sync(server->client, &msg, 0));
 }
 
 static void
diff -puN fs/nfs/nfs4xdr.c~nfsv4-updates fs/nfs/nfs4xdr.c
--- 25/fs/nfs/nfs4xdr.c~nfsv4-updates	2004-04-03 15:03:11.249758928 -0800
+++ 25-akpm/fs/nfs/nfs4xdr.c	2004-04-03 15:03:11.311749504 -0800
@@ -81,21 +81,14 @@ static int nfs_stat_to_errno(int);
 #define decode_putrootfh_maxsz	(op_decode_hdr_maxsz)
 #define encode_getfh_maxsz      (op_encode_hdr_maxsz)
 #define decode_getfh_maxsz      (op_decode_hdr_maxsz + 1 + \
-                                (NFS4_FHSIZE >> 2))
+				((3+NFS4_FHSIZE) >> 2))
 #define encode_getattr_maxsz    (op_encode_hdr_maxsz + 3)
-#define nfs4_fattr_bitmap_maxsz (26 + 2 * ((NFS4_MAXNAMLEN +1) >> 2))
+#define nfs4_name_maxsz		(1 + ((3 + NFS4_MAXNAMLEN) >> 2))
+#define nfs4_fattr_bitmap_maxsz (36 + 2 * nfs4_name_maxsz)
 #define decode_getattr_maxsz    (op_decode_hdr_maxsz + 3 + \
                                 nfs4_fattr_bitmap_maxsz)
 #define encode_savefh_maxsz     (op_encode_hdr_maxsz)
 #define decode_savefh_maxsz     (op_decode_hdr_maxsz)
-#define encode_restorefh_maxsz  (op_encode_hdr_maxsz)
-#define decode_restorefh_maxsz  (op_decode_hdr_maxsz)
-#define encode_read_getattr_maxsz	(op_encode_hdr_maxsz + 2)
-#define decode_read_getattr_maxsz	(op_decode_hdr_maxsz + 8)
-#define encode_pre_write_getattr_maxsz	(op_encode_hdr_maxsz + 2)
-#define decode_pre_write_getattr_maxsz	(op_decode_hdr_maxsz + 5)
-#define encode_post_write_getattr_maxsz	(op_encode_hdr_maxsz + 2)
-#define decode_post_write_getattr_maxsz	(op_decode_hdr_maxsz + 13)
 #define encode_fsinfo_maxsz	(op_encode_hdr_maxsz + 2)
 #define decode_fsinfo_maxsz	(op_decode_hdr_maxsz + 11)
 #define encode_renew_maxsz	(op_encode_hdr_maxsz + 3)
@@ -115,54 +108,63 @@ static int nfs_stat_to_errno(int);
 				3 + (NFS4_VERIFIER_SIZE >> 2))
 #define decode_setclientid_confirm_maxsz \
 				(op_decode_hdr_maxsz)
-
+#define encode_lookup_maxsz	(op_encode_hdr_maxsz + \
+				1 + ((3 + NFS4_FHSIZE) >> 2))
+#define encode_remove_maxsz	(op_encode_hdr_maxsz + \
+				nfs4_name_maxsz)
+#define encode_rename_maxsz	(op_encode_hdr_maxsz + \
+				2 * nfs4_name_maxsz)
+#define decode_rename_maxsz	(op_decode_hdr_maxsz + 5 + 5)
+#define encode_link_maxsz	(op_encode_hdr_maxsz + \
+				nfs4_name_maxsz)
+#define decode_link_maxsz	(op_decode_hdr_maxsz + 5)
+#define encode_create_maxsz	(op_encode_hdr_maxsz + \
+				2 + 2 * nfs4_name_maxsz + \
+				nfs4_fattr_bitmap_maxsz)
+#define decode_create_maxsz	(op_decode_hdr_maxsz + 8)
 #define NFS4_enc_compound_sz	(1024)  /* XXX: large enough? */
 #define NFS4_dec_compound_sz	(1024)  /* XXX: large enough? */
 #define NFS4_enc_read_sz	(compound_encode_hdr_maxsz + \
 				encode_putfh_maxsz + \
-				encode_read_getattr_maxsz + \
 				op_encode_hdr_maxsz + 7)
 #define NFS4_dec_read_sz	(compound_decode_hdr_maxsz + \
 				decode_putfh_maxsz + \
-				decode_read_getattr_maxsz + \
+				op_decode_hdr_maxsz + 2)
+#define NFS4_enc_readlink_sz	(compound_encode_hdr_maxsz + \
+				encode_putfh_maxsz + \
+				op_encode_hdr_maxsz)
+#define NFS4_dec_readlink_sz	(compound_decode_hdr_maxsz + \
+				decode_putfh_maxsz + \
+				op_decode_hdr_maxsz)
+#define NFS4_enc_readdir_sz	(compound_encode_hdr_maxsz + \
+				encode_putfh_maxsz + \
+				op_encode_hdr_maxsz + 9)
+#define NFS4_dec_readdir_sz	(compound_decode_hdr_maxsz + \
+				decode_putfh_maxsz + \
 				op_decode_hdr_maxsz + 2)
 #define NFS4_enc_write_sz	(compound_encode_hdr_maxsz + \
 				encode_putfh_maxsz + \
-				encode_pre_write_getattr_maxsz + \
-				op_encode_hdr_maxsz + 8 + \
-				encode_post_write_getattr_maxsz)
+				op_encode_hdr_maxsz + 8)
 #define NFS4_dec_write_sz	(compound_decode_hdr_maxsz + \
 				decode_putfh_maxsz + \
-				decode_pre_write_getattr_maxsz + \
-				op_decode_hdr_maxsz + 4 + \
-				decode_post_write_getattr_maxsz)
+				op_decode_hdr_maxsz + 4)
 #define NFS4_enc_commit_sz	(compound_encode_hdr_maxsz + \
 				encode_putfh_maxsz + \
-				encode_pre_write_getattr_maxsz + \
-				op_encode_hdr_maxsz + 3 + \
-				encode_post_write_getattr_maxsz)
+				op_encode_hdr_maxsz + 3)
 #define NFS4_dec_commit_sz	(compound_decode_hdr_maxsz + \
 				decode_putfh_maxsz + \
-				decode_pre_write_getattr_maxsz + \
-				op_decode_hdr_maxsz + 2 + \
-				decode_post_write_getattr_maxsz)
+				op_decode_hdr_maxsz + 2)
 #define NFS4_enc_open_sz        (compound_encode_hdr_maxsz + \
                                 encode_putfh_maxsz + \
-                                encode_savefh_maxsz + \
                                 op_encode_hdr_maxsz + \
                                 13 + 3 + 2 + 64 + \
                                 encode_getattr_maxsz + \
-                                encode_getfh_maxsz + \
-                                encode_restorefh_maxsz + \
-                                encode_getattr_maxsz)
+                                encode_getfh_maxsz)
 #define NFS4_dec_open_sz        (compound_decode_hdr_maxsz + \
                                 decode_putfh_maxsz + \
-                                decode_savefh_maxsz + \
                                 op_decode_hdr_maxsz + 4 + 5 + 2 + 3 + \
                                 decode_getattr_maxsz + \
-                                decode_getfh_maxsz + \
-                                decode_restorefh_maxsz + \
-                                decode_getattr_maxsz)
+                                decode_getfh_maxsz)
 #define NFS4_enc_open_confirm_sz      \
                                 (compound_encode_hdr_maxsz + \
                                 encode_putfh_maxsz + \
@@ -255,8 +257,88 @@ static int nfs_stat_to_errno(int);
 				decode_putfh_maxsz + \
 				decode_getattr_maxsz + \
 				op_decode_hdr_maxsz + 4)
-
-
+#define NFS4_enc_access_sz	(compound_encode_hdr_maxsz + \
+				encode_putfh_maxsz + \
+				op_encode_hdr_maxsz + 1)
+#define NFS4_dec_access_sz	(compound_decode_hdr_maxsz + \
+				decode_putfh_maxsz + \
+				op_decode_hdr_maxsz + 2)
+#define NFS4_enc_getattr_sz	(compound_encode_hdr_maxsz + \
+				encode_putfh_maxsz + \
+				encode_getattr_maxsz)
+#define NFS4_dec_getattr_sz	(compound_decode_hdr_maxsz + \
+				decode_putfh_maxsz + \
+				decode_getattr_maxsz)
+#define NFS4_enc_lookup_sz	(compound_encode_hdr_maxsz + \
+				encode_putfh_maxsz + \
+				encode_lookup_maxsz + \
+				encode_getattr_maxsz + \
+				encode_getfh_maxsz)
+#define NFS4_dec_lookup_sz	(compound_decode_hdr_maxsz + \
+				decode_putfh_maxsz + \
+				op_decode_hdr_maxsz + \
+				decode_getattr_maxsz + \
+				decode_getfh_maxsz)
+#define NFS4_enc_lookup_root_sz (compound_encode_hdr_maxsz + \
+				encode_putrootfh_maxsz + \
+				encode_getattr_maxsz + \
+				encode_getfh_maxsz)
+#define NFS4_dec_lookup_root_sz (compound_decode_hdr_maxsz + \
+				decode_putrootfh_maxsz + \
+				decode_getattr_maxsz + \
+				decode_getfh_maxsz)
+#define NFS4_enc_remove_sz	(compound_encode_hdr_maxsz + \
+				encode_putfh_maxsz + \
+				encode_remove_maxsz)
+#define NFS4_dec_remove_sz	(compound_decode_hdr_maxsz + \
+				decode_putfh_maxsz + \
+				op_decode_hdr_maxsz + 5)
+#define NFS4_enc_rename_sz	(compound_encode_hdr_maxsz + \
+				encode_putfh_maxsz + \
+				encode_savefh_maxsz + \
+				encode_putfh_maxsz + \
+				encode_rename_maxsz)
+#define NFS4_dec_rename_sz	(compound_decode_hdr_maxsz + \
+				decode_putfh_maxsz + \
+				decode_savefh_maxsz + \
+				decode_putfh_maxsz + \
+				decode_rename_maxsz)
+#define NFS4_enc_link_sz	(compound_encode_hdr_maxsz + \
+				encode_putfh_maxsz + \
+				encode_savefh_maxsz + \
+				encode_putfh_maxsz + \
+				encode_link_maxsz)
+#define NFS4_dec_link_sz	(compound_decode_hdr_maxsz + \
+				decode_putfh_maxsz + \
+				decode_savefh_maxsz + \
+				decode_putfh_maxsz + \
+				decode_link_maxsz)
+#define NFS4_enc_create_sz	(compound_encode_hdr_maxsz + \
+				encode_putfh_maxsz + \
+				encode_create_maxsz + \
+				encode_getattr_maxsz + \
+				encode_getfh_maxsz)
+#define NFS4_dec_create_sz	(compound_decode_hdr_maxsz + \
+				decode_putfh_maxsz + \
+				decode_create_maxsz + \
+				decode_getattr_maxsz + \
+				decode_getfh_maxsz)
+#define NFS4_enc_pathconf_sz	(compound_encode_hdr_maxsz + \
+				encode_putfh_maxsz + \
+				encode_getattr_maxsz)
+#define NFS4_dec_pathconf_sz	(compound_decode_hdr_maxsz + \
+				decode_putfh_maxsz + \
+				decode_getattr_maxsz)
+#define NFS4_enc_statfs_sz	(compound_encode_hdr_maxsz + \
+				encode_putfh_maxsz + \
+				encode_getattr_maxsz)
+#define NFS4_dec_statfs_sz	(compound_decode_hdr_maxsz + \
+				decode_putfh_maxsz + \
+				op_decode_hdr_maxsz + 12)
+#define NFS4_enc_server_caps_sz (compound_encode_hdr_maxsz + \
+				encode_getattr_maxsz)
+#define NFS4_dec_server_caps_sz (compound_decode_hdr_maxsz + \
+				decode_getattr_maxsz)
 
 static struct {
 	unsigned int	mode;
@@ -297,7 +379,7 @@ struct compound_hdr {
 	*p++ = htonl((uint32_t)(n));					\
 } while (0)
 #define WRITEMEM(ptr,nbytes)     do {				\
-	p = xdr_writemem(p, ptr, nbytes);			\
+	p = xdr_encode_opaque_fixed(p, ptr, nbytes);		\
 } while (0)
 
 #define RESERVE_SPACE(nbytes)	do {				\
@@ -306,19 +388,7 @@ struct compound_hdr {
 	BUG_ON(!p);						\
 } while (0)
 
-static inline
-uint32_t *xdr_writemem(uint32_t *p, const void *ptr, int nbytes)
-{
-	int tmp = XDR_QUADLEN(nbytes);
-	if (!tmp)
-		return p;
-	p[tmp-1] = 0;
-	memcpy(p, ptr, nbytes);
-	return p + tmp;
-}
-
-static int
-encode_compound_hdr(struct xdr_stream *xdr, struct compound_hdr *hdr)
+static int encode_compound_hdr(struct xdr_stream *xdr, struct compound_hdr *hdr)
 {
 	uint32_t *p;
 
@@ -332,9 +402,7 @@ encode_compound_hdr(struct xdr_stream *x
 	return 0;
 }
 
-static int
-encode_attrs(struct xdr_stream *xdr, struct iattr *iap,
-    struct nfs_server *server)
+static int encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const struct nfs_server *server)
 {
 	char owner_name[IDMAP_NAMESZ];
 	char owner_group[IDMAP_NAMESZ];
@@ -461,20 +529,18 @@ encode_attrs(struct xdr_stream *xdr, str
 	return status;
 }
 
-static int
-encode_access(struct xdr_stream *xdr, struct nfs4_access *access)
+static int encode_access(struct xdr_stream *xdr, u32 access)
 {
 	uint32_t *p;
 
 	RESERVE_SPACE(8);
 	WRITE32(OP_ACCESS);
-	WRITE32(access->ac_req_access);
+	WRITE32(access);
 	
 	return 0;
 }
 
-static int
-encode_close(struct xdr_stream *xdr, struct nfs_closeargs *arg)
+static int encode_close(struct xdr_stream *xdr, const struct nfs_closeargs *arg)
 {
 	uint32_t *p;
 
@@ -486,8 +552,7 @@ encode_close(struct xdr_stream *xdr, str
 	return 0;
 }
 
-static int
-encode_commit(struct xdr_stream *xdr, struct nfs_writeargs *args)
+static int encode_commit(struct xdr_stream *xdr, const struct nfs_writeargs *args)
 {
 	uint32_t *p;
         
@@ -499,42 +564,39 @@ encode_commit(struct xdr_stream *xdr, st
         return 0;
 }
 
-static int
-encode_create(struct xdr_stream *xdr, struct nfs4_create *create,
-    struct nfs_server *server)
+static int encode_create(struct xdr_stream *xdr, const struct nfs4_create_arg *create)
 {
 	uint32_t *p;
 	
 	RESERVE_SPACE(8);
 	WRITE32(OP_CREATE);
-	WRITE32(create->cr_ftype);
+	WRITE32(create->ftype);
 
-	switch (create->cr_ftype) {
+	switch (create->ftype) {
 	case NF4LNK:
-		RESERVE_SPACE(4 + create->cr_textlen);
-		WRITE32(create->cr_textlen);
-		WRITEMEM(create->cr_text, create->cr_textlen);
+		RESERVE_SPACE(4 + create->u.symlink->len);
+		WRITE32(create->u.symlink->len);
+		WRITEMEM(create->u.symlink->name, create->u.symlink->len);
 		break;
 
 	case NF4BLK: case NF4CHR:
 		RESERVE_SPACE(8);
-		WRITE32(create->cr_specdata1);
-		WRITE32(create->cr_specdata2);
+		WRITE32(create->u.device.specdata1);
+		WRITE32(create->u.device.specdata2);
 		break;
 
 	default:
 		break;
 	}
 
-	RESERVE_SPACE(4 + create->cr_namelen);
-	WRITE32(create->cr_namelen);
-	WRITEMEM(create->cr_name, create->cr_namelen);
+	RESERVE_SPACE(4 + create->name->len);
+	WRITE32(create->name->len);
+	WRITEMEM(create->name->name, create->name->len);
 
-	return encode_attrs(xdr, create->cr_attrs, server);
+	return encode_attrs(xdr, create->attrs, create->server);
 }
 
-static int
-encode_getattr_one(struct xdr_stream *xdr, uint32_t bitmap)
+static int encode_getattr_one(struct xdr_stream *xdr, uint32_t bitmap)
 {
         uint32_t *p;
 
@@ -545,8 +607,7 @@ encode_getattr_one(struct xdr_stream *xd
         return 0;
 }
 
-static int
-encode_getattr_two(struct xdr_stream *xdr, uint32_t bm0, uint32_t bm1)
+static int encode_getattr_two(struct xdr_stream *xdr, uint32_t bm0, uint32_t bm1)
 {
         uint32_t *p;
 
@@ -558,56 +619,24 @@ encode_getattr_two(struct xdr_stream *xd
         return 0;
 }
 
-static inline int
-encode_getattr(struct xdr_stream *xdr, struct nfs4_getattr *getattr)
-{
-	return encode_getattr_two(xdr, getattr->gt_bmval[0],
-					getattr->gt_bmval[1]);
-}
-
-/*
- * Request the change attribute in order to check attribute+cache consistency
- */
-static inline int
-encode_read_getattr(struct xdr_stream *xdr)
+static int encode_getfattr(struct xdr_stream *xdr, const u32* bitmask)
 {
-	return encode_getattr_two(xdr, FATTR4_WORD0_CHANGE,
-			FATTR4_WORD1_TIME_ACCESS);
-}
+	extern u32 nfs4_fattr_bitmap[];
 
-/*
- * Request the change attribute prior to doing a write operation
- */
-static inline int
-encode_pre_write_getattr(struct xdr_stream *xdr)
-{
-	/* Request the change attribute */
-	return encode_getattr_one(xdr, FATTR4_WORD0_CHANGE);
+	return encode_getattr_two(xdr,
+			bitmask[0] & nfs4_fattr_bitmap[0],
+			bitmask[1] & nfs4_fattr_bitmap[1]);
 }
 
-/*
- * Request the change attribute, size, and [cm]time after a write operation
- */
-static inline int
-encode_post_write_getattr(struct xdr_stream *xdr)
+static int encode_fsinfo(struct xdr_stream *xdr, const u32* bitmask)
 {
-	return encode_getattr_two(xdr, FATTR4_WORD0_CHANGE|FATTR4_WORD0_SIZE,
-			FATTR4_WORD1_SPACE_USED |
-			FATTR4_WORD1_TIME_METADATA |
-			FATTR4_WORD1_TIME_MODIFY);
-}
+	extern u32 nfs4_fsinfo_bitmap[];
 
-static int
-encode_fsinfo(struct xdr_stream *xdr)
-{
-	return encode_getattr_one(xdr, FATTR4_WORD0_MAXFILESIZE
-			| FATTR4_WORD0_MAXREAD
-			| FATTR4_WORD0_MAXWRITE
-			| FATTR4_WORD0_LEASE_TIME);
+	return encode_getattr_two(xdr, bitmask[0] & nfs4_fsinfo_bitmap[0],
+			bitmask[1] & nfs4_fsinfo_bitmap[1]);
 }
 
-static int
-encode_getfh(struct xdr_stream *xdr)
+static int encode_getfh(struct xdr_stream *xdr)
 {
 	uint32_t *p;
 
@@ -617,15 +646,14 @@ encode_getfh(struct xdr_stream *xdr)
 	return 0;
 }
 
-static int
-encode_link(struct xdr_stream *xdr, struct nfs4_link *link)
+static int encode_link(struct xdr_stream *xdr, const struct qstr *name)
 {
 	uint32_t *p;
 
-	RESERVE_SPACE(8 + link->ln_namelen);
+	RESERVE_SPACE(8 + name->len);
 	WRITE32(OP_LINK);
-	WRITE32(link->ln_namelen);
-	WRITEMEM(link->ln_name, link->ln_namelen);
+	WRITE32(name->len);
+	WRITEMEM(name->name, name->len);
 	
 	return 0;
 }
@@ -634,8 +662,7 @@ encode_link(struct xdr_stream *xdr, stru
  * opcode,type,reclaim,offset,length,new_lock_owner = 32
  * open_seqid,open_stateid,lock_seqid,lock_owner.clientid, lock_owner.id = 40
  */
-static int
-encode_lock(struct xdr_stream *xdr, struct nfs_lockargs *arg)
+static int encode_lock(struct xdr_stream *xdr, const struct nfs_lockargs *arg)
 {
 	uint32_t *p;
 	struct nfs_lock_opargs *opargs = arg->u.lock;
@@ -669,8 +696,7 @@ encode_lock(struct xdr_stream *xdr, stru
 	return 0;
 }
 
-static int
-encode_lockt(struct xdr_stream *xdr, struct nfs_lockargs *arg)
+static int encode_lockt(struct xdr_stream *xdr, const struct nfs_lockargs *arg)
 {
 	uint32_t *p;
 	struct nfs_lowner *opargs = arg->u.lockt;
@@ -687,8 +713,7 @@ encode_lockt(struct xdr_stream *xdr, str
 	return 0;
 }
 
-static int
-encode_locku(struct xdr_stream *xdr, struct nfs_lockargs *arg)
+static int encode_locku(struct xdr_stream *xdr, const struct nfs_lockargs *arg)
 {
 	uint32_t *p;
 	struct nfs_locku_opargs *opargs = arg->u.locku;
@@ -704,22 +729,20 @@ encode_locku(struct xdr_stream *xdr, str
 	return 0;
 }
 
-static int
-encode_lookup(struct xdr_stream *xdr, struct nfs4_lookup *lookup)
+static int encode_lookup(struct xdr_stream *xdr, const struct qstr *name)
 {
-	int len = lookup->lo_name->len;
+	int len = name->len;
 	uint32_t *p;
 
 	RESERVE_SPACE(8 + len);
 	WRITE32(OP_LOOKUP);
 	WRITE32(len);
-	WRITEMEM(lookup->lo_name->name, len);
+	WRITEMEM(name->name, len);
 
 	return 0;
 }
 
-static int
-encode_open(struct xdr_stream *xdr, struct nfs_openargs *arg)
+static int encode_open(struct xdr_stream *xdr, const struct nfs_openargs *arg)
 {
 	int status;
 	uint32_t *p;
@@ -778,8 +801,7 @@ encode_open(struct xdr_stream *xdr, stru
 	return 0;
 }
 
-static int
-encode_open_confirm(struct xdr_stream *xdr, struct nfs_open_confirmargs *arg)
+static int encode_open_confirm(struct xdr_stream *xdr, const struct nfs_open_confirmargs *arg)
 {
 	uint32_t *p;
 
@@ -792,8 +814,7 @@ encode_open_confirm(struct xdr_stream *x
 }
 
 
-static int
-encode_open_reclaim(struct xdr_stream *xdr, struct nfs_open_reclaimargs *arg)
+static int encode_open_reclaim(struct xdr_stream *xdr, const struct nfs_open_reclaimargs *arg)
 {
 	uint32_t *p;
 
@@ -827,8 +848,7 @@ encode_open_reclaim(struct xdr_stream *x
 	return 0;
 }
 
-static int
-encode_open_downgrade(struct xdr_stream *xdr, struct nfs_closeargs *arg)
+static int encode_open_downgrade(struct xdr_stream *xdr, const struct nfs_closeargs *arg)
 {
 	uint32_t *p;
 
@@ -844,7 +864,7 @@ encode_open_downgrade(struct xdr_stream 
 }
 
 static int
-encode_putfh(struct xdr_stream *xdr, struct nfs_fh *fh)
+encode_putfh(struct xdr_stream *xdr, const struct nfs_fh *fh)
 {
 	int len = fh->size;
 	uint32_t *p;
@@ -857,8 +877,7 @@ encode_putfh(struct xdr_stream *xdr, str
 	return 0;
 }
 
-static int
-encode_putrootfh(struct xdr_stream *xdr)
+static int encode_putrootfh(struct xdr_stream *xdr)
 {
         uint32_t *p;
         
@@ -868,8 +887,7 @@ encode_putrootfh(struct xdr_stream *xdr)
         return 0;
 }
 
-static void
-encode_stateid(struct xdr_stream *xdr, struct nfs4_state *state, fl_owner_t lockowner)
+static void encode_stateid(struct xdr_stream *xdr, struct nfs4_state *state, fl_owner_t lockowner)
 {
 	extern nfs4_stateid zero_stateid;
 	nfs4_stateid stateid;
@@ -883,8 +901,7 @@ encode_stateid(struct xdr_stream *xdr, s
 		WRITEMEM(zero_stateid.data, sizeof(zero_stateid.data));
 }
 
-static int
-encode_read(struct xdr_stream *xdr, struct nfs_readargs *args)
+static int encode_read(struct xdr_stream *xdr, const struct nfs_readargs *args)
 {
 	uint32_t *p;
 
@@ -900,8 +917,7 @@ encode_read(struct xdr_stream *xdr, stru
 	return 0;
 }
 
-static int
-encode_readdir(struct xdr_stream *xdr, struct nfs4_readdir *readdir, struct rpc_rqst *req)
+static int encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg *readdir, struct rpc_rqst *req)
 {
 	struct rpc_auth *auth = req->rq_task->tk_auth;
 	int replen;
@@ -909,27 +925,26 @@ encode_readdir(struct xdr_stream *xdr, s
 
 	RESERVE_SPACE(32+sizeof(nfs4_verifier));
 	WRITE32(OP_READDIR);
-	WRITE64(readdir->rd_cookie);
-	WRITEMEM(readdir->rd_req_verifier.data, sizeof(readdir->rd_req_verifier.data));
-	WRITE32(readdir->rd_count >> 5);  /* meaningless "dircount" field */
-	WRITE32(readdir->rd_count);
+	WRITE64(readdir->cookie);
+	WRITEMEM(readdir->verifier.data, sizeof(readdir->verifier.data));
+	WRITE32(readdir->count >> 5);  /* meaningless "dircount" field */
+	WRITE32(readdir->count);
 	WRITE32(2);
-	WRITE32(readdir->rd_bmval[0]);
-	WRITE32(readdir->rd_bmval[1]);
+	WRITE32(FATTR4_WORD0_FILEID);
+	WRITE32(0);
 
 	/* set up reply iovec
 	 *    toplevel_status + taglen + rescount + OP_PUTFH + status
 	 *      + OP_READDIR + status + verifer(2)  = 9
 	 */
 	replen = (RPC_REPHDRSIZE + auth->au_rslack + 9) << 2;
-	xdr_inline_pages(&req->rq_rcv_buf, replen, readdir->rd_pages,
-			 readdir->rd_pgbase, readdir->rd_count);
+	xdr_inline_pages(&req->rq_rcv_buf, replen, readdir->pages,
+			 readdir->pgbase, readdir->count);
 
 	return 0;
 }
 
-static int
-encode_readlink(struct xdr_stream *xdr, struct nfs4_readlink *readlink, struct rpc_rqst *req)
+static int encode_readlink(struct xdr_stream *xdr, const struct nfs4_readlink *readlink, struct rpc_rqst *req)
 {
 	struct rpc_auth *auth = req->rq_task->tk_auth;
 	int replen;
@@ -943,43 +958,40 @@ encode_readlink(struct xdr_stream *xdr, 
 	 *      + OP_READLINK + status  = 7
 	 */
 	replen = (RPC_REPHDRSIZE + auth->au_rslack + 7) << 2;
-	xdr_inline_pages(&req->rq_rcv_buf, replen, readlink->rl_pages, 0, readlink->rl_count);
+	xdr_inline_pages(&req->rq_rcv_buf, replen, readlink->pages, 0, readlink->count);
 	
 	return 0;
 }
 
-static int
-encode_remove(struct xdr_stream *xdr, struct nfs4_remove *remove)
+static int encode_remove(struct xdr_stream *xdr, const struct qstr *name)
 {
 	uint32_t *p;
 
-	RESERVE_SPACE(8 + remove->rm_namelen);
+	RESERVE_SPACE(8 + name->len);
 	WRITE32(OP_REMOVE);
-	WRITE32(remove->rm_namelen);
-	WRITEMEM(remove->rm_name, remove->rm_namelen);
+	WRITE32(name->len);
+	WRITEMEM(name->name, name->len);
 
 	return 0;
 }
 
-static int
-encode_rename(struct xdr_stream *xdr, struct nfs4_rename *rename)
+static int encode_rename(struct xdr_stream *xdr, const struct qstr *oldname, const struct qstr *newname)
 {
 	uint32_t *p;
 
-	RESERVE_SPACE(8 + rename->rn_oldnamelen);
+	RESERVE_SPACE(8 + oldname->len);
 	WRITE32(OP_RENAME);
-	WRITE32(rename->rn_oldnamelen);
-	WRITEMEM(rename->rn_oldname, rename->rn_oldnamelen);
+	WRITE32(oldname->len);
+	WRITEMEM(oldname->name, oldname->len);
 	
-	RESERVE_SPACE(4 + rename->rn_newnamelen);
-	WRITE32(rename->rn_newnamelen);
-	WRITEMEM(rename->rn_newname, rename->rn_newnamelen);
+	RESERVE_SPACE(4 + newname->len);
+	WRITE32(newname->len);
+	WRITEMEM(newname->name, newname->len);
 
 	return 0;
 }
 
-static int
-encode_renew(struct xdr_stream *xdr, struct nfs4_client *client_stateid)
+static int encode_renew(struct xdr_stream *xdr, const struct nfs4_client *client_stateid)
 {
 	uint32_t *p;
 
@@ -991,17 +1003,6 @@ encode_renew(struct xdr_stream *xdr, str
 }
 
 static int
-encode_restorefh(struct xdr_stream *xdr)
-{
-	uint32_t *p;
-
-	RESERVE_SPACE(4);
-	WRITE32(OP_RESTOREFH);
-
-	return 0;
-}
-
-static int
 encode_savefh(struct xdr_stream *xdr)
 {
 	uint32_t *p;
@@ -1012,9 +1013,7 @@ encode_savefh(struct xdr_stream *xdr)
 	return 0;
 }
 
-static int
-encode_setattr(struct xdr_stream *xdr, struct nfs_setattrargs *arg,
-    struct nfs_server *server)
+static int encode_setattr(struct xdr_stream *xdr, const struct nfs_setattrargs *arg, const struct nfs_server *server)
 {
 	int status;
 	uint32_t *p;
@@ -1029,8 +1028,7 @@ encode_setattr(struct xdr_stream *xdr, s
         return 0;
 }
 
-static int
-encode_setclientid(struct xdr_stream *xdr, struct nfs4_setclientid *setclientid)
+static int encode_setclientid(struct xdr_stream *xdr, const struct nfs4_setclientid *setclientid)
 {
 	uint32_t total_len;
 	uint32_t len1, len2, len3;
@@ -1057,8 +1055,7 @@ encode_setclientid(struct xdr_stream *xd
 	return 0;
 }
 
-static int
-encode_setclientid_confirm(struct xdr_stream *xdr, struct nfs4_client *client_state)
+static int encode_setclientid_confirm(struct xdr_stream *xdr, const struct nfs4_client *client_state)
 {
         uint32_t *p;
 
@@ -1070,8 +1067,7 @@ encode_setclientid_confirm(struct xdr_st
         return 0;
 }
 
-static int
-encode_write(struct xdr_stream *xdr, struct nfs_writeargs *args)
+static int encode_write(struct xdr_stream *xdr, const struct nfs_writeargs *args)
 {
 	uint32_t *p;
 
@@ -1089,97 +1085,185 @@ encode_write(struct xdr_stream *xdr, str
 
 	return 0;
 }
+/*
+ * END OF "GENERIC" ENCODE ROUTINES.
+ */
 
-/* FIXME: this sucks */
-static int
-encode_compound(struct xdr_stream *xdr, struct nfs4_compound *cp, struct rpc_rqst *req)
+/*
+ * Encode an ACCESS request
+ */
+static int nfs4_xdr_enc_access(struct rpc_rqst *req, uint32_t *p, const struct nfs4_accessargs *args)
 {
+	struct xdr_stream xdr;
 	struct compound_hdr hdr = {
-		.taglen = cp->taglen,
-		.tag	= cp->tag,
-		.nops	= cp->req_nops,
+		.nops = 2,
 	};
-	int i, status = 0;
+	int status;
 
-	encode_compound_hdr(xdr, &hdr);
+	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
+	encode_compound_hdr(&xdr, &hdr);
+	if ((status = encode_putfh(&xdr, args->fh)) == 0)
+		status = encode_access(&xdr, args->access);
+	return status;
+}
 
-	for (i = 0; i < cp->req_nops; i++) {
-		switch (cp->ops[i].opnum) {
-		case OP_ACCESS:
-			status = encode_access(xdr, &cp->ops[i].u.access);
-			break;
-		case OP_CREATE:
-			status = encode_create(xdr, &cp->ops[i].u.create, cp->server);
-			break;
-		case OP_GETATTR:
-			status = encode_getattr(xdr, &cp->ops[i].u.getattr);
-			break;
-		case OP_GETFH:
-			status = encode_getfh(xdr);
-			break;
-		case OP_LINK:
-			status = encode_link(xdr, &cp->ops[i].u.link);
-			break;
-		case OP_LOOKUP:
-			status = encode_lookup(xdr, &cp->ops[i].u.lookup);
-			break;
-		case OP_PUTFH:
-			status = encode_putfh(xdr, cp->ops[i].u.putfh.pf_fhandle);
-			break;
-		case OP_PUTROOTFH:
-			status = encode_putrootfh(xdr);
-			break;
-		case OP_READDIR:
-			status = encode_readdir(xdr, &cp->ops[i].u.readdir, req);
-			break;
-		case OP_READLINK:
-			status = encode_readlink(xdr, &cp->ops[i].u.readlink, req);
-			break;
-		case OP_REMOVE:
-			status = encode_remove(xdr, &cp->ops[i].u.remove);
-			break;
-		case OP_RENAME:
-			status = encode_rename(xdr, &cp->ops[i].u.rename);
-			break;
-		case OP_RESTOREFH:
-			status = encode_restorefh(xdr);
-			break;
-		case OP_SAVEFH:
-			status = encode_savefh(xdr);
-			break;
-		default:
-			BUG();
-		}
-		if (status)
-			return status;
-	}
-	
-	return 0;
+/*
+ * Encode LOOKUP request
+ */
+static int nfs4_xdr_enc_lookup(struct rpc_rqst *req, uint32_t *p, const struct nfs4_lookup_arg *args)
+{
+	struct xdr_stream xdr;
+	struct compound_hdr hdr = {
+		.nops = 4,
+	};
+	int status;
+
+	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
+	encode_compound_hdr(&xdr, &hdr);
+	if ((status = encode_putfh(&xdr, args->dir_fh)) != 0)
+		goto out;
+	if ((status = encode_lookup(&xdr, args->name)) != 0)
+		goto out;
+	if ((status = encode_getfh(&xdr)) != 0)
+		goto out;
+	status = encode_getfattr(&xdr, args->bitmask);
+out:
+	return status;
 }
+
 /*
- * END OF "GENERIC" ENCODE ROUTINES.
+ * Encode LOOKUP_ROOT request
  */
+static int nfs4_xdr_enc_lookup_root(struct rpc_rqst *req, uint32_t *p, const struct nfs4_lookup_root_arg *args)
+{
+	struct xdr_stream xdr;
+	struct compound_hdr hdr = {
+		.nops = 3,
+	};
+	int status;
 
+	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
+	encode_compound_hdr(&xdr, &hdr);
+	if ((status = encode_putrootfh(&xdr)) != 0)
+		goto out;
+	if ((status = encode_getfh(&xdr)) == 0)
+		status = encode_getfattr(&xdr, args->bitmask);
+out:
+	return status;
+}
 
 /*
- * Encode COMPOUND argument
+ * Encode REMOVE request
  */
-static int
-nfs4_xdr_enc_compound(struct rpc_rqst *req, uint32_t *p, struct nfs4_compound *cp)
+static int nfs4_xdr_enc_remove(struct rpc_rqst *req, uint32_t *p, const struct nfs4_remove_arg *args)
 {
 	struct xdr_stream xdr;
+	struct compound_hdr hdr = {
+		.nops = 2,
+	};
 	int status;
-	
+
+	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
+	encode_compound_hdr(&xdr, &hdr);
+	if ((status = encode_putfh(&xdr, args->fh)) == 0)
+		status = encode_remove(&xdr, args->name);
+	return status;
+}
+
+/*
+ * Encode RENAME request
+ */
+static int nfs4_xdr_enc_rename(struct rpc_rqst *req, uint32_t *p, const struct nfs4_rename_arg *args)
+{
+	struct xdr_stream xdr;
+	struct compound_hdr hdr = {
+		.nops = 4,
+	};
+	int status;
+
+	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
+	encode_compound_hdr(&xdr, &hdr);
+	if ((status = encode_putfh(&xdr, args->old_dir)) != 0)
+		goto out;
+	if ((status = encode_savefh(&xdr)) != 0)
+		goto out;
+	if ((status = encode_putfh(&xdr, args->new_dir)) != 0)
+		goto out;
+	status = encode_rename(&xdr, args->old_name, args->new_name);
+out:
+	return status;
+}
+
+/*
+ * Encode LINK request
+ */
+static int nfs4_xdr_enc_link(struct rpc_rqst *req, uint32_t *p, const struct nfs4_link_arg *args)
+{
+	struct xdr_stream xdr;
+	struct compound_hdr hdr = {
+		.nops = 4,
+	};
+	int status;
+
+	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
+	encode_compound_hdr(&xdr, &hdr);
+	if ((status = encode_putfh(&xdr, args->fh)) != 0)
+		goto out;
+	if ((status = encode_savefh(&xdr)) != 0)
+		goto out;
+	if ((status = encode_putfh(&xdr, args->dir_fh)) != 0)
+		goto out;
+	status = encode_link(&xdr, args->name);
+out:
+	return status;
+}
+
+/*
+ * Encode CREATE request
+ */
+static int nfs4_xdr_enc_create(struct rpc_rqst *req, uint32_t *p, const struct nfs4_create_arg *args)
+{
+	struct xdr_stream xdr;
+	struct compound_hdr hdr = {
+		.nops = 4,
+	};
+	int status;
+
+	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
+	encode_compound_hdr(&xdr, &hdr);
+	if ((status = encode_putfh(&xdr, args->dir_fh)) != 0)
+		goto out;
+	if ((status = encode_create(&xdr, args)) != 0)
+		goto out;
+	if ((status = encode_getfattr(&xdr, args->bitmask)) != 0)
+		goto out;
+	status = encode_getfh(&xdr);
+out:
+	return status;
+}
+
+/*
+ * Encode GETATTR request
+ */
+static int nfs4_xdr_enc_getattr(struct rpc_rqst *req, uint32_t *p, const struct nfs4_getattr_arg *args)
+{
+	struct xdr_stream xdr;
+	struct compound_hdr hdr = {
+		.nops = 2,
+	};
+	int status;
+
 	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
-	status = encode_compound(&xdr, cp, req);
-	cp->timestamp = jiffies;
+	encode_compound_hdr(&xdr, &hdr);
+	if ((status = encode_putfh(&xdr, args->fh)) == 0)
+		status = encode_getfattr(&xdr, args->bitmask);
 	return status;
 }
+
 /*
  * Encode a CLOSE request
  */
-static int
-nfs4_xdr_enc_close(struct rpc_rqst *req, uint32_t *p, struct nfs_closeargs *args)
+static int nfs4_xdr_enc_close(struct rpc_rqst *req, uint32_t *p, struct nfs_closeargs *args)
 {
         struct xdr_stream xdr;
         struct compound_hdr hdr = {
@@ -1200,12 +1284,11 @@ out:
 /*
  * Encode an OPEN request
  */
-static int
-nfs4_xdr_enc_open(struct rpc_rqst *req, uint32_t *p, struct nfs_openargs *args)
+static int nfs4_xdr_enc_open(struct rpc_rqst *req, uint32_t *p, struct nfs_openargs *args)
 {
 	struct xdr_stream xdr;
 	struct compound_hdr hdr = {
-		.nops   = 7,
+		.nops = 4,
 	};
 	int status;
 
@@ -1214,22 +1297,13 @@ nfs4_xdr_enc_open(struct rpc_rqst *req, 
 	status = encode_putfh(&xdr, args->fh);
 	if (status)
 		goto out;
-	status = encode_savefh(&xdr);
-	if (status)
-		goto out;
 	status = encode_open(&xdr, args);
 	if (status)
 		goto out;
-	status = encode_getattr(&xdr, args->f_getattr);
+	status = encode_getfattr(&xdr, args->bitmask);
 	if (status)
 		goto out;
 	status = encode_getfh(&xdr);
-	if (status)
-		goto out;
-	status = encode_restorefh(&xdr);
-	if (status)
-		goto out;
-	status = encode_getattr(&xdr, args->d_getattr);
 out:
 	return status;
 }
@@ -1237,8 +1311,7 @@ out:
 /*
  * Encode an OPEN_CONFIRM request
  */
-static int
-nfs4_xdr_enc_open_confirm(struct rpc_rqst *req, uint32_t *p, struct nfs_open_confirmargs *args)
+static int nfs4_xdr_enc_open_confirm(struct rpc_rqst *req, uint32_t *p, struct nfs_open_confirmargs *args)
 {
 	struct xdr_stream xdr;
 	struct compound_hdr hdr = {
@@ -1259,9 +1332,7 @@ out:
 /*
  * Encode an OPEN request
  */
-static int
-nfs4_xdr_enc_open_reclaim(struct rpc_rqst *req, uint32_t *p,
-		struct nfs_open_reclaimargs *args)
+static int nfs4_xdr_enc_open_reclaim(struct rpc_rqst *req, uint32_t *p, struct nfs_open_reclaimargs *args)
 {
 	struct xdr_stream xdr;
 	struct compound_hdr hdr = {
@@ -1277,7 +1348,7 @@ nfs4_xdr_enc_open_reclaim(struct rpc_rqs
 	status = encode_open_reclaim(&xdr, args);
 	if (status)
 		goto out;
-	status = encode_getattr(&xdr, args->f_getattr);
+	status = encode_getfattr(&xdr, args->bitmask);
 out:
 	return status;
 }
@@ -1285,8 +1356,7 @@ out:
 /*
  * Encode an OPEN_DOWNGRADE request
  */
-static int
-nfs4_xdr_enc_open_downgrade(struct rpc_rqst *req, uint32_t *p, struct nfs_closeargs *args)
+static int nfs4_xdr_enc_open_downgrade(struct rpc_rqst *req, uint32_t *p, struct nfs_closeargs *args)
 {
 	struct xdr_stream xdr;
 	struct compound_hdr hdr = {
@@ -1307,8 +1377,7 @@ out:
 /*
  * Encode a LOCK request
  */
-static int
-nfs4_xdr_enc_lock(struct rpc_rqst *req, uint32_t *p, struct nfs_lockargs *args)
+static int nfs4_xdr_enc_lock(struct rpc_rqst *req, uint32_t *p, struct nfs_lockargs *args)
 {
 	struct xdr_stream xdr;
 	struct compound_hdr hdr = {
@@ -1329,8 +1398,7 @@ out:
 /*
  * Encode a LOCKT request
  */
-static int
-nfs4_xdr_enc_lockt(struct rpc_rqst *req, uint32_t *p, struct nfs_lockargs *args)
+static int nfs4_xdr_enc_lockt(struct rpc_rqst *req, uint32_t *p, struct nfs_lockargs *args)
 {
 	struct xdr_stream xdr;
 	struct compound_hdr hdr = {
@@ -1351,8 +1419,7 @@ out:
 /*
  * Encode a LOCKU request
  */
-static int
-nfs4_xdr_enc_locku(struct rpc_rqst *req, uint32_t *p, struct nfs_lockargs *args)
+static int nfs4_xdr_enc_locku(struct rpc_rqst *req, uint32_t *p, struct nfs_lockargs *args)
 {
 	struct xdr_stream xdr;
 	struct compound_hdr hdr = {
@@ -1371,34 +1438,73 @@ out:
 }
 
 /*
- * Encode a READ request
+ * Encode a READLINK request
  */
-static int
-nfs4_xdr_enc_read(struct rpc_rqst *req, uint32_t *p, struct nfs_readargs *args)
+static int nfs4_xdr_enc_readlink(struct rpc_rqst *req, uint32_t *p, const struct nfs4_readlink *args)
 {
-	struct rpc_auth	*auth = req->rq_task->tk_auth;
 	struct xdr_stream xdr;
 	struct compound_hdr hdr = {
-		.nops	= 3,
+		.nops = 2,
 	};
-	int replen, status;
+	int status;
 
 	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
 	encode_compound_hdr(&xdr, &hdr);
 	status = encode_putfh(&xdr, args->fh);
-	if (status)
-		goto out;
-	status = encode_read(&xdr, args);
-	if (status)
+	if(status)
+		goto out;
+	status = encode_readlink(&xdr, args, req);
+out:
+	return status;
+}
+
+/*
+ * Encode a READDIR request
+ */
+static int nfs4_xdr_enc_readdir(struct rpc_rqst *req, uint32_t *p, const struct nfs4_readdir_arg *args)
+{
+	struct xdr_stream xdr;
+	struct compound_hdr hdr = {
+		.nops = 2,
+	};
+	int status;
+
+	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
+	encode_compound_hdr(&xdr, &hdr);
+	status = encode_putfh(&xdr, args->fh);
+	if(status)
+		goto out;
+	status = encode_readdir(&xdr, args, req);
+out:
+	return status;
+}
+
+/*
+ * Encode a READ request
+ */
+static int nfs4_xdr_enc_read(struct rpc_rqst *req, uint32_t *p, struct nfs_readargs *args)
+{
+	struct rpc_auth	*auth = req->rq_task->tk_auth;
+	struct xdr_stream xdr;
+	struct compound_hdr hdr = {
+		.nops = 2,
+	};
+	int replen, status;
+
+	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
+	encode_compound_hdr(&xdr, &hdr);
+	status = encode_putfh(&xdr, args->fh);
+	if (status)
+		goto out;
+	status = encode_read(&xdr, args);
+	if (status)
 		goto out;
-	status = encode_read_getattr(&xdr);
 
 	/* set up reply iovec
 	 *    toplevel status + taglen=0 + rescount + OP_PUTFH + status
 	 *       + OP_READ + status + eof + datalen = 9
 	 */
-	replen = (RPC_REPHDRSIZE + auth->au_rslack +
-			NFS4_dec_read_sz - decode_read_getattr_maxsz) << 2;
+	replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS4_dec_read_sz) << 2;
 	xdr_inline_pages(&req->rq_rcv_buf, replen,
 			 args->pages, args->pgbase, args->count);
 out:
@@ -1408,8 +1514,7 @@ out:
 /*
  * Encode an SETATTR request
  */
-static int
-nfs4_xdr_enc_setattr(struct rpc_rqst *req, uint32_t *p, struct nfs_setattrargs *args)
+static int nfs4_xdr_enc_setattr(struct rpc_rqst *req, uint32_t *p, struct nfs_setattrargs *args)
 
 {
         struct xdr_stream xdr;
@@ -1426,7 +1531,7 @@ nfs4_xdr_enc_setattr(struct rpc_rqst *re
         status = encode_setattr(&xdr, args, args->server);
         if(status)
                 goto out;
-        status = encode_getattr(&xdr, args->attr);
+	status = encode_getfattr(&xdr, args->bitmask);
 out:
         return status;
 }
@@ -1434,12 +1539,11 @@ out:
 /*
  * Encode a WRITE request
  */
-static int
-nfs4_xdr_enc_write(struct rpc_rqst *req, uint32_t *p, struct nfs_writeargs *args)
+static int nfs4_xdr_enc_write(struct rpc_rqst *req, uint32_t *p, struct nfs_writeargs *args)
 {
 	struct xdr_stream xdr;
 	struct compound_hdr hdr = {
-		.nops   = 4,
+		.nops = 2,
 	};
 	int status;
 
@@ -1448,13 +1552,7 @@ nfs4_xdr_enc_write(struct rpc_rqst *req,
 	status = encode_putfh(&xdr, args->fh);
 	if (status)
 		goto out;
-	status = encode_pre_write_getattr(&xdr);
-	if (status)
-		goto out;
 	status = encode_write(&xdr, args);
-	if (status)
-		goto out;
-	status = encode_post_write_getattr(&xdr);
 out:
 	return status;
 }
@@ -1462,12 +1560,11 @@ out:
 /*
  *  a COMMIT request
  */
-static int
-nfs4_xdr_enc_commit(struct rpc_rqst *req, uint32_t *p, struct nfs_writeargs *args)
+static int nfs4_xdr_enc_commit(struct rpc_rqst *req, uint32_t *p, struct nfs_writeargs *args)
 {
 	struct xdr_stream xdr;
 	struct compound_hdr hdr = {
-		.nops   = 4,
+		.nops = 2,
 	};
 	int status;
 
@@ -1476,13 +1573,7 @@ nfs4_xdr_enc_commit(struct rpc_rqst *req
 	status = encode_putfh(&xdr, args->fh);
 	if (status)
 		goto out;
-	status = encode_pre_write_getattr(&xdr);
-	if (status)
-		goto out;
 	status = encode_commit(&xdr, args);
-	if (status)
-		goto out;
-	status = encode_post_write_getattr(&xdr);
 out:
 	return status;
 }
@@ -1490,8 +1581,7 @@ out:
 /*
  * FSINFO request
  */
-static int
-nfs4_xdr_enc_fsinfo(struct rpc_rqst *req, uint32_t *p, void *fhandle)
+static int nfs4_xdr_enc_fsinfo(struct rpc_rqst *req, uint32_t *p, struct nfs4_fsinfo_arg *args)
 {
 	struct xdr_stream xdr;
 	struct compound_hdr hdr = {
@@ -1501,17 +1591,81 @@ nfs4_xdr_enc_fsinfo(struct rpc_rqst *req
 
 	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
 	encode_compound_hdr(&xdr, &hdr);
-	status = encode_putfh(&xdr, fhandle);
+	status = encode_putfh(&xdr, args->fh);
+	if (!status)
+		status = encode_fsinfo(&xdr, args->bitmask);
+	return status;
+}
+
+/*
+ * a PATHCONF request
+ */
+static int nfs4_xdr_enc_pathconf(struct rpc_rqst *req, uint32_t *p, const struct nfs4_pathconf_arg *args)
+{
+	extern u32 nfs4_pathconf_bitmap[2];
+	struct xdr_stream xdr;
+	struct compound_hdr hdr = {
+		.nops = 2,
+	};
+	int status;
+
+	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
+	encode_compound_hdr(&xdr, &hdr);
+	status = encode_putfh(&xdr, args->fh);
 	if (!status)
-		status = encode_fsinfo(&xdr);
+		status = encode_getattr_one(&xdr,
+				args->bitmask[0] & nfs4_pathconf_bitmap[0]);
+	return status;
+}
+
+/*
+ * a STATFS request
+ */
+static int nfs4_xdr_enc_statfs(struct rpc_rqst *req, uint32_t *p, const struct nfs4_statfs_arg *args)
+{
+	extern u32 nfs4_statfs_bitmap[];
+	struct xdr_stream xdr;
+	struct compound_hdr hdr = {
+		.nops = 2,
+	};
+	int status;
+
+	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
+	encode_compound_hdr(&xdr, &hdr);
+	status = encode_putfh(&xdr, args->fh);
+	if (status == 0)
+		status = encode_getattr_two(&xdr,
+				args->bitmask[0] & nfs4_statfs_bitmap[0],
+				args->bitmask[1] & nfs4_statfs_bitmap[1]);
+	return status;
+}
+
+/*
+ * GETATTR_BITMAP request
+ */
+static int nfs4_xdr_enc_server_caps(struct rpc_rqst *req, uint32_t *p, const struct nfs_fh *fhandle)
+{
+	struct xdr_stream xdr;
+	struct compound_hdr hdr = {
+		.nops = 2,
+	};
+	int status;
+
+	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
+	encode_compound_hdr(&xdr, &hdr);
+	status = encode_putfh(&xdr, fhandle);
+	if (status == 0)
+		status = encode_getattr_one(&xdr, FATTR4_WORD0_SUPPORTED_ATTRS|
+				FATTR4_WORD0_LINK_SUPPORT|
+				FATTR4_WORD0_SYMLINK_SUPPORT|
+				FATTR4_WORD0_ACLSUPPORT);
 	return status;
 }
 
 /*
  * a RENEW request
  */
-static int
-nfs4_xdr_enc_renew(struct rpc_rqst *req, uint32_t *p, struct nfs4_client *clp)
+static int nfs4_xdr_enc_renew(struct rpc_rqst *req, uint32_t *p, struct nfs4_client *clp)
 {
 	struct xdr_stream xdr;
 	struct compound_hdr hdr = {
@@ -1526,9 +1680,7 @@ nfs4_xdr_enc_renew(struct rpc_rqst *req,
 /*
  * a SETCLIENTID request
  */
-static int
-nfs4_xdr_enc_setclientid(struct rpc_rqst *req, uint32_t *p,
-		struct nfs4_setclientid *sc)
+static int nfs4_xdr_enc_setclientid(struct rpc_rqst *req, uint32_t *p, struct nfs4_setclientid *sc)
 {
 	struct xdr_stream xdr;
 	struct compound_hdr hdr = {
@@ -1543,14 +1695,13 @@ nfs4_xdr_enc_setclientid(struct rpc_rqst
 /*
  * a SETCLIENTID_CONFIRM request
  */
-static int
-nfs4_xdr_enc_setclientid_confirm(struct rpc_rqst *req, uint32_t *p,
-		struct nfs4_client *clp)
+static int nfs4_xdr_enc_setclientid_confirm(struct rpc_rqst *req, uint32_t *p, struct nfs4_client *clp)
 {
 	struct xdr_stream xdr;
 	struct compound_hdr hdr = {
 		.nops	= 3,
 	};
+	const u32 lease_bitmap[2] = { FATTR4_WORD0_LEASE_TIME, 0 };
 	int status;
 
 	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
@@ -1559,7 +1710,7 @@ nfs4_xdr_enc_setclientid_confirm(struct 
 	if (!status)
 		status = encode_putrootfh(&xdr);
 	if (!status)
-		status = encode_fsinfo(&xdr);
+		status = encode_fsinfo(&xdr, lease_bitmap);
 	return status;
 }
 
@@ -1573,15 +1724,6 @@ nfs4_xdr_enc_setclientid_confirm(struct 
  * task to translate them into Linux-specific versions which are more
  * consistent with the style used in NFSv2/v3...
  */
-#define DECODE_TAIL				\
-	status = 0;				\
-out:						\
-	return status;				\
-xdr_error:					\
-	printk(KERN_NOTICE "xdr error! (%s:%d)\n", __FILE__, __LINE__); \
-	status = -EIO;				\
-	goto out
-
 #define READ32(x)         (x) = ntohl(*p++)
 #define READ64(x)         do {			\
 	(x) = (u64)ntohl(*p++) << 32;		\
@@ -1606,8 +1748,7 @@ xdr_error:					\
 	} \
 } while (0)
 
-static int
-decode_compound_hdr(struct xdr_stream *xdr, struct compound_hdr *hdr)
+static int decode_compound_hdr(struct xdr_stream *xdr, struct compound_hdr *hdr)
 {
 	uint32_t *p;
 
@@ -1622,30 +1763,616 @@ decode_compound_hdr(struct xdr_stream *x
 	return 0;
 }
 
-static int
-decode_op_hdr(struct xdr_stream *xdr, enum nfs_opnum4 expected)
+static int decode_op_hdr(struct xdr_stream *xdr, enum nfs_opnum4 expected)
+{
+	uint32_t *p;
+	uint32_t opnum;
+	int32_t nfserr;
+
+	READ_BUF(8);
+	READ32(opnum);
+	if (opnum != expected) {
+		printk(KERN_NOTICE
+				"nfs4_decode_op_hdr: Server returned operation"
+			       	" %d but we issued a request for %d\n",
+				opnum, expected);
+		return -EIO;
+	}
+	READ32(nfserr);
+	if (nfserr != NFS_OK)
+		return -nfs_stat_to_errno(nfserr);
+	return 0;
+}
+
+static int decode_attr_bitmap(struct xdr_stream *xdr, uint32_t *bitmap)
+{
+	uint32_t bmlen, *p;
+
+	READ_BUF(4);
+	READ32(bmlen);
+
+	bitmap[0] = bitmap[1] = 0;
+	READ_BUF((bmlen << 2));
+	if (bmlen > 0) {
+		READ32(bitmap[0]);
+		if (bmlen > 1)
+			READ32(bitmap[1]);
+	}
+	return 0;
+}
+
+static inline int decode_attr_length(struct xdr_stream *xdr, uint32_t *attrlen, uint32_t **savep)
+{
+	uint32_t *p;
+
+	READ_BUF(4);
+	READ32(*attrlen);
+	*savep = xdr->p;
+	return 0;
+}
+
+static int decode_attr_supported(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *bitmask)
+{
+	if (likely(bitmap[0] & FATTR4_WORD0_SUPPORTED_ATTRS)) {
+		decode_attr_bitmap(xdr, bitmask);
+		bitmap[0] &= ~FATTR4_WORD0_SUPPORTED_ATTRS;
+	} else
+		bitmask[0] = bitmask[1] = 0;
+	dprintk("%s: bitmask=0x%x%x\n", __FUNCTION__, bitmask[0], bitmask[1]);
+	return 0;
+}
+
+static int decode_attr_type(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *type)
+{
+	uint32_t *p;
+
+	*type = 0;
+	if (unlikely(bitmap[0] & (FATTR4_WORD0_TYPE - 1U)))
+		return -EIO;
+	if (likely(bitmap[0] & FATTR4_WORD0_TYPE)) {
+		READ_BUF(4);
+		READ32(*type);
+		if (*type < NF4REG || *type > NF4NAMEDATTR) {
+			dprintk("%s: bad type %d\n", __FUNCTION__, *type);
+			return -EIO;
+		}
+		bitmap[0] &= ~FATTR4_WORD0_TYPE;
+	}
+	dprintk("%s: type=0%o\n", __FUNCTION__, nfs_type2fmt[*type].nfs2type);
+	return 0;
+}
+
+static int decode_attr_change(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *change)
+{
+	uint32_t *p;
+
+	*change = 0;
+	if (unlikely(bitmap[0] & (FATTR4_WORD0_CHANGE - 1U)))
+		return -EIO;
+	if (likely(bitmap[0] & FATTR4_WORD0_CHANGE)) {
+		READ_BUF(8);
+		READ64(*change);
+		bitmap[0] &= ~FATTR4_WORD0_CHANGE;
+	}
+	dprintk("%s: change attribute=%Lu\n", __FUNCTION__,
+			(unsigned long long)*change);
+	return 0;
+}
+
+static int decode_attr_size(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *size)
+{
+	uint32_t *p;
+
+	*size = 0;
+	if (unlikely(bitmap[0] & (FATTR4_WORD0_SIZE - 1U)))
+		return -EIO;
+	if (likely(bitmap[0] & FATTR4_WORD0_SIZE)) {
+		READ_BUF(8);
+		READ64(*size);
+		bitmap[0] &= ~FATTR4_WORD0_SIZE;
+	}
+	dprintk("%s: file size=%Lu\n", __FUNCTION__, (unsigned long long)*size);
+	return 0;
+}
+
+static int decode_attr_link_support(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res)
+{
+	uint32_t *p;
+
+	*res = 0;
+	if (unlikely(bitmap[0] & (FATTR4_WORD0_LINK_SUPPORT - 1U)))
+		return -EIO;
+	if (likely(bitmap[0] & FATTR4_WORD0_LINK_SUPPORT)) {
+		READ_BUF(4);
+		READ32(*res);
+		bitmap[0] &= ~FATTR4_WORD0_LINK_SUPPORT;
+	}
+	dprintk("%s: link support=%s\n", __FUNCTION__, *res == 0 ? "false" : "true");
+	return 0;
+}
+
+static int decode_attr_symlink_support(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res)
+{
+	uint32_t *p;
+
+	*res = 0;
+	if (unlikely(bitmap[0] & (FATTR4_WORD0_SYMLINK_SUPPORT - 1U)))
+		return -EIO;
+	if (likely(bitmap[0] & FATTR4_WORD0_SYMLINK_SUPPORT)) {
+		READ_BUF(4);
+		READ32(*res);
+		bitmap[0] &= ~FATTR4_WORD0_SYMLINK_SUPPORT;
+	}
+	dprintk("%s: symlink support=%s\n", __FUNCTION__, *res == 0 ? "false" : "true");
+	return 0;
+}
+
+static int decode_attr_fsid(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs4_fsid *fsid)
+{
+	uint32_t *p;
+
+	fsid->major = 0;
+	fsid->minor = 0;
+	if (unlikely(bitmap[0] & (FATTR4_WORD0_FSID - 1U)))
+		return -EIO;
+	if (likely(bitmap[0] & FATTR4_WORD0_FSID)) {
+		READ_BUF(16);
+		READ64(fsid->major);
+		READ64(fsid->minor);
+		bitmap[0] &= ~FATTR4_WORD0_FSID;
+	}
+	dprintk("%s: fsid=(0x%Lx/0x%Lx)\n", __FUNCTION__,
+			(unsigned long long)fsid->major,
+			(unsigned long long)fsid->minor);
+	return 0;
+}
+
+static int decode_attr_lease_time(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res)
+{
+	uint32_t *p;
+
+	*res = 60;
+	if (unlikely(bitmap[0] & (FATTR4_WORD0_LEASE_TIME - 1U)))
+		return -EIO;
+	if (likely(bitmap[0] & FATTR4_WORD0_LEASE_TIME)) {
+		READ_BUF(4);
+		READ32(*res);
+		bitmap[0] &= ~FATTR4_WORD0_LEASE_TIME;
+	}
+	dprintk("%s: file size=%u\n", __FUNCTION__, (unsigned int)*res);
+	return 0;
+}
+
+static int decode_attr_aclsupport(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res)
+{
+	uint32_t *p;
+
+	*res = ACL4_SUPPORT_ALLOW_ACL|ACL4_SUPPORT_DENY_ACL;
+	if (unlikely(bitmap[0] & (FATTR4_WORD0_ACLSUPPORT - 1U)))
+		return -EIO;
+	if (likely(bitmap[0] & FATTR4_WORD0_ACLSUPPORT)) {
+		READ_BUF(4);
+		READ32(*res);
+		bitmap[0] &= ~FATTR4_WORD0_ACLSUPPORT;
+	}
+	dprintk("%s: ACLs supported=%u\n", __FUNCTION__, (unsigned int)*res);
+	return 0;
+}
+
+static int decode_attr_fileid(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *fileid)
+{
+	uint32_t *p;
+
+	*fileid = 0;
+	if (unlikely(bitmap[0] & (FATTR4_WORD0_FILEID - 1U)))
+		return -EIO;
+	if (likely(bitmap[0] & FATTR4_WORD0_FILEID)) {
+		READ_BUF(8);
+		READ64(*fileid);
+		bitmap[0] &= ~FATTR4_WORD0_FILEID;
+	}
+	dprintk("%s: fileid=%Lu\n", __FUNCTION__, (unsigned long long)*fileid);
+	return 0;
+}
+
+static int decode_attr_files_avail(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res)
+{
+	uint32_t *p;
+	int status = 0;
+
+	*res = 0;
+	if (unlikely(bitmap[0] & (FATTR4_WORD0_FILES_AVAIL - 1U)))
+		return -EIO;
+	if (likely(bitmap[0] & FATTR4_WORD0_FILES_AVAIL)) {
+		READ_BUF(8);
+		READ64(*res);
+		bitmap[0] &= ~FATTR4_WORD0_FILES_AVAIL;
+	}
+	dprintk("%s: files avail=%Lu\n", __FUNCTION__, (unsigned long long)*res);
+	return status;
+}
+
+static int decode_attr_files_free(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res)
+{
+	uint32_t *p;
+	int status = 0;
+
+	*res = 0;
+	if (unlikely(bitmap[0] & (FATTR4_WORD0_FILES_FREE - 1U)))
+		return -EIO;
+	if (likely(bitmap[0] & FATTR4_WORD0_FILES_FREE)) {
+		READ_BUF(8);
+		READ64(*res);
+		bitmap[0] &= ~FATTR4_WORD0_FILES_FREE;
+	}
+	dprintk("%s: files free=%Lu\n", __FUNCTION__, (unsigned long long)*res);
+	return status;
+}
+
+static int decode_attr_files_total(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res)
+{
+	uint32_t *p;
+	int status = 0;
+
+	*res = 0;
+	if (unlikely(bitmap[0] & (FATTR4_WORD0_FILES_TOTAL - 1U)))
+		return -EIO;
+	if (likely(bitmap[0] & FATTR4_WORD0_FILES_TOTAL)) {
+		READ_BUF(8);
+		READ64(*res);
+		bitmap[0] &= ~FATTR4_WORD0_FILES_TOTAL;
+	}
+	dprintk("%s: files total=%Lu\n", __FUNCTION__, (unsigned long long)*res);
+	return status;
+}
+
+static int decode_attr_maxfilesize(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res)
+{
+	uint32_t *p;
+	int status = 0;
+
+	*res = 0;
+	if (unlikely(bitmap[0] & (FATTR4_WORD0_MAXFILESIZE - 1U)))
+		return -EIO;
+	if (likely(bitmap[0] & FATTR4_WORD0_MAXFILESIZE)) {
+		READ_BUF(8);
+		READ64(*res);
+		bitmap[0] &= ~FATTR4_WORD0_MAXFILESIZE;
+	}
+	dprintk("%s: maxfilesize=%Lu\n", __FUNCTION__, (unsigned long long)*res);
+	return status;
+}
+
+static int decode_attr_maxlink(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *maxlink)
+{
+	uint32_t *p;
+	int status = 0;
+
+	*maxlink = 1;
+	if (unlikely(bitmap[0] & (FATTR4_WORD0_MAXLINK - 1U)))
+		return -EIO;
+	if (likely(bitmap[0] & FATTR4_WORD0_MAXLINK)) {
+		READ_BUF(4);
+		READ32(*maxlink);
+		bitmap[0] &= ~FATTR4_WORD0_MAXLINK;
+	}
+	dprintk("%s: maxlink=%u\n", __FUNCTION__, *maxlink);
+	return status;
+}
+
+static int decode_attr_maxname(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *maxname)
+{
+	uint32_t *p;
+	int status = 0;
+
+	*maxname = 1024;
+	if (unlikely(bitmap[0] & (FATTR4_WORD0_MAXNAME - 1U)))
+		return -EIO;
+	if (likely(bitmap[0] & FATTR4_WORD0_MAXNAME)) {
+		READ_BUF(4);
+		READ32(*maxname);
+		bitmap[0] &= ~FATTR4_WORD0_MAXNAME;
+	}
+	dprintk("%s: maxname=%u\n", __FUNCTION__, *maxname);
+	return status;
+}
+
+static int decode_attr_maxread(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res)
+{
+	uint32_t *p;
+	int status = 0;
+
+	*res = 1024;
+	if (unlikely(bitmap[0] & (FATTR4_WORD0_MAXREAD - 1U)))
+		return -EIO;
+	if (likely(bitmap[0] & FATTR4_WORD0_MAXREAD)) {
+		uint64_t maxread;
+		READ_BUF(8);
+		READ64(maxread);
+		if (maxread > 0x7FFFFFFF)
+			maxread = 0x7FFFFFFF;
+		*res = (uint32_t)maxread;
+		bitmap[0] &= ~FATTR4_WORD0_MAXREAD;
+	}
+	dprintk("%s: maxread=%lu\n", __FUNCTION__, (unsigned long)*res);
+	return status;
+}
+
+static int decode_attr_maxwrite(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res)
+{
+	uint32_t *p;
+	int status = 0;
+
+	*res = 1024;
+	if (unlikely(bitmap[0] & (FATTR4_WORD0_MAXWRITE - 1U)))
+		return -EIO;
+	if (likely(bitmap[0] & FATTR4_WORD0_MAXWRITE)) {
+		uint64_t maxwrite;
+		READ_BUF(8);
+		READ64(maxwrite);
+		if (maxwrite > 0x7FFFFFFF)
+			maxwrite = 0x7FFFFFFF;
+		*res = (uint32_t)maxwrite;
+		bitmap[0] &= ~FATTR4_WORD0_MAXWRITE;
+	}
+	dprintk("%s: maxwrite=%lu\n", __FUNCTION__, (unsigned long)*res);
+	return status;
+}
+
+static int decode_attr_mode(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *mode)
+{
+	uint32_t *p;
+
+	*mode = 0;
+	if (unlikely(bitmap[1] & (FATTR4_WORD1_MODE - 1U)))
+		return -EIO;
+	if (likely(bitmap[1] & FATTR4_WORD1_MODE)) {
+		READ_BUF(4);
+		READ32(*mode);
+		*mode &= ~S_IFMT;
+		bitmap[1] &= ~FATTR4_WORD1_MODE;
+	}
+	dprintk("%s: file mode=0%o\n", __FUNCTION__, (unsigned int)*mode);
+	return 0;
+}
+
+static int decode_attr_nlink(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *nlink)
+{
+	uint32_t *p;
+
+	*nlink = 1;
+	if (unlikely(bitmap[1] & (FATTR4_WORD1_NUMLINKS - 1U)))
+		return -EIO;
+	if (likely(bitmap[1] & FATTR4_WORD1_NUMLINKS)) {
+		READ_BUF(4);
+		READ32(*nlink);
+		bitmap[1] &= ~FATTR4_WORD1_NUMLINKS;
+	}
+	dprintk("%s: nlink=%u\n", __FUNCTION__, (unsigned int)*nlink);
+	return 0;
+}
+
+static int decode_attr_owner(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs4_client *clp, int32_t *uid)
+{
+	uint32_t len, *p;
+	int status = 0;
+
+	*uid = -2;
+	if (unlikely(bitmap[1] & (FATTR4_WORD1_OWNER - 1U)))
+		return -EIO;
+	if (likely(bitmap[1] & FATTR4_WORD1_OWNER)) {
+		READ_BUF(4);
+		READ32(len);
+		READ_BUF(len);
+		if (len < XDR_MAX_NETOBJ) {
+			status = nfs_map_name_to_uid(clp, (char *)p, len, uid);
+			if (status != 0)
+				dprintk("%s: nfs_map_name_to_uid failed!\n",
+						__FUNCTION__);
+		} else
+			printk(KERN_WARNING "%s: name too long (%u)!\n",
+					__FUNCTION__, len);
+		bitmap[1] &= ~FATTR4_WORD1_OWNER;
+	}
+	dprintk("%s: uid=%d\n", __FUNCTION__, (int)*uid);
+	return status;
+}
+
+static int decode_attr_group(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs4_client *clp, int32_t *gid)
+{
+	uint32_t len, *p;
+	int status = 0;
+
+	*gid = -2;
+	if (unlikely(bitmap[1] & (FATTR4_WORD1_OWNER_GROUP - 1U)))
+		return -EIO;
+	if (likely(bitmap[1] & FATTR4_WORD1_OWNER_GROUP)) {
+		READ_BUF(4);
+		READ32(len);
+		READ_BUF(len);
+		if (len < XDR_MAX_NETOBJ) {
+			status = nfs_map_group_to_gid(clp, (char *)p, len, gid);
+			if (status != 0)
+				dprintk("%s: nfs_map_group_to_gid failed!\n",
+						__FUNCTION__);
+		} else
+			printk(KERN_WARNING "%s: name too long (%u)!\n",
+					__FUNCTION__, len);
+		bitmap[1] &= ~FATTR4_WORD1_OWNER_GROUP;
+	}
+	dprintk("%s: gid=%d\n", __FUNCTION__, (int)*gid);
+	return status;
+}
+
+static int decode_attr_rdev(struct xdr_stream *xdr, uint32_t *bitmap, dev_t *rdev)
+{
+	uint32_t major = 0, minor = 0, *p;
+
+	*rdev = MKDEV(0,0);
+	if (unlikely(bitmap[1] & (FATTR4_WORD1_RAWDEV - 1U)))
+		return -EIO;
+	if (likely(bitmap[1] & FATTR4_WORD1_RAWDEV)) {
+		dev_t tmp;
+
+		READ_BUF(8);
+		READ32(major);
+		READ32(minor);
+		tmp = MKDEV(major, minor);
+		if (MAJOR(tmp) == major && MINOR(tmp) == minor)
+			*rdev = tmp;
+		bitmap[1] &= ~ FATTR4_WORD1_RAWDEV;
+	}
+	dprintk("%s: rdev=(0x%x:0x%x)\n", __FUNCTION__, major, minor);
+	return 0;
+}
+
+static int decode_attr_space_avail(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res)
+{
+	uint32_t *p;
+	int status = 0;
+
+	*res = 0;
+	if (unlikely(bitmap[1] & (FATTR4_WORD1_SPACE_AVAIL - 1U)))
+		return -EIO;
+	if (likely(bitmap[1] & FATTR4_WORD1_SPACE_AVAIL)) {
+		READ_BUF(8);
+		READ64(*res);
+		bitmap[1] &= ~FATTR4_WORD1_SPACE_AVAIL;
+	}
+	dprintk("%s: space avail=%Lu\n", __FUNCTION__, (unsigned long long)*res);
+	return status;
+}
+
+static int decode_attr_space_free(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res)
+{
+	uint32_t *p;
+	int status = 0;
+
+	*res = 0;
+	if (unlikely(bitmap[1] & (FATTR4_WORD1_SPACE_FREE - 1U)))
+		return -EIO;
+	if (likely(bitmap[1] & FATTR4_WORD1_SPACE_FREE)) {
+		READ_BUF(8);
+		READ64(*res);
+		bitmap[1] &= ~FATTR4_WORD1_SPACE_FREE;
+	}
+	dprintk("%s: space free=%Lu\n", __FUNCTION__, (unsigned long long)*res);
+	return status;
+}
+
+static int decode_attr_space_total(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res)
+{
+	uint32_t *p;
+	int status = 0;
+
+	*res = 0;
+	if (unlikely(bitmap[1] & (FATTR4_WORD1_SPACE_TOTAL - 1U)))
+		return -EIO;
+	if (likely(bitmap[1] & FATTR4_WORD1_SPACE_TOTAL)) {
+		READ_BUF(8);
+		READ64(*res);
+		bitmap[1] &= ~FATTR4_WORD1_SPACE_TOTAL;
+	}
+	dprintk("%s: space total=%Lu\n", __FUNCTION__, (unsigned long long)*res);
+	return status;
+}
+
+static int decode_attr_space_used(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *used)
+{
+	uint32_t *p;
+
+	*used = 0;
+	if (unlikely(bitmap[1] & (FATTR4_WORD1_SPACE_USED - 1U)))
+		return -EIO;
+	if (likely(bitmap[1] & FATTR4_WORD1_SPACE_USED)) {
+		READ_BUF(8);
+		READ64(*used);
+		bitmap[1] &= ~FATTR4_WORD1_SPACE_USED;
+	}
+	dprintk("%s: space used=%Lu\n", __FUNCTION__,
+			(unsigned long long)*used);
+	return 0;
+}
+
+static int decode_attr_time(struct xdr_stream *xdr, struct timespec *time)
+{
+	uint32_t *p;
+	uint64_t sec;
+	uint32_t nsec;
+
+	READ_BUF(12);
+	READ64(sec);
+	READ32(nsec);
+	time->tv_sec = (time_t)sec;
+	time->tv_nsec = (long)nsec;
+	return 0;
+}
+
+static int decode_attr_time_access(struct xdr_stream *xdr, uint32_t *bitmap, struct timespec *time)
+{
+	int status = 0;
+
+	time->tv_sec = 0;
+	time->tv_nsec = 0;
+	if (unlikely(bitmap[1] & (FATTR4_WORD1_TIME_ACCESS - 1U)))
+		return -EIO;
+	if (likely(bitmap[1] & FATTR4_WORD1_TIME_ACCESS)) {
+		status = decode_attr_time(xdr, time);
+		bitmap[1] &= ~FATTR4_WORD1_TIME_ACCESS;
+	}
+	dprintk("%s: atime=%ld\n", __FUNCTION__, (long)time->tv_sec);
+	return status;
+}
+
+static int decode_attr_time_metadata(struct xdr_stream *xdr, uint32_t *bitmap, struct timespec *time)
+{
+	int status = 0;
+
+	time->tv_sec = 0;
+	time->tv_nsec = 0;
+	if (unlikely(bitmap[1] & (FATTR4_WORD1_TIME_METADATA - 1U)))
+		return -EIO;
+	if (likely(bitmap[1] & FATTR4_WORD1_TIME_METADATA)) {
+		status = decode_attr_time(xdr, time);
+		bitmap[1] &= ~FATTR4_WORD1_TIME_METADATA;
+	}
+	dprintk("%s: ctime=%ld\n", __FUNCTION__, (long)time->tv_sec);
+	return status;
+}
+
+static int decode_attr_time_modify(struct xdr_stream *xdr, uint32_t *bitmap, struct timespec *time)
+{
+	int status = 0;
+
+	time->tv_sec = 0;
+	time->tv_nsec = 0;
+	if (unlikely(bitmap[1] & (FATTR4_WORD1_TIME_MODIFY - 1U)))
+		return -EIO;
+	if (likely(bitmap[1] & FATTR4_WORD1_TIME_MODIFY)) {
+		status = decode_attr_time(xdr, time);
+		bitmap[1] &= ~FATTR4_WORD1_TIME_MODIFY;
+	}
+	dprintk("%s: mtime=%ld\n", __FUNCTION__, (long)time->tv_sec);
+	return status;
+}
+
+static int verify_attr_len(struct xdr_stream *xdr, uint32_t *savep, uint32_t attrlen)
 {
-	uint32_t *p;
-	uint32_t opnum;
-	int32_t nfserr;
+	unsigned int attrwords = XDR_QUADLEN(attrlen);
+	unsigned int nwords = xdr->p - savep;
 
-	READ_BUF(8);
-	READ32(opnum);
-	if (opnum != expected) {
-		printk(KERN_NOTICE
-				"nfs4_decode_op_hdr: Server returned operation"
-			       	" %d but we issued a request for %d\n",
-				opnum, expected);
+	if (unlikely(attrwords != nwords)) {
+		printk(KERN_WARNING "%s: server returned incorrect attribute length: %u %c %u\n",
+				__FUNCTION__,
+				attrwords << 2,
+				(attrwords < nwords) ? '<' : '>',
+				nwords << 2);
 		return -EIO;
 	}
-	READ32(nfserr);
-	if (nfserr != NFS_OK)
-		return -nfs_stat_to_errno(nfserr);
 	return 0;
 }
 
-static int
-decode_change_info(struct xdr_stream *xdr, struct nfs4_change_info *cinfo)
+static int decode_change_info(struct xdr_stream *xdr, struct nfs4_change_info *cinfo)
 {
 	uint32_t *p;
 
@@ -1656,8 +2383,7 @@ decode_change_info(struct xdr_stream *xd
 	return 0;
 }
 
-static int
-decode_access(struct xdr_stream *xdr, struct nfs4_access *access)
+static int decode_access(struct xdr_stream *xdr, struct nfs4_accessres *access)
 {
 	uint32_t *p;
 	uint32_t supp, acc;
@@ -1669,17 +2395,12 @@ decode_access(struct xdr_stream *xdr, st
 	READ_BUF(8);
 	READ32(supp);
 	READ32(acc);
-	if ((supp & ~access->ac_req_access) || (acc & ~supp)) {
-		printk(KERN_NOTICE "NFS: server returned bad bits in access call!\n");
-		return -EIO;
-	}
-	*access->ac_resp_supported = supp;
-	*access->ac_resp_access = acc;
+	access->supported = supp;
+	access->access = acc;
 	return 0;
 }
 
-static int
-decode_close(struct xdr_stream *xdr, struct nfs_closeres *res)
+static int decode_close(struct xdr_stream *xdr, struct nfs_closeres *res)
 {
 	uint32_t *p;
 	int status;
@@ -1692,8 +2413,7 @@ decode_close(struct xdr_stream *xdr, str
 	return 0;
 }
 
-static int
-decode_commit(struct xdr_stream *xdr, struct nfs_writeres *res)
+static int decode_commit(struct xdr_stream *xdr, struct nfs_writeres *res)
 {
 	uint32_t *p;
 	int status;
@@ -1706,8 +2426,7 @@ decode_commit(struct xdr_stream *xdr, st
 	return 0;
 }
 
-static int
-decode_create(struct xdr_stream *xdr, struct nfs4_create *create)
+static int decode_create(struct xdr_stream *xdr, struct nfs4_change_info *cinfo)
 {
 	uint32_t *p;
 	uint32_t bmlen;
@@ -1716,7 +2435,7 @@ decode_create(struct xdr_stream *xdr, st
 	status = decode_op_hdr(xdr, OP_CREATE);
 	if (status)
 		return status;
-	if ((status = decode_change_info(xdr, create->cr_cinfo)))
+	if ((status = decode_change_info(xdr, cinfo)))
 		return status;
 	READ_BUF(4);
 	READ32(bmlen);
@@ -1724,443 +2443,192 @@ decode_create(struct xdr_stream *xdr, st
 	return 0;
 }
 
-extern uint32_t nfs4_fattr_bitmap[2];
-extern uint32_t nfs4_fsstat_bitmap[2];
-extern uint32_t nfs4_pathconf_bitmap[2];
-
-static int
-decode_getattr(struct xdr_stream *xdr, struct nfs4_getattr *getattr,
-    struct nfs_server *server)
+static int decode_server_caps(struct xdr_stream *xdr, struct nfs4_server_caps_res *res)
 {
-	struct nfs_fattr *nfp = getattr->gt_attrs;
-	struct nfs_fsstat *fsstat = getattr->gt_fsstat;
-	struct nfs_pathconf *pathconf = getattr->gt_pathconf;
-	uint32_t attrlen, dummy32, bmlen,
-		 bmval0 = 0,
-		 bmval1 = 0,
-		 len = 0;
-	uint32_t *p;
-	unsigned int type;
-	int fmode = 0;
+	uint32_t *savep;
+	uint32_t attrlen,
+		 bitmap[2] = {0};
 	int status;
+
+	if ((status = decode_op_hdr(xdr, OP_GETATTR)) != 0)
+		goto xdr_error;
+	if ((status = decode_attr_bitmap(xdr, bitmap)) != 0)
+		goto xdr_error;
+	if ((status = decode_attr_length(xdr, &attrlen, &savep)) != 0)
+		goto xdr_error;
+	if ((status = decode_attr_supported(xdr, bitmap, res->attr_bitmask)) != 0)
+		goto xdr_error;
+	if ((status = decode_attr_link_support(xdr, bitmap, &res->has_links)) != 0)
+		goto xdr_error;
+	if ((status = decode_attr_symlink_support(xdr, bitmap, &res->has_symlinks)) != 0)
+		goto xdr_error;
+	if ((status = decode_attr_aclsupport(xdr, bitmap, &res->acl_bitmask)) != 0)
+		goto xdr_error;
+	status = verify_attr_len(xdr, savep, attrlen);
+xdr_error:
+	if (status != 0)
+		printk(KERN_NOTICE "%s: xdr error %d!\n", __FUNCTION__, -status);
+	return status;
+}
 	
-	status = decode_op_hdr(xdr, OP_GETATTR);
-	if (status)
-		return status;
-        
-        READ_BUF(4);
-        READ32(bmlen);
-        if (bmlen > 2)
-                goto xdr_error;
+static int decode_statfs(struct xdr_stream *xdr, struct nfs_fsstat *fsstat)
+{
+	uint32_t *savep;
+	uint32_t attrlen,
+		 bitmap[2] = {0};
+	int status;
 	
-        READ_BUF((bmlen << 2) + 4);
-        if (bmlen > 0)
-                READ32(bmval0);
-        if (bmlen > 1)
-                READ32(bmval1);
-        READ32(attrlen);
-
-	if ((bmval0 & ~getattr->gt_bmval[0]) ||
-	    (bmval1 & ~getattr->gt_bmval[1])) {
-		dprintk("read_attrs: server returned bad attributes!\n");
+	if ((status = decode_op_hdr(xdr, OP_GETATTR)) != 0)
+		goto xdr_error;
+	if ((status = decode_attr_bitmap(xdr, bitmap)) != 0)
+		goto xdr_error;
+	if ((status = decode_attr_length(xdr, &attrlen, &savep)) != 0)
 		goto xdr_error;
-	}
-	if (nfp) {
-		nfp->bitmap[0] = bmval0;
-		nfp->bitmap[1] = bmval1;
-	}
 
-	/*
-	 * In case the server doesn't return some attributes,
-	 * we initialize them here to some nominal values..
-	 */
-	if (nfp) {
-		nfp->valid = NFS_ATTR_FATTR | NFS_ATTR_FATTR_V3 | NFS_ATTR_FATTR_V4;
-		nfp->nlink = 1;
-		nfp->timestamp = jiffies;
-	}
-        if (bmval0 & FATTR4_WORD0_TYPE) {
-                READ_BUF(4);
-                len += 4;
-                READ32(type);
-                if (type < NF4REG || type > NF4NAMEDATTR) {
-                        dprintk("read_attrs: bad type %d\n", type);
-                        goto xdr_error;
-                }
-		nfp->type = nfs_type2fmt[type].nfs2type;
-		fmode = nfs_type2fmt[type].mode;
-                dprintk("read_attrs: type=%d\n", (uint32_t)nfp->type);
-        }
-        if (bmval0 & FATTR4_WORD0_CHANGE) {
-                READ_BUF(8);
-                len += 8;
-                READ64(nfp->change_attr);
-                dprintk("read_attrs: changeid=%Ld\n", (long long)nfp->change_attr);
-        }
-        if (bmval0 & FATTR4_WORD0_SIZE) {
-                READ_BUF(8);
-                len += 8;
-                READ64(nfp->size);
-                dprintk("read_attrs: size=%Ld\n", (long long)nfp->size);
-        }
-        if (bmval0 & FATTR4_WORD0_FSID) {
-                READ_BUF(16);
-                len += 16;
-                READ64(nfp->fsid_u.nfs4.major);
-                READ64(nfp->fsid_u.nfs4.minor);
-                dprintk("read_attrs: fsid=0x%Lx/0x%Lx\n",
-			(long long)nfp->fsid_u.nfs4.major,
-			(long long)nfp->fsid_u.nfs4.minor);
-        }
-        if (bmval0 & FATTR4_WORD0_FILEID) {
-                READ_BUF(8);
-                len += 8;
-                READ64(nfp->fileid);
-                dprintk("read_attrs: fileid=%Ld\n", (long long) nfp->fileid);
-        }
-	if (bmval0 & FATTR4_WORD0_FILES_AVAIL) {
-		READ_BUF(8);
-		len += 8;
-		READ64(fsstat->afiles);
-		dprintk("read_attrs: files_avail=0x%Lx\n", (long long) fsstat->afiles);
-	}
-        if (bmval0 & FATTR4_WORD0_FILES_FREE) {
-                READ_BUF(8);
-                len += 8;
-                READ64(fsstat->ffiles);
-                dprintk("read_attrs: files_free=0x%Lx\n", (long long) fsstat->ffiles);
-        }
-        if (bmval0 & FATTR4_WORD0_FILES_TOTAL) {
-                READ_BUF(8);
-                len += 8;
-                READ64(fsstat->tfiles);
-                dprintk("read_attrs: files_tot=0x%Lx\n", (long long) fsstat->tfiles);
-        }
-	if (bmval0 & FATTR4_WORD0_MAXLINK) {
-		READ_BUF(4);
-		len += 4;
-		READ32(pathconf->max_link);
-		dprintk("read_attrs: maxlink=%d\n", pathconf->max_link);
-	}
-        if (bmval0 & FATTR4_WORD0_MAXNAME) {
-                READ_BUF(4);
-                len += 4;
-                READ32(pathconf->max_namelen);
-                dprintk("read_attrs: maxname=%d\n", pathconf->max_namelen);
-        }
-	
-        if (bmval1 & FATTR4_WORD1_MODE) {
-                READ_BUF(4);
-                len += 4;
-                READ32(dummy32);
-		nfp->mode = (dummy32 & ~S_IFMT) | fmode;
-                dprintk("read_attrs: mode=0%o\n", nfp->mode);
-        }
-        if (bmval1 & FATTR4_WORD1_NUMLINKS) {
-                READ_BUF(4);
-                len += 4;
-                READ32(nfp->nlink);
-                dprintk("read_attrs: nlinks=0%o\n", nfp->nlink);
-        }
-        if (bmval1 & FATTR4_WORD1_OWNER) {
-                READ_BUF(4);
-		len += 4;
-		READ32(dummy32);    /* name length */
-		if (dummy32 > XDR_MAX_NETOBJ) {
-			dprintk("read_attrs: name too long!\n");
-			goto xdr_error;
-		}
-		READ_BUF(dummy32);
-		len += (XDR_QUADLEN(dummy32) << 2);
-		if ((status = nfs_map_name_to_uid(server->nfs4_state, (char *)p, dummy32,
-						&nfp->uid)) < 0) {
-			dprintk("read_attrs: name-to-uid mapping failed!\n");
-			nfp->uid = -2;
-		}
-		dprintk("read_attrs: uid=%d\n", (int)nfp->uid);
-        }
-        if (bmval1 & FATTR4_WORD1_OWNER_GROUP) {
-                READ_BUF(4);
-		len += 4;
-		READ32(dummy32);
-		if (dummy32 > XDR_MAX_NETOBJ) {
-			dprintk("read_attrs: name too long!\n");
-			goto xdr_error;
-		}
-		READ_BUF(dummy32);
-		len += (XDR_QUADLEN(dummy32) << 2);
-		if ((status = nfs_map_group_to_gid(server->nfs4_state, (char *)p, dummy32,
-						&nfp->gid)) < 0) {
-			dprintk("read_attrs: group-to-gid mapping failed!\n");
-			nfp->gid = -2;
-		}
-		dprintk("read_attrs: gid=%d\n", (int)nfp->gid);
-        }
-        if (bmval1 & FATTR4_WORD1_RAWDEV) {
-		uint32_t major, minor;
+	if ((status = decode_attr_files_avail(xdr, bitmap, &fsstat->afiles)) != 0)
+		goto xdr_error;
+	if ((status = decode_attr_files_free(xdr, bitmap, &fsstat->ffiles)) != 0)
+		goto xdr_error;
+	if ((status = decode_attr_files_total(xdr, bitmap, &fsstat->tfiles)) != 0)
+		goto xdr_error;
+	if ((status = decode_attr_space_avail(xdr, bitmap, &fsstat->abytes)) != 0)
+		goto xdr_error;
+	if ((status = decode_attr_space_free(xdr, bitmap, &fsstat->fbytes)) != 0)
+		goto xdr_error;
+	if ((status = decode_attr_space_total(xdr, bitmap, &fsstat->tbytes)) != 0)
+		goto xdr_error;
 
-		READ_BUF(8);
-		len += 8;
-		READ32(major);
-		READ32(minor);
-		nfp->rdev = MKDEV(major, minor);
-		if (MAJOR(nfp->rdev) != major || MINOR(nfp->rdev) != minor)
-			nfp->rdev = 0;
-		dprintk("read_attrs: rdev=%u:%u\n", major, minor);
-        }
-        if (bmval1 & FATTR4_WORD1_SPACE_AVAIL) {
-                READ_BUF(8);
-                len += 8;
-                READ64(fsstat->abytes);
-                dprintk("read_attrs: savail=0x%Lx\n", (long long) fsstat->abytes);
-        }
-	if (bmval1 & FATTR4_WORD1_SPACE_FREE) {
-                READ_BUF(8);
-                len += 8;
-                READ64(fsstat->fbytes);
-                dprintk("read_attrs: sfree=0x%Lx\n", (long long) fsstat->fbytes);
-        }
-        if (bmval1 & FATTR4_WORD1_SPACE_TOTAL) {
-                READ_BUF(8);
-                len += 8;
-                READ64(fsstat->tbytes);
-                dprintk("read_attrs: stotal=0x%Lx\n", (long long) fsstat->tbytes);
-        }
-        if (bmval1 & FATTR4_WORD1_SPACE_USED) {
-                READ_BUF(8);
-                len += 8;
-                READ64(nfp->du.nfs3.used);
-                dprintk("read_attrs: sused=0x%Lx\n", (long long) nfp->du.nfs3.used);
-        }
-        if (bmval1 & FATTR4_WORD1_TIME_ACCESS) {
-                READ_BUF(12);
-                len += 12;
-                READTIME(nfp->atime);
-                dprintk("read_attrs: atime=%ld\n", (long)nfp->atime.tv_sec);
-        }
-        if (bmval1 & FATTR4_WORD1_TIME_METADATA) {
-                READ_BUF(12);
-                len += 12;
-                READTIME(nfp->ctime);
-                dprintk("read_attrs: ctime=%ld\n", (long)nfp->ctime.tv_sec);
-        }
-        if (bmval1 & FATTR4_WORD1_TIME_MODIFY) {
-                READ_BUF(12);
-                len += 12;
-                READTIME(nfp->mtime);
-                dprintk("read_attrs: mtime=%ld\n", (long)nfp->mtime.tv_sec);
-        }
-        if (len != attrlen)
-                goto xdr_error;
-	
-        DECODE_TAIL;
+	status = verify_attr_len(xdr, savep, attrlen);
+xdr_error:
+	if (status != 0)
+		printk(KERN_NOTICE "%s: xdr error %d!\n", __FUNCTION__, -status);
+	return status;
 }
 
-static int
-decode_change_attr(struct xdr_stream *xdr, uint64_t *change_attr)
+static int decode_pathconf(struct xdr_stream *xdr, struct nfs_pathconf *pathconf)
 {
-	uint32_t *p;
-	uint32_t attrlen, bmlen, bmval = 0;
+	uint32_t *savep;
+	uint32_t attrlen,
+		 bitmap[2] = {0};
 	int status;
 
-	status = decode_op_hdr(xdr, OP_GETATTR);
-	if (status)
-		return status;
-	READ_BUF(4);
-	READ32(bmlen);
-	if (bmlen < 1)
-		return -EIO;
-	READ_BUF(bmlen << 2);
-	READ32(bmval);
-	if (bmval != FATTR4_WORD0_CHANGE) {
-		printk(KERN_NOTICE "decode_change_attr: server returned bad attribute bitmap 0x%x\n",
-			(unsigned int)bmval);
-		return -EIO;
-	}
-	READ_BUF(4);
-	READ32(attrlen);
-	READ_BUF(attrlen);
-	if (attrlen < 8) {
-		printk(KERN_NOTICE "decode_change_attr: server returned bad attribute length %u\n",
-				(unsigned int)attrlen);
-		return -EIO;
-	}
-	READ64(*change_attr);
-	return 0;
-}
+	if ((status = decode_op_hdr(xdr, OP_GETATTR)) != 0)
+		goto xdr_error;
+	if ((status = decode_attr_bitmap(xdr, bitmap)) != 0)
+		goto xdr_error;
+	if ((status = decode_attr_length(xdr, &attrlen, &savep)) != 0)
+		goto xdr_error;
 
-static int
-decode_read_getattr(struct xdr_stream *xdr, struct nfs_fattr *fattr)
-{
-	uint32_t *p;
-	uint32_t attrlen, bmlen, bmval0 = 0, bmval1 = 0;
-	int status;
+	if ((status = decode_attr_maxlink(xdr, bitmap, &pathconf->max_link)) != 0)
+		goto xdr_error;
+	if ((status = decode_attr_maxname(xdr, bitmap, &pathconf->max_namelen)) != 0)
+		goto xdr_error;
 
-	status = decode_op_hdr(xdr, OP_GETATTR);
-	if (status)
-		return status;
-	READ_BUF(4);
-	READ32(bmlen);
-	if (bmlen < 1)
-		return -EIO;
-	READ_BUF(bmlen << 2);
-	READ32(bmval0);
-	if (bmval0 != FATTR4_WORD0_CHANGE)
-		goto out_bad_bitmap;
-	if (bmlen > 1) {
-		READ32(bmval1);
-		if (bmval1 & ~(FATTR4_WORD1_TIME_ACCESS))
-			goto out_bad_bitmap;
-	}
-	READ_BUF(4);
-	READ32(attrlen);
-	READ_BUF(attrlen);
-	if (attrlen < 16) {
-		printk(KERN_NOTICE "decode_post_write_getattr: server returned bad attribute length %u\n",
-				(unsigned int)attrlen);
-		return -EIO;
-	}
-	READ64(fattr->change_attr);
-	if (bmval1 & FATTR4_WORD1_TIME_ACCESS)
-		READTIME(fattr->atime);
-	fattr->bitmap[0] = bmval0;
-	fattr->bitmap[1] = bmval1;
-	return 0;
-out_bad_bitmap:
-	printk(KERN_NOTICE "decode_read_getattr: server returned bad attribute bitmap 0x%x/0x%x\n",
-			(unsigned int)bmval0, (unsigned int)bmval1);
-	return -EIO;
+	status = verify_attr_len(xdr, savep, attrlen);
+xdr_error:
+	if (status != 0)
+		printk(KERN_NOTICE "%s: xdr error %d!\n", __FUNCTION__, -status);
+	return status;
 }
 
-static int
-decode_pre_write_getattr(struct xdr_stream *xdr, struct nfs_fattr *fattr)
+static int decode_getfattr(struct xdr_stream *xdr, struct nfs_fattr *fattr, const struct nfs_server *server)
 {
-	return decode_change_attr(xdr, &fattr->pre_change_attr);
-}
+	uint32_t *savep;
+	uint32_t attrlen,
+		 bitmap[2] = {0},
+		 type;
+	int status, fmode = 0;
 
-static int
-decode_post_write_getattr(struct xdr_stream *xdr, struct nfs_fattr *fattr)
-{
-	uint32_t *p;
-	uint32_t attrlen, bmlen, bmval0 = 0, bmval1 = 0;
-	int status;
+	if ((status = decode_op_hdr(xdr, OP_GETATTR)) != 0)
+		goto xdr_error;
+	if ((status = decode_attr_bitmap(xdr, bitmap)) != 0)
+		goto xdr_error;
 
-	status = decode_op_hdr(xdr, OP_GETATTR);
-	if (status)
-		return status;
-	READ_BUF(4);
-	READ32(bmlen);
-	if (bmlen < 1)
-		return -EIO;
-	READ_BUF(bmlen << 2);
-	READ32(bmval0);
-	if (bmval0 != (FATTR4_WORD0_CHANGE|FATTR4_WORD0_SIZE))
-		goto out_bad_bitmap;
-	if (bmlen > 1) {
-		READ32(bmval1);
-		if (bmval1 & ~(FATTR4_WORD1_SPACE_USED |
-					FATTR4_WORD1_TIME_METADATA |
-					FATTR4_WORD1_TIME_MODIFY))
-			goto out_bad_bitmap;
+	fattr->bitmap[0] = bitmap[0];
+	fattr->bitmap[1] = bitmap[1];
+
+	if ((status = decode_attr_length(xdr, &attrlen, &savep)) != 0)
+		goto xdr_error;
+
+
+	if ((status = decode_attr_type(xdr, bitmap, &type)) != 0)
+		goto xdr_error;
+	fattr->type = nfs_type2fmt[type].nfs2type;
+	fmode = nfs_type2fmt[type].mode;
+
+	if ((status = decode_attr_change(xdr, bitmap, &fattr->change_attr)) != 0)
+		goto xdr_error;
+	if ((status = decode_attr_size(xdr, bitmap, &fattr->size)) != 0)
+		goto xdr_error;
+	if ((status = decode_attr_fsid(xdr, bitmap, &fattr->fsid_u.nfs4)) != 0)
+		goto xdr_error;
+	if ((status = decode_attr_fileid(xdr, bitmap, &fattr->fileid)) != 0)
+		goto xdr_error;
+	if ((status = decode_attr_mode(xdr, bitmap, &fattr->mode)) != 0)
+		goto xdr_error;
+	fattr->mode |= fmode;
+	if ((status = decode_attr_nlink(xdr, bitmap, &fattr->nlink)) != 0)
+		goto xdr_error;
+	if ((status = decode_attr_owner(xdr, bitmap, server->nfs4_state, &fattr->uid)) != 0)
+		goto xdr_error;
+	if ((status = decode_attr_group(xdr, bitmap, server->nfs4_state, &fattr->gid)) != 0)
+		goto xdr_error;
+	if ((status = decode_attr_rdev(xdr, bitmap, &fattr->rdev)) != 0)
+		goto xdr_error;
+	if ((status = decode_attr_space_used(xdr, bitmap, &fattr->du.nfs3.used)) != 0)
+		goto xdr_error;
+	if ((status = decode_attr_time_access(xdr, bitmap, &fattr->atime)) != 0)
+		goto xdr_error;
+	if ((status = decode_attr_time_metadata(xdr, bitmap, &fattr->ctime)) != 0)
+		goto xdr_error;
+	if ((status = decode_attr_time_modify(xdr, bitmap, &fattr->mtime)) != 0)
+		goto xdr_error;
+	if ((status = verify_attr_len(xdr, savep, attrlen)) == 0) {
+		fattr->valid = NFS_ATTR_FATTR | NFS_ATTR_FATTR_V3 | NFS_ATTR_FATTR_V4;
+		fattr->timestamp = jiffies;
 	}
-	READ_BUF(4);
-	READ32(attrlen);
-	READ_BUF(attrlen);
-	if (attrlen < 16) {
-		printk(KERN_NOTICE "decode_post_write_getattr: server returned bad attribute length %u\n",
-				(unsigned int)attrlen);
-		return -EIO;
-	}
-	READ64(fattr->change_attr);
-	READ64(fattr->size);
-	if (bmval1 & FATTR4_WORD1_SPACE_USED)
-		READ64(fattr->du.nfs3.used);
-	if (bmval1 & FATTR4_WORD1_TIME_METADATA)
-		READTIME(fattr->ctime);
-	if (bmval1 & FATTR4_WORD1_TIME_MODIFY)
-		READTIME(fattr->mtime);
-	fattr->bitmap[0] = bmval0;
-	fattr->bitmap[1] = bmval1;
-	return 0;
-out_bad_bitmap:
-	printk(KERN_NOTICE "decode_post_write_getattr: server returned bad attribute bitmap 0x%x/0x%x\n",
-			(unsigned int)bmval0, (unsigned int)bmval1);
-	return -EIO;
+xdr_error:
+	if (status != 0)
+		printk(KERN_NOTICE "%s: xdr error %d!\n", __FUNCTION__, -status);
+	return status;
 }
 
 
-static int
-decode_fsinfo(struct xdr_stream *xdr, struct nfs_fsinfo *fsinfo)
+static int decode_fsinfo(struct xdr_stream *xdr, struct nfs_fsinfo *fsinfo)
 {
-	uint32_t *p;
-	uint32_t len, attrlen, bmlen, bmval0 = 0, bmval1 = 0;
+	uint32_t *savep;
+	uint32_t attrlen, bitmap[2];
 	int status;
 
-	status = decode_op_hdr(xdr, OP_GETATTR);
-	if (status)
-		return status;
-	READ_BUF(4);
-	READ32(bmlen);
-	if (bmlen < 1)
-		return -EIO;
-	READ_BUF(bmlen << 2);
-	READ32(bmval0);
-	if (bmval0 & ~(FATTR4_WORD0_MAXFILESIZE|FATTR4_WORD0_MAXREAD|
-				FATTR4_WORD0_MAXWRITE|FATTR4_WORD0_LEASE_TIME))
-		goto out_bad_bitmap;
-	if (bmlen > 1) {
-		READ32(bmval1);
-		if (bmval1 != 0 || bmlen > 2)
-			goto out_bad_bitmap;
-	}
-	READ_BUF(4);
-	READ32(attrlen);
-	READ_BUF(attrlen);
+	if ((status = decode_op_hdr(xdr, OP_GETATTR)) != 0)
+		goto xdr_error;
+	if ((status = decode_attr_bitmap(xdr, bitmap)) != 0)
+		goto xdr_error;
+	if ((status = decode_attr_length(xdr, &attrlen, &savep)) != 0)
+		goto xdr_error;
+
 	fsinfo->rtmult = fsinfo->wtmult = 512;	/* ??? */
-	fsinfo->lease_time = 60;
-	len = attrlen;
 
-	if (bmval0 & FATTR4_WORD0_LEASE_TIME) {
-		len -= 4;
-		READ32(fsinfo->lease_time);
-		dprintk("read_attrs: lease_time=%d\n", fsinfo->lease_time);
-	}
-	if (bmval0 & FATTR4_WORD0_MAXFILESIZE) {
-		len -= 8;
-		READ64(fsinfo->maxfilesize);
-		dprintk("read_attrs: maxfilesize=0x%Lx\n", (long long) fsinfo->maxfilesize);
-	}
-	if (bmval0 & FATTR4_WORD0_MAXREAD) {
-		len -= 8;
-		READ64(fsinfo->rtmax);
-		fsinfo->rtpref = fsinfo->dtpref = fsinfo->rtmax;
-		dprintk("read_attrs: maxread=%d\n", fsinfo->rtmax);
-	}
-	if (bmval0 & FATTR4_WORD0_MAXWRITE) {
-		len -= 8;
-		READ64(fsinfo->wtmax);
-		fsinfo->wtpref = fsinfo->wtmax;
-		dprintk("read_attrs: maxwrite=%d\n", fsinfo->wtmax);
-	}
-	if (len != 0)
-		goto out_bad_attrlen;
-	return 0;
-out_bad_attrlen:
-	printk(KERN_NOTICE "%s: server attribute length %u does not match bitmap 0x%x/0x%x\n",
-			__FUNCTION__, (unsigned int)attrlen,
-			(unsigned int) bmval0, (unsigned int)bmval1);
-	return -EIO;
-out_bad_bitmap:
-	printk(KERN_NOTICE "%s: server returned bad attribute bitmap 0x%x/0x%x\n",
-			__FUNCTION__,
-			(unsigned int)bmval0, (unsigned int)bmval1);
-	return -EIO;
+	if ((status = decode_attr_lease_time(xdr, bitmap, &fsinfo->lease_time)) != 0)
+		goto xdr_error;
+	if ((status = decode_attr_maxfilesize(xdr, bitmap, &fsinfo->maxfilesize)) != 0)
+		goto xdr_error;
+	if ((status = decode_attr_maxread(xdr, bitmap, &fsinfo->rtmax)) != 0)
+		goto xdr_error;
+	fsinfo->rtpref = fsinfo->dtpref = fsinfo->rtmax;
+	if ((status = decode_attr_maxwrite(xdr, bitmap, &fsinfo->wtmax)) != 0)
+		goto xdr_error;
+	fsinfo->wtpref = fsinfo->wtmax;
+
+	status = verify_attr_len(xdr, savep, attrlen);
+xdr_error:
+	if (status != 0)
+		printk(KERN_NOTICE "%s: xdr error %d!\n", __FUNCTION__, -status);
+	return status;
 }
 
-static int
-decode_getfh(struct xdr_stream *xdr, struct nfs4_getfh *getfh)
+static int decode_getfh(struct xdr_stream *xdr, struct nfs_fh *fh)
 {
-	struct nfs_fh *fh = getfh->gf_fhandle;
 	uint32_t *p;
 	uint32_t len;
 	int status;
@@ -2173,7 +2641,7 @@ decode_getfh(struct xdr_stream *xdr, str
 
 	READ_BUF(4);
 	READ32(len);
-	if (len > NFS_MAXFHSIZE)
+	if (len > NFS4_FHSIZE)
 		return -EIO;
 	fh->size = len;
 	READ_BUF(len);
@@ -2181,22 +2649,20 @@ decode_getfh(struct xdr_stream *xdr, str
 	return 0;
 }
 
-static int
-decode_link(struct xdr_stream *xdr, struct nfs4_link *link)
+static int decode_link(struct xdr_stream *xdr, struct nfs4_change_info *cinfo)
 {
 	int status;
 	
 	status = decode_op_hdr(xdr, OP_LINK);
 	if (status)
 		return status;
-	return decode_change_info(xdr, link->ln_cinfo);
+	return decode_change_info(xdr, cinfo);
 }
 
 /*
  * We create the owner, so we know a proper owner.id length is 4.
  */
-static int
-decode_lock_denied (struct xdr_stream *xdr, struct nfs_lock_denied *denied)
+static int decode_lock_denied (struct xdr_stream *xdr, struct nfs_lock_denied *denied)
 {
 	uint32_t *p;
 	uint32_t namelen;
@@ -2213,8 +2679,7 @@ decode_lock_denied (struct xdr_stream *x
 	return -NFS4ERR_DENIED;
 }
 
-static int
-decode_lock(struct xdr_stream *xdr, struct nfs_lockres *res)
+static int decode_lock(struct xdr_stream *xdr, struct nfs_lockres *res)
 {
 	uint32_t *p;
 	int status;
@@ -2228,8 +2693,7 @@ decode_lock(struct xdr_stream *xdr, stru
 	return status;
 }
 
-static int
-decode_lockt(struct xdr_stream *xdr, struct nfs_lockres *res)
+static int decode_lockt(struct xdr_stream *xdr, struct nfs_lockres *res)
 {
 	int status;
 	status = decode_op_hdr(xdr, OP_LOCKT);
@@ -2238,8 +2702,7 @@ decode_lockt(struct xdr_stream *xdr, str
 	return status;
 }
 
-static int
-decode_locku(struct xdr_stream *xdr, struct nfs_lockres *res)
+static int decode_locku(struct xdr_stream *xdr, struct nfs_lockres *res)
 {
 	uint32_t *p;
 	int status;
@@ -2252,14 +2715,12 @@ decode_locku(struct xdr_stream *xdr, str
 	return status;
 }
 
-static int
-decode_lookup(struct xdr_stream *xdr)
+static int decode_lookup(struct xdr_stream *xdr)
 {
 	return decode_op_hdr(xdr, OP_LOOKUP);
 }
 
-static int
-decode_open(struct xdr_stream *xdr, struct nfs_openres *res)
+static int decode_open(struct xdr_stream *xdr, struct nfs_openres *res)
 {
         uint32_t *p;
         uint32_t bmlen, delegation_type;
@@ -2271,7 +2732,7 @@ decode_open(struct xdr_stream *xdr, stru
         READ_BUF(sizeof(res->stateid.data));
         COPYMEM(res->stateid.data, sizeof(res->stateid.data));
 
-        decode_change_info(xdr, res->cinfo);
+        decode_change_info(xdr, &res->cinfo);
 
         READ_BUF(8);
         READ32(res->rflags);
@@ -2282,14 +2743,14 @@ decode_open(struct xdr_stream *xdr, stru
         READ_BUF((bmlen << 2) + 4);
         p += bmlen;
         READ32(delegation_type);
-        if (delegation_type != NFS4_OPEN_DELEGATE_NONE)
-                goto xdr_error;
-
-        DECODE_TAIL;
+        if (delegation_type == NFS4_OPEN_DELEGATE_NONE)
+		return 0;
+xdr_error:
+	printk(KERN_NOTICE "%s: xdr error!\n", __FUNCTION__);
+	return -EIO;
 }
 
-static int
-decode_open_confirm(struct xdr_stream *xdr, struct nfs_open_confirmres *res)
+static int decode_open_confirm(struct xdr_stream *xdr, struct nfs_open_confirmres *res)
 {
         uint32_t *p;
 	int status;
@@ -2302,8 +2763,7 @@ decode_open_confirm(struct xdr_stream *x
         return 0;
 }
 
-static int
-decode_open_downgrade(struct xdr_stream *xdr, struct nfs_closeres *res)
+static int decode_open_downgrade(struct xdr_stream *xdr, struct nfs_closeres *res)
 {
 	uint32_t *p;
 	int status;
@@ -2316,22 +2776,19 @@ decode_open_downgrade(struct xdr_stream 
 	return 0;
 }
 
-static int
-decode_putfh(struct xdr_stream *xdr)
+static int decode_putfh(struct xdr_stream *xdr)
 {
 	return decode_op_hdr(xdr, OP_PUTFH);
 }
 
-static int
-decode_putrootfh(struct xdr_stream *xdr)
+static int decode_putrootfh(struct xdr_stream *xdr)
 {
 	return decode_op_hdr(xdr, OP_PUTROOTFH);
 }
 
-static int
-decode_read(struct xdr_stream *xdr, struct rpc_rqst *req, struct nfs_readres *res)
+static int decode_read(struct xdr_stream *xdr, struct rpc_rqst *req, struct nfs_readres *res)
 {
-	struct iovec *iov = req->rq_rvec;
+	struct iovec *iov = req->rq_rcv_buf.head;
 	uint32_t *p;
 	uint32_t count, eof, recvd, hdrlen;
 	int status;
@@ -2343,7 +2800,7 @@ decode_read(struct xdr_stream *xdr, stru
 	READ32(eof);
 	READ32(count);
 	hdrlen = (u8 *) p - (u8 *) iov->iov_base;
-	recvd = req->rq_received - hdrlen;
+	recvd = req->rq_rcv_buf.len - hdrlen;
 	if (count > recvd) {
 		printk(KERN_WARNING "NFS: server cheating in read reply: "
 				"count %u > recvd %u\n", count, recvd);
@@ -2356,8 +2813,7 @@ decode_read(struct xdr_stream *xdr, stru
 	return 0;
 }
 
-static int
-decode_readdir(struct xdr_stream *xdr, struct rpc_rqst *req, struct nfs4_readdir *readdir)
+static int decode_readdir(struct xdr_stream *xdr, struct rpc_rqst *req, struct nfs4_readdir_res *readdir)
 {
 	struct xdr_buf	*rcvbuf = &req->rq_rcv_buf;
 	struct page	*page = *rcvbuf->pages;
@@ -2371,17 +2827,17 @@ decode_readdir(struct xdr_stream *xdr, s
 	if (status)
 		return status;
 	READ_BUF(8);
-	COPYMEM(readdir->rd_resp_verifier.data, 8);
+	COPYMEM(readdir->verifier.data, 8);
 
 	hdrlen = (char *) p - (char *) iov->iov_base;
-	recvd = req->rq_received - hdrlen;
+	recvd = rcvbuf->len - hdrlen;
 	if (pglen > recvd)
 		pglen = recvd;
 	xdr_read_pages(xdr, pglen);
 
-	BUG_ON(pglen + readdir->rd_pgbase > PAGE_CACHE_SIZE);
+	BUG_ON(pglen + readdir->pgbase > PAGE_CACHE_SIZE);
 	kaddr = p = (uint32_t *) kmap_atomic(page, KM_USER0);
-	end = (uint32_t *) ((char *)p + pglen + readdir->rd_pgbase);
+	end = (uint32_t *) ((char *)p + pglen + readdir->pgbase);
 	entry = p;
 	for (nr = 0; *p++; nr++) {
 		if (p + 3 > end)
@@ -2441,8 +2897,7 @@ err_unmap:
 	return -errno_NFSERR_IO;
 }
 
-static int
-decode_readlink(struct xdr_stream *xdr, struct rpc_rqst *req, struct nfs4_readlink *readlink)
+static int decode_readlink(struct xdr_stream *xdr, struct rpc_rqst *req)
 {
 	struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
 	struct iovec *iov = rcvbuf->head;
@@ -2483,43 +2938,34 @@ decode_readlink(struct xdr_stream *xdr, 
 	return 0;
 }
 
-static int
-decode_restorefh(struct xdr_stream *xdr)
-{
-	return decode_op_hdr(xdr, OP_RESTOREFH);
-}
-
-static int
-decode_remove(struct xdr_stream *xdr, struct nfs4_remove *remove)
+static int decode_remove(struct xdr_stream *xdr, struct nfs4_change_info *cinfo)
 {
 	int status;
 
 	status = decode_op_hdr(xdr, OP_REMOVE);
 	if (status)
 		goto out;
-	status = decode_change_info(xdr, remove->rm_cinfo);
+	status = decode_change_info(xdr, cinfo);
 out:
 	return status;
 }
 
-static int
-decode_rename(struct xdr_stream *xdr, struct nfs4_rename *rename)
+static int decode_rename(struct xdr_stream *xdr, struct nfs4_change_info *old_cinfo,
+	      struct nfs4_change_info *new_cinfo)
 {
 	int status;
 
 	status = decode_op_hdr(xdr, OP_RENAME);
 	if (status)
 		goto out;
-	if ((status = decode_change_info(xdr, rename->rn_src_cinfo)))
-		goto out;
-	if ((status = decode_change_info(xdr, rename->rn_dst_cinfo)))
+	if ((status = decode_change_info(xdr, old_cinfo)))
 		goto out;
+	status = decode_change_info(xdr, new_cinfo);
 out:
 	return status;
 }
 
-static int
-decode_renew(struct xdr_stream *xdr)
+static int decode_renew(struct xdr_stream *xdr)
 {
 	return decode_op_hdr(xdr, OP_RENEW);
 }
@@ -2530,8 +2976,7 @@ decode_savefh(struct xdr_stream *xdr)
 	return decode_op_hdr(xdr, OP_SAVEFH);
 }
 
-static int
-decode_setattr(struct xdr_stream *xdr, struct nfs_setattrres *res)
+static int decode_setattr(struct xdr_stream *xdr, struct nfs_setattrres *res)
 {
 	uint32_t *p;
 	uint32_t bmlen;
@@ -2547,8 +2992,7 @@ decode_setattr(struct xdr_stream *xdr, s
 	return 0;
 }
 
-static int
-decode_setclientid(struct xdr_stream *xdr, struct nfs4_client *clp)
+static int decode_setclientid(struct xdr_stream *xdr, struct nfs4_client *clp)
 {
 	uint32_t *p;
 	uint32_t opnum;
@@ -2579,124 +3023,38 @@ decode_setclientid(struct xdr_stream *xd
 		READ_BUF(4);
 		READ32(len);
 		READ_BUF(len);
-		return -EEXIST;
-	} else
-		return -nfs_stat_to_errno(nfserr);
-
-	return 0;
-}
-
-static int
-decode_setclientid_confirm(struct xdr_stream *xdr)
-{
-	return decode_op_hdr(xdr, OP_SETCLIENTID_CONFIRM);
-}
-
-static int
-decode_write(struct xdr_stream *xdr, struct nfs_writeres *res)
-{
-	uint32_t *p;
-	int status;
-
-	status = decode_op_hdr(xdr, OP_WRITE);
-	if (status)
-		return status;
-
-	READ_BUF(16);
-	READ32(res->count);
-	READ32(res->verf->committed);
-	COPYMEM(res->verf->verifier, 8);
-	return 0;
-}
-
-/* FIXME: this sucks */
-static int
-decode_compound(struct xdr_stream *xdr, struct nfs4_compound *cp, struct rpc_rqst *req)
-{
-	struct compound_hdr hdr;
-	struct nfs4_op *op;
-	int status;
-
-	status = decode_compound_hdr(xdr, &hdr);
-	if (status)
-		goto out;
-
-	cp->toplevel_status = hdr.status;
-
-	/*
-	 * We need this if our zero-copy I/O is going to work.  Rumor has
-	 * it that the spec will soon mandate it...
-	 */
-	if (hdr.taglen != cp->taglen)
-		dprintk("nfs4: non-conforming server returns tag length mismatch!\n");
-
-	cp->resp_nops = hdr.nops;
-	if (hdr.nops > cp->req_nops) {
-		dprintk("nfs4: resp_nops > req_nops!\n");
-		goto xdr_error;
-	}
-
-	op = &cp->ops[0];
-	for (cp->nops = 0; cp->nops < cp->resp_nops; cp->nops++, op++) {
-		switch (op->opnum) {
-		case OP_ACCESS:
-			status = decode_access(xdr, &op->u.access);
-			break;
-		case OP_CREATE:
-			status = decode_create(xdr, &op->u.create);
-			break;
-		case OP_GETATTR:
-			status = decode_getattr(xdr, &op->u.getattr, cp->server);
-			break;
-		case OP_GETFH:
-			status = decode_getfh(xdr, &op->u.getfh);
-			break;
-		case OP_LINK:
-			status = decode_link(xdr, &op->u.link);
-			break;
-		case OP_LOOKUP:
-			status = decode_lookup(xdr);
-			break;
-		case OP_PUTFH:
-			status = decode_putfh(xdr);
-			break;
-		case OP_PUTROOTFH:
-			status = decode_putrootfh(xdr);
-			break;
-		case OP_READDIR:
-			status = decode_readdir(xdr, req, &op->u.readdir);
-			break;
-		case OP_READLINK:
-			status = decode_readlink(xdr, req, &op->u.readlink);
-			break;
-		case OP_RESTOREFH:
-			status = decode_restorefh(xdr);
-			break;
-		case OP_REMOVE:
-			status = decode_remove(xdr, &op->u.remove);
-			break;
-		case OP_RENAME:
-			status = decode_rename(xdr, &op->u.rename);
-			break;
-		case OP_SAVEFH:
-			status = decode_savefh(xdr);
-			break;
-		default:
-			BUG();
-			return -EIO;
-		}
-		if (status)
-			break;
-	}
+		return -EEXIST;
+	} else
+		return -nfs_stat_to_errno(nfserr);
+
+	return 0;
+}
+
+static int decode_setclientid_confirm(struct xdr_stream *xdr)
+{
+	return decode_op_hdr(xdr, OP_SETCLIENTID_CONFIRM);
+}
+
+static int decode_write(struct xdr_stream *xdr, struct nfs_writeres *res)
+{
+	uint32_t *p;
+	int status;
+
+	status = decode_op_hdr(xdr, OP_WRITE);
+	if (status)
+		return status;
 
-	DECODE_TAIL;
+	READ_BUF(16);
+	READ32(res->count);
+	READ32(res->verf->committed);
+	COPYMEM(res->verf->verifier, 8);
+	return 0;
 }
 
 /*
  * Decode OPEN_DOWNGRADE response
  */
-static int
-nfs4_xdr_dec_open_downgrade(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_closeres *res)
+static int nfs4_xdr_dec_open_downgrade(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_closeres *res)
 {
         struct xdr_stream xdr;
         struct compound_hdr hdr;
@@ -2719,31 +3077,180 @@ out:
  */
 
 /*
- * Decode COMPOUND response
+ * Decode ACCESS response
  */
-static int
-nfs4_xdr_dec_compound(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_compound *cp)
+static int nfs4_xdr_dec_access(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_accessres *res)
+{
+	struct xdr_stream xdr;
+	struct compound_hdr hdr;
+	int status;
+
+	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
+	if ((status = decode_compound_hdr(&xdr, &hdr)) != 0)
+		goto out;
+	if ((status = decode_putfh(&xdr)) == 0)
+		status = decode_access(&xdr, res);
+out:
+	return status;
+}
+
+/*
+ * Decode LOOKUP response
+ */
+static int nfs4_xdr_dec_lookup(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_lookup_res *res)
 {
 	struct xdr_stream xdr;
+	struct compound_hdr hdr;
 	int status;
 	
 	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
-	if ((status = decode_compound(&xdr, cp, rqstp)))
+	if ((status = decode_compound_hdr(&xdr, &hdr)) != 0)
+		goto out;
+	if ((status = decode_putfh(&xdr)) != 0)
 		goto out;
+	if ((status = decode_lookup(&xdr)) != 0)
+		goto out;
+	if ((status = decode_getfh(&xdr, res->fh)) != 0)
+		goto out;
+	status = decode_getfattr(&xdr, res->fattr, res->server);
+out:
+	return status;
+}
+
+/*
+ * Decode LOOKUP_ROOT response
+ */
+static int nfs4_xdr_dec_lookup_root(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_lookup_res *res)
+{
+	struct xdr_stream xdr;
+	struct compound_hdr hdr;
+	int status;
 	
-	status = 0;
-	if (cp->toplevel_status)
-		status = -nfs_stat_to_errno(cp->toplevel_status);
+	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
+	if ((status = decode_compound_hdr(&xdr, &hdr)) != 0)
+		goto out;
+	if ((status = decode_putrootfh(&xdr)) != 0)
+		goto out;
+	if ((status = decode_getfh(&xdr, res->fh)) == 0)
+		status = decode_getfattr(&xdr, res->fattr, res->server);
+out:
+	return status;
+}
+
+/*
+ * Decode REMOVE response
+ */
+static int nfs4_xdr_dec_remove(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_change_info *cinfo)
+{
+	struct xdr_stream xdr;
+	struct compound_hdr hdr;
+	int status;
+
+	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
+	if ((status = decode_compound_hdr(&xdr, &hdr)) != 0)
+		goto out;
+	if ((status = decode_putfh(&xdr)) == 0)
+		status = decode_remove(&xdr, cinfo);
+out:
+	return status;
+}
+
+/*
+ * Decode RENAME response
+ */
+static int nfs4_xdr_dec_rename(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_rename_res *res)
+{
+	struct xdr_stream xdr;
+	struct compound_hdr hdr;
+	int status;
+
+	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
+	if ((status = decode_compound_hdr(&xdr, &hdr)) != 0)
+		goto out;
+	if ((status = decode_putfh(&xdr)) != 0)
+		goto out;
+	if ((status = decode_savefh(&xdr)) != 0)
+		goto out;
+	if ((status = decode_putfh(&xdr)) != 0)
+		goto out;
+	status = decode_rename(&xdr, &res->old_cinfo, &res->new_cinfo);
+out:
+	return status;
+}
+
+/*
+ * Decode LINK response
+ */
+static int nfs4_xdr_dec_link(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_change_info *cinfo)
+{
+	struct xdr_stream xdr;
+	struct compound_hdr hdr;
+	int status;
+
+	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
+	if ((status = decode_compound_hdr(&xdr, &hdr)) != 0)
+		goto out;
+	if ((status = decode_putfh(&xdr)) != 0)
+		goto out;
+	if ((status = decode_savefh(&xdr)) != 0)
+		goto out;
+	if ((status = decode_putfh(&xdr)) != 0)
+		goto out;
+	status = decode_link(&xdr, cinfo);
+out:
+	return status;
+}
+
+/*
+ * Decode CREATE response
+ */
+static int nfs4_xdr_dec_create(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_create_res *res)
+{
+	struct xdr_stream xdr;
+	struct compound_hdr hdr;
+	int status;
+
+	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
+	if ((status = decode_compound_hdr(&xdr, &hdr)) != 0)
+		goto out;
+	if ((status = decode_putfh(&xdr)) != 0)
+		goto out;
+	if ((status = decode_create(&xdr,&res->dir_cinfo)) != 0)
+		goto out;
+	if ((status = decode_getfattr(&xdr, res->fattr, res->server)) != 0)
+		goto out;
+	status = decode_getfh(&xdr, res->fh);
+out:
+	return status;
+}
 
+/*
+ * Decode GETATTR response
+ */
+static int nfs4_xdr_dec_getattr(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_getattr_res *res)
+{
+	struct xdr_stream xdr;
+	struct compound_hdr hdr;
+	int status;
+
+	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
+	status = decode_compound_hdr(&xdr, &hdr);
+	if (status)
+		goto out;
+	status = decode_putfh(&xdr);
+	if (status)
+		goto out;
+	status = decode_getfattr(&xdr, res->fattr, res->server);
 out:
 	return status;
+
 }
 
+
 /*
  * Decode CLOSE response
  */
-static int
-nfs4_xdr_dec_close(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_closeres *res)
+static int nfs4_xdr_dec_close(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_closeres *res)
 {
         struct xdr_stream xdr;
         struct compound_hdr hdr;
@@ -2764,14 +3271,10 @@ out:
 /*
  * Decode OPEN response
  */
-static int
-nfs4_xdr_dec_open(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_openres *res)
+static int nfs4_xdr_dec_open(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_openres *res)
 {
         struct xdr_stream xdr;
         struct compound_hdr hdr;
-	struct nfs4_getfh gfh	= {
-		.gf_fhandle = &res->fh,
-	};
         int status;
 
         xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
@@ -2781,24 +3284,13 @@ nfs4_xdr_dec_open(struct rpc_rqst *rqstp
         status = decode_putfh(&xdr);
         if (status)
                 goto out;
-        status = decode_savefh(&xdr);
-        if (status)
-                goto out;
         status = decode_open(&xdr, res);
         if (status)
                 goto out;
-        status = decode_getattr(&xdr, res->f_getattr, res->server);
-        if (status)
-                goto out;
-        status = decode_getfh(&xdr, &gfh);
-        if (status)
-                goto out;
-        status = decode_restorefh(&xdr);
-        if (status)
-                goto out;
-        status = decode_getattr(&xdr, res->d_getattr, res->server);
+	status = decode_getfattr(&xdr, res->f_attr, res->server);
         if (status)
                 goto out;
+	status = decode_getfh(&xdr, &res->fh);
 out:
         return status;
 }
@@ -2806,8 +3298,7 @@ out:
 /*
  * Decode OPEN_CONFIRM response
  */
-static int
-nfs4_xdr_dec_open_confirm(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_open_confirmres *res)
+static int nfs4_xdr_dec_open_confirm(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_open_confirmres *res)
 {
         struct xdr_stream xdr;
         struct compound_hdr hdr;
@@ -2828,8 +3319,7 @@ out:
 /*
  * Decode OPEN_RECLAIM response
  */
-static int
-nfs4_xdr_dec_open_reclaim(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_openres *res)
+static int nfs4_xdr_dec_open_reclaim(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_openres *res)
 {
         struct xdr_stream xdr;
         struct compound_hdr hdr;
@@ -2845,7 +3335,7 @@ nfs4_xdr_dec_open_reclaim(struct rpc_rqs
         status = decode_open(&xdr, res);
         if (status)
                 goto out;
-        status = decode_getattr(&xdr, res->f_getattr, res->server);
+	status = decode_getfattr(&xdr, res->f_attr, res->server);
 out:
         return status;
 }
@@ -2853,8 +3343,7 @@ out:
 /*
  * Decode SETATTR response
  */
-static int
-nfs4_xdr_dec_setattr(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_setattrres *res)
+static int nfs4_xdr_dec_setattr(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_setattrres *res)
 {
         struct xdr_stream xdr;
         struct compound_hdr hdr;
@@ -2870,7 +3359,7 @@ nfs4_xdr_dec_setattr(struct rpc_rqst *rq
         status = decode_setattr(&xdr, res);
         if (status)
                 goto out;
-        status = decode_getattr(&xdr, res->attr, res->server);
+	status = decode_getfattr(&xdr, res->fattr, res->server);
 out:
         return status;
 }
@@ -2878,8 +3367,7 @@ out:
 /*
  * Decode LOCK response
  */
-static int
-nfs4_xdr_dec_lock(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_lockres *res)
+static int nfs4_xdr_dec_lock(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_lockres *res)
 {
 	struct xdr_stream xdr;
 	struct compound_hdr hdr;
@@ -2900,8 +3388,7 @@ out:
 /*
  * Decode LOCKT response
  */
-static int
-nfs4_xdr_dec_lockt(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_lockres *res)
+static int nfs4_xdr_dec_lockt(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_lockres *res)
 {
 	struct xdr_stream xdr;
 	struct compound_hdr hdr;
@@ -2922,8 +3409,7 @@ out:
 /*
  * Decode LOCKU response
  */
-static int
-nfs4_xdr_dec_locku(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_lockres *res)
+static int nfs4_xdr_dec_locku(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_lockres *res)
 {
 	struct xdr_stream xdr;
 	struct compound_hdr hdr;
@@ -2942,10 +3428,9 @@ out:
 }
 
 /*
- * Decode Read response
+ * Decode READLINK response
  */
-static int
-nfs4_xdr_dec_read(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_readres *res)
+static int nfs4_xdr_dec_readlink(struct rpc_rqst *rqstp, uint32_t *p, void *res)
 {
 	struct xdr_stream xdr;
 	struct compound_hdr hdr;
@@ -2958,23 +3443,15 @@ nfs4_xdr_dec_read(struct rpc_rqst *rqstp
 	status = decode_putfh(&xdr);
 	if (status)
 		goto out;
-	status = decode_read(&xdr, rqstp, res);
-	if (status)
-		goto out;
-	status = decode_read_getattr(&xdr, res->fattr);
-	if (!status)
-		status = -nfs_stat_to_errno(hdr.status);
-	if (!status)
-		status = res->count;
+	status = decode_readlink(&xdr, rqstp);
 out:
 	return status;
 }
 
 /*
- * Decode WRITE response
+ * Decode READDIR response
  */
-static int
-nfs4_xdr_dec_write(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_writeres *res)
+static int nfs4_xdr_dec_readdir(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_readdir_res *res)
 {
 	struct xdr_stream xdr;
 	struct compound_hdr hdr;
@@ -2987,15 +3464,28 @@ nfs4_xdr_dec_write(struct rpc_rqst *rqst
 	status = decode_putfh(&xdr);
 	if (status)
 		goto out;
-	status = decode_pre_write_getattr(&xdr, res->fattr);
+	status = decode_readdir(&xdr, rqstp, res);
+out:
+	return status;
+}
+
+/*
+ * Decode Read response
+ */
+static int nfs4_xdr_dec_read(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_readres *res)
+{
+	struct xdr_stream xdr;
+	struct compound_hdr hdr;
+	int status;
+
+	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
+	status = decode_compound_hdr(&xdr, &hdr);
 	if (status)
 		goto out;
-	status = decode_write(&xdr, res);
+	status = decode_putfh(&xdr);
 	if (status)
 		goto out;
-	status = decode_post_write_getattr(&xdr, res->fattr);
-	if (!status)
-		status = -nfs_stat_to_errno(hdr.status);
+	status = decode_read(&xdr, rqstp, res);
 	if (!status)
 		status = res->count;
 out:
@@ -3003,10 +3493,9 @@ out:
 }
 
 /*
- * Decode COMMIT response
+ * Decode WRITE response
  */
-static int
-nfs4_xdr_dec_commit(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_writeres *res)
+static int nfs4_xdr_dec_write(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_writeres *res)
 {
 	struct xdr_stream xdr;
 	struct compound_hdr hdr;
@@ -3019,15 +3508,30 @@ nfs4_xdr_dec_commit(struct rpc_rqst *rqs
 	status = decode_putfh(&xdr);
 	if (status)
 		goto out;
-	status = decode_pre_write_getattr(&xdr, res->fattr);
+	status = decode_write(&xdr, res);
+	if (!status)
+		status = res->count;
+out:
+	return status;
+}
+
+/*
+ * Decode COMMIT response
+ */
+static int nfs4_xdr_dec_commit(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_writeres *res)
+{
+	struct xdr_stream xdr;
+	struct compound_hdr hdr;
+	int status;
+
+	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
+	status = decode_compound_hdr(&xdr, &hdr);
 	if (status)
 		goto out;
-	status = decode_commit(&xdr, res);
+	status = decode_putfh(&xdr);
 	if (status)
 		goto out;
-	status = decode_post_write_getattr(&xdr, res->fattr);
-	if (!status)
-		status = -nfs_stat_to_errno(hdr.status);
+	status = decode_commit(&xdr, res);
 out:
 	return status;
 }
@@ -3035,8 +3539,7 @@ out:
 /*
  * FSINFO request
  */
-static int
-nfs4_xdr_dec_fsinfo(struct rpc_rqst *req, uint32_t *p, struct nfs_fsinfo *fsinfo)
+static int nfs4_xdr_dec_fsinfo(struct rpc_rqst *req, uint32_t *p, struct nfs_fsinfo *fsinfo)
 {
 	struct xdr_stream xdr;
 	struct compound_hdr hdr;
@@ -3054,10 +3557,64 @@ nfs4_xdr_dec_fsinfo(struct rpc_rqst *req
 }
 
 /*
+ * PATHCONF request
+ */
+static int nfs4_xdr_dec_pathconf(struct rpc_rqst *req, uint32_t *p, struct nfs_pathconf *pathconf)
+{
+	struct xdr_stream xdr;
+	struct compound_hdr hdr;
+	int status;
+
+	xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
+	status = decode_compound_hdr(&xdr, &hdr);
+	if (!status)
+		status = decode_putfh(&xdr);
+	if (!status)
+		status = decode_pathconf(&xdr, pathconf);
+	return status;
+}
+
+/*
+ * STATFS request
+ */
+static int nfs4_xdr_dec_statfs(struct rpc_rqst *req, uint32_t *p, struct nfs_fsstat *fsstat)
+{
+	struct xdr_stream xdr;
+	struct compound_hdr hdr;
+	int status;
+
+	xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
+	status = decode_compound_hdr(&xdr, &hdr);
+	if (!status)
+		status = decode_putfh(&xdr);
+	if (!status)
+		status = decode_statfs(&xdr, fsstat);
+	return status;
+}
+
+/*
+ * GETATTR_BITMAP request
+ */
+static int nfs4_xdr_dec_server_caps(struct rpc_rqst *req, uint32_t *p, struct nfs4_server_caps_res *res)
+{
+	struct xdr_stream xdr;
+	struct compound_hdr hdr;
+	int status;
+
+	xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
+	if ((status = decode_compound_hdr(&xdr, &hdr)) != 0)
+		goto out;
+	if ((status = decode_putfh(&xdr)) != 0)
+		goto out;
+	status = decode_server_caps(&xdr, res);
+out:
+	return status;
+}
+
+/*
  * Decode RENEW response
  */
-static int
-nfs4_xdr_dec_renew(struct rpc_rqst *rqstp, uint32_t *p, void *dummy)
+static int nfs4_xdr_dec_renew(struct rpc_rqst *rqstp, uint32_t *p, void *dummy)
 {
 	struct xdr_stream xdr;
 	struct compound_hdr hdr;
@@ -3073,8 +3630,7 @@ nfs4_xdr_dec_renew(struct rpc_rqst *rqst
 /*
  * a SETCLIENTID request
  */
-static int
-nfs4_xdr_dec_setclientid(struct rpc_rqst *req, uint32_t *p,
+static int nfs4_xdr_dec_setclientid(struct rpc_rqst *req, uint32_t *p,
 		struct nfs4_client *clp)
 {
 	struct xdr_stream xdr;
@@ -3093,8 +3649,7 @@ nfs4_xdr_dec_setclientid(struct rpc_rqst
 /*
  * a SETCLIENTID_CONFIRM request
  */
-static int
-nfs4_xdr_dec_setclientid_confirm(struct rpc_rqst *req, uint32_t *p, struct nfs_fsinfo *fsinfo)
+static int nfs4_xdr_dec_setclientid_confirm(struct rpc_rqst *req, uint32_t *p, struct nfs_fsinfo *fsinfo)
 {
 	struct xdr_stream xdr;
 	struct compound_hdr hdr;
@@ -3113,8 +3668,7 @@ nfs4_xdr_dec_setclientid_confirm(struct 
 	return status;
 }
 
-uint32_t *
-nfs4_decode_dirent(uint32_t *p, struct nfs_entry *entry, int plus)
+uint32_t *nfs4_decode_dirent(uint32_t *p, struct nfs_entry *entry, int plus)
 {
 	uint32_t len;
 
@@ -3230,7 +3784,6 @@ nfs_stat_to_errno(int stat)
     }
 
 struct rpc_procinfo	nfs4_procedures[] = {
-  PROC(COMPOUND,	enc_compound,	dec_compound),
   PROC(READ,		enc_read,	dec_read),
   PROC(WRITE,		enc_write,	dec_write),
   PROC(COMMIT,		enc_commit,	dec_commit),
@@ -3247,6 +3800,19 @@ struct rpc_procinfo	nfs4_procedures[] = 
   PROC(LOCK,            enc_lock,       dec_lock),
   PROC(LOCKT,           enc_lockt,      dec_lockt),
   PROC(LOCKU,           enc_locku,      dec_locku),
+  PROC(ACCESS,		enc_access,	dec_access),
+  PROC(GETATTR,		enc_getattr,	dec_getattr),
+  PROC(LOOKUP,		enc_lookup,	dec_lookup),
+  PROC(LOOKUP_ROOT,	enc_lookup_root,	dec_lookup_root),
+  PROC(REMOVE,		enc_remove,	dec_remove),
+  PROC(RENAME,		enc_rename,	dec_rename),
+  PROC(LINK,		enc_link,	dec_link),
+  PROC(CREATE,		enc_create,	dec_create),
+  PROC(PATHCONF,	enc_pathconf,	dec_pathconf),
+  PROC(STATFS,		enc_statfs,	dec_statfs),
+  PROC(READLINK,	enc_readlink,	dec_readlink),
+  PROC(READDIR,		enc_readdir,	dec_readdir),
+  PROC(SERVER_CAPS,	enc_server_caps, dec_server_caps),
 };
 
 struct rpc_version		nfs_version4 = {
diff -puN fs/nfs/nfsroot.c~nfsv4-updates fs/nfs/nfsroot.c
--- 25/fs/nfs/nfsroot.c~nfsv4-updates	2004-04-03 15:03:11.250758776 -0800
+++ 25-akpm/fs/nfs/nfsroot.c	2004-04-03 15:03:11.314749048 -0800
@@ -66,7 +66,8 @@
  *				is NOT for the length of the hostname.
  *	Hua Qin		:	Support for mounting root file system via
  *				NFS over TCP.
- */
+ *	Fabian Frederick:	Option parser rebuilt (using parser lib)
+*/
 
 #include <linux/config.h>
 #include <linux/types.h>
@@ -85,6 +86,7 @@
 #include <linux/inet.h>
 #include <linux/root_dev.h>
 #include <net/ipconfig.h>
+#include <linux/parser.h>
 
 /* Define this to allow debugging output */
 #undef NFSROOT_DEBUG
@@ -114,92 +116,158 @@ static int mount_port __initdata = 0;		/
 
  ***************************************************************************/
 
-/*
- *  The following integer options are recognized
- */
-static struct nfs_int_opts {
-	char *name;
-	int  *val;
-} root_int_opts[] __initdata = {
-	{ "port",	&nfs_port },
-	{ "rsize",	&nfs_data.rsize },
-	{ "wsize",	&nfs_data.wsize },
-	{ "timeo",	&nfs_data.timeo },
-	{ "retrans",	&nfs_data.retrans },
-	{ "acregmin",	&nfs_data.acregmin },
-	{ "acregmax",	&nfs_data.acregmax },
-	{ "acdirmin",	&nfs_data.acdirmin },
-	{ "acdirmax",	&nfs_data.acdirmax },
-	{ NULL,		NULL }
+enum {
+	Opt_port, Opt_rsize, Opt_wsize, Opt_timeo, Opt_retrans, Opt_acregmin,
+	Opt_acregmax, Opt_acdirmin, Opt_acdirmax, Opt_soft, Opt_hard, Opt_intr,
+	Opt_nointr, Opt_posix, Opt_noposix, Opt_cto, Opt_nocto, Opt_ac,
+	Opt_noac, Opt_lock, Opt_nolock, Opt_v2, Opt_v3, Opt_udp, Opt_tcp,
+	Opt_broken_suid, Opt_err,
 };
 
+static match_table_t tokens = {
+	{Opt_port, "port=%u"},
+	{Opt_rsize, "rsize=%u"},
+	{Opt_wsize, "wsize=%u"},
+	{Opt_timeo, "timeo=%u"},
+	{Opt_retrans, "retrans=%u"},
+	{Opt_acregmin, "acregmin=%u"},
+	{Opt_acregmax, "acregmax=%u"},
+	{Opt_acdirmin, "acdirmin=%u"},
+	{Opt_acdirmax, "acdirmax=%u"},
+	{Opt_soft, "soft"},
+	{Opt_hard, "hard"},
+	{Opt_intr, "intr"},
+	{Opt_nointr, "nointr"},
+	{Opt_posix, "posix"},
+	{Opt_noposix, "noposix"},
+	{Opt_cto, "cto"},
+	{Opt_nocto, "nocto"},
+	{Opt_ac, "ac"},
+	{Opt_noac, "noac"},
+	{Opt_lock, "lock"},
+	{Opt_nolock, "nolock"},
+	{Opt_v2, "v2"},
+	{Opt_v3, "v3"},
+	{Opt_udp, "udp"},
+	{Opt_tcp, "tcp"},
+	{Opt_broken_suid, "broken_suid"},
+	{Opt_err, NULL}
 
-/*
- *  And now the flag options
- */
-static struct nfs_bool_opts {
-	char *name;
-	int  and_mask;
-	int  or_mask;
-} root_bool_opts[] __initdata = {
-	{ "soft",	~NFS_MOUNT_SOFT,	NFS_MOUNT_SOFT },
-	{ "hard",	~NFS_MOUNT_SOFT,	0 },
-	{ "intr",	~NFS_MOUNT_INTR,	NFS_MOUNT_INTR },
-	{ "nointr",	~NFS_MOUNT_INTR,	0 },
-	{ "posix",	~NFS_MOUNT_POSIX,	NFS_MOUNT_POSIX },
-	{ "noposix",	~NFS_MOUNT_POSIX,	0 },
-	{ "cto",	~NFS_MOUNT_NOCTO,	0 },
-	{ "nocto",	~NFS_MOUNT_NOCTO,	NFS_MOUNT_NOCTO },
-	{ "ac",		~NFS_MOUNT_NOAC,	0 },
-	{ "noac",	~NFS_MOUNT_NOAC,	NFS_MOUNT_NOAC },
-	{ "lock",	~NFS_MOUNT_NONLM,	0 },
-	{ "nolock",	~NFS_MOUNT_NONLM,	NFS_MOUNT_NONLM },
-#ifdef CONFIG_NFS_V3
-	{ "v2",		~NFS_MOUNT_VER3,	0 },
-	{ "v3",		~NFS_MOUNT_VER3,	NFS_MOUNT_VER3 },
-#endif
-	{ "udp",	~NFS_MOUNT_TCP,		0 },
-	{ "tcp",	~NFS_MOUNT_TCP,		NFS_MOUNT_TCP },
-	{ "broken_suid",~NFS_MOUNT_BROKEN_SUID,	NFS_MOUNT_BROKEN_SUID },
-	{ NULL,		0,			0 }
 };
 
-
 /*
  *  Parse option string.
  */
-static void __init root_nfs_parse(char *name, char *buf)
+
+static int __init root_nfs_parse(char *name, char *buf)
 {
-	char *options, *val, *cp;
 
-	if ((options = strchr(name, ','))) {
-		*options++ = 0;
-		while ((cp = strsep(&options, ",")) != NULL) {
-			if (!*cp)
-				continue;
-			if ((val = strchr(cp, '='))) {
-				struct nfs_int_opts *opts = root_int_opts;
-				*val++ = '\0';
-				while (opts->name && strcmp(opts->name, cp))
-					opts++;
-				if (opts->name)
-					*(opts->val) = (int) simple_strtoul(val, NULL, 10);
-			} else {
-				struct nfs_bool_opts *opts = root_bool_opts;
-				while (opts->name && strcmp(opts->name, cp))
-					opts++;
-				if (opts->name) {
-					nfs_data.flags &= opts->and_mask;
-					nfs_data.flags |= opts->or_mask;
-				}
-			}
+	char *p;
+	substring_t args[MAX_OPT_ARGS];
+	int option;
+
+	if (!name)
+		return 1;
+
+	if (name[0] && strcmp(name, "default")){
+		strlcpy(buf, name, NFS_MAXPATHLEN);
+		return 1;
+	}
+	while ((p = strsep (&name, ",")) != NULL) {
+		int token;
+		if (!*p)
+			continue;
+		token = match_token(p, tokens, args);
+
+		/* %u tokens only */
+		if (match_int(&args[0], &option))
+			return 0;
+		switch (token) {
+			case Opt_port:
+				nfs_port = option;
+				break;
+			case Opt_rsize:
+				nfs_data.rsize = option;
+				break;
+			case Opt_wsize:
+				nfs_data.wsize = option;
+				break;
+			case Opt_timeo:
+				nfs_data.timeo = option;
+				break;
+			case Opt_retrans:
+				nfs_data.retrans = option;
+				break;
+			case Opt_acregmin:
+				nfs_data.acregmin = option;
+				break;
+			case Opt_acregmax:
+				nfs_data.acregmax = option;
+				break;
+			case Opt_acdirmin:
+				nfs_data.acdirmin = option;
+				break;
+			case Opt_acdirmax:
+				nfs_data.acdirmax = option;
+				break;
+			case Opt_soft:
+				nfs_data.flags |= NFS_MOUNT_SOFT;
+				break;
+			case Opt_hard:
+				nfs_data.flags &= ~NFS_MOUNT_SOFT;
+				break;
+			case Opt_intr:
+				nfs_data.flags |= NFS_MOUNT_INTR;
+				break;
+			case Opt_nointr:
+				nfs_data.flags &= ~NFS_MOUNT_INTR;
+				break;
+			case Opt_posix:
+				nfs_data.flags |= NFS_MOUNT_POSIX;
+				break;
+			case Opt_noposix:
+				nfs_data.flags &= ~NFS_MOUNT_POSIX;
+				break;
+			case Opt_cto:
+				nfs_data.flags &= ~NFS_MOUNT_NOCTO;
+				break;
+			case Opt_nocto:
+				nfs_data.flags |= NFS_MOUNT_NOCTO;
+				break;
+			case Opt_ac:
+				nfs_data.flags &= ~NFS_MOUNT_NOAC;
+				break;
+			case Opt_noac:
+				nfs_data.flags |= NFS_MOUNT_NOAC;
+				break;
+			case Opt_lock:
+				nfs_data.flags &= ~NFS_MOUNT_NONLM;
+				break;
+			case Opt_nolock:
+				nfs_data.flags |= NFS_MOUNT_NONLM;
+				break;
+			case Opt_v2:
+				nfs_data.flags &= ~NFS_MOUNT_VER3;
+				break;
+			case Opt_v3:
+				nfs_data.flags |= NFS_MOUNT_VER3;
+				break;
+			case Opt_udp:
+				nfs_data.flags &= ~NFS_MOUNT_TCP;
+				break;
+			case Opt_tcp:
+				nfs_data.flags |= NFS_MOUNT_TCP;
+				break;
+			case Opt_broken_suid:
+				nfs_data.flags |= NFS_MOUNT_BROKEN_SUID;
+				break;
+			default :
+				return 0;
 		}
 	}
-	if (name[0] && strcmp(name, "default"))
-		strlcpy(buf, name, NFS_MAXPATHLEN);
+	return 1;
 }
 
-
 /*
  *  Prepare the NFS data structure and parse all options.
  */
diff -puN fs/nfs/write.c~nfsv4-updates fs/nfs/write.c
--- 25/fs/nfs/write.c~nfsv4-updates	2004-04-03 15:03:11.251758624 -0800
+++ 25-akpm/fs/nfs/write.c	2004-04-03 15:03:11.315748896 -0800
@@ -233,7 +233,7 @@ static int nfs_writepage_sync(struct fil
 		ClearPageError(page);
 
 io_error:
-	nfs_end_data_update(inode);
+	nfs_end_data_update_defer(inode);
 	if (wdata.cred)
 		put_rpccred(wdata.cred);
 
@@ -404,7 +404,7 @@ nfs_inode_remove_request(struct nfs_page
 	nfsi->npages--;
 	if (!nfsi->npages) {
 		spin_unlock(&nfs_wreq_lock);
-		nfs_end_data_update(inode);
+		nfs_end_data_update_defer(inode);
 		iput(inode);
 	} else
 		spin_unlock(&nfs_wreq_lock);
diff -puN include/linux/nfs4.h~nfsv4-updates include/linux/nfs4.h
--- 25/include/linux/nfs4.h~nfsv4-updates	2004-04-03 15:03:11.253758320 -0800
+++ 25-akpm/include/linux/nfs4.h	2004-04-03 15:04:00.139326584 -0800
@@ -47,6 +47,11 @@
 #define NFS4_ACE_SYSTEM_AUDIT_ACE_TYPE   2
 #define NFS4_ACE_SYSTEM_ALARM_ACE_TYPE   3
 
+#define ACL4_SUPPORT_ALLOW_ACL 0x01
+#define ACL4_SUPPORT_DENY_ACL  0x02
+#define ACL4_SUPPORT_AUDIT_ACL 0x04
+#define ACL4_SUPPORT_ALARM_ACL 0x08
+
 typedef struct { char data[NFS4_VERIFIER_SIZE]; } nfs4_verifier;
 typedef struct { char data[16]; } nfs4_stateid;
 
@@ -217,64 +222,64 @@ enum lock_type4 {
 
 
 /* Mandatory Attributes */
-#define FATTR4_WORD0_SUPPORTED_ATTRS    (1)
-#define FATTR4_WORD0_TYPE               (1 << 1)
-#define FATTR4_WORD0_FH_EXPIRE_TYPE     (1 << 2)
-#define FATTR4_WORD0_CHANGE             (1 << 3)
-#define FATTR4_WORD0_SIZE               (1 << 4)
-#define FATTR4_WORD0_LINK_SUPPORT       (1 << 5)
-#define FATTR4_WORD0_SYMLINK_SUPPORT    (1 << 6)
-#define FATTR4_WORD0_NAMED_ATTR         (1 << 7)
-#define FATTR4_WORD0_FSID               (1 << 8)
-#define FATTR4_WORD0_UNIQUE_HANDLES     (1 << 9)
-#define FATTR4_WORD0_LEASE_TIME         (1 << 10)
-#define FATTR4_WORD0_RDATTR_ERROR       (1 << 11)
+#define FATTR4_WORD0_SUPPORTED_ATTRS    (1UL)
+#define FATTR4_WORD0_TYPE               (1UL << 1)
+#define FATTR4_WORD0_FH_EXPIRE_TYPE     (1UL << 2)
+#define FATTR4_WORD0_CHANGE             (1UL << 3)
+#define FATTR4_WORD0_SIZE               (1UL << 4)
+#define FATTR4_WORD0_LINK_SUPPORT       (1UL << 5)
+#define FATTR4_WORD0_SYMLINK_SUPPORT    (1UL << 6)
+#define FATTR4_WORD0_NAMED_ATTR         (1UL << 7)
+#define FATTR4_WORD0_FSID               (1UL << 8)
+#define FATTR4_WORD0_UNIQUE_HANDLES     (1UL << 9)
+#define FATTR4_WORD0_LEASE_TIME         (1UL << 10)
+#define FATTR4_WORD0_RDATTR_ERROR       (1UL << 11)
 
 /* Recommended Attributes */
-#define FATTR4_WORD0_ACL                (1 << 12)
-#define FATTR4_WORD0_ACLSUPPORT         (1 << 13)
-#define FATTR4_WORD0_ARCHIVE            (1 << 14)
-#define FATTR4_WORD0_CANSETTIME         (1 << 15)
-#define FATTR4_WORD0_CASE_INSENSITIVE   (1 << 16)
-#define FATTR4_WORD0_CASE_PRESERVING    (1 << 17)
-#define FATTR4_WORD0_CHOWN_RESTRICTED   (1 << 18)
-#define FATTR4_WORD0_FILEHANDLE         (1 << 19)
-#define FATTR4_WORD0_FILEID             (1 << 20)
-#define FATTR4_WORD0_FILES_AVAIL        (1 << 21)
-#define FATTR4_WORD0_FILES_FREE         (1 << 22)
-#define FATTR4_WORD0_FILES_TOTAL        (1 << 23)
-#define FATTR4_WORD0_FS_LOCATIONS       (1 << 24)
-#define FATTR4_WORD0_HIDDEN             (1 << 25)
-#define FATTR4_WORD0_HOMOGENEOUS        (1 << 26)
-#define FATTR4_WORD0_MAXFILESIZE        (1 << 27)
-#define FATTR4_WORD0_MAXLINK            (1 << 28)
-#define FATTR4_WORD0_MAXNAME            (1 << 29)
-#define FATTR4_WORD0_MAXREAD            (1 << 30)
-#define FATTR4_WORD0_MAXWRITE           (1 << 31)
-#define FATTR4_WORD1_MIMETYPE           (1)
-#define FATTR4_WORD1_MODE               (1 << 1)
-#define FATTR4_WORD1_NO_TRUNC           (1 << 2)
-#define FATTR4_WORD1_NUMLINKS           (1 << 3)
-#define FATTR4_WORD1_OWNER              (1 << 4)
-#define FATTR4_WORD1_OWNER_GROUP        (1 << 5)
-#define FATTR4_WORD1_QUOTA_HARD         (1 << 6)
-#define FATTR4_WORD1_QUOTA_SOFT         (1 << 7)
-#define FATTR4_WORD1_QUOTA_USED         (1 << 8)
-#define FATTR4_WORD1_RAWDEV             (1 << 9)
-#define FATTR4_WORD1_SPACE_AVAIL        (1 << 10)
-#define FATTR4_WORD1_SPACE_FREE         (1 << 11)
-#define FATTR4_WORD1_SPACE_TOTAL        (1 << 12)
-#define FATTR4_WORD1_SPACE_USED         (1 << 13)
-#define FATTR4_WORD1_SYSTEM             (1 << 14)
-#define FATTR4_WORD1_TIME_ACCESS        (1 << 15)
-#define FATTR4_WORD1_TIME_ACCESS_SET    (1 << 16)
-#define FATTR4_WORD1_TIME_BACKUP        (1 << 17)
-#define FATTR4_WORD1_TIME_CREATE        (1 << 18)
-#define FATTR4_WORD1_TIME_DELTA         (1 << 19)
-#define FATTR4_WORD1_TIME_METADATA      (1 << 20)
-#define FATTR4_WORD1_TIME_MODIFY        (1 << 21)
-#define FATTR4_WORD1_TIME_MODIFY_SET    (1 << 22)
-#define FATTR4_WORD1_MOUNTED_ON_FILEID  (1 << 23)
+#define FATTR4_WORD0_ACL                (1UL << 12)
+#define FATTR4_WORD0_ACLSUPPORT         (1UL << 13)
+#define FATTR4_WORD0_ARCHIVE            (1UL << 14)
+#define FATTR4_WORD0_CANSETTIME         (1UL << 15)
+#define FATTR4_WORD0_CASE_INSENSITIVE   (1UL << 16)
+#define FATTR4_WORD0_CASE_PRESERVING    (1UL << 17)
+#define FATTR4_WORD0_CHOWN_RESTRICTED   (1UL << 18)
+#define FATTR4_WORD0_FILEHANDLE         (1UL << 19)
+#define FATTR4_WORD0_FILEID             (1UL << 20)
+#define FATTR4_WORD0_FILES_AVAIL        (1UL << 21)
+#define FATTR4_WORD0_FILES_FREE         (1UL << 22)
+#define FATTR4_WORD0_FILES_TOTAL        (1UL << 23)
+#define FATTR4_WORD0_FS_LOCATIONS       (1UL << 24)
+#define FATTR4_WORD0_HIDDEN             (1UL << 25)
+#define FATTR4_WORD0_HOMOGENEOUS        (1UL << 26)
+#define FATTR4_WORD0_MAXFILESIZE        (1UL << 27)
+#define FATTR4_WORD0_MAXLINK            (1UL << 28)
+#define FATTR4_WORD0_MAXNAME            (1UL << 29)
+#define FATTR4_WORD0_MAXREAD            (1UL << 30)
+#define FATTR4_WORD0_MAXWRITE           (1UL << 31)
+#define FATTR4_WORD1_MIMETYPE           (1UL)
+#define FATTR4_WORD1_MODE               (1UL << 1)
+#define FATTR4_WORD1_NO_TRUNC           (1UL << 2)
+#define FATTR4_WORD1_NUMLINKS           (1UL << 3)
+#define FATTR4_WORD1_OWNER              (1UL << 4)
+#define FATTR4_WORD1_OWNER_GROUP        (1UL << 5)
+#define FATTR4_WORD1_QUOTA_HARD         (1UL << 6)
+#define FATTR4_WORD1_QUOTA_SOFT         (1UL << 7)
+#define FATTR4_WORD1_QUOTA_USED         (1UL << 8)
+#define FATTR4_WORD1_RAWDEV             (1UL << 9)
+#define FATTR4_WORD1_SPACE_AVAIL        (1UL << 10)
+#define FATTR4_WORD1_SPACE_FREE         (1UL << 11)
+#define FATTR4_WORD1_SPACE_TOTAL        (1UL << 12)
+#define FATTR4_WORD1_SPACE_USED         (1UL << 13)
+#define FATTR4_WORD1_SYSTEM             (1UL << 14)
+#define FATTR4_WORD1_TIME_ACCESS        (1UL << 15)
+#define FATTR4_WORD1_TIME_ACCESS_SET    (1UL << 16)
+#define FATTR4_WORD1_TIME_BACKUP        (1UL << 17)
+#define FATTR4_WORD1_TIME_CREATE        (1UL << 18)
+#define FATTR4_WORD1_TIME_DELTA         (1UL << 19)
+#define FATTR4_WORD1_TIME_METADATA      (1UL << 20)
+#define FATTR4_WORD1_TIME_MODIFY        (1UL << 21)
+#define FATTR4_WORD1_TIME_MODIFY_SET    (1UL << 22)
+#define FATTR4_WORD1_MOUNTED_ON_FILEID  (1UL << 23)
 
 #define NFSPROC4_NULL 0
 #define NFSPROC4_COMPOUND 1
@@ -287,7 +292,6 @@ enum lock_type4 {
 
 enum {
 	NFSPROC4_CLNT_NULL = 0,		/* Unused */
-	NFSPROC4_CLNT_COMPOUND,		/* Soon to be unused */
 	NFSPROC4_CLNT_READ,
 	NFSPROC4_CLNT_WRITE,
 	NFSPROC4_CLNT_COMMIT,
@@ -304,6 +308,19 @@ enum {
 	NFSPROC4_CLNT_LOCK,
 	NFSPROC4_CLNT_LOCKT,
 	NFSPROC4_CLNT_LOCKU,
+	NFSPROC4_CLNT_ACCESS,
+	NFSPROC4_CLNT_GETATTR,
+	NFSPROC4_CLNT_LOOKUP,
+	NFSPROC4_CLNT_LOOKUP_ROOT,
+	NFSPROC4_CLNT_REMOVE,
+	NFSPROC4_CLNT_RENAME,
+	NFSPROC4_CLNT_LINK,
+	NFSPROC4_CLNT_CREATE,
+	NFSPROC4_CLNT_PATHCONF,
+	NFSPROC4_CLNT_STATFS,
+	NFSPROC4_CLNT_READLINK,
+	NFSPROC4_CLNT_READDIR,
+	NFSPROC4_CLNT_SERVER_CAPS,
 };
 
 #endif
diff -puN include/linux/nfs_fs.h~nfsv4-updates include/linux/nfs_fs.h
--- 25/include/linux/nfs_fs.h~nfsv4-updates	2004-04-03 15:03:11.254758168 -0800
+++ 25-akpm/include/linux/nfs_fs.h	2004-04-03 15:03:11.318748440 -0800
@@ -277,6 +277,7 @@ extern void nfs_begin_attr_update(struct
 extern void nfs_end_attr_update(struct inode *);
 extern void nfs_begin_data_update(struct inode *);
 extern void nfs_end_data_update(struct inode *);
+extern void nfs_end_data_update_defer(struct inode *);
 
 /* linux/net/ipv4/ipconfig.c: trims ip addr off front of name, too. */
 extern u32 root_nfs_parse_addr(char *name); /*__init*/
diff -puN include/linux/nfs_fs_sb.h~nfsv4-updates include/linux/nfs_fs_sb.h
--- 25/include/linux/nfs_fs_sb.h~nfsv4-updates	2004-04-03 15:03:11.255758016 -0800
+++ 25-akpm/include/linux/nfs_fs_sb.h	2004-04-03 15:03:11.319748288 -0800
@@ -38,10 +38,19 @@ struct nfs_server {
 	struct list_head	nfs4_siblings;	/* List of other nfs_server structs
 						 * that share the same clientid
 						 */
+	u32			attr_bitmask[2];/* V4 bitmask representing the set
+						   of attributes supported on this
+						   filesystem */
+	u32			acl_bitmask;	/* V4 bitmask representing the ACEs
+						   that are supported on this
+						   filesystem */
 #endif
 };
 
 /* Server capabilities */
-#define NFS_CAP_READDIRPLUS	(1)
+#define NFS_CAP_READDIRPLUS	(1U << 0)
+#define NFS_CAP_HARDLINKS	(1U << 1)
+#define NFS_CAP_SYMLINKS	(1U << 2)
+#define NFS_CAP_ACLS		(1U << 3)
 
 #endif
diff -puN include/linux/nfs_xdr.h~nfsv4-updates include/linux/nfs_xdr.h
--- 25/include/linux/nfs_xdr.h~nfsv4-updates	2004-04-03 15:03:11.256757864 -0800
+++ 25-akpm/include/linux/nfs_xdr.h	2004-04-03 15:03:11.321747984 -0800
@@ -3,6 +3,11 @@
 
 #include <linux/sunrpc/xprt.h>
 
+struct nfs4_fsid {
+	__u64 major;
+	__u64 minor;
+};
+
 struct nfs_fattr {
 	unsigned short		valid;		/* which fields are valid */
 	__u64			pre_size;	/* pre_op_attr.size	  */
@@ -26,10 +31,7 @@ struct nfs_fattr {
 	dev_t			rdev;
 	union {
 		__u64		nfs3;		/* also nfs2 */
-		struct {
-			__u64	major;
-			__u64	minor;
-		} nfs4;
+		struct nfs4_fsid nfs4;
 	} fsid_u;
 	__u64			fileid;
 	struct timespec		atime;
@@ -87,6 +89,12 @@ struct nfs_pathconf {
 	__u32			max_namelen; /* max name length */
 };
 
+struct nfs4_change_info {
+	u32			atomic;
+	u64			before;
+	u64			after;
+};
+
 /*
  * Arguments to the open call.
  */
@@ -102,20 +110,18 @@ struct nfs_openargs {
 		struct iattr *  attrs;    /* UNCHECKED, GUARDED */
 		nfs4_verifier   verifier; /* EXCLUSIVE */
 	} u;
-	struct qstr *           name;
-	struct nfs4_getattr *   f_getattr;
-	struct nfs4_getattr *   d_getattr;
-	struct nfs_server *     server;	 /* Needed for ID mapping */
+	const struct qstr *	name;
+	const struct nfs_server *server;	 /* Needed for ID mapping */
+	const u32 *		bitmask;
 };
 
 struct nfs_openres {
 	nfs4_stateid            stateid;
 	struct nfs_fh           fh;
-	struct nfs4_change_info * cinfo;
+	struct nfs4_change_info	cinfo;
 	__u32                   rflags;
-	struct nfs4_getattr *   f_getattr;
-	struct nfs4_getattr *   d_getattr;
-	struct nfs_server *     server;
+	struct nfs_fattr *      f_attr;
+	const struct nfs_server *server;
 };
 
 /*
@@ -141,7 +147,7 @@ struct nfs_open_reclaimargs {
 	__u32			id;
 	__u32			share_access;
 	__u32			claim;
-	struct nfs4_getattr *   f_getattr;
+	const __u32 *		bitmask;
 };
 
 /*
@@ -215,7 +221,7 @@ struct nfs_lockres {
 		nfs4_stateid            stateid;/* LOCK success, LOCKU */
 		struct nfs_lock_denied  denied; /* LOCK failed, LOCKT success */
 	} u;
-	struct nfs_server *     server;
+	const struct nfs_server *	server;
 };
 
 /*
@@ -321,13 +327,13 @@ struct nfs_setattrargs {
 	struct nfs_fh *                 fh;
 	nfs4_stateid                    stateid;
 	struct iattr *                  iap;
-	struct nfs4_getattr *           attr;
-	struct nfs_server *             server; /* Needed for name mapping */
+	const struct nfs_server *	server; /* Needed for name mapping */
+	const u32 *			bitmask;
 };
 
 struct nfs_setattrres {
-	struct nfs4_getattr *           attr;
-	struct nfs_server *             server;
+	struct nfs_fattr *              fattr;
+	const struct nfs_server *	server;
 };
 
 struct nfs_linkargs {
@@ -478,124 +484,116 @@ struct nfs3_readdirres {
 
 typedef u64 clientid4;
 
-struct nfs4_change_info {
-	u32				atomic;
-	u64				before;
-	u64				after;
+struct nfs4_accessargs {
+	const struct nfs_fh *		fh;
+	u32				access;
 };
 
-struct nfs4_access {
-	u32				ac_req_access;     /* request */
-	u32 *				ac_resp_supported; /* response */
-	u32 *				ac_resp_access;    /* response */
+struct nfs4_accessres {
+	u32				supported;
+	u32				access;
 };
 
-struct nfs4_close {
-	char *				cl_stateid;        /* request */
-	u32				cl_seqid;          /* request */
-};
-
-struct nfs4_create {
-	u32				cr_ftype;          /* request */
-	union {                                            /* request */
-		struct {
-			u32		textlen;
-			const char *	text;
-		} symlink;   /* NF4LNK */
+struct nfs4_create_arg {
+	u32				ftype;
+	union {
+		struct qstr *		symlink;    /* NF4LNK */
 		struct {
 			u32		specdata1;
 			u32		specdata2;
 		} device;    /* NF4BLK, NF4CHR */
 	} u;
-	u32				cr_namelen;        /* request */
-	const char *			cr_name;           /* request */
-	struct iattr *			cr_attrs;          /* request */
-	struct nfs4_change_info	*	cr_cinfo;          /* response */
+	const struct qstr *		name;
+	const struct nfs_server *	server;
+	const struct iattr *		attrs;
+	const struct nfs_fh *		dir_fh;
+	const u32 *			bitmask;
 };
-#define cr_textlen			u.symlink.textlen
-#define cr_text				u.symlink.text
-#define cr_specdata1			u.device.specdata1
-#define cr_specdata2			u.device.specdata2
 
-struct nfs4_getattr {
-        u32 *				gt_bmval;          /* request */
-        struct nfs_fattr *		gt_attrs;          /* response */
-	struct nfs_fsstat *		gt_fsstat;         /* response */
-	struct nfs_pathconf *		gt_pathconf;       /* response */
+struct nfs4_create_res {
+	const struct nfs_server *	server;
+	struct nfs_fh *			fh;
+	struct nfs_fattr *		fattr;
+	struct nfs4_change_info		dir_cinfo;
 };
 
-struct nfs4_getfh {
-	struct nfs_fh *			gf_fhandle;       /* response */
+struct nfs4_fsinfo_arg {
+	const struct nfs_fh *		fh;
+	const u32 *			bitmask;
 };
 
-struct nfs4_link {
-	u32				ln_namelen;       /* request */
-	const char *			ln_name;          /* request */
-	struct nfs4_change_info *	ln_cinfo;         /* response */
+struct nfs4_getattr_arg {
+	const struct nfs_fh *		fh;
+	const u32 *			bitmask;
 };
 
-struct nfs4_lookup {
-	struct qstr *			lo_name;          /* request */
+struct nfs4_getattr_res {
+	const struct nfs_server *	server;
+	struct nfs_fattr *		fattr;
 };
 
-struct nfs4_open {
-	struct nfs4_client *		op_client_state;  /* request */
-	u32				op_share_access;  /* request */
-	u32				op_opentype;      /* request */
-	u32				op_createmode;    /* request */
-	union {                                           /* request */
-		struct iattr *		attrs;    /* UNCHECKED, GUARDED */
-		nfs4_verifier		verifier; /* EXCLUSIVE */
-	} u;
-	struct qstr *			op_name;          /* request */
-	char *				op_stateid;       /* response */
-	struct nfs4_change_info	*	op_cinfo;         /* response */
-	u32 *				op_rflags;        /* response */
-};
-#define op_attrs     u.attrs
-#define op_verifier  u.verifier
-
-struct nfs4_open_confirm {
-	char *				oc_stateid;       /* request */
-};
-
-struct nfs4_putfh {
-	struct nfs_fh *			pf_fhandle;       /* request */
-};
-
-struct nfs4_readdir {
-	u64				rd_cookie;        /* request */
-	nfs4_verifier			rd_req_verifier;  /* request */
-	u32				rd_count;         /* request */
-	u32				rd_bmval[2];      /* request */	
-	nfs4_verifier			rd_resp_verifier; /* response */
-	struct page **			rd_pages;   /* zero-copy data */
-	unsigned int			rd_pgbase;  /* zero-copy data */
+struct nfs4_link_arg {
+	const struct nfs_fh *		fh;
+	const struct nfs_fh *		dir_fh;
+	const struct qstr *		name;
+};
+
+struct nfs4_lookup_arg {
+	const struct nfs_fh *		dir_fh;
+	const struct qstr *		name;
+	const u32 *			bitmask;
+};
+
+struct nfs4_lookup_res {
+	const struct nfs_server *	server;
+	struct nfs_fattr *		fattr;
+	struct nfs_fh *			fh;
+};
+
+struct nfs4_lookup_root_arg {
+	const u32 *			bitmask;
+};
+
+struct nfs4_pathconf_arg {
+	const struct nfs_fh *		fh;
+	const u32 *			bitmask;
+};
+
+struct nfs4_readdir_arg {
+	const struct nfs_fh *		fh;
+	u64				cookie;
+	nfs4_verifier			verifier;
+	u32				count;
+	struct page **			pages;	/* zero-copy data */
+	unsigned int			pgbase;	/* zero-copy data */
+};
+
+struct nfs4_readdir_res {
+	nfs4_verifier			verifier;
+	unsigned int			pgbase;
 };
 
 struct nfs4_readlink {
-	u32				rl_count;   /* zero-copy data */
-	struct page **			rl_pages;   /* zero-copy data */
+	const struct nfs_fh *		fh;
+	u32				count;   /* zero-copy data */
+	struct page **			pages;   /* zero-copy data */
 };
 
-struct nfs4_remove {
-	u32				rm_namelen;       /* request */
-	const char *			rm_name;          /* request */
-	struct nfs4_change_info *	rm_cinfo;         /* response */
+struct nfs4_remove_arg {
+	const struct nfs_fh *		fh;
+	const struct qstr *		name;
 };
 
-struct nfs4_rename {
-	u32				rn_oldnamelen;    /* request */
-	const char *			rn_oldname;       /* request */
-	u32				rn_newnamelen;    /* request */
-	const char *			rn_newname;       /* request */
-	struct nfs4_change_info	*	rn_src_cinfo;     /* response */
-	struct nfs4_change_info *	rn_dst_cinfo;     /* response */
+struct nfs4_rename_arg {
+	const struct nfs_fh *		old_dir;
+	const struct nfs_fh *		new_dir;
+	const struct qstr *		old_name;
+	const struct qstr *		new_name;
 };
 
-struct nfs4_setattr {
-	char *				st_stateid;       /* request */
-	struct iattr *			st_iap;           /* request */
+struct nfs4_rename_res {
+	struct nfs4_change_info		old_cinfo;
+	struct nfs4_change_info		new_cinfo;
 };
 
 struct nfs4_setclientid {
@@ -608,52 +606,16 @@ struct nfs4_setclientid {
 	struct nfs4_client *		sc_state;	  /* response */
 };
 
-struct nfs4_op {
-	u32				opnum;
-	union {
-		struct nfs4_access	access;
-		struct nfs4_close	close;
-		struct nfs4_create	create;
-		struct nfs4_getattr	getattr;
-		struct nfs4_getfh	getfh;
-		struct nfs4_link	link;
-		struct nfs4_lookup	lookup;
-		struct nfs4_open	open;
-		struct nfs4_open_confirm open_confirm;
-		struct nfs4_putfh	putfh;
-		struct nfs4_readdir	readdir;
-		struct nfs4_readlink	readlink;
-		struct nfs4_remove	remove;
-		struct nfs4_rename	rename;
-		struct nfs4_client *	renew;
-		struct nfs4_setattr	setattr;
-	} u;
+struct nfs4_statfs_arg {
+	const struct nfs_fh *		fh;
+	const u32 *			bitmask;
 };
 
-struct nfs4_compound {
-	unsigned int		flags;   /* defined below */
-	struct nfs_server *	server;
-
-	/* RENEW information */
-	int			renew_index;
-	unsigned long		timestamp;
-
-	/* scratch variables for XDR encode/decode */
-	int			nops;
-	u32 *			p;
-	u32 *			end;
-
-	/* the individual COMPOUND operations */
-	struct nfs4_op		*ops;
-
-	/* request */
-	int			req_nops;
-	u32			taglen;
-	char *			tag;
-	
-	/* response */
-	int			resp_nops;
-	int			toplevel_status;
+struct nfs4_server_caps_res {
+	u32				attr_bitmask[2];
+	u32				acl_bitmask;
+	u32				has_links;
+	u32				has_symlinks;
 };
 
 #endif /* CONFIG_NFS_V4 */
diff -puN include/linux/sunrpc/xdr.h~nfsv4-updates include/linux/sunrpc/xdr.h
--- 25/include/linux/sunrpc/xdr.h~nfsv4-updates	2004-04-03 15:03:11.258757560 -0800
+++ 25-akpm/include/linux/sunrpc/xdr.h	2004-04-03 15:03:11.322747832 -0800
@@ -55,7 +55,8 @@ struct xdr_buf {
 	unsigned int	page_base,	/* Start of page data */
 			page_len;	/* Length of page data */
 
-	unsigned int	len;		/* Total length of data */
+	unsigned int	buflen,		/* Total length of storage buffer */
+			len;		/* Length of XDR encoded message */
 
 };
 
@@ -87,7 +88,8 @@ struct xdr_buf {
 /*
  * Miscellaneous XDR helper functions
  */
-u32 *	xdr_encode_array(u32 *p, const void *s, unsigned int len);
+u32 *	xdr_encode_opaque_fixed(u32 *p, const void *ptr, unsigned int len);
+u32 *	xdr_encode_opaque(u32 *p, const void *ptr, unsigned int len);
 u32 *	xdr_encode_string(u32 *p, const char *s);
 u32 *	xdr_decode_string(u32 *p, char **sp, int *lenp, int maxlen);
 u32 *	xdr_decode_string_inplace(u32 *p, char **sp, int *lenp, int maxlen);
@@ -100,6 +102,11 @@ void	xdr_encode_pages(struct xdr_buf *, 
 void	xdr_inline_pages(struct xdr_buf *, unsigned int,
 			 struct page **, unsigned int, unsigned int);
 
+static inline u32 *xdr_encode_array(u32 *p, const void *s, unsigned int len)
+{
+	return xdr_encode_opaque(p, s, len);
+}
+
 /*
  * Decode 64bit quantities (NFSv3 support)
  */
@@ -178,86 +185,14 @@ struct xdr_stream {
 	struct iovec *iov;	/* pointer to the current iovec */
 };
 
-/*
- * Initialize an xdr_stream for encoding data.
- *
- * Note: at the moment the RPC client only passes the length of our
- *	 scratch buffer in the xdr_buf's header iovec. Previously this
- *	 meant we needed to call xdr_adjust_iovec() after encoding the
- *	 data. With the new scheme, the xdr_stream manages the details
- *	 of the buffer length, and takes care of adjusting the iovec
- *	 length for us.
- */
-static inline void
-xdr_init_encode(struct xdr_stream *xdr, struct xdr_buf *buf, uint32_t *p)
-{
-	struct iovec *iov = buf->head;
-
-	xdr->buf = buf;
-	xdr->iov = iov;
-	xdr->end = (uint32_t *)((char *)iov->iov_base + iov->iov_len);
-	buf->len = iov->iov_len = (char *)p - (char *)iov->iov_base;
-	xdr->p = p;
-}
-
-/*
- * Check that we have enough buffer space to encode 'nbytes' more
- * bytes of data. If so, update the total xdr_buf length, and
- * adjust the length of the current iovec.
- */
-static inline uint32_t *
-xdr_reserve_space(struct xdr_stream *xdr, size_t nbytes)
-{
-	uint32_t *p = xdr->p;
-	uint32_t *q;
-
-	/* align nbytes on the next 32-bit boundary */
-	nbytes += 3;
-	nbytes &= ~3;
-	q = p + (nbytes >> 2);
-	if (unlikely(q > xdr->end || q < p))
-		return NULL;
-	xdr->p = q;
-	xdr->iov->iov_len += nbytes;
-	xdr->buf->len += nbytes;
-	return p;
-}
-
+extern void xdr_init_encode(struct xdr_stream *xdr, struct xdr_buf *buf, uint32_t *p);
+extern uint32_t *xdr_reserve_space(struct xdr_stream *xdr, size_t nbytes);
 extern void xdr_write_pages(struct xdr_stream *xdr, struct page **pages,
 		unsigned int base, unsigned int len);
+extern void xdr_init_decode(struct xdr_stream *xdr, struct xdr_buf *buf, uint32_t *p);
+extern uint32_t *xdr_inline_decode(struct xdr_stream *xdr, size_t nbytes);
 extern void xdr_read_pages(struct xdr_stream *xdr, unsigned int len);
 
-/*
- * Initialize an xdr_stream for decoding data.
- */
-static inline void
-xdr_init_decode(struct xdr_stream *xdr, struct xdr_buf *buf, uint32_t *p)
-{
-	struct iovec *iov = buf->head;
-	xdr->buf = buf;
-	xdr->iov = iov;
-	xdr->p = p;
-	xdr->end = (uint32_t *)((char *)iov->iov_base + iov->iov_len);
-}
-
-/*
- * Check if the input buffer is long enough to enable us to decode
- * 'nbytes' more bytes of data starting at the current position.
- * If so return the current pointer, then update the current
- * position.
- */
-static inline uint32_t *
-xdr_inline_decode(struct xdr_stream *xdr, size_t nbytes)
-{
-	uint32_t *p = xdr->p;
-	uint32_t *q = p + XDR_QUADLEN(nbytes);
-
-	if (unlikely(q > xdr->end || q < p))
-		return NULL;
-	xdr->p = q;
-	return p;
-}
-
 #endif /* __KERNEL__ */
 
 #endif /* _SUNRPC_XDR_H_ */
diff -puN include/linux/sunrpc/xprt.h~nfsv4-updates include/linux/sunrpc/xprt.h
--- 25/include/linux/sunrpc/xprt.h~nfsv4-updates	2004-04-03 15:03:11.259757408 -0800
+++ 25-akpm/include/linux/sunrpc/xprt.h	2004-04-03 15:03:11.323747680 -0800
@@ -120,8 +120,6 @@ struct rpc_rqst {
 };
 #define rq_svec			rq_snd_buf.head
 #define rq_slen			rq_snd_buf.len
-#define rq_rvec			rq_rcv_buf.head
-#define rq_rlen			rq_rcv_buf.len
 
 #define XPRT_LAST_FRAG		(1 << 0)
 #define XPRT_COPY_RECM		(1 << 1)
diff -puN net/sunrpc/auth_gss/auth_gss.c~nfsv4-updates net/sunrpc/auth_gss/auth_gss.c
--- 25/net/sunrpc/auth_gss/auth_gss.c~nfsv4-updates	2004-04-03 15:03:11.260757256 -0800
+++ 25-akpm/net/sunrpc/auth_gss/auth_gss.c	2004-04-03 15:03:11.324747528 -0800
@@ -721,8 +721,7 @@ gss_marshal(struct rpc_task *task, u32 *
 		printk("gss_marshal: gss_get_mic FAILED (%d)\n", maj_stat);
 		goto out_put_ctx;
 	}
-	*p++ = htonl(mic.len);
-	p += XDR_QUADLEN(mic.len);
+	p = xdr_encode_opaque(p, NULL, mic.len);
 	gss_put_ctx(ctx);
 	return p;
 out_put_ctx:
@@ -857,9 +856,7 @@ gss_wrap_req(struct rpc_task *task,
 			status = -EIO; /* XXX? */
 			if (maj_stat)
 				goto out;
-			q = p;
-			*q++ = htonl(mic.len);
-			q += XDR_QUADLEN(mic.len);
+			q = xdr_encode_opaque(p, NULL, mic.len);
 
 			offset = (u8 *)q - (u8 *)p;
 			iov->iov_len += offset;
diff -puN net/sunrpc/clnt.c~nfsv4-updates net/sunrpc/clnt.c
--- 25/net/sunrpc/clnt.c~nfsv4-updates	2004-04-03 15:03:11.262756952 -0800
+++ 25-akpm/net/sunrpc/clnt.c	2004-04-03 15:03:11.325747376 -0800
@@ -605,11 +605,13 @@ call_encode(struct rpc_task *task)
 	sndbuf->tail[0].iov_len  = 0;
 	sndbuf->page_len	 = 0;
 	sndbuf->len		 = 0;
+	sndbuf->buflen		 = bufsiz;
 	rcvbuf->head[0].iov_base = (void *)((char *)task->tk_buffer + bufsiz);
 	rcvbuf->head[0].iov_len  = bufsiz;
 	rcvbuf->tail[0].iov_len  = 0;
 	rcvbuf->page_len	 = 0;
-	rcvbuf->len		 = bufsiz;
+	rcvbuf->len		 = 0;
+	rcvbuf->buflen		 = bufsiz;
 
 	/* Encode header and provided arguments */
 	encode = task->tk_msg.rpc_proc->p_encode;
@@ -849,6 +851,8 @@ call_decode(struct rpc_task *task)
 		return;
 	}
 
+	req->rq_rcv_buf.len = req->rq_private_buf.len;
+
 	/* Check that the softirq receive buffer is valid */
 	WARN_ON(memcmp(&req->rq_rcv_buf, &req->rq_private_buf,
 				sizeof(req->rq_rcv_buf)) != 0);
@@ -884,7 +888,7 @@ call_decode(struct rpc_task *task)
 					task->tk_status);
 	return;
 out_retry:
-	req->rq_received = 0;
+	req->rq_received = req->rq_private_buf.len = 0;
 	task->tk_status = 0;
 }
 
@@ -956,7 +960,7 @@ call_header(struct rpc_task *task)
 static u32 *
 call_verify(struct rpc_task *task)
 {
-	u32	*p = task->tk_rqstp->rq_rvec[0].iov_base, n;
+	u32	*p = task->tk_rqstp->rq_rcv_buf.head[0].iov_base, n;
 
 	p += 1;	/* skip XID */
 
diff -puN net/sunrpc/sunrpc_syms.c~nfsv4-updates net/sunrpc/sunrpc_syms.c
--- 25/net/sunrpc/sunrpc_syms.c~nfsv4-updates	2004-04-03 15:03:11.274755128 -0800
+++ 25-akpm/net/sunrpc/sunrpc_syms.c	2004-04-03 15:03:11.325747376 -0800
@@ -120,7 +120,6 @@ EXPORT_SYMBOL(svcauth_unix_purge);
 EXPORT_SYMBOL(unix_domain_find);
 
 /* Generic XDR */
-EXPORT_SYMBOL(xdr_encode_array);
 EXPORT_SYMBOL(xdr_encode_string);
 EXPORT_SYMBOL(xdr_decode_string);
 EXPORT_SYMBOL(xdr_decode_string_inplace);
@@ -129,8 +128,6 @@ EXPORT_SYMBOL(xdr_encode_netobj);
 EXPORT_SYMBOL(xdr_encode_pages);
 EXPORT_SYMBOL(xdr_inline_pages);
 EXPORT_SYMBOL(xdr_shift_buf);
-EXPORT_SYMBOL(xdr_write_pages);
-EXPORT_SYMBOL(xdr_read_pages);
 EXPORT_SYMBOL(xdr_buf_from_iov);
 EXPORT_SYMBOL(xdr_buf_subsegment);
 EXPORT_SYMBOL(xdr_buf_read_netobj);
diff -puN net/sunrpc/xdr.c~nfsv4-updates net/sunrpc/xdr.c
--- 25/net/sunrpc/xdr.c~nfsv4-updates	2004-04-03 15:03:11.275754976 -0800
+++ 25-akpm/net/sunrpc/xdr.c	2004-04-03 15:03:11.327747072 -0800
@@ -53,16 +53,50 @@ xdr_decode_netobj(u32 *p, struct xdr_net
 	return p + XDR_QUADLEN(len);
 }
 
-u32 *
-xdr_encode_array(u32 *p, const void *array, unsigned int len)
+/**
+ * xdr_encode_opaque_fixed - Encode fixed length opaque data
+ * @p - pointer to current position in XDR buffer.
+ * @ptr - pointer to data to encode (or NULL)
+ * @nbytes - size of data.
+ *
+ * Copy the array of data of length nbytes at ptr to the XDR buffer
+ * at position p, then align to the next 32-bit boundary by padding
+ * with zero bytes (see RFC1832).
+ * Note: if ptr is NULL, only the padding is performed.
+ *
+ * Returns the updated current XDR buffer position
+ *
+ */
+u32 *xdr_encode_opaque_fixed(u32 *p, const void *ptr, unsigned int nbytes)
 {
-	int quadlen = XDR_QUADLEN(len);
-
-	p[quadlen] = 0;
-	*p++ = htonl(len);
-	memcpy(p, array, len);
-	return p + quadlen;
+	if (likely(nbytes != 0)) {
+		unsigned int quadlen = XDR_QUADLEN(nbytes);
+		unsigned int padding = (quadlen << 2) - nbytes;
+
+		if (ptr != NULL)
+			memcpy(p, ptr, nbytes);
+		if (padding != 0)
+			memset((char *)p + nbytes, 0, padding);
+		p += quadlen;
+	}
+	return p;
+}
+EXPORT_SYMBOL(xdr_encode_opaque_fixed);
+
+/**
+ * xdr_encode_opaque - Encode variable length opaque data
+ * @p - pointer to current position in XDR buffer.
+ * @ptr - pointer to data to encode (or NULL)
+ * @nbytes - size of data.
+ *
+ * Returns the updated current XDR buffer position
+ */
+u32 *xdr_encode_opaque(u32 *p, const void *ptr, unsigned int nbytes)
+{
+	*p++ = htonl(nbytes);
+	return xdr_encode_opaque_fixed(p, ptr, nbytes);
 }
+EXPORT_SYMBOL(xdr_encode_opaque);
 
 u32 *
 xdr_encode_string(u32 *p, const char *string)
@@ -126,6 +160,7 @@ xdr_encode_pages(struct xdr_buf *xdr, st
 		tail->iov_len  = pad;
 		len += pad;
 	}
+	xdr->buflen += len;
 	xdr->len += len;
 }
 
@@ -147,7 +182,7 @@ xdr_inline_pages(struct xdr_buf *xdr, un
 	tail->iov_base = buf + offset;
 	tail->iov_len = buflen - offset;
 
-	xdr->len += len;
+	xdr->buflen += len;
 }
 
 /*
@@ -641,7 +676,10 @@ xdr_shrink_bufhead(struct xdr_buf *buf, 
 				copy);
 	}
 	head->iov_len -= len;
-	buf->len -= len;
+	buf->buflen -= len;
+	/* Have we truncated the message? */
+	if (buf->len > buf->buflen)
+		buf->len = buf->buflen;
 }
 
 /*
@@ -671,7 +709,7 @@ xdr_shrink_pagelen(struct xdr_buf *buf, 
 			copy = tail->iov_len - len;
 			memmove(p, tail->iov_base, copy);
 		} else
-			buf->len -= len;
+			buf->buflen -= len;
 		/* Copy from the inlined pages into the tail */
 		copy = len;
 		if (copy > tail->iov_len)
@@ -681,7 +719,10 @@ xdr_shrink_pagelen(struct xdr_buf *buf, 
 				copy);
 	}
 	buf->page_len -= len;
-	buf->len -= len;
+	buf->buflen -= len;
+	/* Have we truncated the message? */
+	if (buf->len > buf->buflen)
+		buf->len = buf->buflen;
 }
 
 void
@@ -690,8 +731,67 @@ xdr_shift_buf(struct xdr_buf *buf, size_
 	xdr_shrink_bufhead(buf, len);
 }
 
-void
-xdr_write_pages(struct xdr_stream *xdr, struct page **pages, unsigned int base,
+/**
+ * xdr_init_encode - Initialize a struct xdr_stream for sending data.
+ * @xdr: pointer to xdr_stream struct
+ * @buf: pointer to XDR buffer in which to encode data
+ * @p: current pointer inside XDR buffer
+ *
+ * Note: at the moment the RPC client only passes the length of our
+ *	 scratch buffer in the xdr_buf's header iovec. Previously this
+ *	 meant we needed to call xdr_adjust_iovec() after encoding the
+ *	 data. With the new scheme, the xdr_stream manages the details
+ *	 of the buffer length, and takes care of adjusting the iovec
+ *	 length for us.
+ */
+void xdr_init_encode(struct xdr_stream *xdr, struct xdr_buf *buf, uint32_t *p)
+{
+	struct iovec *iov = buf->head;
+
+	xdr->buf = buf;
+	xdr->iov = iov;
+	xdr->end = (uint32_t *)((char *)iov->iov_base + iov->iov_len);
+	buf->len = iov->iov_len = (char *)p - (char *)iov->iov_base;
+	xdr->p = p;
+}
+EXPORT_SYMBOL(xdr_init_encode);
+
+/**
+ * xdr_reserve_space - Reserve buffer space for sending
+ * @xdr: pointer to xdr_stream
+ * @nbytes: number of bytes to reserve
+ *
+ * Checks that we have enough buffer space to encode 'nbytes' more
+ * bytes of data. If so, update the total xdr_buf length, and
+ * adjust the length of the current iovec.
+ */
+uint32_t * xdr_reserve_space(struct xdr_stream *xdr, size_t nbytes)
+{
+	uint32_t *p = xdr->p;
+	uint32_t *q;
+
+	/* align nbytes on the next 32-bit boundary */
+	nbytes += 3;
+	nbytes &= ~3;
+	q = p + (nbytes >> 2);
+	if (unlikely(q > xdr->end || q < p))
+		return NULL;
+	xdr->p = q;
+	xdr->iov->iov_len += nbytes;
+	xdr->buf->len += nbytes;
+	return p;
+}
+EXPORT_SYMBOL(xdr_reserve_space);
+
+/**
+ * xdr_write_pages - Insert a list of pages into an XDR buffer for sending
+ * @xdr: pointer to xdr_stream
+ * @pages: list of pages
+ * @base: offset of first byte
+ * @len: length of data in bytes
+ *
+ */
+void xdr_write_pages(struct xdr_stream *xdr, struct page **pages, unsigned int base,
 		 unsigned int len)
 {
 	struct xdr_buf *buf = xdr->buf;
@@ -713,15 +813,69 @@ xdr_write_pages(struct xdr_stream *xdr, 
 		len += pad;
 		*xdr->p++ = 0;
 	}
+	buf->buflen += len;
 	buf->len += len;
 }
+EXPORT_SYMBOL(xdr_write_pages);
 
-void
-xdr_read_pages(struct xdr_stream *xdr, unsigned int len)
+/**
+ * xdr_init_decode - Initialize an xdr_stream for decoding data.
+ * @xdr: pointer to xdr_stream struct
+ * @buf: pointer to XDR buffer from which to decode data
+ * @p: current pointer inside XDR buffer
+ */
+void xdr_init_decode(struct xdr_stream *xdr, struct xdr_buf *buf, uint32_t *p)
+{
+	struct iovec *iov = buf->head;
+	unsigned int len = iov->iov_len;
+
+	if (len > buf->len)
+		len = buf->len;
+	xdr->buf = buf;
+	xdr->iov = iov;
+	xdr->p = p;
+	xdr->end = (uint32_t *)((char *)iov->iov_base + len);
+}
+EXPORT_SYMBOL(xdr_init_decode);
+
+/**
+ * xdr_inline_decode - Retrieve non-page XDR data to decode
+ * @xdr: pointer to xdr_stream struct
+ * @nbytes: number of bytes of data to decode
+ *
+ * Check if the input buffer is long enough to enable us to decode
+ * 'nbytes' more bytes of data starting at the current position.
+ * If so return the current pointer, then update the current
+ * pointer position.
+ */
+uint32_t * xdr_inline_decode(struct xdr_stream *xdr, size_t nbytes)
+{
+	uint32_t *p = xdr->p;
+	uint32_t *q = p + XDR_QUADLEN(nbytes);
+
+	if (unlikely(q > xdr->end || q < p))
+		return NULL;
+	xdr->p = q;
+	return p;
+}
+EXPORT_SYMBOL(xdr_inline_decode);
+
+/**
+ * xdr_read_pages - Ensure page-based XDR data to decode is aligned at current pointer position
+ * @xdr: pointer to xdr_stream struct
+ * @len: number of bytes of page data
+ *
+ * Moves data beyond the current pointer position from the XDR head[] buffer
+ * into the page list. Any data that lies beyond current position + "len"
+ * bytes is moved into the XDR tail[]. The current pointer is then
+ * repositioned at the beginning of the XDR tail.
+ */
+void xdr_read_pages(struct xdr_stream *xdr, unsigned int len)
 {
 	struct xdr_buf *buf = xdr->buf;
 	struct iovec *iov;
 	ssize_t shift;
+	unsigned int end;
 	int padding;
 
 	/* Realign pages to current pointer position */
@@ -735,9 +889,21 @@ xdr_read_pages(struct xdr_stream *xdr, u
 		xdr_shrink_pagelen(buf, buf->page_len - len);
 	padding = (XDR_QUADLEN(len) << 2) - len;
 	xdr->iov = iov = buf->tail;
+	/* Compute remaining message length.  */
+	end = iov->iov_len;
+	shift = buf->buflen - buf->len;
+	if (shift < end)
+		end -= shift;
+	else if (shift > 0)
+		end = 0;
+	/*
+	 * Position current pointer at beginning of tail, and
+	 * set remaining message length.
+	 */
 	xdr->p = (uint32_t *)((char *)iov->iov_base + padding);
-	xdr->end = (uint32_t *)((char *)iov->iov_base + iov->iov_len);
+	xdr->end = (uint32_t *)((char *)iov->iov_base + end);
 }
+EXPORT_SYMBOL(xdr_read_pages);
 
 static struct iovec empty_iov = {.iov_base = NULL, .iov_len = 0};
 
@@ -747,7 +913,7 @@ xdr_buf_from_iov(struct iovec *iov, stru
 	buf->head[0] = *iov;
 	buf->tail[0] = empty_iov;
 	buf->page_len = 0;
-	buf->len = iov->iov_len;
+	buf->buflen = buf->len = iov->iov_len;
 }
 
 /* Sets subiov to the intersection of iov with the buffer of length len
@@ -777,7 +943,7 @@ xdr_buf_subsegment(struct xdr_buf *buf, 
 {
 	int i;
 
-	subbuf->len = len;
+	subbuf->buflen = subbuf->len = len;
 	iov_subsegment(buf->head, subbuf->head, &base, &len);
 
 	if (base < buf->page_len) {
diff -puN net/sunrpc/xprt.c~nfsv4-updates net/sunrpc/xprt.c
--- 25/net/sunrpc/xprt.c~nfsv4-updates	2004-04-03 15:03:11.276754824 -0800
+++ 25-akpm/net/sunrpc/xprt.c	2004-04-03 15:03:11.329746768 -0800
@@ -647,8 +647,8 @@ xprt_complete_rqst(struct rpc_xprt *xprt
 #endif
 
 	dprintk("RPC: %4d has input (%d bytes)\n", task->tk_pid, copied);
-	req->rq_received = copied;
 	list_del_init(&req->rq_list);
+	req->rq_received = req->rq_private_buf.len = copied;
 
 	/* ... and wake up the process. */
 	rpc_wake_up_task(task);
@@ -765,7 +765,7 @@ udp_data_ready(struct sock *sk, int len)
 
 	dprintk("RPC: %4d received reply\n", task->tk_pid);
 
-	if ((copied = rovr->rq_private_buf.len) > repsize)
+	if ((copied = rovr->rq_private_buf.buflen) > repsize)
 		copied = repsize;
 
 	/* Suck it into the iovec, verify checksum if not done by hw. */
@@ -908,7 +908,7 @@ tcp_read_request(struct rpc_xprt *xprt, 
 	xprt->tcp_copied += len;
 	xprt->tcp_offset += len;
 
-	if (xprt->tcp_copied == req->rq_private_buf.len)
+	if (xprt->tcp_copied == req->rq_private_buf.buflen)
 		xprt->tcp_flags &= ~XPRT_COPY_DATA;
 	else if (xprt->tcp_offset == xprt->tcp_reclen) {
 		if (xprt->tcp_flags & XPRT_LAST_FRAG)

_