NFS: define and initialize compound_hdr.replen
[safe/jmp/linux-2.6] / fs / nfs / nfs4xdr.c
index 9f1df83..c85dbee 100644 (file)
@@ -192,12 +192,16 @@ static int nfs4_stat_to_errno(int);
                                 decode_verifier_maxsz)
 #define encode_remove_maxsz    (op_encode_hdr_maxsz + \
                                nfs4_name_maxsz)
+#define decode_remove_maxsz    (op_decode_hdr_maxsz + \
+                                decode_change_info_maxsz)
 #define encode_rename_maxsz    (op_encode_hdr_maxsz + \
                                2 * nfs4_name_maxsz)
-#define decode_rename_maxsz    (op_decode_hdr_maxsz + 5 + 5)
+#define decode_rename_maxsz    (op_decode_hdr_maxsz + \
+                                decode_change_info_maxsz + \
+                                decode_change_info_maxsz)
 #define encode_link_maxsz      (op_encode_hdr_maxsz + \
                                nfs4_name_maxsz)
-#define decode_link_maxsz      (op_decode_hdr_maxsz + 5)
+#define decode_link_maxsz      (op_decode_hdr_maxsz + decode_change_info_maxsz)
 #define encode_lock_maxsz      (op_encode_hdr_maxsz + \
                                 7 + \
                                 1 + encode_stateid_maxsz + 8)
@@ -414,7 +418,7 @@ static int nfs4_stat_to_errno(int);
                                encode_getattr_maxsz)
 #define NFS4_dec_remove_sz     (compound_decode_hdr_maxsz + \
                                decode_putfh_maxsz + \
-                               op_decode_hdr_maxsz + 5 + \
+                               decode_remove_maxsz + \
                                decode_getattr_maxsz)
 #define NFS4_enc_rename_sz     (compound_encode_hdr_maxsz + \
                                encode_putfh_maxsz + \
@@ -522,20 +526,17 @@ static int nfs4_stat_to_errno(int);
                                 decode_lookup_maxsz + \
                                 decode_fs_locations_maxsz)
 
