Merge branch 'bugfixes' into nfs-for-2.6.38
authorTrond Myklebust <Trond.Myklebust@netapp.com>
Mon, 10 Jan 2011 19:48:02 +0000 (14:48 -0500)
committerTrond Myklebust <Trond.Myklebust@netapp.com>
Mon, 10 Jan 2011 19:48:02 +0000 (14:48 -0500)
Conflicts:
fs/nfs/nfs2xdr.c
fs/nfs/nfs3xdr.c
fs/nfs/nfs4xdr.c

1  2 
fs/nfs/dir.c
fs/nfs/nfs2xdr.c
fs/nfs/nfs3xdr.c
fs/nfs/nfs4xdr.c
include/linux/sunrpc/xdr.h

diff --combined fs/nfs/dir.c
@@@ -33,9 -33,7 +33,8 @@@
  #include <linux/namei.h>
  #include <linux/mount.h>
  #include <linux/sched.h>
- #include <linux/vmalloc.h>
  #include <linux/kmemleak.h>
 +#include <linux/xattr.h>
  
  #include "delegation.h"
  #include "iostat.h"
@@@ -126,10 -124,9 +125,10 @@@ const struct inode_operations nfs4_dir_
        .permission     = nfs_permission,
        .getattr        = nfs_getattr,
        .setattr        = nfs_setattr,
 -      .getxattr       = nfs4_getxattr,
 -      .setxattr       = nfs4_setxattr,
 -      .listxattr      = nfs4_listxattr,
 +      .getxattr       = generic_getxattr,
 +      .setxattr       = generic_setxattr,
 +      .listxattr      = generic_listxattr,
 +      .removexattr    = generic_removexattr,
  };
  
  #endif /* CONFIG_NFS_V4 */
@@@ -174,7 -171,7 +173,7 @@@ struct nfs_cache_array 
        struct nfs_cache_array_entry array[0];
  };
  
 -typedef __be32 * (*decode_dirent_t)(struct xdr_stream *, struct nfs_entry *, struct nfs_server *, int);
 +typedef int (*decode_dirent_t)(struct xdr_stream *, struct nfs_entry *, int);
  typedef struct {
        struct file     *file;
        struct page     *page;
@@@ -380,14 -377,14 +379,14 @@@ error
        return error;
  }
  
 -/* Fill in an entry based on the xdr code stored in desc->page */
 -static
 -int xdr_decode(nfs_readdir_descriptor_t *desc, struct nfs_entry *entry, struct xdr_stream *stream)
 +static int xdr_decode(nfs_readdir_descriptor_t *desc,
 +                    struct nfs_entry *entry, struct xdr_stream *xdr)
  {
 -      __be32 *p = desc->decode(stream, entry, NFS_SERVER(desc->file->f_path.dentry->d_inode), desc->plus);
 -      if (IS_ERR(p))
 -              return PTR_ERR(p);
 +      int error;
  
 +      error = desc->decode(xdr, entry, desc->plus);
 +      if (error)
 +              return error;
        entry->fattr->time_start = desc->timestamp;
        entry->fattr->gencount = desc->gencount;
        return 0;
@@@ -461,25 -458,26 +460,26 @@@ out
  /* Perform conversion from xdr to cache array */
  static
  int nfs_readdir_page_filler(nfs_readdir_descriptor_t *desc, struct nfs_entry *entry,
-                               void *xdr_page, struct page *page, unsigned int buflen)
+                               struct page **xdr_pages, struct page *page, unsigned int buflen)
  {
        struct xdr_stream stream;
-       struct xdr_buf buf;
-       __be32 *ptr = xdr_page;
+       struct xdr_buf buf = {
+               .pages = xdr_pages,
+               .page_len = buflen,
+               .buflen = buflen,
+               .len = buflen,
+       };
+       struct page *scratch;
        struct nfs_cache_array *array;
        unsigned int count = 0;
        int status;
  
-       buf.head->iov_base = xdr_page;
-       buf.head->iov_len = buflen;
-       buf.tail->iov_len = 0;
-       buf.page_base = 0;
-       buf.page_len = 0;
-       buf.buflen = buf.head->iov_len;
-       buf.len = buf.head->iov_len;
-       xdr_init_decode(&stream, &buf, ptr);
+       scratch = alloc_page(GFP_KERNEL);
+       if (scratch == NULL)
+               return -ENOMEM;
  
+       xdr_init_decode(&stream, &buf, NULL);
+       xdr_set_scratch_buffer(&stream, page_address(scratch), PAGE_SIZE);
  
        do {
                status = xdr_decode(desc, entry, &stream);
                } else
                        status = PTR_ERR(array);
        }
+       put_page(scratch);
        return status;
  }
  
@@@ -523,7 -523,6 +525,6 @@@ stati
  void nfs_readdir_free_large_page(void *ptr, struct page **pages,
                unsigned int npages)
  {
-       vm_unmap_ram(ptr, npages);
        nfs_readdir_free_pagearray(pages, npages);
  }
  
   * to nfs_readdir_free_large_page
   */
  static
void *nfs_readdir_large_page(struct page **pages, unsigned int npages)
int nfs_readdir_large_page(struct page **pages, unsigned int npages)
  {
-       void *ptr;
        unsigned int i;
  
        for (i = 0; i < npages; i++) {
                        goto out_freepages;
                pages[i] = page;
        }
+       return 0;
  
-       ptr = vm_map_ram(pages, npages, 0, PAGE_KERNEL);
-       if (!IS_ERR_OR_NULL(ptr))
-               return ptr;
  out_freepages:
        nfs_readdir_free_pagearray(pages, i);
-       return NULL;
+       return -ENOMEM;
  }
  
  static
