fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / fs / nfs / nfs4xdr.c
index a14079f..0cf3fa3 100644 (file)
 #include <linux/nfs4.h>
 #include <linux/nfs_fs.h>
 #include <linux/nfs_idmap.h>
+#include "nfs4_fs.h"
 
 #define NFSDBG_FACILITY                NFSDBG_XDR
 
 /* Mapping from NFS error code to "errno" error code. */
 #define errno_NFSERR_IO                EIO
 
-static int nfs_stat_to_errno(int);
+static int nfs4_stat_to_errno(int);
 
 /* NFSv4 COMPOUND tags are only wanted for debugging purposes */
 #ifdef DEBUG
@@ -82,13 +83,20 @@ static int nfs_stat_to_errno(int);
 #define encode_getfh_maxsz      (op_encode_hdr_maxsz)
 #define decode_getfh_maxsz      (op_decode_hdr_maxsz + 1 + \
                                ((3+NFS4_FHSIZE) >> 2))
-#define encode_getattr_maxsz    (op_encode_hdr_maxsz + 3)
+#define nfs4_fattr_bitmap_maxsz 3
+#define encode_getattr_maxsz    (op_encode_hdr_maxsz + nfs4_fattr_bitmap_maxsz)
 #define nfs4_name_maxsz                (1 + ((3 + NFS4_MAXNAMLEN) >> 2))
-#define nfs4_fattr_bitmap_maxsz (36 + 2 * nfs4_name_maxsz)
-#define decode_getattr_maxsz    (op_decode_hdr_maxsz + 3 + \
-                                nfs4_fattr_bitmap_maxsz)
+#define nfs4_path_maxsz                (1 + ((3 + NFS4_MAXPATHLEN) >> 2))
+/* This is based on getfattr, which uses the most attributes: */
+#define nfs4_fattr_value_maxsz (1 + (1 + 2 + 2 + 4 + 2 + 1 + 1 + 2 + 2 + \
+                               3 + 3 + 3 + 2 * nfs4_name_maxsz))
+#define nfs4_fattr_maxsz       (nfs4_fattr_bitmap_maxsz + \
+                               nfs4_fattr_value_maxsz)
+#define decode_getattr_maxsz    (op_decode_hdr_maxsz + nfs4_fattr_maxsz)
 #define encode_savefh_maxsz     (op_encode_hdr_maxsz)
 #define decode_savefh_maxsz     (op_decode_hdr_maxsz)
+#define encode_restorefh_maxsz  (op_encode_hdr_maxsz)
+#define decode_restorefh_maxsz  (op_decode_hdr_maxsz)
 #define encode_fsinfo_maxsz    (op_encode_hdr_maxsz + 2)
 #define decode_fsinfo_maxsz    (op_decode_hdr_maxsz + 11)
 #define encode_renew_maxsz     (op_encode_hdr_maxsz + 3)
@@ -118,10 +126,17 @@ static int nfs_stat_to_errno(int);
 #define encode_link_maxsz      (op_encode_hdr_maxsz + \
                                nfs4_name_maxsz)
 #define decode_link_maxsz      (op_decode_hdr_maxsz + 5)
+#define encode_symlink_maxsz   (op_encode_hdr_maxsz + \
+                               1 + nfs4_name_maxsz + \
+                               1 + \
+                               nfs4_fattr_maxsz)
+#define decode_symlink_maxsz   (op_decode_hdr_maxsz + 8)
 #define encode_create_maxsz    (op_encode_hdr_maxsz + \
-                               2 + 2 * nfs4_name_maxsz + \
-                               nfs4_fattr_bitmap_maxsz)
+                               2 + nfs4_name_maxsz + \
+                               nfs4_fattr_maxsz)
 #define decode_create_maxsz    (op_decode_hdr_maxsz + 8)
+#define encode_delegreturn_maxsz (op_encode_hdr_maxsz + 4)
+#define decode_delegreturn_maxsz (op_decode_hdr_maxsz)
 #define NFS4_enc_compound_sz   (1024)  /* XXX: large enough? */
 #define NFS4_dec_compound_sz   (1024)  /* XXX: large enough? */
 #define NFS4_enc_read_sz       (compound_encode_hdr_maxsz + \
@@ -144,16 +159,20 @@ static int nfs_stat_to_errno(int);
                                op_decode_hdr_maxsz + 2)
 #define NFS4_enc_write_sz      (compound_encode_hdr_maxsz + \
                                encode_putfh_maxsz + \
-                               op_encode_hdr_maxsz + 8)
+                               op_encode_hdr_maxsz + 8 + \
+                               encode_getattr_maxsz)
 #define NFS4_dec_write_sz      (compound_decode_hdr_maxsz + \
                                decode_putfh_maxsz + \
-                               op_decode_hdr_maxsz + 4)
+                               op_decode_hdr_maxsz + 4 + \
+                               decode_getattr_maxsz)
 #define NFS4_enc_commit_sz     (compound_encode_hdr_maxsz + \
                                encode_putfh_maxsz + \
-                               op_encode_hdr_maxsz + 3)
+                               op_encode_hdr_maxsz + 3 + \
+                               encode_getattr_maxsz)
 #define NFS4_dec_commit_sz     (compound_decode_hdr_maxsz + \
                                decode_putfh_maxsz + \
-                               op_decode_hdr_maxsz + 2)
+                               op_decode_hdr_maxsz + 2 + \
+                               decode_getattr_maxsz)
 #define NFS4_enc_open_sz        (compound_encode_hdr_maxsz + \
                                 encode_putfh_maxsz + \
                                 op_encode_hdr_maxsz + \
@@ -172,34 +191,36 @@ static int nfs_stat_to_errno(int);
 #define NFS4_dec_open_confirm_sz        (compound_decode_hdr_maxsz + \
                                         decode_putfh_maxsz + \
                                         op_decode_hdr_maxsz + 4)
-#define NFS4_enc_open_reclaim_sz       (compound_encode_hdr_maxsz + \
+#define NFS4_enc_open_noattr_sz        (compound_encode_hdr_maxsz + \
                                        encode_putfh_maxsz + \
                                        op_encode_hdr_maxsz + \
-                                       11 + \
-                                       encode_getattr_maxsz)
-#define NFS4_dec_open_reclaim_sz       (compound_decode_hdr_maxsz + \
+                                       11)
+#define NFS4_dec_open_noattr_sz        (compound_decode_hdr_maxsz + \
                                        decode_putfh_maxsz + \
                                        op_decode_hdr_maxsz + \
-                                       4 + 5 + 2 + 3 + \
-                                       decode_getattr_maxsz)
+                                       4 + 5 + 2 + 3)
 #define NFS4_enc_open_downgrade_sz \
                                (compound_encode_hdr_maxsz + \
                                 encode_putfh_maxsz + \
-                                op_encode_hdr_maxsz + 7)
+                                op_encode_hdr_maxsz + 7 + \
+                               encode_getattr_maxsz)
 #define NFS4_dec_open_downgrade_sz \
                                (compound_decode_hdr_maxsz + \
                                 decode_putfh_maxsz + \
-                                op_decode_hdr_maxsz + 4)
+                                op_decode_hdr_maxsz + 4 + \
+                               decode_getattr_maxsz)
 #define NFS4_enc_close_sz       (compound_encode_hdr_maxsz + \
                                 encode_putfh_maxsz + \
-                                op_encode_hdr_maxsz + 5)
+                                op_encode_hdr_maxsz + 5 + \
+                               encode_getattr_maxsz)
 #define NFS4_dec_close_sz       (compound_decode_hdr_maxsz + \
                                 decode_putfh_maxsz + \
-                                op_decode_hdr_maxsz + 4)
+                                op_decode_hdr_maxsz + 4 + \
+                               decode_getattr_maxsz)
 #define NFS4_enc_setattr_sz     (compound_encode_hdr_maxsz + \
                                 encode_putfh_maxsz + \
                                 op_encode_hdr_maxsz + 4 + \
-                                nfs4_fattr_bitmap_maxsz + \
+                                nfs4_fattr_maxsz + \
                                 encode_getattr_maxsz)
 #define NFS4_dec_setattr_sz     (compound_decode_hdr_maxsz + \
                                 decode_putfh_maxsz + \
@@ -289,40 +310,70 @@ static int nfs_stat_to_errno(int);
                                decode_getfh_maxsz)
 #define NFS4_enc_remove_sz     (compound_encode_hdr_maxsz + \
                                encode_putfh_maxsz + \
-                               encode_remove_maxsz)
+                               encode_remove_maxsz + \
+                               encode_getattr_maxsz)
 #define NFS4_dec_remove_sz     (compound_decode_hdr_maxsz + \
                                decode_putfh_maxsz + \
-                               op_decode_hdr_maxsz + 5)
+                               op_decode_hdr_maxsz + 5 + \
+                               decode_getattr_maxsz)
 #define NFS4_enc_rename_sz     (compound_encode_hdr_maxsz + \
                                encode_putfh_maxsz + \
                                encode_savefh_maxsz + \
                                encode_putfh_maxsz + \
-                               encode_rename_maxsz)
+                               encode_rename_maxsz + \
+                               encode_getattr_maxsz + \
+                               encode_restorefh_maxsz + \
+                               encode_getattr_maxsz)
 #define NFS4_dec_rename_sz     (compound_decode_hdr_maxsz + \
                                decode_putfh_maxsz + \
                                decode_savefh_maxsz + \
                                decode_putfh_maxsz + \
-                               decode_rename_maxsz)
+                               decode_rename_maxsz + \
+                               decode_getattr_maxsz + \
+                               decode_restorefh_maxsz + \
+                               decode_getattr_maxsz)
 #define NFS4_enc_link_sz       (compound_encode_hdr_maxsz + \
                                encode_putfh_maxsz + \
                                encode_savefh_maxsz + \
                                encode_putfh_maxsz + \
-                               encode_link_maxsz)
+                               encode_link_maxsz + \
+                               decode_getattr_maxsz + \
+                               encode_restorefh_maxsz + \
+                               decode_getattr_maxsz)
 #define NFS4_dec_link_sz       (compound_decode_hdr_maxsz + \
                                decode_putfh_maxsz + \
                                decode_savefh_maxsz + \
                                decode_putfh_maxsz + \
-                               decode_link_maxsz)
+                               decode_link_maxsz + \
+                               decode_getattr_maxsz + \
+                               decode_restorefh_maxsz + \
+                               decode_getattr_maxsz)
+#define NFS4_enc_symlink_sz    (compound_encode_hdr_maxsz + \
+                               encode_putfh_maxsz + \
+                               encode_symlink_maxsz + \
+                               encode_getattr_maxsz + \
+                               encode_getfh_maxsz)
+#define NFS4_dec_symlink_sz    (compound_decode_hdr_maxsz + \
+                               decode_putfh_maxsz + \
+                               decode_symlink_maxsz + \
+                               decode_getattr_maxsz + \
+                               decode_getfh_maxsz)
 #define NFS4_enc_create_sz     (compound_encode_hdr_maxsz + \
                                encode_putfh_maxsz + \
+                               encode_savefh_maxsz + \
                                encode_create_maxsz + \
+                               encode_getfh_maxsz + \
                                encode_getattr_maxsz + \
-                               encode_getfh_maxsz)
+                               encode_restorefh_maxsz + \
+                               encode_getattr_maxsz)
 #define NFS4_dec_create_sz     (compound_decode_hdr_maxsz + \
                                decode_putfh_maxsz + \
+                               decode_savefh_maxsz + \
                                decode_create_maxsz + \
+                               decode_getfh_maxsz + \
                                decode_getattr_maxsz + \
-                               decode_getfh_maxsz)
+                               decode_restorefh_maxsz + \
+                               decode_getattr_maxsz)
 #define NFS4_enc_pathconf_sz   (compound_encode_hdr_maxsz + \
                                encode_putfh_maxsz + \
                                encode_getattr_maxsz)
@@ -339,6 +390,36 @@ static int nfs_stat_to_errno(int);
                                encode_getattr_maxsz)
 #define NFS4_dec_server_caps_sz (compound_decode_hdr_maxsz + \
                                decode_getattr_maxsz)