-static struct {
-       unsigned int    mode;
-       unsigned int    nfs2type;
-} nfs_type2fmt[] = {
-       { 0,            NFNON        },
-       { S_IFREG,      NFREG        },
-       { S_IFDIR,      NFDIR        },
-       { S_IFBLK,      NFBLK        },
-       { S_IFCHR,      NFCHR        },
-       { S_IFLNK,      NFLNK        },
-       { S_IFSOCK,     NFSOCK       },
-       { S_IFIFO,      NFFIFO       },
-       { 0,            NFNON        },
-       { 0,            NFNON        },
+static const umode_t nfs_type2fmt[] = {
+       [NF4BAD] = 0,
+       [NF4REG] = S_IFREG,
+       [NF4DIR] = S_IFDIR,
+       [NF4BLK] = S_IFBLK,
+       [NF4CHR] = S_IFCHR,
+       [NF4LNK] = S_IFLNK,
+       [NF4SOCK] = S_IFSOCK,
+       [NF4FIFO] = S_IFIFO,
+       [NF4ATTRDIR] = 0,
+       [NF4NAMEDATTR] = 0,
 };
 
 struct compound_hdr {
@@ -544,6 +545,7 @@ struct compound_hdr {
        __be32 *        nops_p;
        uint32_t        taglen;
        char *          tag;
+       uint32_t        replen;         /* expected reply words */
 };
 
 /*
@@ -579,9 +581,17 @@ static void encode_string(struct xdr_stream *xdr, unsigned int len, const char *
        xdr_encode_opaque(p, str, len);
 }
 
-static void encode_compound_hdr(struct xdr_stream *xdr, struct compound_hdr *hdr)
+static void encode_compound_hdr(struct xdr_stream *xdr,
+                               struct rpc_rqst *req,
+                               struct compound_hdr *hdr)
 {
        __be32 *p;
+       struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth;
+
+       /* initialize running count of expected bytes in reply.
+        * NOTE: the replied tag SHOULD be the same is the one sent,
+        * but this is not required as a MUST for the server to do so. */
+       hdr->replen = RPC_REPHDRSIZE + auth->au_rslack + 3 + hdr->taglen;
 
        dprintk("encode_compound: tag=%.*s\n", (int)hdr->taglen, hdr->tag);
        BUG_ON(hdr->taglen > NFS4_MAXTAGLEN);
@@ -1358,7 +1368,7 @@ static int nfs4_xdr_enc_access(struct rpc_rqst *req, __be32 *p, const struct nfs
        };
 
        xdr_init_encode(&xdr, &req->rq_snd_buf, p);
-       encode_compound_hdr(&xdr, &hdr);
+       encode_compound_hdr(&xdr, req, &hdr);
        encode_putfh(&xdr, args->fh, &hdr);
        encode_access(&xdr, args->access, &hdr);
        encode_getfattr(&xdr, args->bitmask, &hdr);
@@ -1377,7 +1387,7 @@ static int nfs4_xdr_enc_lookup(struct rpc_rqst *req, __be32 *p, const struct nfs
        };
 
        xdr_init_encode(&xdr, &req->rq_snd_buf, p);
-       encode_compound_hdr(&xdr, &hdr);
+       encode_compound_hdr(&xdr, req, &hdr);
        encode_putfh(&xdr, args->dir_fh, &hdr);
        encode_lookup(&xdr, args->name, &hdr);
        encode_getfh(&xdr, &hdr);
@@ -1397,7 +1407,7 @@ static int nfs4_xdr_enc_lookup_root(struct rpc_rqst *req, __be32 *p, const struc
        };
 
        xdr_init_encode(&xdr, &req->rq_snd_buf, p);
-       encode_compound_hdr(&xdr, &hdr);
+       encode_compound_hdr(&xdr, req, &hdr);
        encode_putrootfh(&xdr, &hdr);
        encode_getfh(&xdr, &hdr);
        encode_getfattr(&xdr, args->bitmask, &hdr);
@@ -1416,7 +1426,7 @@ static int nfs4_xdr_enc_remove(struct rpc_rqst *req, __be32 *p, const struct nfs
        };
 
        xdr_init_encode(&xdr, &req->rq_snd_buf, p);
-       encode_compound_hdr(&xdr, &hdr);
+       encode_compound_hdr(&xdr, req, &hdr);
        encode_putfh(&xdr, args->fh, &hdr);
        encode_remove(&xdr, &args->name, &hdr);
        encode_getfattr(&xdr, args->bitmask, &hdr);
@@ -1435,7 +1445,7 @@ static int nfs4_xdr_enc_rename(struct rpc_rqst *req, __be32 *p, const struct nfs
        };
 
        xdr_init_encode(&xdr, &req->rq_snd_buf, p);
-       encode_compound_hdr(&xdr, &hdr);
+       encode_compound_hdr(&xdr, req, &hdr);
        encode_putfh(&xdr, args->old_dir, &hdr);
        encode_savefh(&xdr, &hdr);
        encode_putfh(&xdr, args->new_dir, &hdr);
@@ -1458,7 +1468,7 @@ static int nfs4_xdr_enc_link(struct rpc_rqst *req, __be32 *p, const struct nfs4_
        };
 
        xdr_init_encode(&xdr, &req->rq_snd_buf, p);
-       encode_compound_hdr(&xdr, &hdr);
+       encode_compound_hdr(&xdr, req, &hdr);
        encode_putfh(&xdr, args->fh, &hdr);
        encode_savefh(&xdr, &hdr);
        encode_putfh(&xdr, args->dir_fh, &hdr);
@@ -1481,7 +1491,7 @@ static int nfs4_xdr_enc_create(struct rpc_rqst *req, __be32 *p, const struct nfs
        };
 
        xdr_init_encode(&xdr, &req->rq_snd_buf, p);
-       encode_compound_hdr(&xdr, &hdr);
+       encode_compound_hdr(&xdr, req, &hdr);
        encode_putfh(&xdr, args->dir_fh, &hdr);
        encode_savefh(&xdr, &hdr);
        encode_create(&xdr, args, &hdr);
@@ -1512,7 +1522,7 @@ static int nfs4_xdr_enc_getattr(struct rpc_rqst *req, __be32 *p, const struct nf
        };
 
        xdr_init_encode(&xdr, &req->rq_snd_buf, p);
-       encode_compound_hdr(&xdr, &hdr);
+       encode_compound_hdr(&xdr, req, &hdr);
        encode_putfh(&xdr, args->fh, &hdr);
        encode_getfattr(&xdr, args->bitmask, &hdr);
        encode_nops(&hdr);
@@ -1530,7 +1540,7 @@ static int nfs4_xdr_enc_close(struct rpc_rqst *req, __be32 *p, struct nfs_closea
        };
 
        xdr_init_encode(&xdr, &req->rq_snd_buf, p);
-       encode_compound_hdr(&xdr, &hdr);
+       encode_compound_hdr(&xdr, req, &hdr);
        encode_putfh(&xdr, args->fh, &hdr);
        encode_close(&xdr, args, &hdr);
        encode_getfattr(&xdr, args->bitmask, &hdr);
@@ -1549,7 +1559,7 @@ static int nfs4_xdr_enc_open(struct rpc_rqst *req, __be32 *p, struct nfs_openarg
        };
 
        xdr_init_encode(&xdr, &req->rq_snd_buf, p);
-       encode_compound_hdr(&xdr, &hdr);
+       encode_compound_hdr(&xdr, req, &hdr);
        encode_putfh(&xdr, args->fh, &hdr);
        encode_savefh(&xdr, &hdr);
        encode_open(&xdr, args, &hdr);
@@ -1572,7 +1582,7 @@ static int nfs4_xdr_enc_open_confirm(struct rpc_rqst *req, __be32 *p, struct nfs
        };
 
        xdr_init_encode(&xdr, &req->rq_snd_buf, p);
-       encode_compound_hdr(&xdr, &hdr);
+       encode_compound_hdr(&xdr, req, &hdr);
        encode_putfh(&xdr, args->fh, &hdr);
        encode_open_confirm(&xdr, args, &hdr);
        encode_nops(&hdr);
@@ -1590,7 +1600,7 @@ static int nfs4_xdr_enc_open_noattr(struct rpc_rqst *req, __be32 *p, struct nfs_
        };
 
        xdr_init_encode(&xdr, &req->rq_snd_buf, p);
-       encode_compound_hdr(&xdr, &hdr);
+       encode_compound_hdr(&xdr, req, &hdr);
        encode_putfh(&xdr, args->fh, &hdr);
        encode_open(&xdr, args, &hdr);
        encode_getfattr(&xdr, args->bitmask, &hdr);
@@ -1609,7 +1619,7 @@ static int nfs4_xdr_enc_open_downgrade(struct rpc_rqst *req, __be32 *p, struct n
        };
 
        xdr_init_encode(&xdr, &req->rq_snd_buf, p);
-       encode_compound_hdr(&xdr, &hdr);
+       encode_compound_hdr(&xdr, req, &hdr);
        encode_putfh(&xdr, args->fh, &hdr);
        encode_open_downgrade(&xdr, args, &hdr);
        encode_getfattr(&xdr, args->bitmask, &hdr);
@@ -1628,7 +1638,7 @@ static int nfs4_xdr_enc_lock(struct rpc_rqst *req, __be32 *p, struct nfs_lock_ar
        };
 
        xdr_init_encode(&xdr, &req->rq_snd_buf, p);
-       encode_compound_hdr(&xdr, &hdr);
+       encode_compound_hdr(&xdr, req, &hdr);
        encode_putfh(&xdr, args->fh, &hdr);
        encode_lock(&xdr, args, &hdr);
        encode_nops(&hdr);
@@ -1646,7 +1656,7 @@ static int nfs4_xdr_enc_lockt(struct rpc_rqst *req, __be32 *p, struct nfs_lockt_
        };
 
        xdr_init_encode(&xdr, &req->rq_snd_buf, p);
-       encode_compound_hdr(&xdr, &hdr);
+       encode_compound_hdr(&xdr, req, &hdr);
        encode_putfh(&xdr, args->fh, &hdr);
        encode_lockt(&xdr, args, &hdr);
        encode_nops(&hdr);
@@ -1664,7 +1674,7 @@ static int nfs4_xdr_enc_locku(struct rpc_rqst *req, __be32 *p, struct nfs_locku_
        };
 
        xdr_init_encode(&xdr, &req->rq_snd_buf, p);
-       encode_compound_hdr(&xdr, &hdr);
+       encode_compound_hdr(&xdr, req, &hdr);
        encode_putfh(&xdr, args->fh, &hdr);
        encode_locku(&xdr, args, &hdr);
        encode_nops(&hdr);
@@ -1684,7 +1694,7 @@ static int nfs4_xdr_enc_readlink(struct rpc_rqst *req, __be32 *p, const struct n
        unsigned int replen;
 
        xdr_init_encode(&xdr, &req->rq_snd_buf, p);
-       encode_compound_hdr(&xdr, &hdr);
+       encode_compound_hdr(&xdr, req, &hdr);
        encode_putfh(&xdr, args->fh, &hdr);
        encode_readlink(&xdr, args, req, &hdr);
 
@@ -1712,7 +1722,7 @@ static int nfs4_xdr_enc_readdir(struct rpc_rqst *req, __be32 *p, const struct nf
        int replen;
 
        xdr_init_encode(&xdr, &req->rq_snd_buf, p);
-       encode_compound_hdr(&xdr, &hdr);
+       encode_compound_hdr(&xdr, req, &hdr);
        encode_putfh(&xdr, args->fh, &hdr);
        encode_readdir(&xdr, args, req, &hdr);
 
@@ -1743,7 +1753,7 @@ static int nfs4_xdr_enc_read(struct rpc_rqst *req, __be32 *p, struct nfs_readarg
        int replen;
 
        xdr_init_encode(&xdr, &req->rq_snd_buf, p);
-       encode_compound_hdr(&xdr, &hdr);
+       encode_compound_hdr(&xdr, req, &hdr);
        encode_putfh(&xdr, args->fh, &hdr);
        encode_read(&xdr, args, &hdr);
 
@@ -1770,7 +1780,7 @@ static int nfs4_xdr_enc_setattr(struct rpc_rqst *req, __be32 *p, struct nfs_seta
        };
 
        xdr_init_encode(&xdr, &req->rq_snd_buf, p);
-       encode_compound_hdr(&xdr, &hdr);
+       encode_compound_hdr(&xdr, req, &hdr);
        encode_putfh(&xdr, args->fh, &hdr);
        encode_setattr(&xdr, args, args->server, &hdr);
        encode_getfattr(&xdr, args->bitmask, &hdr);
@@ -1793,7 +1803,7 @@ nfs4_xdr_enc_getacl(struct rpc_rqst *req, __be32 *p,
        int replen;
 
        xdr_init_encode(&xdr, &req->rq_snd_buf, p);
-       encode_compound_hdr(&xdr, &hdr);
+       encode_compound_hdr(&xdr, req, &hdr);
        encode_putfh(&xdr, args->fh, &hdr);
        encode_getattr_two(&xdr, FATTR4_WORD0_ACL, 0, &hdr);
 
@@ -1816,7 +1826,7 @@ static int nfs4_xdr_enc_write(struct rpc_rqst *req, __be32 *p, struct nfs_writea
        };
 
        xdr_init_encode(&xdr, &req->rq_snd_buf, p);
-       encode_compound_hdr(&xdr, &hdr);
+       encode_compound_hdr(&xdr, req, &hdr);
        encode_putfh(&xdr, args->fh, &hdr);
        encode_write(&xdr, args, &hdr);
        req->rq_snd_buf.flags |= XDRBUF_WRITE;
@@ -1836,7 +1846,7 @@ static int nfs4_xdr_enc_commit(struct rpc_rqst *req, __be32 *p, struct nfs_write
        };
 
        xdr_init_encode(&xdr, &req->rq_snd_buf, p);
-       encode_compound_hdr(&xdr, &hdr);
+       encode_compound_hdr(&xdr, req, &hdr);
        encode_putfh(&xdr, args->fh, &hdr);
        encode_commit(&xdr, args, &hdr);
        encode_getfattr(&xdr, args->bitmask, &hdr);
@@ -1855,7 +1865,7 @@ static int nfs4_xdr_enc_fsinfo(struct rpc_rqst *req, __be32 *p, struct nfs4_fsin
        };
 
        xdr_init_encode(&xdr, &req->rq_snd_buf, p);
-       encode_compound_hdr(&xdr, &hdr);
+       encode_compound_hdr(&xdr, req, &hdr);
        encode_putfh(&xdr, args->fh, &hdr);
        encode_fsinfo(&xdr, args->bitmask, &hdr);
        encode_nops(&hdr);
@@ -1873,7 +1883,7 @@ static int nfs4_xdr_enc_pathconf(struct rpc_rqst *req, __be32 *p, const struct n
        };
 
        xdr_init_encode(&xdr, &req->rq_snd_buf, p);
-       encode_compound_hdr(&xdr, &hdr);
+       encode_compound_hdr(&xdr, req, &hdr);
        encode_putfh(&xdr, args->fh, &hdr);
        encode_getattr_one(&xdr, args->bitmask[0] & nfs4_pathconf_bitmap[0],
                           &hdr);
@@ -1892,7 +1902,7 @@ static int nfs4_xdr_enc_statfs(struct rpc_rqst *req, __be32 *p, const struct nfs
        };
 
        xdr_init_encode(&xdr, &req->rq_snd_buf, p);
-       encode_compound_hdr(&xdr, &hdr);
+       encode_compound_hdr(&xdr, req, &hdr);
        encode_putfh(&xdr, args->fh, &hdr);
        encode_getattr_two(&xdr, args->bitmask[0] & nfs4_statfs_bitmap[0],
                           args->bitmask[1] & nfs4_statfs_bitmap[1], &hdr);
@@ -1903,7 +1913,8 @@ static int nfs4_xdr_enc_statfs(struct rpc_rqst *req, __be32 *p, const struct nfs
 /*
  * GETATTR_BITMAP request
  */
-static int nfs4_xdr_enc_server_caps(struct rpc_rqst *req, __be32 *p, const struct nfs_fh *fhandle)
+static int nfs4_xdr_enc_server_caps(struct rpc_rqst *req, __be32 *p,
+                                   struct nfs4_server_caps_arg *args)
 {
        struct xdr_stream xdr;
        struct compound_hdr hdr = {
@@ -1911,8 +1922,8 @@ static int nfs4_xdr_enc_server_caps(struct rpc_rqst *req, __be32 *p, const struc
        };
 
        xdr_init_encode(&xdr, &req->rq_snd_buf, p);
-       encode_compound_hdr(&xdr, &hdr);
-       encode_putfh(&xdr, fhandle, &hdr);
+       encode_compound_hdr(&xdr, req, &hdr);
+       encode_putfh(&xdr, args->fhandle, &hdr);
        encode_getattr_one(&xdr, FATTR4_WORD0_SUPPORTED_ATTRS|
                           FATTR4_WORD0_LINK_SUPPORT|
                           FATTR4_WORD0_SYMLINK_SUPPORT|
@@ -1932,7 +1943,7 @@ static int nfs4_xdr_enc_renew(struct rpc_rqst *req, __be32 *p, struct nfs_client
        };
 
        xdr_init_encode(&xdr, &req->rq_snd_buf, p);
-       encode_compound_hdr(&xdr, &hdr);
+       encode_compound_hdr(&xdr, req, &hdr);
        encode_renew(&xdr, clp, &hdr);
        encode_nops(&hdr);
        return 0;
@@ -1949,7 +1960,7 @@ static int nfs4_xdr_enc_setclientid(struct rpc_rqst *req, __be32 *p, struct nfs4
        };
 
        xdr_init_encode(&xdr, &req->rq_snd_buf, p);
-       encode_compound_hdr(&xdr, &hdr);
+       encode_compound_hdr(&xdr, req, &hdr);
        encode_setclientid(&xdr, sc, &hdr);
        encode_nops(&hdr);
        return 0;
@@ -1967,7 +1978,7 @@ static int nfs4_xdr_enc_setclientid_confirm(struct rpc_rqst *req, __be32 *p, str
        const u32 lease_bitmap[2] = { FATTR4_WORD0_LEASE_TIME, 0 };
 
        xdr_init_encode(&xdr, &req->rq_snd_buf, p);
-       encode_compound_hdr(&xdr, &hdr);
+       encode_compound_hdr(&xdr, req, &hdr);
        encode_setclientid_confirm(&xdr, clp, &hdr);
        encode_putrootfh(&xdr, &hdr);
        encode_fsinfo(&xdr, lease_bitmap, &hdr);
@@ -1986,7 +1997,7 @@ static int nfs4_xdr_enc_delegreturn(struct rpc_rqst *req, __be32 *p, const struc
        };
 
        xdr_init_encode(&xdr, &req->rq_snd_buf, p);
-       encode_compound_hdr(&xdr, &hdr);
+       encode_compound_hdr(&xdr, req, &hdr);
        encode_putfh(&xdr, args->fhandle, &hdr);
        encode_delegreturn(&xdr, args->stateid, &hdr);
        encode_getfattr(&xdr, args->bitmask, &hdr);
@@ -2007,7 +2018,7 @@ static int nfs4_xdr_enc_fs_locations(struct rpc_rqst *req, __be32 *p, struct nfs
        int replen;
 
        xdr_init_encode(&xdr, &req->rq_snd_buf, p);
-       encode_compound_hdr(&xdr, &hdr);
+       encode_compound_hdr(&xdr, req, &hdr);
        encode_putfh(&xdr, args->dir_fh, &hdr);
        encode_lookup(&xdr, args->name, &hdr);
        encode_fs_locations(&xdr, args->bitmask, &hdr);
@@ -2160,6 +2171,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)
 {
        __be32 *p;
+       int ret = 0;
 
        *type = 0;
        if (unlikely(bitmap[0] & (FATTR4_WORD0_TYPE - 1U)))
@@ -2172,14 +2184,16 @@ static int decode_attr_type(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *
                        return -EIO;
                }
                bitmap[0] &= ~FATTR4_WORD0_TYPE;
+               ret = NFS_ATTR_FATTR_TYPE;
        }
-       dprintk("%s: type=0%o\n", __func__, nfs_type2fmt[*type].nfs2type);
-       return 0;
+       dprintk("%s: type=0%o\n", __func__, nfs_type2fmt[*type]);
+       return ret;
 }
 
 static int decode_attr_change(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *change)
 {
        __be32 *p;
+       int ret = 0;
 
        *change = 0;
        if (unlikely(bitmap[0] & (FATTR4_WORD0_CHANGE - 1U)))
@@ -2188,15 +2202,17 @@ static int decode_attr_change(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t
                READ_BUF(8);
                READ64(*change);
                bitmap[0] &= ~FATTR4_WORD0_CHANGE;
+               ret = NFS_ATTR_FATTR_CHANGE;
        }
        dprintk("%s: change attribute=%Lu\n", __func__,
                        (unsigned long long)*change);
-       return 0;
+       return ret;
 }
 
 static int decode_attr_size(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *size)
 {
        __be32 *p;
+       int ret = 0;
 
        *size = 0;
        if (unlikely(bitmap[0] & (FATTR4_WORD0_SIZE - 1U)))
@@ -2205,9 +2221,10 @@ static int decode_attr_size(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *
                READ_BUF(8);
                READ64(*size);
                bitmap[0] &= ~FATTR4_WORD0_SIZE;
+               ret = NFS_ATTR_FATTR_SIZE;
        }
        dprintk("%s: file size=%Lu\n", __func__, (unsigned long long)*size);
-       return 0;
+       return ret;
 }
 
 static int decode_attr_link_support(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res)
@@ -2245,6 +2262,7 @@ static int decode_attr_symlink_support(struct xdr_stream *xdr, uint32_t *bitmap,
 static int decode_attr_fsid(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs_fsid *fsid)
 {
        __be32 *p;
+       int ret = 0;
 
        fsid->major = 0;
        fsid->minor = 0;
@@ -2255,11 +2273,12 @@ static int decode_attr_fsid(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs
                READ64(fsid->major);
                READ64(fsid->minor);
                bitmap[0] &= ~FATTR4_WORD0_FSID;
+               ret = NFS_ATTR_FATTR_FSID;
        }
        dprintk("%s: fsid=(0x%Lx/0x%Lx)\n", __func__,
                        (unsigned long long)fsid->major,
                        (unsigned long long)fsid->minor);
-       return 0;
+       return ret;
 }
 
 static int decode_attr_lease_time(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res)
@@ -2297,6 +2316,7 @@ static int decode_attr_aclsupport(struct xdr_stream *xdr, uint32_t *bitmap, uint
 static int decode_attr_fileid(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *fileid)
 {
        __be32 *p;
+       int ret = 0;
 
        *fileid = 0;
        if (unlikely(bitmap[0] & (FATTR4_WORD0_FILEID - 1U)))
@@ -2305,14 +2325,16 @@ static int decode_attr_fileid(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t
                READ_BUF(8);
                READ64(*fileid);
                bitmap[0] &= ~FATTR4_WORD0_FILEID;
+               ret = NFS_ATTR_FATTR_FILEID;
        }
        dprintk("%s: fileid=%Lu\n", __func__, (unsigned long long)*fileid);
-       return 0;
+       return ret;
 }
 
 static int decode_attr_mounted_on_fileid(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *fileid)
 {
        __be32 *p;
+       int ret = 0;
 
        *fileid = 0;
        if (unlikely(bitmap[1] & (FATTR4_WORD1_MOUNTED_ON_FILEID - 1U)))
@@ -2321,9 +2343,10 @@ static int decode_attr_mounted_on_fileid(struct xdr_stream *xdr, uint32_t *bitma
                READ_BUF(8);
                READ64(*fileid);
                bitmap[1] &= ~FATTR4_WORD1_MOUNTED_ON_FILEID;
+               ret = NFS_ATTR_FATTR_FILEID;
        }
        dprintk("%s: fileid=%Lu\n", __func__, (unsigned long long)*fileid);
-       return 0;
+       return ret;
 }
 
 static int decode_attr_files_avail(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res)
@@ -2479,6 +2502,8 @@ static int decode_attr_fs_locations(struct xdr_stream *xdr, uint32_t *bitmap, st
                if (res->nlocations < NFS4_FS_LOCATIONS_MAXENTRIES)
                        res->nlocations++;
        }
+       if (res->nlocations != 0)
+               status = NFS_ATTR_FATTR_V4_REFERRAL;
 out:
        dprintk("%s: fs_locations done, error = %d\n", __func__, status);
        return status;
@@ -2580,26 +2605,30 @@ static int decode_attr_maxwrite(struct xdr_stream *xdr, uint32_t *bitmap, uint32
        return status;
 }
 
-static int decode_attr_mode(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *mode)
+static int decode_attr_mode(struct xdr_stream *xdr, uint32_t *bitmap, umode_t *mode)
 {
+       uint32_t tmp;
        __be32 *p;
+       int ret = 0;
 
        *mode = 0;
        if (unlikely(bitmap[1] & (FATTR4_WORD1_MODE - 1U)))
                return -EIO;
        if (likely(bitmap[1] & FATTR4_WORD1_MODE)) {
                READ_BUF(4);
-               READ32(*mode);
-               *mode &= ~S_IFMT;
+               READ32(tmp);
+               *mode = tmp & ~S_IFMT;
                bitmap[1] &= ~FATTR4_WORD1_MODE;
+               ret = NFS_ATTR_FATTR_MODE;
        }
        dprintk("%s: file mode=0%o\n", __func__, (unsigned int)*mode);
-       return 0;
+       return ret;
 }
 
 static int decode_attr_nlink(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *nlink)
 {
        __be32 *p;
+       int ret = 0;
 
        *nlink = 1;
        if (unlikely(bitmap[1] & (FATTR4_WORD1_NUMLINKS - 1U)))
@@ -2608,15 +2637,17 @@ static int decode_attr_nlink(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t
                READ_BUF(4);
                READ32(*nlink);
                bitmap[1] &= ~FATTR4_WORD1_NUMLINKS;
+               ret = NFS_ATTR_FATTR_NLINK;
        }
        dprintk("%s: nlink=%u\n", __func__, (unsigned int)*nlink);
-       return 0;
+       return ret;
 }
 
 static int decode_attr_owner(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs_client *clp, uint32_t *uid)
 {
        uint32_t len;
        __be32 *p;
+       int ret = 0;
 
        *uid = -2;
        if (unlikely(bitmap[1] & (FATTR4_WORD1_OWNER - 1U)))
@@ -2626,7 +2657,9 @@ static int decode_attr_owner(struct xdr_stream *xdr, uint32_t *bitmap, struct nf
                READ32(len);
                READ_BUF(len);
                if (len < XDR_MAX_NETOBJ) {
-                       if (nfs_map_name_to_uid(clp, (char *)p, len, uid) != 0)
+                       if (nfs_map_name_to_uid(clp, (char *)p, len, uid) == 0)
+                               ret = NFS_ATTR_FATTR_OWNER;
+                       else
                                dprintk("%s: nfs_map_name_to_uid failed!\n",
                                                __func__);
                } else
@@ -2635,13 +2668,14 @@ static int decode_attr_owner(struct xdr_stream *xdr, uint32_t *bitmap, struct nf
                bitmap[1] &= ~FATTR4_WORD1_OWNER;
        }
        dprintk("%s: uid=%d\n", __func__, (int)*uid);
-       return 0;
+       return ret;
 }
 
 static int decode_attr_group(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs_client *clp, uint32_t *gid)
 {
        uint32_t len;
        __be32 *p;
+       int ret = 0;
 
        *gid = -2;
        if (unlikely(bitmap[1] & (FATTR4_WORD1_OWNER_GROUP - 1U)))
@@ -2651,7 +2685,9 @@ static int decode_attr_group(struct xdr_stream *xdr, uint32_t *bitmap, struct nf
                READ32(len);
                READ_BUF(len);
                if (len < XDR_MAX_NETOBJ) {
-                       if (nfs_map_group_to_gid(clp, (char *)p, len, gid) != 0)
+                       if (nfs_map_group_to_gid(clp, (char *)p, len, gid) == 0)
+                               ret = NFS_ATTR_FATTR_GROUP;
+                       else
                                dprintk("%s: nfs_map_group_to_gid failed!\n",
                                                __func__);
                } else
@@ -2660,13 +2696,14 @@ static int decode_attr_group(struct xdr_stream *xdr, uint32_t *bitmap, struct nf
                bitmap[1] &= ~FATTR4_WORD1_OWNER_GROUP;
        }
        dprintk("%s: gid=%d\n", __func__, (int)*gid);
-       return 0;
+       return ret;
 }
 
 static int decode_attr_rdev(struct xdr_stream *xdr, uint32_t *bitmap, dev_t *rdev)
 {
        uint32_t major = 0, minor = 0;
        __be32 *p;
+       int ret = 0;
 
        *rdev = MKDEV(0,0);
        if (unlikely(bitmap[1] & (FATTR4_WORD1_RAWDEV - 1U)))
@@ -2681,9 +2718,10 @@ static int decode_attr_rdev(struct xdr_stream *xdr, uint32_t *bitmap, dev_t *rde
                if (MAJOR(tmp) == major && MINOR(tmp) == minor)
                        *rdev = tmp;
                bitmap[1] &= ~ FATTR4_WORD1_RAWDEV;
+               ret = NFS_ATTR_FATTR_RDEV;
        }
        dprintk("%s: rdev=(0x%x:0x%x)\n", __func__, major, minor);
-       return 0;
+       return ret;
 }
 
 static int decode_attr_space_avail(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res)
@@ -2740,6 +2778,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)
 {
        __be32 *p;
+       int ret = 0;
 
        *used = 0;
        if (unlikely(bitmap[1] & (FATTR4_WORD1_SPACE_USED - 1U)))
@@ -2748,10 +2787,11 @@ static int decode_attr_space_used(struct xdr_stream *xdr, uint32_t *bitmap, uint
                READ_BUF(8);
                READ64(*used);
                bitmap[1] &= ~FATTR4_WORD1_SPACE_USED;
+               ret = NFS_ATTR_FATTR_SPACE_USED;
        }
        dprintk("%s: space used=%Lu\n", __func__,
                        (unsigned long long)*used);
-       return 0;
+       return ret;
 }
 
 static int decode_attr_time(struct xdr_stream *xdr, struct timespec *time)
@@ -2778,6 +2818,8 @@ static int decode_attr_time_access(struct xdr_stream *xdr, uint32_t *bitmap, str
                return -EIO;
        if (likely(bitmap[1] & FATTR4_WORD1_TIME_ACCESS)) {
                status = decode_attr_time(xdr, time);
+               if (status == 0)
+                       status = NFS_ATTR_FATTR_ATIME;
                bitmap[1] &= ~FATTR4_WORD1_TIME_ACCESS;
        }
        dprintk("%s: atime=%ld\n", __func__, (long)time->tv_sec);
@@ -2794,6 +2836,8 @@ static int decode_attr_time_metadata(struct xdr_stream *xdr, uint32_t *bitmap, s
                return -EIO;
        if (likely(bitmap[1] & FATTR4_WORD1_TIME_METADATA)) {
                status = decode_attr_time(xdr, time);
+               if (status == 0)
+                       status = NFS_ATTR_FATTR_CTIME;
                bitmap[1] &= ~FATTR4_WORD1_TIME_METADATA;
        }
        dprintk("%s: ctime=%ld\n", __func__, (long)time->tv_sec);
@@ -2810,6 +2854,8 @@ static int decode_attr_time_modify(struct xdr_stream *xdr, uint32_t *bitmap, str
                return -EIO;
        if (likely(bitmap[1] & FATTR4_WORD1_TIME_MODIFY)) {
                status = decode_attr_time(xdr, time);
+               if (status == 0)
+                       status = NFS_ATTR_FATTR_MTIME;
                bitmap[1] &= ~FATTR4_WORD1_TIME_MODIFY;
        }
        dprintk("%s: mtime=%ld\n", __func__, (long)time->tv_sec);
@@ -2994,60 +3040,116 @@ static int decode_getfattr(struct xdr_stream *xdr, struct nfs_fattr *fattr, cons
        uint32_t attrlen,
                 bitmap[2] = {0},
                 type;
-       int status, fmode = 0;
+       int status;
+       umode_t fmode = 0;
        uint64_t fileid;
 
-       if ((status = decode_op_hdr(xdr, OP_GETATTR)) != 0)
+       status = decode_op_hdr(xdr, OP_GETATTR);
+       if (status < 0)
                goto xdr_error;
-       if ((status = decode_attr_bitmap(xdr, bitmap)) != 0)
+
+       status = decode_attr_bitmap(xdr, bitmap);
+       if (status < 0)
                goto xdr_error;
 
-       if ((status = decode_attr_length(xdr, &attrlen, &savep)) != 0)
+       status = decode_attr_length(xdr, &attrlen, &savep);
+       if (status < 0)
                goto xdr_error;
 
 
-       if ((status = decode_attr_type(xdr, bitmap, &type)) != 0)
+       status = decode_attr_type(xdr, bitmap, &type);
+       if (status < 0)
                goto xdr_error;
-       fattr->type = nfs_type2fmt[type].nfs2type;
-       fattr->mode = nfs_type2fmt[type].mode;
+       fattr->mode = 0;
+       if (status != 0) {
+               fattr->mode |= nfs_type2fmt[type];
+               fattr->valid |= status;
+       }
 
-       if ((status = decode_attr_change(xdr, bitmap, &fattr->change_attr)) != 0)
+       status = decode_attr_change(xdr, bitmap, &fattr->change_attr);
+       if (status < 0)
                goto xdr_error;
-       if ((status = decode_attr_size(xdr, bitmap, &fattr->size)) != 0)
+       fattr->valid |= status;
+
+       status = decode_attr_size(xdr, bitmap, &fattr->size);
+       if (status < 0)
                goto xdr_error;
-       if ((status = decode_attr_fsid(xdr, bitmap, &fattr->fsid)) != 0)
+       fattr->valid |= status;
+
+       status = decode_attr_fsid(xdr, bitmap, &fattr->fsid);
+       if (status < 0)
                goto xdr_error;
-       if ((status = decode_attr_fileid(xdr, bitmap, &fattr->fileid)) != 0)
+       fattr->valid |= status;
+
+       status = decode_attr_fileid(xdr, bitmap, &fattr->fileid);
+       if (status < 0)
                goto xdr_error;
-       if ((status = decode_attr_fs_locations(xdr, bitmap, container_of(fattr,
+       fattr->valid |= status;
+
+       status = decode_attr_fs_locations(xdr, bitmap, container_of(fattr,
                                                struct nfs4_fs_locations,
-                                               fattr))) != 0)
+                                               fattr));
+       if (status < 0)
                goto xdr_error;
-       if ((status = decode_attr_mode(xdr, bitmap, &fmode)) != 0)
+       fattr->valid |= status;
+
+       status = decode_attr_mode(xdr, bitmap, &fmode);
+       if (status < 0)
                goto xdr_error;
-       fattr->mode |= fmode;
-       if ((status = decode_attr_nlink(xdr, bitmap, &fattr->nlink)) != 0)
+       if (status != 0) {
+               fattr->mode |= fmode;
+               fattr->valid |= status;
+       }
+
+       status = decode_attr_nlink(xdr, bitmap, &fattr->nlink);
+       if (status < 0)
                goto xdr_error;
-       if ((status = decode_attr_owner(xdr, bitmap, server->nfs_client, &fattr->uid)) != 0)
+       fattr->valid |= status;
+
+       status = decode_attr_owner(xdr, bitmap, server->nfs_client, &fattr->uid);
+       if (status < 0)
                goto xdr_error;
-       if ((status = decode_attr_group(xdr, bitmap, server->nfs_client, &fattr->gid)) != 0)
+       fattr->valid |= status;
+
+       status = decode_attr_group(xdr, bitmap, server->nfs_client, &fattr->gid);
+       if (status < 0)
                goto xdr_error;
-       if ((status = decode_attr_rdev(xdr, bitmap, &fattr->rdev)) != 0)
+       fattr->valid |= status;
+
+       status = decode_attr_rdev(xdr, bitmap, &fattr->rdev);
+       if (status < 0)
                goto xdr_error;
-       if ((status = decode_attr_space_used(xdr, bitmap, &fattr->du.nfs3.used)) != 0)
+       fattr->valid |= status;
+
+       status = decode_attr_space_used(xdr, bitmap, &fattr->du.nfs3.used);
+       if (status < 0)
                goto xdr_error;
-       if ((status = decode_attr_time_access(xdr, bitmap, &fattr->atime)) != 0)
+       fattr->valid |= status;
+
+       status = decode_attr_time_access(xdr, bitmap, &fattr->atime);
+       if (status < 0)
                goto xdr_error;
-       if ((status = decode_attr_time_metadata(xdr, bitmap, &fattr->ctime)) != 0)
+       fattr->valid |= status;
+
+       status = decode_attr_time_metadata(xdr, bitmap, &fattr->ctime);
+       if (status < 0)
                goto xdr_error;
-       if ((status = decode_attr_time_modify(xdr, bitmap, &fattr->mtime)) != 0)
+       fattr->valid |= status;
+
+       status = decode_attr_time_modify(xdr, bitmap, &fattr->mtime);
+       if (status < 0)
                goto xdr_error;
-       if ((status = decode_attr_mounted_on_fileid(xdr, bitmap, &fileid)) != 0)
+       fattr->valid |= status;
+
+       status = decode_attr_mounted_on_fileid(xdr, bitmap, &fileid);
+       if (status < 0)
                goto xdr_error;
-       if (fattr->fileid == 0 && fileid != 0)
+       if (status != 0 && !(fattr->valid & status)) {
                fattr->fileid = fileid;
-       if ((status = verify_attr_len(xdr, savep, attrlen)) == 0)
-               fattr->valid = NFS_ATTR_FATTR_V4;
+               fattr->valid |= status;
+       }
+
+       status = verify_attr_len(xdr, savep, attrlen);
 xdr_error:
        dprintk("%s: xdr returned %d\n", __func__, -status);
        return status;
@@ -3569,7 +3671,7 @@ decode_savefh(struct xdr_stream *xdr)
        return decode_op_hdr(xdr, OP_SAVEFH);
 }
 
-static int decode_setattr(struct xdr_stream *xdr, struct nfs_setattrres *res)
+static int decode_setattr(struct xdr_stream *xdr)
 {
        __be32 *p;
        uint32_t bmlen;
@@ -3896,7 +3998,7 @@ nfs4_xdr_enc_setacl(struct rpc_rqst *req, __be32 *p, struct nfs_setaclargs *args
        int status;
 
        xdr_init_encode(&xdr, &req->rq_snd_buf, p);
-       encode_compound_hdr(&xdr, &hdr);
+       encode_compound_hdr(&xdr, req, &hdr);
        encode_putfh(&xdr, args->fh, &hdr);
        status = encode_setacl(&xdr, args, &hdr);
        encode_nops(&hdr);
@@ -3907,7 +4009,8 @@ nfs4_xdr_enc_setacl(struct rpc_rqst *req, __be32 *p, struct nfs_setaclargs *args
  * Decode SETACL response
  */
 static int
-nfs4_xdr_dec_setacl(struct rpc_rqst *rqstp, __be32 *p, void *res)
+nfs4_xdr_dec_setacl(struct rpc_rqst *rqstp, __be32 *p,
+                   struct nfs_setaclres *res)
 {
        struct xdr_stream xdr;
        struct compound_hdr hdr;
@@ -3920,7 +4023,7 @@ nfs4_xdr_dec_setacl(struct rpc_rqst *rqstp, __be32 *p, void *res)
        status = decode_putfh(&xdr);
        if (status)
                goto out;
-       status = decode_setattr(&xdr, res);
+       status = decode_setattr(&xdr);
 out:
        return status;
 }
@@ -3929,7 +4032,8 @@ out:
  * Decode GETACL response
  */
 static int
-nfs4_xdr_dec_getacl(struct rpc_rqst *rqstp, __be32 *p, size_t *acl_len)
+nfs4_xdr_dec_getacl(struct rpc_rqst *rqstp, __be32 *p,
+                   struct nfs_getaclres *res)
 {
        struct xdr_stream xdr;
        struct compound_hdr hdr;
@@ -3942,7 +4046,7 @@ nfs4_xdr_dec_getacl(struct rpc_rqst *rqstp, __be32 *p, size_t *acl_len)
        status = decode_putfh(&xdr);
        if (status)
                goto out;
-       status = decode_getacl(&xdr, rqstp, acl_len);
+       status = decode_getacl(&xdr, rqstp, &res->acl_len);
 
 out:
        return status;
@@ -4072,7 +4176,7 @@ static int nfs4_xdr_dec_setattr(struct rpc_rqst *rqstp, __be32 *p, struct nfs_se
        status = decode_putfh(&xdr);
        if (status)
                goto out;
-       status = decode_setattr(&xdr, res);
+       status = decode_setattr(&xdr);
        if (status)
                goto out;
        decode_getfattr(&xdr, res->fattr, res->server);
@@ -4146,7 +4250,8 @@ out:
 /*
  * Decode READLINK response
  */
-static int nfs4_xdr_dec_readlink(struct rpc_rqst *rqstp, __be32 *p, void *res)
+static int nfs4_xdr_dec_readlink(struct rpc_rqst *rqstp, __be32 *p,
+                                struct nfs4_readlink_res *res)
 {
        struct xdr_stream xdr;
        struct compound_hdr hdr;
@@ -4261,7 +4366,8 @@ out:
 /*
  * FSINFO request
  */
-static int nfs4_xdr_dec_fsinfo(struct rpc_rqst *req, __be32 *p, struct nfs_fsinfo *fsinfo)
+static int nfs4_xdr_dec_fsinfo(struct rpc_rqst *req, __be32 *p,
+                              struct nfs4_fsinfo_res *res)
 {
        struct xdr_stream xdr;
        struct compound_hdr hdr;
@@ -4272,14 +4378,15 @@ static int nfs4_xdr_dec_fsinfo(struct rpc_rqst *req, __be32 *p, struct nfs_fsinf
        if (!status)
                status = decode_putfh(&xdr);
        if (!status)
-               status = decode_fsinfo(&xdr, fsinfo);
+               status = decode_fsinfo(&xdr, res->fsinfo);
        return status;
 }
 
 /*
  * PATHCONF request
  */
-static int nfs4_xdr_dec_pathconf(struct rpc_rqst *req, __be32 *p, struct nfs_pathconf *pathconf)
+static int nfs4_xdr_dec_pathconf(struct rpc_rqst *req, __be32 *p,
+                                struct nfs4_pathconf_res *res)
 {
        struct xdr_stream xdr;
        struct compound_hdr hdr;
@@ -4290,14 +4397,15 @@ static int nfs4_xdr_dec_pathconf(struct rpc_rqst *req, __be32 *p, struct nfs_pat
        if (!status)
                status = decode_putfh(&xdr);
        if (!status)
-               status = decode_pathconf(&xdr, pathconf);
+               status = decode_pathconf(&xdr, res->pathconf);
        return status;
 }
 
 /*
  * STATFS request
  */
-static int nfs4_xdr_dec_statfs(struct rpc_rqst *req, __be32 *p, struct nfs_fsstat *fsstat)
+static int nfs4_xdr_dec_statfs(struct rpc_rqst *req, __be32 *p,
+                              struct nfs4_statfs_res *res)
 {
        struct xdr_stream xdr;
        struct compound_hdr hdr;
@@ -4308,7 +4416,7 @@ static int nfs4_xdr_dec_statfs(struct rpc_rqst *req, __be32 *p, struct nfs_fssta
        if (!status)
                status = decode_putfh(&xdr);
        if (!status)
-               status = decode_statfs(&xdr, fsstat);
+               status = decode_statfs(&xdr, res->fsstat);
        return status;
 }
 
@@ -4409,7 +4517,8 @@ out:
 /*
  * FS_LOCATIONS request
  */
-static int nfs4_xdr_dec_fs_locations(struct rpc_rqst *req, __be32 *p, struct nfs4_fs_locations *res)
+static int nfs4_xdr_dec_fs_locations(struct rpc_rqst *req, __be32 *p,
+                                    struct nfs4_fs_locations_res *res)
 {
        struct xdr_stream xdr;
        struct compound_hdr hdr;
@@ -4424,7 +4533,8 @@ static int nfs4_xdr_dec_fs_locations(struct rpc_rqst *req, __be32 *p, struct nfs
        if ((status = decode_lookup(&xdr)) != 0)
                goto out;
        xdr_enter_page(&xdr, PAGE_SIZE);
-       status = decode_getfattr(&xdr, &res->fattr, res->server);
+       status = decode_getfattr(&xdr, &res->fs_locations->fattr,
+                                res->fs_locations->server);
 out:
        return status;
 }