@@@ -568,7 -564,6 +566,7 @@@ int nfs_readdir_xdr_to_array(nfs_readdi
        entry.eof = 0;
        entry.fh = nfs_alloc_fhandle();
        entry.fattr = nfs_alloc_fattr();
 +      entry.server = NFS_SERVER(inode);
        if (entry.fh == NULL || entry.fattr == NULL)
                goto out;
  
        memset(array, 0, sizeof(struct nfs_cache_array));
        array->eof_index = -1;
  
-       pages_ptr = nfs_readdir_large_page(pages, array_size);
-       if (!pages_ptr)
+       status = nfs_readdir_large_page(pages, array_size);
+       if (status < 0)
                goto out_release_array;
        do {
                unsigned int pglen;
                if (status < 0)
                        break;
                pglen = status;
-               status = nfs_readdir_page_filler(desc, &entry, pages_ptr, page, pglen);
+               status = nfs_readdir_page_filler(desc, &entry, pages, page, pglen);
                if (status < 0) {
                        if (status == -ENOSPC)
                                status = 0;
@@@ -1220,7 -1215,7 +1218,7 @@@ static struct dentry *nfs_lookup(struc
                goto out_unblock_sillyrename;
        }
        inode = nfs_fhget(dentry->d_sb, fhandle, fattr);
 -      res = (struct dentry *)inode;
 +      res = ERR_CAST(inode);
        if (IS_ERR(res))
                goto out_unblock_sillyrename;
  
@@@ -1354,7 -1349,8 +1352,7 @@@ static struct dentry *nfs_atomic_lookup
        if (nd->flags & LOOKUP_CREATE) {
                attr.ia_mode = nd->intent.open.create_mode;
                attr.ia_valid = ATTR_MODE;
 -              if (!IS_POSIXACL(dir))
 -                      attr.ia_mode &= ~current_umask();
 +              attr.ia_mode &= ~current_umask();
        } else {
                open_flags &= ~(O_EXCL | O_CREAT);
                attr.ia_valid = 0;
diff --combined fs/nfs/nfs2xdr.c
  #define NFS_readdirres_sz     (1)
  #define NFS_statfsres_sz      (1+NFS_info_sz)
  
 +
 +/*
 + * While encoding arguments, set up the reply buffer in advance to
 + * receive reply data directly into the page cache.
 + */
 +static void prepare_reply_buffer(struct rpc_rqst *req, struct page **pages,
 +                               unsigned int base, unsigned int len,
 +                               unsigned int bufsize)
 +{
 +      struct rpc_auth *auth = req->rq_cred->cr_auth;
 +      unsigned int replen;
 +
 +      replen = RPC_REPHDRSIZE + auth->au_rslack + bufsize;
 +      xdr_inline_pages(&req->rq_rcv_buf, replen << 2, pages, base, len);
 +}
 +
  /*
 - * Common NFS XDR functions as inlines
 + * Handle decode buffer overflows out-of-line.
   */
 -static inline __be32 *
 -xdr_encode_fhandle(__be32 *p, const struct nfs_fh *fhandle)
 +static void print_overflow_msg(const char *func, const struct xdr_stream *xdr)
  {
 -      memcpy(p, fhandle->data, NFS2_FHSIZE);
 -      return p + XDR_QUADLEN(NFS2_FHSIZE);
 +      dprintk("NFS: %s prematurely hit the end of our receive buffer. "
 +              "Remaining buffer length is %tu words.\n",
 +              func, xdr->end - xdr->p);
  }
  
 -static inline __be32 *
 -xdr_decode_fhandle(__be32 *p, struct nfs_fh *fhandle)
 +
 +/*
 + * Encode/decode NFSv2 basic data types
 + *
 + * Basic NFSv2 data types are defined in section 2.3 of RFC 1094:
 + * "NFS: Network File System Protocol Specification".
 + *
 + * Not all basic data types have their own encoding and decoding
 + * functions.  For run-time efficiency, some data types are encoded
 + * or decoded inline.
 + */
 +
 +/*
 + *    typedef opaque  nfsdata<>;
 + */
 +static int decode_nfsdata(struct xdr_stream *xdr, struct nfs_readres *result)
  {
 -      /* NFSv2 handles have a fixed length */
 -      fhandle->size = NFS2_FHSIZE;
 -      memcpy(fhandle->data, p, NFS2_FHSIZE);
 -      return p + XDR_QUADLEN(NFS2_FHSIZE);
 +      u32 recvd, count;
 +      size_t hdrlen;
 +      __be32 *p;
 +
 +      p = xdr_inline_decode(xdr, 4);
 +      if (unlikely(p == NULL))
 +              goto out_overflow;
 +      count = be32_to_cpup(p);
 +      hdrlen = (u8 *)xdr->p - (u8 *)xdr->iov->iov_base;
 +      recvd = xdr->buf->len - hdrlen;
 +      if (unlikely(count > recvd))
 +              goto out_cheating;
 +out:
 +      xdr_read_pages(xdr, count);
 +      result->eof = 0;        /* NFSv2 does not pass EOF flag on the wire. */
 +      result->count = count;
 +      return count;
 +out_cheating:
 +      dprintk("NFS: server cheating in read result: "
 +              "count %u > recvd %u\n", count, recvd);
 +      count = recvd;
 +      goto out;
 +out_overflow:
 +      print_overflow_msg(__func__, xdr);
 +      return -EIO;
  }
  
 -static inline __be32*
 -xdr_encode_time(__be32 *p, struct timespec *timep)
 +/*
 + *    enum stat {
 + *            NFS_OK = 0,
 + *            NFSERR_PERM = 1,
 + *            NFSERR_NOENT = 2,
 + *            NFSERR_IO = 5,
 + *            NFSERR_NXIO = 6,
 + *            NFSERR_ACCES = 13,
 + *            NFSERR_EXIST = 17,
 + *            NFSERR_NODEV = 19,
 + *            NFSERR_NOTDIR = 20,
 + *            NFSERR_ISDIR = 21,
 + *            NFSERR_FBIG = 27,
 + *            NFSERR_NOSPC = 28,
 + *            NFSERR_ROFS = 30,
 + *            NFSERR_NAMETOOLONG = 63,
 + *            NFSERR_NOTEMPTY = 66,
 + *            NFSERR_DQUOT = 69,
 + *            NFSERR_STALE = 70,
 + *            NFSERR_WFLUSH = 99
 + *    };
 + */
 +static int decode_stat(struct xdr_stream *xdr, enum nfs_stat *status)
  {
 -      *p++ = htonl(timep->tv_sec);
 -      /* Convert nanoseconds into microseconds */
 -      *p++ = htonl(timep->tv_nsec ? timep->tv_nsec / 1000 : 0);
 +      __be32 *p;
 +
 +      p = xdr_inline_decode(xdr, 4);
 +      if (unlikely(p == NULL))
 +              goto out_overflow;
 +      *status = be32_to_cpup(p);
 +      return 0;
 +out_overflow:
 +      print_overflow_msg(__func__, xdr);
 +      return -EIO;
 +}
 +
 +/*
 + * 2.3.2.  ftype
 + *
 + *    enum ftype {
 + *            NFNON = 0,
 + *            NFREG = 1,
 + *            NFDIR = 2,
 + *            NFBLK = 3,
 + *            NFCHR = 4,
 + *            NFLNK = 5
 + *    };
 + *
 + */
 +static __be32 *xdr_decode_ftype(__be32 *p, u32 *type)
 +{
 +      *type = be32_to_cpup(p++);
 +      if (unlikely(*type > NF2FIFO))
 +              *type = NFBAD;
        return p;
  }
  
 -static inline __be32*
 -xdr_encode_current_server_time(__be32 *p, struct timespec *timep)
 +/*
 + * 2.3.3.  fhandle
 + *
 + *    typedef opaque fhandle[FHSIZE];
 + */
 +static void encode_fhandle(struct xdr_stream *xdr, const struct nfs_fh *fh)
 +{
 +      __be32 *p;
 +
 +      BUG_ON(fh->size != NFS2_FHSIZE);
 +      p = xdr_reserve_space(xdr, NFS2_FHSIZE);
 +      memcpy(p, fh->data, NFS2_FHSIZE);
 +}
 +
 +static int decode_fhandle(struct xdr_stream *xdr, struct nfs_fh *fh)
  {
 -      /*
 -       * Passing the invalid value useconds=1000000 is a
 -       * Sun convention for "set to current server time".
 -       * It's needed to make permissions checks for the
 -       * "touch" program across v2 mounts to Solaris and
 -       * Irix boxes work correctly. See description of
 -       * sattr in section 6.1 of "NFS Illustrated" by
 -       * Brent Callaghan, Addison-Wesley, ISBN 0-201-32750-5
 -       */
 -      *p++ = htonl(timep->tv_sec);
 -      *p++ = htonl(1000000);
 +      __be32 *p;
 +
 +      p = xdr_inline_decode(xdr, NFS2_FHSIZE);
 +      if (unlikely(p == NULL))
 +              goto out_overflow;
 +      fh->size = NFS2_FHSIZE;
 +      memcpy(fh->data, p, NFS2_FHSIZE);
 +      return 0;
 +out_overflow:
 +      print_overflow_msg(__func__, xdr);
 +      return -EIO;
 +}
 +
 +/*
 + * 2.3.4.  timeval
 + *
 + *    struct timeval {
 + *            unsigned int seconds;
 + *            unsigned int useconds;
 + *    };
 + */
 +static __be32 *xdr_encode_time(__be32 *p, const struct timespec *timep)
 +{
 +      *p++ = cpu_to_be32(timep->tv_sec);
 +      if (timep->tv_nsec != 0)
 +              *p++ = cpu_to_be32(timep->tv_nsec / NSEC_PER_USEC);
 +      else
 +              *p++ = cpu_to_be32(0);
 +      return p;
 +}
 +
 +/*
 + * Passing the invalid value useconds=1000000 is a Sun convention for
 + * "set to current server time".  It's needed to make permissions checks
 + * for the "touch" program across v2 mounts to Solaris and Irix servers
 + * work correctly.  See description of sattr in section 6.1 of "NFS
 + * Illustrated" by Brent Callaghan, Addison-Wesley, ISBN 0-201-32750-5.
 + */
 +static __be32 *xdr_encode_current_server_time(__be32 *p,
 +                                            const struct timespec *timep)
 +{
 +      *p++ = cpu_to_be32(timep->tv_sec);
 +      *p++ = cpu_to_be32(1000000);
        return p;
  }
  
 -static inline __be32*
 -xdr_decode_time(__be32 *p, struct timespec *timep)
 +static __be32 *xdr_decode_time(__be32 *p, struct timespec *timep)
  {
 -      timep->tv_sec = ntohl(*p++);
 -      /* Convert microseconds into nanoseconds */
 -      timep->tv_nsec = ntohl(*p++) * 1000;
 +      timep->tv_sec = be32_to_cpup(p++);
 +      timep->tv_nsec = be32_to_cpup(p++) * NSEC_PER_USEC;
        return p;
  }
  
 -static __be32 *
 -xdr_decode_fattr(__be32 *p, struct nfs_fattr *fattr)
 +/*
 + * 2.3.5.  fattr
 + *
 + *    struct fattr {
 + *            ftype           type;
 + *            unsigned int    mode;
 + *            unsigned int    nlink;
 + *            unsigned int    uid;
 + *            unsigned int    gid;
 + *            unsigned int    size;
 + *            unsigned int    blocksize;
 + *            unsigned int    rdev;
 + *            unsigned int    blocks;
 + *            unsigned int    fsid;
 + *            unsigned int    fileid;
 + *            timeval         atime;
 + *            timeval         mtime;
 + *            timeval         ctime;
 + *    };
 + *
 + */
 +static int decode_fattr(struct xdr_stream *xdr, struct nfs_fattr *fattr)
  {
        u32 rdev, type;
 -      type = ntohl(*p++);
 -      fattr->mode = ntohl(*p++);
 -      fattr->nlink = ntohl(*p++);
 -      fattr->uid = ntohl(*p++);
 -      fattr->gid = ntohl(*p++);
 -      fattr->size = ntohl(*p++);
 -      fattr->du.nfs2.blocksize = ntohl(*p++);
 -      rdev = ntohl(*p++);
 -      fattr->du.nfs2.blocks = ntohl(*p++);
 -      fattr->fsid.major = ntohl(*p++);
 -      fattr->fsid.minor = 0;
 -      fattr->fileid = ntohl(*p++);
 -      p = xdr_decode_time(p, &fattr->atime);
 -      p = xdr_decode_time(p, &fattr->mtime);
 -      p = xdr_decode_time(p, &fattr->ctime);
 +      __be32 *p;
 +
 +      p = xdr_inline_decode(xdr, NFS_fattr_sz << 2);
 +      if (unlikely(p == NULL))
 +              goto out_overflow;
 +
        fattr->valid |= NFS_ATTR_FATTR_V2;
 +
 +      p = xdr_decode_ftype(p, &type);
 +
 +      fattr->mode = be32_to_cpup(p++);
 +      fattr->nlink = be32_to_cpup(p++);
 +      fattr->uid = be32_to_cpup(p++);
 +      fattr->gid = be32_to_cpup(p++);
 +      fattr->size = be32_to_cpup(p++);
 +      fattr->du.nfs2.blocksize = be32_to_cpup(p++);
 +
 +      rdev = be32_to_cpup(p++);
        fattr->rdev = new_decode_dev(rdev);
 -      if (type == NFCHR && rdev == NFS2_FIFO_DEV) {
 +      if (type == (u32)NFCHR && rdev == (u32)NFS2_FIFO_DEV) {
                fattr->mode = (fattr->mode & ~S_IFMT) | S_IFIFO;
                fattr->rdev = 0;
        }
 -      return p;
 +
 +      fattr->du.nfs2.blocks = be32_to_cpup(p++);
 +      fattr->fsid.major = be32_to_cpup(p++);
 +      fattr->fsid.minor = 0;
 +      fattr->fileid = be32_to_cpup(p++);
 +
 +      p = xdr_decode_time(p, &fattr->atime);
 +      p = xdr_decode_time(p, &fattr->mtime);
 +      xdr_decode_time(p, &fattr->ctime);
 +      return 0;
 +out_overflow:
 +      print_overflow_msg(__func__, xdr);
 +      return -EIO;
  }
  
 -static inline __be32 *
 -xdr_encode_sattr(__be32 *p, struct iattr *attr)
 +/*
 + * 2.3.6.  sattr
 + *
 + *    struct sattr {
 + *            unsigned int    mode;
 + *            unsigned int    uid;
 + *            unsigned int    gid;
 + *            unsigned int    size;
 + *            timeval         atime;
 + *            timeval         mtime;
 + *    };
 + */
 +
 +#define NFS2_SATTR_NOT_SET    (0xffffffff)
 +
 +static __be32 *xdr_time_not_set(__be32 *p)
  {
 -      const __be32 not_set = __constant_htonl(0xFFFFFFFF);
 +      *p++ = cpu_to_be32(NFS2_SATTR_NOT_SET);
 +      *p++ = cpu_to_be32(NFS2_SATTR_NOT_SET);
 +      return p;
 +}
  
 -      *p++ = (attr->ia_valid & ATTR_MODE) ? htonl(attr->ia_mode) : not_set;
 -      *p++ = (attr->ia_valid & ATTR_UID) ? htonl(attr->ia_uid) : not_set;
 -      *p++ = (attr->ia_valid & ATTR_GID) ? htonl(attr->ia_gid) : not_set;
 -      *p++ = (attr->ia_valid & ATTR_SIZE) ? htonl(attr->ia_size) : not_set;
 +static void encode_sattr(struct xdr_stream *xdr, const struct iattr *attr)
 +{
 +      __be32 *p;
  
 -      if (attr->ia_valid & ATTR_ATIME_SET) {
 +      p = xdr_reserve_space(xdr, NFS_sattr_sz << 2);
 +
 +      if (attr->ia_valid & ATTR_MODE)
 +              *p++ = cpu_to_be32(attr->ia_mode);
 +      else
 +              *p++ = cpu_to_be32(NFS2_SATTR_NOT_SET);
 +      if (attr->ia_valid & ATTR_UID)
 +              *p++ = cpu_to_be32(attr->ia_uid);
 +      else
 +              *p++ = cpu_to_be32(NFS2_SATTR_NOT_SET);
 +      if (attr->ia_valid & ATTR_GID)
 +              *p++ = cpu_to_be32(attr->ia_gid);
 +      else
 +              *p++ = cpu_to_be32(NFS2_SATTR_NOT_SET);
 +      if (attr->ia_valid & ATTR_SIZE)
 +              *p++ = cpu_to_be32((u32)attr->ia_size);
 +      else
 +              *p++ = cpu_to_be32(NFS2_SATTR_NOT_SET);
 +
 +      if (attr->ia_valid & ATTR_ATIME_SET)
                p = xdr_encode_time(p, &attr->ia_atime);
 -      } else if (attr->ia_valid & ATTR_ATIME) {
 +      else if (attr->ia_valid & ATTR_ATIME)
                p = xdr_encode_current_server_time(p, &attr->ia_atime);
 -      } else {
 -              *p++ = not_set;
 -              *p++ = not_set;
 -      }
 -
 -      if (attr->ia_valid & ATTR_MTIME_SET) {
 -              p = xdr_encode_time(p, &attr->ia_mtime);
 -      } else if (attr->ia_valid & ATTR_MTIME) {
 -              p = xdr_encode_current_server_time(p, &attr->ia_mtime);
 -      } else {
 -              *p++ = not_set; 
 -              *p++ = not_set;
 -      }
 -      return p;
 +      else
 +              p = xdr_time_not_set(p);
 +      if (attr->ia_valid & ATTR_MTIME_SET)
 +              xdr_encode_time(p, &attr->ia_mtime);
 +      else if (attr->ia_valid & ATTR_MTIME)
 +              xdr_encode_current_server_time(p, &attr->ia_mtime);
 +      else
 +              xdr_time_not_set(p);
  }
  
  /*
 - * NFS encode functions
 + * 2.3.7.  filename
 + *
 + *    typedef string filename<MAXNAMLEN>;
   */
 +static void encode_filename(struct xdr_stream *xdr,
 +                          const char *name, u32 length)
 +{
 +      __be32 *p;
 +
 +      BUG_ON(length > NFS2_MAXNAMLEN);
 +      p = xdr_reserve_space(xdr, 4 + length);
 +      xdr_encode_opaque(p, name, length);
 +}
 +
 +static int decode_filename_inline(struct xdr_stream *xdr,
 +                                const char **name, u32 *length)
 +{
 +      __be32 *p;
 +      u32 count;
 +
 +      p = xdr_inline_decode(xdr, 4);
 +      if (unlikely(p == NULL))
 +              goto out_overflow;
 +      count = be32_to_cpup(p);
 +      if (count > NFS3_MAXNAMLEN)
 +              goto out_nametoolong;
 +      p = xdr_inline_decode(xdr, count);
 +      if (unlikely(p == NULL))
 +              goto out_overflow;
 +      *name = (const char *)p;
 +      *length = count;
 +      return 0;
 +out_nametoolong:
 +      dprintk("NFS: returned filename too long: %u\n", count);
 +      return -ENAMETOOLONG;
 +out_overflow:
 +      print_overflow_msg(__func__, xdr);
 +      return -EIO;
 +}
 +
  /*
 - * Encode file handle argument
 - * GETATTR, READLINK, STATFS
 + * 2.3.8.  path
 + *
 + *    typedef string path<MAXPATHLEN>;
   */
 -static int
 -nfs_xdr_fhandle(struct rpc_rqst *req, __be32 *p, struct nfs_fh *fh)
 +static void encode_path(struct xdr_stream *xdr, struct page **pages, u32 length)
  {
 -      p = xdr_encode_fhandle(p, fh);
 -      req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
 +      __be32 *p;
 +
 +      BUG_ON(length > NFS2_MAXPATHLEN);
 +      p = xdr_reserve_space(xdr, 4);
 +      *p = cpu_to_be32(length);
 +      xdr_write_pages(xdr, pages, 0, length);
 +}
 +
 +static int decode_path(struct xdr_stream *xdr)
 +{
 +      u32 length, recvd;
 +      size_t hdrlen;
 +      __be32 *p;
 +
 +      p = xdr_inline_decode(xdr, 4);
 +      if (unlikely(p == NULL))
 +              goto out_overflow;
 +      length = be32_to_cpup(p);
 +      if (unlikely(length >= xdr->buf->page_len || length > NFS_MAXPATHLEN))
 +              goto out_size;
 +      hdrlen = (u8 *)xdr->p - (u8 *)xdr->iov->iov_base;
 +      recvd = xdr->buf->len - hdrlen;
 +      if (unlikely(length > recvd))
 +              goto out_cheating;
 +
 +      xdr_read_pages(xdr, length);
 +      xdr_terminate_string(xdr->buf, length);
        return 0;
 +out_size:
 +      dprintk("NFS: returned pathname too long: %u\n", length);
 +      return -ENAMETOOLONG;
 +out_cheating:
 +      dprintk("NFS: server cheating in pathname result: "
 +              "length %u > received %u\n", length, recvd);
 +      return -EIO;
 +out_overflow:
 +      print_overflow_msg(__func__, xdr);
 +      return -EIO;
  }
  
  /*
 - * Encode SETATTR arguments
 + * 2.3.9.  attrstat
 + *
 + *    union attrstat switch (stat status) {
 + *    case NFS_OK:
 + *            fattr attributes;
 + *    default:
 + *            void;
 + *    };
   */
 -static int
 -nfs_xdr_sattrargs(struct rpc_rqst *req, __be32 *p, struct nfs_sattrargs *args)
 +static int decode_attrstat(struct xdr_stream *xdr, struct nfs_fattr *result)
  {
 -      p = xdr_encode_fhandle(p, args->fh);
 -      p = xdr_encode_sattr(p, args->sattr);
 -      req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
 -      return 0;
 +      enum nfs_stat status;
 +      int error;
 +
 +      error = decode_stat(xdr, &status);
 +      if (unlikely(error))
 +              goto out;
 +      if (status != NFS_OK)
 +              goto out_default;
 +      error = decode_fattr(xdr, result);
 +out:
 +      return error;
 +out_default:
 +      return nfs_stat_to_errno(status);
  }
  
  /*
 - * Encode directory ops argument
 - * LOOKUP, RMDIR
 + * 2.3.10.  diropargs
 + *
 + *    struct diropargs {
 + *            fhandle  dir;
 + *            filename name;
 + *    };
   */
 -static int
 -nfs_xdr_diropargs(struct rpc_rqst *req, __be32 *p, struct nfs_diropargs *args)
 +static void encode_diropargs(struct xdr_stream *xdr, const struct nfs_fh *fh,
 +                           const char *name, u32 length)
  {
 -      p = xdr_encode_fhandle(p, args->fh);
 -      p = xdr_encode_array(p, args->name, args->len);
 -      req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
 -      return 0;
 +      encode_fhandle(xdr, fh);
 +      encode_filename(xdr, name, length);
 +}
 +
 +/*
 + * 2.3.11.  diropres
 + *
 + *    union diropres switch (stat status) {
 + *    case NFS_OK:
 + *            struct {
 + *                    fhandle file;
 + *                    fattr   attributes;
 + *            } diropok;
 + *    default:
 + *            void;
 + *    };
 + */
 +static int decode_diropok(struct xdr_stream *xdr, struct nfs_diropok *result)
 +{
 +      int error;
 +
 +      error = decode_fhandle(xdr, result->fh);
 +      if (unlikely(error))
 +              goto out;
 +      error = decode_fattr(xdr, result->fattr);
 +out:
 +      return error;
  }
  
 +static int decode_diropres(struct xdr_stream *xdr, struct nfs_diropok *result)
 +{
 +      enum nfs_stat status;
 +      int error;
 +
 +      error = decode_stat(xdr, &status);
 +      if (unlikely(error))
 +              goto out;
 +      if (status != NFS_OK)
 +              goto out_default;
 +      error = decode_diropok(xdr, result);
 +out:
 +      return error;
 +out_default:
 +      return nfs_stat_to_errno(status);
 +}
 +
 +
  /*
 - * Encode REMOVE argument
 + * NFSv2 XDR encode functions
 + *
 + * NFSv2 argument types are defined in section 2.2 of RFC 1094:
 + * "NFS: Network File System Protocol Specification".
   */
 -static int
 -nfs_xdr_removeargs(struct rpc_rqst *req, __be32 *p, const struct nfs_removeargs *args)
 +
 +static void nfs2_xdr_enc_fhandle(struct rpc_rqst *req,
 +                               struct xdr_stream *xdr,
 +                               const struct nfs_fh *fh)
  {
 -      p = xdr_encode_fhandle(p, args->fh);
 -      p = xdr_encode_array(p, args->name.name, args->name.len);
 -      req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
 -      return 0;
 +      encode_fhandle(xdr, fh);
  }
  
  /*
 - * Arguments to a READ call. Since we read data directly into the page
 - * cache, we also set up the reply iovec here so that iov[1] points
 - * exactly to the page we want to fetch.
 + * 2.2.3.  sattrargs
 + *
 + *    struct sattrargs {
 + *            fhandle file;
 + *            sattr attributes;
 + *    };
   */
 -static int
 -nfs_xdr_readargs(struct rpc_rqst *req, __be32 *p, struct nfs_readargs *args)
 +static void nfs2_xdr_enc_sattrargs(struct rpc_rqst *req,
 +                                 struct xdr_stream *xdr,
 +                                 const struct nfs_sattrargs *args)
  {
 -      struct rpc_auth *auth = req->rq_cred->cr_auth;
 -      unsigned int replen;
 -      u32 offset = (u32)args->offset;
 +      encode_fhandle(xdr, args->fh);
 +      encode_sattr(xdr, args->sattr);
 +}
 +
 +static void nfs2_xdr_enc_diropargs(struct rpc_rqst *req,
 +                                 struct xdr_stream *xdr,
 +                                 const struct nfs_diropargs *args)
 +{
 +      encode_diropargs(xdr, args->fh, args->name, args->len);
 +}
 +
 +static void nfs2_xdr_enc_readlinkargs(struct rpc_rqst *req,
 +                                    struct xdr_stream *xdr,
 +                                    const struct nfs_readlinkargs *args)
 +{
 +      encode_fhandle(xdr, args->fh);
 +      prepare_reply_buffer(req, args->pages, args->pgbase,
 +                                      args->pglen, NFS_readlinkres_sz);
 +}
 +
 +/*
 + * 2.2.7.  readargs
 + *
 + *    struct readargs {
 + *            fhandle file;
 + *            unsigned offset;
 + *            unsigned count;
 + *            unsigned totalcount;
 + *    };
 + */
 +static void encode_readargs(struct xdr_stream *xdr,
 +                          const struct nfs_readargs *args)
 +{
 +      u32 offset = args->offset;
        u32 count = args->count;
 +      __be32 *p;
 +
 +      encode_fhandle(xdr, args->fh);
  
 -      p = xdr_encode_fhandle(p, args->fh);
 -      *p++ = htonl(offset);
 -      *p++ = htonl(count);
 -      *p++ = htonl(count);
 -      req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
 +      p = xdr_reserve_space(xdr, 4 + 4 + 4);
 +      *p++ = cpu_to_be32(offset);
 +      *p++ = cpu_to_be32(count);
 +      *p = cpu_to_be32(count);
 +}
  
 -      /* Inline the page array */
 -      replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS_readres_sz) << 2;
 -      xdr_inline_pages(&req->rq_rcv_buf, replen,
 -                       args->pages, args->pgbase, count);
 +static void nfs2_xdr_enc_readargs(struct rpc_rqst *req,
 +                                struct xdr_stream *xdr,
 +                                const struct nfs_readargs *args)
 +{
 +      encode_readargs(xdr, args);
 +      prepare_reply_buffer(req, args->pages, args->pgbase,
 +                                      args->count, NFS_readres_sz);
        req->rq_rcv_buf.flags |= XDRBUF_READ;
 -      return 0;
  }
  
  /*
 - * Decode READ reply
 + * 2.2.9.  writeargs
 + *
 + *    struct writeargs {
 + *            fhandle file;
 + *            unsigned beginoffset;
 + *            unsigned offset;
 + *            unsigned totalcount;
 + *            nfsdata data;
 + *    };
   */
 -static int
 -nfs_xdr_readres(struct rpc_rqst *req, __be32 *p, struct nfs_readres *res)
 +static void encode_writeargs(struct xdr_stream *xdr,
 +                           const struct nfs_writeargs *args)
  {
 -      struct kvec *iov = req->rq_rcv_buf.head;
 -      size_t hdrlen;
 -      u32 count, recvd;
 -      int status;
 -
 -      if ((status = ntohl(*p++)))
 -              return nfs_stat_to_errno(status);
 -      p = xdr_decode_fattr(p, res->fattr);
 -
 -      count = ntohl(*p++);
 -      res->eof = 0;
 -      hdrlen = (u8 *) p - (u8 *) iov->iov_base;
 -      if (iov->iov_len < hdrlen) {
 -              dprintk("NFS: READ reply header overflowed:"
 -                              "length %Zu > %Zu\n", hdrlen, iov->iov_len);
 -              return -errno_NFSERR_IO;
 -      } else if (iov->iov_len != hdrlen) {
 -              dprintk("NFS: READ header is short. iovec will be shifted.\n");
 -              xdr_shift_buf(&req->rq_rcv_buf, iov->iov_len - hdrlen);
 -      }
 +      u32 offset = args->offset;
 +      u32 count = args->count;
 +      __be32 *p;
  
 -      recvd = req->rq_rcv_buf.len - hdrlen;
 -      if (count > recvd) {
 -              dprintk("NFS: server cheating in read reply: "
 -                      "count %u > recvd %u\n", count, recvd);
 -              count = recvd;
 -      }
 +      encode_fhandle(xdr, args->fh);
  
 -      dprintk("RPC:      readres OK count %u\n", count);
 -      if (count < res->count)
 -              res->count = count;
 +      p = xdr_reserve_space(xdr, 4 + 4 + 4 + 4);
 +      *p++ = cpu_to_be32(offset);
 +      *p++ = cpu_to_be32(offset);
 +      *p++ = cpu_to_be32(count);
  
 -      return count;
 +      /* nfsdata */
 +      *p = cpu_to_be32(count);
 +      xdr_write_pages(xdr, args->pages, args->pgbase, count);
  }
  
 +static void nfs2_xdr_enc_writeargs(struct rpc_rqst *req,
 +                                 struct xdr_stream *xdr,
 +                                 const struct nfs_writeargs *args)
 +{
 +      encode_writeargs(xdr, args);
 +      xdr->buf->flags |= XDRBUF_WRITE;
 +}
  
  /*
 - * Write arguments. Splice the buffer to be written into the iovec.
 + * 2.2.10.  createargs
 + *
 + *    struct createargs {
 + *            diropargs where;
 + *            sattr attributes;
 + *    };
   */
 -static int
 -nfs_xdr_writeargs(struct rpc_rqst *req, __be32 *p, struct nfs_writeargs *args)
 +static void nfs2_xdr_enc_createargs(struct rpc_rqst *req,
 +                                  struct xdr_stream *xdr,
 +                                  const struct nfs_createargs *args)
  {
 -      struct xdr_buf *sndbuf = &req->rq_snd_buf;
 -      u32 offset = (u32)args->offset;
 -      u32 count = args->count;
 -
 -      p = xdr_encode_fhandle(p, args->fh);
 -      *p++ = htonl(offset);
 -      *p++ = htonl(offset);
 -      *p++ = htonl(count);
 -      *p++ = htonl(count);
 -      sndbuf->len = xdr_adjust_iovec(sndbuf->head, p);
 +      encode_diropargs(xdr, args->fh, args->name, args->len);
 +      encode_sattr(xdr, args->sattr);
 +}
  
 -      /* Copy the page array */
 -      xdr_encode_pages(sndbuf, args->pages, args->pgbase, count);
 -      sndbuf->flags |= XDRBUF_WRITE;
 -      return 0;
 +static void nfs2_xdr_enc_removeargs(struct rpc_rqst *req,
 +                                  struct xdr_stream *xdr,
 +                                  const struct nfs_removeargs *args)
 +{
 +      encode_diropargs(xdr, args->fh, args->name.name, args->name.len);
  }
  
  /*
 - * Encode create arguments
 - * CREATE, MKDIR
 + * 2.2.12.  renameargs
 + *
 + *    struct renameargs {
 + *            diropargs from;
 + *            diropargs to;
 + *    };
   */
 -static int
 -nfs_xdr_createargs(struct rpc_rqst *req, __be32 *p, struct nfs_createargs *args)
 +static void nfs2_xdr_enc_renameargs(struct rpc_rqst *req,
 +                                  struct xdr_stream *xdr,
 +                                  const struct nfs_renameargs *args)
  {
 -      p = xdr_encode_fhandle(p, args->fh);
 -      p = xdr_encode_array(p, args->name, args->len);
 -      p = xdr_encode_sattr(p, args->sattr);
 -      req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
 -      return 0;
 +      const struct qstr *old = args->old_name;
 +      const struct qstr *new = args->new_name;
 +
 +      encode_diropargs(xdr, args->old_dir, old->name, old->len);
 +      encode_diropargs(xdr, args->new_dir, new->name, new->len);
  }
  
  /*
 - * Encode RENAME arguments
 + * 2.2.13.  linkargs
 + *
 + *    struct linkargs {
 + *            fhandle from;
 + *            diropargs to;
 + *    };
   */
 -static int
 -nfs_xdr_renameargs(struct rpc_rqst *req, __be32 *p, struct nfs_renameargs *args)
 +static void nfs2_xdr_enc_linkargs(struct rpc_rqst *req,
 +                                struct xdr_stream *xdr,
 +                                const struct nfs_linkargs *args)
  {
 -      p = xdr_encode_fhandle(p, args->old_dir);
 -      p = xdr_encode_array(p, args->old_name->name, args->old_name->len);
 -      p = xdr_encode_fhandle(p, args->new_dir);
 -      p = xdr_encode_array(p, args->new_name->name, args->new_name->len);
 -      req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
 -      return 0;
 +      encode_fhandle(xdr, args->fromfh);
 +      encode_diropargs(xdr, args->tofh, args->toname, args->tolen);
  }
  
  /*
 - * Encode LINK arguments
 + * 2.2.14.  symlinkargs
 + *
 + *    struct symlinkargs {
 + *            diropargs from;
 + *            path to;
 + *            sattr attributes;
 + *    };
   */
 -static int
 -nfs_xdr_linkargs(struct rpc_rqst *req, __be32 *p, struct nfs_linkargs *args)
 +static void nfs2_xdr_enc_symlinkargs(struct rpc_rqst *req,
 +                                   struct xdr_stream *xdr,
 +                                   const struct nfs_symlinkargs *args)
  {
 -      p = xdr_encode_fhandle(p, args->fromfh);
 -      p = xdr_encode_fhandle(p, args->tofh);
 -      p = xdr_encode_array(p, args->toname, args->tolen);
 -      req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
 -      return 0;
 +      encode_diropargs(xdr, args->fromfh, args->fromname, args->fromlen);
 +      encode_path(xdr, args->pages, args->pathlen);
 +      encode_sattr(xdr, args->sattr);
  }
  
  /*
 - * Encode SYMLINK arguments
 + * 2.2.17.  readdirargs
 + *
 + *    struct readdirargs {
 + *            fhandle dir;
 + *            nfscookie cookie;
 + *            unsigned count;
 + *    };
   */
 -static int
 -nfs_xdr_symlinkargs(struct rpc_rqst *req, __be32 *p, struct nfs_symlinkargs *args)
 +static void encode_readdirargs(struct xdr_stream *xdr,
 +                             const struct nfs_readdirargs *args)
  {
 -      struct xdr_buf *sndbuf = &req->rq_snd_buf;
 -      size_t pad;
 +      __be32 *p;
  
 -      p = xdr_encode_fhandle(p, args->fromfh);
 -      p = xdr_encode_array(p, args->fromname, args->fromlen);
 -      *p++ = htonl(args->pathlen);
 -      sndbuf->len = xdr_adjust_iovec(sndbuf->head, p);
 +      encode_fhandle(xdr, args->fh);
  
 -      xdr_encode_pages(sndbuf, args->pages, 0, args->pathlen);
 +      p = xdr_reserve_space(xdr, 4 + 4);
 +      *p++ = cpu_to_be32(args->cookie);
 +      *p = cpu_to_be32(args->count);
 +}
  
 -      /*
 -       * xdr_encode_pages may have added a few bytes to ensure the
 -       * pathname ends on a 4-byte boundary.  Start encoding the
 -       * attributes after the pad bytes.
 -       */
 -      pad = sndbuf->tail->iov_len;
 -      if (pad > 0)
 -              p++;
 -      p = xdr_encode_sattr(p, args->sattr);
 -      sndbuf->len += xdr_adjust_iovec(sndbuf->tail, p) - pad;
 -      return 0;
 +static void nfs2_xdr_enc_readdirargs(struct rpc_rqst *req,
 +                                   struct xdr_stream *xdr,
 +                                   const struct nfs_readdirargs *args)
 +{
 +      encode_readdirargs(xdr, args);
 +      prepare_reply_buffer(req, args->pages, 0,
 +                                      args->count, NFS_readdirres_sz);
  }
  
  /*
 - * Encode arguments to readdir call
 + * NFSv2 XDR decode functions
 + *
 + * NFSv2 result types are defined in section 2.2 of RFC 1094:
 + * "NFS: Network File System Protocol Specification".
   */
 -static int
 -nfs_xdr_readdirargs(struct rpc_rqst *req, __be32 *p, struct nfs_readdirargs *args)
 +
 +static int nfs2_xdr_dec_stat(struct rpc_rqst *req, struct xdr_stream *xdr,
 +                           void *__unused)
  {
 -      struct rpc_auth *auth = req->rq_cred->cr_auth;
 -      unsigned int replen;
 -      u32 count = args->count;
 +      enum nfs_stat status;
 +      int error;
 +
 +      error = decode_stat(xdr, &status);
 +      if (unlikely(error))
 +              goto out;
 +      if (status != NFS_OK)
 +              goto out_default;
 +out:
 +      return error;
 +out_default:
 +      return nfs_stat_to_errno(status);
 +}
  
 -      p = xdr_encode_fhandle(p, args->fh);
 -      *p++ = htonl(args->cookie);
 -      *p++ = htonl(count); /* see above */
 -      req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
 +static int nfs2_xdr_dec_attrstat(struct rpc_rqst *req, struct xdr_stream *xdr,
 +                               struct nfs_fattr *result)
 +{
 +      return decode_attrstat(xdr, result);
 +}
  
 -      /* Inline the page array */
 -      replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS_readdirres_sz) << 2;
 -      xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, 0, count);
 -      return 0;
 +static int nfs2_xdr_dec_diropres(struct rpc_rqst *req, struct xdr_stream *xdr,
 +                               struct nfs_diropok *result)
 +{
 +      return decode_diropres(xdr, result);
  }
  
  /*
 - * Decode the result of a readdir call.
 - * We're not really decoding anymore, we just leave the buffer untouched
 - * and only check that it is syntactically correct.
 - * The real decoding happens in nfs_decode_entry below, called directly
 - * from nfs_readdir for each entry.
 + * 2.2.6.  readlinkres
 + *
 + *    union readlinkres switch (stat status) {
 + *    case NFS_OK:
 + *            path data;
 + *    default:
 + *            void;
 + *    };
   */
 -static int
 -nfs_xdr_readdirres(struct rpc_rqst *req, __be32 *p, void *dummy)
 +static int nfs2_xdr_dec_readlinkres(struct rpc_rqst *req,
 +                                  struct xdr_stream *xdr, void *__unused)
  {
 -      struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
 -      struct kvec *iov = rcvbuf->head;
 -      struct page **page;
 -      size_t hdrlen;
 -      unsigned int pglen, recvd;
 -      int status;
 -
 -      if ((status = ntohl(*p++)))
 -              return nfs_stat_to_errno(status);
 -
 -      hdrlen = (u8 *) p - (u8 *) iov->iov_base;
 -      if (iov->iov_len < hdrlen) {
 -              dprintk("NFS: READDIR reply header overflowed:"
 -                              "length %Zu > %Zu\n", hdrlen, iov->iov_len);
 -              return -errno_NFSERR_IO;
 -      } else if (iov->iov_len != hdrlen) {
 -              dprintk("NFS: READDIR header is short. iovec will be shifted.\n");
 -              xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen);
 -      }
 +      enum nfs_stat status;
 +      int error;
 +
 +      error = decode_stat(xdr, &status);
 +      if (unlikely(error))
 +              goto out;
 +      if (status != NFS_OK)
 +              goto out_default;
 +      error = decode_path(xdr);
 +out:
 +      return error;
 +out_default:
 +      return nfs_stat_to_errno(status);
 +}
  
 -      pglen = rcvbuf->page_len;
 -      recvd = rcvbuf->len - hdrlen;
 -      if (pglen > recvd)
 -              pglen = recvd;
 -      page = rcvbuf->pages;
 -      return pglen;
 +/*
 + * 2.2.7.  readres
 + *
 + *    union readres switch (stat status) {
 + *    case NFS_OK:
 + *            fattr attributes;
 + *            nfsdata data;
 + *    default:
 + *            void;
 + *    };
 + */
 +static int nfs2_xdr_dec_readres(struct rpc_rqst *req, struct xdr_stream *xdr,
 +                              struct nfs_readres *result)
 +{
 +      enum nfs_stat status;
 +      int error;
 +
 +      error = decode_stat(xdr, &status);
 +      if (unlikely(error))
 +              goto out;
 +      if (status != NFS_OK)
 +              goto out_default;
 +      error = decode_fattr(xdr, result->fattr);
 +      if (unlikely(error))
 +              goto out;
 +      error = decode_nfsdata(xdr, result);
 +out:
 +      return error;
 +out_default:
 +      return nfs_stat_to_errno(status);
  }
  
 -static void print_overflow_msg(const char *func, const struct xdr_stream *xdr)
 +static int nfs2_xdr_dec_writeres(struct rpc_rqst *req, struct xdr_stream *xdr,
 +                               struct nfs_writeres *result)
  {
 -      dprintk("nfs: %s: prematurely hit end of receive buffer. "
 -              "Remaining buffer length is %tu words.\n",
 -              func, xdr->end - xdr->p);
 +      /* All NFSv2 writes are "file sync" writes */
 +      result->verf->committed = NFS_FILE_SYNC;
 +      return decode_attrstat(xdr, result->fattr);
  }
  
 -__be32 *
 -nfs_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry, struct nfs_server *server, int plus)
 +/**
 + * nfs2_decode_dirent - Decode a single NFSv2 directory entry stored in
 + *                      the local page cache.
 + * @xdr: XDR stream where entry resides
 + * @entry: buffer to fill in with entry data
 + * @plus: boolean indicating whether this should be a readdirplus entry
 + *
 + * Returns zero if successful, otherwise a negative errno value is
 + * returned.
 + *
 + * This function is not invoked during READDIR reply decoding, but
 + * rather whenever an application invokes the getdents(2) system call
 + * on a directory already in our cache.
 + *
 + * 2.2.17.  entry
 + *
 + *    struct entry {
 + *            unsigned        fileid;
 + *            filename        name;
 + *            nfscookie       cookie;
 + *            entry           *nextentry;
 + *    };
 + */
 +int nfs2_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry,
 +                     int plus)
  {
        __be32 *p;
 +      int error;
 +
        p = xdr_inline_decode(xdr, 4);
 -      if (unlikely(!p))
 +      if (unlikely(p == NULL))
                goto out_overflow;
 -      if (!ntohl(*p++)) {
 +      if (*p++ == xdr_zero) {
                p = xdr_inline_decode(xdr, 4);
 -              if (unlikely(!p))
 +              if (unlikely(p == NULL))
                        goto out_overflow;
 -              if (!ntohl(*p++))
 -                      return ERR_PTR(-EAGAIN);
 +              if (*p++ == xdr_zero)
 +                      return -EAGAIN;
                entry->eof = 1;
 -              return ERR_PTR(-EBADCOOKIE);
 +              return -EBADCOOKIE;
        }
  
 -      p = xdr_inline_decode(xdr, 8);
 -      if (unlikely(!p))
 +      p = xdr_inline_decode(xdr, 4);
 +      if (unlikely(p == NULL))
                goto out_overflow;
 +      entry->ino = be32_to_cpup(p);
  
 -      entry->ino        = ntohl(*p++);
 -      entry->len        = ntohl(*p++);
 +      error = decode_filename_inline(xdr, &entry->name, &entry->len);
 +      if (unlikely(error))
 +              return error;
  
 -      p = xdr_inline_decode(xdr, entry->len + 4);
 -      if (unlikely(!p))
 +      /*
 +       * The type (size and byte order) of nfscookie isn't defined in
 +       * RFC 1094.  This implementation assumes that it's an XDR uint32.
 +       */
 +      entry->prev_cookie = entry->cookie;
 +      p = xdr_inline_decode(xdr, 4);
 +      if (unlikely(p == NULL))
                goto out_overflow;
 -      entry->name       = (const char *) p;
 -      p                += XDR_QUADLEN(entry->len);
 -      entry->prev_cookie        = entry->cookie;
 -      entry->cookie     = ntohl(*p++);
 +      entry->cookie = be32_to_cpup(p);
  
        entry->d_type = DT_UNKNOWN;
  
-       /* Peek at the next entry to see if we're at EOD */
-       p = xdr_inline_peek(xdr, 4 + 4);
-       entry->eof = 0;
-       if (p != NULL)
-               entry->eof = (p[0] == xdr_zero) && (p[1] != xdr_zero);
 -      return p;
 +      return 0;
  
  out_overflow:
        print_overflow_msg(__func__, xdr);
 -      return ERR_PTR(-EAGAIN);
 -}
 -
 -/*
 - * NFS XDR decode functions
 - */
 -/*
 - * Decode simple status reply
 - */
 -static int
 -nfs_xdr_stat(struct rpc_rqst *req, __be32 *p, void *dummy)
 -{
 -      int     status;
 -
 -      if ((status = ntohl(*p++)) != 0)
 -              status = nfs_stat_to_errno(status);
 -      return status;
 +      return -EAGAIN;
  }
  
  /*
 - * Decode attrstat reply
 - * GETATTR, SETATTR, WRITE
 - */
 -static int
 -nfs_xdr_attrstat(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
 -{
 -      int     status;
 -
 -      if ((status = ntohl(*p++)))
 -              return nfs_stat_to_errno(status);
 -      xdr_decode_fattr(p, fattr);
 -      return 0;
 -}
 -
 -/*
 - * Decode diropres reply
 - * LOOKUP, CREATE, MKDIR
 + * 2.2.17.  readdirres
 + *
 + *    union readdirres switch (stat status) {
 + *    case NFS_OK:
 + *            struct {
 + *                    entry *entries;
 + *                    bool eof;
 + *            } readdirok;
 + *    default:
 + *            void;
 + *    };
 + *
 + * Read the directory contents into the page cache, but don't
 + * touch them.  The actual decoding is done by nfs2_decode_dirent()
 + * during subsequent nfs_readdir() calls.
   */
 -static int
 -nfs_xdr_diropres(struct rpc_rqst *req, __be32 *p, struct nfs_diropok *res)
 +static int decode_readdirok(struct xdr_stream *xdr)
  {
 -      int     status;
 +      u32 recvd, pglen;
 +      size_t hdrlen;
  
 -      if ((status = ntohl(*p++)))
 -              return nfs_stat_to_errno(status);
 -      p = xdr_decode_fhandle(p, res->fh);
 -      xdr_decode_fattr(p, res->fattr);
 -      return 0;
 +      pglen = xdr->buf->page_len;
 +      hdrlen = (u8 *)xdr->p - (u8 *)xdr->iov->iov_base;
 +      recvd = xdr->buf->len - hdrlen;
 +      if (unlikely(pglen > recvd))
 +              goto out_cheating;
 +out:
 +      xdr_read_pages(xdr, pglen);
 +      return pglen;
 +out_cheating:
 +      dprintk("NFS: server cheating in readdir result: "
 +              "pglen %u > recvd %u\n", pglen, recvd);
 +      pglen = recvd;
 +      goto out;
  }
  
 -/*
 - * Encode READLINK args
 - */
 -static int
 -nfs_xdr_readlinkargs(struct rpc_rqst *req, __be32 *p, struct nfs_readlinkargs *args)
 +static int nfs2_xdr_dec_readdirres(struct rpc_rqst *req,
 +                                 struct xdr_stream *xdr, void *__unused)
  {
 -      struct rpc_auth *auth = req->rq_cred->cr_auth;
 -      unsigned int replen;
 -
 -      p = xdr_encode_fhandle(p, args->fh);
 -      req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
 -
 -      /* Inline the page array */
 -      replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS_readlinkres_sz) << 2;
 -      xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, args->pgbase, args->pglen);
 -      return 0;
 +      enum nfs_stat status;
 +      int error;
 +
 +      error = decode_stat(xdr, &status);
 +      if (unlikely(error))
 +              goto out;
 +      if (status != NFS_OK)
 +              goto out_default;
 +      error = decode_readdirok(xdr);
 +out:
 +      return error;
 +out_default:
 +      return nfs_stat_to_errno(status);
  }
  
  /*
 - * Decode READLINK reply
 + * 2.2.18.  statfsres
 + *
 + *    union statfsres (stat status) {
 + *    case NFS_OK:
 + *            struct {
 + *                    unsigned tsize;
 + *                    unsigned bsize;
 + *                    unsigned blocks;
 + *                    unsigned bfree;
 + *                    unsigned bavail;
 + *            } info;
 + *    default:
 + *            void;
 + *    };
   */
 -static int
 -nfs_xdr_readlinkres(struct rpc_rqst *req, __be32 *p, void *dummy)
 +static int decode_info(struct xdr_stream *xdr, struct nfs2_fsstat *result)
  {
 -      struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
 -      struct kvec *iov = rcvbuf->head;
 -      size_t hdrlen;
 -      u32 len, recvd;
 -      int     status;
 -
 -      if ((status = ntohl(*p++)))
 -              return nfs_stat_to_errno(status);
 -      /* Convert length of symlink */
 -      len = ntohl(*p++);
 -      if (len >= rcvbuf->page_len) {
 -              dprintk("nfs: server returned giant symlink!\n");
 -              return -ENAMETOOLONG;
 -      }
 -      hdrlen = (u8 *) p - (u8 *) iov->iov_base;
 -      if (iov->iov_len < hdrlen) {
 -              dprintk("NFS: READLINK reply header overflowed:"
 -                              "length %Zu > %Zu\n", hdrlen, iov->iov_len);
 -              return -errno_NFSERR_IO;
 -      } else if (iov->iov_len != hdrlen) {
 -              dprintk("NFS: READLINK header is short. iovec will be shifted.\n");
 -              xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen);
 -      }
 -      recvd = req->rq_rcv_buf.len - hdrlen;
 -      if (recvd < len) {
 -              dprintk("NFS: server cheating in readlink reply: "
 -                              "count %u > recvd %u\n", len, recvd);
 -              return -EIO;
 -      }
 +      __be32 *p;
  
 -      xdr_terminate_string(rcvbuf, len);
 +      p = xdr_inline_decode(xdr, NFS_info_sz << 2);
 +      if (unlikely(p == NULL))
 +              goto out_overflow;
 +      result->tsize  = be32_to_cpup(p++);
 +      result->bsize  = be32_to_cpup(p++);
 +      result->blocks = be32_to_cpup(p++);
 +      result->bfree  = be32_to_cpup(p++);
 +      result->bavail = be32_to_cpup(p);
        return 0;
 +out_overflow:
 +      print_overflow_msg(__func__, xdr);
 +      return -EIO;
  }
  
 -/*
 - * Decode WRITE reply
 - */
 -static int
 -nfs_xdr_writeres(struct rpc_rqst *req, __be32 *p, struct nfs_writeres *res)
 +static int nfs2_xdr_dec_statfsres(struct rpc_rqst *req, struct xdr_stream *xdr,
 +                                struct nfs2_fsstat *result)
  {
 -      res->verf->committed = NFS_FILE_SYNC;
 -      return nfs_xdr_attrstat(req, p, res->fattr);
 +      enum nfs_stat status;
 +      int error;
 +
 +      error = decode_stat(xdr, &status);
 +      if (unlikely(error))
 +              goto out;
 +      if (status != NFS_OK)
 +              goto out_default;
 +      error = decode_info(xdr, result);
 +out:
 +      return error;
 +out_default:
 +      return nfs_stat_to_errno(status);
  }
  
 -/*
 - * Decode STATFS reply
 - */
 -static int
 -nfs_xdr_statfsres(struct rpc_rqst *req, __be32 *p, struct nfs2_fsstat *res)
 -{
 -      int     status;
 -
 -      if ((status = ntohl(*p++)))
 -              return nfs_stat_to_errno(status);
 -
 -      res->tsize  = ntohl(*p++);
 -      res->bsize  = ntohl(*p++);
 -      res->blocks = ntohl(*p++);
 -      res->bfree  = ntohl(*p++);
 -      res->bavail = ntohl(*p++);
 -      return 0;
 -}
  
  /*
   * We need to translate between nfs status return values and
   * the local errno values which may not be the same.
   */
 -static struct {
 +static const struct {
        int stat;
        int errno;
  } nfs_errtbl[] = {
        { -1,                   -EIO            }
  };
  
 -/*
 - * Convert an NFS error code to a local one.
 - * This one is used jointly by NFSv2 and NFSv3.
 +/**
 + * nfs_stat_to_errno - convert an NFS status code to a local errno
 + * @status: NFS status code to convert
 + *
 + * Returns a local errno value, or -EIO if the NFS status code is
 + * not recognized.  This function is used jointly by NFSv2 and NFSv3.
   */
 -int
 -nfs_stat_to_errno(int stat)
 +int nfs_stat_to_errno(enum nfs_stat status)
  {
        int i;
  
        for (i = 0; nfs_errtbl[i].stat != -1; i++) {
 -              if (nfs_errtbl[i].stat == stat)
 +              if (nfs_errtbl[i].stat == (int)status)
                        return nfs_errtbl[i].errno;
        }
 -      dprintk("nfs_stat_to_errno: bad nfs status return value: %d\n", stat);
 +      dprintk("NFS: Unrecognized nfs status value: %u\n", status);
        return nfs_errtbl[i].errno;
  }
  
  #define PROC(proc, argtype, restype, timer)                           \
  [NFSPROC_##proc] = {                                                  \
        .p_proc     =  NFSPROC_##proc,                                  \
 -      .p_encode   =  (kxdrproc_t) nfs_xdr_##argtype,                  \
 -      .p_decode   =  (kxdrproc_t) nfs_xdr_##restype,                  \
 +      .p_encode   =  (kxdreproc_t)nfs2_xdr_enc_##argtype,             \
 +      .p_decode   =  (kxdrdproc_t)nfs2_xdr_dec_##restype,             \
        .p_arglen   =  NFS_##argtype##_sz,                              \
        .p_replen   =  NFS_##restype##_sz,                              \
        .p_timer    =  timer,                                           \
        .p_name     =  #proc,                                           \
        }
  struct rpc_procinfo   nfs_procedures[] = {
 -    PROC(GETATTR,     fhandle,        attrstat, 1),
 -    PROC(SETATTR,     sattrargs,      attrstat, 0),
 -    PROC(LOOKUP,      diropargs,      diropres, 2),
 -    PROC(READLINK,    readlinkargs,   readlinkres, 3),
 -    PROC(READ,                readargs,       readres, 3),
 -    PROC(WRITE,               writeargs,      writeres, 4),
 -    PROC(CREATE,      createargs,     diropres, 0),
 -    PROC(REMOVE,      removeargs,     stat, 0),
 -    PROC(RENAME,      renameargs,     stat, 0),
 -    PROC(LINK,                linkargs,       stat, 0),
 -    PROC(SYMLINK,     symlinkargs,    stat, 0),
 -    PROC(MKDIR,               createargs,     diropres, 0),
 -    PROC(RMDIR,               diropargs,      stat, 0),
 -    PROC(READDIR,     readdirargs,    readdirres, 3),
 -    PROC(STATFS,      fhandle,        statfsres, 0),
 +      PROC(GETATTR,   fhandle,        attrstat,       1),
 +      PROC(SETATTR,   sattrargs,      attrstat,       0),
 +      PROC(LOOKUP,    diropargs,      diropres,       2),
 +      PROC(READLINK,  readlinkargs,   readlinkres,    3),
 +      PROC(READ,      readargs,       readres,        3),
 +      PROC(WRITE,     writeargs,      writeres,       4),
 +      PROC(CREATE,    createargs,     diropres,       0),
 +      PROC(REMOVE,    removeargs,     stat,           0),
 +      PROC(RENAME,    renameargs,     stat,           0),
 +      PROC(LINK,      linkargs,       stat,           0),
 +      PROC(SYMLINK,   symlinkargs,    stat,           0),
 +      PROC(MKDIR,     createargs,     diropres,       0),
 +      PROC(RMDIR,     diropargs,      stat,           0),
 +      PROC(READDIR,   readdirargs,    readdirres,     3),
 +      PROC(STATFS,    fhandle,        statfsres,      0),
  };
  
  struct rpc_version            nfs_version2 = {
diff --combined fs/nfs/nfs3xdr.c
  #define NFS3_filename_sz      (1+(NFS3_MAXNAMLEN>>2))
  #define NFS3_path_sz          (1+(NFS3_MAXPATHLEN>>2))
  #define NFS3_fattr_sz         (21)
 -#define NFS3_wcc_attr_sz              (6)
 +#define NFS3_cookieverf_sz    (NFS3_COOKIEVERFSIZE>>2)
 +#define NFS3_wcc_attr_sz      (6)
  #define NFS3_pre_op_attr_sz   (1+NFS3_wcc_attr_sz)
  #define NFS3_post_op_attr_sz  (1+NFS3_fattr_sz)
 -#define NFS3_wcc_data_sz              (NFS3_pre_op_attr_sz+NFS3_post_op_attr_sz)
 -#define NFS3_fsstat_sz                
 -#define NFS3_fsinfo_sz                
 -#define NFS3_pathconf_sz              
 -#define NFS3_entry_sz         (NFS3_filename_sz+3)
 -
 -#define NFS3_sattrargs_sz     (NFS3_fh_sz+NFS3_sattr_sz+3)
 +#define NFS3_wcc_data_sz      (NFS3_pre_op_attr_sz+NFS3_post_op_attr_sz)
  #define NFS3_diropargs_sz     (NFS3_fh_sz+NFS3_filename_sz)
 -#define NFS3_removeargs_sz    (NFS3_fh_sz+NFS3_filename_sz)
 +
 +#define NFS3_getattrargs_sz   (NFS3_fh_sz)
 +#define NFS3_setattrargs_sz   (NFS3_fh_sz+NFS3_sattr_sz+3)
 +#define NFS3_lookupargs_sz    (NFS3_fh_sz+NFS3_filename_sz)
  #define NFS3_accessargs_sz    (NFS3_fh_sz+1)
  #define NFS3_readlinkargs_sz  (NFS3_fh_sz)
  #define NFS3_readargs_sz      (NFS3_fh_sz+3)
  #define NFS3_mkdirargs_sz     (NFS3_diropargs_sz+NFS3_sattr_sz)
  #define NFS3_symlinkargs_sz   (NFS3_diropargs_sz+1+NFS3_sattr_sz)
  #define NFS3_mknodargs_sz     (NFS3_diropargs_sz+2+NFS3_sattr_sz)
 +#define NFS3_removeargs_sz    (NFS3_fh_sz+NFS3_filename_sz)
  #define NFS3_renameargs_sz    (NFS3_diropargs_sz+NFS3_diropargs_sz)
  #define NFS3_linkargs_sz              (NFS3_fh_sz+NFS3_diropargs_sz)
 -#define NFS3_readdirargs_sz   (NFS3_fh_sz+2)
 +#define NFS3_readdirargs_sz   (NFS3_fh_sz+NFS3_cookieverf_sz+3)
 +#define NFS3_readdirplusargs_sz       (NFS3_fh_sz+NFS3_cookieverf_sz+4)
  #define NFS3_commitargs_sz    (NFS3_fh_sz+3)
  
 -#define NFS3_attrstat_sz      (1+NFS3_fattr_sz)
 -#define NFS3_wccstat_sz               (1+NFS3_wcc_data_sz)
 -#define NFS3_removeres_sz     (NFS3_wccstat_sz)
 +#define NFS3_getattrres_sz    (1+NFS3_fattr_sz)
 +#define NFS3_setattrres_sz    (1+NFS3_wcc_data_sz)
 +#define NFS3_removeres_sz     (NFS3_setattrres_sz)
  #define NFS3_lookupres_sz     (1+NFS3_fh_sz+(2 * NFS3_post_op_attr_sz))
  #define NFS3_accessres_sz     (1+NFS3_post_op_attr_sz+1)
  #define NFS3_readlinkres_sz   (1+NFS3_post_op_attr_sz+1)
@@@ -100,2367 -100,1073 +100,2362 @@@ static const umode_t nfs_type2fmt[] = 
        [NF3FIFO] = S_IFIFO,
  };
  
 +/*
 + * While encoding arguments, set up the reply buffer in advance to
 + * receive reply data directly into the page cache.
 + */
 +static void prepare_reply_buffer(struct rpc_rqst *req, struct page **pages,
 +                               unsigned int base, unsigned int len,
 +                               unsigned int bufsize)
 +{
 +      struct rpc_auth *auth = req->rq_cred->cr_auth;
 +      unsigned int replen;
 +
 +      replen = RPC_REPHDRSIZE + auth->au_rslack + bufsize;
 +      xdr_inline_pages(&req->rq_rcv_buf, replen << 2, pages, base, len);
 +}
 +
 +/*
 + * Handle decode buffer overflows out-of-line.
 + */
  static void print_overflow_msg(const char *func, const struct xdr_stream *xdr)
  {
 -      dprintk("nfs: %s: prematurely hit end of receive buffer. "
 +      dprintk("NFS: %s prematurely hit the end of our receive buffer. "
                "Remaining buffer length is %tu words.\n",
                func, xdr->end - xdr->p);
  }
  
 +
  /*
 - * Common NFS XDR functions as inlines
 + * Encode/decode NFSv3 basic data types
 + *
 + * Basic NFSv3 data types are defined in section 2.5 of RFC 1813:
 + * "NFS Version 3 Protocol Specification".
 + *
 + * Not all basic data types have their own encoding and decoding
 + * functions.  For run-time efficiency, some data types are encoded
 + * or decoded inline.
   */
 -static inline __be32 *
 -xdr_encode_fhandle(__be32 *p, const struct nfs_fh *fh)
 -{
 -      return xdr_encode_array(p, fh->data, fh->size);
 -}
  
 -static inline __be32 *
 -xdr_decode_fhandle(__be32 *p, struct nfs_fh *fh)
 +static void encode_uint32(struct xdr_stream *xdr, u32 value)
  {
 -      if ((fh->size = ntohl(*p++)) <= NFS3_FHSIZE) {
 -              memcpy(fh->data, p, fh->size);
 -              return p + XDR_QUADLEN(fh->size);
 -      }
 -      return NULL;
 +      __be32 *p = xdr_reserve_space(xdr, 4);
 +      *p = cpu_to_be32(value);
  }
  
 -static inline __be32 *
 -xdr_decode_fhandle_stream(struct xdr_stream *xdr, struct nfs_fh *fh)
 +static int decode_uint32(struct xdr_stream *xdr, u32 *value)
  {
        __be32 *p;
 +
        p = xdr_inline_decode(xdr, 4);
 -      if (unlikely(!p))
 +      if (unlikely(p == NULL))
                goto out_overflow;
 -      fh->size = ntohl(*p++);
 -
 -      if (fh->size <= NFS3_FHSIZE) {
 -              p = xdr_inline_decode(xdr, fh->size);
 -              if (unlikely(!p))
 -                      goto out_overflow;
 -              memcpy(fh->data, p, fh->size);
 -              return p + XDR_QUADLEN(fh->size);
 -      }
 -      return NULL;
 -
 +      *value = be32_to_cpup(p);
 +      return 0;
  out_overflow:
        print_overflow_msg(__func__, xdr);
 -      return ERR_PTR(-EIO);
 +      return -EIO;
  }
  
 -/*
 - * Encode/decode time.
 - */
 -static inline __be32 *
 -xdr_encode_time3(__be32 *p, struct timespec *timep)
 +static int decode_uint64(struct xdr_stream *xdr, u64 *value)
  {
 -      *p++ = htonl(timep->tv_sec);
 -      *p++ = htonl(timep->tv_nsec);
 -      return p;
 -}
 +      __be32 *p;
  
 -static inline __be32 *
 -xdr_decode_time3(__be32 *p, struct timespec *timep)
 -{
 -      timep->tv_sec = ntohl(*p++);
 -      timep->tv_nsec = ntohl(*p++);
 -      return p;
 +      p = xdr_inline_decode(xdr, 8);
 +      if (unlikely(p == NULL))
 +              goto out_overflow;
 +      xdr_decode_hyper(p, value);
 +      return 0;
 +out_overflow:
 +      print_overflow_msg(__func__, xdr);
 +      return -EIO;
  }
  
 -static __be32 *
 -xdr_decode_fattr(__be32 *p, struct nfs_fattr *fattr)
 +/*
 + * fileid3
 + *
 + *    typedef uint64 fileid3;
 + */
 +static __be32 *xdr_decode_fileid3(__be32 *p, u64 *fileid)
  {
 -      unsigned int    type, major, minor;
 -      umode_t         fmode;
 -
 -      type = ntohl(*p++);
 -      if (type > NF3FIFO)
 -              type = NF3NON;
 -      fmode = nfs_type2fmt[type];
 -      fattr->mode = (ntohl(*p++) & ~S_IFMT) | fmode;
 -      fattr->nlink = ntohl(*p++);
 -      fattr->uid = ntohl(*p++);
 -      fattr->gid = ntohl(*p++);
 -      p = xdr_decode_hyper(p, &fattr->size);
 -      p = xdr_decode_hyper(p, &fattr->du.nfs3.used);
 -
 -      /* Turn remote device info into Linux-specific dev_t */
 -      major = ntohl(*p++);
 -      minor = ntohl(*p++);
 -      fattr->rdev = MKDEV(major, minor);
 -      if (MAJOR(fattr->rdev) != major || MINOR(fattr->rdev) != minor)
 -              fattr->rdev = 0;
 -
 -      p = xdr_decode_hyper(p, &fattr->fsid.major);
 -      fattr->fsid.minor = 0;
 -      p = xdr_decode_hyper(p, &fattr->fileid);
 -      p = xdr_decode_time3(p, &fattr->atime);
 -      p = xdr_decode_time3(p, &fattr->mtime);
 -      p = xdr_decode_time3(p, &fattr->ctime);
 -
 -      /* Update the mode bits */
 -      fattr->valid |= NFS_ATTR_FATTR_V3;
 -      return p;
 +      return xdr_decode_hyper(p, fileid);
  }
  
 -static inline __be32 *
 -xdr_encode_sattr(__be32 *p, struct iattr *attr)
 +static int decode_fileid3(struct xdr_stream *xdr, u64 *fileid)
  {
 -      if (attr->ia_valid & ATTR_MODE) {
 -              *p++ = xdr_one;
 -              *p++ = htonl(attr->ia_mode & S_IALLUGO);
 -      } else {
 -              *p++ = xdr_zero;
 -      }
 -      if (attr->ia_valid & ATTR_UID) {
 -              *p++ = xdr_one;
 -              *p++ = htonl(attr->ia_uid);
 -      } else {
 -              *p++ = xdr_zero;
 -      }
 -      if (attr->ia_valid & ATTR_GID) {
 -              *p++ = xdr_one;
 -              *p++ = htonl(attr->ia_gid);
 -      } else {
 -              *p++ = xdr_zero;
 -      }
 -      if (attr->ia_valid & ATTR_SIZE) {
 -              *p++ = xdr_one;
 -              p = xdr_encode_hyper(p, (__u64) attr->ia_size);
 -      } else {
 -              *p++ = xdr_zero;
 -      }
 -      if (attr->ia_valid & ATTR_ATIME_SET) {
 -              *p++ = xdr_two;
 -              p = xdr_encode_time3(p, &attr->ia_atime);
 -      } else if (attr->ia_valid & ATTR_ATIME) {
 -              *p++ = xdr_one;
 -      } else {
 -              *p++ = xdr_zero;
 -      }
 -      if (attr->ia_valid & ATTR_MTIME_SET) {
 -              *p++ = xdr_two;
 -              p = xdr_encode_time3(p, &attr->ia_mtime);
 -      } else if (attr->ia_valid & ATTR_MTIME) {
 -              *p++ = xdr_one;
 -      } else {
 -              *p++ = xdr_zero;
 -      }
 -      return p;
 +      return decode_uint64(xdr, fileid);
  }
  
 -static inline __be32 *
 -xdr_decode_wcc_attr(__be32 *p, struct nfs_fattr *fattr)
 +/*
 + * filename3
 + *
 + *    typedef string filename3<>;
 + */
 +static void encode_filename3(struct xdr_stream *xdr,
 +                           const char *name, u32 length)
  {
 -      p = xdr_decode_hyper(p, &fattr->pre_size);
 -      p = xdr_decode_time3(p, &fattr->pre_mtime);
 -      p = xdr_decode_time3(p, &fattr->pre_ctime);
 -      fattr->valid |= NFS_ATTR_FATTR_PRESIZE
 -              | NFS_ATTR_FATTR_PREMTIME
 -              | NFS_ATTR_FATTR_PRECTIME;
 -      return p;
 -}
 +      __be32 *p;
  
 -static inline __be32 *
 -xdr_decode_post_op_attr(__be32 *p, struct nfs_fattr *fattr)
 -{
 -      if (*p++)
 -              p = xdr_decode_fattr(p, fattr);
 -      return p;
 +      BUG_ON(length > NFS3_MAXNAMLEN);
 +      p = xdr_reserve_space(xdr, 4 + length);
 +      xdr_encode_opaque(p, name, length);
  }
  
 -static inline __be32 *
 -xdr_decode_post_op_attr_stream(struct xdr_stream *xdr, struct nfs_fattr *fattr)
 +static int decode_inline_filename3(struct xdr_stream *xdr,
 +                                 const char **name, u32 *length)
  {
        __be32 *p;
 +      u32 count;
  
        p = xdr_inline_decode(xdr, 4);
 -      if (unlikely(!p))
 +      if (unlikely(p == NULL))
                goto out_overflow;
 -      if (ntohl(*p++)) {
 -              p = xdr_inline_decode(xdr, 84);
 -              if (unlikely(!p))
 -                      goto out_overflow;
 -              p = xdr_decode_fattr(p, fattr);
 -      }
 -      return p;
 +      count = be32_to_cpup(p);
 +      if (count > NFS3_MAXNAMLEN)
 +              goto out_nametoolong;
 +      p = xdr_inline_decode(xdr, count);
 +      if (unlikely(p == NULL))
 +              goto out_overflow;
 +      *name = (const char *)p;
 +      *length = count;
 +      return 0;
 +
 +out_nametoolong:
 +      dprintk("NFS: returned filename too long: %u\n", count);
 +      return -ENAMETOOLONG;
  out_overflow:
        print_overflow_msg(__func__, xdr);
 -      return ERR_PTR(-EIO);
 +      return -EIO;
  }
  
 -static inline __be32 *
 -xdr_decode_pre_op_attr(__be32 *p, struct nfs_fattr *fattr)
 +/*
 + * nfspath3
 + *
 + *    typedef string nfspath3<>;
 + */
 +static void encode_nfspath3(struct xdr_stream *xdr, struct page **pages,
 +                          const u32 length)
  {
 -      if (*p++)
 -              return xdr_decode_wcc_attr(p, fattr);
 -      return p;
 +      BUG_ON(length > NFS3_MAXPATHLEN);
 +      encode_uint32(xdr, length);
 +      xdr_write_pages(xdr, pages, 0, length);
  }
  
 -
 -static inline __be32 *
 -xdr_decode_wcc_data(__be32 *p, struct nfs_fattr *fattr)
 +static int decode_nfspath3(struct xdr_stream *xdr)
  {
 -      p = xdr_decode_pre_op_attr(p, fattr);
 -      return xdr_decode_post_op_attr(p, fattr);
 -}
 -
 -/*
 - * NFS encode functions
 - */
 +      u32 recvd, count;
 +      size_t hdrlen;
 +      __be32 *p;
  
 -/*
 - * Encode file handle argument
 - */
 -static int
 -nfs3_xdr_fhandle(struct rpc_rqst *req, __be32 *p, struct nfs_fh *fh)
 -{
 -      p = xdr_encode_fhandle(p, fh);
 -      req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
 +      p = xdr_inline_decode(xdr, 4);
 +      if (unlikely(p == NULL))
 +              goto out_overflow;
 +      count = be32_to_cpup(p);
 +      if (unlikely(count >= xdr->buf->page_len || count > NFS3_MAXPATHLEN))
 +              goto out_nametoolong;
 +      hdrlen = (u8 *)xdr->p - (u8 *)xdr->iov->iov_base;
 +      recvd = xdr->buf->len - hdrlen;
 +      if (unlikely(count > recvd))
 +              goto out_cheating;
 +
 +      xdr_read_pages(xdr, count);
 +      xdr_terminate_string(xdr->buf, count);
        return 0;
 -}
  
 -/*
 - * Encode SETATTR arguments
 - */
 -static int
 -nfs3_xdr_sattrargs(struct rpc_rqst *req, __be32 *p, struct nfs3_sattrargs *args)
 -{
 -      p = xdr_encode_fhandle(p, args->fh);
 -      p = xdr_encode_sattr(p, args->sattr);
 -      *p++ = htonl(args->guard);
 -      if (args->guard)
 -              p = xdr_encode_time3(p, &args->guardtime);
 -      req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
 -      return 0;
 +out_nametoolong:
 +      dprintk("NFS: returned pathname too long: %u\n", count);
 +      return -ENAMETOOLONG;
 +out_cheating:
 +      dprintk("NFS: server cheating in pathname result: "
 +              "count %u > recvd %u\n", count, recvd);
 +      return -EIO;
 +out_overflow:
 +      print_overflow_msg(__func__, xdr);
 +      return -EIO;
  }
  
  /*
 - * Encode directory ops argument
 + * cookie3
 + *
 + *    typedef uint64 cookie3
   */
 -static int
 -nfs3_xdr_diropargs(struct rpc_rqst *req, __be32 *p, struct nfs3_diropargs *args)
 +static __be32 *xdr_encode_cookie3(__be32 *p, u64 cookie)
  {
 -      p = xdr_encode_fhandle(p, args->fh);
 -      p = xdr_encode_array(p, args->name, args->len);
 -      req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
 -      return 0;
 +      return xdr_encode_hyper(p, cookie);
  }
  
 -/*
 - * Encode REMOVE argument
 - */
 -static int
 -nfs3_xdr_removeargs(struct rpc_rqst *req, __be32 *p, const struct nfs_removeargs *args)
 +static int decode_cookie3(struct xdr_stream *xdr, u64 *cookie)
  {
 -      p = xdr_encode_fhandle(p, args->fh);
 -      p = xdr_encode_array(p, args->name.name, args->name.len);
 -      req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
 -      return 0;
 +      return decode_uint64(xdr, cookie);
  }
  
  /*
 - * Encode access() argument
 + * cookieverf3
 + *
 + *    typedef opaque cookieverf3[NFS3_COOKIEVERFSIZE];
   */
 -static int
 -nfs3_xdr_accessargs(struct rpc_rqst *req, __be32 *p, struct nfs3_accessargs *args)
 +static __be32 *xdr_encode_cookieverf3(__be32 *p, const __be32 *verifier)
  {
 -      p = xdr_encode_fhandle(p, args->fh);
 -      *p++ = htonl(args->access);
 -      req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
 -      return 0;
 +      memcpy(p, verifier, NFS3_COOKIEVERFSIZE);
 +      return p + XDR_QUADLEN(NFS3_COOKIEVERFSIZE);
  }
  
 -/*
 - * Arguments to a READ call. Since we read data directly into the page
 - * cache, we also set up the reply iovec here so that iov[1] points
 - * exactly to the page we want to fetch.
 - */
 -static int
 -nfs3_xdr_readargs(struct rpc_rqst *req, __be32 *p, struct nfs_readargs *args)
 +static int decode_cookieverf3(struct xdr_stream *xdr, __be32 *verifier)
  {
 -      struct rpc_auth *auth = req->rq_cred->cr_auth;
 -      unsigned int replen;
 -      u32 count = args->count;
 -
 -      p = xdr_encode_fhandle(p, args->fh);
 -      p = xdr_encode_hyper(p, args->offset);
 -      *p++ = htonl(count);
 -      req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
 +      __be32 *p;
  
 -      /* Inline the page array */
 -      replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS3_readres_sz) << 2;
 -      xdr_inline_pages(&req->rq_rcv_buf, replen,
 -                       args->pages, args->pgbase, count);
 -      req->rq_rcv_buf.flags |= XDRBUF_READ;
 +      p = xdr_inline_decode(xdr, NFS3_COOKIEVERFSIZE);
 +      if (unlikely(p == NULL))
 +              goto out_overflow;
 +      memcpy(verifier, p, NFS3_COOKIEVERFSIZE);
        return 0;
 +out_overflow:
 +      print_overflow_msg(__func__, xdr);
 +      return -EIO;
  }
  
  /*
 - * Write arguments. Splice the buffer to be written into the iovec.
 + * createverf3
 + *
 + *    typedef opaque createverf3[NFS3_CREATEVERFSIZE];
   */
 -static int
 -nfs3_xdr_writeargs(struct rpc_rqst *req, __be32 *p, struct nfs_writeargs *args)
 +static void encode_createverf3(struct xdr_stream *xdr, const __be32 *verifier)
  {
 -      struct xdr_buf *sndbuf = &req->rq_snd_buf;
 -      u32 count = args->count;
 +      __be32 *p;
  
 -      p = xdr_encode_fhandle(p, args->fh);
 -      p = xdr_encode_hyper(p, args->offset);
 -      *p++ = htonl(count);
 -      *p++ = htonl(args->stable);
 -      *p++ = htonl(count);
 -      sndbuf->len = xdr_adjust_iovec(sndbuf->head, p);
 -
 -      /* Copy the page array */
 -      xdr_encode_pages(sndbuf, args->pages, args->pgbase, count);
 -      sndbuf->flags |= XDRBUF_WRITE;
 -      return 0;
 +      p = xdr_reserve_space(xdr, NFS3_CREATEVERFSIZE);
 +      memcpy(p, verifier, NFS3_CREATEVERFSIZE);
  }
  
 -/*
 - * Encode CREATE arguments
 - */
 -static int
 -nfs3_xdr_createargs(struct rpc_rqst *req, __be32 *p, struct nfs3_createargs *args)
 +static int decode_writeverf3(struct xdr_stream *xdr, __be32 *verifier)
  {
 -      p = xdr_encode_fhandle(p, args->fh);
 -      p = xdr_encode_array(p, args->name, args->len);
 -
 -      *p++ = htonl(args->createmode);
 -      if (args->createmode == NFS3_CREATE_EXCLUSIVE) {
 -              *p++ = args->verifier[0];
 -              *p++ = args->verifier[1];
 -      } else
 -              p = xdr_encode_sattr(p, args->sattr);
 +      __be32 *p;
  
 -      req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
 +      p = xdr_inline_decode(xdr, NFS3_WRITEVERFSIZE);
 +      if (unlikely(p == NULL))
 +              goto out_overflow;
 +      memcpy(verifier, p, NFS3_WRITEVERFSIZE);
        return 0;
 +out_overflow:
 +      print_overflow_msg(__func__, xdr);
 +      return -EIO;
  }
  
  /*
 - * Encode MKDIR arguments
 + * size3
 + *
 + *    typedef uint64 size3;
   */
 -static int
 -nfs3_xdr_mkdirargs(struct rpc_rqst *req, __be32 *p, struct nfs3_mkdirargs *args)
 +static __be32 *xdr_decode_size3(__be32 *p, u64 *size)
  {
 -      p = xdr_encode_fhandle(p, args->fh);
 -      p = xdr_encode_array(p, args->name, args->len);
 -      p = xdr_encode_sattr(p, args->sattr);
 -      req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
 -      return 0;
 +      return xdr_decode_hyper(p, size);
  }
  
  /*
 - * Encode SYMLINK arguments
 + * nfsstat3
 + *
 + *    enum nfsstat3 {
 + *            NFS3_OK = 0,
 + *            ...
 + *    }
   */
 -static int
 -nfs3_xdr_symlinkargs(struct rpc_rqst *req, __be32 *p, struct nfs3_symlinkargs *args)
 +#define NFS3_OK               NFS_OK
 +
 +static int decode_nfsstat3(struct xdr_stream *xdr, enum nfs_stat *status)
  {
 -      p = xdr_encode_fhandle(p, args->fromfh);
 -      p = xdr_encode_array(p, args->fromname, args->fromlen);
 -      p = xdr_encode_sattr(p, args->sattr);
 -      *p++ = htonl(args->pathlen);
 -      req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
 +      __be32 *p;
  
 -      /* Copy the page */
 -      xdr_encode_pages(&req->rq_snd_buf, args->pages, 0, args->pathlen);
 +      p = xdr_inline_decode(xdr, 4);
 +      if (unlikely(p == NULL))
 +              goto out_overflow;
 +      *status = be32_to_cpup(p);
        return 0;
 +out_overflow:
 +      print_overflow_msg(__func__, xdr);
 +      return -EIO;
  }
  
  /*
 - * Encode MKNOD arguments
 + * ftype3
 + *
 + *    enum ftype3 {
 + *            NF3REG  = 1,
 + *            NF3DIR  = 2,
 + *            NF3BLK  = 3,
 + *            NF3CHR  = 4,
 + *            NF3LNK  = 5,
 + *            NF3SOCK = 6,
 + *            NF3FIFO = 7
 + *    };
   */
 -static int
 -nfs3_xdr_mknodargs(struct rpc_rqst *req, __be32 *p, struct nfs3_mknodargs *args)
 -{
 -      p = xdr_encode_fhandle(p, args->fh);
 -      p = xdr_encode_array(p, args->name, args->len);
 -      *p++ = htonl(args->type);
 -      p = xdr_encode_sattr(p, args->sattr);
 -      if (args->type == NF3CHR || args->type == NF3BLK) {
 -              *p++ = htonl(MAJOR(args->rdev));
 -              *p++ = htonl(MINOR(args->rdev));
 -      }
 -
 -      req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
 -      return 0;
 +static void encode_ftype3(struct xdr_stream *xdr, const u32 type)
 +{
 +      BUG_ON(type > NF3FIFO);
 +      encode_uint32(xdr, type);
  }
  
 -/*
 - * Encode RENAME arguments
 - */
 -static int
 -nfs3_xdr_renameargs(struct rpc_rqst *req, __be32 *p, struct nfs_renameargs *args)
 -{
 -      p = xdr_encode_fhandle(p, args->old_dir);
 -      p = xdr_encode_array(p, args->old_name->name, args->old_name->len);
 -      p = xdr_encode_fhandle(p, args->new_dir);
 -      p = xdr_encode_array(p, args->new_name->name, args->new_name->len);
 -      req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
 -      return 0;
 +static __be32 *xdr_decode_ftype3(__be32 *p, umode_t *mode)
 +{
 +      u32 type;
 +
 +      type = be32_to_cpup(p++);
 +      if (type > NF3FIFO)
 +              type = NF3NON;
 +      *mode = nfs_type2fmt[type];
 +      return p;
  }
  
  /*
 - * Encode LINK arguments
 + * specdata3
 + *
 + *     struct specdata3 {
 + *             uint32  specdata1;
 + *             uint32  specdata2;
 + *     };
   */
 -static int
 -nfs3_xdr_linkargs(struct rpc_rqst *req, __be32 *p, struct nfs3_linkargs *args)
 +static void encode_specdata3(struct xdr_stream *xdr, const dev_t rdev)
  {
 -      p = xdr_encode_fhandle(p, args->fromfh);
 -      p = xdr_encode_fhandle(p, args->tofh);
 -      p = xdr_encode_array(p, args->toname, args->tolen);
 -      req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
 -      return 0;
 +      __be32 *p;
 +
 +      p = xdr_reserve_space(xdr, 8);
 +      *p++ = cpu_to_be32(MAJOR(rdev));
 +      *p = cpu_to_be32(MINOR(rdev));
  }
  
 -/*
 - * Encode arguments to readdir call
 - */
 -static int
 -nfs3_xdr_readdirargs(struct rpc_rqst *req, __be32 *p, struct nfs3_readdirargs *args)
 +static __be32 *xdr_decode_specdata3(__be32 *p, dev_t *rdev)
  {
 -      struct rpc_auth *auth = req->rq_cred->cr_auth;
 -      unsigned int replen;
 -      u32 count = args->count;
 -
 -      p = xdr_encode_fhandle(p, args->fh);
 -      p = xdr_encode_hyper(p, args->cookie);
 -      *p++ = args->verf[0];
 -      *p++ = args->verf[1];
 -      if (args->plus) {
 -              /* readdirplus: need dircount + buffer size.
 -               * We just make sure we make dircount big enough */
 -              *p++ = htonl(count >> 3);
 -      }
 -      *p++ = htonl(count);
 -      req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
 +      unsigned int major, minor;
  
 -      /* Inline the page array */
 -      replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS3_readdirres_sz) << 2;
 -      xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, 0, count);
 -      return 0;
 +      major = be32_to_cpup(p++);
 +      minor = be32_to_cpup(p++);
 +      *rdev = MKDEV(major, minor);
 +      if (MAJOR(*rdev) != major || MINOR(*rdev) != minor)
 +              *rdev = 0;
 +      return p;
  }
  
  /*
 - * Decode the result of a readdir call.
 - * We just check for syntactical correctness.
 + * nfs_fh3
 + *
 + *    struct nfs_fh3 {
 + *            opaque       data<NFS3_FHSIZE>;
 + *    };
   */
 -static int
 -nfs3_xdr_readdirres(struct rpc_rqst *req, __be32 *p, struct nfs3_readdirres *res)
 +static void encode_nfs_fh3(struct xdr_stream *xdr, const struct nfs_fh *fh)
  {
 -      struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
 -      struct kvec *iov = rcvbuf->head;
 -      struct page **page;
 -      size_t hdrlen;
 -      u32 recvd, pglen;
 -      int status;
 -
 -      status = ntohl(*p++);
 -      /* Decode post_op_attrs */
 -      p = xdr_decode_post_op_attr(p, res->dir_attr);
 -      if (status)
 -              return nfs_stat_to_errno(status);
 -      /* Decode verifier cookie */
 -      if (res->verf) {
 -              res->verf[0] = *p++;
 -              res->verf[1] = *p++;
 -      } else {
 -              p += 2;
 -      }
 -
 -      hdrlen = (u8 *) p - (u8 *) iov->iov_base;
 -      if (iov->iov_len < hdrlen) {
 -              dprintk("NFS: READDIR reply header overflowed:"
 -                              "length %Zu > %Zu\n", hdrlen, iov->iov_len);
 -              return -errno_NFSERR_IO;
 -      } else if (iov->iov_len != hdrlen) {
 -              dprintk("NFS: READDIR header is short. iovec will be shifted.\n");
 -              xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen);
 -      }
 -
 -      pglen = rcvbuf->page_len;
 -      recvd = rcvbuf->len - hdrlen;
 -      if (pglen > recvd)
 -              pglen = recvd;
 -      page = rcvbuf->pages;
 +      __be32 *p;
  
 -      return pglen;
 +      BUG_ON(fh->size > NFS3_FHSIZE);
 +      p = xdr_reserve_space(xdr, 4 + fh->size);
 +      xdr_encode_opaque(p, fh->data, fh->size);
  }
  
 -__be32 *
 -nfs3_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry, struct nfs_server *server, int plus)
 +static int decode_nfs_fh3(struct xdr_stream *xdr, struct nfs_fh *fh)
  {
 +      u32 length;
        __be32 *p;
 -      struct nfs_entry old = *entry;
  
        p = xdr_inline_decode(xdr, 4);
 -      if (unlikely(!p))
 -              goto out_overflow;
 -      if (!ntohl(*p++)) {
 -              p = xdr_inline_decode(xdr, 4);
 -              if (unlikely(!p))
 -                      goto out_overflow;
 -              if (!ntohl(*p++))
 -                      return ERR_PTR(-EAGAIN);
 -              entry->eof = 1;
 -              return ERR_PTR(-EBADCOOKIE);
 -      }
 -
 -      p = xdr_inline_decode(xdr, 12);
 -      if (unlikely(!p))
 +      if (unlikely(p == NULL))
                goto out_overflow;
 -      p = xdr_decode_hyper(p, &entry->ino);
 -      entry->len  = ntohl(*p++);
 -
 -      p = xdr_inline_decode(xdr, entry->len + 8);
 -      if (unlikely(!p))
 +      length = be32_to_cpup(p++);
 +      if (unlikely(length > NFS3_FHSIZE))
 +              goto out_toobig;
 +      p = xdr_inline_decode(xdr, length);
 +      if (unlikely(p == NULL))
                goto out_overflow;
 -      entry->name = (const char *) p;
 -      p += XDR_QUADLEN(entry->len);
 -      entry->prev_cookie = entry->cookie;
 -      p = xdr_decode_hyper(p, &entry->cookie);
 -
 -      entry->d_type = DT_UNKNOWN;
 -      if (plus) {
 -              entry->fattr->valid = 0;
 -              p = xdr_decode_post_op_attr_stream(xdr, entry->fattr);
 -              if (IS_ERR(p))
 -                      goto out_overflow_exit;
 -              entry->d_type = nfs_umode_to_dtype(entry->fattr->mode);
 -              /* In fact, a post_op_fh3: */
 -              p = xdr_inline_decode(xdr, 4);
 -              if (unlikely(!p))
 -                      goto out_overflow;
 -              if (*p++) {
 -                      p = xdr_decode_fhandle_stream(xdr, entry->fh);
 -                      if (IS_ERR(p))
 -                              goto out_overflow_exit;
 -                      /* Ugh -- server reply was truncated */
 -                      if (p == NULL) {
 -                              dprintk("NFS: FH truncated\n");
 -                              *entry = old;
 -                              return ERR_PTR(-EAGAIN);
 -                      }
 -              } else
 -                      memset((u8*)(entry->fh), 0, sizeof(*entry->fh));
 -      }
 -
 -      return p;
 -
 +      fh->size = length;
 +      memcpy(fh->data, p, length);
 +      return 0;
 +out_toobig:
 +      dprintk("NFS: file handle size (%u) too big\n", length);
 +      return -E2BIG;
  out_overflow:
        print_overflow_msg(__func__, xdr);
 -out_overflow_exit:
 -      return ERR_PTR(-EAGAIN);
 +      return -EIO;
  }
  
 -/*
 - * Encode COMMIT arguments
 - */
 -static int
 -nfs3_xdr_commitargs(struct rpc_rqst *req, __be32 *p, struct nfs_writeargs *args)
 +static void zero_nfs_fh3(struct nfs_fh *fh)
  {
 -      p = xdr_encode_fhandle(p, args->fh);
 -      p = xdr_encode_hyper(p, args->offset);
 -      *p++ = htonl(args->count);
 -      req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
 -      return 0;
 +      memset(fh, 0, sizeof(*fh));
  }
  
 -#ifdef CONFIG_NFS_V3_ACL
  /*
 - * Encode GETACL arguments
 + * nfstime3
 + *
 + *    struct nfstime3 {
 + *            uint32  seconds;
 + *            uint32  nseconds;
 + *    };
   */
 -static int
 -nfs3_xdr_getaclargs(struct rpc_rqst *req, __be32 *p,
 -                  struct nfs3_getaclargs *args)
 +static __be32 *xdr_encode_nfstime3(__be32 *p, const struct timespec *timep)
  {
 -      struct rpc_auth *auth = req->rq_cred->cr_auth;
 -      unsigned int replen;
 -
 -      p = xdr_encode_fhandle(p, args->fh);
 -      *p++ = htonl(args->mask);
 -      req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
 -
 -      if (args->mask & (NFS_ACL | NFS_DFACL)) {
 -              /* Inline the page array */
 -              replen = (RPC_REPHDRSIZE + auth->au_rslack +
 -                        ACL3_getaclres_sz) << 2;
 -              xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, 0,
 -                               NFSACL_MAXPAGES << PAGE_SHIFT);
 -      }
 -      return 0;
 +      *p++ = cpu_to_be32(timep->tv_sec);
 +      *p++ = cpu_to_be32(timep->tv_nsec);
 +      return p;
  }
  
 -/*
 - * Encode SETACL arguments
 - */
 -static int
 -nfs3_xdr_setaclargs(struct rpc_rqst *req, __be32 *p,
 -                   struct nfs3_setaclargs *args)
 +static __be32 *xdr_decode_nfstime3(__be32 *p, struct timespec *timep)
  {
 -      struct xdr_buf *buf = &req->rq_snd_buf;
 -      unsigned int base;
 -      int err;
 -
 -      p = xdr_encode_fhandle(p, NFS_FH(args->inode));
 -      *p++ = htonl(args->mask);
 -      req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
 -      base = req->rq_slen;
 -
 -      if (args->npages != 0)
 -              xdr_encode_pages(buf, args->pages, 0, args->len);
 -      else
 -              req->rq_slen = xdr_adjust_iovec(req->rq_svec,
 -                              p + XDR_QUADLEN(args->len));
 -
 -      err = nfsacl_encode(buf, base, args->inode,
 -                          (args->mask & NFS_ACL) ?
 -                          args->acl_access : NULL, 1, 0);
 -      if (err > 0)
 -              err = nfsacl_encode(buf, base + err, args->inode,
 -                                  (args->mask & NFS_DFACL) ?
 -                                  args->acl_default : NULL, 1,
 -                                  NFS_ACL_DEFAULT);
 -      return (err > 0) ? 0 : err;
 +      timep->tv_sec = be32_to_cpup(p++);
 +      timep->tv_nsec = be32_to_cpup(p++);
 +      return p;
  }
 -#endif  /* CONFIG_NFS_V3_ACL */
  
  /*
 - * NFS XDR decode functions
 - */
 -
 -/*
 - * Decode attrstat reply.
 + * sattr3
 + *
 + *    enum time_how {
 + *            DONT_CHANGE             = 0,
 + *            SET_TO_SERVER_TIME      = 1,
 + *            SET_TO_CLIENT_TIME      = 2
 + *    };
 + *
 + *    union set_mode3 switch (bool set_it) {
 + *    case TRUE:
 + *            mode3   mode;
 + *    default:
 + *            void;
 + *    };
 + *
 + *    union set_uid3 switch (bool set_it) {
 + *    case TRUE:
 + *            uid3    uid;
 + *    default:
 + *            void;
 + *    };
 + *
 + *    union set_gid3 switch (bool set_it) {
 + *    case TRUE:
 + *            gid3    gid;
 + *    default:
 + *            void;
 + *    };
 + *
 + *    union set_size3 switch (bool set_it) {
 + *    case TRUE:
 + *            size3   size;
 + *    default:
 + *            void;
 + *    };
 + *
 + *    union set_atime switch (time_how set_it) {
 + *    case SET_TO_CLIENT_TIME:
 + *            nfstime3        atime;
 + *    default:
 + *            void;
 + *    };
 + *
 + *    union set_mtime switch (time_how set_it) {
 + *    case SET_TO_CLIENT_TIME:
 + *            nfstime3  mtime;
 + *    default:
 + *            void;
 + *    };
 + *
 + *    struct sattr3 {
 + *            set_mode3       mode;
 + *            set_uid3        uid;
 + *            set_gid3        gid;
 + *            set_size3       size;
 + *            set_atime       atime;
 + *            set_mtime       mtime;
 + *    };
   */
 -static int
 -nfs3_xdr_attrstat(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
 +static void encode_sattr3(struct xdr_stream *xdr, const struct iattr *attr)
  {
 -      int     status;
 +      u32 nbytes;
 +      __be32 *p;
  
 -      if ((status = ntohl(*p++)))
 -              return nfs_stat_to_errno(status);
 -      xdr_decode_fattr(p, fattr);
 +      /*
 +       * In order to make only a single xdr_reserve_space() call,
 +       * pre-compute the total number of bytes to be reserved.
 +       * Six boolean values, one for each set_foo field, are always
 +       * present in the encoded result, so start there.
 +       */
 +      nbytes = 6 * 4;
 +      if (attr->ia_valid & ATTR_MODE)
 +              nbytes += 4;
 +      if (attr->ia_valid & ATTR_UID)
 +              nbytes += 4;
 +      if (attr->ia_valid & ATTR_GID)
 +              nbytes += 4;
 +      if (attr->ia_valid & ATTR_SIZE)
 +              nbytes += 8;
 +      if (attr->ia_valid & ATTR_ATIME_SET)
 +              nbytes += 8;
 +      if (attr->ia_valid & ATTR_MTIME_SET)
 +              nbytes += 8;
 +      p = xdr_reserve_space(xdr, nbytes);
 +
 +      if (attr->ia_valid & ATTR_MODE) {
 +              *p++ = xdr_one;
 +              *p++ = cpu_to_be32(attr->ia_mode & S_IALLUGO);
 +      } else
 +              *p++ = xdr_zero;
 +
 +      if (attr->ia_valid & ATTR_UID) {
 +              *p++ = xdr_one;
 +              *p++ = cpu_to_be32(attr->ia_uid);
 +      } else
 +              *p++ = xdr_zero;
 +
 +      if (attr->ia_valid & ATTR_GID) {
 +              *p++ = xdr_one;
 +              *p++ = cpu_to_be32(attr->ia_gid);
 +      } else
 +              *p++ = xdr_zero;
 +
 +      if (attr->ia_valid & ATTR_SIZE) {
 +              *p++ = xdr_one;
 +              p = xdr_encode_hyper(p, (u64)attr->ia_size);
 +      } else
 +              *p++ = xdr_zero;
 +
 +      if (attr->ia_valid & ATTR_ATIME_SET) {
 +              *p++ = xdr_two;
 +              p = xdr_encode_nfstime3(p, &attr->ia_atime);
 +      } else if (attr->ia_valid & ATTR_ATIME) {
 +              *p++ = xdr_one;
 +      } else
 +              *p++ = xdr_zero;
 +
 +      if (attr->ia_valid & ATTR_MTIME_SET) {
 +              *p++ = xdr_two;
 +              xdr_encode_nfstime3(p, &attr->ia_mtime);
 +      } else if (attr->ia_valid & ATTR_MTIME) {
 +              *p = xdr_one;
 +      } else
 +              *p = xdr_zero;
 +}
 +
 +/*
 + * fattr3
 + *
 + *    struct fattr3 {
 + *            ftype3          type;
 + *            mode3           mode;
 + *            uint32          nlink;
 + *            uid3            uid;
 + *            gid3            gid;
 + *            size3           size;
 + *            size3           used;
 + *            specdata3       rdev;
 + *            uint64          fsid;
 + *            fileid3         fileid;
 + *            nfstime3        atime;
 + *            nfstime3        mtime;
 + *            nfstime3        ctime;
 + *    };
 + */
 +static int decode_fattr3(struct xdr_stream *xdr, struct nfs_fattr *fattr)
 +{
 +      umode_t fmode;
 +      __be32 *p;
 +
 +      p = xdr_inline_decode(xdr, NFS3_fattr_sz << 2);
 +      if (unlikely(p == NULL))
 +              goto out_overflow;
 +
 +      p = xdr_decode_ftype3(p, &fmode);
 +
 +      fattr->mode = (be32_to_cpup(p++) & ~S_IFMT) | fmode;
 +      fattr->nlink = be32_to_cpup(p++);
 +      fattr->uid = be32_to_cpup(p++);
 +      fattr->gid = be32_to_cpup(p++);
 +
 +      p = xdr_decode_size3(p, &fattr->size);
 +      p = xdr_decode_size3(p, &fattr->du.nfs3.used);
 +      p = xdr_decode_specdata3(p, &fattr->rdev);
 +
 +      p = xdr_decode_hyper(p, &fattr->fsid.major);
 +      fattr->fsid.minor = 0;
 +
 +      p = xdr_decode_fileid3(p, &fattr->fileid);
 +      p = xdr_decode_nfstime3(p, &fattr->atime);
 +      p = xdr_decode_nfstime3(p, &fattr->mtime);
 +      xdr_decode_nfstime3(p, &fattr->ctime);
 +
 +      fattr->valid |= NFS_ATTR_FATTR_V3;
        return 0;
 +out_overflow:
 +      print_overflow_msg(__func__, xdr);
 +      return -EIO;
  }
  
  /*
 - * Decode status+wcc_data reply
 - * SATTR, REMOVE, RMDIR
 + * post_op_attr
 + *
 + *    union post_op_attr switch (bool attributes_follow) {
 + *    case TRUE:
 + *            fattr3  attributes;
 + *    case FALSE:
 + *            void;
 + *    };
   */
 -static int
 -nfs3_xdr_wccstat(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
 +static int decode_post_op_attr(struct xdr_stream *xdr, struct nfs_fattr *fattr)
  {
 -      int     status;
 +      __be32 *p;
  
 -      if ((status = ntohl(*p++)))
 -              status = nfs_stat_to_errno(status);
 -      xdr_decode_wcc_data(p, fattr);
 -      return status;
 +      p = xdr_inline_decode(xdr, 4);
 +      if (unlikely(p == NULL))
 +              goto out_overflow;
 +      if (*p != xdr_zero)
 +              return decode_fattr3(xdr, fattr);
 +      return 0;
 +out_overflow:
 +      print_overflow_msg(__func__, xdr);
 +      return -EIO;
 +}
 +
 +/*
 + * wcc_attr
 + *    struct wcc_attr {
 + *            size3           size;
 + *            nfstime3        mtime;
 + *            nfstime3        ctime;
 + *    };
 + */
 +static int decode_wcc_attr(struct xdr_stream *xdr, struct nfs_fattr *fattr)
 +{
 +      __be32 *p;
 +
 +      p = xdr_inline_decode(xdr, NFS3_wcc_attr_sz << 2);
 +      if (unlikely(p == NULL))
 +              goto out_overflow;
 +
 +      fattr->valid |= NFS_ATTR_FATTR_PRESIZE
 +              | NFS_ATTR_FATTR_PREMTIME
 +              | NFS_ATTR_FATTR_PRECTIME;
 +
 +      p = xdr_decode_size3(p, &fattr->pre_size);
 +      p = xdr_decode_nfstime3(p, &fattr->pre_mtime);
 +      xdr_decode_nfstime3(p, &fattr->pre_ctime);
 +
 +      return 0;
 +out_overflow:
 +      print_overflow_msg(__func__, xdr);
 +      return -EIO;
 +}
 +
 +/*
 + * pre_op_attr
 + *    union pre_op_attr switch (bool attributes_follow) {
 + *    case TRUE:
 + *            wcc_attr        attributes;
 + *    case FALSE:
 + *            void;
 + *    };
 + *
 + * wcc_data
 + *
 + *    struct wcc_data {
 + *            pre_op_attr     before;
 + *            post_op_attr    after;
 + *    };
 + */
 +static int decode_pre_op_attr(struct xdr_stream *xdr, struct nfs_fattr *fattr)
 +{
 +      __be32 *p;
 +
 +      p = xdr_inline_decode(xdr, 4);
 +      if (unlikely(p == NULL))
 +              goto out_overflow;
 +      if (*p != xdr_zero)
 +              return decode_wcc_attr(xdr, fattr);
 +      return 0;
 +out_overflow:
 +      print_overflow_msg(__func__, xdr);
 +      return -EIO;
 +}
 +
 +static int decode_wcc_data(struct xdr_stream *xdr, struct nfs_fattr *fattr)
 +{
 +      int error;
 +
 +      error = decode_pre_op_attr(xdr, fattr);
 +      if (unlikely(error))
 +              goto out;
 +      error = decode_post_op_attr(xdr, fattr);
 +out:
 +      return error;
 +}
 +
 +/*
 + * post_op_fh3
 + *
 + *    union post_op_fh3 switch (bool handle_follows) {
 + *    case TRUE:
 + *            nfs_fh3  handle;
 + *    case FALSE:
 + *            void;
 + *    };
 + */
 +static int decode_post_op_fh3(struct xdr_stream *xdr, struct nfs_fh *fh)
 +{
 +      __be32 *p = xdr_inline_decode(xdr, 4);
 +      if (unlikely(p == NULL))
 +              goto out_overflow;
 +      if (*p != xdr_zero)
 +              return decode_nfs_fh3(xdr, fh);
 +      zero_nfs_fh3(fh);
 +      return 0;
 +out_overflow:
 +      print_overflow_msg(__func__, xdr);
 +      return -EIO;
 +}
 +
 +/*
 + * diropargs3
 + *
 + *    struct diropargs3 {
 + *            nfs_fh3         dir;
 + *            filename3       name;
 + *    };
 + */
 +static void encode_diropargs3(struct xdr_stream *xdr, const struct nfs_fh *fh,
 +                            const char *name, u32 length)
 +{
 +      encode_nfs_fh3(xdr, fh);
 +      encode_filename3(xdr, name, length);
  }
  
 -static int
 -nfs3_xdr_removeres(struct rpc_rqst *req, __be32 *p, struct nfs_removeres *res)
 +
 +/*
 + * NFSv3 XDR encode functions
 + *
 + * NFSv3 argument types are defined in section 3.3 of RFC 1813:
 + * "NFS Version 3 Protocol Specification".
 + */
 +
 +/*
 + * 3.3.1  GETATTR3args
 + *
 + *    struct GETATTR3args {
 + *            nfs_fh3  object;
 + *    };
 + */
 +static void nfs3_xdr_enc_getattr3args(struct rpc_rqst *req,
 +                                    struct xdr_stream *xdr,
 +                                    const struct nfs_fh *fh)
  {
 -      return nfs3_xdr_wccstat(req, p, res->dir_attr);
 +      encode_nfs_fh3(xdr, fh);
  }
  
  /*
 - * Decode LOOKUP reply
 + * 3.3.2  SETATTR3args
 + *
 + *    union sattrguard3 switch (bool check) {
 + *    case TRUE:
 + *            nfstime3  obj_ctime;
 + *    case FALSE:
 + *            void;
 + *    };
 + *
 + *    struct SETATTR3args {
 + *            nfs_fh3         object;
 + *            sattr3          new_attributes;
 + *            sattrguard3     guard;
 + *    };
   */
 -static int
 -nfs3_xdr_lookupres(struct rpc_rqst *req, __be32 *p, struct nfs3_diropres *res)
 +static void encode_sattrguard3(struct xdr_stream *xdr,
 +                             const struct nfs3_sattrargs *args)
  {
 -      int     status;
 +      __be32 *p;
  
 -      if ((status = ntohl(*p++))) {
 -              status = nfs_stat_to_errno(status);
 +      if (args->guard) {
 +              p = xdr_reserve_space(xdr, 4 + 8);
 +              *p++ = xdr_one;
 +              xdr_encode_nfstime3(p, &args->guardtime);
        } else {
 -              if (!(p = xdr_decode_fhandle(p, res->fh)))
 -                      return -errno_NFSERR_IO;
 -              p = xdr_decode_post_op_attr(p, res->fattr);
 +              p = xdr_reserve_space(xdr, 4);
 +              *p = xdr_zero;
        }
 -      xdr_decode_post_op_attr(p, res->dir_attr);
 -      return status;
 +}
 +
 +static void nfs3_xdr_enc_setattr3args(struct rpc_rqst *req,
 +                                    struct xdr_stream *xdr,
 +                                    const struct nfs3_sattrargs *args)
 +{
 +      encode_nfs_fh3(xdr, args->fh);
 +      encode_sattr3(xdr, args->sattr);
 +      encode_sattrguard3(xdr, args);
  }
  
  /*
 - * Decode ACCESS reply
 + * 3.3.3  LOOKUP3args
 + *
 + *    struct LOOKUP3args {
 + *            diropargs3  what;
 + *    };
   */
 -static int
 -nfs3_xdr_accessres(struct rpc_rqst *req, __be32 *p, struct nfs3_accessres *res)
 +static void nfs3_xdr_enc_lookup3args(struct rpc_rqst *req,
 +                                   struct xdr_stream *xdr,
 +                                   const struct nfs3_diropargs *args)
  {
 -      int     status = ntohl(*p++);
 +      encode_diropargs3(xdr, args->fh, args->name, args->len);
 +}
  
 -      p = xdr_decode_post_op_attr(p, res->fattr);
 -      if (status)
 -              return nfs_stat_to_errno(status);
 -      res->access = ntohl(*p++);
 -      return 0;
 +/*
 + * 3.3.4  ACCESS3args
 + *
 + *    struct ACCESS3args {
 + *            nfs_fh3         object;
 + *            uint32          access;
 + *    };
 + */
 +static void encode_access3args(struct xdr_stream *xdr,
 +                             const struct nfs3_accessargs *args)
 +{
 +      encode_nfs_fh3(xdr, args->fh);
 +      encode_uint32(xdr, args->access);
  }
  
 -static int
 -nfs3_xdr_readlinkargs(struct rpc_rqst *req, __be32 *p, struct nfs3_readlinkargs *args)
 +static void nfs3_xdr_enc_access3args(struct rpc_rqst *req,
 +                                   struct xdr_stream *xdr,
 +                                   const struct nfs3_accessargs *args)
  {
 -      struct rpc_auth *auth = req->rq_cred->cr_auth;
 -      unsigned int replen;
 +      encode_access3args(xdr, args);
 +}
  
 -      p = xdr_encode_fhandle(p, args->fh);
 -      req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
 +/*
 + * 3.3.5  READLINK3args
 + *
 + *    struct READLINK3args {
 + *            nfs_fh3 symlink;
 + *    };
 + */
 +static void nfs3_xdr_enc_readlink3args(struct rpc_rqst *req,
 +                                     struct xdr_stream *xdr,
 +                                     const struct nfs3_readlinkargs *args)
 +{
 +      encode_nfs_fh3(xdr, args->fh);
 +      prepare_reply_buffer(req, args->pages, args->pgbase,
 +                                      args->pglen, NFS3_readlinkres_sz);
 +}
  
 -      /* Inline the page array */
 -      replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS3_readlinkres_sz) << 2;
 -      xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, args->pgbase, args->pglen);
 -      return 0;
 +/*
 + * 3.3.6  READ3args
 + *
 + *    struct READ3args {
 + *            nfs_fh3         file;
 + *            offset3         offset;
 + *            count3          count;
 + *    };
 + */
 +static void encode_read3args(struct xdr_stream *xdr,
 +                           const struct nfs_readargs *args)
 +{
 +      __be32 *p;
 +
 +      encode_nfs_fh3(xdr, args->fh);
 +
 +      p = xdr_reserve_space(xdr, 8 + 4);
 +      p = xdr_encode_hyper(p, args->offset);
 +      *p = cpu_to_be32(args->count);
 +}
 +
 +static void nfs3_xdr_enc_read3args(struct rpc_rqst *req,
 +                                 struct xdr_stream *xdr,
 +                                 const struct nfs_readargs *args)
 +{
 +      encode_read3args(xdr, args);
 +      prepare_reply_buffer(req, args->pages, args->pgbase,
 +                                      args->count, NFS3_readres_sz);
 +      req->rq_rcv_buf.flags |= XDRBUF_READ;
  }
  
  /*
 - * Decode READLINK reply
 + * 3.3.7  WRITE3args
 + *
 + *    enum stable_how {
 + *            UNSTABLE  = 0,
 + *            DATA_SYNC = 1,
 + *            FILE_SYNC = 2
 + *    };
 + *
 + *    struct WRITE3args {
 + *            nfs_fh3         file;
 + *            offset3         offset;
 + *            count3          count;
 + *            stable_how      stable;
 + *            opaque          data<>;
 + *    };
   */
 -static int
 -nfs3_xdr_readlinkres(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
 +static void encode_write3args(struct xdr_stream *xdr,
 +                            const struct nfs_writeargs *args)
  {
 -      struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
 -      struct kvec *iov = rcvbuf->head;
 -      size_t hdrlen;
 -      u32 len, recvd;
 -      int     status;
 +      __be32 *p;
  
 -      status = ntohl(*p++);
 -      p = xdr_decode_post_op_attr(p, fattr);
 +      encode_nfs_fh3(xdr, args->fh);
  
 -      if (status != 0)
 -              return nfs_stat_to_errno(status);
 +      p = xdr_reserve_space(xdr, 8 + 4 + 4 + 4);
 +      p = xdr_encode_hyper(p, args->offset);
 +      *p++ = cpu_to_be32(args->count);
 +      *p++ = cpu_to_be32(args->stable);
 +      *p = cpu_to_be32(args->count);
 +      xdr_write_pages(xdr, args->pages, args->pgbase, args->count);
 +}
  
 -      /* Convert length of symlink */
 -      len = ntohl(*p++);
 -      if (len >= rcvbuf->page_len) {
 -              dprintk("nfs: server returned giant symlink!\n");
 -              return -ENAMETOOLONG;
 -      }
 +static void nfs3_xdr_enc_write3args(struct rpc_rqst *req,
 +                                  struct xdr_stream *xdr,
 +                                  const struct nfs_writeargs *args)
 +{
 +      encode_write3args(xdr, args);
 +      xdr->buf->flags |= XDRBUF_WRITE;
 +}
  
 -      hdrlen = (u8 *) p - (u8 *) iov->iov_base;
 -      if (iov->iov_len < hdrlen) {
 -              dprintk("NFS: READLINK reply header overflowed:"
 -                              "length %Zu > %Zu\n", hdrlen, iov->iov_len);
 -              return -errno_NFSERR_IO;
 -      } else if (iov->iov_len != hdrlen) {
 -              dprintk("NFS: READLINK header is short. "
 -                      "iovec will be shifted.\n");
 -              xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen);
 -      }
 -      recvd = req->rq_rcv_buf.len - hdrlen;
 -      if (recvd < len) {
 -              dprintk("NFS: server cheating in readlink reply: "
 -                              "count %u > recvd %u\n", len, recvd);
 -              return -EIO;
 +/*
 + * 3.3.8  CREATE3args
 + *
 + *    enum createmode3 {
 + *            UNCHECKED = 0,
 + *            GUARDED   = 1,
 + *            EXCLUSIVE = 2
 + *    };
 + *
 + *    union createhow3 switch (createmode3 mode) {
 + *    case UNCHECKED:
 + *    case GUARDED:
 + *            sattr3       obj_attributes;
 + *    case EXCLUSIVE:
 + *            createverf3  verf;
 + *    };
 + *
 + *    struct CREATE3args {
 + *            diropargs3      where;
 + *            createhow3      how;
 + *    };
 + */
 +static void encode_createhow3(struct xdr_stream *xdr,
 +                            const struct nfs3_createargs *args)
 +{
 +      encode_uint32(xdr, args->createmode);
 +      switch (args->createmode) {
 +      case NFS3_CREATE_UNCHECKED:
 +      case NFS3_CREATE_GUARDED:
 +              encode_sattr3(xdr, args->sattr);
 +              break;
 +      case NFS3_CREATE_EXCLUSIVE:
 +              encode_createverf3(xdr, args->verifier);
 +              break;
 +      default:
 +              BUG();
        }
 +}
  
 -      xdr_terminate_string(rcvbuf, len);
 -      return 0;
 +static void nfs3_xdr_enc_create3args(struct rpc_rqst *req,
 +                                   struct xdr_stream *xdr,
 +                                   const struct nfs3_createargs *args)
 +{
 +      encode_diropargs3(xdr, args->fh, args->name, args->len);
 +      encode_createhow3(xdr, args);
  }
  
  /*
 - * Decode READ reply
 + * 3.3.9  MKDIR3args
 + *
 + *    struct MKDIR3args {
 + *            diropargs3      where;
 + *            sattr3          attributes;
 + *    };
   */
 -static int
 -nfs3_xdr_readres(struct rpc_rqst *req, __be32 *p, struct nfs_readres *res)
 +static void nfs3_xdr_enc_mkdir3args(struct rpc_rqst *req,
 +                                  struct xdr_stream *xdr,
 +                                  const struct nfs3_mkdirargs *args)
  {
 -      struct kvec *iov = req->rq_rcv_buf.head;
 -      size_t hdrlen;
 -      u32 count, ocount, recvd;
 -      int status;
 +      encode_diropargs3(xdr, args->fh, args->name, args->len);
 +      encode_sattr3(xdr, args->sattr);
 +}
  
 -      status = ntohl(*p++);
 -      p = xdr_decode_post_op_attr(p, res->fattr);
 +/*
 + * 3.3.10  SYMLINK3args
 + *
 + *    struct symlinkdata3 {
 + *            sattr3          symlink_attributes;
 + *            nfspath3        symlink_data;
 + *    };
 + *
 + *    struct SYMLINK3args {
 + *            diropargs3      where;
 + *            symlinkdata3    symlink;
 + *    };
 + */
 +static void encode_symlinkdata3(struct xdr_stream *xdr,
 +                              const struct nfs3_symlinkargs *args)
 +{
 +      encode_sattr3(xdr, args->sattr);
 +      encode_nfspath3(xdr, args->pages, args->pathlen);
 +}
  
 -      if (status != 0)
 -              return nfs_stat_to_errno(status);
 +static void nfs3_xdr_enc_symlink3args(struct rpc_rqst *req,
 +                                    struct xdr_stream *xdr,
 +                                    const struct nfs3_symlinkargs *args)
 +{
 +      encode_diropargs3(xdr, args->fromfh, args->fromname, args->fromlen);
 +      encode_symlinkdata3(xdr, args);
 +}
  
 -      /* Decode reply count and EOF flag. NFSv3 is somewhat redundant
 -       * in that it puts the count both in the res struct and in the
 -       * opaque data count. */
 -      count    = ntohl(*p++);
 -      res->eof = ntohl(*p++);
 -      ocount   = ntohl(*p++);
 +/*
 + * 3.3.11  MKNOD3args
 + *
 + *    struct devicedata3 {
 + *            sattr3          dev_attributes;
 + *            specdata3       spec;
 + *    };
 + *
 + *    union mknoddata3 switch (ftype3 type) {
 + *    case NF3CHR:
 + *    case NF3BLK:
 + *            devicedata3     device;
 + *    case NF3SOCK:
 + *    case NF3FIFO:
 + *            sattr3          pipe_attributes;
 + *    default:
 + *            void;
 + *    };
 + *
 + *    struct MKNOD3args {
 + *            diropargs3      where;
 + *            mknoddata3      what;
 + *    };
 + */
 +static void encode_devicedata3(struct xdr_stream *xdr,
 +                             const struct nfs3_mknodargs *args)
 +{
 +      encode_sattr3(xdr, args->sattr);
 +      encode_specdata3(xdr, args->rdev);
 +}
  
 -      if (ocount != count) {
 -              dprintk("NFS: READ count doesn't match RPC opaque count.\n");
 -              return -errno_NFSERR_IO;
 +static void encode_mknoddata3(struct xdr_stream *xdr,
 +                            const struct nfs3_mknodargs *args)
 +{
 +      encode_ftype3(xdr, args->type);
 +      switch (args->type) {
 +      case NF3CHR:
 +      case NF3BLK:
 +              encode_devicedata3(xdr, args);
 +              break;
 +      case NF3SOCK:
 +      case NF3FIFO:
 +              encode_sattr3(xdr, args->sattr);
 +              break;
 +      case NF3REG:
 +      case NF3DIR:
 +              break;
 +      default:
 +              BUG();
        }
 +}
  
 -      hdrlen = (u8 *) p - (u8 *) iov->iov_base;
 -      if (iov->iov_len < hdrlen) {
 -              dprintk("NFS: READ reply header overflowed:"
 -                              "length %Zu > %Zu\n", hdrlen, iov->iov_len);
 -                      return -errno_NFSERR_IO;
 -      } else if (iov->iov_len != hdrlen) {
 -              dprintk("NFS: READ header is short. iovec will be shifted.\n");
 -              xdr_shift_buf(&req->rq_rcv_buf, iov->iov_len - hdrlen);
 -      }
 +static void nfs3_xdr_enc_mknod3args(struct rpc_rqst *req,
 +                                  struct xdr_stream *xdr,
 +                                  const struct nfs3_mknodargs *args)
 +{
 +      encode_diropargs3(xdr, args->fh, args->name, args->len);
 +      encode_mknoddata3(xdr, args);
 +}
  
 -      recvd = req->rq_rcv_buf.len - hdrlen;
 -      if (count > recvd) {
 -              dprintk("NFS: server cheating in read reply: "
 -                      "count %u > recvd %u\n", count, recvd);
 -              count = recvd;
 -              res->eof = 0;
 -      }
 +/*
 + * 3.3.12  REMOVE3args
 + *
 + *    struct REMOVE3args {
 + *            diropargs3  object;
 + *    };
 + */
 +static void nfs3_xdr_enc_remove3args(struct rpc_rqst *req,
 +                                   struct xdr_stream *xdr,
 +                                   const struct nfs_removeargs *args)
 +{
 +      encode_diropargs3(xdr, args->fh, args->name.name, args->name.len);
 +}
  
 -      if (count < res->count)
 -              res->count = count;
 +/*
 + * 3.3.14  RENAME3args
 + *
 + *    struct RENAME3args {
 + *            diropargs3      from;
 + *            diropargs3      to;
 + *    };
 + */
 +static void nfs3_xdr_enc_rename3args(struct rpc_rqst *req,
 +                                   struct xdr_stream *xdr,
 +                                   const struct nfs_renameargs *args)
 +{
 +      const struct qstr *old = args->old_name;
 +      const struct qstr *new = args->new_name;
  
 -      return count;
 +      encode_diropargs3(xdr, args->old_dir, old->name, old->len);
 +      encode_diropargs3(xdr, args->new_dir, new->name, new->len);
  }
  
  /*
 - * Decode WRITE response
 + * 3.3.15  LINK3args
 + *
 + *    struct LINK3args {
 + *            nfs_fh3         file;
 + *            diropargs3      link;
 + *    };
   */
 -static int
 -nfs3_xdr_writeres(struct rpc_rqst *req, __be32 *p, struct nfs_writeres *res)
 +static void nfs3_xdr_enc_link3args(struct rpc_rqst *req,
 +                                 struct xdr_stream *xdr,
 +                                 const struct nfs3_linkargs *args)
  {
 -      int     status;
 +      encode_nfs_fh3(xdr, args->fromfh);
 +      encode_diropargs3(xdr, args->tofh, args->toname, args->tolen);
 +}
  
 -      status = ntohl(*p++);
 -      p = xdr_decode_wcc_data(p, res->fattr);
 +/*
 + * 3.3.16  READDIR3args
 + *
 + *    struct READDIR3args {
 + *            nfs_fh3         dir;
 + *            cookie3         cookie;
 + *            cookieverf3     cookieverf;
 + *            count3          count;
 + *    };
 + */
 +static void encode_readdir3args(struct xdr_stream *xdr,
 +                              const struct nfs3_readdirargs *args)
 +{
 +      __be32 *p;
  
 -      if (status != 0)
 -              return nfs_stat_to_errno(status);
 +      encode_nfs_fh3(xdr, args->fh);
  
 -      res->count = ntohl(*p++);
 -      res->verf->committed = (enum nfs3_stable_how)ntohl(*p++);
 -      res->verf->verifier[0] = *p++;
 -      res->verf->verifier[1] = *p++;
 +      p = xdr_reserve_space(xdr, 8 + NFS3_COOKIEVERFSIZE + 4);
 +      p = xdr_encode_cookie3(p, args->cookie);
 +      p = xdr_encode_cookieverf3(p, args->verf);
 +      *p = cpu_to_be32(args->count);
 +}
  
 -      return res->count;
 +static void nfs3_xdr_enc_readdir3args(struct rpc_rqst *req,
 +                                    struct xdr_stream *xdr,
 +                                    const struct nfs3_readdirargs *args)
 +{
 +      encode_readdir3args(xdr, args);
 +      prepare_reply_buffer(req, args->pages, 0,
 +                              args->count, NFS3_readdirres_sz);
  }
  
  /*
 - * Decode a CREATE response
 + * 3.3.17  READDIRPLUS3args
 + *
 + *    struct READDIRPLUS3args {
 + *            nfs_fh3         dir;
 + *            cookie3         cookie;
 + *            cookieverf3     cookieverf;
 + *            count3          dircount;
 + *            count3          maxcount;
 + *    };
   */
 -static int
 -nfs3_xdr_createres(struct rpc_rqst *req, __be32 *p, struct nfs3_diropres *res)
 -{
 -      int     status;
 -
 -      status = ntohl(*p++);
 -      if (status == 0) {
 -              if (*p++) {
 -                      if (!(p = xdr_decode_fhandle(p, res->fh)))
 -                              return -errno_NFSERR_IO;
 -                      p = xdr_decode_post_op_attr(p, res->fattr);
 -              } else {
 -                      memset(res->fh, 0, sizeof(*res->fh));
 -                      /* Do decode post_op_attr but set it to NULL */
 -                      p = xdr_decode_post_op_attr(p, res->fattr);
 -                      res->fattr->valid = 0;
 -              }
 -      } else {
 -              status = nfs_stat_to_errno(status);
 -      }
 -      p = xdr_decode_wcc_data(p, res->dir_attr);
 -      return status;
 +static void encode_readdirplus3args(struct xdr_stream *xdr,
 +                                  const struct nfs3_readdirargs *args)
 +{
 +      __be32 *p;
 +
 +      encode_nfs_fh3(xdr, args->fh);
 +
 +      p = xdr_reserve_space(xdr, 8 + NFS3_COOKIEVERFSIZE + 4 + 4);
 +      p = xdr_encode_cookie3(p, args->cookie);
 +      p = xdr_encode_cookieverf3(p, args->verf);
 +
 +      /*
 +       * readdirplus: need dircount + buffer size.
 +       * We just make sure we make dircount big enough
 +       */
 +      *p++ = cpu_to_be32(args->count >> 3);
 +
 +      *p = cpu_to_be32(args->count);
 +}
 +
 +static void nfs3_xdr_enc_readdirplus3args(struct rpc_rqst *req,
 +                                        struct xdr_stream *xdr,
 +                                        const struct nfs3_readdirargs *args)
 +{
 +      encode_readdirplus3args(xdr, args);
 +      prepare_reply_buffer(req, args->pages, 0,
 +                              args->count, NFS3_readdirres_sz);
  }
  
  /*
 - * Decode RENAME reply
 + * 3.3.21  COMMIT3args
 + *
 + *    struct COMMIT3args {
 + *            nfs_fh3         file;
 + *            offset3         offset;
 + *            count3          count;
 + *    };
   */
 -static int
 -nfs3_xdr_renameres(struct rpc_rqst *req, __be32 *p, struct nfs_renameres *res)
 +static void encode_commit3args(struct xdr_stream *xdr,
 +                             const struct nfs_writeargs *args)
  {
 -      int     status;
 +      __be32 *p;
 +
 +      encode_nfs_fh3(xdr, args->fh);
 +
 +      p = xdr_reserve_space(xdr, 8 + 4);
 +      p = xdr_encode_hyper(p, args->offset);
 +      *p = cpu_to_be32(args->count);
 +}
  
 -      if ((status = ntohl(*p++)) != 0)
 -              status = nfs_stat_to_errno(status);
 -      p = xdr_decode_wcc_data(p, res->old_fattr);
 -      p = xdr_decode_wcc_data(p, res->new_fattr);
 -      return status;
 +static void nfs3_xdr_enc_commit3args(struct rpc_rqst *req,
 +                                   struct xdr_stream *xdr,
 +                                   const struct nfs_writeargs *args)
 +{
 +      encode_commit3args(xdr, args);
  }
  
 +#ifdef CONFIG_NFS_V3_ACL
 +
 +static void nfs3_xdr_enc_getacl3args(struct rpc_rqst *req,
 +                                   struct xdr_stream *xdr,
 +                                   const struct nfs3_getaclargs *args)
 +{
 +      encode_nfs_fh3(xdr, args->fh);
 +      encode_uint32(xdr, args->mask);
 +      if (args->mask & (NFS_ACL | NFS_DFACL))
 +              prepare_reply_buffer(req, args->pages, 0,
 +                                      NFSACL_MAXPAGES << PAGE_SHIFT,
 +                                      ACL3_getaclres_sz);
 +}
 +
 +static void nfs3_xdr_enc_setacl3args(struct rpc_rqst *req,
 +                                   struct xdr_stream *xdr,
 +                                   const struct nfs3_setaclargs *args)
 +{
 +      unsigned int base;
 +      int error;
 +
 +      encode_nfs_fh3(xdr, NFS_FH(args->inode));
 +      encode_uint32(xdr, args->mask);
 +      if (args->npages != 0)
 +              xdr_write_pages(xdr, args->pages, 0, args->len);
 +
 +      base = req->rq_slen;
 +      error = nfsacl_encode(xdr->buf, base, args->inode,
 +                          (args->mask & NFS_ACL) ?
 +                          args->acl_access : NULL, 1, 0);
 +      BUG_ON(error < 0);
 +      error = nfsacl_encode(xdr->buf, base + error, args->inode,
 +                          (args->mask & NFS_DFACL) ?
 +                          args->acl_default : NULL, 1,
 +                          NFS_ACL_DEFAULT);
 +      BUG_ON(error < 0);
 +}
 +
 +#endif  /* CONFIG_NFS_V3_ACL */
 +
  /*
 - * Decode LINK reply
 + * NFSv3 XDR decode functions
 + *
 + * NFSv3 result types are defined in section 3.3 of RFC 1813:
 + * "NFS Version 3 Protocol Specification".
   */
 -static int
 -nfs3_xdr_linkres(struct rpc_rqst *req, __be32 *p, struct nfs3_linkres *res)
 +
 +/*
 + * 3.3.1  GETATTR3res
 + *
 + *    struct GETATTR3resok {
 + *            fattr3          obj_attributes;
 + *    };
 + *
 + *    union GETATTR3res switch (nfsstat3 status) {
 + *    case NFS3_OK:
 + *            GETATTR3resok  resok;
 + *    default:
 + *            void;
 + *    };
 + */
 +static int nfs3_xdr_dec_getattr3res(struct rpc_rqst *req,
 +                                  struct xdr_stream *xdr,
 +                                  struct nfs_fattr *result)
  {
 -      int     status;
 +      enum nfs_stat status;
 +      int error;
 +
 +      error = decode_nfsstat3(xdr, &status);
 +      if (unlikely(error))
 +              goto out;
 +      if (status != NFS3_OK)
 +              goto out_default;
 +      error = decode_fattr3(xdr, result);
 +out:
 +      return error;
 +out_default:
 +      return nfs_stat_to_errno(status);
 +}
  
 -      if ((status = ntohl(*p++)) != 0)
 -              status = nfs_stat_to_errno(status);
 -      p = xdr_decode_post_op_attr(p, res->fattr);
 -      p = xdr_decode_wcc_data(p, res->dir_attr);
 -      return status;
 +/*
 + * 3.3.2  SETATTR3res
 + *
 + *    struct SETATTR3resok {
 + *            wcc_data  obj_wcc;
 + *    };
 + *
 + *    struct SETATTR3resfail {
 + *            wcc_data  obj_wcc;
 + *    };
 + *
 + *    union SETATTR3res switch (nfsstat3 status) {
 + *    case NFS3_OK:
 + *            SETATTR3resok   resok;
 + *    default:
 + *            SETATTR3resfail resfail;
 + *    };
 + */
 +static int nfs3_xdr_dec_setattr3res(struct rpc_rqst *req,
 +                                  struct xdr_stream *xdr,
 +                                  struct nfs_fattr *result)
 +{
 +      enum nfs_stat status;
 +      int error;
 +
 +      error = decode_nfsstat3(xdr, &status);
 +      if (unlikely(error))
 +              goto out;
 +      error = decode_wcc_data(xdr, result);
 +      if (unlikely(error))
 +              goto out;
 +      if (status != NFS3_OK)
 +              goto out_status;
 +out:
 +      return error;
 +out_status:
 +      return nfs_stat_to_errno(status);
  }
  
  /*
 - * Decode FSSTAT reply
 + * 3.3.3  LOOKUP3res
 + *
 + *    struct LOOKUP3resok {
 + *            nfs_fh3         object;
 + *            post_op_attr    obj_attributes;
 + *            post_op_attr    dir_attributes;
 + *    };
 + *
 + *    struct LOOKUP3resfail {
 + *            post_op_attr    dir_attributes;
 + *    };
 + *
 + *    union LOOKUP3res switch (nfsstat3 status) {
 + *    case NFS3_OK:
 + *            LOOKUP3resok    resok;
 + *    default:
 + *            LOOKUP3resfail  resfail;
 + *    };
   */
 -static int
 -nfs3_xdr_fsstatres(struct rpc_rqst *req, __be32 *p, struct nfs_fsstat *res)
 +static int nfs3_xdr_dec_lookup3res(struct rpc_rqst *req,
 +                                 struct xdr_stream *xdr,
 +                                 struct nfs3_diropres *result)
  {
 -      int             status;
 +      enum nfs_stat status;
 +      int error;
 +
 +      error = decode_nfsstat3(xdr, &status);
 +      if (unlikely(error))
 +              goto out;
 +      if (status != NFS3_OK)
 +              goto out_default;
 +      error = decode_nfs_fh3(xdr, result->fh);
 +      if (unlikely(error))
 +              goto out;
 +      error = decode_post_op_attr(xdr, result->fattr);
 +      if (unlikely(error))
 +              goto out;
 +      error = decode_post_op_attr(xdr, result->dir_attr);
 +out:
 +      return error;
 +out_default:
 +      error = decode_post_op_attr(xdr, result->dir_attr);
 +      if (unlikely(error))
 +              goto out;
 +      return nfs_stat_to_errno(status);
 +}
  
 -      status = ntohl(*p++);
 +/*
 + * 3.3.4  ACCESS3res
 + *
 + *    struct ACCESS3resok {
 + *            post_op_attr    obj_attributes;
 + *            uint32          access;
 + *    };
 + *
 + *    struct ACCESS3resfail {
 + *            post_op_attr    obj_attributes;
 + *    };
 + *
 + *    union ACCESS3res switch (nfsstat3 status) {
 + *    case NFS3_OK:
 + *            ACCESS3resok    resok;
 + *    default:
 + *            ACCESS3resfail  resfail;
 + *    };
 + */
 +static int nfs3_xdr_dec_access3res(struct rpc_rqst *req,
 +                                 struct xdr_stream *xdr,
 +                                 struct nfs3_accessres *result)
 +{
 +      enum nfs_stat status;
 +      int error;
 +
 +      error = decode_nfsstat3(xdr, &status);
 +      if (unlikely(error))
 +              goto out;
 +      error = decode_post_op_attr(xdr, result->fattr);
 +      if (unlikely(error))
 +              goto out;
 +      if (status != NFS3_OK)
 +              goto out_default;
 +      error = decode_uint32(xdr, &result->access);
 +out:
 +      return error;
 +out_default:
 +      return nfs_stat_to_errno(status);
 +}
  
 -      p = xdr_decode_post_op_attr(p, res->fattr);
 -      if (status != 0)
 -              return nfs_stat_to_errno(status);
 +/*
 + * 3.3.5  READLINK3res
 + *
 + *    struct READLINK3resok {
 + *            post_op_attr    symlink_attributes;
 + *            nfspath3        data;
 + *    };
 + *
 + *    struct READLINK3resfail {
 + *            post_op_attr    symlink_attributes;
 + *    };
 + *
 + *    union READLINK3res switch (nfsstat3 status) {
 + *    case NFS3_OK:
 + *            READLINK3resok  resok;
 + *    default:
 + *            READLINK3resfail resfail;
 + *    };
 + */
 +static int nfs3_xdr_dec_readlink3res(struct rpc_rqst *req,
 +                                   struct xdr_stream *xdr,
 +                                   struct nfs_fattr *result)
 +{
 +      enum nfs_stat status;
 +      int error;
 +
 +      error = decode_nfsstat3(xdr, &status);
 +      if (unlikely(error))
 +              goto out;
 +      error = decode_post_op_attr(xdr, result);
 +      if (unlikely(error))
 +              goto out;
 +      if (status != NFS3_OK)
 +              goto out_default;
 +      error = decode_nfspath3(xdr);
 +out:
 +      return error;
 +out_default:
 +      return nfs_stat_to_errno(status);
 +}
  
 -      p = xdr_decode_hyper(p, &res->tbytes);
 -      p = xdr_decode_hyper(p, &res->fbytes);
 -      p = xdr_decode_hyper(p, &res->abytes);
 -      p = xdr_decode_hyper(p, &res->tfiles);
 -      p = xdr_decode_hyper(p, &res->ffiles);
 -      p = xdr_decode_hyper(p, &res->afiles);
 +/*
 + * 3.3.6  READ3res
 + *
 + *    struct READ3resok {
 + *            post_op_attr    file_attributes;
 + *            count3          count;
 + *            bool            eof;
 + *            opaque          data<>;
 + *    };
 + *
 + *    struct READ3resfail {
 + *            post_op_attr    file_attributes;
 + *    };
 + *
 + *    union READ3res switch (nfsstat3 status) {
 + *    case NFS3_OK:
 + *            READ3resok      resok;
 + *    default:
 + *            READ3resfail    resfail;
 + *    };
 + */
 +static int decode_read3resok(struct xdr_stream *xdr,
 +                           struct nfs_readres *result)
 +{
 +      u32 eof, count, ocount, recvd;
 +      size_t hdrlen;
 +      __be32 *p;
  
 -      /* ignore invarsec */
 -      return 0;
 +      p = xdr_inline_decode(xdr, 4 + 4 + 4);
 +      if (unlikely(p == NULL))
 +              goto out_overflow;
 +      count = be32_to_cpup(p++);
 +      eof = be32_to_cpup(p++);
 +      ocount = be32_to_cpup(p++);
 +      if (unlikely(ocount != count))
 +              goto out_mismatch;
 +      hdrlen = (u8 *)xdr->p - (u8 *)xdr->iov->iov_base;
 +      recvd = xdr->buf->len - hdrlen;
 +      if (unlikely(count > recvd))
 +              goto out_cheating;
 +
 +out:
 +      xdr_read_pages(xdr, count);
 +      result->eof = eof;
 +      result->count = count;
 +      return count;
 +out_mismatch:
 +      dprintk("NFS: READ count doesn't match length of opaque: "
 +              "count %u != ocount %u\n", count, ocount);
 +      return -EIO;
 +out_cheating:
 +      dprintk("NFS: server cheating in read result: "
 +              "count %u > recvd %u\n", count, recvd);
 +      count = recvd;
 +      eof = 0;
 +      goto out;
 +out_overflow:
 +      print_overflow_msg(__func__, xdr);
 +      return -EIO;
 +}
 +
 +static int nfs3_xdr_dec_read3res(struct rpc_rqst *req, struct xdr_stream *xdr,
 +                               struct nfs_readres *result)
 +{
 +      enum nfs_stat status;
 +      int error;
 +
 +      error = decode_nfsstat3(xdr, &status);
 +      if (unlikely(error))
 +              goto out;
 +      error = decode_post_op_attr(xdr, result->fattr);
 +      if (unlikely(error))
 +              goto out;
 +      if (status != NFS3_OK)
 +              goto out_status;
 +      error = decode_read3resok(xdr, result);
 +out:
 +      return error;
 +out_status:
 +      return nfs_stat_to_errno(status);
  }
  
  /*
 - * Decode FSINFO reply
 + * 3.3.7  WRITE3res
 + *
 + *    enum stable_how {
 + *            UNSTABLE  = 0,
 + *            DATA_SYNC = 1,
 + *            FILE_SYNC = 2
 + *    };
 + *
 + *    struct WRITE3resok {
 + *            wcc_data        file_wcc;
 + *            count3          count;
 + *            stable_how      committed;
 + *            writeverf3      verf;
 + *    };
 + *
 + *    struct WRITE3resfail {
 + *            wcc_data        file_wcc;
 + *    };
 + *
 + *    union WRITE3res switch (nfsstat3 status) {
 + *    case NFS3_OK:
 + *            WRITE3resok     resok;
 + *    default:
 + *            WRITE3resfail   resfail;
 + *    };
   */
 -static int
 -nfs3_xdr_fsinfores(struct rpc_rqst *req, __be32 *p, struct nfs_fsinfo *res)
 +static int decode_write3resok(struct xdr_stream *xdr,
 +                            struct nfs_writeres *result)
  {
 -      int             status;
 +      __be32 *p;
  
 -      status = ntohl(*p++);
 +      p = xdr_inline_decode(xdr, 4 + 4 + NFS3_WRITEVERFSIZE);
 +      if (unlikely(p == NULL))
 +              goto out_overflow;
 +      result->count = be32_to_cpup(p++);
 +      result->verf->committed = be32_to_cpup(p++);
 +      if (unlikely(result->verf->committed > NFS_FILE_SYNC))
 +              goto out_badvalue;
 +      memcpy(result->verf->verifier, p, NFS3_WRITEVERFSIZE);
 +      return result->count;
 +out_badvalue:
 +      dprintk("NFS: bad stable_how value: %u\n", result->verf->committed);
 +      return -EIO;
 +out_overflow:
 +      print_overflow_msg(__func__, xdr);
 +      return -EIO;
 +}
  
 -      p = xdr_decode_post_op_attr(p, res->fattr);
 -      if (status != 0)
 -              return nfs_stat_to_errno(status);
 +static int nfs3_xdr_dec_write3res(struct rpc_rqst *req, struct xdr_stream *xdr,
 +                                struct nfs_writeres *result)
 +{
 +      enum nfs_stat status;
 +      int error;
 +
 +      error = decode_nfsstat3(xdr, &status);
 +      if (unlikely(error))
 +              goto out;
 +      error = decode_wcc_data(xdr, result->fattr);
 +      if (unlikely(error))
 +              goto out;
 +      if (status != NFS3_OK)
 +              goto out_status;
 +      error = decode_write3resok(xdr, result);
 +out:
 +      return error;
 +out_status:
 +      return nfs_stat_to_errno(status);
 +}
  
 -      res->rtmax  = ntohl(*p++);
 -      res->rtpref = ntohl(*p++);
 -      res->rtmult = ntohl(*p++);
 -      res->wtmax  = ntohl(*p++);
 -      res->wtpref = ntohl(*p++);
 -      res->wtmult = ntohl(*p++);
 -      res->dtpref = ntohl(*p++);
 -      p = xdr_decode_hyper(p, &res->maxfilesize);
 -      p = xdr_decode_time3(p, &res->time_delta);
 +/*
 + * 3.3.8  CREATE3res
 + *
 + *    struct CREATE3resok {
 + *            post_op_fh3     obj;
 + *            post_op_attr    obj_attributes;
 + *            wcc_data        dir_wcc;
 + *    };
 + *
 + *    struct CREATE3resfail {
 + *            wcc_data        dir_wcc;
 + *    };
 + *
 + *    union CREATE3res switch (nfsstat3 status) {
 + *    case NFS3_OK:
 + *            CREATE3resok    resok;
 + *    default:
 + *            CREATE3resfail  resfail;
 + *    };
 + */
 +static int decode_create3resok(struct xdr_stream *xdr,
 +                             struct nfs3_diropres *result)
 +{
 +      int error;
 +
 +      error = decode_post_op_fh3(xdr, result->fh);
 +      if (unlikely(error))
 +              goto out;
 +      error = decode_post_op_attr(xdr, result->fattr);
 +      if (unlikely(error))
 +              goto out;
 +      /* The server isn't required to return a file handle.
 +       * If it didn't, force the client to perform a LOOKUP
 +       * to determine the correct file handle and attribute
 +       * values for the new object. */
 +      if (result->fh->size == 0)
 +              result->fattr->valid = 0;
 +      error = decode_wcc_data(xdr, result->dir_attr);
 +out:
 +      return error;
 +}
  
 -      /* ignore properties */
 -      res->lease_time = 0;
 -      return 0;
 +static int nfs3_xdr_dec_create3res(struct rpc_rqst *req,
 +                                 struct xdr_stream *xdr,
 +                                 struct nfs3_diropres *result)
 +{
 +      enum nfs_stat status;
 +      int error;
 +
 +      error = decode_nfsstat3(xdr, &status);
 +      if (unlikely(error))
 +              goto out;
 +      if (status != NFS3_OK)
 +              goto out_default;
 +      error = decode_create3resok(xdr, result);
 +out:
 +      return error;
 +out_default:
 +      error = decode_wcc_data(xdr, result->dir_attr);
 +      if (unlikely(error))
 +              goto out;
 +      return nfs_stat_to_errno(status);
  }
  
  /*
 - * Decode PATHCONF reply
 + * 3.3.12  REMOVE3res
 + *
 + *    struct REMOVE3resok {
 + *            wcc_data    dir_wcc;
 + *    };
 + *
 + *    struct REMOVE3resfail {
 + *            wcc_data    dir_wcc;
 + *    };
 + *
 + *    union REMOVE3res switch (nfsstat3 status) {
 + *    case NFS3_OK:
 + *            REMOVE3resok   resok;
 + *    default:
 + *            REMOVE3resfail resfail;
 + *    };
   */
 -static int
 -nfs3_xdr_pathconfres(struct rpc_rqst *req, __be32 *p, struct nfs_pathconf *res)
 +static int nfs3_xdr_dec_remove3res(struct rpc_rqst *req,
 +                                 struct xdr_stream *xdr,
 +                                 struct nfs_removeres *result)
  {
 -      int             status;
 +      enum nfs_stat status;
 +      int error;
 +
 +      error = decode_nfsstat3(xdr, &status);
 +      if (unlikely(error))
 +              goto out;
 +      error = decode_wcc_data(xdr, result->dir_attr);
 +      if (unlikely(error))
 +              goto out;
 +      if (status != NFS3_OK)
 +              goto out_status;
 +out:
 +      return error;
 +out_status:
 +      return nfs_stat_to_errno(status);
 +}
  
 -      status = ntohl(*p++);
 +/*
 + * 3.3.14  RENAME3res
 + *
 + *    struct RENAME3resok {
 + *            wcc_data        fromdir_wcc;
 + *            wcc_data        todir_wcc;
 + *    };
 + *
 + *    struct RENAME3resfail {
 + *            wcc_data        fromdir_wcc;
 + *            wcc_data        todir_wcc;
 + *    };
 + *
 + *    union RENAME3res switch (nfsstat3 status) {
 + *    case NFS3_OK:
 + *            RENAME3resok   resok;
 + *    default:
 + *            RENAME3resfail resfail;
 + *    };
 + */
 +static int nfs3_xdr_dec_rename3res(struct rpc_rqst *req,
 +                                 struct xdr_stream *xdr,
 +                                 struct nfs_renameres *result)
 +{
 +      enum nfs_stat status;
 +      int error;
 +
 +      error = decode_nfsstat3(xdr, &status);
 +      if (unlikely(error))
 +              goto out;
 +      error = decode_wcc_data(xdr, result->old_fattr);
 +      if (unlikely(error))
 +              goto out;
 +      error = decode_wcc_data(xdr, result->new_fattr);
 +      if (unlikely(error))
 +              goto out;
 +      if (status != NFS3_OK)
 +              goto out_status;
 +out:
 +      return error;
 +out_status:
 +      return nfs_stat_to_errno(status);
 +}
  
 -      p = xdr_decode_post_op_attr(p, res->fattr);
 -      if (status != 0)
 -              return nfs_stat_to_errno(status);
 -      res->max_link = ntohl(*p++);
 -      res->max_namelen = ntohl(*p++);
 +/*
 + * 3.3.15  LINK3res
 + *
 + *    struct LINK3resok {
 + *            post_op_attr    file_attributes;
 + *            wcc_data        linkdir_wcc;
 + *    };
 + *
 + *    struct LINK3resfail {
 + *            post_op_attr    file_attributes;
 + *            wcc_data        linkdir_wcc;
 + *    };
 + *
 + *    union LINK3res switch (nfsstat3 status) {
 + *    case NFS3_OK:
 + *            LINK3resok      resok;
 + *    default:
 + *            LINK3resfail    resfail;
 + *    };
 + */
 +static int nfs3_xdr_dec_link3res(struct rpc_rqst *req, struct xdr_stream *xdr,
 +                               struct nfs3_linkres *result)
 +{
 +      enum nfs_stat status;
 +      int error;
 +
 +      error = decode_nfsstat3(xdr, &status);
 +      if (unlikely(error))
 +              goto out;
 +      error = decode_post_op_attr(xdr, result->fattr);
 +      if (unlikely(error))
 +              goto out;
 +      error = decode_wcc_data(xdr, result->dir_attr);
 +      if (unlikely(error))
 +              goto out;
 +      if (status != NFS3_OK)
 +              goto out_status;
 +out:
 +      return error;
 +out_status:
 +      return nfs_stat_to_errno(status);
 +}
 +
 +/**
 + * nfs3_decode_dirent - Decode a single NFSv3 directory entry stored in
 + *                    the local page cache
 + * @xdr: XDR stream where entry resides
 + * @entry: buffer to fill in with entry data
 + * @plus: boolean indicating whether this should be a readdirplus entry
 + *
 + * Returns zero if successful, otherwise a negative errno value is
 + * returned.
 + *
 + * This function is not invoked during READDIR reply decoding, but
 + * rather whenever an application invokes the getdents(2) system call
 + * on a directory already in our cache.
 + *
 + * 3.3.16  entry3
 + *
 + *    struct entry3 {
 + *            fileid3         fileid;
 + *            filename3       name;
 + *            cookie3         cookie;
 + *            fhandle3        filehandle;
 + *            post_op_attr3   attributes;
 + *            entry3          *nextentry;
 + *    };
 + *
 + * 3.3.17  entryplus3
 + *    struct entryplus3 {
 + *            fileid3         fileid;
 + *            filename3       name;
 + *            cookie3         cookie;
 + *            post_op_attr    name_attributes;
 + *            post_op_fh3     name_handle;
 + *            entryplus3      *nextentry;
 + *    };
 + */
 +int nfs3_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry,
 +                     int plus)
 +{
 +      struct nfs_entry old = *entry;
 +      __be32 *p;
 +      int error;
 +
 +      p = xdr_inline_decode(xdr, 4);
 +      if (unlikely(p == NULL))
 +              goto out_overflow;
 +      if (*p == xdr_zero) {
 +              p = xdr_inline_decode(xdr, 4);
 +              if (unlikely(p == NULL))
 +                      goto out_overflow;
 +              if (*p == xdr_zero)
 +                      return -EAGAIN;
 +              entry->eof = 1;
 +              return -EBADCOOKIE;
 +      }
 +
 +      error = decode_fileid3(xdr, &entry->ino);
 +      if (unlikely(error))
 +              return error;
 +
 +      error = decode_inline_filename3(xdr, &entry->name, &entry->len);
 +      if (unlikely(error))
 +              return error;
 +
 +      entry->prev_cookie = entry->cookie;
 +      error = decode_cookie3(xdr, &entry->cookie);
 +      if (unlikely(error))
 +              return error;
 +
 +      entry->d_type = DT_UNKNOWN;
 +
 +      if (plus) {
 +              entry->fattr->valid = 0;
 +              error = decode_post_op_attr(xdr, entry->fattr);
 +              if (unlikely(error))
 +                      return error;
 +              if (entry->fattr->valid & NFS_ATTR_FATTR_V3)
 +                      entry->d_type = nfs_umode_to_dtype(entry->fattr->mode);
 +
 +              /* In fact, a post_op_fh3: */
 +              p = xdr_inline_decode(xdr, 4);
 +              if (unlikely(p == NULL))
 +                      goto out_overflow;
 +              if (*p != xdr_zero) {
 +                      error = decode_nfs_fh3(xdr, entry->fh);
 +                      if (unlikely(error)) {
 +                              if (error == -E2BIG)
 +                                      goto out_truncated;
 +                              return error;
 +                      }
 +              } else
 +                      zero_nfs_fh3(entry->fh);
 +      }
  
-       /* Peek at the next entry to see if we're at EOD */
-       p = xdr_inline_peek(xdr, 4 + 4);
-       entry->eof = 0;
-       if (p != NULL)
-               entry->eof = (p[0] == xdr_zero) && (p[1] != xdr_zero);
 -      /* ignore remaining fields */
        return 0;
 +
 +out_overflow:
 +      print_overflow_msg(__func__, xdr);
 +      return -EAGAIN;
 +out_truncated:
 +      dprintk("NFS: directory entry contains invalid file handle\n");
 +      *entry = old;
 +      return -EAGAIN;
  }
  
  /*
 - * Decode COMMIT reply
 + * 3.3.16  READDIR3res
 + *
 + *    struct dirlist3 {
 + *            entry3          *entries;
 + *            bool            eof;
 + *    };
 + *
 + *    struct READDIR3resok {
 + *            post_op_attr    dir_attributes;
 + *            cookieverf3     cookieverf;
 + *            dirlist3        reply;
 + *    };
 + *
 + *    struct READDIR3resfail {
 + *            post_op_attr    dir_attributes;
 + *    };
 + *
 + *    union READDIR3res switch (nfsstat3 status) {
 + *    case NFS3_OK:
 + *            READDIR3resok   resok;
 + *    default:
 + *            READDIR3resfail resfail;
 + *    };
 + *
 + * Read the directory contents into the page cache, but otherwise
 + * don't touch them.  The actual decoding is done by nfs3_decode_entry()
 + * during subsequent nfs_readdir() calls.
   */
 -static int
 -nfs3_xdr_commitres(struct rpc_rqst *req, __be32 *p, struct nfs_writeres *res)
 +static int decode_dirlist3(struct xdr_stream *xdr)
 +{
 +      u32 recvd, pglen;
 +      size_t hdrlen;
 +
 +      pglen = xdr->buf->page_len;
 +      hdrlen = (u8 *)xdr->p - (u8 *)xdr->iov->iov_base;
 +      recvd = xdr->buf->len - hdrlen;
 +      if (unlikely(pglen > recvd))
 +              goto out_cheating;
 +out:
 +      xdr_read_pages(xdr, pglen);
 +      return pglen;
 +out_cheating:
 +      dprintk("NFS: server cheating in readdir result: "
 +              "pglen %u > recvd %u\n", pglen, recvd);
 +      pglen = recvd;
 +      goto out;
 +}
 +
 +static int decode_readdir3resok(struct xdr_stream *xdr,
 +                              struct nfs3_readdirres *result)
  {
 -      int             status;
 +      int error;
 +
 +      error = decode_post_op_attr(xdr, result->dir_attr);
 +      if (unlikely(error))
 +              goto out;
 +      /* XXX: do we need to check if result->verf != NULL ? */
 +      error = decode_cookieverf3(xdr, result->verf);
 +      if (unlikely(error))
 +              goto out;
 +      error = decode_dirlist3(xdr);
 +out:
 +      return error;
 +}
  
 -      status = ntohl(*p++);
 -      p = xdr_decode_wcc_data(p, res->fattr);
 -      if (status != 0)
 -              return nfs_stat_to_errno(status);
 +static int nfs3_xdr_dec_readdir3res(struct rpc_rqst *req,
 +                                  struct xdr_stream *xdr,
 +                                  struct nfs3_readdirres *result)
 +{
 +      enum nfs_stat status;
 +      int error;
 +
 +      error = decode_nfsstat3(xdr, &status);
 +      if (unlikely(error))
 +              goto out;
 +      if (status != NFS3_OK)
 +              goto out_default;
 +      error = decode_readdir3resok(xdr, result);
 +out:
 +      return error;
 +out_default:
 +      error = decode_post_op_attr(xdr, result->dir_attr);
 +      if (unlikely(error))
 +              goto out;
 +      return nfs_stat_to_errno(status);
 +}
  
 -      res->verf->verifier[0] = *p++;
 -      res->verf->verifier[1] = *p++;
 +/*
 + * 3.3.18  FSSTAT3res
 + *
 + *    struct FSSTAT3resok {
 + *            post_op_attr    obj_attributes;
 + *            size3           tbytes;
 + *            size3           fbytes;
 + *            size3           abytes;
 + *            size3           tfiles;
 + *            size3           ffiles;
 + *            size3           afiles;
 + *            uint32          invarsec;
 + *    };
 + *
 + *    struct FSSTAT3resfail {
 + *            post_op_attr    obj_attributes;
 + *    };
 + *
 + *    union FSSTAT3res switch (nfsstat3 status) {
 + *    case NFS3_OK:
 + *            FSSTAT3resok    resok;
 + *    default:
 + *            FSSTAT3resfail  resfail;
 + *    };
 + */
 +static int decode_fsstat3resok(struct xdr_stream *xdr,
 +                             struct nfs_fsstat *result)
 +{
 +      __be32 *p;
 +
 +      p = xdr_inline_decode(xdr, 8 * 6 + 4);
 +      if (unlikely(p == NULL))
 +              goto out_overflow;
 +      p = xdr_decode_size3(p, &result->tbytes);
 +      p = xdr_decode_size3(p, &result->fbytes);
 +      p = xdr_decode_size3(p, &result->abytes);
 +      p = xdr_decode_size3(p, &result->tfiles);
 +      p = xdr_decode_size3(p, &result->ffiles);
 +      xdr_decode_size3(p, &result->afiles);
 +      /* ignore invarsec */
        return 0;
 +out_overflow:
 +      print_overflow_msg(__func__, xdr);
 +      return -EIO;
 +}
 +
 +static int nfs3_xdr_dec_fsstat3res(struct rpc_rqst *req,
 +                                 struct xdr_stream *xdr,
 +                                 struct nfs_fsstat *result)
 +{
 +      enum nfs_stat status;
 +      int error;
 +
 +      error = decode_nfsstat3(xdr, &status);
 +      if (unlikely(error))
 +              goto out;
 +      error = decode_post_op_attr(xdr, result->fattr);
 +      if (unlikely(error))
 +              goto out;
 +      if (status != NFS3_OK)
 +              goto out_status;
 +      error = decode_fsstat3resok(xdr, result);
 +out:
 +      return error;
 +out_status:
 +      return nfs_stat_to_errno(status);
  }
  
 -#ifdef CONFIG_NFS_V3_ACL
  /*
 - * Decode GETACL reply
 + * 3.3.19  FSINFO3res
 + *
 + *    struct FSINFO3resok {
 + *            post_op_attr    obj_attributes;
 + *            uint32          rtmax;
 + *            uint32          rtpref;
 + *            uint32          rtmult;
 + *            uint32          wtmax;
 + *            uint32          wtpref;
 + *            uint32          wtmult;
 + *            uint32          dtpref;
 + *            size3           maxfilesize;
 + *            nfstime3        time_delta;
 + *            uint32          properties;
 + *    };
 + *
 + *    struct FSINFO3resfail {
 + *            post_op_attr    obj_attributes;
 + *    };
 + *
 + *    union FSINFO3res switch (nfsstat3 status) {
 + *    case NFS3_OK:
 + *            FSINFO3resok    resok;
 + *    default:
 + *            FSINFO3resfail  resfail;
 + *    };
   */
 -static int
 -nfs3_xdr_getaclres(struct rpc_rqst *req, __be32 *p,
 -                 struct nfs3_getaclres *res)
 +static int decode_fsinfo3resok(struct xdr_stream *xdr,
 +                             struct nfs_fsinfo *result)
  {
 -      struct xdr_buf *buf = &req->rq_rcv_buf;
 -      int status = ntohl(*p++);
 -      struct posix_acl **acl;
 -      unsigned int *aclcnt;
 -      int err, base;
 +      __be32 *p;
  
 -      if (status != 0)
 -              return nfs_stat_to_errno(status);
 -      p = xdr_decode_post_op_attr(p, res->fattr);
 -      res->mask = ntohl(*p++);
 -      if (res->mask & ~(NFS_ACL|NFS_ACLCNT|NFS_DFACL|NFS_DFACLCNT))
 -              return -EINVAL;
 -      base = (char *)p - (char *)req->rq_rcv_buf.head->iov_base;
 +      p = xdr_inline_decode(xdr, 4 * 7 + 8 + 8 + 4);
 +      if (unlikely(p == NULL))
 +              goto out_overflow;
 +      result->rtmax  = be32_to_cpup(p++);
 +      result->rtpref = be32_to_cpup(p++);
 +      result->rtmult = be32_to_cpup(p++);
 +      result->wtmax  = be32_to_cpup(p++);
 +      result->wtpref = be32_to_cpup(p++);
 +      result->wtmult = be32_to_cpup(p++);
 +      result->dtpref = be32_to_cpup(p++);
 +      p = xdr_decode_size3(p, &result->maxfilesize);
 +      xdr_decode_nfstime3(p, &result->time_delta);
  
 -      acl = (res->mask & NFS_ACL) ? &res->acl_access : NULL;
 -      aclcnt = (res->mask & NFS_ACLCNT) ? &res->acl_access_count : NULL;
 -      err = nfsacl_decode(buf, base, aclcnt, acl);
 +      /* ignore properties */
 +      result->lease_time = 0;
 +      return 0;
 +out_overflow:
 +      print_overflow_msg(__func__, xdr);
 +      return -EIO;
 +}
  
 -      acl = (res->mask & NFS_DFACL) ? &res->acl_default : NULL;
 -      aclcnt = (res->mask & NFS_DFACLCNT) ? &res->acl_default_count : NULL;
 -      if (err > 0)
 -              err = nfsacl_decode(buf, base + err, aclcnt, acl);
 -      return (err > 0) ? 0 : err;
 +static int nfs3_xdr_dec_fsinfo3res(struct rpc_rqst *req,
 +                                 struct xdr_stream *xdr,
 +                                 struct nfs_fsinfo *result)
 +{
 +      enum nfs_stat status;
 +      int error;
 +
 +      error = decode_nfsstat3(xdr, &status);
 +      if (unlikely(error))
 +              goto out;
 +      error = decode_post_op_attr(xdr, result->fattr);
 +      if (unlikely(error))
 +              goto out;
 +      if (status != NFS3_OK)
 +              goto out_status;
 +      error = decode_fsinfo3resok(xdr, result);
 +out:
 +      return error;
 +out_status:
 +      return nfs_stat_to_errno(status);
  }
  
  /*
 - * Decode setacl reply.
 + * 3.3.20  PATHCONF3res
 + *
 + *    struct PATHCONF3resok {
 + *            post_op_attr    obj_attributes;
 + *            uint32          linkmax;
 + *            uint32          name_max;
 + *            bool            no_trunc;
 + *            bool            chown_restricted;
 + *            bool            case_insensitive;
 + *            bool            case_preserving;
 + *    };
 + *
 + *    struct PATHCONF3resfail {
 + *            post_op_attr    obj_attributes;
 + *    };
 + *
 + *    union PATHCONF3res switch (nfsstat3 status) {
 + *    case NFS3_OK:
 + *            PATHCONF3resok  resok;
 + *    default:
 + *            PATHCONF3resfail resfail;
 + *    };
   */
 -static int
 -nfs3_xdr_setaclres(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
 +static int decode_pathconf3resok(struct xdr_stream *xdr,
 +                               struct nfs_pathconf *result)
  {
 -      int status = ntohl(*p++);
 +      __be32 *p;
  
 -      if (status)
 -              return nfs_stat_to_errno(status);
 -      xdr_decode_post_op_attr(p, fattr);
 +      p = xdr_inline_decode(xdr, 4 * 6);
 +      if (unlikely(p == NULL))
 +              goto out_overflow;
 +      result->max_link = be32_to_cpup(p++);
 +      result->max_namelen = be32_to_cpup(p);
 +      /* ignore remaining fields */
        return 0;
 +out_overflow:
 +      print_overflow_msg(__func__, xdr);
 +      return -EIO;
 +}
 +
 +static int nfs3_xdr_dec_pathconf3res(struct rpc_rqst *req,
 +                                   struct xdr_stream *xdr,
 +                                   struct nfs_pathconf *result)
 +{
 +      enum nfs_stat status;
 +      int error;
 +
 +      error = decode_nfsstat3(xdr, &status);
 +      if (unlikely(error))
 +              goto out;
 +      error = decode_post_op_attr(xdr, result->fattr);
 +      if (unlikely(error))
 +              goto out;
 +      if (status != NFS3_OK)
 +              goto out_status;
 +      error = decode_pathconf3resok(xdr, result);
 +out:
 +      return error;
 +out_status:
 +      return nfs_stat_to_errno(status);
 +}
 +
 +/*
 + * 3.3.21  COMMIT3res
 + *
 + *    struct COMMIT3resok {
 + *            wcc_data        file_wcc;
 + *            writeverf3      verf;
 + *    };
 + *
 + *    struct COMMIT3resfail {
 + *            wcc_data        file_wcc;
 + *    };
 + *
 + *    union COMMIT3res switch (nfsstat3 status) {
 + *    case NFS3_OK:
 + *            COMMIT3resok    resok;
 + *    default:
 + *            COMMIT3resfail  resfail;
 + *    };
 + */
 +static int nfs3_xdr_dec_commit3res(struct rpc_rqst *req,
 +                                 struct xdr_stream *xdr,
 +                                 struct nfs_writeres *result)
 +{
 +      enum nfs_stat status;
 +      int error;
 +
 +      error = decode_nfsstat3(xdr, &status);
 +      if (unlikely(error))
 +              goto out;
 +      error = decode_wcc_data(xdr, result->fattr);
 +      if (unlikely(error))
 +              goto out;
 +      if (status != NFS3_OK)
 +              goto out_status;
 +      error = decode_writeverf3(xdr, result->verf->verifier);
 +out:
 +      return error;
 +out_status:
 +      return nfs_stat_to_errno(status);
 +}
 +
 +#ifdef CONFIG_NFS_V3_ACL
 +
 +static inline int decode_getacl3resok(struct xdr_stream *xdr,
 +                                    struct nfs3_getaclres *result)
 +{
 +      struct posix_acl **acl;
 +      unsigned int *aclcnt;
 +      size_t hdrlen;
 +      int error;
 +
 +      error = decode_post_op_attr(xdr, result->fattr);
 +      if (unlikely(error))
 +              goto out;
 +      error = decode_uint32(xdr, &result->mask);
 +      if (unlikely(error))
 +              goto out;
 +      error = -EINVAL;
 +      if (result->mask & ~(NFS_ACL|NFS_ACLCNT|NFS_DFACL|NFS_DFACLCNT))
 +              goto out;
 +
 +      hdrlen = (u8 *)xdr->p - (u8 *)xdr->iov->iov_base;
 +
 +      acl = NULL;
 +      if (result->mask & NFS_ACL)
 +              acl = &result->acl_access;
 +      aclcnt = NULL;
 +      if (result->mask & NFS_ACLCNT)
 +              aclcnt = &result->acl_access_count;
 +      error = nfsacl_decode(xdr->buf, hdrlen, aclcnt, acl);
 +      if (unlikely(error <= 0))
 +              goto out;
 +
 +      acl = NULL;
 +      if (result->mask & NFS_DFACL)
 +              acl = &result->acl_default;
 +      aclcnt = NULL;
 +      if (result->mask & NFS_DFACLCNT)
 +              aclcnt = &result->acl_default_count;
 +      error = nfsacl_decode(xdr->buf, hdrlen + error, aclcnt, acl);
 +      if (unlikely(error <= 0))
 +              return error;
 +      error = 0;
 +out:
 +      return error;
  }
 +
 +static int nfs3_xdr_dec_getacl3res(struct rpc_rqst *req,
 +                                 struct xdr_stream *xdr,
 +                                 struct nfs3_getaclres *result)
 +{
 +      enum nfs_stat status;
 +      int error;
 +
 +      error = decode_nfsstat3(xdr, &status);
 +      if (unlikely(error))
 +              goto out;
 +      if (status != NFS3_OK)
 +              goto out_default;
 +      error = decode_getacl3resok(xdr, result);
 +out:
 +      return error;
 +out_default:
 +      return nfs_stat_to_errno(status);
 +}
 +
 +static int nfs3_xdr_dec_setacl3res(struct rpc_rqst *req,
 +                                 struct xdr_stream *xdr,
 +                                 struct nfs_fattr *result)
 +{
 +      enum nfs_stat status;
 +      int error;
 +
 +      error = decode_nfsstat3(xdr, &status);
 +      if (unlikely(error))
 +              goto out;
 +      if (status != NFS3_OK)
 +              goto out_default;
 +      error = decode_post_op_attr(xdr, result);
 +out:
 +      return error;
 +out_default:
 +      return nfs_stat_to_errno(status);
 +}
 +
  #endif  /* CONFIG_NFS_V3_ACL */
  
  #define PROC(proc, argtype, restype, timer)                           \
  [NFS3PROC_##proc] = {                                                 \
        .p_proc      = NFS3PROC_##proc,                                 \
 -      .p_encode    = (kxdrproc_t) nfs3_xdr_##argtype,                 \
 -      .p_decode    = (kxdrproc_t) nfs3_xdr_##restype,                 \
 -      .p_arglen    = NFS3_##argtype##_sz,                             \
 -      .p_replen    = NFS3_##restype##_sz,                             \
 +      .p_encode    = (kxdreproc_t)nfs3_xdr_enc_##argtype##3args,      \
 +      .p_decode    = (kxdrdproc_t)nfs3_xdr_dec_##restype##3res,       \
 +      .p_arglen    = NFS3_##argtype##args_sz,                         \
 +      .p_replen    = NFS3_##restype##res_sz,                          \
        .p_timer     = timer,                                           \
        .p_statidx   = NFS3PROC_##proc,                                 \
        .p_name      = #proc,                                           \
        }
  
  struct rpc_procinfo   nfs3_procedures[] = {
 -  PROC(GETATTR,               fhandle,        attrstat, 1),
 -  PROC(SETATTR,       sattrargs,      wccstat, 0),
 -  PROC(LOOKUP,                diropargs,      lookupres, 2),
 -  PROC(ACCESS,                accessargs,     accessres, 1),
 -  PROC(READLINK,      readlinkargs,   readlinkres, 3),
 -  PROC(READ,          readargs,       readres, 3),
 -  PROC(WRITE,         writeargs,      writeres, 4),
 -  PROC(CREATE,                createargs,     createres, 0),
 -  PROC(MKDIR,         mkdirargs,      createres, 0),
 -  PROC(SYMLINK,               symlinkargs,    createres, 0),
 -  PROC(MKNOD,         mknodargs,      createres, 0),
 -  PROC(REMOVE,                removeargs,     removeres, 0),
 -  PROC(RMDIR,         diropargs,      wccstat, 0),
 -  PROC(RENAME,                renameargs,     renameres, 0),
 -  PROC(LINK,          linkargs,       linkres, 0),
 -  PROC(READDIR,               readdirargs,    readdirres, 3),
 -  PROC(READDIRPLUS,   readdirargs,    readdirres, 3),
 -  PROC(FSSTAT,                fhandle,        fsstatres, 0),
 -  PROC(FSINFO,        fhandle,        fsinfores, 0),
 -  PROC(PATHCONF,      fhandle,        pathconfres, 0),
 -  PROC(COMMIT,                commitargs,     commitres, 5),
 +      PROC(GETATTR,           getattr,        getattr,        1),
 +      PROC(SETATTR,           setattr,        setattr,        0),
 +      PROC(LOOKUP,            lookup,         lookup,         2),
 +      PROC(ACCESS,            access,         access,         1),
 +      PROC(READLINK,          readlink,       readlink,       3),
 +      PROC(READ,              read,           read,           3),
 +      PROC(WRITE,             write,          write,          4),
 +      PROC(CREATE,            create,         create,         0),
 +      PROC(MKDIR,             mkdir,          create,         0),
 +      PROC(SYMLINK,           symlink,        create,         0),
 +      PROC(MKNOD,             mknod,          create,         0),
 +      PROC(REMOVE,            remove,         remove,         0),
 +      PROC(RMDIR,             lookup,         setattr,        0),
 +      PROC(RENAME,            rename,         rename,         0),
 +      PROC(LINK,              link,           link,           0),
 +      PROC(READDIR,           readdir,        readdir,        3),
 +      PROC(READDIRPLUS,       readdirplus,    readdir,        3),
 +      PROC(FSSTAT,            getattr,        fsstat,         0),
 +      PROC(FSINFO,            getattr,        fsinfo,         0),
 +      PROC(PATHCONF,          getattr,        pathconf,       0),
 +      PROC(COMMIT,            commit,         commit,         5),
  };
  
  struct rpc_version            nfs_version3 = {
  static struct rpc_procinfo    nfs3_acl_procedures[] = {
        [ACLPROC3_GETACL] = {
                .p_proc = ACLPROC3_GETACL,
 -              .p_encode = (kxdrproc_t) nfs3_xdr_getaclargs,
 -              .p_decode = (kxdrproc_t) nfs3_xdr_getaclres,
 +              .p_encode = (kxdreproc_t)nfs3_xdr_enc_getacl3args,
 +              .p_decode = (kxdrdproc_t)nfs3_xdr_dec_getacl3res,
                .p_arglen = ACL3_getaclargs_sz,
                .p_replen = ACL3_getaclres_sz,
                .p_timer = 1,
        },
        [ACLPROC3_SETACL] = {
                .p_proc = ACLPROC3_SETACL,
 -              .p_encode = (kxdrproc_t) nfs3_xdr_setaclargs,
 -              .p_decode = (kxdrproc_t) nfs3_xdr_setaclres,
 +              .p_encode = (kxdreproc_t)nfs3_xdr_enc_setacl3args,
 +              .p_decode = (kxdrdproc_t)nfs3_xdr_dec_setacl3res,
                .p_arglen = ACL3_setaclargs_sz,
                .p_replen = ACL3_setaclres_sz,
                .p_timer = 0,
diff --combined fs/nfs/nfs4xdr.c
@@@ -71,8 -71,8 +71,8 @@@ static int nfs4_stat_to_errno(int)
  /* lock,open owner id:
   * we currently use size 2 (u64) out of (NFS4_OPAQUE_LIMIT  >> 2)
   */
 -#define open_owner_id_maxsz   (1 + 4)
 -#define lock_owner_id_maxsz   (1 + 4)
 +#define open_owner_id_maxsz   (1 + 1 + 4)
 +#define lock_owner_id_maxsz   (1 + 1 + 4)
  #define decode_lockowner_maxsz        (1 + XDR_QUADLEN(IDMAP_NAMESZ))
  #define compound_encode_hdr_maxsz     (3 + (NFS4_MAXTAGLEN >> 2))
  #define compound_decode_hdr_maxsz     (3 + (NFS4_MAXTAGLEN >> 2))
@@@ -1088,11 -1088,10 +1088,11 @@@ static void encode_lockowner(struct xdr
  {
        __be32 *p;
  
 -      p = reserve_space(xdr, 28);
 +      p = reserve_space(xdr, 32);
        p = xdr_encode_hyper(p, lowner->clientid);
 -      *p++ = cpu_to_be32(16);
 +      *p++ = cpu_to_be32(20);
        p = xdr_encode_opaque_fixed(p, "lock id:", 8);
 +      *p++ = cpu_to_be32(lowner->s_dev);
        xdr_encode_hyper(p, lowner->id);
  }
  
@@@ -1211,11 -1210,10 +1211,11 @@@ static inline void encode_openhdr(struc
        *p++ = cpu_to_be32(OP_OPEN);
        *p = cpu_to_be32(arg->seqid->sequence->counter);
        encode_share_access(xdr, arg->fmode);
 -      p = reserve_space(xdr, 28);
 +      p = reserve_space(xdr, 32);
        p = xdr_encode_hyper(p, arg->clientid);
 -      *p++ = cpu_to_be32(16);
 +      *p++ = cpu_to_be32(20);
        p = xdr_encode_opaque_fixed(p, "open id:", 8);
 +      *p++ = cpu_to_be32(arg->server->s_dev);
        xdr_encode_hyper(p, arg->id);
  }
  
@@@ -1512,7 -1510,7 +1512,7 @@@ encode_restorefh(struct xdr_stream *xdr
        hdr->replen += decode_restorefh_maxsz;
  }
  
 -static int
 +static void
  encode_setacl(struct xdr_stream *xdr, struct nfs_setaclargs *arg, struct compound_hdr *hdr)
  {
        __be32 *p;
        p = reserve_space(xdr, 2*4);
        *p++ = cpu_to_be32(1);
        *p = cpu_to_be32(FATTR4_WORD0_ACL);
 -      if (arg->acl_len % 4)
 -              return -EINVAL;
 +      BUG_ON(arg->acl_len % 4);
        p = reserve_space(xdr, 4);
        *p = cpu_to_be32(arg->acl_len);
        xdr_write_pages(xdr, arg->acl_pages, arg->acl_pgbase, arg->acl_len);
        hdr->nops++;
        hdr->replen += decode_setacl_maxsz;
 -      return 0;
  }
  
  static void
@@@ -1789,6 -1789,7 +1789,6 @@@ encode_layoutget(struct xdr_stream *xdr
                      const struct nfs4_layoutget_args *args,
                      struct compound_hdr *hdr)
  {
 -      nfs4_stateid stateid;
        __be32 *p;
  
        p = reserve_space(xdr, 44 + NFS4_STATEID_SIZE);
        p = xdr_encode_hyper(p, args->range.offset);
        p = xdr_encode_hyper(p, args->range.length);
        p = xdr_encode_hyper(p, args->minlength);
 -      pnfs_get_layout_stateid(&stateid, NFS_I(args->inode)->layout,
 -                              args->ctx->state);
 -      p = xdr_encode_opaque_fixed(p, &stateid.data, NFS4_STATEID_SIZE);
 +      p = xdr_encode_opaque_fixed(p, &args->stateid.data, NFS4_STATEID_SIZE);
        *p = cpu_to_be32(args->maxcount);
  
        dprintk("%s: 1st type:0x%x iomode:%d off:%lu len:%lu mc:%d\n",
@@@ -1830,362 -1833,393 +1830,362 @@@ static u32 nfs4_xdr_minorversion(const 
  /*
   * Encode an ACCESS request
   */
 -static int nfs4_xdr_enc_access(struct rpc_rqst *req, __be32 *p, const struct nfs4_accessargs *args)
 +static void nfs4_xdr_enc_access(struct rpc_rqst *req, struct xdr_stream *xdr,
 +                              const struct nfs4_accessargs *args)
  {
 -      struct xdr_stream xdr;
        struct compound_hdr hdr = {
                .minorversion = nfs4_xdr_minorversion(&args->seq_args),
        };
  
 -      xdr_init_encode(&xdr, &req->rq_snd_buf, p);
 -      encode_compound_hdr(&xdr, req, &hdr);
 -      encode_sequence(&xdr, &args->seq_args, &hdr);
 -      encode_putfh(&xdr, args->fh, &hdr);
 -      encode_access(&xdr, args->access, &hdr);
 -      encode_getfattr(&xdr, args->bitmask, &hdr);
 +      encode_compound_hdr(xdr, req, &hdr);
 +      encode_sequence(xdr, &args->seq_args, &hdr);
 +      encode_putfh(xdr, args->fh, &hdr);
 +      encode_access(xdr, args->access, &hdr);
 +      encode_getfattr(xdr, args->bitmask, &hdr);
        encode_nops(&hdr);
 -      return 0;
  }
  
  /*
   * Encode LOOKUP request
   */
 -static int nfs4_xdr_enc_lookup(struct rpc_rqst *req, __be32 *p, const struct nfs4_lookup_arg *args)
 +static void nfs4_xdr_enc_lookup(struct rpc_rqst *req, struct xdr_stream *xdr,
 +                              const struct nfs4_lookup_arg *args)
  {
 -      struct xdr_stream xdr;
        struct compound_hdr hdr = {
                .minorversion = nfs4_xdr_minorversion(&args->seq_args),
        };
  
 -      xdr_init_encode(&xdr, &req->rq_snd_buf, p);
 -      encode_compound_hdr(&xdr, req, &hdr);
 -      encode_sequence(&xdr, &args->seq_args, &hdr);
 -      encode_putfh(&xdr, args->dir_fh, &hdr);
 -      encode_lookup(&xdr, args->name, &hdr);
 -      encode_getfh(&xdr, &hdr);
 -      encode_getfattr(&xdr, args->bitmask, &hdr);
 +      encode_compound_hdr(xdr, req, &hdr);
 +      encode_sequence(xdr, &args->seq_args, &hdr);
 +      encode_putfh(xdr, args->dir_fh, &hdr);
 +      encode_lookup(xdr, args->name, &hdr);
 +      encode_getfh(xdr, &hdr);
 +      encode_getfattr(xdr, args->bitmask, &hdr);
        encode_nops(&hdr);
 -      return 0;
  }
  
  /*
   * Encode LOOKUP_ROOT request
   */
 -static int nfs4_xdr_enc_lookup_root(struct rpc_rqst *req, __be32 *p, const struct nfs4_lookup_root_arg *args)
 +static void nfs4_xdr_enc_lookup_root(struct rpc_rqst *req,
 +                                   struct xdr_stream *xdr,
 +                                   const struct nfs4_lookup_root_arg *args)
  {
 -      struct xdr_stream xdr;
        struct compound_hdr hdr = {
                .minorversion = nfs4_xdr_minorversion(&args->seq_args),
        };
  
 -      xdr_init_encode(&xdr, &req->rq_snd_buf, p);
 -      encode_compound_hdr(&xdr, req, &hdr);
 -      encode_sequence(&xdr, &args->seq_args, &hdr);
 -      encode_putrootfh(&xdr, &hdr);
 -      encode_getfh(&xdr, &hdr);
 -      encode_getfattr(&xdr, args->bitmask, &hdr);
 +      encode_compound_hdr(xdr, req, &hdr);
 +      encode_sequence(xdr, &args->seq_args, &hdr);
 +      encode_putrootfh(xdr, &hdr);
 +      encode_getfh(xdr, &hdr);
 +      encode_getfattr(xdr, args->bitmask, &hdr);
        encode_nops(&hdr);
 -      return 0;
  }
  
  /*
   * Encode REMOVE request
   */
 -static int nfs4_xdr_enc_remove(struct rpc_rqst *req, __be32 *p, const struct nfs_removeargs *args)
 +static void nfs4_xdr_enc_remove(struct rpc_rqst *req, struct xdr_stream *xdr,
 +                              const struct nfs_removeargs *args)
  {
 -      struct xdr_stream xdr;
        struct compound_hdr hdr = {
                .minorversion = nfs4_xdr_minorversion(&args->seq_args),
        };
  
 -      xdr_init_encode(&xdr, &req->rq_snd_buf, p);
 -      encode_compound_hdr(&xdr, req, &hdr);
 -      encode_sequence(&xdr, &args->seq_args, &hdr);
 -      encode_putfh(&xdr, args->fh, &hdr);
 -      encode_remove(&xdr, &args->name, &hdr);
 -      encode_getfattr(&xdr, args->bitmask, &hdr);
 +      encode_compound_hdr(xdr, req, &hdr);
 +      encode_sequence(xdr, &args->seq_args, &hdr);
 +      encode_putfh(xdr, args->fh, &hdr);
 +      encode_remove(xdr, &args->name, &hdr);
 +      encode_getfattr(xdr, args->bitmask, &hdr);
        encode_nops(&hdr);
 -      return 0;
  }
  
  /*
   * Encode RENAME request
   */
 -static int nfs4_xdr_enc_rename(struct rpc_rqst *req, __be32 *p, const struct nfs_renameargs *args)
 +static void nfs4_xdr_enc_rename(struct rpc_rqst *req, struct xdr_stream *xdr,
 +                              const struct nfs_renameargs *args)
  {
 -      struct xdr_stream xdr;
        struct compound_hdr hdr = {
                .minorversion = nfs4_xdr_minorversion(&args->seq_args),
        };
  
 -      xdr_init_encode(&xdr, &req->rq_snd_buf, p);
 -      encode_compound_hdr(&xdr, req, &hdr);
 -      encode_sequence(&xdr, &args->seq_args, &hdr);
 -      encode_putfh(&xdr, args->old_dir, &hdr);
 -      encode_savefh(&xdr, &hdr);
 -      encode_putfh(&xdr, args->new_dir, &hdr);
 -      encode_rename(&xdr, args->old_name, args->new_name, &hdr);
 -      encode_getfattr(&xdr, args->bitmask, &hdr);
 -      encode_restorefh(&xdr, &hdr);
 -      encode_getfattr(&xdr, args->bitmask, &hdr);
 +      encode_compound_hdr(xdr, req, &hdr);
 +      encode_sequence(xdr, &args->seq_args, &hdr);
 +      encode_putfh(xdr, args->old_dir, &hdr);
 +      encode_savefh(xdr, &hdr);
 +      encode_putfh(xdr, args->new_dir, &hdr);
 +      encode_rename(xdr, args->old_name, args->new_name, &hdr);
 +      encode_getfattr(xdr, args->bitmask, &hdr);
 +      encode_restorefh(xdr, &hdr);
 +      encode_getfattr(xdr, args->bitmask, &hdr);
        encode_nops(&hdr);
 -      return 0;
  }
  
  /*
   * Encode LINK request
   */
 -static int nfs4_xdr_enc_link(struct rpc_rqst *req, __be32 *p, const struct nfs4_link_arg *args)
 +static void nfs4_xdr_enc_link(struct rpc_rqst *req, struct xdr_stream *xdr,
 +                           const struct nfs4_link_arg *args)
  {
 -      struct xdr_stream xdr;
        struct compound_hdr hdr = {
                .minorversion = nfs4_xdr_minorversion(&args->seq_args),
        };
  
 -      xdr_init_encode(&xdr, &req->rq_snd_buf, p);
 -      encode_compound_hdr(&xdr, req, &hdr);
 -      encode_sequence(&xdr, &args->seq_args, &hdr);
 -      encode_putfh(&xdr, args->fh, &hdr);
 -      encode_savefh(&xdr, &hdr);
 -      encode_putfh(&xdr, args->dir_fh, &hdr);
 -      encode_link(&xdr, args->name, &hdr);
 -      encode_getfattr(&xdr, args->bitmask, &hdr);
 -      encode_restorefh(&xdr, &hdr);
 -      encode_getfattr(&xdr, args->bitmask, &hdr);
 +      encode_compound_hdr(xdr, req, &hdr);
 +      encode_sequence(xdr, &args->seq_args, &hdr);
 +      encode_putfh(xdr, args->fh, &hdr);
 +      encode_savefh(xdr, &hdr);
 +      encode_putfh(xdr, args->dir_fh, &hdr);
 +      encode_link(xdr, args->name, &hdr);
 +      encode_getfattr(xdr, args->bitmask, &hdr);
 +      encode_restorefh(xdr, &hdr);
 +      encode_getfattr(xdr, args->bitmask, &hdr);
        encode_nops(&hdr);
 -      return 0;
  }
  
  /*
   * Encode CREATE request
   */
 -static int nfs4_xdr_enc_create(struct rpc_rqst *req, __be32 *p, const struct nfs4_create_arg *args)
 +static void nfs4_xdr_enc_create(struct rpc_rqst *req, struct xdr_stream *xdr,
 +                              const struct nfs4_create_arg *args)
  {
 -      struct xdr_stream xdr;
        struct compound_hdr hdr = {
                .minorversion = nfs4_xdr_minorversion(&args->seq_args),
        };
  
 -      xdr_init_encode(&xdr, &req->rq_snd_buf, p);
 -      encode_compound_hdr(&xdr, req, &hdr);
 -      encode_sequence(&xdr, &args->seq_args, &hdr);
 -      encode_putfh(&xdr, args->dir_fh, &hdr);
 -      encode_savefh(&xdr, &hdr);
 -      encode_create(&xdr, args, &hdr);
 -      encode_getfh(&xdr, &hdr);
 -      encode_getfattr(&xdr, args->bitmask, &hdr);
 -      encode_restorefh(&xdr, &hdr);
 -      encode_getfattr(&xdr, args->bitmask, &hdr);
 +      encode_compound_hdr(xdr, req, &hdr);
 +      encode_sequence(xdr, &args->seq_args, &hdr);
 +      encode_putfh(xdr, args->dir_fh, &hdr);
 +      encode_savefh(xdr, &hdr);
 +      encode_create(xdr, args, &hdr);
 +      encode_getfh(xdr, &hdr);
 +      encode_getfattr(xdr, args->bitmask, &hdr);
 +      encode_restorefh(xdr, &hdr);
 +      encode_getfattr(xdr, args->bitmask, &hdr);
        encode_nops(&hdr);
 -      return 0;
  }
  
  /*
   * Encode SYMLINK request
   */
 -static int nfs4_xdr_enc_symlink(struct rpc_rqst *req, __be32 *p, const struct nfs4_create_arg *args)
 +static void nfs4_xdr_enc_symlink(struct rpc_rqst *req, struct xdr_stream *xdr,
 +                               const struct nfs4_create_arg *args)
  {
 -      return nfs4_xdr_enc_create(req, p, args);
 +      nfs4_xdr_enc_create(req, xdr, args);
  }
  
  /*
   * Encode GETATTR request
   */
 -static int nfs4_xdr_enc_getattr(struct rpc_rqst *req, __be32 *p, const struct nfs4_getattr_arg *args)
 +static void nfs4_xdr_enc_getattr(struct rpc_rqst *req, struct xdr_stream *xdr,
 +                               const struct nfs4_getattr_arg *args)
  {
 -      struct xdr_stream xdr;
        struct compound_hdr hdr = {
                .minorversion = nfs4_xdr_minorversion(&args->seq_args),
        };
  
 -      xdr_init_encode(&xdr, &req->rq_snd_buf, p);
 -      encode_compound_hdr(&xdr, req, &hdr);
 -      encode_sequence(&xdr, &args->seq_args, &hdr);
 -      encode_putfh(&xdr, args->fh, &hdr);
 -      encode_getfattr(&xdr, args->bitmask, &hdr);
 +      encode_compound_hdr(xdr, req, &hdr);
 +      encode_sequence(xdr, &args->seq_args, &hdr);
 +      encode_putfh(xdr, args->fh, &hdr);
 +      encode_getfattr(xdr, args->bitmask, &hdr);
        encode_nops(&hdr);
 -      return 0;
  }
  
  /*
   * Encode a CLOSE request
   */
 -static int nfs4_xdr_enc_close(struct rpc_rqst *req, __be32 *p, struct nfs_closeargs *args)
 +static void nfs4_xdr_enc_close(struct rpc_rqst *req, struct xdr_stream *xdr,
 +                             struct nfs_closeargs *args)
  {
 -      struct xdr_stream xdr;
        struct compound_hdr hdr = {
                .minorversion = nfs4_xdr_minorversion(&args->seq_args),
        };
  
 -      xdr_init_encode(&xdr, &req->rq_snd_buf, p);
 -      encode_compound_hdr(&xdr, req, &hdr);
 -      encode_sequence(&xdr, &args->seq_args, &hdr);
 -      encode_putfh(&xdr, args->fh, &hdr);
 -      encode_close(&xdr, args, &hdr);
 -      encode_getfattr(&xdr, args->bitmask, &hdr);
 +      encode_compound_hdr(xdr, req, &hdr);
 +      encode_sequence(xdr, &args->seq_args, &hdr);
 +      encode_putfh(xdr, args->fh, &hdr);
 +      encode_close(xdr, args, &hdr);
 +      encode_getfattr(xdr, args->bitmask, &hdr);
        encode_nops(&hdr);
 -      return 0;
  }
  
  /*
   * Encode an OPEN request
   */
 -static int nfs4_xdr_enc_open(struct rpc_rqst *req, __be32 *p, struct nfs_openargs *args)
 +static void nfs4_xdr_enc_open(struct rpc_rqst *req, struct xdr_stream *xdr,
 +                            struct nfs_openargs *args)
  {
 -      struct xdr_stream xdr;
        struct compound_hdr hdr = {
                .minorversion = nfs4_xdr_minorversion(&args->seq_args),
        };
  
 -      xdr_init_encode(&xdr, &req->rq_snd_buf, p);
 -      encode_compound_hdr(&xdr, req, &hdr);
 -      encode_sequence(&xdr, &args->seq_args, &hdr);
 -      encode_putfh(&xdr, args->fh, &hdr);
 -      encode_savefh(&xdr, &hdr);
 -      encode_open(&xdr, args, &hdr);
 -      encode_getfh(&xdr, &hdr);
 -      encode_getfattr(&xdr, args->bitmask, &hdr);
 -      encode_restorefh(&xdr, &hdr);
 -      encode_getfattr(&xdr, args->bitmask, &hdr);
 +      encode_compound_hdr(xdr, req, &hdr);
 +      encode_sequence(xdr, &args->seq_args, &hdr);
 +      encode_putfh(xdr, args->fh, &hdr);
 +      encode_savefh(xdr, &hdr);
 +      encode_open(xdr, args, &hdr);
 +      encode_getfh(xdr, &hdr);
 +      encode_getfattr(xdr, args->bitmask, &hdr);
 +      encode_restorefh(xdr, &hdr);
 +      encode_getfattr(xdr, args->bitmask, &hdr);
        encode_nops(&hdr);
 -      return 0;
  }
  
  /*
   * Encode an OPEN_CONFIRM request
   */
 -static int nfs4_xdr_enc_open_confirm(struct rpc_rqst *req, __be32 *p, struct nfs_open_confirmargs *args)
 +static void nfs4_xdr_enc_open_confirm(struct rpc_rqst *req,
 +                                    struct xdr_stream *xdr,
 +                                    struct nfs_open_confirmargs *args)
  {
 -      struct xdr_stream xdr;
        struct compound_hdr hdr = {
                .nops   = 0,
        };
  
 -      xdr_init_encode(&xdr, &req->rq_snd_buf, p);
 -      encode_compound_hdr(&xdr, req, &hdr);
 -      encode_putfh(&xdr, args->fh, &hdr);
 -      encode_open_confirm(&xdr, args, &hdr);
 +      encode_compound_hdr(xdr, req, &hdr);
 +      encode_putfh(xdr, args->fh, &hdr);
 +      encode_open_confirm(xdr, args, &hdr);
        encode_nops(&hdr);
 -      return 0;
  }
  
  /*
   * Encode an OPEN request with no attributes.
   */
 -static int nfs4_xdr_enc_open_noattr(struct rpc_rqst *req, __be32 *p, struct nfs_openargs *args)
 +static void nfs4_xdr_enc_open_noattr(struct rpc_rqst *req,
 +                                   struct xdr_stream *xdr,
 +                                   struct nfs_openargs *args)
  {
 -      struct xdr_stream xdr;
        struct compound_hdr hdr = {
                .minorversion = nfs4_xdr_minorversion(&args->seq_args),
        };
  
 -      xdr_init_encode(&xdr, &req->rq_snd_buf, p);
 -      encode_compound_hdr(&xdr, req, &hdr);
 -      encode_sequence(&xdr, &args->seq_args, &hdr);
 -      encode_putfh(&xdr, args->fh, &hdr);
 -      encode_open(&xdr, args, &hdr);
 -      encode_getfattr(&xdr, args->bitmask, &hdr);
 +      encode_compound_hdr(xdr, req, &hdr);
 +      encode_sequence(xdr, &args->seq_args, &hdr);
 +      encode_putfh(xdr, args->fh, &hdr);
 +      encode_open(xdr, args, &hdr);
 +      encode_getfattr(xdr, args->bitmask, &hdr);
        encode_nops(&hdr);
 -      return 0;
  }
  
  /*
   * Encode an OPEN_DOWNGRADE request
   */
 -static int nfs4_xdr_enc_open_downgrade(struct rpc_rqst *req, __be32 *p, struct nfs_closeargs *args)
 +static void nfs4_xdr_enc_open_downgrade(struct rpc_rqst *req,
 +                                      struct xdr_stream *xdr,
 +                                      struct nfs_closeargs *args)
  {
 -      struct xdr_stream xdr;
        struct compound_hdr hdr = {
                .minorversion = nfs4_xdr_minorversion(&args->seq_args),
        };
  
 -      xdr_init_encode(&xdr, &req->rq_snd_buf, p);
 -      encode_compound_hdr(&xdr, req, &hdr);
 -      encode_sequence(&xdr, &args->seq_args, &hdr);
 -      encode_putfh(&xdr, args->fh, &hdr);
 -      encode_open_downgrade(&xdr, args, &hdr);
 -      encode_getfattr(&xdr, args->bitmask, &hdr);
 +      encode_compound_hdr(xdr, req, &hdr);
 +      encode_sequence(xdr, &args->seq_args, &hdr);
 +      encode_putfh(xdr, args->fh, &hdr);
 +      encode_open_downgrade(xdr, args, &hdr);
 +      encode_getfattr(xdr, args->bitmask, &hdr);
        encode_nops(&hdr);
 -      return 0;
  }
  
  /*
   * Encode a LOCK request
   */
 -static int nfs4_xdr_enc_lock(struct rpc_rqst *req, __be32 *p, struct nfs_lock_args *args)
 +static void nfs4_xdr_enc_lock(struct rpc_rqst *req, struct xdr_stream *xdr,
 +                            struct nfs_lock_args *args)
  {
 -      struct xdr_stream xdr;
        struct compound_hdr hdr = {
                .minorversion = nfs4_xdr_minorversion(&args->seq_args),
        };
  
 -      xdr_init_encode(&xdr, &req->rq_snd_buf, p);
 -      encode_compound_hdr(&xdr, req, &hdr);
 -      encode_sequence(&xdr, &args->seq_args, &hdr);
 -      encode_putfh(&xdr, args->fh, &hdr);
 -      encode_lock(&xdr, args, &hdr);
 +      encode_compound_hdr(xdr, req, &hdr);
 +      encode_sequence(xdr, &args->seq_args, &hdr);
 +      encode_putfh(xdr, args->fh, &hdr);
 +      encode_lock(xdr, args, &hdr);
        encode_nops(&hdr);
 -      return 0;
  }
  
  /*
   * Encode a LOCKT request
   */
 -static int nfs4_xdr_enc_lockt(struct rpc_rqst *req, __be32 *p, struct nfs_lockt_args *args)
 +static void nfs4_xdr_enc_lockt(struct rpc_rqst *req, struct xdr_stream *xdr,
 +                             struct nfs_lockt_args *args)
  {
 -      struct xdr_stream xdr;
        struct compound_hdr hdr = {
                .minorversion = nfs4_xdr_minorversion(&args->seq_args),
        };
  
 -      xdr_init_encode(&xdr, &req->rq_snd_buf, p);
 -      encode_compound_hdr(&xdr, req, &hdr);
 -      encode_sequence(&xdr, &args->seq_args, &hdr);
 -      encode_putfh(&xdr, args->fh, &hdr);
 -      encode_lockt(&xdr, args, &hdr);
 +      encode_compound_hdr(xdr, req, &hdr);
 +      encode_sequence(xdr, &args->seq_args, &hdr);
 +      encode_putfh(xdr, args->fh, &hdr);
 +      encode_lockt(xdr, args, &hdr);
        encode_nops(&hdr);
 -      return 0;
  }
  
  /*
   * Encode a LOCKU request
   */
 -static int nfs4_xdr_enc_locku(struct rpc_rqst *req, __be32 *p, struct nfs_locku_args *args)
 +static void nfs4_xdr_enc_locku(struct rpc_rqst *req, struct xdr_stream *xdr,
 +                             struct nfs_locku_args *args)
  {
 -      struct xdr_stream xdr;
        struct compound_hdr hdr = {
                .minorversion = nfs4_xdr_minorversion(&args->seq_args),
        };
  
 -      xdr_init_encode(&xdr, &req->rq_snd_buf, p);
 -      encode_compound_hdr(&xdr, req, &hdr);
 -      encode_sequence(&xdr, &args->seq_args, &hdr);
 -      encode_putfh(&xdr, args->fh, &hdr);
 -      encode_locku(&xdr, args, &hdr);
 +      encode_compound_hdr(xdr, req, &hdr);
 +      encode_sequence(xdr, &args->seq_args, &hdr);
 +      encode_putfh(xdr, args->fh, &hdr);
 +      encode_locku(xdr, args, &hdr);
        encode_nops(&hdr);
 -      return 0;
  }
  
 -static int nfs4_xdr_enc_release_lockowner(struct rpc_rqst *req, __be32 *p, struct nfs_release_lockowner_args *args)
 +static void nfs4_xdr_enc_release_lockowner(struct rpc_rqst *req,
 +                                         struct xdr_stream *xdr,
 +                                      struct nfs_release_lockowner_args *args)
  {
 -      struct xdr_stream xdr;
        struct compound_hdr hdr = {
                .minorversion = 0,
        };
  
 -      xdr_init_encode(&xdr, &req->rq_snd_buf, p);
 -      encode_compound_hdr(&xdr, req, &hdr);
 -      encode_release_lockowner(&xdr, &args->lock_owner, &hdr);
 +      encode_compound_hdr(xdr, req, &hdr);
 +      encode_release_lockowner(xdr, &args->lock_owner, &hdr);
        encode_nops(&hdr);
 -      return 0;
  }
  
  /*
   * Encode a READLINK request
   */
 -static int nfs4_xdr_enc_readlink(struct rpc_rqst *req, __be32 *p, const struct nfs4_readlink *args)
 +static void nfs4_xdr_enc_readlink(struct rpc_rqst *req, struct xdr_stream *xdr,
 +                                const struct nfs4_readlink *args)
  {
 -      struct xdr_stream xdr;
        struct compound_hdr hdr = {
                .minorversion = nfs4_xdr_minorversion(&args->seq_args),
        };
  
 -      xdr_init_encode(&xdr, &req->rq_snd_buf, p);
 -      encode_compound_hdr(&xdr, req, &hdr);
 -      encode_sequence(&xdr, &args->seq_args, &hdr);
 -      encode_putfh(&xdr, args->fh, &hdr);
 -      encode_readlink(&xdr, args, req, &hdr);
 +      encode_compound_hdr(xdr, req, &hdr);
 +      encode_sequence(xdr, &args->seq_args, &hdr);
 +      encode_putfh(xdr, args->fh, &hdr);
 +      encode_readlink(xdr, args, req, &hdr);
  
        xdr_inline_pages(&req->rq_rcv_buf, hdr.replen << 2, args->pages,
                        args->pgbase, args->pglen);
        encode_nops(&hdr);
 -      return 0;
  }
  
  /*
   * Encode a READDIR request
   */
 -static int nfs4_xdr_enc_readdir(struct rpc_rqst *req, __be32 *p, const struct nfs4_readdir_arg *args)
 +static void nfs4_xdr_enc_readdir(struct rpc_rqst *req, struct xdr_stream *xdr,
 +                               const struct nfs4_readdir_arg *args)
  {
 -      struct xdr_stream xdr;
        struct compound_hdr hdr = {
                .minorversion = nfs4_xdr_minorversion(&args->seq_args),
        };
  
 -      xdr_init_encode(&xdr, &req->rq_snd_buf, p);
 -      encode_compound_hdr(&xdr, req, &hdr);
 -      encode_sequence(&xdr, &args->seq_args, &hdr);
 -      encode_putfh(&xdr, args->fh, &hdr);
 -      encode_readdir(&xdr, args, req, &hdr);
 +      encode_compound_hdr(xdr, req, &hdr);
 +      encode_sequence(xdr, &args->seq_args, &hdr);
 +      encode_putfh(xdr, args->fh, &hdr);
 +      encode_readdir(xdr, args, req, &hdr);
  
        xdr_inline_pages(&req->rq_rcv_buf, hdr.replen << 2, args->pages,
                         args->pgbase, args->count);
                        __func__, hdr.replen << 2, args->pages,
                        args->pgbase, args->count);
        encode_nops(&hdr);
 -      return 0;
  }
  
  /*
   * Encode a READ request
   */
 -static int nfs4_xdr_enc_read(struct rpc_rqst *req, __be32 *p, struct nfs_readargs *args)
 +static void nfs4_xdr_enc_read(struct rpc_rqst *req, struct xdr_stream *xdr,
 +                            struct nfs_readargs *args)
  {
 -      struct xdr_stream xdr;
        struct compound_hdr hdr = {
                .minorversion = nfs4_xdr_minorversion(&args->seq_args),
        };
  
 -      xdr_init_encode(&xdr, &req->rq_snd_buf, p);
 -      encode_compound_hdr(&xdr, req, &hdr);
 -      encode_sequence(&xdr, &args->seq_args, &hdr);
 -      encode_putfh(&xdr, args->fh, &hdr);
 -      encode_read(&xdr, args, &hdr);
 +      encode_compound_hdr(xdr, req, &hdr);
 +      encode_sequence(xdr, &args->seq_args, &hdr);
 +      encode_putfh(xdr, args->fh, &hdr);
 +      encode_read(xdr, args, &hdr);
  
        xdr_inline_pages(&req->rq_rcv_buf, hdr.replen << 2,
                         args->pages, args->pgbase, args->count);
        req->rq_rcv_buf.flags |= XDRBUF_READ;
        encode_nops(&hdr);
 -      return 0;
  }
  
  /*
   * Encode an SETATTR request
   */
 -static int nfs4_xdr_enc_setattr(struct rpc_rqst *req, __be32 *p, struct nfs_setattrargs *args)
 +static void nfs4_xdr_enc_setattr(struct rpc_rqst *req, struct xdr_stream *xdr,
 +                               struct nfs_setattrargs *args)
  {
 -      struct xdr_stream xdr;
        struct compound_hdr hdr = {
                .minorversion = nfs4_xdr_minorversion(&args->seq_args),
        };
  
 -      xdr_init_encode(&xdr, &req->rq_snd_buf, p);
 -      encode_compound_hdr(&xdr, req, &hdr);
 -      encode_sequence(&xdr, &args->seq_args, &hdr);
 -      encode_putfh(&xdr, args->fh, &hdr);
 -      encode_setattr(&xdr, args, args->server, &hdr);
 -      encode_getfattr(&xdr, args->bitmask, &hdr);
 +      encode_compound_hdr(xdr, req, &hdr);
 +      encode_sequence(xdr, &args->seq_args, &hdr);
 +      encode_putfh(xdr, args->fh, &hdr);
 +      encode_setattr(xdr, args, args->server, &hdr);
 +      encode_getfattr(xdr, args->bitmask, &hdr);
        encode_nops(&hdr);
 -      return 0;
  }
  
  /*
   * Encode a GETACL request
   */
 -static int
 -nfs4_xdr_enc_getacl(struct rpc_rqst *req, __be32 *p,
 -              struct nfs_getaclargs *args)
 +static void nfs4_xdr_enc_getacl(struct rpc_rqst *req, struct xdr_stream *xdr,
 +                              struct nfs_getaclargs *args)
  {
 -      struct xdr_stream xdr;
        struct compound_hdr hdr = {
                .minorversion = nfs4_xdr_minorversion(&args->seq_args),
        };
        uint32_t replen;
  
 -      xdr_init_encode(&xdr, &req->rq_snd_buf, p);
 -      encode_compound_hdr(&xdr, req, &hdr);
 -      encode_sequence(&xdr, &args->seq_args, &hdr);
 -      encode_putfh(&xdr, args->fh, &hdr);
 +      encode_compound_hdr(xdr, req, &hdr);
 +      encode_sequence(xdr, &args->seq_args, &hdr);
 +      encode_putfh(xdr, args->fh, &hdr);
        replen = hdr.replen + op_decode_hdr_maxsz + nfs4_fattr_bitmap_maxsz + 1;
 -      encode_getattr_two(&xdr, FATTR4_WORD0_ACL, 0, &hdr);
 +      encode_getattr_two(xdr, FATTR4_WORD0_ACL, 0, &hdr);
  
        xdr_inline_pages(&req->rq_rcv_buf, replen << 2,
                args->acl_pages, args->acl_pgbase, args->acl_len);
        encode_nops(&hdr);
 -      return 0;
  }
  
  /*
   * Encode a WRITE request
   */
 -static int nfs4_xdr_enc_write(struct rpc_rqst *req, __be32 *p, struct nfs_writeargs *args)
 +static void nfs4_xdr_enc_write(struct rpc_rqst *req, struct xdr_stream *xdr,
 +                             struct nfs_writeargs *args)
  {
 -      struct xdr_stream xdr;
        struct compound_hdr hdr = {
                .minorversion = nfs4_xdr_minorversion(&args->seq_args),
        };
  
 -      xdr_init_encode(&xdr, &req->rq_snd_buf, p);
 -      encode_compound_hdr(&xdr, req, &hdr);
 -      encode_sequence(&xdr, &args->seq_args, &hdr);
 -      encode_putfh(&xdr, args->fh, &hdr);
 -      encode_write(&xdr, args, &hdr);
 +      encode_compound_hdr(xdr, req, &hdr);
 +      encode_sequence(xdr, &args->seq_args, &hdr);
 +      encode_putfh(xdr, args->fh, &hdr);
 +      encode_write(xdr, args, &hdr);
        req->rq_snd_buf.flags |= XDRBUF_WRITE;
 -      encode_getfattr(&xdr, args->bitmask, &hdr);
 +      encode_getfattr(xdr, args->bitmask, &hdr);
        encode_nops(&hdr);
 -      return 0;
  }
  
  /*
   *  a COMMIT request
   */
 -static int nfs4_xdr_enc_commit(struct rpc_rqst *req, __be32 *p, struct nfs_writeargs *args)
 +static void nfs4_xdr_enc_commit(struct rpc_rqst *req, struct xdr_stream *xdr,
 +                              struct nfs_writeargs *args)
  {
 -      struct xdr_stream xdr;
        struct compound_hdr hdr = {
                .minorversion = nfs4_xdr_minorversion(&args->seq_args),
        };
  
 -      xdr_init_encode(&xdr, &req->rq_snd_buf, p);
 -      encode_compound_hdr(&xdr, req, &hdr);
 -      encode_sequence(&xdr, &args->seq_args, &hdr);
 -      encode_putfh(&xdr, args->fh, &hdr);
 -      encode_commit(&xdr, args, &hdr);
 -      encode_getfattr(&xdr, args->bitmask, &hdr);
 +      encode_compound_hdr(xdr, req, &hdr);
 +      encode_sequence(xdr, &args->seq_args, &hdr);
 +      encode_putfh(xdr, args->fh, &hdr);
 +      encode_commit(xdr, args, &hdr);
 +      encode_getfattr(xdr, args->bitmask, &hdr);
        encode_nops(&hdr);
 -      return 0;
  }
  
  /*
   * FSINFO request
   */
 -static int nfs4_xdr_enc_fsinfo(struct rpc_rqst *req, __be32 *p, struct nfs4_fsinfo_arg *args)
 +static void nfs4_xdr_enc_fsinfo(struct rpc_rqst *req, struct xdr_stream *xdr,
 +                              struct nfs4_fsinfo_arg *args)
  {
 -      struct xdr_stream xdr;
        struct compound_hdr hdr = {
                .minorversion = nfs4_xdr_minorversion(&args->seq_args),
        };
  
 -      xdr_init_encode(&xdr, &req->rq_snd_buf, p);
 -      encode_compound_hdr(&xdr, req, &hdr);
 -      encode_sequence(&xdr, &args->seq_args, &hdr);
 -      encode_putfh(&xdr, args->fh, &hdr);
 -      encode_fsinfo(&xdr, args->bitmask, &hdr);
 +      encode_compound_hdr(xdr, req, &hdr);
 +      encode_sequence(xdr, &args->seq_args, &hdr);
 +      encode_putfh(xdr, args->fh, &hdr);
 +      encode_fsinfo(xdr, args->bitmask, &hdr);
        encode_nops(&hdr);
 -      return 0;
  }
  
  /*
   * a PATHCONF request
   */
 -static int nfs4_xdr_enc_pathconf(struct rpc_rqst *req, __be32 *p, const struct nfs4_pathconf_arg *args)
 +static void nfs4_xdr_enc_pathconf(struct rpc_rqst *req, struct xdr_stream *xdr,
 +                                const struct nfs4_pathconf_arg *args)
  {
 -      struct xdr_stream xdr;
        struct compound_hdr hdr = {
                .minorversion = nfs4_xdr_minorversion(&args->seq_args),
        };
  
 -      xdr_init_encode(&xdr, &req->rq_snd_buf, p);
 -      encode_compound_hdr(&xdr, req, &hdr);
 -      encode_sequence(&xdr, &args->seq_args, &hdr);
 -      encode_putfh(&xdr, args->fh, &hdr);
 -      encode_getattr_one(&xdr, args->bitmask[0] & nfs4_pathconf_bitmap[0],
 +      encode_compound_hdr(xdr, req, &hdr);
 +      encode_sequence(xdr, &args->seq_args, &hdr);
 +      encode_putfh(xdr, args->fh, &hdr);
 +      encode_getattr_one(xdr, args->bitmask[0] & nfs4_pathconf_bitmap[0],
                           &hdr);
        encode_nops(&hdr);
 -      return 0;
  }
  
  /*
   * a STATFS request
   */
 -static int nfs4_xdr_enc_statfs(struct rpc_rqst *req, __be32 *p, const struct nfs4_statfs_arg *args)
 +static void nfs4_xdr_enc_statfs(struct rpc_rqst *req, struct xdr_stream *xdr,
 +                              const struct nfs4_statfs_arg *args)
  {
 -      struct xdr_stream xdr;
        struct compound_hdr hdr = {
                .minorversion = nfs4_xdr_minorversion(&args->seq_args),
        };
  
 -      xdr_init_encode(&xdr, &req->rq_snd_buf, p);
 -      encode_compound_hdr(&xdr, req, &hdr);
 -      encode_sequence(&xdr, &args->seq_args, &hdr);
 -      encode_putfh(&xdr, args->fh, &hdr);
 -      encode_getattr_two(&xdr, args->bitmask[0] & nfs4_statfs_bitmap[0],
 +      encode_compound_hdr(xdr, req, &hdr);
 +      encode_sequence(xdr, &args->seq_args, &hdr);
 +      encode_putfh(xdr, args->fh, &hdr);
 +      encode_getattr_two(xdr, args->bitmask[0] & nfs4_statfs_bitmap[0],
                           args->bitmask[1] & nfs4_statfs_bitmap[1], &hdr);
        encode_nops(&hdr);
 -      return 0;
  }
  
  /*
   * GETATTR_BITMAP request
   */
 -static int nfs4_xdr_enc_server_caps(struct rpc_rqst *req, __be32 *p,
 -                                  struct nfs4_server_caps_arg *args)
 +static void nfs4_xdr_enc_server_caps(struct rpc_rqst *req,
 +                                   struct xdr_stream *xdr,
 +                                   struct nfs4_server_caps_arg *args)
  {
 -      struct xdr_stream xdr;
        struct compound_hdr hdr = {
                .minorversion = nfs4_xdr_minorversion(&args->seq_args),
        };
  
 -      xdr_init_encode(&xdr, &req->rq_snd_buf, p);
 -      encode_compound_hdr(&xdr, req, &hdr);
 -      encode_sequence(&xdr, &args->seq_args, &hdr);
 -      encode_putfh(&xdr, args->fhandle, &hdr);
 -      encode_getattr_one(&xdr, FATTR4_WORD0_SUPPORTED_ATTRS|
 +      encode_compound_hdr(xdr, req, &hdr);
 +      encode_sequence(xdr, &args->seq_args, &hdr);
 +      encode_putfh(xdr, args->fhandle, &hdr);
 +      encode_getattr_one(xdr, FATTR4_WORD0_SUPPORTED_ATTRS|
                           FATTR4_WORD0_LINK_SUPPORT|
                           FATTR4_WORD0_SYMLINK_SUPPORT|
                           FATTR4_WORD0_ACLSUPPORT, &hdr);
        encode_nops(&hdr);
 -      return 0;
  }
  
  /*
   * a RENEW request
   */
 -static int nfs4_xdr_enc_renew(struct rpc_rqst *req, __be32 *p, struct nfs_client *clp)
 +static void nfs4_xdr_enc_renew(struct rpc_rqst *req, struct xdr_stream *xdr,
 +                             struct nfs_client *clp)
  {
 -      struct xdr_stream xdr;
        struct compound_hdr hdr = {
                .nops   = 0,
        };
  
 -      xdr_init_encode(&xdr, &req->rq_snd_buf, p);
 -      encode_compound_hdr(&xdr, req, &hdr);
 -      encode_renew(&xdr, clp, &hdr);
 +      encode_compound_hdr(xdr, req, &hdr);
 +      encode_renew(xdr, clp, &hdr);
        encode_nops(&hdr);
 -      return 0;
  }
  
  /*
   * a SETCLIENTID request
   */
 -static int nfs4_xdr_enc_setclientid(struct rpc_rqst *req, __be32 *p, struct nfs4_setclientid *sc)
 +static void nfs4_xdr_enc_setclientid(struct rpc_rqst *req,
 +                                   struct xdr_stream *xdr,
 +                                   struct nfs4_setclientid *sc)
  {
 -      struct xdr_stream xdr;
        struct compound_hdr hdr = {
                .nops   = 0,
        };
  
 -      xdr_init_encode(&xdr, &req->rq_snd_buf, p);
 -      encode_compound_hdr(&xdr, req, &hdr);
 -      encode_setclientid(&xdr, sc, &hdr);
 +      encode_compound_hdr(xdr, req, &hdr);
 +      encode_setclientid(xdr, sc, &hdr);
        encode_nops(&hdr);
 -      return 0;
  }
  
  /*
   * a SETCLIENTID_CONFIRM request
   */
 -static int nfs4_xdr_enc_setclientid_confirm(struct rpc_rqst *req, __be32 *p, struct nfs4_setclientid_res *arg)
 +static void nfs4_xdr_enc_setclientid_confirm(struct rpc_rqst *req,
 +                                           struct xdr_stream *xdr,
 +                                           struct nfs4_setclientid_res *arg)
  {
 -      struct xdr_stream xdr;
        struct compound_hdr hdr = {
                .nops   = 0,
        };
        const u32 lease_bitmap[2] = { FATTR4_WORD0_LEASE_TIME, 0 };
  
 -      xdr_init_encode(&xdr, &req->rq_snd_buf, p);
 -      encode_compound_hdr(&xdr, req, &hdr);
 -      encode_setclientid_confirm(&xdr, arg, &hdr);
 -      encode_putrootfh(&xdr, &hdr);
 -      encode_fsinfo(&xdr, lease_bitmap, &hdr);
 +      encode_compound_hdr(xdr, req, &hdr);
 +      encode_setclientid_confirm(xdr, arg, &hdr);
 +      encode_putrootfh(xdr, &hdr);
 +      encode_fsinfo(xdr, lease_bitmap, &hdr);
        encode_nops(&hdr);
 -      return 0;
  }
  
  /*
   * DELEGRETURN request
   */
 -static int nfs4_xdr_enc_delegreturn(struct rpc_rqst *req, __be32 *p, const struct nfs4_delegreturnargs *args)
 +static void nfs4_xdr_enc_delegreturn(struct rpc_rqst *req,
 +                                   struct xdr_stream *xdr,
 +                                   const struct nfs4_delegreturnargs *args)
  {
 -      struct xdr_stream xdr;
        struct compound_hdr hdr = {
                .minorversion = nfs4_xdr_minorversion(&args->seq_args),
        };
  
 -      xdr_init_encode(&xdr, &req->rq_snd_buf, p);
 -      encode_compound_hdr(&xdr, req, &hdr);
 -      encode_sequence(&xdr, &args->seq_args, &hdr);
 -      encode_putfh(&xdr, args->fhandle, &hdr);
 -      encode_delegreturn(&xdr, args->stateid, &hdr);
 -      encode_getfattr(&xdr, args->bitmask, &hdr);
 +      encode_compound_hdr(xdr, req, &hdr);
 +      encode_sequence(xdr, &args->seq_args, &hdr);
 +      encode_putfh(xdr, args->fhandle, &hdr);
 +      encode_delegreturn(xdr, args->stateid, &hdr);
 +      encode_getfattr(xdr, args->bitmask, &hdr);
        encode_nops(&hdr);
 -      return 0;
  }
  
  /*
   * Encode FS_LOCATIONS request
   */
 -static int nfs4_xdr_enc_fs_locations(struct rpc_rqst *req, __be32 *p, struct nfs4_fs_locations_arg *args)
 +static void nfs4_xdr_enc_fs_locations(struct rpc_rqst *req,
 +                                    struct xdr_stream *xdr,
 +                                    struct nfs4_fs_locations_arg *args)
  {
 -      struct xdr_stream xdr;
        struct compound_hdr hdr = {
                .minorversion = nfs4_xdr_minorversion(&args->seq_args),
        };
        uint32_t replen;
  
 -      xdr_init_encode(&xdr, &req->rq_snd_buf, p);
 -      encode_compound_hdr(&xdr, req, &hdr);
 -      encode_sequence(&xdr, &args->seq_args, &hdr);
 -      encode_putfh(&xdr, args->dir_fh, &hdr);
 -      encode_lookup(&xdr, args->name, &hdr);
 +      encode_compound_hdr(xdr, req, &hdr);
 +      encode_sequence(xdr, &args->seq_args, &hdr);
 +      encode_putfh(xdr, args->dir_fh, &hdr);
 +      encode_lookup(xdr, args->name, &hdr);
        replen = hdr.replen;    /* get the attribute into args->page */
 -      encode_fs_locations(&xdr, args->bitmask, &hdr);
 +      encode_fs_locations(xdr, args->bitmask, &hdr);
  
        xdr_inline_pages(&req->rq_rcv_buf, replen << 2, &args->page,
                        0, PAGE_SIZE);
        encode_nops(&hdr);
 -      return 0;
  }
  
  #if defined(CONFIG_NFS_V4_1)
  /*
   * EXCHANGE_ID request
   */
 -static int nfs4_xdr_enc_exchange_id(struct rpc_rqst *req, uint32_t *p,
 -                                  struct nfs41_exchange_id_args *args)
 +static void nfs4_xdr_enc_exchange_id(struct rpc_rqst *req,
 +                                   struct xdr_stream *xdr,
 +                                   struct nfs41_exchange_id_args *args)
  {
 -      struct xdr_stream xdr;
        struct compound_hdr hdr = {
                .minorversion = args->client->cl_mvops->minor_version,
        };
  
 -      xdr_init_encode(&xdr, &req->rq_snd_buf, p);
 -      encode_compound_hdr(&xdr, req, &hdr);
 -      encode_exchange_id(&xdr, args, &hdr);
 +      encode_compound_hdr(xdr, req, &hdr);
 +      encode_exchange_id(xdr, args, &hdr);
        encode_nops(&hdr);
 -      return 0;
  }
  
  /*
   * a CREATE_SESSION request
   */
 -static int nfs4_xdr_enc_create_session(struct rpc_rqst *req, uint32_t *p,
 -                                     struct nfs41_create_session_args *args)
 +static void nfs4_xdr_enc_create_session(struct rpc_rqst *req,
 +                                      struct xdr_stream *xdr,
 +                                      struct nfs41_create_session_args *args)
  {
 -      struct xdr_stream xdr;
        struct compound_hdr hdr = {
                .minorversion = args->client->cl_mvops->minor_version,
        };
  
 -      xdr_init_encode(&xdr, &req->rq_snd_buf, p);
 -      encode_compound_hdr(&xdr, req, &hdr);
 -      encode_create_session(&xdr, args, &hdr);
 +      encode_compound_hdr(xdr, req, &hdr);
 +      encode_create_session(xdr, args, &hdr);
        encode_nops(&hdr);
 -      return 0;
  }
  
  /*
   * a DESTROY_SESSION request
   */
 -static int nfs4_xdr_enc_destroy_session(struct rpc_rqst *req, uint32_t *p,
 -                                      struct nfs4_session *session)
 +static void nfs4_xdr_enc_destroy_session(struct rpc_rqst *req,
 +                                       struct xdr_stream *xdr,
 +                                       struct nfs4_session *session)
  {
 -      struct xdr_stream xdr;
        struct compound_hdr hdr = {
                .minorversion = session->clp->cl_mvops->minor_version,
        };
  
 -      xdr_init_encode(&xdr, &req->rq_snd_buf, p);
 -      encode_compound_hdr(&xdr, req, &hdr);
 -      encode_destroy_session(&xdr, session, &hdr);
 +      encode_compound_hdr(xdr, req, &hdr);
 +      encode_destroy_session(xdr, session, &hdr);
        encode_nops(&hdr);
 -      return 0;
  }
  
  /*
   * a SEQUENCE request
   */
 -static int nfs4_xdr_enc_sequence(struct rpc_rqst *req, uint32_t *p,
 -                               struct nfs4_sequence_args *args)
 +static void nfs4_xdr_enc_sequence(struct rpc_rqst *req, struct xdr_stream *xdr,
 +                                struct nfs4_sequence_args *args)
  {
 -      struct xdr_stream xdr;
        struct compound_hdr hdr = {
                .minorversion = nfs4_xdr_minorversion(args),
        };
  
 -      xdr_init_encode(&xdr, &req->rq_snd_buf, p);
 -      encode_compound_hdr(&xdr, req, &hdr);
 -      encode_sequence(&xdr, args, &hdr);
 +      encode_compound_hdr(xdr, req, &hdr);
 +      encode_sequence(xdr, args, &hdr);
        encode_nops(&hdr);
 -      return 0;
  }
  
  /*
   * a GET_LEASE_TIME request
   */
 -static int nfs4_xdr_enc_get_lease_time(struct rpc_rqst *req, uint32_t *p,
 -                                     struct nfs4_get_lease_time_args *args)
 +static void nfs4_xdr_enc_get_lease_time(struct rpc_rqst *req,
 +                                      struct xdr_stream *xdr,
 +                                      struct nfs4_get_lease_time_args *args)
  {
 -      struct xdr_stream xdr;
        struct compound_hdr hdr = {
                .minorversion = nfs4_xdr_minorversion(&args->la_seq_args),
        };
        const u32 lease_bitmap[2] = { FATTR4_WORD0_LEASE_TIME, 0 };
  
 -      xdr_init_encode(&xdr, &req->rq_snd_buf, p);
 -      encode_compound_hdr(&xdr, req, &hdr);
 -      encode_sequence(&xdr, &args->la_seq_args, &hdr);
 -      encode_putrootfh(&xdr, &hdr);
 -      encode_fsinfo(&xdr, lease_bitmap, &hdr);
 +      encode_compound_hdr(xdr, req, &hdr);
 +      encode_sequence(xdr, &args->la_seq_args, &hdr);
 +      encode_putrootfh(xdr, &hdr);
 +      encode_fsinfo(xdr, lease_bitmap, &hdr);
        encode_nops(&hdr);
 -      return 0;
  }
  
  /*
   * a RECLAIM_COMPLETE request
   */
 -static int nfs4_xdr_enc_reclaim_complete(struct rpc_rqst *req, uint32_t *p,
 -                                   struct nfs41_reclaim_complete_args *args)
 +static void nfs4_xdr_enc_reclaim_complete(struct rpc_rqst *req,
 +                                        struct xdr_stream *xdr,
 +                              struct nfs41_reclaim_complete_args *args)
  {
 -      struct xdr_stream xdr;
        struct compound_hdr hdr = {
                .minorversion = nfs4_xdr_minorversion(&args->seq_args)
        };
  
 -      xdr_init_encode(&xdr, &req->rq_snd_buf, p);
 -      encode_compound_hdr(&xdr, req, &hdr);
 -      encode_sequence(&xdr, &args->seq_args, &hdr);
 -      encode_reclaim_complete(&xdr, args, &hdr);
 +      encode_compound_hdr(xdr, req, &hdr);
 +      encode_sequence(xdr, &args->seq_args, &hdr);
 +      encode_reclaim_complete(xdr, args, &hdr);
        encode_nops(&hdr);
 -      return 0;
  }
  
  /*
   * Encode GETDEVICEINFO request
   */
 -static int nfs4_xdr_enc_getdeviceinfo(struct rpc_rqst *req, uint32_t *p,
 -                                    struct nfs4_getdeviceinfo_args *args)
 +static void nfs4_xdr_enc_getdeviceinfo(struct rpc_rqst *req,
 +                                     struct xdr_stream *xdr,
 +                                     struct nfs4_getdeviceinfo_args *args)
  {
 -      struct xdr_stream xdr;
        struct compound_hdr hdr = {
                .minorversion = nfs4_xdr_minorversion(&args->seq_args),
        };
  
 -      xdr_init_encode(&xdr, &req->rq_snd_buf, p);
 -      encode_compound_hdr(&xdr, req, &hdr);
 -      encode_sequence(&xdr, &args->seq_args, &hdr);
 -      encode_getdeviceinfo(&xdr, args, &hdr);
 +      encode_compound_hdr(xdr, req, &hdr);
 +      encode_sequence(xdr, &args->seq_args, &hdr);
 +      encode_getdeviceinfo(xdr, args, &hdr);
  
        /* set up reply kvec. Subtract notification bitmap max size (2)
         * so that notification bitmap is put in xdr_buf tail */
                         args->pdev->pglen);
  
        encode_nops(&hdr);
 -      return 0;
  }
  
  /*
   *  Encode LAYOUTGET request
   */
 -static int nfs4_xdr_enc_layoutget(struct rpc_rqst *req, uint32_t *p,
 -                                struct nfs4_layoutget_args *args)
 +static void nfs4_xdr_enc_layoutget(struct rpc_rqst *req,
 +                                 struct xdr_stream *xdr,
 +                                 struct nfs4_layoutget_args *args)
  {
 -      struct xdr_stream xdr;
        struct compound_hdr hdr = {
                .minorversion = nfs4_xdr_minorversion(&args->seq_args),
        };
  
 -      xdr_init_encode(&xdr, &req->rq_snd_buf, p);
 -      encode_compound_hdr(&xdr, req, &hdr);
 -      encode_sequence(&xdr, &args->seq_args, &hdr);
 -      encode_putfh(&xdr, NFS_FH(args->inode), &hdr);
 -      encode_layoutget(&xdr, args, &hdr);
 +      encode_compound_hdr(xdr, req, &hdr);
 +      encode_sequence(xdr, &args->seq_args, &hdr);
 +      encode_putfh(xdr, NFS_FH(args->inode), &hdr);
 +      encode_layoutget(xdr, args, &hdr);
        encode_nops(&hdr);
 -      return 0;
  }
  #endif /* CONFIG_NFS_V4_1 */
  
@@@ -4397,7 -4475,7 +4397,7 @@@ static int decode_read(struct xdr_strea
                goto out_overflow;
        eof = be32_to_cpup(p++);
        count = be32_to_cpup(p);
 -      hdrlen = (u8 *) p - (u8 *) iov->iov_base;
 +      hdrlen = (u8 *) xdr->p - (u8 *) iov->iov_base;
        recvd = req->rq_rcv_buf.len - hdrlen;
        if (count > recvd) {
                dprintk("NFS: server cheating in read reply: "
@@@ -4922,7 -5000,7 +4922,7 @@@ static int decode_getdeviceinfo(struct 
                goto out_overflow;
        len = be32_to_cpup(p);
        if (len) {
 -              int i;
 +              uint32_t i;
  
                p = xdr_inline_decode(xdr, 4 * len);
                if (unlikely(!p))
@@@ -5012,26 -5090,26 +5012,26 @@@ out_overflow
  /*
   * Decode OPEN_DOWNGRADE response
   */
 -static int nfs4_xdr_dec_open_downgrade(struct rpc_rqst *rqstp, __be32 *p, struct nfs_closeres *res)
 +static int nfs4_xdr_dec_open_downgrade(struct rpc_rqst *rqstp,
 +                                     struct xdr_stream *xdr,
 +                                     struct nfs_closeres *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);
 +      status = decode_compound_hdr(xdr, &hdr);
        if (status)
                goto out;
 -      status = decode_sequence(&xdr, &res->seq_res, rqstp);
 +      status = decode_sequence(xdr, &res->seq_res, rqstp);
        if (status)
                goto out;
 -      status = decode_putfh(&xdr);
 +      status = decode_putfh(xdr);
        if (status)
                goto out;
 -      status = decode_open_downgrade(&xdr, res);
 +      status = decode_open_downgrade(xdr, res);
        if (status != 0)
                goto out;
 -      decode_getfattr(&xdr, res->fattr, res->server,
 +      decode_getfattr(xdr, res->fattr, res->server,
                        !RPC_IS_ASYNC(rqstp->rq_task));
  out:
        return status;
  /*
   * Decode ACCESS response
   */
 -static int nfs4_xdr_dec_access(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_accessres *res)
 +static int nfs4_xdr_dec_access(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
 +                             struct nfs4_accessres *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);
 +      status = decode_compound_hdr(xdr, &hdr);
        if (status)
                goto out;
 -      status = decode_sequence(&xdr, &res->seq_res, rqstp);
 +      status = decode_sequence(xdr, &res->seq_res, rqstp);
        if (status)
                goto out;
 -      status = decode_putfh(&xdr);
 +      status = decode_putfh(xdr);
        if (status != 0)
                goto out;
 -      status = decode_access(&xdr, res);
 +      status = decode_access(xdr, res);
        if (status != 0)
                goto out;
 -      decode_getfattr(&xdr, res->fattr, res->server,
 +      decode_getfattr(xdr, res->fattr, res->server,
                        !RPC_IS_ASYNC(rqstp->rq_task));
  out:
        return status;
  /*
   * Decode LOOKUP response
   */
 -static int nfs4_xdr_dec_lookup(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_lookup_res *res)
 +static int nfs4_xdr_dec_lookup(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
 +                             struct nfs4_lookup_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);
 +      status = decode_compound_hdr(xdr, &hdr);
        if (status)
                goto out;
 -      status = decode_sequence(&xdr, &res->seq_res, rqstp);
 +      status = decode_sequence(xdr, &res->seq_res, rqstp);
        if (status)
                goto out;
 -      if ((status = decode_putfh(&xdr)) != 0)
 +      status = decode_putfh(xdr);
 +      if (status)
                goto out;
 -      if ((status = decode_lookup(&xdr)) != 0)
 +      status = decode_lookup(xdr);
 +      if (status)
                goto out;
 -      if ((status = decode_getfh(&xdr, res->fh)) != 0)
 +      status = decode_getfh(xdr, res->fh);
 +      if (status)
                goto out;
 -      status = decode_getfattr(&xdr, res->fattr, res->server
 +      status = decode_getfattr(xdr, res->fattr, res->server
                        ,!RPC_IS_ASYNC(rqstp->rq_task));
  out:
        return status;
  /*
   * Decode LOOKUP_ROOT response
   */
 -static int nfs4_xdr_dec_lookup_root(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_lookup_res *res)
 +static int nfs4_xdr_dec_lookup_root(struct rpc_rqst *rqstp,
 +                                  struct xdr_stream *xdr,
 +                                  struct nfs4_lookup_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);
 +      status = decode_compound_hdr(xdr, &hdr);
        if (status)
                goto out;
 -      status = decode_sequence(&xdr, &res->seq_res, rqstp);
 +      status = decode_sequence(xdr, &res->seq_res, rqstp);
        if (status)
                goto out;
 -      if ((status = decode_putrootfh(&xdr)) != 0)
 +      status = decode_putrootfh(xdr);
 +      if (status)
                goto out;
 -      if ((status = decode_getfh(&xdr, res->fh)) == 0)
 -              status = decode_getfattr(&xdr, res->fattr, res->server,
 +      status = decode_getfh(xdr, res->fh);
 +      if (status == 0)
 +              status = decode_getfattr(xdr, res->fattr, res->server,
                                !RPC_IS_ASYNC(rqstp->rq_task));
  out:
        return status;
  /*
   * Decode REMOVE response
   */
 -static int nfs4_xdr_dec_remove(struct rpc_rqst *rqstp, __be32 *p, struct nfs_removeres *res)
 +static int nfs4_xdr_dec_remove(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
 +                             struct nfs_removeres *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);
 +      status = decode_compound_hdr(xdr, &hdr);
        if (status)
                goto out;
 -      status = decode_sequence(&xdr, &res->seq_res, rqstp);
 +      status = decode_sequence(xdr, &res->seq_res, rqstp);
        if (status)
                goto out;
 -      if ((status = decode_putfh(&xdr)) != 0)
 +      status = decode_putfh(xdr);
 +      if (status)
                goto out;
 -      if ((status = decode_remove(&xdr, &res->cinfo)) != 0)
 +      status = decode_remove(xdr, &res->cinfo);
 +      if (status)
                goto out;
 -      decode_getfattr(&xdr, res->dir_attr, res->server,
 +      decode_getfattr(xdr, res->dir_attr, res->server,
                        !RPC_IS_ASYNC(rqstp->rq_task));
  out:
        return status;
  /*
   * Decode RENAME response
   */
 -static int nfs4_xdr_dec_rename(struct rpc_rqst *rqstp, __be32 *p, struct nfs_renameres *res)
 +static int nfs4_xdr_dec_rename(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
 +                             struct nfs_renameres *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);
 +      status = decode_compound_hdr(xdr, &hdr);
        if (status)
                goto out;
 -      status = decode_sequence(&xdr, &res->seq_res, rqstp);
 +      status = decode_sequence(xdr, &res->seq_res, rqstp);
        if (status)
                goto out;
 -      if ((status = decode_putfh(&xdr)) != 0)
 +      status = decode_putfh(xdr);
 +      if (status)
                goto out;
 -      if ((status = decode_savefh(&xdr)) != 0)
 +      status = decode_savefh(xdr);
 +      if (status)
                goto out;
 -      if ((status = decode_putfh(&xdr)) != 0)
 +      status = decode_putfh(xdr);
 +      if (status)
                goto out;
 -      if ((status = decode_rename(&xdr, &res->old_cinfo, &res->new_cinfo)) != 0)
 +      status = decode_rename(xdr, &res->old_cinfo, &res->new_cinfo);
 +      if (status)
                goto out;
        /* Current FH is target directory */
 -      if (decode_getfattr(&xdr, res->new_fattr, res->server,
 +      if (decode_getfattr(xdr, res->new_fattr, res->server,
                                !RPC_IS_ASYNC(rqstp->rq_task)) != 0)
                goto out;
 -      if ((status = decode_restorefh(&xdr)) != 0)
 +      status = decode_restorefh(xdr);
 +      if (status)
                goto out;
 -      decode_getfattr(&xdr, res->old_fattr, res->server,
 +      decode_getfattr(xdr, res->old_fattr, res->server,
                        !RPC_IS_ASYNC(rqstp->rq_task));
  out:
        return status;
  /*
   * Decode LINK response
   */
 -static int nfs4_xdr_dec_link(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_link_res *res)
 +static int nfs4_xdr_dec_link(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
 +                           struct nfs4_link_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);
 +      status = decode_compound_hdr(xdr, &hdr);
        if (status)
                goto out;
 -      status = decode_sequence(&xdr, &res->seq_res, rqstp);
 +      status = decode_sequence(xdr, &res->seq_res, rqstp);
        if (status)
                goto out;
 -      if ((status = decode_putfh(&xdr)) != 0)
 +      status = decode_putfh(xdr);
 +      if (status)
                goto out;
 -      if ((status = decode_savefh(&xdr)) != 0)
 +      status = decode_savefh(xdr);
 +      if (status)
                goto out;
 -      if ((status = decode_putfh(&xdr)) != 0)
 +      status = decode_putfh(xdr);
 +      if (status)
                goto out;
 -      if ((status = decode_link(&xdr, &res->cinfo)) != 0)
 +      status = decode_link(xdr, &res->cinfo);
 +      if (status)
                goto out;
        /*
         * Note order: OP_LINK leaves the directory as the current
         *             filehandle.
         */
 -      if (decode_getfattr(&xdr, res->dir_attr, res->server,
 +      if (decode_getfattr(xdr, res->dir_attr, res->server,
                                !RPC_IS_ASYNC(rqstp->rq_task)) != 0)
                goto out;
 -      if ((status = decode_restorefh(&xdr)) != 0)
 +      status = decode_restorefh(xdr);
 +      if (status)
                goto out;
 -      decode_getfattr(&xdr, res->fattr, res->server,
 +      decode_getfattr(xdr, res->fattr, res->server,
                        !RPC_IS_ASYNC(rqstp->rq_task));
  out:
        return status;
  /*
   * Decode CREATE response
   */
 -static int nfs4_xdr_dec_create(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_create_res *res)
 +static int nfs4_xdr_dec_create(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
 +                             struct nfs4_create_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);
 +      status = decode_compound_hdr(xdr, &hdr);
        if (status)
                goto out;
 -      status = decode_sequence(&xdr, &res->seq_res, rqstp);
 +      status = decode_sequence(xdr, &res->seq_res, rqstp);
        if (status)
                goto out;
 -      if ((status = decode_putfh(&xdr)) != 0)
 +      status = decode_putfh(xdr);
 +      if (status)
                goto out;
 -      if ((status = decode_savefh(&xdr)) != 0)
 +      status = decode_savefh(xdr);
 +      if (status)
                goto out;
 -      if ((status = decode_create(&xdr,&res->dir_cinfo)) != 0)
 +      status = decode_create(xdr, &res->dir_cinfo);
 +      if (status)
                goto out;
 -      if ((status = decode_getfh(&xdr, res->fh)) != 0)
 +      status = decode_getfh(xdr, res->fh);
 +      if (status)
                goto out;
 -      if (decode_getfattr(&xdr, res->fattr, res->server,
 +      if (decode_getfattr(xdr, res->fattr, res->server,
                                !RPC_IS_ASYNC(rqstp->rq_task)) != 0)
                goto out;
 -      if ((status = decode_restorefh(&xdr)) != 0)
 +      status = decode_restorefh(xdr);
 +      if (status)
                goto out;
 -      decode_getfattr(&xdr, res->dir_fattr, res->server,
 +      decode_getfattr(xdr, res->dir_fattr, res->server,
                        !RPC_IS_ASYNC(rqstp->rq_task));
  out:
        return status;
  /*
   * Decode SYMLINK response
   */
 -static int nfs4_xdr_dec_symlink(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_create_res *res)
 +static int nfs4_xdr_dec_symlink(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
 +                              struct nfs4_create_res *res)
  {
 -      return nfs4_xdr_dec_create(rqstp, p, res);
 +      return nfs4_xdr_dec_create(rqstp, xdr, res);
  }
  
  /*
   * Decode GETATTR response
   */
 -static int nfs4_xdr_dec_getattr(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_getattr_res *res)
 +static int nfs4_xdr_dec_getattr(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
 +                              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);
 +      status = decode_compound_hdr(xdr, &hdr);
        if (status)
                goto out;
 -      status = decode_sequence(&xdr, &res->seq_res, rqstp);
 +      status = decode_sequence(xdr, &res->seq_res, rqstp);
        if (status)
                goto out;
 -      status = decode_putfh(&xdr);
 +      status = decode_putfh(xdr);
        if (status)
                goto out;
 -      status = decode_getfattr(&xdr, res->fattr, res->server,
 +      status = decode_getfattr(xdr, res->fattr, res->server,
                        !RPC_IS_ASYNC(rqstp->rq_task));
  out:
        return status;
  /*
   * Encode an SETACL request
   */
 -static int
 -nfs4_xdr_enc_setacl(struct rpc_rqst *req, __be32 *p, struct nfs_setaclargs *args)
 +static void nfs4_xdr_enc_setacl(struct rpc_rqst *req, struct xdr_stream *xdr,
 +                              struct nfs_setaclargs *args)
  {
 -      struct xdr_stream xdr;
        struct compound_hdr hdr = {
                .minorversion = nfs4_xdr_minorversion(&args->seq_args),
        };
 -      int status;
  
 -      xdr_init_encode(&xdr, &req->rq_snd_buf, p);
 -      encode_compound_hdr(&xdr, req, &hdr);
 -      encode_sequence(&xdr, &args->seq_args, &hdr);
 -      encode_putfh(&xdr, args->fh, &hdr);
 -      status = encode_setacl(&xdr, args, &hdr);
 +      encode_compound_hdr(xdr, req, &hdr);
 +      encode_sequence(xdr, &args->seq_args, &hdr);
 +      encode_putfh(xdr, args->fh, &hdr);
 +      encode_setacl(xdr, args, &hdr);
        encode_nops(&hdr);
 -      return status;
  }
  
  /*
   * Decode SETACL response
   */
  static int
 -nfs4_xdr_dec_setacl(struct rpc_rqst *rqstp, __be32 *p,
 +nfs4_xdr_dec_setacl(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
                    struct nfs_setaclres *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);
 +      status = decode_compound_hdr(xdr, &hdr);
        if (status)
                goto out;
 -      status = decode_sequence(&xdr, &res->seq_res, rqstp);
 +      status = decode_sequence(xdr, &res->seq_res, rqstp);
        if (status)
                goto out;
 -      status = decode_putfh(&xdr);
 +      status = decode_putfh(xdr);
        if (status)
                goto out;
 -      status = decode_setattr(&xdr);
 +      status = decode_setattr(xdr);
  out:
        return status;
  }
   * Decode GETACL response
   */
  static int
 -nfs4_xdr_dec_getacl(struct rpc_rqst *rqstp, __be32 *p,
 +nfs4_xdr_dec_getacl(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
                    struct nfs_getaclres *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);
 +      status = decode_compound_hdr(xdr, &hdr);
        if (status)
                goto out;
 -      status = decode_sequence(&xdr, &res->seq_res, rqstp);
 +      status = decode_sequence(xdr, &res->seq_res, rqstp);
        if (status)
                goto out;
 -      status = decode_putfh(&xdr);
 +      status = decode_putfh(xdr);
        if (status)
                goto out;
 -      status = decode_getacl(&xdr, rqstp, &res->acl_len);
 +      status = decode_getacl(xdr, rqstp, &res->acl_len);
  
  out:
        return status;
  /*
   * Decode CLOSE response
   */
 -static int nfs4_xdr_dec_close(struct rpc_rqst *rqstp, __be32 *p, struct nfs_closeres *res)
 +static int nfs4_xdr_dec_close(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
 +                            struct nfs_closeres *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);
 +      status = decode_compound_hdr(xdr, &hdr);
        if (status)
                goto out;
 -      status = decode_sequence(&xdr, &res->seq_res, rqstp);
 +      status = decode_sequence(xdr, &res->seq_res, rqstp);
        if (status)
                goto out;
 -      status = decode_putfh(&xdr);
 +      status = decode_putfh(xdr);
        if (status)
                goto out;
 -      status = decode_close(&xdr, res);
 +      status = decode_close(xdr, res);
        if (status != 0)
                goto out;
        /*
         *      an ESTALE error. Shouldn't be a problem,
         *      though, since fattr->valid will remain unset.
         */
 -      decode_getfattr(&xdr, res->fattr, res->server,
 +      decode_getfattr(xdr, res->fattr, res->server,
                        !RPC_IS_ASYNC(rqstp->rq_task));
  out:
        return status;
  /*
   * Decode OPEN response
   */
 -static int nfs4_xdr_dec_open(struct rpc_rqst *rqstp, __be32 *p, struct nfs_openres *res)
 +static int nfs4_xdr_dec_open(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
 +                           struct nfs_openres *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);
 +      status = decode_compound_hdr(xdr, &hdr);
        if (status)
                goto out;
 -      status = decode_sequence(&xdr, &res->seq_res, rqstp);
 +      status = decode_sequence(xdr, &res->seq_res, rqstp);
        if (status)
                goto out;
 -      status = decode_putfh(&xdr);
 +      status = decode_putfh(xdr);
        if (status)
                goto out;
 -      status = decode_savefh(&xdr);
 +      status = decode_savefh(xdr);
        if (status)
                goto out;
 -      status = decode_open(&xdr, res);
 +      status = decode_open(xdr, res);
        if (status)
                goto out;
 -      if (decode_getfh(&xdr, &res->fh) != 0)
 +      if (decode_getfh(xdr, &res->fh) != 0)
                goto out;
 -      if (decode_getfattr(&xdr, res->f_attr, res->server,
 +      if (decode_getfattr(xdr, res->f_attr, res->server,
                                !RPC_IS_ASYNC(rqstp->rq_task)) != 0)
                goto out;
 -      if (decode_restorefh(&xdr) != 0)
 +      if (decode_restorefh(xdr) != 0)
                goto out;
 -      decode_getfattr(&xdr, res->dir_attr, res->server,
 +      decode_getfattr(xdr, res->dir_attr, res->server,
                        !RPC_IS_ASYNC(rqstp->rq_task));
  out:
        return status;
  /*
   * Decode OPEN_CONFIRM response
   */
 -static int nfs4_xdr_dec_open_confirm(struct rpc_rqst *rqstp, __be32 *p, struct nfs_open_confirmres *res)
 +static int nfs4_xdr_dec_open_confirm(struct rpc_rqst *rqstp,
 +                                   struct xdr_stream *xdr,
 +                                   struct nfs_open_confirmres *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);
 +      status = decode_compound_hdr(xdr, &hdr);
        if (status)
                goto out;
 -      status = decode_putfh(&xdr);
 +      status = decode_putfh(xdr);
        if (status)
                goto out;
 -      status = decode_open_confirm(&xdr, res);
 +      status = decode_open_confirm(xdr, res);
  out:
        return status;
  }
  /*
   * Decode OPEN response
   */
 -static int nfs4_xdr_dec_open_noattr(struct rpc_rqst *rqstp, __be32 *p, struct nfs_openres *res)
 +static int nfs4_xdr_dec_open_noattr(struct rpc_rqst *rqstp,
 +                                  struct xdr_stream *xdr,
 +                                  struct nfs_openres *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);
 +      status = decode_compound_hdr(xdr, &hdr);
        if (status)
                goto out;
 -      status = decode_sequence(&xdr, &res->seq_res, rqstp);
 +      status = decode_sequence(xdr, &res->seq_res, rqstp);
        if (status)
                goto out;
 -      status = decode_putfh(&xdr);
 +      status = decode_putfh(xdr);
        if (status)
                goto out;
 -      status = decode_open(&xdr, res);
 +      status = decode_open(xdr, res);
        if (status)
                goto out;
 -      decode_getfattr(&xdr, res->f_attr, res->server,
 +      decode_getfattr(xdr, res->f_attr, res->server,
                        !RPC_IS_ASYNC(rqstp->rq_task));
  out:
        return status;
  /*
   * Decode SETATTR response
   */
 -static int nfs4_xdr_dec_setattr(struct rpc_rqst *rqstp, __be32 *p, struct nfs_setattrres *res)
 +static int nfs4_xdr_dec_setattr(struct rpc_rqst *rqstp,
 +                              struct xdr_stream *xdr,
 +                              struct nfs_setattrres *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);
 +      status = decode_compound_hdr(xdr, &hdr);
        if (status)
                goto out;
 -      status = decode_sequence(&xdr, &res->seq_res, rqstp);
 +      status = decode_sequence(xdr, &res->seq_res, rqstp);
        if (status)
                goto out;
 -      status = decode_putfh(&xdr);
 +      status = decode_putfh(xdr);
        if (status)
                goto out;
 -      status = decode_setattr(&xdr);
 +      status = decode_setattr(xdr);
        if (status)
                goto out;
 -      decode_getfattr(&xdr, res->fattr, res->server,
 +      decode_getfattr(xdr, res->fattr, res->server,
                        !RPC_IS_ASYNC(rqstp->rq_task));
  out:
        return status;
  /*
   * Decode LOCK response
   */
 -static int nfs4_xdr_dec_lock(struct rpc_rqst *rqstp, __be32 *p, struct nfs_lock_res *res)
 +static int nfs4_xdr_dec_lock(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
 +                           struct nfs_lock_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);
 +      status = decode_compound_hdr(xdr, &hdr);
        if (status)
                goto out;
 -      status = decode_sequence(&xdr, &res->seq_res, rqstp);
 +      status = decode_sequence(xdr, &res->seq_res, rqstp);
        if (status)
                goto out;
 -      status = decode_putfh(&xdr);
 +      status = decode_putfh(xdr);
        if (status)
                goto out;
 -      status = decode_lock(&xdr, res);
 +      status = decode_lock(xdr, res);
  out:
        return status;
  }
  /*
   * Decode LOCKT response
   */
 -static int nfs4_xdr_dec_lockt(struct rpc_rqst *rqstp, __be32 *p, struct nfs_lockt_res *res)
 +static int nfs4_xdr_dec_lockt(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
 +                            struct nfs_lockt_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);
 +      status = decode_compound_hdr(xdr, &hdr);
        if (status)
                goto out;
 -      status = decode_sequence(&xdr, &res->seq_res, rqstp);
 +      status = decode_sequence(xdr, &res->seq_res, rqstp);
        if (status)
                goto out;
 -      status = decode_putfh(&xdr);
 +      status = decode_putfh(xdr);
        if (status)
                goto out;
 -      status = decode_lockt(&xdr, res);
 +      status = decode_lockt(xdr, res);
  out:
        return status;
  }
  /*
   * Decode LOCKU response
   */
 -static int nfs4_xdr_dec_locku(struct rpc_rqst *rqstp, __be32 *p, struct nfs_locku_res *res)
 +static int nfs4_xdr_dec_locku(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
 +                            struct nfs_locku_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);
 +      status = decode_compound_hdr(xdr, &hdr);
        if (status)
                goto out;
 -      status = decode_sequence(&xdr, &res->seq_res, rqstp);
 +      status = decode_sequence(xdr, &res->seq_res, rqstp);
        if (status)
                goto out;
 -      status = decode_putfh(&xdr);
 +      status = decode_putfh(xdr);
        if (status)
                goto out;
 -      status = decode_locku(&xdr, res);
 +      status = decode_locku(xdr, res);
  out:
        return status;
  }
  
 -static int nfs4_xdr_dec_release_lockowner(struct rpc_rqst *rqstp, __be32 *p, void *dummy)
 +static int nfs4_xdr_dec_release_lockowner(struct rpc_rqst *rqstp,
 +                                        struct xdr_stream *xdr, void *dummy)
  {
 -      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);
 +      status = decode_compound_hdr(xdr, &hdr);
        if (!status)
 -              status = decode_release_lockowner(&xdr);
 +              status = decode_release_lockowner(xdr);
        return status;
  }
  
  /*
   * Decode READLINK response
   */
 -static int nfs4_xdr_dec_readlink(struct rpc_rqst *rqstp, __be32 *p,
 +static int nfs4_xdr_dec_readlink(struct rpc_rqst *rqstp,
 +                               struct xdr_stream *xdr,
                                 struct nfs4_readlink_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);
 +      status = decode_compound_hdr(xdr, &hdr);
        if (status)
                goto out;
 -      status = decode_sequence(&xdr, &res->seq_res, rqstp);
 +      status = decode_sequence(xdr, &res->seq_res, rqstp);
        if (status)
                goto out;
 -      status = decode_putfh(&xdr);
 +      status = decode_putfh(xdr);
        if (status)
                goto out;
 -      status = decode_readlink(&xdr, rqstp);
 +      status = decode_readlink(xdr, rqstp);
  out:
        return status;
  }
  /*
   * Decode READDIR response
   */
 -static int nfs4_xdr_dec_readdir(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_readdir_res *res)
 +static int nfs4_xdr_dec_readdir(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
 +                              struct nfs4_readdir_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);
 +      status = decode_compound_hdr(xdr, &hdr);
        if (status)
                goto out;
 -      status = decode_sequence(&xdr, &res->seq_res, rqstp);
 +      status = decode_sequence(xdr, &res->seq_res, rqstp);
        if (status)
                goto out;
 -      status = decode_putfh(&xdr);
 +      status = decode_putfh(xdr);
        if (status)
                goto out;
 -      status = decode_readdir(&xdr, rqstp, res);
 +      status = decode_readdir(xdr, rqstp, res);
  out:
        return status;
  }
  /*
   * Decode Read response
   */
 -static int nfs4_xdr_dec_read(struct rpc_rqst *rqstp, __be32 *p, struct nfs_readres *res)
 +static int nfs4_xdr_dec_read(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
 +                           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);
 +      status = decode_compound_hdr(xdr, &hdr);
        if (status)
                goto out;
 -      status = decode_sequence(&xdr, &res->seq_res, rqstp);
 +      status = decode_sequence(xdr, &res->seq_res, rqstp);
        if (status)
                goto out;
 -      status = decode_putfh(&xdr);
 +      status = decode_putfh(xdr);
        if (status)
                goto out;
 -      status = decode_read(&xdr, rqstp, res);
 +      status = decode_read(xdr, rqstp, res);
        if (!status)
                status = res->count;
  out:
  /*
   * Decode WRITE response
   */
 -static int nfs4_xdr_dec_write(struct rpc_rqst *rqstp, __be32 *p, struct nfs_writeres *res)
 +static int nfs4_xdr_dec_write(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
 +                            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);
 +      status = decode_compound_hdr(xdr, &hdr);
        if (status)
                goto out;
 -      status = decode_sequence(&xdr, &res->seq_res, rqstp);
 +      status = decode_sequence(xdr, &res->seq_res, rqstp);
        if (status)
                goto out;
 -      status = decode_putfh(&xdr);
 +      status = decode_putfh(xdr);
        if (status)
                goto out;
 -      status = decode_write(&xdr, res);
 +      status = decode_write(xdr, res);
        if (status)
                goto out;
 -      decode_getfattr(&xdr, res->fattr, res->server,
 +      decode_getfattr(xdr, res->fattr, res->server,
                        !RPC_IS_ASYNC(rqstp->rq_task));
        if (!status)
                status = res->count;
  /*
   * Decode COMMIT response
   */
 -static int nfs4_xdr_dec_commit(struct rpc_rqst *rqstp, __be32 *p, struct nfs_writeres *res)
 +static int nfs4_xdr_dec_commit(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
 +                             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);
 +      status = decode_compound_hdr(xdr, &hdr);
        if (status)
                goto out;
 -      status = decode_sequence(&xdr, &res->seq_res, rqstp);
 +      status = decode_sequence(xdr, &res->seq_res, rqstp);
        if (status)
                goto out;
 -      status = decode_putfh(&xdr);
 +      status = decode_putfh(xdr);
        if (status)
                goto out;
 -      status = decode_commit(&xdr, res);
 +      status = decode_commit(xdr, res);
        if (status)
                goto out;
 -      decode_getfattr(&xdr, res->fattr, res->server,
 +      decode_getfattr(xdr, res->fattr, res->server,
                        !RPC_IS_ASYNC(rqstp->rq_task));
  out:
        return status;
  /*
   * Decode FSINFO response
   */
 -static int nfs4_xdr_dec_fsinfo(struct rpc_rqst *req, __be32 *p,
 +static int nfs4_xdr_dec_fsinfo(struct rpc_rqst *req, struct xdr_stream *xdr,
                               struct nfs4_fsinfo_res *res)
  {
 -      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);
 +      status = decode_compound_hdr(xdr, &hdr);
        if (!status)
 -              status = decode_sequence(&xdr, &res->seq_res, req);
 +              status = decode_sequence(xdr, &res->seq_res, req);
        if (!status)
 -              status = decode_putfh(&xdr);
 +              status = decode_putfh(xdr);
        if (!status)
 -              status = decode_fsinfo(&xdr, res->fsinfo);
 +              status = decode_fsinfo(xdr, res->fsinfo);
        return status;
  }
  
  /*
   * Decode PATHCONF response
   */
 -static int nfs4_xdr_dec_pathconf(struct rpc_rqst *req, __be32 *p,
 +static int nfs4_xdr_dec_pathconf(struct rpc_rqst *req, struct xdr_stream *xdr,
                                 struct nfs4_pathconf_res *res)
  {
 -      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);
 +      status = decode_compound_hdr(xdr, &hdr);
        if (!status)
 -              status = decode_sequence(&xdr, &res->seq_res, req);
 +              status = decode_sequence(xdr, &res->seq_res, req);
        if (!status)
 -              status = decode_putfh(&xdr);
 +              status = decode_putfh(xdr);
        if (!status)
 -              status = decode_pathconf(&xdr, res->pathconf);
 +              status = decode_pathconf(xdr, res->pathconf);
        return status;
  }
  
  /*
   * Decode STATFS response
   */
 -static int nfs4_xdr_dec_statfs(struct rpc_rqst *req, __be32 *p,
 +static int nfs4_xdr_dec_statfs(struct rpc_rqst *req, struct xdr_stream *xdr,
                               struct nfs4_statfs_res *res)
  {
 -      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);
 +      status = decode_compound_hdr(xdr, &hdr);
        if (!status)
 -              status = decode_sequence(&xdr, &res->seq_res, req);
 +              status = decode_sequence(xdr, &res->seq_res, req);
        if (!status)
 -              status = decode_putfh(&xdr);
 +              status = decode_putfh(xdr);
        if (!status)
 -              status = decode_statfs(&xdr, res->fsstat);
 +              status = decode_statfs(xdr, res->fsstat);
        return status;
  }
  
  /*
   * Decode GETATTR_BITMAP response
   */
 -static int nfs4_xdr_dec_server_caps(struct rpc_rqst *req, __be32 *p, struct nfs4_server_caps_res *res)
 +static int nfs4_xdr_dec_server_caps(struct rpc_rqst *req,
 +                                  struct xdr_stream *xdr,
 +                                  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);
 -      status = decode_compound_hdr(&xdr, &hdr);
 +      status = decode_compound_hdr(xdr, &hdr);
        if (status)
                goto out;
 -      status = decode_sequence(&xdr, &res->seq_res, req);
 +      status = decode_sequence(xdr, &res->seq_res, req);
        if (status)
                goto out;
 -      if ((status = decode_putfh(&xdr)) != 0)
 +      status = decode_putfh(xdr);
 +      if (status)
                goto out;
 -      status = decode_server_caps(&xdr, res);
 +      status = decode_server_caps(xdr, res);
  out:
        return status;
  }
  /*
   * Decode RENEW response
   */
 -static int nfs4_xdr_dec_renew(struct rpc_rqst *rqstp, __be32 *p, void *dummy)
 +static int nfs4_xdr_dec_renew(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
 +                            void *__unused)
  {
 -      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);
 +      status = decode_compound_hdr(xdr, &hdr);
        if (!status)
 -              status = decode_renew(&xdr);
 +              status = decode_renew(xdr);
        return status;
  }
  
  /*
   * Decode SETCLIENTID response
   */
 -static int nfs4_xdr_dec_setclientid(struct rpc_rqst *req, __be32 *p,
 -              struct nfs4_setclientid_res *res)
 +static int nfs4_xdr_dec_setclientid(struct rpc_rqst *req,
 +                                  struct xdr_stream *xdr,
 +                                  struct nfs4_setclientid_res *res)
  {
 -      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);
 +      status = decode_compound_hdr(xdr, &hdr);
        if (!status)
 -              status = decode_setclientid(&xdr, res);
 +              status = decode_setclientid(xdr, res);
        return status;
  }
  
  /*
   * Decode SETCLIENTID_CONFIRM response
   */
 -static int nfs4_xdr_dec_setclientid_confirm(struct rpc_rqst *req, __be32 *p, struct nfs_fsinfo *fsinfo)
 +static int nfs4_xdr_dec_setclientid_confirm(struct rpc_rqst *req,
 +                                          struct xdr_stream *xdr,
 +                                          struct nfs_fsinfo *fsinfo)
  {
 -      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);
 +      status = decode_compound_hdr(xdr, &hdr);
        if (!status)
 -              status = decode_setclientid_confirm(&xdr);
 +              status = decode_setclientid_confirm(xdr);
        if (!status)
 -              status = decode_putrootfh(&xdr);
 +              status = decode_putrootfh(xdr);
        if (!status)
 -              status = decode_fsinfo(&xdr, fsinfo);
 +              status = decode_fsinfo(xdr, fsinfo);
        return status;
  }
  
  /*
   * Decode DELEGRETURN response
   */
 -static int nfs4_xdr_dec_delegreturn(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_delegreturnres *res)
 +static int nfs4_xdr_dec_delegreturn(struct rpc_rqst *rqstp,
 +                                  struct xdr_stream *xdr,
 +                                  struct nfs4_delegreturnres *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);
 +      status = decode_compound_hdr(xdr, &hdr);
        if (status)
                goto out;
 -      status = decode_sequence(&xdr, &res->seq_res, rqstp);
 +      status = decode_sequence(xdr, &res->seq_res, rqstp);
        if (status)
                goto out;
 -      status = decode_putfh(&xdr);
 +      status = decode_putfh(xdr);
        if (status != 0)
                goto out;
 -      status = decode_delegreturn(&xdr);
 +      status = decode_delegreturn(xdr);
        if (status != 0)
                goto out;
 -      decode_getfattr(&xdr, res->fattr, res->server,
 +      decode_getfattr(xdr, res->fattr, res->server,
                        !RPC_IS_ASYNC(rqstp->rq_task));
  out:
        return status;
  /*
   * Decode FS_LOCATIONS response
   */
 -static int nfs4_xdr_dec_fs_locations(struct rpc_rqst *req, __be32 *p,
 +static int nfs4_xdr_dec_fs_locations(struct rpc_rqst *req,
 +                                   struct xdr_stream *xdr,
                                     struct nfs4_fs_locations_res *res)
  {
 -      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);
 +      status = decode_compound_hdr(xdr, &hdr);
        if (status)
                goto out;
 -      status = decode_sequence(&xdr, &res->seq_res, req);
 +      status = decode_sequence(xdr, &res->seq_res, req);
        if (status)
                goto out;
 -      if ((status = decode_putfh(&xdr)) != 0)
 +      status = decode_putfh(xdr);
 +      if (status)
                goto out;
 -      if ((status = decode_lookup(&xdr)) != 0)
 +      status = decode_lookup(xdr);
 +      if (status)
                goto out;
 -      xdr_enter_page(&xdr, PAGE_SIZE);
 -      status = decode_getfattr(&xdr, &res->fs_locations->fattr,
 +      xdr_enter_page(xdr, PAGE_SIZE);
 +      status = decode_getfattr(xdr, &res->fs_locations->fattr,
                                 res->fs_locations->server,
                                 !RPC_IS_ASYNC(req->rq_task));
  out:
  /*
   * Decode EXCHANGE_ID response
   */
 -static int nfs4_xdr_dec_exchange_id(struct rpc_rqst *rqstp, uint32_t *p,
 +static int nfs4_xdr_dec_exchange_id(struct rpc_rqst *rqstp,
 +                                  struct xdr_stream *xdr,
                                    void *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);
 +      status = decode_compound_hdr(xdr, &hdr);
        if (!status)
 -              status = decode_exchange_id(&xdr, res);
 +              status = decode_exchange_id(xdr, res);
        return status;
  }
  
  /*
   * Decode CREATE_SESSION response
   */
 -static int nfs4_xdr_dec_create_session(struct rpc_rqst *rqstp, uint32_t *p,
 +static int nfs4_xdr_dec_create_session(struct rpc_rqst *rqstp,
 +                                     struct xdr_stream *xdr,
                                       struct nfs41_create_session_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);
 +      status = decode_compound_hdr(xdr, &hdr);
        if (!status)
 -              status = decode_create_session(&xdr, res);
 +              status = decode_create_session(xdr, res);
        return status;
  }
  
  /*
   * Decode DESTROY_SESSION response
   */
 -static int nfs4_xdr_dec_destroy_session(struct rpc_rqst *rqstp, uint32_t *p,
 -                                      void *dummy)
 +static int nfs4_xdr_dec_destroy_session(struct rpc_rqst *rqstp,
 +                                      struct xdr_stream *xdr,
 +                                      void *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);
 +      status = decode_compound_hdr(xdr, &hdr);
        if (!status)
 -              status = decode_destroy_session(&xdr, dummy);
 +              status = decode_destroy_session(xdr, res);
        return status;
  }
  
  /*
   * Decode SEQUENCE response
   */
 -static int nfs4_xdr_dec_sequence(struct rpc_rqst *rqstp, uint32_t *p,
 +static int nfs4_xdr_dec_sequence(struct rpc_rqst *rqstp,
 +                               struct xdr_stream *xdr,
                                 struct nfs4_sequence_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);
 +      status = decode_compound_hdr(xdr, &hdr);
        if (!status)
 -              status = decode_sequence(&xdr, res, rqstp);
 +              status = decode_sequence(xdr, res, rqstp);
        return status;
  }
  
  /*
   * Decode GET_LEASE_TIME response
   */
 -static int nfs4_xdr_dec_get_lease_time(struct rpc_rqst *rqstp, uint32_t *p,
 +static int nfs4_xdr_dec_get_lease_time(struct rpc_rqst *rqstp,
 +                                     struct xdr_stream *xdr,
                                       struct nfs4_get_lease_time_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);
 +      status = decode_compound_hdr(xdr, &hdr);
        if (!status)
 -              status = decode_sequence(&xdr, &res->lr_seq_res, rqstp);
 +              status = decode_sequence(xdr, &res->lr_seq_res, rqstp);
        if (!status)
 -              status = decode_putrootfh(&xdr);
 +              status = decode_putrootfh(xdr);
        if (!status)
 -              status = decode_fsinfo(&xdr, res->lr_fsinfo);
 +              status = decode_fsinfo(xdr, res->lr_fsinfo);
        return status;
  }
  
  /*
   * Decode RECLAIM_COMPLETE response
   */
 -static int nfs4_xdr_dec_reclaim_complete(struct rpc_rqst *rqstp, uint32_t *p,
 +static int nfs4_xdr_dec_reclaim_complete(struct rpc_rqst *rqstp,
 +                                       struct xdr_stream *xdr,
                                         struct nfs41_reclaim_complete_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);
 +      status = decode_compound_hdr(xdr, &hdr);
        if (!status)
 -              status = decode_sequence(&xdr, &res->seq_res, rqstp);
 +              status = decode_sequence(xdr, &res->seq_res, rqstp);
        if (!status)
 -              status = decode_reclaim_complete(&xdr, (void *)NULL);
 +              status = decode_reclaim_complete(xdr, (void *)NULL);
        return status;
  }
  
  /*
   * Decode GETDEVINFO response
   */
 -static int nfs4_xdr_dec_getdeviceinfo(struct rpc_rqst *rqstp, uint32_t *p,
 +static int nfs4_xdr_dec_getdeviceinfo(struct rpc_rqst *rqstp,
 +                                    struct xdr_stream *xdr,
                                      struct nfs4_getdeviceinfo_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);
 +      status = decode_compound_hdr(xdr, &hdr);
        if (status != 0)
                goto out;
 -      status = decode_sequence(&xdr, &res->seq_res, rqstp);
 +      status = decode_sequence(xdr, &res->seq_res, rqstp);
        if (status != 0)
                goto out;
 -      status = decode_getdeviceinfo(&xdr, res->pdev);
 +      status = decode_getdeviceinfo(xdr, res->pdev);
  out:
        return status;
  }
  /*
   * Decode LAYOUTGET response
   */
 -static int nfs4_xdr_dec_layoutget(struct rpc_rqst *rqstp, uint32_t *p,
 +static int nfs4_xdr_dec_layoutget(struct rpc_rqst *rqstp,
 +                                struct xdr_stream *xdr,
                                  struct nfs4_layoutget_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);
 +      status = decode_compound_hdr(xdr, &hdr);
        if (status)
                goto out;
 -      status = decode_sequence(&xdr, &res->seq_res, rqstp);
 +      status = decode_sequence(xdr, &res->seq_res, rqstp);
        if (status)
                goto out;
 -      status = decode_putfh(&xdr);
 +      status = decode_putfh(xdr);
        if (status)
                goto out;
 -      status = decode_layoutget(&xdr, rqstp, res);
 +      status = decode_layoutget(xdr, rqstp, res);
  out:
        return status;
  }
  #endif /* CONFIG_NFS_V4_1 */
  
 -__be32 *nfs4_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry,
 -                         struct nfs_server *server, int plus)
 +/**
 + * nfs4_decode_dirent - Decode a single NFSv4 directory entry stored in
 + *                      the local page cache.
 + * @xdr: XDR stream where entry resides
 + * @entry: buffer to fill in with entry data
 + * @plus: boolean indicating whether this should be a readdirplus entry
 + *
 + * Returns zero if successful, otherwise a negative errno value is
 + * returned.
 + *
 + * This function is not invoked during READDIR reply decoding, but
 + * rather whenever an application invokes the getdents(2) system call
 + * on a directory already in our cache.
 + */
 +int nfs4_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry,
 +                     int plus)
  {
        uint32_t bitmap[2] = {0};
        uint32_t len;
                if (unlikely(!p))
                        goto out_overflow;
                if (!ntohl(*p++))
 -                      return ERR_PTR(-EAGAIN);
 +                      return -EAGAIN;
                entry->eof = 1;
 -              return ERR_PTR(-EBADCOOKIE);
 +              return -EBADCOOKIE;
        }
  
        p = xdr_inline_decode(xdr, 12);
        if (decode_attr_length(xdr, &len, &p) < 0)
                goto out_overflow;
  
 -      if (decode_getfattr_attrs(xdr, bitmap, entry->fattr, entry->fh, server, 1) < 0)
 +      if (decode_getfattr_attrs(xdr, bitmap, entry->fattr, entry->fh,
 +                                      entry->server, 1) < 0)
                goto out_overflow;
        if (entry->fattr->valid & NFS_ATTR_FATTR_FILEID)
                entry->ino = entry->fattr->fileid;
        if (verify_attr_len(xdr, p, len) < 0)
                goto out_overflow;
  
-       p = xdr_inline_peek(xdr, 8);
-       if (p != NULL)
-               entry->eof = !p[0] && p[1];
-       else
-               entry->eof = 0;
 -      return p;
 +      return 0;
  
  out_overflow:
        print_overflow_msg(__func__, xdr);
 -      return ERR_PTR(-EAGAIN);
 +      return -EAGAIN;
  }
  
  /*
@@@ -6221,8 -6295,8 +6215,8 @@@ nfs4_stat_to_errno(int stat
  #define PROC(proc, argtype, restype)                          \
  [NFSPROC4_CLNT_##proc] = {                                    \
        .p_proc   = NFSPROC4_COMPOUND,                          \
 -      .p_encode = (kxdrproc_t) nfs4_xdr_##argtype,            \
 -      .p_decode = (kxdrproc_t) nfs4_xdr_##restype,            \
 +      .p_encode = (kxdreproc_t)nfs4_xdr_##argtype,            \
 +      .p_decode = (kxdrdproc_t)nfs4_xdr_##restype,            \
        .p_arglen = NFS4_##argtype##_sz,                        \
        .p_replen = NFS4_##restype##_sz,                        \
        .p_statidx = NFSPROC4_CLNT_##proc,                      \
  }
  
  struct rpc_procinfo   nfs4_procedures[] = {
 -  PROC(READ,          enc_read,       dec_read),
 -  PROC(WRITE,         enc_write,      dec_write),
 -  PROC(COMMIT,                enc_commit,     dec_commit),
 -  PROC(OPEN,          enc_open,       dec_open),
 -  PROC(OPEN_CONFIRM,  enc_open_confirm,       dec_open_confirm),
 -  PROC(OPEN_NOATTR,   enc_open_noattr,        dec_open_noattr),
 -  PROC(OPEN_DOWNGRADE,        enc_open_downgrade,     dec_open_downgrade),
 -  PROC(CLOSE,         enc_close,      dec_close),
 -  PROC(SETATTR,               enc_setattr,    dec_setattr),
 -  PROC(FSINFO,                enc_fsinfo,     dec_fsinfo),
 -  PROC(RENEW,         enc_renew,      dec_renew),
 -  PROC(SETCLIENTID,   enc_setclientid,        dec_setclientid),
 -  PROC(SETCLIENTID_CONFIRM,   enc_setclientid_confirm,        dec_setclientid_confirm),
 -  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(SYMLINK,               enc_symlink,    dec_symlink),
 -  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),
 -  PROC(DELEGRETURN,   enc_delegreturn, dec_delegreturn),
 -  PROC(GETACL,                enc_getacl,     dec_getacl),
 -  PROC(SETACL,                enc_setacl,     dec_setacl),
 -  PROC(FS_LOCATIONS,  enc_fs_locations, dec_fs_locations),
 -  PROC(RELEASE_LOCKOWNER, enc_release_lockowner, dec_release_lockowner),
 +      PROC(READ,              enc_read,               dec_read),
 +      PROC(WRITE,             enc_write,              dec_write),
 +      PROC(COMMIT,            enc_commit,             dec_commit),
 +      PROC(OPEN,              enc_open,               dec_open),
 +      PROC(OPEN_CONFIRM,      enc_open_confirm,       dec_open_confirm),
 +      PROC(OPEN_NOATTR,       enc_open_noattr,        dec_open_noattr),
 +      PROC(OPEN_DOWNGRADE,    enc_open_downgrade,     dec_open_downgrade),
 +      PROC(CLOSE,             enc_close,              dec_close),
 +      PROC(SETATTR,           enc_setattr,            dec_setattr),
 +      PROC(FSINFO,            enc_fsinfo,             dec_fsinfo),
 +      PROC(RENEW,             enc_renew,              dec_renew),
 +      PROC(SETCLIENTID,       enc_setclientid,        dec_setclientid),
 +      PROC(SETCLIENTID_CONFIRM, enc_setclientid_confirm, dec_setclientid_confirm),
 +      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(SYMLINK,           enc_symlink,            dec_symlink),
 +      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),
 +      PROC(DELEGRETURN,       enc_delegreturn,        dec_delegreturn),
 +      PROC(GETACL,            enc_getacl,             dec_getacl),
 +      PROC(SETACL,            enc_setacl,             dec_setacl),
 +      PROC(FS_LOCATIONS,      enc_fs_locations,       dec_fs_locations),
 +      PROC(RELEASE_LOCKOWNER, enc_release_lockowner,  dec_release_lockowner),
  #if defined(CONFIG_NFS_V4_1)
 -  PROC(EXCHANGE_ID,   enc_exchange_id,        dec_exchange_id),
 -  PROC(CREATE_SESSION,        enc_create_session,     dec_create_session),
 -  PROC(DESTROY_SESSION,       enc_destroy_session,    dec_destroy_session),
 -  PROC(SEQUENCE,      enc_sequence,   dec_sequence),
 -  PROC(GET_LEASE_TIME,        enc_get_lease_time,     dec_get_lease_time),
 -  PROC(RECLAIM_COMPLETE, enc_reclaim_complete,  dec_reclaim_complete),
 -  PROC(GETDEVICEINFO, enc_getdeviceinfo, dec_getdeviceinfo),
 -  PROC(LAYOUTGET,  enc_layoutget,     dec_layoutget),
 +      PROC(EXCHANGE_ID,       enc_exchange_id,        dec_exchange_id),
 +      PROC(CREATE_SESSION,    enc_create_session,     dec_create_session),
 +      PROC(DESTROY_SESSION,   enc_destroy_session,    dec_destroy_session),
 +      PROC(SEQUENCE,          enc_sequence,           dec_sequence),
 +      PROC(GET_LEASE_TIME,    enc_get_lease_time,     dec_get_lease_time),
 +      PROC(RECLAIM_COMPLETE,  enc_reclaim_complete,   dec_reclaim_complete),
 +      PROC(GETDEVICEINFO,     enc_getdeviceinfo,      dec_getdeviceinfo),
 +      PROC(LAYOUTGET,         enc_layoutget,          dec_layoutget),
  #endif /* CONFIG_NFS_V4_1 */
  };
  
@@@ -33,8 -33,8 +33,8 @@@ struct xdr_netobj 
  };
  
  /*
 - * This is the generic XDR function. rqstp is either a rpc_rqst (client
 - * side) or svc_rqst pointer (server side).
 + * This is the legacy generic XDR function. rqstp is either a rpc_rqst
 + * (client side) or svc_rqst pointer (server side).
   * Encode functions always assume there's enough room in the buffer.
   */
  typedef int   (*kxdrproc_t)(void *rqstp, __be32 *data, void *obj);
@@@ -201,20 -201,16 +201,22 @@@ struct xdr_stream 
  
        __be32 *end;            /* end of available buffer space */
        struct kvec *iov;       /* pointer to the current kvec */
+       struct kvec scratch;    /* Scratch buffer */
+       struct page **page_ptr; /* pointer to the current page */
  };
  
 +/*
 + * These are the xdr_stream style generic XDR encode and decode functions.
 + */
 +typedef void  (*kxdreproc_t)(void *rqstp, struct xdr_stream *xdr, void *obj);
 +typedef int   (*kxdrdproc_t)(void *rqstp, struct xdr_stream *xdr, void *obj);
 +
  extern void xdr_init_encode(struct xdr_stream *xdr, struct xdr_buf *buf, __be32 *p);
  extern __be32 *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, __be32 *p);
- extern __be32 *xdr_inline_peek(struct xdr_stream *xdr, size_t nbytes);
+ extern void xdr_set_scratch_buffer(struct xdr_stream *xdr, void *buf, size_t buflen);
  extern __be32 *xdr_inline_decode(struct xdr_stream *xdr, size_t nbytes);
  extern void xdr_read_pages(struct xdr_stream *xdr, unsigned int len);
  extern void xdr_enter_page(struct xdr_stream *xdr, unsigned int len);