+#define NFS4_enc_delegreturn_sz        (compound_encode_hdr_maxsz + \
+                               encode_putfh_maxsz + \
+                               encode_delegreturn_maxsz + \
+                               encode_getattr_maxsz)
+#define NFS4_dec_delegreturn_sz (compound_decode_hdr_maxsz + \
+                               decode_delegreturn_maxsz + \
+                               decode_getattr_maxsz)
+#define NFS4_enc_getacl_sz     (compound_encode_hdr_maxsz + \
+                               encode_putfh_maxsz + \
+                               encode_getattr_maxsz)
+#define NFS4_dec_getacl_sz     (compound_decode_hdr_maxsz + \
+                               decode_putfh_maxsz + \
+                               op_decode_hdr_maxsz + \
+                               nfs4_fattr_bitmap_maxsz + 1)
+#define NFS4_enc_setacl_sz     (compound_encode_hdr_maxsz + \
+                               encode_putfh_maxsz + \
+                               op_encode_hdr_maxsz + 4 + \
+                               nfs4_fattr_bitmap_maxsz + 1)
+#define NFS4_dec_setacl_sz     (compound_decode_hdr_maxsz + \
+                               decode_putfh_maxsz + \
+                               op_decode_hdr_maxsz + nfs4_fattr_bitmap_maxsz)
+#define NFS4_enc_fs_locations_sz \
+                               (compound_encode_hdr_maxsz + \
+                                encode_putfh_maxsz + \
+                                encode_getattr_maxsz)
+#define NFS4_dec_fs_locations_sz \
+                               (compound_decode_hdr_maxsz + \
+                                decode_putfh_maxsz + \
+                                op_decode_hdr_maxsz + \
+                                nfs4_fattr_bitmap_maxsz)
 
 static struct {
        unsigned int    mode;
@@ -388,9 +469,18 @@ struct compound_hdr {
        BUG_ON(!p);                                             \
 } while (0)
 
+static void encode_string(struct xdr_stream *xdr, unsigned int len, const char *str)
+{
+       __be32 *p;
+
+       p = xdr_reserve_space(xdr, 4 + len);
+       BUG_ON(p == NULL);
+       xdr_encode_opaque(p, str, len);
+}
+
 static int encode_compound_hdr(struct xdr_stream *xdr, struct compound_hdr *hdr)
 {
-       uint32_t *p;
+       __be32 *p;
 
        dprintk("encode_compound: tag=%.*s\n", (int)hdr->taglen, hdr->tag);
        BUG_ON(hdr->taglen > NFS4_MAXTAGLEN);
@@ -402,14 +492,23 @@ static int encode_compound_hdr(struct xdr_stream *xdr, struct compound_hdr *hdr)
        return 0;
 }
 
+static void encode_nfs4_verifier(struct xdr_stream *xdr, const nfs4_verifier *verf)
+{
+       __be32 *p;
+
+       p = xdr_reserve_space(xdr, NFS4_VERIFIER_SIZE);
+       BUG_ON(p == NULL);
+       xdr_encode_opaque_fixed(p, verf->data, NFS4_VERIFIER_SIZE);
+}
+
 static int encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const struct nfs_server *server)
 {
        char owner_name[IDMAP_NAMESZ];
        char owner_group[IDMAP_NAMESZ];
        int owner_namelen = 0;
        int owner_grouplen = 0;
-       uint32_t *p;
-       uint32_t *q;
+       __be32 *p;
+       __be32 *q;
        int len;
        uint32_t bmval0 = 0;
        uint32_t bmval1 = 0;
@@ -420,7 +519,7 @@ static int encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const s
         * In the worst-case, this would be
         *   12(bitmap) + 4(attrlen) + 8(size) + 4(mode) + 4(atime) + 4(mtime)
         *          = 36 bytes, plus any contribution from variable-length fields
-        *            such as owner/group/acl's.
+        *            such as owner/group.
         */
        len = 16;
 
@@ -430,7 +529,7 @@ static int encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const s
        if (iap->ia_valid & ATTR_MODE)
                len += 4;
        if (iap->ia_valid & ATTR_UID) {
-               owner_namelen = nfs_map_uid_to_name(server->nfs4_state, iap->ia_uid, owner_name);
+               owner_namelen = nfs_map_uid_to_name(server->nfs_client, iap->ia_uid, owner_name);
                if (owner_namelen < 0) {
                        printk(KERN_WARNING "nfs: couldn't resolve uid %d to string\n",
                               iap->ia_uid);
@@ -442,7 +541,7 @@ static int encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const s
                len += 4 + (XDR_QUADLEN(owner_namelen) << 2);
        }
        if (iap->ia_valid & ATTR_GID) {
-               owner_grouplen = nfs_map_gid_to_group(server->nfs4_state, iap->ia_gid, owner_group);
+               owner_grouplen = nfs_map_gid_to_group(server->nfs_client, iap->ia_gid, owner_group);
                if (owner_grouplen < 0) {
                        printk(KERN_WARNING "nfs4: couldn't resolve gid %d to string\n",
                               iap->ia_gid);
@@ -476,7 +575,7 @@ static int encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const s
        }
        if (iap->ia_valid & ATTR_MODE) {
                bmval1 |= FATTR4_WORD1_MODE;
-               WRITE32(iap->ia_mode);
+               WRITE32(iap->ia_mode & S_IALLUGO);
        }
        if (iap->ia_valid & ATTR_UID) {
                bmval1 |= FATTR4_WORD1_OWNER;
@@ -531,7 +630,7 @@ static int encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const s
 
 static int encode_access(struct xdr_stream *xdr, u32 access)
 {
-       uint32_t *p;
+       __be32 *p;
 
        RESERVE_SPACE(8);
        WRITE32(OP_ACCESS);
@@ -542,19 +641,19 @@ static int encode_access(struct xdr_stream *xdr, u32 access)
 
 static int encode_close(struct xdr_stream *xdr, const struct nfs_closeargs *arg)
 {
-       uint32_t *p;
+       __be32 *p;
 
-       RESERVE_SPACE(8+sizeof(arg->stateid.data));
+       RESERVE_SPACE(8+sizeof(arg->stateid->data));
        WRITE32(OP_CLOSE);
-       WRITE32(arg->seqid);
-       WRITEMEM(arg->stateid.data, sizeof(arg->stateid.data));
+       WRITE32(arg->seqid->sequence->counter);
+       WRITEMEM(arg->stateid->data, sizeof(arg->stateid->data));
        
        return 0;
 }
 
 static int encode_commit(struct xdr_stream *xdr, const struct nfs_writeargs *args)
 {
-       uint32_t *p;
+       __be32 *p;
         
         RESERVE_SPACE(16);
         WRITE32(OP_COMMIT);
@@ -566,7 +665,7 @@ static int encode_commit(struct xdr_stream *xdr, const struct nfs_writeargs *arg
 
 static int encode_create(struct xdr_stream *xdr, const struct nfs4_create_arg *create)
 {
-       uint32_t *p;
+       __be32 *p;
        
        RESERVE_SPACE(8);
        WRITE32(OP_CREATE);
@@ -574,9 +673,9 @@ static int encode_create(struct xdr_stream *xdr, const struct nfs4_create_arg *c
 
        switch (create->ftype) {
        case NF4LNK:
-               RESERVE_SPACE(4 + create->u.symlink->len);
-               WRITE32(create->u.symlink->len);
-               WRITEMEM(create->u.symlink->name, create->u.symlink->len);
+               RESERVE_SPACE(4);
+               WRITE32(create->u.symlink.len);
+               xdr_write_pages(xdr, create->u.symlink.pages, 0, create->u.symlink.len);
                break;
 
        case NF4BLK: case NF4CHR:
@@ -598,7 +697,7 @@ static int encode_create(struct xdr_stream *xdr, const struct nfs4_create_arg *c
 
 static int encode_getattr_one(struct xdr_stream *xdr, uint32_t bitmap)
 {
-        uint32_t *p;
+        __be32 *p;
 
         RESERVE_SPACE(12);
         WRITE32(OP_GETATTR);
@@ -609,7 +708,7 @@ static int encode_getattr_one(struct xdr_stream *xdr, uint32_t bitmap)
 
 static int encode_getattr_two(struct xdr_stream *xdr, uint32_t bm0, uint32_t bm1)
 {
-        uint32_t *p;
+        __be32 *p;
 
         RESERVE_SPACE(16);
         WRITE32(OP_GETATTR);
@@ -621,8 +720,6 @@ static int encode_getattr_two(struct xdr_stream *xdr, uint32_t bm0, uint32_t bm1
 
 static int encode_getfattr(struct xdr_stream *xdr, const u32* bitmask)
 {
-       extern u32 nfs4_fattr_bitmap[];
-
        return encode_getattr_two(xdr,
                        bitmask[0] & nfs4_fattr_bitmap[0],
                        bitmask[1] & nfs4_fattr_bitmap[1]);
@@ -630,15 +727,20 @@ static int encode_getfattr(struct xdr_stream *xdr, const u32* bitmask)
 
 static int encode_fsinfo(struct xdr_stream *xdr, const u32* bitmask)
 {
-       extern u32 nfs4_fsinfo_bitmap[];
-
        return encode_getattr_two(xdr, bitmask[0] & nfs4_fsinfo_bitmap[0],
                        bitmask[1] & nfs4_fsinfo_bitmap[1]);
 }
 
+static int encode_fs_locations(struct xdr_stream *xdr, const u32* bitmask)
+{
+       return encode_getattr_two(xdr,
+                                 bitmask[0] & nfs4_fs_locations_bitmap[0],
+                                 bitmask[1] & nfs4_fs_locations_bitmap[1]);
+}
+
 static int encode_getfh(struct xdr_stream *xdr)
 {
-       uint32_t *p;
+       __be32 *p;
 
        RESERVE_SPACE(4);
        WRITE32(OP_GETFH);
@@ -648,7 +750,7 @@ static int encode_getfh(struct xdr_stream *xdr)
 
 static int encode_link(struct xdr_stream *xdr, const struct qstr *name)
 {
-       uint32_t *p;
+       __be32 *p;
 
        RESERVE_SPACE(8 + name->len);
        WRITE32(OP_LINK);
@@ -658,73 +760,80 @@ static int encode_link(struct xdr_stream *xdr, const struct qstr *name)
        return 0;
 }
 
+static inline int nfs4_lock_type(struct file_lock *fl, int block)
+{
+       if ((fl->fl_type & (F_RDLCK|F_WRLCK|F_UNLCK)) == F_RDLCK)
+               return block ? NFS4_READW_LT : NFS4_READ_LT;
+       return block ? NFS4_WRITEW_LT : NFS4_WRITE_LT;
+}
+
+static inline uint64_t nfs4_lock_length(struct file_lock *fl)
+{
+       if (fl->fl_end == OFFSET_MAX)
+               return ~(uint64_t)0;
+       return fl->fl_end - fl->fl_start + 1;
+}
+
 /*
  * opcode,type,reclaim,offset,length,new_lock_owner = 32
  * open_seqid,open_stateid,lock_seqid,lock_owner.clientid, lock_owner.id = 40
  */
-static int encode_lock(struct xdr_stream *xdr, const struct nfs_lockargs *arg)
+static int encode_lock(struct xdr_stream *xdr, const struct nfs_lock_args *args)
 {
-       uint32_t *p;
-       struct nfs_lock_opargs *opargs = arg->u.lock;
+       __be32 *p;
 
        RESERVE_SPACE(32);
        WRITE32(OP_LOCK);
-       WRITE32(arg->type); 
-       WRITE32(opargs->reclaim);
-       WRITE64(arg->offset);
-       WRITE64(arg->length);
-       WRITE32(opargs->new_lock_owner);
-       if (opargs->new_lock_owner){
-               struct nfs_open_to_lock *ol = opargs->u.open_lock;
-
+       WRITE32(nfs4_lock_type(args->fl, args->block));
+       WRITE32(args->reclaim);
+       WRITE64(args->fl->fl_start);
+       WRITE64(nfs4_lock_length(args->fl));
+       WRITE32(args->new_lock_owner);
+       if (args->new_lock_owner){
                RESERVE_SPACE(40);
-               WRITE32(ol->open_seqid);
-               WRITEMEM(&ol->open_stateid, sizeof(ol->open_stateid));
-               WRITE32(ol->lock_seqid);
-               WRITE64(ol->lock_owner.clientid);
+               WRITE32(args->open_seqid->sequence->counter);
+               WRITEMEM(args->open_stateid->data, sizeof(args->open_stateid->data));
+               WRITE32(args->lock_seqid->sequence->counter);
+               WRITE64(args->lock_owner.clientid);
                WRITE32(4);
-               WRITE32(ol->lock_owner.id);
+               WRITE32(args->lock_owner.id);
        }
        else {
-               struct nfs_exist_lock *el = opargs->u.exist_lock;
-
                RESERVE_SPACE(20);
-               WRITEMEM(&el->stateid, sizeof(el->stateid));
-               WRITE32(el->seqid);
+               WRITEMEM(args->lock_stateid->data, sizeof(args->lock_stateid->data));
+               WRITE32(args->lock_seqid->sequence->counter);
        }
 
        return 0;
 }
 
-static int encode_lockt(struct xdr_stream *xdr, const struct nfs_lockargs *arg)
+static int encode_lockt(struct xdr_stream *xdr, const struct nfs_lockt_args *args)
 {
-       uint32_t *p;
-       struct nfs_lowner *opargs = arg->u.lockt;
+       __be32 *p;
 
        RESERVE_SPACE(40);
        WRITE32(OP_LOCKT);
-       WRITE32(arg->type);
-       WRITE64(arg->offset);
-       WRITE64(arg->length);
-       WRITE64(opargs->clientid);
+       WRITE32(nfs4_lock_type(args->fl, 0));
+       WRITE64(args->fl->fl_start);
+       WRITE64(nfs4_lock_length(args->fl));
+       WRITE64(args->lock_owner.clientid);
        WRITE32(4);
-       WRITE32(opargs->id);
+       WRITE32(args->lock_owner.id);
 
        return 0;
 }
 
-static int encode_locku(struct xdr_stream *xdr, const struct nfs_lockargs *arg)
+static int encode_locku(struct xdr_stream *xdr, const struct nfs_locku_args *args)
 {
-       uint32_t *p;
-       struct nfs_locku_opargs *opargs = arg->u.locku;
+       __be32 *p;
 
        RESERVE_SPACE(44);
        WRITE32(OP_LOCKU);
-       WRITE32(arg->type);
-       WRITE32(opargs->seqid);
-       WRITEMEM(&opargs->stateid, sizeof(opargs->stateid));
-       WRITE64(arg->offset);
-       WRITE64(arg->length);
+       WRITE32(nfs4_lock_type(args->fl, 0));
+       WRITE32(args->seqid->sequence->counter);
+       WRITEMEM(args->stateid->data, sizeof(args->stateid->data));
+       WRITE64(args->fl->fl_start);
+       WRITE64(nfs4_lock_length(args->fl));
 
        return 0;
 }
@@ -732,7 +841,7 @@ static int encode_locku(struct xdr_stream *xdr, const struct nfs_lockargs *arg)
 static int encode_lookup(struct xdr_stream *xdr, const struct qstr *name)
 {
        int len = name->len;
-       uint32_t *p;
+       __be32 *p;
 
        RESERVE_SPACE(8 + len);
        WRITE32(OP_LOOKUP);
@@ -742,19 +851,12 @@ static int encode_lookup(struct xdr_stream *xdr, const struct qstr *name)
        return 0;
 }
 
-static int encode_open(struct xdr_stream *xdr, const struct nfs_openargs *arg)
+static void encode_share_access(struct xdr_stream *xdr, int open_flags)
 {
-       int status;
-       uint32_t *p;
+       __be32 *p;
 
- /*
- * opcode 4, seqid 4, share_access 4, share_deny 4, clientid 8, ownerlen 4,
- * owner 4, opentype 4 = 36
- */
-       RESERVE_SPACE(36);
-       WRITE32(OP_OPEN);
-       WRITE32(arg->seqid);
-       switch (arg->share_access) {
+       RESERVE_SPACE(8);
+       switch (open_flags & (FMODE_READ|FMODE_WRITE)) {
                case FMODE_READ:
                        WRITE32(NFS4_SHARE_ACCESS_READ);
                        break;
@@ -767,99 +869,147 @@ static int encode_open(struct xdr_stream *xdr, const struct nfs_openargs *arg)
                default:
                        BUG();
        }
-       WRITE32(0);                  /* for linux, share_deny = 0 always */
+       WRITE32(0);             /* for linux, share_deny = 0 always */
+}
+
+static inline void encode_openhdr(struct xdr_stream *xdr, const struct nfs_openargs *arg)
+{
+       __be32 *p;
+ /*
+ * opcode 4, seqid 4, share_access 4, share_deny 4, clientid 8, ownerlen 4,
+ * owner 4 = 32
+ */
+       RESERVE_SPACE(8);
+       WRITE32(OP_OPEN);
+       WRITE32(arg->seqid->sequence->counter);
+       encode_share_access(xdr, arg->open_flags);
+       RESERVE_SPACE(16);
        WRITE64(arg->clientid);
        WRITE32(4);
        WRITE32(arg->id);
-       WRITE32(arg->opentype);
+}
 
-       if (arg->opentype == NFS4_OPEN_CREATE) {
-               if (arg->createmode == NFS4_CREATE_EXCLUSIVE) {
-                       RESERVE_SPACE(12);
-                       WRITE32(arg->createmode);
-                       WRITEMEM(arg->u.verifier.data, sizeof(arg->u.verifier.data));
-               }
-               else if (arg->u.attrs) {
-                       RESERVE_SPACE(4);
-                       WRITE32(arg->createmode);
-                       if ((status = encode_attrs(xdr, arg->u.attrs, arg->server)))
-                               return status;
-               }
-               else {
-                       RESERVE_SPACE(12);
-                       WRITE32(arg->createmode);
-                       WRITE32(0);
-                       WRITE32(0);
-               }
+static inline void encode_createmode(struct xdr_stream *xdr, const struct nfs_openargs *arg)
+{
+       __be32 *p;
+
+       RESERVE_SPACE(4);
+       switch(arg->open_flags & O_EXCL) {
+               case 0:
+                       WRITE32(NFS4_CREATE_UNCHECKED);
+                       encode_attrs(xdr, arg->u.attrs, arg->server);
+                       break;
+               default:
+                       WRITE32(NFS4_CREATE_EXCLUSIVE);
+                       encode_nfs4_verifier(xdr, &arg->u.verifier);
        }
+}
 
-       RESERVE_SPACE(8 + arg->name->len);
-       WRITE32(NFS4_OPEN_CLAIM_NULL);
-       WRITE32(arg->name->len);
-       WRITEMEM(arg->name->name, arg->name->len);
+static void encode_opentype(struct xdr_stream *xdr, const struct nfs_openargs *arg)
+{
+       __be32 *p;
 
-       return 0;
+       RESERVE_SPACE(4);
+       switch (arg->open_flags & O_CREAT) {
+               case 0:
+                       WRITE32(NFS4_OPEN_NOCREATE);
+                       break;
+               default:
+                       BUG_ON(arg->claim != NFS4_OPEN_CLAIM_NULL);
+                       WRITE32(NFS4_OPEN_CREATE);
+                       encode_createmode(xdr, arg);
+       }
 }
 
-static int encode_open_confirm(struct xdr_stream *xdr, const struct nfs_open_confirmargs *arg)
+static inline void encode_delegation_type(struct xdr_stream *xdr, int delegation_type)
 {
-       uint32_t *p;
+       __be32 *p;
 
-       RESERVE_SPACE(8+sizeof(arg->stateid.data));
-       WRITE32(OP_OPEN_CONFIRM);
-       WRITEMEM(arg->stateid.data, sizeof(arg->stateid.data));
-       WRITE32(arg->seqid);
+       RESERVE_SPACE(4);
+       switch (delegation_type) {
+               case 0:
+                       WRITE32(NFS4_OPEN_DELEGATE_NONE);
+                       break;
+               case FMODE_READ:
+                       WRITE32(NFS4_OPEN_DELEGATE_READ);
+                       break;
+               case FMODE_WRITE|FMODE_READ:
+                       WRITE32(NFS4_OPEN_DELEGATE_WRITE);
+                       break;
+               default:
+                       BUG();
+       }
+}
 
-       return 0;
+static inline void encode_claim_null(struct xdr_stream *xdr, const struct qstr *name)
+{
+       __be32 *p;
+
+       RESERVE_SPACE(4);
+       WRITE32(NFS4_OPEN_CLAIM_NULL);
+       encode_string(xdr, name->len, name->name);
 }
 
+static inline void encode_claim_previous(struct xdr_stream *xdr, int type)
+{
+       __be32 *p;
+
+       RESERVE_SPACE(4);
+       WRITE32(NFS4_OPEN_CLAIM_PREVIOUS);
+       encode_delegation_type(xdr, type);
+}
 
-static int encode_open_reclaim(struct xdr_stream *xdr, const struct nfs_open_reclaimargs *arg)
+static inline void encode_claim_delegate_cur(struct xdr_stream *xdr, const struct qstr *name, const nfs4_stateid *stateid)
 {
-       uint32_t *p;
+       __be32 *p;
 
- /*
- * opcode 4, seqid 4, share_access 4, share_deny 4, clientid 8, ownerlen 4,
- * owner 4, opentype 4, claim 4, delegation_type 4 = 44
- */
-       RESERVE_SPACE(44);
-       WRITE32(OP_OPEN);
-       WRITE32(arg->seqid);
-       switch (arg->share_access) {
-               case FMODE_READ:
-                       WRITE32(NFS4_SHARE_ACCESS_READ);
+       RESERVE_SPACE(4+sizeof(stateid->data));
+       WRITE32(NFS4_OPEN_CLAIM_DELEGATE_CUR);
+       WRITEMEM(stateid->data, sizeof(stateid->data));
+       encode_string(xdr, name->len, name->name);
+}
+
+static int encode_open(struct xdr_stream *xdr, const struct nfs_openargs *arg)
+{
+       encode_openhdr(xdr, arg);
+       encode_opentype(xdr, arg);
+       switch (arg->claim) {
+               case NFS4_OPEN_CLAIM_NULL:
+                       encode_claim_null(xdr, arg->name);
                        break;
-               case FMODE_WRITE:
-                       WRITE32(NFS4_SHARE_ACCESS_WRITE);
+               case NFS4_OPEN_CLAIM_PREVIOUS:
+                       encode_claim_previous(xdr, arg->u.delegation_type);
                        break;
-               case FMODE_READ|FMODE_WRITE:
-                       WRITE32(NFS4_SHARE_ACCESS_BOTH);
+               case NFS4_OPEN_CLAIM_DELEGATE_CUR:
+                       encode_claim_delegate_cur(xdr, arg->name, &arg->u.delegation);
                        break;
                default:
                        BUG();
        }
-       WRITE32(0);                  /* for linux, share_deny = 0 always */
-       WRITE64(arg->clientid);
-       WRITE32(4);
-       WRITE32(arg->id);
-       WRITE32(NFS4_OPEN_NOCREATE);
-       WRITE32(NFS4_OPEN_CLAIM_PREVIOUS);
-       WRITE32(NFS4_OPEN_DELEGATE_NONE);
+       return 0;
+}
+
+static int encode_open_confirm(struct xdr_stream *xdr, const struct nfs_open_confirmargs *arg)
+{
+       __be32 *p;
+
+       RESERVE_SPACE(8+sizeof(arg->stateid->data));
+       WRITE32(OP_OPEN_CONFIRM);
+       WRITEMEM(arg->stateid->data, sizeof(arg->stateid->data));
+       WRITE32(arg->seqid->sequence->counter);
+
        return 0;
 }
 
 static int encode_open_downgrade(struct xdr_stream *xdr, const struct nfs_closeargs *arg)
 {
-       uint32_t *p;
+       __be32 *p;
 
-       RESERVE_SPACE(16+sizeof(arg->stateid.data));
+       RESERVE_SPACE(8+sizeof(arg->stateid->data));
        WRITE32(OP_OPEN_DOWNGRADE);
-       WRITEMEM(arg->stateid.data, sizeof(arg->stateid.data));
-       WRITE32(arg->seqid);
-       WRITE32(arg->share_access);
-       /* No deny modes */
-       WRITE32(0);
-
+       WRITEMEM(arg->stateid->data, sizeof(arg->stateid->data));
+       WRITE32(arg->seqid->sequence->counter);
+       encode_share_access(xdr, arg->open_flags);
        return 0;
 }
 
@@ -867,7 +1017,7 @@ static int
 encode_putfh(struct xdr_stream *xdr, const struct nfs_fh *fh)
 {
        int len = fh->size;
-       uint32_t *p;
+       __be32 *p;
 
        RESERVE_SPACE(8 + len);
        WRITE32(OP_PUTFH);
@@ -879,7 +1029,7 @@ encode_putfh(struct xdr_stream *xdr, const struct nfs_fh *fh)
 
 static int encode_putrootfh(struct xdr_stream *xdr)
 {
-        uint32_t *p;
+        __be32 *p;
         
         RESERVE_SPACE(4);
         WRITE32(OP_PUTROOTFH);
@@ -887,15 +1037,14 @@ static int encode_putrootfh(struct xdr_stream *xdr)
         return 0;
 }
 
-static void encode_stateid(struct xdr_stream *xdr, struct nfs4_state *state, fl_owner_t lockowner)
+static void encode_stateid(struct xdr_stream *xdr, const struct nfs_open_context *ctx)
 {
-       extern nfs4_stateid zero_stateid;
        nfs4_stateid stateid;
-       uint32_t *p;
+       __be32 *p;
 
        RESERVE_SPACE(16);
-       if (state != NULL) {
-               nfs4_copy_stateid(&stateid, state, lockowner);
+       if (ctx->state != NULL) {
+               nfs4_copy_stateid(&stateid, ctx->state, ctx->lockowner);
                WRITEMEM(stateid.data, sizeof(stateid.data));
        } else
                WRITEMEM(zero_stateid.data, sizeof(zero_stateid.data));
@@ -903,12 +1052,12 @@ static void encode_stateid(struct xdr_stream *xdr, struct nfs4_state *state, fl_
 
 static int encode_read(struct xdr_stream *xdr, const struct nfs_readargs *args)
 {
-       uint32_t *p;
+       __be32 *p;
 
        RESERVE_SPACE(4);
        WRITE32(OP_READ);
 
-       encode_stateid(xdr, args->state, args->lockowner);
+       encode_stateid(xdr, args->context);
 
        RESERVE_SPACE(12);
        WRITE64(args->offset);
@@ -920,18 +1069,34 @@ static int encode_read(struct xdr_stream *xdr, const struct nfs_readargs *args)
 static int encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg *readdir, struct rpc_rqst *req)
 {
        struct rpc_auth *auth = req->rq_task->tk_auth;
+       uint32_t attrs[2] = {
+               FATTR4_WORD0_RDATTR_ERROR|FATTR4_WORD0_FILEID,
+               FATTR4_WORD1_MOUNTED_ON_FILEID,
+       };
        int replen;
-       uint32_t *p;
+       __be32 *p;
 
        RESERVE_SPACE(32+sizeof(nfs4_verifier));
        WRITE32(OP_READDIR);
        WRITE64(readdir->cookie);
        WRITEMEM(readdir->verifier.data, sizeof(readdir->verifier.data));
-       WRITE32(readdir->count >> 5);  /* meaningless "dircount" field */
+       WRITE32(readdir->count >> 1);  /* We're not doing readdirplus */
        WRITE32(readdir->count);
        WRITE32(2);
-       WRITE32(FATTR4_WORD0_FILEID);
-       WRITE32(0);
+       /* Switch to mounted_on_fileid if the server supports it */
+       if (readdir->bitmask[1] & FATTR4_WORD1_MOUNTED_ON_FILEID)
+               attrs[0] &= ~FATTR4_WORD0_FILEID;
+       else
+               attrs[1] &= ~FATTR4_WORD1_MOUNTED_ON_FILEID;
+       WRITE32(attrs[0] & readdir->bitmask[0]);
+       WRITE32(attrs[1] & readdir->bitmask[1]);
+       dprintk("%s: cookie = %Lu, verifier = 0x%x%x, bitmap = 0x%x%x\n",
+                       __FUNCTION__,
+                       (unsigned long long)readdir->cookie,
+                       ((u32 *)readdir->verifier.data)[0],
+                       ((u32 *)readdir->verifier.data)[1],
+                       attrs[0] & readdir->bitmask[0],
+                       attrs[1] & readdir->bitmask[1]);
 
        /* set up reply kvec
         *    toplevel_status + taglen + rescount + OP_PUTFH + status
@@ -940,6 +1105,9 @@ static int encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg
        replen = (RPC_REPHDRSIZE + auth->au_rslack + 9) << 2;
        xdr_inline_pages(&req->rq_rcv_buf, replen, readdir->pages,
                         readdir->pgbase, readdir->count);
+       dprintk("%s: inlined page args = (%u, %p, %u, %u)\n",
+                       __FUNCTION__, replen, readdir->pages,
+                       readdir->pgbase, readdir->count);
 
        return 0;
 }
@@ -947,26 +1115,26 @@ static int encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg
 static int encode_readlink(struct xdr_stream *xdr, const struct nfs4_readlink *readlink, struct rpc_rqst *req)
 {
        struct rpc_auth *auth = req->rq_task->tk_auth;
-       unsigned int count = readlink->count - 5;
        unsigned int replen;
-       uint32_t *p;
+       __be32 *p;
 
        RESERVE_SPACE(4);
        WRITE32(OP_READLINK);
 
        /* set up reply kvec
         *    toplevel_status + taglen + rescount + OP_PUTFH + status
-        *      + OP_READLINK + status  = 7
+        *      + OP_READLINK + status + string length = 8
         */
-       replen = (RPC_REPHDRSIZE + auth->au_rslack + 7) << 2;
-       xdr_inline_pages(&req->rq_rcv_buf, replen, readlink->pages, 0, count);
+       replen = (RPC_REPHDRSIZE + auth->au_rslack + 8) << 2;
+       xdr_inline_pages(&req->rq_rcv_buf, replen, readlink->pages,
+                       readlink->pgbase, readlink->pglen);
        
        return 0;
 }
 
 static int encode_remove(struct xdr_stream *xdr, const struct qstr *name)
 {
-       uint32_t *p;
+       __be32 *p;
 
        RESERVE_SPACE(8 + name->len);
        WRITE32(OP_REMOVE);
@@ -978,7 +1146,7 @@ static int encode_remove(struct xdr_stream *xdr, const struct qstr *name)
 
 static int encode_rename(struct xdr_stream *xdr, const struct qstr *oldname, const struct qstr *newname)
 {
-       uint32_t *p;
+       __be32 *p;
 
        RESERVE_SPACE(8 + oldname->len);
        WRITE32(OP_RENAME);
@@ -992,9 +1160,9 @@ static int encode_rename(struct xdr_stream *xdr, const struct qstr *oldname, con
        return 0;
 }
 
-static int encode_renew(struct xdr_stream *xdr, const struct nfs4_client *client_stateid)
+static int encode_renew(struct xdr_stream *xdr, const struct nfs_client *client_stateid)
 {
-       uint32_t *p;
+       __be32 *p;
 
        RESERVE_SPACE(12);
        WRITE32(OP_RENEW);
@@ -1003,10 +1171,40 @@ static int encode_renew(struct xdr_stream *xdr, const struct nfs4_client *client
        return 0;
 }
 
+static int
+encode_restorefh(struct xdr_stream *xdr)
+{
+       __be32 *p;
+
+       RESERVE_SPACE(4);
+       WRITE32(OP_RESTOREFH);
+
+       return 0;
+}
+
+static int
+encode_setacl(struct xdr_stream *xdr, struct nfs_setaclargs *arg)
+{
+       __be32 *p;
+
+       RESERVE_SPACE(4+sizeof(zero_stateid.data));
+       WRITE32(OP_SETATTR);
+       WRITEMEM(zero_stateid.data, sizeof(zero_stateid.data));
+       RESERVE_SPACE(2*4);
+       WRITE32(1);
+       WRITE32(FATTR4_WORD0_ACL);
+       if (arg->acl_len % 4)
+               return -EINVAL;
+       RESERVE_SPACE(4);
+       WRITE32(arg->acl_len);
+       xdr_write_pages(xdr, arg->acl_pages, arg->acl_pgbase, arg->acl_len);
+       return 0;
+}
+
 static int
 encode_savefh(struct xdr_stream *xdr)
 {
-       uint32_t *p;
+       __be32 *p;
 
        RESERVE_SPACE(4);
        WRITE32(OP_SAVEFH);
@@ -1017,7 +1215,7 @@ encode_savefh(struct xdr_stream *xdr)
 static int encode_setattr(struct xdr_stream *xdr, const struct nfs_setattrargs *arg, const struct nfs_server *server)
 {
        int status;
-       uint32_t *p;
+       __be32 *p;
        
         RESERVE_SPACE(4+sizeof(arg->stateid.data));
         WRITE32(OP_SETATTR);
@@ -1031,34 +1229,26 @@ static int encode_setattr(struct xdr_stream *xdr, const struct nfs_setattrargs *
 
 static int encode_setclientid(struct xdr_stream *xdr, const struct nfs4_setclientid *setclientid)
 {
-       uint32_t total_len;
-       uint32_t len1, len2, len3;
-       uint32_t *p;
-
-       len1 = strlen(setclientid->sc_name);
-       len2 = strlen(setclientid->sc_netid);
-       len3 = strlen(setclientid->sc_uaddr);
-       total_len = XDR_QUADLEN(len1) + XDR_QUADLEN(len2) + XDR_QUADLEN(len3);
-       total_len = (total_len << 2) + 24 + sizeof(setclientid->sc_verifier.data);
+       __be32 *p;
 
-       RESERVE_SPACE(total_len);
+       RESERVE_SPACE(4 + sizeof(setclientid->sc_verifier->data));
        WRITE32(OP_SETCLIENTID);
-       WRITEMEM(setclientid->sc_verifier.data, sizeof(setclientid->sc_verifier.data));
-       WRITE32(len1);
-       WRITEMEM(setclientid->sc_name, len1);
+       WRITEMEM(setclientid->sc_verifier->data, sizeof(setclientid->sc_verifier->data));
+
+       encode_string(xdr, setclientid->sc_name_len, setclientid->sc_name);
+       RESERVE_SPACE(4);
        WRITE32(setclientid->sc_prog);
-       WRITE32(len2);
-       WRITEMEM(setclientid->sc_netid, len2);
-       WRITE32(len3);
-       WRITEMEM(setclientid->sc_uaddr, len3);
+       encode_string(xdr, setclientid->sc_netid_len, setclientid->sc_netid);
+       encode_string(xdr, setclientid->sc_uaddr_len, setclientid->sc_uaddr);
+       RESERVE_SPACE(4);
        WRITE32(setclientid->sc_cb_ident);
 
        return 0;
 }
 
-static int encode_setclientid_confirm(struct xdr_stream *xdr, const struct nfs4_client *client_state)
+static int encode_setclientid_confirm(struct xdr_stream *xdr, const struct nfs_client *client_state)
 {
-        uint32_t *p;
+        __be32 *p;
 
         RESERVE_SPACE(12 + sizeof(client_state->cl_confirm.data));
         WRITE32(OP_SETCLIENTID_CONFIRM);
@@ -1070,12 +1260,12 @@ static int encode_setclientid_confirm(struct xdr_stream *xdr, const struct nfs4_
 
 static int encode_write(struct xdr_stream *xdr, const struct nfs_writeargs *args)
 {
-       uint32_t *p;
+       __be32 *p;
 
        RESERVE_SPACE(4);
        WRITE32(OP_WRITE);
 
-       encode_stateid(xdr, args->state, args->lockowner);
+       encode_stateid(xdr, args->context);
 
        RESERVE_SPACE(16);
        WRITE64(args->offset);
@@ -1086,6 +1276,18 @@ static int encode_write(struct xdr_stream *xdr, const struct nfs_writeargs *args
 
        return 0;
 }
+
+static int encode_delegreturn(struct xdr_stream *xdr, const nfs4_stateid *stateid)
+{
+       __be32 *p;
+
+       RESERVE_SPACE(20);
+
+       WRITE32(OP_DELEGRETURN);
+       WRITEMEM(stateid->data, sizeof(stateid->data));
+       return 0;
+
+}
 /*
  * END OF "GENERIC" ENCODE ROUTINES.
  */
@@ -1093,7 +1295,7 @@ static int encode_write(struct xdr_stream *xdr, const struct nfs_writeargs *args
 /*
  * Encode an ACCESS request
  */
-static int nfs4_xdr_enc_access(struct rpc_rqst *req, uint32_t *p, const struct nfs4_accessargs *args)
+static int nfs4_xdr_enc_access(struct rpc_rqst *req, __be32 *p, const struct nfs4_accessargs *args)
 {
        struct xdr_stream xdr;
        struct compound_hdr hdr = {
@@ -1111,7 +1313,7 @@ static int nfs4_xdr_enc_access(struct rpc_rqst *req, uint32_t *p, const struct n
 /*
  * Encode LOOKUP request
  */
-static int nfs4_xdr_enc_lookup(struct rpc_rqst *req, uint32_t *p, const struct nfs4_lookup_arg *args)
+static int nfs4_xdr_enc_lookup(struct rpc_rqst *req, __be32 *p, const struct nfs4_lookup_arg *args)
 {
        struct xdr_stream xdr;
        struct compound_hdr hdr = {
@@ -1135,7 +1337,7 @@ out:
 /*
  * Encode LOOKUP_ROOT request
  */
-static int nfs4_xdr_enc_lookup_root(struct rpc_rqst *req, uint32_t *p, const struct nfs4_lookup_root_arg *args)
+static int nfs4_xdr_enc_lookup_root(struct rpc_rqst *req, __be32 *p, const struct nfs4_lookup_root_arg *args)
 {
        struct xdr_stream xdr;
        struct compound_hdr hdr = {
@@ -1156,29 +1358,33 @@ out:
 /*
  * Encode REMOVE request
  */
-static int nfs4_xdr_enc_remove(struct rpc_rqst *req, uint32_t *p, const struct nfs4_remove_arg *args)
+static int nfs4_xdr_enc_remove(struct rpc_rqst *req, __be32 *p, const struct nfs4_remove_arg *args)
 {
        struct xdr_stream xdr;
        struct compound_hdr hdr = {
-               .nops = 2,
+               .nops = 3,
        };
        int status;
 
        xdr_init_encode(&xdr, &req->rq_snd_buf, p);
        encode_compound_hdr(&xdr, &hdr);
-       if ((status = encode_putfh(&xdr, args->fh)) == 0)
-               status = encode_remove(&xdr, args->name);
+       if ((status = encode_putfh(&xdr, args->fh)) != 0)
+               goto out;
+       if ((status = encode_remove(&xdr, args->name)) != 0)
+               goto out;
+       status = encode_getfattr(&xdr, args->bitmask);
+out:
        return status;
 }
 
 /*
  * Encode RENAME request
  */
-static int nfs4_xdr_enc_rename(struct rpc_rqst *req, uint32_t *p, const struct nfs4_rename_arg *args)
+static int nfs4_xdr_enc_rename(struct rpc_rqst *req, __be32 *p, const struct nfs4_rename_arg *args)
 {
        struct xdr_stream xdr;
        struct compound_hdr hdr = {
-               .nops = 4,
+               .nops = 7,
        };
        int status;
 
@@ -1190,7 +1396,13 @@ static int nfs4_xdr_enc_rename(struct rpc_rqst *req, uint32_t *p, const struct n
                goto out;
        if ((status = encode_putfh(&xdr, args->new_dir)) != 0)
                goto out;
-       status = encode_rename(&xdr, args->old_name, args->new_name);
+       if ((status = encode_rename(&xdr, args->old_name, args->new_name)) != 0)
+               goto out;
+       if ((status = encode_getfattr(&xdr, args->bitmask)) != 0)
+               goto out;
+       if ((status = encode_restorefh(&xdr)) != 0)
+               goto out;
+       status = encode_getfattr(&xdr, args->bitmask);
 out:
        return status;
 }
@@ -1198,11 +1410,11 @@ out:
 /*
  * Encode LINK request
  */
-static int nfs4_xdr_enc_link(struct rpc_rqst *req, uint32_t *p, const struct nfs4_link_arg *args)
+static int nfs4_xdr_enc_link(struct rpc_rqst *req, __be32 *p, const struct nfs4_link_arg *args)
 {
        struct xdr_stream xdr;
        struct compound_hdr hdr = {
-               .nops = 4,
+               .nops = 7,
        };
        int status;
 
@@ -1214,7 +1426,13 @@ static int nfs4_xdr_enc_link(struct rpc_rqst *req, uint32_t *p, const struct nfs
                goto out;
        if ((status = encode_putfh(&xdr, args->dir_fh)) != 0)
                goto out;
-       status = encode_link(&xdr, args->name);
+       if ((status = encode_link(&xdr, args->name)) != 0)
+               goto out;
+       if ((status = encode_getfattr(&xdr, args->bitmask)) != 0)
+               goto out;
+       if ((status = encode_restorefh(&xdr)) != 0)
+               goto out;
+       status = encode_getfattr(&xdr, args->bitmask);
 out:
        return status;
 }
@@ -1222,11 +1440,11 @@ out:
 /*
  * Encode CREATE request
  */
-static int nfs4_xdr_enc_create(struct rpc_rqst *req, uint32_t *p, const struct nfs4_create_arg *args)
+static int nfs4_xdr_enc_create(struct rpc_rqst *req, __be32 *p, const struct nfs4_create_arg *args)
 {
        struct xdr_stream xdr;
        struct compound_hdr hdr = {
-               .nops = 4,
+               .nops = 7,
        };
        int status;
 
@@ -1234,19 +1452,33 @@ static int nfs4_xdr_enc_create(struct rpc_rqst *req, uint32_t *p, const struct n
        encode_compound_hdr(&xdr, &hdr);
        if ((status = encode_putfh(&xdr, args->dir_fh)) != 0)
                goto out;
+       if ((status = encode_savefh(&xdr)) != 0)
+               goto out;
        if ((status = encode_create(&xdr, args)) != 0)
                goto out;
+       if ((status = encode_getfh(&xdr)) != 0)
+               goto out;
        if ((status = encode_getfattr(&xdr, args->bitmask)) != 0)
                goto out;
-       status = encode_getfh(&xdr);
+       if ((status = encode_restorefh(&xdr)) != 0)
+               goto out;
+       status = encode_getfattr(&xdr, args->bitmask);
 out:
        return status;
 }
 
+/*
+ * Encode SYMLINK request
+ */
+static int nfs4_xdr_enc_symlink(struct rpc_rqst *req, __be32 *p, const struct nfs4_create_arg *args)
+{
+       return nfs4_xdr_enc_create(req, p, args);
+}
+
 /*
  * Encode GETATTR request
  */
-static int nfs4_xdr_enc_getattr(struct rpc_rqst *req, uint32_t *p, const struct nfs4_getattr_arg *args)
+static int nfs4_xdr_enc_getattr(struct rpc_rqst *req, __be32 *p, const struct nfs4_getattr_arg *args)
 {
        struct xdr_stream xdr;
        struct compound_hdr hdr = {
@@ -1264,11 +1496,11 @@ static int nfs4_xdr_enc_getattr(struct rpc_rqst *req, uint32_t *p, const struct
 /*
  * Encode a CLOSE request
  */
-static int nfs4_xdr_enc_close(struct rpc_rqst *req, uint32_t *p, struct nfs_closeargs *args)
+static int nfs4_xdr_enc_close(struct rpc_rqst *req, __be32 *p, struct nfs_closeargs *args)
 {
         struct xdr_stream xdr;
         struct compound_hdr hdr = {
-                .nops   = 2,
+                .nops   = 3,
         };
         int status;
 
@@ -1278,6 +1510,9 @@ static int nfs4_xdr_enc_close(struct rpc_rqst *req, uint32_t *p, struct nfs_clos
         if(status)
                 goto out;
         status = encode_close(&xdr, args);
+       if (status != 0)
+               goto out;
+       status = encode_getfattr(&xdr, args->bitmask);
 out:
         return status;
 }
@@ -1285,26 +1520,35 @@ out:
 /*
  * Encode an OPEN request
  */
-static int nfs4_xdr_enc_open(struct rpc_rqst *req, uint32_t *p, struct nfs_openargs *args)
+static int nfs4_xdr_enc_open(struct rpc_rqst *req, __be32 *p, struct nfs_openargs *args)
 {
        struct xdr_stream xdr;
        struct compound_hdr hdr = {
-               .nops = 4,
+               .nops = 7,
        };
        int status;
 
        xdr_init_encode(&xdr, &req->rq_snd_buf, p);
        encode_compound_hdr(&xdr, &hdr);
        status = encode_putfh(&xdr, args->fh);
+       if (status)
+               goto out;
+       status = encode_savefh(&xdr);
        if (status)
                goto out;
        status = encode_open(&xdr, args);
+       if (status)
+               goto out;
+       status = encode_getfh(&xdr);
        if (status)
                goto out;
        status = encode_getfattr(&xdr, args->bitmask);
        if (status)
                goto out;
-       status = encode_getfh(&xdr);
+       status = encode_restorefh(&xdr);
+       if (status)
+               goto out;
+       status = encode_getfattr(&xdr, args->bitmask);
 out:
        return status;
 }
@@ -1312,7 +1556,7 @@ out:
 /*
  * Encode an OPEN_CONFIRM request
  */
-static int nfs4_xdr_enc_open_confirm(struct rpc_rqst *req, uint32_t *p, struct nfs_open_confirmargs *args)
+static int nfs4_xdr_enc_open_confirm(struct rpc_rqst *req, __be32 *p, struct nfs_open_confirmargs *args)
 {
        struct xdr_stream xdr;
        struct compound_hdr hdr = {
@@ -1331,9 +1575,9 @@ out:
 }
 
 /*
- * Encode an OPEN request
+ * Encode an OPEN request with no attributes.
  */
-static int nfs4_xdr_enc_open_reclaim(struct rpc_rqst *req, uint32_t *p, struct nfs_open_reclaimargs *args)
+static int nfs4_xdr_enc_open_noattr(struct rpc_rqst *req, __be32 *p, struct nfs_openargs *args)
 {
        struct xdr_stream xdr;
        struct compound_hdr hdr = {
@@ -1346,7 +1590,7 @@ static int nfs4_xdr_enc_open_reclaim(struct rpc_rqst *req, uint32_t *p, struct n
        status = encode_putfh(&xdr, args->fh);
        if (status)
                goto out;
-       status = encode_open_reclaim(&xdr, args);
+       status = encode_open(&xdr, args);
        if (status)
                goto out;
        status = encode_getfattr(&xdr, args->bitmask);
@@ -1357,11 +1601,11 @@ out:
 /*
  * Encode an OPEN_DOWNGRADE request
  */
-static int nfs4_xdr_enc_open_downgrade(struct rpc_rqst *req, uint32_t *p, struct nfs_closeargs *args)
+static int nfs4_xdr_enc_open_downgrade(struct rpc_rqst *req, __be32 *p, struct nfs_closeargs *args)
 {
        struct xdr_stream xdr;
        struct compound_hdr hdr = {
-               .nops   = 2,
+               .nops   = 3,
        };
        int status;
 
@@ -1371,6 +1615,9 @@ static int nfs4_xdr_enc_open_downgrade(struct rpc_rqst *req, uint32_t *p, struct
        if (status)
                goto out;
        status = encode_open_downgrade(&xdr, args);
+       if (status != 0)
+               goto out;
+       status = encode_getfattr(&xdr, args->bitmask);
 out:
        return status;
 }
@@ -1378,7 +1625,7 @@ out:
 /*
  * Encode a LOCK request
  */
-static int nfs4_xdr_enc_lock(struct rpc_rqst *req, uint32_t *p, struct nfs_lockargs *args)
+static int nfs4_xdr_enc_lock(struct rpc_rqst *req, __be32 *p, struct nfs_lock_args *args)
 {
        struct xdr_stream xdr;
        struct compound_hdr hdr = {
@@ -1399,7 +1646,7 @@ out:
 /*
  * Encode a LOCKT request
  */
-static int nfs4_xdr_enc_lockt(struct rpc_rqst *req, uint32_t *p, struct nfs_lockargs *args)
+static int nfs4_xdr_enc_lockt(struct rpc_rqst *req, __be32 *p, struct nfs_lockt_args *args)
 {
        struct xdr_stream xdr;
        struct compound_hdr hdr = {
@@ -1420,7 +1667,7 @@ out:
 /*
  * Encode a LOCKU request
  */
-static int nfs4_xdr_enc_locku(struct rpc_rqst *req, uint32_t *p, struct nfs_lockargs *args)
+static int nfs4_xdr_enc_locku(struct rpc_rqst *req, __be32 *p, struct nfs_locku_args *args)
 {
        struct xdr_stream xdr;
        struct compound_hdr hdr = {
@@ -1441,7 +1688,7 @@ out:
 /*
  * Encode a READLINK request
  */
-static int nfs4_xdr_enc_readlink(struct rpc_rqst *req, uint32_t *p, const struct nfs4_readlink *args)
+static int nfs4_xdr_enc_readlink(struct rpc_rqst *req, __be32 *p, const struct nfs4_readlink *args)
 {
        struct xdr_stream xdr;
        struct compound_hdr hdr = {
@@ -1462,7 +1709,7 @@ out:
 /*
  * Encode a READDIR request
  */
-static int nfs4_xdr_enc_readdir(struct rpc_rqst *req, uint32_t *p, const struct nfs4_readdir_arg *args)
+static int nfs4_xdr_enc_readdir(struct rpc_rqst *req, __be32 *p, const struct nfs4_readdir_arg *args)
 {
        struct xdr_stream xdr;
        struct compound_hdr hdr = {
@@ -1483,7 +1730,7 @@ out:
 /*
  * Encode a READ request
  */
-static int nfs4_xdr_enc_read(struct rpc_rqst *req, uint32_t *p, struct nfs_readargs *args)
+static int nfs4_xdr_enc_read(struct rpc_rqst *req, __be32 *p, struct nfs_readargs *args)
 {
        struct rpc_auth *auth = req->rq_task->tk_auth;
        struct xdr_stream xdr;
@@ -1515,7 +1762,7 @@ out:
 /*
  * Encode an SETATTR request
  */
-static int nfs4_xdr_enc_setattr(struct rpc_rqst *req, uint32_t *p, struct nfs_setattrargs *args)
+static int nfs4_xdr_enc_setattr(struct rpc_rqst *req, __be32 *p, struct nfs_setattrargs *args)
 
 {
         struct xdr_stream xdr;
@@ -1537,14 +1784,42 @@ out:
         return status;
 }
 
+/*
+ * Encode a GETACL request
+ */
+static int
+nfs4_xdr_enc_getacl(struct rpc_rqst *req, __be32 *p,
+               struct nfs_getaclargs *args)
+{
+       struct xdr_stream xdr;
+       struct rpc_auth *auth = req->rq_task->tk_auth;
+       struct compound_hdr hdr = {
+               .nops   = 2,
+       };
+       int replen, status;
+
+       xdr_init_encode(&xdr, &req->rq_snd_buf, p);
+       encode_compound_hdr(&xdr, &hdr);
+       status = encode_putfh(&xdr, args->fh);
+       if (status)
+               goto out;
+       status = encode_getattr_two(&xdr, FATTR4_WORD0_ACL, 0);
+       /* set up reply buffer: */
+       replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS4_dec_getacl_sz) << 2;
+       xdr_inline_pages(&req->rq_rcv_buf, replen,
+               args->acl_pages, args->acl_pgbase, args->acl_len);
+out:
+       return status;
+}
+
 /*
  * Encode a WRITE request
  */
-static int nfs4_xdr_enc_write(struct rpc_rqst *req, uint32_t *p, struct nfs_writeargs *args)
+static int nfs4_xdr_enc_write(struct rpc_rqst *req, __be32 *p, struct nfs_writeargs *args)
 {
        struct xdr_stream xdr;
        struct compound_hdr hdr = {
-               .nops = 2,
+               .nops = 3,
        };
        int status;
 
@@ -1554,6 +1829,9 @@ static int nfs4_xdr_enc_write(struct rpc_rqst *req, uint32_t *p, struct nfs_writ
        if (status)
                goto out;
        status = encode_write(&xdr, args);
+       if (status)
+               goto out;
+       status = encode_getfattr(&xdr, args->bitmask);
 out:
        return status;
 }
@@ -1561,11 +1839,11 @@ out:
 /*
  *  a COMMIT request
  */
-static int nfs4_xdr_enc_commit(struct rpc_rqst *req, uint32_t *p, struct nfs_writeargs *args)
+static int nfs4_xdr_enc_commit(struct rpc_rqst *req, __be32 *p, struct nfs_writeargs *args)
 {
        struct xdr_stream xdr;
        struct compound_hdr hdr = {
-               .nops = 2,
+               .nops = 3,
        };
        int status;
 
@@ -1575,6 +1853,9 @@ static int nfs4_xdr_enc_commit(struct rpc_rqst *req, uint32_t *p, struct nfs_wri
        if (status)
                goto out;
        status = encode_commit(&xdr, args);
+       if (status)
+               goto out;
+       status = encode_getfattr(&xdr, args->bitmask);
 out:
        return status;
 }
@@ -1582,7 +1863,7 @@ out:
 /*
  * FSINFO request
  */
-static int nfs4_xdr_enc_fsinfo(struct rpc_rqst *req, uint32_t *p, struct nfs4_fsinfo_arg *args)
+static int nfs4_xdr_enc_fsinfo(struct rpc_rqst *req, __be32 *p, struct nfs4_fsinfo_arg *args)
 {
        struct xdr_stream xdr;
        struct compound_hdr hdr = {
@@ -1601,9 +1882,8 @@ static int nfs4_xdr_enc_fsinfo(struct rpc_rqst *req, uint32_t *p, struct nfs4_fs
 /*
  * a PATHCONF request
  */
-static int nfs4_xdr_enc_pathconf(struct rpc_rqst *req, uint32_t *p, const struct nfs4_pathconf_arg *args)
+static int nfs4_xdr_enc_pathconf(struct rpc_rqst *req, __be32 *p, const struct nfs4_pathconf_arg *args)
 {
-       extern u32 nfs4_pathconf_bitmap[2];
        struct xdr_stream xdr;
        struct compound_hdr hdr = {
                .nops = 2,
@@ -1622,9 +1902,8 @@ static int nfs4_xdr_enc_pathconf(struct rpc_rqst *req, uint32_t *p, const struct
 /*
  * a STATFS request
  */
-static int nfs4_xdr_enc_statfs(struct rpc_rqst *req, uint32_t *p, const struct nfs4_statfs_arg *args)
+static int nfs4_xdr_enc_statfs(struct rpc_rqst *req, __be32 *p, const struct nfs4_statfs_arg *args)
 {
-       extern u32 nfs4_statfs_bitmap[];
        struct xdr_stream xdr;
        struct compound_hdr hdr = {
                .nops = 2,
@@ -1644,7 +1923,7 @@ static int nfs4_xdr_enc_statfs(struct rpc_rqst *req, uint32_t *p, const struct n
 /*
  * GETATTR_BITMAP request
  */
-static int nfs4_xdr_enc_server_caps(struct rpc_rqst *req, uint32_t *p, const struct nfs_fh *fhandle)
+static int nfs4_xdr_enc_server_caps(struct rpc_rqst *req, __be32 *p, const struct nfs_fh *fhandle)
 {
        struct xdr_stream xdr;
        struct compound_hdr hdr = {
@@ -1666,7 +1945,7 @@ static int nfs4_xdr_enc_server_caps(struct rpc_rqst *req, uint32_t *p, const str
 /*
  * a RENEW request
  */
-static int nfs4_xdr_enc_renew(struct rpc_rqst *req, uint32_t *p, struct nfs4_client *clp)
+static int nfs4_xdr_enc_renew(struct rpc_rqst *req, __be32 *p, struct nfs_client *clp)
 {
        struct xdr_stream xdr;
        struct compound_hdr hdr = {
@@ -1681,7 +1960,7 @@ static int nfs4_xdr_enc_renew(struct rpc_rqst *req, uint32_t *p, struct nfs4_cli
 /*
  * a SETCLIENTID request
  */
-static int nfs4_xdr_enc_setclientid(struct rpc_rqst *req, uint32_t *p, struct nfs4_setclientid *sc)
+static int nfs4_xdr_enc_setclientid(struct rpc_rqst *req, __be32 *p, struct nfs4_setclientid *sc)
 {
        struct xdr_stream xdr;
        struct compound_hdr hdr = {
@@ -1696,7 +1975,7 @@ static int nfs4_xdr_enc_setclientid(struct rpc_rqst *req, uint32_t *p, struct nf
 /*
  * a SETCLIENTID_CONFIRM request
  */
-static int nfs4_xdr_enc_setclientid_confirm(struct rpc_rqst *req, uint32_t *p, struct nfs4_client *clp)
+static int nfs4_xdr_enc_setclientid_confirm(struct rpc_rqst *req, __be32 *p, struct nfs_client *clp)
 {
        struct xdr_stream xdr;
        struct compound_hdr hdr = {
@@ -1715,6 +1994,62 @@ static int nfs4_xdr_enc_setclientid_confirm(struct rpc_rqst *req, uint32_t *p, s
        return status;
 }
 
+/*
+ * DELEGRETURN request
+ */
+static int nfs4_xdr_enc_delegreturn(struct rpc_rqst *req, __be32 *p, const struct nfs4_delegreturnargs *args)
+{
+       struct xdr_stream xdr;
+       struct compound_hdr hdr = {
+               .nops = 3,
+       };
+       int status;
+
+       xdr_init_encode(&xdr, &req->rq_snd_buf, p);
+       encode_compound_hdr(&xdr, &hdr);
+       status = encode_putfh(&xdr, args->fhandle);
+       if (status != 0)
+               goto out;
+       status = encode_delegreturn(&xdr, args->stateid);
+       if (status != 0)
+               goto out;
+       status = encode_getfattr(&xdr, args->bitmask);
+out:
+       return status;
+}
+
+/*
+ * Encode FS_LOCATIONS request
+ */
+static int nfs4_xdr_enc_fs_locations(struct rpc_rqst *req, __be32 *p, struct nfs4_fs_locations_arg *args)
+{
+       struct xdr_stream xdr;
+       struct compound_hdr hdr = {
+               .nops = 3,
+       };
+       struct rpc_auth *auth = req->rq_task->tk_auth;
+       int replen;
+       int status;
+
+       xdr_init_encode(&xdr, &req->rq_snd_buf, p);
+       encode_compound_hdr(&xdr, &hdr);
+       if ((status = encode_putfh(&xdr, args->dir_fh)) != 0)
+               goto out;
+       if ((status = encode_lookup(&xdr, args->name)) != 0)
+               goto out;
+       if ((status = encode_fs_locations(&xdr, args->bitmask)) != 0)
+               goto out;
+       /* set up reply
+        *   toplevel_status + OP_PUTFH + status
+        *   + OP_LOOKUP + status + OP_GETATTR + status = 7
+        */
+       replen = (RPC_REPHDRSIZE + auth->au_rslack + 7) << 2;
+       xdr_inline_pages(&req->rq_rcv_buf, replen, &args->page,
+                       0, PAGE_SIZE);
+out:
+       return status;
+}
+
 /*
  * START OF "GENERIC" DECODE ROUTINES.
  *   These may look a little ugly since they are imported from a "generic"
@@ -1749,9 +2084,20 @@ static int nfs4_xdr_enc_setclientid_confirm(struct rpc_rqst *req, uint32_t *p, s
        } \
 } while (0)
 
+static int decode_opaque_inline(struct xdr_stream *xdr, unsigned int *len, char **string)
+{
+       __be32 *p;
+
+       READ_BUF(4);
+       READ32(*len);
+       READ_BUF(*len);
+       *string = (char *)p;
+       return 0;
+}
+
 static int decode_compound_hdr(struct xdr_stream *xdr, struct compound_hdr *hdr)
 {
-       uint32_t *p;
+       __be32 *p;
 
        READ_BUF(8);
        READ32(hdr->status);
@@ -1766,7 +2112,7 @@ static int decode_compound_hdr(struct xdr_stream *xdr, struct compound_hdr *hdr)
 
 static int decode_op_hdr(struct xdr_stream *xdr, enum nfs_opnum4 expected)
 {
-       uint32_t *p;
+       __be32 *p;
        uint32_t opnum;
        int32_t nfserr;
 
@@ -1781,13 +2127,25 @@ static int decode_op_hdr(struct xdr_stream *xdr, enum nfs_opnum4 expected)
        }
        READ32(nfserr);
        if (nfserr != NFS_OK)
-               return -nfs_stat_to_errno(nfserr);
+               return -nfs4_stat_to_errno(nfserr);
        return 0;
 }
 
+/* Dummy routine */
+static int decode_ace(struct xdr_stream *xdr, void *ace, struct nfs_client *clp)
+{
+       __be32 *p;
+       unsigned int strlen;
+       char *str;
+
+       READ_BUF(12);
+       return decode_opaque_inline(xdr, &strlen, &str);
+}
+
 static int decode_attr_bitmap(struct xdr_stream *xdr, uint32_t *bitmap)
 {
-       uint32_t bmlen, *p;
+       uint32_t bmlen;
+       __be32 *p;
 
        READ_BUF(4);
        READ32(bmlen);
@@ -1802,9 +2160,9 @@ static int decode_attr_bitmap(struct xdr_stream *xdr, uint32_t *bitmap)
        return 0;
 }
 
-static inline int decode_attr_length(struct xdr_stream *xdr, uint32_t *attrlen, uint32_t **savep)
+static inline int decode_attr_length(struct xdr_stream *xdr, uint32_t *attrlen, __be32 **savep)
 {
-       uint32_t *p;
+       __be32 *p;
 
        READ_BUF(4);
        READ32(*attrlen);
@@ -1825,7 +2183,7 @@ static int decode_attr_supported(struct xdr_stream *xdr, uint32_t *bitmap, uint3
 
 static int decode_attr_type(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *type)
 {
-       uint32_t *p;
+       __be32 *p;
 
        *type = 0;
        if (unlikely(bitmap[0] & (FATTR4_WORD0_TYPE - 1U)))
@@ -1845,7 +2203,7 @@ static int decode_attr_type(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *
 
 static int decode_attr_change(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *change)
 {
-       uint32_t *p;
+       __be32 *p;
 
        *change = 0;
        if (unlikely(bitmap[0] & (FATTR4_WORD0_CHANGE - 1U)))
@@ -1862,7 +2220,7 @@ static int decode_attr_change(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t
 
 static int decode_attr_size(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *size)
 {
-       uint32_t *p;
+       __be32 *p;
 
        *size = 0;
        if (unlikely(bitmap[0] & (FATTR4_WORD0_SIZE - 1U)))
@@ -1878,7 +2236,7 @@ static int decode_attr_size(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *
 
 static int decode_attr_link_support(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res)
 {
-       uint32_t *p;
+       __be32 *p;
 
        *res = 0;
        if (unlikely(bitmap[0] & (FATTR4_WORD0_LINK_SUPPORT - 1U)))
@@ -1894,7 +2252,7 @@ static int decode_attr_link_support(struct xdr_stream *xdr, uint32_t *bitmap, ui
 
 static int decode_attr_symlink_support(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res)
 {
-       uint32_t *p;
+       __be32 *p;
 
        *res = 0;
        if (unlikely(bitmap[0] & (FATTR4_WORD0_SYMLINK_SUPPORT - 1U)))
@@ -1908,9 +2266,9 @@ static int decode_attr_symlink_support(struct xdr_stream *xdr, uint32_t *bitmap,
        return 0;
 }
 
-static int decode_attr_fsid(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs4_fsid *fsid)
+static int decode_attr_fsid(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs_fsid *fsid)
 {
-       uint32_t *p;
+       __be32 *p;
 
        fsid->major = 0;
        fsid->minor = 0;
@@ -1930,7 +2288,7 @@ static int decode_attr_fsid(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs
 
 static int decode_attr_lease_time(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res)
 {
-       uint32_t *p;
+       __be32 *p;
 
        *res = 60;
        if (unlikely(bitmap[0] & (FATTR4_WORD0_LEASE_TIME - 1U)))
@@ -1946,7 +2304,7 @@ static int decode_attr_lease_time(struct xdr_stream *xdr, uint32_t *bitmap, uint
 
 static int decode_attr_aclsupport(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res)
 {
-       uint32_t *p;
+       __be32 *p;
 
        *res = ACL4_SUPPORT_ALLOW_ACL|ACL4_SUPPORT_DENY_ACL;
        if (unlikely(bitmap[0] & (FATTR4_WORD0_ACLSUPPORT - 1U)))
@@ -1956,21 +2314,37 @@ static int decode_attr_aclsupport(struct xdr_stream *xdr, uint32_t *bitmap, uint
                READ32(*res);
                bitmap[0] &= ~FATTR4_WORD0_ACLSUPPORT;
        }
-       dprintk("%s: ACLs supported=%u\n", __FUNCTION__, (unsigned int)*res);
+       dprintk("%s: ACLs supported=%u\n", __FUNCTION__, (unsigned int)*res);
+       return 0;
+}
+
+static int decode_attr_fileid(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *fileid)
+{
+       __be32 *p;
+
+       *fileid = 0;
+       if (unlikely(bitmap[0] & (FATTR4_WORD0_FILEID - 1U)))
+               return -EIO;
+       if (likely(bitmap[0] & FATTR4_WORD0_FILEID)) {
+               READ_BUF(8);
+               READ64(*fileid);
+               bitmap[0] &= ~FATTR4_WORD0_FILEID;
+       }
+       dprintk("%s: fileid=%Lu\n", __FUNCTION__, (unsigned long long)*fileid);
        return 0;
 }
 
-static int decode_attr_fileid(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *fileid)
+static int decode_attr_mounted_on_fileid(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *fileid)
 {
-       uint32_t *p;
+       __be32 *p;
 
        *fileid = 0;
-       if (unlikely(bitmap[0] & (FATTR4_WORD0_FILEID - 1U)))
+       if (unlikely(bitmap[1] & (FATTR4_WORD1_MOUNTED_ON_FILEID - 1U)))
                return -EIO;
-       if (likely(bitmap[0] & FATTR4_WORD0_FILEID)) {
+       if (likely(bitmap[1] & FATTR4_WORD1_MOUNTED_ON_FILEID)) {
                READ_BUF(8);
                READ64(*fileid);
-               bitmap[0] &= ~FATTR4_WORD0_FILEID;
+               bitmap[1] &= ~FATTR4_WORD1_MOUNTED_ON_FILEID;
        }
        dprintk("%s: fileid=%Lu\n", __FUNCTION__, (unsigned long long)*fileid);
        return 0;
@@ -1978,7 +2352,7 @@ static int decode_attr_fileid(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t
 
 static int decode_attr_files_avail(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res)
 {
-       uint32_t *p;
+       __be32 *p;
        int status = 0;
 
        *res = 0;
@@ -1995,7 +2369,7 @@ static int decode_attr_files_avail(struct xdr_stream *xdr, uint32_t *bitmap, uin
 
 static int decode_attr_files_free(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res)
 {
-       uint32_t *p;
+       __be32 *p;
        int status = 0;
 
        *res = 0;
@@ -2012,7 +2386,7 @@ static int decode_attr_files_free(struct xdr_stream *xdr, uint32_t *bitmap, uint
 
 static int decode_attr_files_total(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res)
 {
-       uint32_t *p;
+       __be32 *p;
        int status = 0;
 
        *res = 0;
@@ -2027,9 +2401,119 @@ static int decode_attr_files_total(struct xdr_stream *xdr, uint32_t *bitmap, uin
        return status;
 }
 
+static int decode_pathname(struct xdr_stream *xdr, struct nfs4_pathname *path)
+{
+       int n;
+       __be32 *p;
+       int status = 0;
+
+       READ_BUF(4);
+       READ32(n);
+       if (n < 0)
+               goto out_eio;
+       if (n == 0)
+               goto root_path;
+       dprintk("path ");
+       path->ncomponents = 0;
+       while (path->ncomponents < n) {
+               struct nfs4_string *component = &path->components[path->ncomponents];
+               status = decode_opaque_inline(xdr, &component->len, &component->data);
+               if (unlikely(status != 0))
+                       goto out_eio;
+               if (path->ncomponents != n)
+                       dprintk("/");
+               dprintk("%s", component->data);
+               if (path->ncomponents < NFS4_PATHNAME_MAXCOMPONENTS)
+                       path->ncomponents++;
+               else {
+                       dprintk("cannot parse %d components in path\n", n);
+                       goto out_eio;
+               }
+       }
+out:
+       dprintk("\n");
+       return status;
+root_path:
+/* a root pathname is sent as a zero component4 */
+       path->ncomponents = 1;
+       path->components[0].len=0;
+       path->components[0].data=NULL;
+       dprintk("path /\n");
+       goto out;
+out_eio:
+       dprintk(" status %d", status);
+       status = -EIO;
+       goto out;
+}
+
+static int decode_attr_fs_locations(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs4_fs_locations *res)
+{
+       int n;
+       __be32 *p;
+       int status = -EIO;
+
+       if (unlikely(bitmap[0] & (FATTR4_WORD0_FS_LOCATIONS -1U)))
+               goto out;
+       status = 0;
+       if (unlikely(!(bitmap[0] & FATTR4_WORD0_FS_LOCATIONS)))
+               goto out;
+       dprintk("%s: fsroot ", __FUNCTION__);
+       status = decode_pathname(xdr, &res->fs_path);
+       if (unlikely(status != 0))
+               goto out;
+       READ_BUF(4);
+       READ32(n);
+       if (n <= 0)
+               goto out_eio;
+       res->nlocations = 0;
+       while (res->nlocations < n) {
+               int m;
+               struct nfs4_fs_location *loc = &res->locations[res->nlocations];
+
+               READ_BUF(4);
+               READ32(m);
+               if (m <= 0)
+                       goto out_eio;
+
+               loc->nservers = 0;
+               dprintk("%s: servers ", __FUNCTION__);
+               while (loc->nservers < m) {
+                       struct nfs4_string *server = &loc->servers[loc->nservers];
+                       status = decode_opaque_inline(xdr, &server->len, &server->data);
+                       if (unlikely(status != 0))
+                               goto out_eio;
+                       dprintk("%s ", server->data);
+                       if (loc->nservers < NFS4_FS_LOCATION_MAXSERVERS)
+                               loc->nservers++;
+                       else {
+                               int i;
+                               dprintk("%s: using first %d of %d servers returned for location %d\n", __FUNCTION__, NFS4_FS_LOCATION_MAXSERVERS, m, res->nlocations);
+                               for (i = loc->nservers; i < m; i++) {
+                                       int len;
+                                       char *data;
+                                       status = decode_opaque_inline(xdr, &len, &data);
+                                       if (unlikely(status != 0))
+                                               goto out_eio;
+                               }
+                       }
+               }
+               status = decode_pathname(xdr, &loc->rootpath);
+               if (unlikely(status != 0))
+                       goto out_eio;
+               if (res->nlocations < NFS4_FS_LOCATIONS_MAXENTRIES)
+                       res->nlocations++;
+       }
+out:
+       dprintk("%s: fs_locations done, error = %d\n", __FUNCTION__, status);
+       return status;
+out_eio:
+       status = -EIO;
+       goto out;
+}
+
 static int decode_attr_maxfilesize(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res)
 {
-       uint32_t *p;
+       __be32 *p;
        int status = 0;
 
        *res = 0;
@@ -2046,7 +2530,7 @@ static int decode_attr_maxfilesize(struct xdr_stream *xdr, uint32_t *bitmap, uin
 
 static int decode_attr_maxlink(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *maxlink)
 {
-       uint32_t *p;
+       __be32 *p;
        int status = 0;
 
        *maxlink = 1;
@@ -2063,7 +2547,7 @@ static int decode_attr_maxlink(struct xdr_stream *xdr, uint32_t *bitmap, uint32_
 
 static int decode_attr_maxname(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *maxname)
 {
-       uint32_t *p;
+       __be32 *p;
        int status = 0;
 
        *maxname = 1024;
@@ -2080,7 +2564,7 @@ static int decode_attr_maxname(struct xdr_stream *xdr, uint32_t *bitmap, uint32_
 
 static int decode_attr_maxread(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res)
 {
-       uint32_t *p;
+       __be32 *p;
        int status = 0;
 
        *res = 1024;
@@ -2101,7 +2585,7 @@ static int decode_attr_maxread(struct xdr_stream *xdr, uint32_t *bitmap, uint32_
 
 static int decode_attr_maxwrite(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res)
 {
-       uint32_t *p;
+       __be32 *p;
        int status = 0;
 
        *res = 1024;
@@ -2122,7 +2606,7 @@ static int decode_attr_maxwrite(struct xdr_stream *xdr, uint32_t *bitmap, uint32
 
 static int decode_attr_mode(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *mode)
 {
-       uint32_t *p;
+       __be32 *p;
 
        *mode = 0;
        if (unlikely(bitmap[1] & (FATTR4_WORD1_MODE - 1U)))
@@ -2139,7 +2623,7 @@ static int decode_attr_mode(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *
 
 static int decode_attr_nlink(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *nlink)
 {
-       uint32_t *p;
+       __be32 *p;
 
        *nlink = 1;
        if (unlikely(bitmap[1] & (FATTR4_WORD1_NUMLINKS - 1U)))
@@ -2153,9 +2637,10 @@ static int decode_attr_nlink(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t
        return 0;
 }
 
-static int decode_attr_owner(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs4_client *clp, int32_t *uid)
+static int decode_attr_owner(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs_client *clp, int32_t *uid)
 {
-       uint32_t len, *p;
+       uint32_t len;
+       __be32 *p;
 
        *uid = -2;
        if (unlikely(bitmap[1] & (FATTR4_WORD1_OWNER - 1U)))
@@ -2177,9 +2662,10 @@ static int decode_attr_owner(struct xdr_stream *xdr, uint32_t *bitmap, struct nf
        return 0;
 }
 
-static int decode_attr_group(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs4_client *clp, int32_t *gid)
+static int decode_attr_group(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs_client *clp, int32_t *gid)
 {
-       uint32_t len, *p;
+       uint32_t len;
+       __be32 *p;
 
        *gid = -2;
        if (unlikely(bitmap[1] & (FATTR4_WORD1_OWNER_GROUP - 1U)))
@@ -2203,7 +2689,8 @@ static int decode_attr_group(struct xdr_stream *xdr, uint32_t *bitmap, struct nf
 
 static int decode_attr_rdev(struct xdr_stream *xdr, uint32_t *bitmap, dev_t *rdev)
 {
-       uint32_t major = 0, minor = 0, *p;
+       uint32_t major = 0, minor = 0;
+       __be32 *p;
 
        *rdev = MKDEV(0,0);
        if (unlikely(bitmap[1] & (FATTR4_WORD1_RAWDEV - 1U)))
@@ -2225,7 +2712,7 @@ static int decode_attr_rdev(struct xdr_stream *xdr, uint32_t *bitmap, dev_t *rde
 
 static int decode_attr_space_avail(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res)
 {
-       uint32_t *p;
+       __be32 *p;
        int status = 0;
 
        *res = 0;
@@ -2242,7 +2729,7 @@ static int decode_attr_space_avail(struct xdr_stream *xdr, uint32_t *bitmap, uin
 
 static int decode_attr_space_free(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res)
 {
-       uint32_t *p;
+       __be32 *p;
        int status = 0;
 
        *res = 0;
@@ -2259,7 +2746,7 @@ static int decode_attr_space_free(struct xdr_stream *xdr, uint32_t *bitmap, uint
 
 static int decode_attr_space_total(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res)
 {
-       uint32_t *p;
+       __be32 *p;
        int status = 0;
 
        *res = 0;
@@ -2276,7 +2763,7 @@ static int decode_attr_space_total(struct xdr_stream *xdr, uint32_t *bitmap, uin
 
 static int decode_attr_space_used(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *used)
 {
-       uint32_t *p;
+       __be32 *p;
 
        *used = 0;
        if (unlikely(bitmap[1] & (FATTR4_WORD1_SPACE_USED - 1U)))
@@ -2293,7 +2780,7 @@ static int decode_attr_space_used(struct xdr_stream *xdr, uint32_t *bitmap, uint
 
 static int decode_attr_time(struct xdr_stream *xdr, struct timespec *time)
 {
-       uint32_t *p;
+       __be32 *p;
        uint64_t sec;
        uint32_t nsec;
 
@@ -2353,7 +2840,7 @@ static int decode_attr_time_modify(struct xdr_stream *xdr, uint32_t *bitmap, str
        return status;
 }
 
-static int verify_attr_len(struct xdr_stream *xdr, uint32_t *savep, uint32_t attrlen)
+static int verify_attr_len(struct xdr_stream *xdr, __be32 *savep, uint32_t attrlen)
 {
        unsigned int attrwords = XDR_QUADLEN(attrlen);
        unsigned int nwords = xdr->p - savep;
@@ -2371,7 +2858,7 @@ static int verify_attr_len(struct xdr_stream *xdr, uint32_t *savep, uint32_t att
 
 static int decode_change_info(struct xdr_stream *xdr, struct nfs4_change_info *cinfo)
 {
-       uint32_t *p;
+       __be32 *p;
 
        READ_BUF(20);
        READ32(cinfo->atomic);
@@ -2382,7 +2869,7 @@ static int decode_change_info(struct xdr_stream *xdr, struct nfs4_change_info *c
 
 static int decode_access(struct xdr_stream *xdr, struct nfs4_accessres *access)
 {
-       uint32_t *p;
+       __be32 *p;
        uint32_t supp, acc;
        int status;
 
@@ -2399,7 +2886,7 @@ static int decode_access(struct xdr_stream *xdr, struct nfs4_accessres *access)
 
 static int decode_close(struct xdr_stream *xdr, struct nfs_closeres *res)
 {
-       uint32_t *p;
+       __be32 *p;
        int status;
 
        status = decode_op_hdr(xdr, OP_CLOSE);
@@ -2412,7 +2899,7 @@ static int decode_close(struct xdr_stream *xdr, struct nfs_closeres *res)
 
 static int decode_commit(struct xdr_stream *xdr, struct nfs_writeres *res)
 {
-       uint32_t *p;
+       __be32 *p;
        int status;
 
        status = decode_op_hdr(xdr, OP_COMMIT);
@@ -2425,7 +2912,7 @@ static int decode_commit(struct xdr_stream *xdr, struct nfs_writeres *res)
 
 static int decode_create(struct xdr_stream *xdr, struct nfs4_change_info *cinfo)
 {
-       uint32_t *p;
+       __be32 *p;
        uint32_t bmlen;
        int status;
 
@@ -2442,7 +2929,7 @@ static int decode_create(struct xdr_stream *xdr, struct nfs4_change_info *cinfo)
 
 static int decode_server_caps(struct xdr_stream *xdr, struct nfs4_server_caps_res *res)
 {
-       uint32_t *savep;
+       __be32 *savep;
        uint32_t attrlen, 
                 bitmap[2] = {0};
        int status;
@@ -2463,14 +2950,13 @@ static int decode_server_caps(struct xdr_stream *xdr, struct nfs4_server_caps_re
                goto xdr_error;
        status = verify_attr_len(xdr, savep, attrlen);
 xdr_error:
-       if (status != 0)
-               printk(KERN_NOTICE "%s: xdr error %d!\n", __FUNCTION__, -status);
+       dprintk("%s: xdr returned %d!\n", __FUNCTION__, -status);
        return status;
 }
        
 static int decode_statfs(struct xdr_stream *xdr, struct nfs_fsstat *fsstat)
 {
-       uint32_t *savep;
+       __be32 *savep;
        uint32_t attrlen, 
                 bitmap[2] = {0};
        int status;
@@ -2497,14 +2983,13 @@ static int decode_statfs(struct xdr_stream *xdr, struct nfs_fsstat *fsstat)
 
        status = verify_attr_len(xdr, savep, attrlen);
 xdr_error:
-       if (status != 0)
-               printk(KERN_NOTICE "%s: xdr error %d!\n", __FUNCTION__, -status);
+       dprintk("%s: xdr returned %d!\n", __FUNCTION__, -status);
        return status;
 }
 
 static int decode_pathconf(struct xdr_stream *xdr, struct nfs_pathconf *pathconf)
 {
-       uint32_t *savep;
+       __be32 *savep;
        uint32_t attrlen, 
                 bitmap[2] = {0};
        int status;
@@ -2523,18 +3008,18 @@ static int decode_pathconf(struct xdr_stream *xdr, struct nfs_pathconf *pathconf
 
        status = verify_attr_len(xdr, savep, attrlen);
 xdr_error:
-       if (status != 0)
-               printk(KERN_NOTICE "%s: xdr error %d!\n", __FUNCTION__, -status);
+       dprintk("%s: xdr returned %d!\n", __FUNCTION__, -status);
        return status;
 }
 
 static int decode_getfattr(struct xdr_stream *xdr, struct nfs_fattr *fattr, const struct nfs_server *server)
 {
-       uint32_t *savep;
+       __be32 *savep;
        uint32_t attrlen,
                 bitmap[2] = {0},
                 type;
        int status, fmode = 0;
+       uint64_t fileid;
 
        if ((status = decode_op_hdr(xdr, OP_GETATTR)) != 0)
                goto xdr_error;
@@ -2557,18 +3042,22 @@ static int decode_getfattr(struct xdr_stream *xdr, struct nfs_fattr *fattr, cons
                goto xdr_error;
        if ((status = decode_attr_size(xdr, bitmap, &fattr->size)) != 0)
                goto xdr_error;
-       if ((status = decode_attr_fsid(xdr, bitmap, &fattr->fsid_u.nfs4)) != 0)
+       if ((status = decode_attr_fsid(xdr, bitmap, &fattr->fsid)) != 0)
                goto xdr_error;
        if ((status = decode_attr_fileid(xdr, bitmap, &fattr->fileid)) != 0)
                goto xdr_error;
+       if ((status = decode_attr_fs_locations(xdr, bitmap, container_of(fattr,
+                                               struct nfs4_fs_locations,
+                                               fattr))) != 0)
+               goto xdr_error;
        if ((status = decode_attr_mode(xdr, bitmap, &fattr->mode)) != 0)
                goto xdr_error;
        fattr->mode |= fmode;
        if ((status = decode_attr_nlink(xdr, bitmap, &fattr->nlink)) != 0)
                goto xdr_error;
-       if ((status = decode_attr_owner(xdr, bitmap, server->nfs4_state, &fattr->uid)) != 0)
+       if ((status = decode_attr_owner(xdr, bitmap, server->nfs_client, &fattr->uid)) != 0)
                goto xdr_error;
-       if ((status = decode_attr_group(xdr, bitmap, server->nfs4_state, &fattr->gid)) != 0)
+       if ((status = decode_attr_group(xdr, bitmap, server->nfs_client, &fattr->gid)) != 0)
                goto xdr_error;
        if ((status = decode_attr_rdev(xdr, bitmap, &fattr->rdev)) != 0)
                goto xdr_error;
@@ -2580,20 +3069,21 @@ static int decode_getfattr(struct xdr_stream *xdr, struct nfs_fattr *fattr, cons
                goto xdr_error;
        if ((status = decode_attr_time_modify(xdr, bitmap, &fattr->mtime)) != 0)
                goto xdr_error;
-       if ((status = verify_attr_len(xdr, savep, attrlen)) == 0) {
+       if ((status = decode_attr_mounted_on_fileid(xdr, bitmap, &fileid)) != 0)
+               goto xdr_error;
+       if (fattr->fileid == 0 && fileid != 0)
+               fattr->fileid = fileid;
+       if ((status = verify_attr_len(xdr, savep, attrlen)) == 0)
                fattr->valid = NFS_ATTR_FATTR | NFS_ATTR_FATTR_V3 | NFS_ATTR_FATTR_V4;
-               fattr->timestamp = jiffies;
-       }
 xdr_error:
-       if (status != 0)
-               printk(KERN_NOTICE "%s: xdr error %d!\n", __FUNCTION__, -status);
+       dprintk("%s: xdr returned %d\n", __FUNCTION__, -status);
        return status;
 }
 
 
 static int decode_fsinfo(struct xdr_stream *xdr, struct nfs_fsinfo *fsinfo)
 {
-       uint32_t *savep;
+       __be32 *savep;
        uint32_t attrlen, bitmap[2];
        int status;
 
@@ -2619,14 +3109,13 @@ static int decode_fsinfo(struct xdr_stream *xdr, struct nfs_fsinfo *fsinfo)
 
        status = verify_attr_len(xdr, savep, attrlen);
 xdr_error:
-       if (status != 0)
-               printk(KERN_NOTICE "%s: xdr error %d!\n", __FUNCTION__, -status);
+       dprintk("%s: xdr returned %d!\n", __FUNCTION__, -status);
        return status;
 }
 
 static int decode_getfh(struct xdr_stream *xdr, struct nfs_fh *fh)
 {
-       uint32_t *p;
+       __be32 *p;
        uint32_t len;
        int status;
 
@@ -2659,55 +3148,64 @@ static int decode_link(struct xdr_stream *xdr, struct nfs4_change_info *cinfo)
 /*
  * We create the owner, so we know a proper owner.id length is 4.
  */
-static int decode_lock_denied (struct xdr_stream *xdr, struct nfs_lock_denied *denied)
+static int decode_lock_denied (struct xdr_stream *xdr, struct file_lock *fl)
 {
-       uint32_t *p;
-       uint32_t namelen;
+       uint64_t offset, length, clientid;
+       __be32 *p;
+       uint32_t namelen, type;
 
        READ_BUF(32);
-       READ64(denied->offset);
-       READ64(denied->length);
-       READ32(denied->type);
-       READ64(denied->owner.clientid);
+       READ64(offset);
+       READ64(length);
+       READ32(type);
+       if (fl != NULL) {
+               fl->fl_start = (loff_t)offset;
+               fl->fl_end = fl->fl_start + (loff_t)length - 1;
+               if (length == ~(uint64_t)0)
+                       fl->fl_end = OFFSET_MAX;
+               fl->fl_type = F_WRLCK;
+               if (type & 1)
+                       fl->fl_type = F_RDLCK;
+               fl->fl_pid = 0;
+       }
+       READ64(clientid);
        READ32(namelen);
        READ_BUF(namelen);
-       if (namelen == 4)
-               READ32(denied->owner.id);
        return -NFS4ERR_DENIED;
 }
 
-static int decode_lock(struct xdr_stream *xdr, struct nfs_lockres *res)
+static int decode_lock(struct xdr_stream *xdr, struct nfs_lock_res *res)
 {
-       uint32_t *p;
+       __be32 *p;
        int status;
 
        status = decode_op_hdr(xdr, OP_LOCK);
        if (status == 0) {
-               READ_BUF(sizeof(nfs4_stateid));
-               COPYMEM(&res->u.stateid, sizeof(res->u.stateid));
+               READ_BUF(sizeof(res->stateid.data));
+               COPYMEM(res->stateid.data, sizeof(res->stateid.data));
        } else if (status == -NFS4ERR_DENIED)
-               return decode_lock_denied(xdr, &res->u.denied);
+               return decode_lock_denied(xdr, NULL);
        return status;
 }
 
-static int decode_lockt(struct xdr_stream *xdr, struct nfs_lockres *res)
+static int decode_lockt(struct xdr_stream *xdr, struct nfs_lockt_res *res)
 {
        int status;
        status = decode_op_hdr(xdr, OP_LOCKT);
        if (status == -NFS4ERR_DENIED)
-               return decode_lock_denied(xdr, &res->u.denied);
+               return decode_lock_denied(xdr, res->denied);
        return status;
 }
 
-static int decode_locku(struct xdr_stream *xdr, struct nfs_lockres *res)
+static int decode_locku(struct xdr_stream *xdr, struct nfs_locku_res *res)
 {
-       uint32_t *p;
+       __be32 *p;
        int status;
 
        status = decode_op_hdr(xdr, OP_LOCKU);
        if (status == 0) {
-               READ_BUF(sizeof(nfs4_stateid));
-               COPYMEM(&res->u.stateid, sizeof(res->u.stateid));
+               READ_BUF(sizeof(res->stateid.data));
+               COPYMEM(res->stateid.data, sizeof(res->stateid.data));
        }
        return status;
 }
@@ -2717,10 +3215,56 @@ static int decode_lookup(struct xdr_stream *xdr)
        return decode_op_hdr(xdr, OP_LOOKUP);
 }
 
+/* This is too sick! */
+static int decode_space_limit(struct xdr_stream *xdr, u64 *maxsize)
+{
+        __be32 *p;
+       uint32_t limit_type, nblocks, blocksize;
+
+       READ_BUF(12);
+       READ32(limit_type);
+       switch (limit_type) {
+               case 1:
+                       READ64(*maxsize);
+                       break;
+               case 2:
+                       READ32(nblocks);
+                       READ32(blocksize);
+                       *maxsize = (uint64_t)nblocks * (uint64_t)blocksize;
+       }
+       return 0;
+}
+
+static int decode_delegation(struct xdr_stream *xdr, struct nfs_openres *res)
+{
+        __be32 *p;
+        uint32_t delegation_type;
+
+       READ_BUF(4);
+       READ32(delegation_type);
+       if (delegation_type == NFS4_OPEN_DELEGATE_NONE) {
+               res->delegation_type = 0;
+               return 0;
+       }
+       READ_BUF(20);
+       COPYMEM(res->delegation.data, sizeof(res->delegation.data));
+       READ32(res->do_recall);
+       switch (delegation_type) {
+               case NFS4_OPEN_DELEGATE_READ:
+                       res->delegation_type = FMODE_READ;
+                       break;
+               case NFS4_OPEN_DELEGATE_WRITE:
+                       res->delegation_type = FMODE_WRITE|FMODE_READ;
+                       if (decode_space_limit(xdr, &res->maxsize) < 0)
+                               return -EIO;
+       }
+       return decode_ace(xdr, NULL, res->server->nfs_client);
+}
+
 static int decode_open(struct xdr_stream *xdr, struct nfs_openres *res)
 {
-        uint32_t *p;
-        uint32_t bmlen, delegation_type;
+        __be32 *p;
+        uint32_t bmlen;
         int status;
 
         status = decode_op_hdr(xdr, OP_OPEN);
@@ -2737,19 +3281,17 @@ static int decode_open(struct xdr_stream *xdr, struct nfs_openres *res)
         if (bmlen > 10)
                 goto xdr_error;
 
-        READ_BUF((bmlen << 2) + 4);
+        READ_BUF(bmlen << 2);
         p += bmlen;
-        READ32(delegation_type);
-        if (delegation_type == NFS4_OPEN_DELEGATE_NONE)
-               return 0;
+       return decode_delegation(xdr, res);
 xdr_error:
-       printk(KERN_NOTICE "%s: xdr error!\n", __FUNCTION__);
+       dprintk("%s: Bitmap too large! Length = %u\n", __FUNCTION__, bmlen);
        return -EIO;
 }
 
 static int decode_open_confirm(struct xdr_stream *xdr, struct nfs_open_confirmres *res)
 {
-        uint32_t *p;
+        __be32 *p;
        int status;
 
         status = decode_op_hdr(xdr, OP_OPEN_CONFIRM);
@@ -2762,7 +3304,7 @@ static int decode_open_confirm(struct xdr_stream *xdr, struct nfs_open_confirmre
 
 static int decode_open_downgrade(struct xdr_stream *xdr, struct nfs_closeres *res)
 {
-       uint32_t *p;
+       __be32 *p;
        int status;
 
        status = decode_op_hdr(xdr, OP_OPEN_DOWNGRADE);
@@ -2786,7 +3328,7 @@ static int decode_putrootfh(struct xdr_stream *xdr)
 static int decode_read(struct xdr_stream *xdr, struct rpc_rqst *req, struct nfs_readres *res)
 {
        struct kvec *iov = req->rq_rcv_buf.head;
-       uint32_t *p;
+       __be32 *p;
        uint32_t count, eof, recvd, hdrlen;
        int status;
 
@@ -2816,15 +3358,20 @@ static int decode_readdir(struct xdr_stream *xdr, struct rpc_rqst *req, struct n
        struct page     *page = *rcvbuf->pages;
        struct kvec     *iov = rcvbuf->head;
        unsigned int    nr, pglen = rcvbuf->page_len;
-       uint32_t        *end, *entry, *p, *kaddr;
-       uint32_t        len, attrlen, word;
-       int             i, hdrlen, recvd, status;
+       __be32          *end, *entry, *p, *kaddr;
+       uint32_t        len, attrlen, xlen;
+       int             hdrlen, recvd, status;
 
        status = decode_op_hdr(xdr, OP_READDIR);
        if (status)
                return status;
        READ_BUF(8);
        COPYMEM(readdir->verifier.data, 8);
+       dprintk("%s: verifier = 0x%x%x\n",
+                       __FUNCTION__,
+                       ((u32 *)readdir->verifier.data)[0],
+                       ((u32 *)readdir->verifier.data)[1]);
+
 
        hdrlen = (char *) p - (char *) iov->iov_base;
        recvd = rcvbuf->len - hdrlen;
@@ -2833,48 +3380,33 @@ static int decode_readdir(struct xdr_stream *xdr, struct rpc_rqst *req, struct n
        xdr_read_pages(xdr, pglen);
 
        BUG_ON(pglen + readdir->pgbase > PAGE_CACHE_SIZE);
-       kaddr = p = (uint32_t *) kmap_atomic(page, KM_USER0);
-       end = (uint32_t *) ((char *)p + pglen + readdir->pgbase);
+       kaddr = p = kmap_atomic(page, KM_USER0);
+       end = p + ((pglen + readdir->pgbase) >> 2);
        entry = p;
        for (nr = 0; *p++; nr++) {
-               if (p + 3 > end)
+               if (end - p < 3)
                        goto short_pkt;
-               p += 2;     /* cookie */
-               len = ntohl(*p++);  /* filename length */
+               dprintk("cookie = %Lu, ", *((unsigned long long *)p));
+               p += 2;                 /* cookie */
+               len = ntohl(*p++);      /* filename length */
                if (len > NFS4_MAXNAMLEN) {
                        printk(KERN_WARNING "NFS: giant filename in readdir (len 0x%x)\n", len);
                        goto err_unmap;
                }
-                       
-               p += XDR_QUADLEN(len);
-               if (p + 1 > end)
+               xlen = XDR_QUADLEN(len);
+               if (end - p < xlen + 1)
                        goto short_pkt;
-               len = ntohl(*p++);  /* bitmap length */
-               if (len > 10) {
-                       printk(KERN_WARNING "NFS: giant bitmap in readdir (len 0x%x)\n", len);
-                       goto err_unmap;
-               }
-               if (p + len + 1 > end)
+               dprintk("filename = %*s\n", len, (char *)p);
+               p += xlen;
+               len = ntohl(*p++);      /* bitmap length */
+               if (end - p < len + 1)
                        goto short_pkt;
-               attrlen = 0;
-               for (i = 0; i < len; i++) {
-                       word = ntohl(*p++);
-                       if (!word)
-                               continue;
-                       else if (i == 0 && word == FATTR4_WORD0_FILEID) {
-                               attrlen = 8;
-                               continue;
-                       }
-                       printk(KERN_WARNING "NFS: unexpected bitmap word in readdir (0x%x)\n", word);
-                       goto err_unmap;
-               }
-               if (ntohl(*p++) != attrlen) {
-                       printk(KERN_WARNING "NFS: unexpected attrlen in readdir\n");
-                       goto err_unmap;
-               }
-               p += XDR_QUADLEN(attrlen);
-               if (p + 1 > end)
+               p += len;
+               attrlen = XDR_QUADLEN(ntohl(*p++));
+               if (end - p < attrlen + 2)
                        goto short_pkt;
+               p += attrlen;           /* attributes */
+               entry = p;
        }
        if (!nr && (entry[0] != 0 || entry[1] == 0))
                goto short_pkt;
@@ -2882,6 +3414,7 @@ out:
        kunmap_atomic(kaddr, KM_USER0);
        return 0;
 short_pkt:
+       dprintk("%s: short packet at entry %d\n", __FUNCTION__, nr);
        entry[0] = entry[1] = 0;
        /* truncate listing ? */
        if (!nr) {
@@ -2898,21 +3431,30 @@ static int decode_readlink(struct xdr_stream *xdr, struct rpc_rqst *req)
 {
        struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
        struct kvec *iov = rcvbuf->head;
-       uint32_t *strlen;
-       unsigned int hdrlen, len;
-       char *string;
+       int hdrlen, len, recvd;
+       __be32 *p;
+       char *kaddr;
        int status;
 
        status = decode_op_hdr(xdr, OP_READLINK);
        if (status)
                return status;
 
+       /* Convert length of symlink */
+       READ_BUF(4);
+       READ32(len);
+       if (len >= rcvbuf->page_len || len <= 0) {
+               dprintk(KERN_WARNING "nfs: server returned giant symlink!\n");
+               return -ENAMETOOLONG;
+       }
        hdrlen = (char *) xdr->p - (char *) iov->iov_base;
-       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) {
+               printk(KERN_WARNING "NFS: server cheating in readlink reply: "
+                               "count %u > recvd %u\n", len, recvd);
+               return -EIO;
        }
+       xdr_read_pages(xdr, len);
        /*
         * The XDR encode routine has set things up so that
         * the link text will be copied directly into the
@@ -2920,18 +3462,9 @@ static int decode_readlink(struct xdr_stream *xdr, struct rpc_rqst *req)
         * and and null-terminate the text (the VFS expects
         * null-termination).
         */
-       strlen = (uint32_t *) kmap_atomic(rcvbuf->pages[0], KM_USER0);
-       len = ntohl(*strlen);
-       if (len > rcvbuf->page_len) {
-               dprintk(KERN_WARNING "nfs: server returned giant symlink!\n");
-               kunmap_atomic(strlen, KM_USER0);
-               return -ENAMETOOLONG;
-       }
-       *strlen = len;
-
-       string = (char *)(strlen + 1);
-       string[len] = '\0';
-       kunmap_atomic(strlen, KM_USER0);
+       kaddr = (char *)kmap_atomic(rcvbuf->pages[0], KM_USER0);
+       kaddr[len+rcvbuf->page_base] = '\0';
+       kunmap_atomic(kaddr, KM_USER0);
        return 0;
 }
 
@@ -2967,6 +3500,53 @@ static int decode_renew(struct xdr_stream *xdr)
        return decode_op_hdr(xdr, OP_RENEW);
 }
 
+static int
+decode_restorefh(struct xdr_stream *xdr)
+{
+       return decode_op_hdr(xdr, OP_RESTOREFH);
+}
+
+static int decode_getacl(struct xdr_stream *xdr, struct rpc_rqst *req,
+               size_t *acl_len)
+{
+       __be32 *savep;
+       uint32_t attrlen,
+                bitmap[2] = {0};
+       struct kvec *iov = req->rq_rcv_buf.head;
+       int status;
+
+       *acl_len = 0;
+       if ((status = decode_op_hdr(xdr, OP_GETATTR)) != 0)
+               goto out;
+       if ((status = decode_attr_bitmap(xdr, bitmap)) != 0)
+               goto out;
+       if ((status = decode_attr_length(xdr, &attrlen, &savep)) != 0)
+               goto out;
+
+       if (unlikely(bitmap[0] & (FATTR4_WORD0_ACL - 1U)))
+               return -EIO;
+       if (likely(bitmap[0] & FATTR4_WORD0_ACL)) {
+               int hdrlen, recvd;
+
+               /* We ignore &savep and don't do consistency checks on
+                * the attr length.  Let userspace figure it out.... */
+               hdrlen = (u8 *)xdr->p - (u8 *)iov->iov_base;
+               recvd = req->rq_rcv_buf.len - hdrlen;
+               if (attrlen > recvd) {
+                       printk(KERN_WARNING "NFS: server cheating in getattr"
+                                       " acl reply: attrlen %u > recvd %u\n",
+                                       attrlen, recvd);
+                       return -EINVAL;
+               }
+               xdr_read_pages(xdr, attrlen);
+               *acl_len = attrlen;
+       } else
+               status = -EOPNOTSUPP;
+
+out:
+       return status;
+}
+
 static int
 decode_savefh(struct xdr_stream *xdr)
 {
@@ -2975,7 +3555,7 @@ decode_savefh(struct xdr_stream *xdr)
 
 static int decode_setattr(struct xdr_stream *xdr, struct nfs_setattrres *res)
 {
-       uint32_t *p;
+       __be32 *p;
        uint32_t bmlen;
        int status;
 
@@ -2989,9 +3569,9 @@ static int decode_setattr(struct xdr_stream *xdr, struct nfs_setattrres *res)
        return 0;
 }
 
-static int decode_setclientid(struct xdr_stream *xdr, struct nfs4_client *clp)
+static int decode_setclientid(struct xdr_stream *xdr, struct nfs_client *clp)
 {
-       uint32_t *p;
+       __be32 *p;
        uint32_t opnum;
        int32_t nfserr;
 
@@ -3020,9 +3600,9 @@ static int decode_setclientid(struct xdr_stream *xdr, struct nfs4_client *clp)
                READ_BUF(4);
                READ32(len);
                READ_BUF(len);
-               return -EEXIST;
+               return -NFSERR_CLID_INUSE;
        } else
-               return -nfs_stat_to_errno(nfserr);
+               return -nfs4_stat_to_errno(nfserr);
 
        return 0;
 }
@@ -3034,7 +3614,7 @@ static int decode_setclientid_confirm(struct xdr_stream *xdr)
 
 static int decode_write(struct xdr_stream *xdr, struct nfs_writeres *res)
 {
-       uint32_t *p;
+       __be32 *p;
        int status;
 
        status = decode_op_hdr(xdr, OP_WRITE);
@@ -3048,10 +3628,15 @@ static int decode_write(struct xdr_stream *xdr, struct nfs_writeres *res)
        return 0;
 }
 
+static int decode_delegreturn(struct xdr_stream *xdr)
+{
+       return decode_op_hdr(xdr, OP_DELEGRETURN);
+}
+
 /*
  * Decode OPEN_DOWNGRADE response
  */
-static int nfs4_xdr_dec_open_downgrade(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_closeres *res)
+static int nfs4_xdr_dec_open_downgrade(struct rpc_rqst *rqstp, __be32 *p, struct nfs_closeres *res)
 {
         struct xdr_stream xdr;
         struct compound_hdr hdr;
@@ -3065,6 +3650,9 @@ static int nfs4_xdr_dec_open_downgrade(struct rpc_rqst *rqstp, uint32_t *p, stru
         if (status)
                 goto out;
         status = decode_open_downgrade(&xdr, res);
+       if (status != 0)
+               goto out;
+       decode_getfattr(&xdr, res->fattr, res->server);
 out:
         return status;
 }
@@ -3076,7 +3664,7 @@ out:
 /*
  * Decode ACCESS response
  */
-static int nfs4_xdr_dec_access(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_accessres *res)
+static int nfs4_xdr_dec_access(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_accessres *res)
 {
        struct xdr_stream xdr;
        struct compound_hdr hdr;
@@ -3094,7 +3682,7 @@ out:
 /*
  * Decode LOOKUP response
  */
-static int nfs4_xdr_dec_lookup(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_lookup_res *res)
+static int nfs4_xdr_dec_lookup(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_lookup_res *res)
 {
        struct xdr_stream xdr;
        struct compound_hdr hdr;
@@ -3117,7 +3705,7 @@ out:
 /*
  * Decode LOOKUP_ROOT response
  */
-static int nfs4_xdr_dec_lookup_root(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_lookup_res *res)
+static int nfs4_xdr_dec_lookup_root(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_lookup_res *res)
 {
        struct xdr_stream xdr;
        struct compound_hdr hdr;
@@ -3137,7 +3725,7 @@ out:
 /*
  * Decode REMOVE response
  */
-static int nfs4_xdr_dec_remove(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_change_info *cinfo)
+static int nfs4_xdr_dec_remove(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_remove_res *res)
 {
        struct xdr_stream xdr;
        struct compound_hdr hdr;
@@ -3146,8 +3734,11 @@ static int nfs4_xdr_dec_remove(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_
        xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
        if ((status = decode_compound_hdr(&xdr, &hdr)) != 0)
                goto out;
-       if ((status = decode_putfh(&xdr)) == 0)
-               status = decode_remove(&xdr, cinfo);
+       if ((status = decode_putfh(&xdr)) != 0)
+               goto out;
+       if ((status = decode_remove(&xdr, &res->cinfo)) != 0)
+               goto out;
+       decode_getfattr(&xdr, res->dir_attr, res->server);
 out:
        return status;
 }
@@ -3155,7 +3746,7 @@ out:
 /*
  * Decode RENAME response
  */
-static int nfs4_xdr_dec_rename(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_rename_res *res)
+static int nfs4_xdr_dec_rename(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_rename_res *res)
 {
        struct xdr_stream xdr;
        struct compound_hdr hdr;
@@ -3170,7 +3761,14 @@ static int nfs4_xdr_dec_rename(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_
                goto out;
        if ((status = decode_putfh(&xdr)) != 0)
                goto out;
-       status = decode_rename(&xdr, &res->old_cinfo, &res->new_cinfo);
+       if ((status = decode_rename(&xdr, &res->old_cinfo, &res->new_cinfo)) != 0)
+               goto out;
+       /* Current FH is target directory */
+       if (decode_getfattr(&xdr, res->new_fattr, res->server) != 0)
+               goto out;
+       if ((status = decode_restorefh(&xdr)) != 0)
+               goto out;
+       decode_getfattr(&xdr, res->old_fattr, res->server);
 out:
        return status;
 }
@@ -3178,7 +3776,7 @@ out:
 /*
  * Decode LINK response
  */
-static int nfs4_xdr_dec_link(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_change_info *cinfo)
+static int nfs4_xdr_dec_link(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_link_res *res)
 {
        struct xdr_stream xdr;
        struct compound_hdr hdr;
@@ -3193,7 +3791,17 @@ static int nfs4_xdr_dec_link(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_ch
                goto out;
        if ((status = decode_putfh(&xdr)) != 0)
                goto out;
-       status = decode_link(&xdr, cinfo);
+       if ((status = decode_link(&xdr, &res->cinfo)) != 0)
+               goto out;
+       /*
+        * Note order: OP_LINK leaves the directory as the current
+        *             filehandle.
+        */
+       if (decode_getfattr(&xdr, res->dir_attr, res->server) != 0)
+               goto out;
+       if ((status = decode_restorefh(&xdr)) != 0)
+               goto out;
+       decode_getfattr(&xdr, res->fattr, res->server);
 out:
        return status;
 }
@@ -3201,7 +3809,7 @@ out:
 /*
  * Decode CREATE response
  */
-static int nfs4_xdr_dec_create(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_create_res *res)
+static int nfs4_xdr_dec_create(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_create_res *res)
 {
        struct xdr_stream xdr;
        struct compound_hdr hdr;
@@ -3212,19 +3820,33 @@ static int nfs4_xdr_dec_create(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_
                goto out;
        if ((status = decode_putfh(&xdr)) != 0)
                goto out;
+       if ((status = decode_savefh(&xdr)) != 0)
+               goto out;
        if ((status = decode_create(&xdr,&res->dir_cinfo)) != 0)
                goto out;
-       if ((status = decode_getfattr(&xdr, res->fattr, res->server)) != 0)
+       if ((status = decode_getfh(&xdr, res->fh)) != 0)
+               goto out;
+       if (decode_getfattr(&xdr, res->fattr, res->server) != 0)
                goto out;
-       status = decode_getfh(&xdr, res->fh);
+       if ((status = decode_restorefh(&xdr)) != 0)
+               goto out;
+       decode_getfattr(&xdr, res->dir_fattr, res->server);
 out:
        return status;
 }
 
+/*
+ * Decode SYMLINK response
+ */
+static int nfs4_xdr_dec_symlink(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_create_res *res)
+{
+       return nfs4_xdr_dec_create(rqstp, p, res);
+}
+
 /*
  * Decode GETATTR response
  */
-static int nfs4_xdr_dec_getattr(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_getattr_res *res)
+static int nfs4_xdr_dec_getattr(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_getattr_res *res)
 {
        struct xdr_stream xdr;
        struct compound_hdr hdr;
@@ -3243,11 +3865,76 @@ out:
 
 }
 
+/*
+ * Encode an SETACL request
+ */
+static int
+nfs4_xdr_enc_setacl(struct rpc_rqst *req, __be32 *p, struct nfs_setaclargs *args)
+{
+        struct xdr_stream xdr;
+        struct compound_hdr hdr = {
+                .nops   = 2,
+        };
+        int status;
+
+        xdr_init_encode(&xdr, &req->rq_snd_buf, p);
+        encode_compound_hdr(&xdr, &hdr);
+        status = encode_putfh(&xdr, args->fh);
+        if (status)
+                goto out;
+        status = encode_setacl(&xdr, args);
+out:
+        return status;
+}
+/*
+ * Decode SETACL response
+ */
+static int
+nfs4_xdr_dec_setacl(struct rpc_rqst *rqstp, __be32 *p, 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);
+       if (status)
+               goto out;
+       status = decode_putfh(&xdr);
+       if (status)
+               goto out;
+       status = decode_setattr(&xdr, res);
+out:
+       return status;
+}
+
+/*
+ * Decode GETACL response
+ */
+static int
+nfs4_xdr_dec_getacl(struct rpc_rqst *rqstp, __be32 *p, size_t *acl_len)
+{
+       struct xdr_stream xdr;
+       struct compound_hdr hdr;
+       int status;
+
+       xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
+       status = decode_compound_hdr(&xdr, &hdr);
+       if (status)
+               goto out;
+       status = decode_putfh(&xdr);
+       if (status)
+               goto out;
+       status = decode_getacl(&xdr, rqstp, acl_len);
+
+out:
+       return status;
+}
 
 /*
  * Decode CLOSE response
  */
-static int nfs4_xdr_dec_close(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_closeres *res)
+static int nfs4_xdr_dec_close(struct rpc_rqst *rqstp, __be32 *p, struct nfs_closeres *res)
 {
         struct xdr_stream xdr;
         struct compound_hdr hdr;
@@ -3261,6 +3948,15 @@ static int nfs4_xdr_dec_close(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_cl
         if (status)
                 goto out;
         status = decode_close(&xdr, res);
+       if (status != 0)
+               goto out;
+       /*
+        * Note: Server may do delete on close for this file
+        *      in which case the getattr call will fail with
+        *      an ESTALE error. Shouldn't be a problem,
+        *      though, since fattr->valid will remain unset.
+        */
+       decode_getfattr(&xdr, res->fattr, res->server);
 out:
         return status;
 }
@@ -3268,7 +3964,7 @@ out:
 /*
  * Decode OPEN response
  */
-static int nfs4_xdr_dec_open(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_openres *res)
+static int nfs4_xdr_dec_open(struct rpc_rqst *rqstp, __be32 *p, struct nfs_openres *res)
 {
         struct xdr_stream xdr;
         struct compound_hdr hdr;
@@ -3281,13 +3977,20 @@ static int nfs4_xdr_dec_open(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_ope
         status = decode_putfh(&xdr);
         if (status)
                 goto out;
+        status = decode_savefh(&xdr);
+       if (status)
+               goto out;
         status = decode_open(&xdr, res);
-        if (status)
-                goto out;
-       status = decode_getfattr(&xdr, res->f_attr, res->server);
         if (status)
                 goto out;
        status = decode_getfh(&xdr, &res->fh);
+        if (status)
+               goto out;
+       if (decode_getfattr(&xdr, res->f_attr, res->server) != 0)
+               goto out;
+       if ((status = decode_restorefh(&xdr)) != 0)
+               goto out;
+       decode_getfattr(&xdr, res->dir_attr, res->server);
 out:
         return status;
 }
@@ -3295,7 +3998,7 @@ out:
 /*
  * Decode OPEN_CONFIRM response
  */
-static int nfs4_xdr_dec_open_confirm(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_open_confirmres *res)
+static int nfs4_xdr_dec_open_confirm(struct rpc_rqst *rqstp, __be32 *p, struct nfs_open_confirmres *res)
 {
         struct xdr_stream xdr;
         struct compound_hdr hdr;
@@ -3314,9 +4017,9 @@ out:
 }
 
 /*
- * Decode OPEN_RECLAIM response
+ * Decode OPEN response
  */
-static int nfs4_xdr_dec_open_reclaim(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_openres *res)
+static int nfs4_xdr_dec_open_noattr(struct rpc_rqst *rqstp, __be32 *p, struct nfs_openres *res)
 {
         struct xdr_stream xdr;
         struct compound_hdr hdr;
@@ -3332,7 +4035,7 @@ static int nfs4_xdr_dec_open_reclaim(struct rpc_rqst *rqstp, uint32_t *p, struct
         status = decode_open(&xdr, res);
         if (status)
                 goto out;
-       status = decode_getfattr(&xdr, res->f_attr, res->server);
+       decode_getfattr(&xdr, res->f_attr, res->server);
 out:
         return status;
 }
@@ -3340,7 +4043,7 @@ out:
 /*
  * Decode SETATTR response
  */
-static int nfs4_xdr_dec_setattr(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_setattrres *res)
+static int nfs4_xdr_dec_setattr(struct rpc_rqst *rqstp, __be32 *p, struct nfs_setattrres *res)
 {
         struct xdr_stream xdr;
         struct compound_hdr hdr;
@@ -3357,6 +4060,8 @@ static int nfs4_xdr_dec_setattr(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_
         if (status)
                 goto out;
        status = decode_getfattr(&xdr, res->fattr, res->server);
+       if (status == NFS4ERR_DELAY)
+               status = 0;
 out:
         return status;
 }
@@ -3364,7 +4069,7 @@ out:
 /*
  * Decode LOCK response
  */
-static int nfs4_xdr_dec_lock(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_lockres *res)
+static int nfs4_xdr_dec_lock(struct rpc_rqst *rqstp, __be32 *p, struct nfs_lock_res *res)
 {
        struct xdr_stream xdr;
        struct compound_hdr hdr;
@@ -3385,7 +4090,7 @@ out:
 /*
  * Decode LOCKT response
  */
-static int nfs4_xdr_dec_lockt(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_lockres *res)
+static int nfs4_xdr_dec_lockt(struct rpc_rqst *rqstp, __be32 *p, struct nfs_lockt_res *res)
 {
        struct xdr_stream xdr;
        struct compound_hdr hdr;
@@ -3406,7 +4111,7 @@ out:
 /*
  * Decode LOCKU response
  */
-static int nfs4_xdr_dec_locku(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_lockres *res)
+static int nfs4_xdr_dec_locku(struct rpc_rqst *rqstp, __be32 *p, struct nfs_locku_res *res)
 {
        struct xdr_stream xdr;
        struct compound_hdr hdr;
@@ -3427,7 +4132,7 @@ out:
 /*
  * Decode READLINK response
  */
-static int nfs4_xdr_dec_readlink(struct rpc_rqst *rqstp, uint32_t *p, void *res)
+static int nfs4_xdr_dec_readlink(struct rpc_rqst *rqstp, __be32 *p, void *res)
 {
        struct xdr_stream xdr;
        struct compound_hdr hdr;
@@ -3448,7 +4153,7 @@ out:
 /*
  * Decode READDIR response
  */
-static int nfs4_xdr_dec_readdir(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_readdir_res *res)
+static int nfs4_xdr_dec_readdir(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_readdir_res *res)
 {
        struct xdr_stream xdr;
        struct compound_hdr hdr;
@@ -3469,7 +4174,7 @@ out:
 /*
  * Decode Read response
  */
-static int nfs4_xdr_dec_read(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_readres *res)
+static int nfs4_xdr_dec_read(struct rpc_rqst *rqstp, __be32 *p, struct nfs_readres *res)
 {
        struct xdr_stream xdr;
        struct compound_hdr hdr;
@@ -3492,7 +4197,7 @@ out:
 /*
  * Decode WRITE response
  */
-static int nfs4_xdr_dec_write(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_writeres *res)
+static int nfs4_xdr_dec_write(struct rpc_rqst *rqstp, __be32 *p, struct nfs_writeres *res)
 {
        struct xdr_stream xdr;
        struct compound_hdr hdr;
@@ -3506,6 +4211,9 @@ static int nfs4_xdr_dec_write(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_wr
        if (status)
                goto out;
        status = decode_write(&xdr, res);
+       if (status)
+               goto out;
+       decode_getfattr(&xdr, res->fattr, res->server);
        if (!status)
                status = res->count;
 out:
@@ -3515,7 +4223,7 @@ out:
 /*
  * Decode COMMIT response
  */
-static int nfs4_xdr_dec_commit(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_writeres *res)
+static int nfs4_xdr_dec_commit(struct rpc_rqst *rqstp, __be32 *p, struct nfs_writeres *res)
 {
        struct xdr_stream xdr;
        struct compound_hdr hdr;
@@ -3529,6 +4237,9 @@ static int nfs4_xdr_dec_commit(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_w
        if (status)
                goto out;
        status = decode_commit(&xdr, res);
+       if (status)
+               goto out;
+       decode_getfattr(&xdr, res->fattr, res->server);
 out:
        return status;
 }
@@ -3536,7 +4247,7 @@ out:
 /*
  * FSINFO request
  */
-static int nfs4_xdr_dec_fsinfo(struct rpc_rqst *req, uint32_t *p, struct nfs_fsinfo *fsinfo)
+static int nfs4_xdr_dec_fsinfo(struct rpc_rqst *req, __be32 *p, struct nfs_fsinfo *fsinfo)
 {
        struct xdr_stream xdr;
        struct compound_hdr hdr;
@@ -3549,14 +4260,14 @@ static int nfs4_xdr_dec_fsinfo(struct rpc_rqst *req, uint32_t *p, struct nfs_fsi
        if (!status)
                status = decode_fsinfo(&xdr, fsinfo);
        if (!status)
-               status = -nfs_stat_to_errno(hdr.status);
+               status = -nfs4_stat_to_errno(hdr.status);
        return status;
 }
 
 /*
  * PATHCONF request
  */
-static int nfs4_xdr_dec_pathconf(struct rpc_rqst *req, uint32_t *p, struct nfs_pathconf *pathconf)
+static int nfs4_xdr_dec_pathconf(struct rpc_rqst *req, __be32 *p, struct nfs_pathconf *pathconf)
 {
        struct xdr_stream xdr;
        struct compound_hdr hdr;
@@ -3574,7 +4285,7 @@ static int nfs4_xdr_dec_pathconf(struct rpc_rqst *req, uint32_t *p, struct nfs_p
 /*
  * STATFS request
  */
-static int nfs4_xdr_dec_statfs(struct rpc_rqst *req, uint32_t *p, struct nfs_fsstat *fsstat)
+static int nfs4_xdr_dec_statfs(struct rpc_rqst *req, __be32 *p, struct nfs_fsstat *fsstat)
 {
        struct xdr_stream xdr;
        struct compound_hdr hdr;
@@ -3592,7 +4303,7 @@ static int nfs4_xdr_dec_statfs(struct rpc_rqst *req, uint32_t *p, struct nfs_fss
 /*
  * GETATTR_BITMAP request
  */
-static int nfs4_xdr_dec_server_caps(struct rpc_rqst *req, uint32_t *p, struct nfs4_server_caps_res *res)
+static int nfs4_xdr_dec_server_caps(struct rpc_rqst *req, __be32 *p, struct nfs4_server_caps_res *res)
 {
        struct xdr_stream xdr;
        struct compound_hdr hdr;
@@ -3611,7 +4322,7 @@ out:
 /*
  * Decode RENEW response
  */
-static int nfs4_xdr_dec_renew(struct rpc_rqst *rqstp, uint32_t *p, void *dummy)
+static int nfs4_xdr_dec_renew(struct rpc_rqst *rqstp, __be32 *p, void *dummy)
 {
        struct xdr_stream xdr;
        struct compound_hdr hdr;
@@ -3627,8 +4338,8 @@ static int nfs4_xdr_dec_renew(struct rpc_rqst *rqstp, uint32_t *p, void *dummy)
 /*
  * a SETCLIENTID request
  */
-static int nfs4_xdr_dec_setclientid(struct rpc_rqst *req, uint32_t *p,
-               struct nfs4_client *clp)
+static int nfs4_xdr_dec_setclientid(struct rpc_rqst *req, __be32 *p,
+               struct nfs_client *clp)
 {
        struct xdr_stream xdr;
        struct compound_hdr hdr;
@@ -3639,14 +4350,14 @@ static int nfs4_xdr_dec_setclientid(struct rpc_rqst *req, uint32_t *p,
        if (!status)
                status = decode_setclientid(&xdr, clp);
        if (!status)
-               status = -nfs_stat_to_errno(hdr.status);
+               status = -nfs4_stat_to_errno(hdr.status);
        return status;
 }
 
 /*
  * a SETCLIENTID_CONFIRM request
  */
-static int nfs4_xdr_dec_setclientid_confirm(struct rpc_rqst *req, uint32_t *p, struct nfs_fsinfo *fsinfo)
+static int nfs4_xdr_dec_setclientid_confirm(struct rpc_rqst *req, __be32 *p, struct nfs_fsinfo *fsinfo)
 {
        struct xdr_stream xdr;
        struct compound_hdr hdr;
@@ -3661,12 +4372,58 @@ static int nfs4_xdr_dec_setclientid_confirm(struct rpc_rqst *req, uint32_t *p, s
        if (!status)
                status = decode_fsinfo(&xdr, fsinfo);
        if (!status)
-               status = -nfs_stat_to_errno(hdr.status);
+               status = -nfs4_stat_to_errno(hdr.status);
+       return status;
+}
+
+/*
+ * DELEGRETURN request
+ */
+static int nfs4_xdr_dec_delegreturn(struct rpc_rqst *rqstp, __be32 *p, 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);
+       if (status != 0)
+               goto out;
+       status = decode_putfh(&xdr);
+       if (status != 0)
+               goto out;
+       status = decode_delegreturn(&xdr);
+       decode_getfattr(&xdr, res->fattr, res->server);
+out:
+       return status;
+}
+
+/*
+ * FS_LOCATIONS request
+ */
+static int nfs4_xdr_dec_fs_locations(struct rpc_rqst *req, __be32 *p, struct nfs4_fs_locations *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);
+       if (status != 0)
+               goto out;
+       if ((status = decode_putfh(&xdr)) != 0)
+               goto out;
+       if ((status = decode_lookup(&xdr)) != 0)
+               goto out;
+       xdr_enter_page(&xdr, PAGE_SIZE);
+       status = decode_getfattr(&xdr, &res->fattr, res->server);
+out:
        return status;
 }
 
-uint32_t *nfs4_decode_dirent(uint32_t *p, struct nfs_entry *entry, int plus)
+__be32 *nfs4_decode_dirent(__be32 *p, struct nfs_entry *entry, int plus)
 {
+       uint32_t bitmap[2] = {0};
        uint32_t len;
 
        if (!*p++) {
@@ -3689,11 +4446,28 @@ uint32_t *nfs4_decode_dirent(uint32_t *p, struct nfs_entry *entry, int plus)
         */
        entry->ino = 1;
 
-       len = ntohl(*p++);             /* bitmap length */
-       p += len;
-       len = ntohl(*p++);             /* attribute buffer length */
-       if (len)
-               p = xdr_decode_hyper(p, &entry->ino);
+       len = ntohl(*p++);              /* bitmap length */
+       if (len-- > 0) {
+               bitmap[0] = ntohl(*p++);
+               if (len-- > 0) {
+                       bitmap[1] = ntohl(*p++);
+                       p += len;
+               }
+       }
+       len = XDR_QUADLEN(ntohl(*p++)); /* attribute buffer length */
+       if (len > 0) {
+               if (bitmap[0] & FATTR4_WORD0_RDATTR_ERROR) {
+                       bitmap[0] &= ~FATTR4_WORD0_RDATTR_ERROR;
+                       /* Ignore the return value of rdattr_error for now */
+                       p++;
+                       len--;
+               }
+               if (bitmap[0] == 0 && bitmap[1] == FATTR4_WORD1_MOUNTED_ON_FILEID)
+                       xdr_decode_hyper(p, &entry->ino);
+               else if (bitmap[0] == FATTR4_WORD0_FILEID)
+                       xdr_decode_hyper(p, &entry->ino);
+               p += len;
+       }
 
        entry->eof = !p[0] && p[1];
        return p;
@@ -3727,6 +4501,8 @@ static struct {
        { NFS4ERR_DQUOT,        EDQUOT          },
        { NFS4ERR_STALE,        ESTALE          },
        { NFS4ERR_BADHANDLE,    EBADHANDLE      },
+       { NFS4ERR_BADOWNER,     EINVAL          },
+       { NFS4ERR_BADNAME,      EINVAL          },
        { NFS4ERR_BAD_COOKIE,   EBADCOOKIE      },
        { NFS4ERR_NOTSUPP,      ENOTSUPP        },
        { NFS4ERR_TOOSMALL,     ETOOSMALL       },
@@ -3749,14 +4525,14 @@ static struct {
  * This one is used jointly by NFSv2 and NFSv3.
  */
 static int
-nfs_stat_to_errno(int stat)
+nfs4_stat_to_errno(int stat)
 {
        int i;
        for (i = 0; nfs_errtbl[i].stat != -1; i++) {
                if (nfs_errtbl[i].stat == stat)
                        return nfs_errtbl[i].errno;
        }
-       if (stat < 0) {
+       if (stat <= 10000 || stat > 10100) {
                /* The server is looney tunes. */
                return ESERVERFAULT;
        }
@@ -3778,6 +4554,8 @@ nfs_stat_to_errno(int stat)
        .p_encode = (kxdrproc_t) nfs4_xdr_##argtype,            \
        .p_decode = (kxdrproc_t) nfs4_xdr_##restype,            \
        .p_bufsiz = MAX(NFS4_##argtype##_sz,NFS4_##restype##_sz) << 2,  \
+       .p_statidx = NFSPROC4_CLNT_##proc,                      \
+       .p_name   = #proc,                                      \
     }
 
 struct rpc_procinfo    nfs4_procedures[] = {
@@ -3786,7 +4564,7 @@ struct rpc_procinfo       nfs4_procedures[] = {
   PROC(COMMIT,         enc_commit,     dec_commit),
   PROC(OPEN,           enc_open,       dec_open),
   PROC(OPEN_CONFIRM,   enc_open_confirm,       dec_open_confirm),
-  PROC(OPEN_RECLAIM,   enc_open_reclaim,       dec_open_reclaim),
+  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),
@@ -3804,17 +4582,22 @@ struct rpc_procinfo     nfs4_procedures[] = {
   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),
 };
 
 struct rpc_version             nfs_version4 = {
        .number                 = 4,
-       .nrprocs                = sizeof(nfs4_procedures)/sizeof(nfs4_procedures[0]),
+       .nrprocs                = ARRAY_SIZE(nfs4_procedures),
        .procs                  = nfs4_procedures
 };