Merge git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux
[firefly-linux-kernel-4.4.55.git] / fs / nfs / nfs4xdr.c
index 33bd8d0f745d8baaa11b41fc3fcffde52ee3f02a..c74fdb114b48af141a719d1facd11ed249c5f5d1 100644 (file)
@@ -44,6 +44,8 @@
 #include <linux/pagemap.h>
 #include <linux/proc_fs.h>
 #include <linux/kdev_t.h>
+#include <linux/module.h>
+#include <linux/utsname.h>
 #include <linux/sunrpc/clnt.h>
 #include <linux/sunrpc/msg_prot.h>
 #include <linux/sunrpc/gss_api.h>
@@ -271,7 +273,12 @@ static int nfs4_stat_to_errno(int);
                                1 /* flags */ + \
                                1 /* spa_how */ + \
                                0 /* SP4_NONE (for now) */ + \
-                               1 /* zero implemetation id array */)
+                               1 /* implementation id array of size 1 */ + \
+                               1 /* nii_domain */ + \
+                               XDR_QUADLEN(NFS4_OPAQUE_LIMIT) + \
+                               1 /* nii_name */ + \
+                               XDR_QUADLEN(NFS4_OPAQUE_LIMIT) + \
+                               3 /* nii_date */)
 #define decode_exchange_id_maxsz (op_decode_hdr_maxsz + \
                                2 /* eir_clientid */ + \
                                1 /* eir_sequenceid */ + \
@@ -284,7 +291,11 @@ static int nfs4_stat_to_errno(int);
                                /* eir_server_scope<> */ \
                                XDR_QUADLEN(NFS4_OPAQUE_LIMIT) + 1 + \
                                1 /* eir_server_impl_id array length */ + \
-                               0 /* ignored eir_server_impl_id contents */)
+                               1 /* nii_domain */ + \
+                               XDR_QUADLEN(NFS4_OPAQUE_LIMIT) + \
+                               1 /* nii_name */ + \
+                               XDR_QUADLEN(NFS4_OPAQUE_LIMIT) + \
+                               3 /* nii_date */)
 #define encode_channel_attrs_maxsz  (6 + 1 /* ca_rdma_ird.len (0) */)
 #define decode_channel_attrs_maxsz  (6 + \
                                     1 /* ca_rdma_ird.len */ + \
@@ -838,6 +849,12 @@ const u32 nfs41_maxread_overhead = ((RPC_MAX_HEADER_WITH_AUTH +
                                    XDR_UNIT);
 #endif /* CONFIG_NFS_V4_1 */
 
+static unsigned short send_implementation_id = 1;
+
+module_param(send_implementation_id, ushort, 0644);
+MODULE_PARM_DESC(send_implementation_id,
+               "Send implementation ID with NFSv4.1 exchange_id");
+
 static const umode_t nfs_type2fmt[] = {
        [NF4BAD] = 0,
        [NF4REG] = S_IFREG,
@@ -868,15 +885,44 @@ static __be32 *reserve_space(struct xdr_stream *xdr, size_t nbytes)
        return p;
 }
 
+static void encode_opaque_fixed(struct xdr_stream *xdr, const void *buf, size_t len)
+{
+       __be32 *p;
+
+       p = xdr_reserve_space(xdr, len);
+       xdr_encode_opaque_fixed(p, buf, len);
+}
+
 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);
+       p = reserve_space(xdr, 4 + len);
        xdr_encode_opaque(p, str, len);
 }
 
+static void encode_uint32(struct xdr_stream *xdr, u32 n)
+{
+       __be32 *p;
+
+       p = reserve_space(xdr, 4);
+       *p = cpu_to_be32(n);
+}
+
+static void encode_uint64(struct xdr_stream *xdr, u64 n)
+{
+       __be32 *p;
+
+       p = reserve_space(xdr, 8);
+       xdr_encode_hyper(p, n);
+}
+
+static void encode_nfs4_seqid(struct xdr_stream *xdr,
+               const struct nfs_seqid *seqid)
+{
+       encode_uint32(xdr, seqid->sequence->counter);
+}
+
 static void encode_compound_hdr(struct xdr_stream *xdr,
                                struct rpc_rqst *req,
                                struct compound_hdr *hdr)
@@ -889,28 +935,37 @@ static void encode_compound_hdr(struct xdr_stream *xdr,
         * 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);
-       p = reserve_space(xdr, 4 + hdr->taglen + 8);
-       p = xdr_encode_opaque(p, hdr->tag, hdr->taglen);
+       encode_string(xdr, hdr->taglen, hdr->tag);
+       p = reserve_space(xdr, 8);
        *p++ = cpu_to_be32(hdr->minorversion);
        hdr->nops_p = p;
        *p = cpu_to_be32(hdr->nops);
 }
 
+static void encode_op_hdr(struct xdr_stream *xdr, enum nfs_opnum4 op,
+               uint32_t replen,
+               struct compound_hdr *hdr)
+{
+       encode_uint32(xdr, op);
+       hdr->nops++;
+       hdr->replen += replen;
+}
+
 static void encode_nops(struct compound_hdr *hdr)
 {
        BUG_ON(hdr->nops > NFS4_MAX_OPS);
        *hdr->nops_p = htonl(hdr->nops);
 }
 
-static void encode_nfs4_verifier(struct xdr_stream *xdr, const nfs4_verifier *verf)
+static void encode_nfs4_stateid(struct xdr_stream *xdr, const nfs4_stateid *stateid)
 {
-       __be32 *p;
+       encode_opaque_fixed(xdr, stateid, NFS4_STATEID_SIZE);
+}
 
-       p = xdr_reserve_space(xdr, NFS4_VERIFIER_SIZE);
-       BUG_ON(p == NULL);
-       xdr_encode_opaque_fixed(p, verf->data, NFS4_VERIFIER_SIZE);
+static void encode_nfs4_verifier(struct xdr_stream *xdr, const nfs4_verifier *verf)
+{
+       encode_opaque_fixed(xdr, verf->data, NFS4_VERIFIER_SIZE);
 }
 
 static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const struct nfs_server *server)
@@ -1023,7 +1078,7 @@ static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const
         * Now we backfill the bitmap and the attribute buffer length.
         */
        if (len != ((char *)p - (char *)q) + 4) {
-               printk(KERN_ERR "nfs: Attr length error, %u != %Zu\n",
+               printk(KERN_ERR "NFS: Attr length error, %u != %Zu\n",
                                len, ((char *)p - (char *)q) + 4);
                BUG();
        }
@@ -1037,46 +1092,33 @@ static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const
 
 static void encode_access(struct xdr_stream *xdr, u32 access, struct compound_hdr *hdr)
 {
-       __be32 *p;
-
-       p = reserve_space(xdr, 8);
-       *p++ = cpu_to_be32(OP_ACCESS);
-       *p = cpu_to_be32(access);
-       hdr->nops++;
-       hdr->replen += decode_access_maxsz;
+       encode_op_hdr(xdr, OP_ACCESS, decode_access_maxsz, hdr);
+       encode_uint32(xdr, access);
 }
 
 static void encode_close(struct xdr_stream *xdr, const struct nfs_closeargs *arg, struct compound_hdr *hdr)
 {
-       __be32 *p;
-
-       p = reserve_space(xdr, 8+NFS4_STATEID_SIZE);
-       *p++ = cpu_to_be32(OP_CLOSE);
-       *p++ = cpu_to_be32(arg->seqid->sequence->counter);
-       xdr_encode_opaque_fixed(p, arg->stateid->data, NFS4_STATEID_SIZE);
-       hdr->nops++;
-       hdr->replen += decode_close_maxsz;
+       encode_op_hdr(xdr, OP_CLOSE, decode_close_maxsz, hdr);
+       encode_nfs4_seqid(xdr, arg->seqid);
+       encode_nfs4_stateid(xdr, arg->stateid);
 }
 
 static void encode_commit(struct xdr_stream *xdr, const struct nfs_writeargs *args, struct compound_hdr *hdr)
 {
        __be32 *p;
 
-       p = reserve_space(xdr, 16);
-       *p++ = cpu_to_be32(OP_COMMIT);
+       encode_op_hdr(xdr, OP_COMMIT, decode_commit_maxsz, hdr);
+       p = reserve_space(xdr, 12);
        p = xdr_encode_hyper(p, args->offset);
        *p = cpu_to_be32(args->count);
-       hdr->nops++;
-       hdr->replen += decode_commit_maxsz;
 }
 
 static void encode_create(struct xdr_stream *xdr, const struct nfs4_create_arg *create, struct compound_hdr *hdr)
 {
        __be32 *p;
 
-       p = reserve_space(xdr, 8);
-       *p++ = cpu_to_be32(OP_CREATE);
-       *p = cpu_to_be32(create->ftype);
+       encode_op_hdr(xdr, OP_CREATE, decode_create_maxsz, hdr);
+       encode_uint32(xdr, create->ftype);
 
        switch (create->ftype) {
        case NF4LNK:
@@ -1096,9 +1138,6 @@ static void encode_create(struct xdr_stream *xdr, const struct nfs4_create_arg *
        }
 
        encode_string(xdr, create->name->len, create->name->name);
-       hdr->nops++;
-       hdr->replen += decode_create_maxsz;
-
        encode_attrs(xdr, create->attrs, create->server);
 }
 
@@ -1106,25 +1145,21 @@ static void encode_getattr_one(struct xdr_stream *xdr, uint32_t bitmap, struct c
 {
        __be32 *p;
 
-       p = reserve_space(xdr, 12);
-       *p++ = cpu_to_be32(OP_GETATTR);
+       encode_op_hdr(xdr, OP_GETATTR, decode_getattr_maxsz, hdr);
+       p = reserve_space(xdr, 8);
        *p++ = cpu_to_be32(1);
        *p = cpu_to_be32(bitmap);
-       hdr->nops++;
-       hdr->replen += decode_getattr_maxsz;
 }
 
 static void encode_getattr_two(struct xdr_stream *xdr, uint32_t bm0, uint32_t bm1, struct compound_hdr *hdr)
 {
        __be32 *p;
 
-       p = reserve_space(xdr, 16);
-       *p++ = cpu_to_be32(OP_GETATTR);
+       encode_op_hdr(xdr, OP_GETATTR, decode_getattr_maxsz, hdr);
+       p = reserve_space(xdr, 12);
        *p++ = cpu_to_be32(2);
        *p++ = cpu_to_be32(bm0);
        *p = cpu_to_be32(bm1);
-       hdr->nops++;
-       hdr->replen += decode_getattr_maxsz;
 }
 
 static void
@@ -1134,8 +1169,7 @@ encode_getattr_three(struct xdr_stream *xdr,
 {
        __be32 *p;
 
-       p = reserve_space(xdr, 4);
-       *p = cpu_to_be32(OP_GETATTR);
+       encode_op_hdr(xdr, OP_GETATTR, decode_getattr_maxsz, hdr);
        if (bm2) {
                p = reserve_space(xdr, 16);
                *p++ = cpu_to_be32(3);
@@ -1152,8 +1186,6 @@ encode_getattr_three(struct xdr_stream *xdr,
                *p++ = cpu_to_be32(1);
                *p = cpu_to_be32(bm0);
        }
-       hdr->nops++;
-       hdr->replen += decode_getattr_maxsz;
 }
 
 static void encode_getfattr(struct xdr_stream *xdr, const u32* bitmask, struct compound_hdr *hdr)
@@ -1179,23 +1211,13 @@ static void encode_fs_locations(struct xdr_stream *xdr, const u32* bitmask, stru
 
 static void encode_getfh(struct xdr_stream *xdr, struct compound_hdr *hdr)
 {
-       __be32 *p;
-
-       p = reserve_space(xdr, 4);
-       *p = cpu_to_be32(OP_GETFH);
-       hdr->nops++;
-       hdr->replen += decode_getfh_maxsz;
+       encode_op_hdr(xdr, OP_GETFH, decode_getfh_maxsz, hdr);
 }
 
 static void encode_link(struct xdr_stream *xdr, const struct qstr *name, struct compound_hdr *hdr)
 {
-       __be32 *p;
-
-       p = reserve_space(xdr, 8 + name->len);
-       *p++ = cpu_to_be32(OP_LINK);
-       xdr_encode_opaque(p, name->name, name->len);
-       hdr->nops++;
-       hdr->replen += decode_link_maxsz;
+       encode_op_hdr(xdr, OP_LINK, decode_link_maxsz, hdr);
+       encode_string(xdr, name->len, name->name);
 }
 
 static inline int nfs4_lock_type(struct file_lock *fl, int block)
@@ -1232,79 +1254,60 @@ static void encode_lock(struct xdr_stream *xdr, const struct nfs_lock_args *args
 {
        __be32 *p;
 
-       p = reserve_space(xdr, 32);
-       *p++ = cpu_to_be32(OP_LOCK);
+       encode_op_hdr(xdr, OP_LOCK, decode_lock_maxsz, hdr);
+       p = reserve_space(xdr, 28);
        *p++ = cpu_to_be32(nfs4_lock_type(args->fl, args->block));
        *p++ = cpu_to_be32(args->reclaim);
        p = xdr_encode_hyper(p, args->fl->fl_start);
        p = xdr_encode_hyper(p, nfs4_lock_length(args->fl));
        *p = cpu_to_be32(args->new_lock_owner);
        if (args->new_lock_owner){
-               p = reserve_space(xdr, 4+NFS4_STATEID_SIZE+4);
-               *p++ = cpu_to_be32(args->open_seqid->sequence->counter);
-               p = xdr_encode_opaque_fixed(p, args->open_stateid->data, NFS4_STATEID_SIZE);
-               *p++ = cpu_to_be32(args->lock_seqid->sequence->counter);
+               encode_nfs4_seqid(xdr, args->open_seqid);
+               encode_nfs4_stateid(xdr, args->open_stateid);
+               encode_nfs4_seqid(xdr, args->lock_seqid);
                encode_lockowner(xdr, &args->lock_owner);
        }
        else {
-               p = reserve_space(xdr, NFS4_STATEID_SIZE+4);
-               p = xdr_encode_opaque_fixed(p, args->lock_stateid->data, NFS4_STATEID_SIZE);
-               *p = cpu_to_be32(args->lock_seqid->sequence->counter);
+               encode_nfs4_stateid(xdr, args->lock_stateid);
+               encode_nfs4_seqid(xdr, args->lock_seqid);
        }
-       hdr->nops++;
-       hdr->replen += decode_lock_maxsz;
 }
 
 static void encode_lockt(struct xdr_stream *xdr, const struct nfs_lockt_args *args, struct compound_hdr *hdr)
 {
        __be32 *p;
 
-       p = reserve_space(xdr, 24);
-       *p++ = cpu_to_be32(OP_LOCKT);
+       encode_op_hdr(xdr, OP_LOCKT, decode_lockt_maxsz, hdr);
+       p = reserve_space(xdr, 20);
        *p++ = cpu_to_be32(nfs4_lock_type(args->fl, 0));
        p = xdr_encode_hyper(p, args->fl->fl_start);
        p = xdr_encode_hyper(p, nfs4_lock_length(args->fl));
        encode_lockowner(xdr, &args->lock_owner);
-       hdr->nops++;
-       hdr->replen += decode_lockt_maxsz;
 }
 
 static void encode_locku(struct xdr_stream *xdr, const struct nfs_locku_args *args, struct compound_hdr *hdr)
 {
        __be32 *p;
 
-       p = reserve_space(xdr, 12+NFS4_STATEID_SIZE+16);
-       *p++ = cpu_to_be32(OP_LOCKU);
-       *p++ = cpu_to_be32(nfs4_lock_type(args->fl, 0));
-       *p++ = cpu_to_be32(args->seqid->sequence->counter);
-       p = xdr_encode_opaque_fixed(p, args->stateid->data, NFS4_STATEID_SIZE);
+       encode_op_hdr(xdr, OP_LOCKU, decode_locku_maxsz, hdr);
+       encode_uint32(xdr, nfs4_lock_type(args->fl, 0));
+       encode_nfs4_seqid(xdr, args->seqid);
+       encode_nfs4_stateid(xdr, args->stateid);
+       p = reserve_space(xdr, 16);
        p = xdr_encode_hyper(p, args->fl->fl_start);
        xdr_encode_hyper(p, nfs4_lock_length(args->fl));
-       hdr->nops++;
-       hdr->replen += decode_locku_maxsz;
 }
 
 static void encode_release_lockowner(struct xdr_stream *xdr, const struct nfs_lowner *lowner, struct compound_hdr *hdr)
 {
-       __be32 *p;
-
-       p = reserve_space(xdr, 4);
-       *p = cpu_to_be32(OP_RELEASE_LOCKOWNER);
+       encode_op_hdr(xdr, OP_RELEASE_LOCKOWNER, decode_release_lockowner_maxsz, hdr);
        encode_lockowner(xdr, lowner);
-       hdr->nops++;
-       hdr->replen += decode_release_lockowner_maxsz;
 }
 
 static void encode_lookup(struct xdr_stream *xdr, const struct qstr *name, struct compound_hdr *hdr)
 {
-       int len = name->len;
-       __be32 *p;
-
-       p = reserve_space(xdr, 8 + len);
-       *p++ = cpu_to_be32(OP_LOOKUP);
-       xdr_encode_opaque(p, name->name, len);
-       hdr->nops++;
-       hdr->replen += decode_lookup_maxsz;
+       encode_op_hdr(xdr, OP_LOOKUP, decode_lookup_maxsz, hdr);
+       encode_string(xdr, name->len, name->name);
 }
 
 static void encode_share_access(struct xdr_stream *xdr, fmode_t fmode)
@@ -1335,9 +1338,7 @@ static inline void encode_openhdr(struct xdr_stream *xdr, const struct nfs_opena
  * opcode 4, seqid 4, share_access 4, share_deny 4, clientid 8, ownerlen 4,
  * owner 4 = 32
  */
-       p = reserve_space(xdr, 8);
-       *p++ = cpu_to_be32(OP_OPEN);
-       *p = cpu_to_be32(arg->seqid->sequence->counter);
+       encode_nfs4_seqid(xdr, arg->seqid);
        encode_share_access(xdr, arg->fmode);
        p = reserve_space(xdr, 32);
        p = xdr_encode_hyper(p, arg->clientid);
@@ -1437,14 +1438,15 @@ static inline void encode_claim_delegate_cur(struct xdr_stream *xdr, const struc
 {
        __be32 *p;
 
-       p = reserve_space(xdr, 4+NFS4_STATEID_SIZE);
-       *p++ = cpu_to_be32(NFS4_OPEN_CLAIM_DELEGATE_CUR);
-       xdr_encode_opaque_fixed(p, stateid->data, NFS4_STATEID_SIZE);
+       p = reserve_space(xdr, 4);
+       *p = cpu_to_be32(NFS4_OPEN_CLAIM_DELEGATE_CUR);
+       encode_nfs4_stateid(xdr, stateid);
        encode_string(xdr, name->len, name->name);
 }
 
 static void encode_open(struct xdr_stream *xdr, const struct nfs_openargs *arg, struct compound_hdr *hdr)
 {
+       encode_op_hdr(xdr, OP_OPEN, decode_open_maxsz, hdr);
        encode_openhdr(xdr, arg);
        encode_opentype(xdr, arg);
        switch (arg->claim) {
@@ -1460,88 +1462,64 @@ static void encode_open(struct xdr_stream *xdr, const struct nfs_openargs *arg,
        default:
                BUG();
        }
-       hdr->nops++;
-       hdr->replen += decode_open_maxsz;
 }
 
 static void encode_open_confirm(struct xdr_stream *xdr, const struct nfs_open_confirmargs *arg, struct compound_hdr *hdr)
 {
-       __be32 *p;
-
-       p = reserve_space(xdr, 4+NFS4_STATEID_SIZE+4);
-       *p++ = cpu_to_be32(OP_OPEN_CONFIRM);
-       p = xdr_encode_opaque_fixed(p, arg->stateid->data, NFS4_STATEID_SIZE);
-       *p = cpu_to_be32(arg->seqid->sequence->counter);
-       hdr->nops++;
-       hdr->replen += decode_open_confirm_maxsz;
+       encode_op_hdr(xdr, OP_OPEN_CONFIRM, decode_open_confirm_maxsz, hdr);
+       encode_nfs4_stateid(xdr, arg->stateid);
+       encode_nfs4_seqid(xdr, arg->seqid);
 }
 
 static void encode_open_downgrade(struct xdr_stream *xdr, const struct nfs_closeargs *arg, struct compound_hdr *hdr)
 {
-       __be32 *p;
-
-       p = reserve_space(xdr, 4+NFS4_STATEID_SIZE+4);
-       *p++ = cpu_to_be32(OP_OPEN_DOWNGRADE);
-       p = xdr_encode_opaque_fixed(p, arg->stateid->data, NFS4_STATEID_SIZE);
-       *p = cpu_to_be32(arg->seqid->sequence->counter);
+       encode_op_hdr(xdr, OP_OPEN_DOWNGRADE, decode_open_downgrade_maxsz, hdr);
+       encode_nfs4_stateid(xdr, arg->stateid);
+       encode_nfs4_seqid(xdr, arg->seqid);
        encode_share_access(xdr, arg->fmode);
-       hdr->nops++;
-       hdr->replen += decode_open_downgrade_maxsz;
 }
 
 static void
 encode_putfh(struct xdr_stream *xdr, const struct nfs_fh *fh, struct compound_hdr *hdr)
 {
-       int len = fh->size;
-       __be32 *p;
-
-       p = reserve_space(xdr, 8 + len);
-       *p++ = cpu_to_be32(OP_PUTFH);
-       xdr_encode_opaque(p, fh->data, len);
-       hdr->nops++;
-       hdr->replen += decode_putfh_maxsz;
+       encode_op_hdr(xdr, OP_PUTFH, decode_putfh_maxsz, hdr);
+       encode_string(xdr, fh->size, fh->data);
 }
 
 static void encode_putrootfh(struct xdr_stream *xdr, struct compound_hdr *hdr)
 {
-       __be32 *p;
-
-       p = reserve_space(xdr, 4);
-       *p = cpu_to_be32(OP_PUTROOTFH);
-       hdr->nops++;
-       hdr->replen += decode_putrootfh_maxsz;
+       encode_op_hdr(xdr, OP_PUTROOTFH, decode_putrootfh_maxsz, hdr);
 }
 
-static void encode_stateid(struct xdr_stream *xdr, const struct nfs_open_context *ctx, const struct nfs_lock_context *l_ctx, int zero_seqid)
+static void encode_open_stateid(struct xdr_stream *xdr,
+               const struct nfs_open_context *ctx,
+               const struct nfs_lock_context *l_ctx,
+               fmode_t fmode,
+               int zero_seqid)
 {
        nfs4_stateid stateid;
-       __be32 *p;
 
-       p = reserve_space(xdr, NFS4_STATEID_SIZE);
        if (ctx->state != NULL) {
-               nfs4_copy_stateid(&stateid, ctx->state, l_ctx->lockowner, l_ctx->pid);
+               nfs4_select_rw_stateid(&stateid, ctx->state,
+                               fmode, l_ctx->lockowner, l_ctx->pid);
                if (zero_seqid)
-                       stateid.stateid.seqid = 0;
-               xdr_encode_opaque_fixed(p, stateid.data, NFS4_STATEID_SIZE);
+                       stateid.seqid = 0;
+               encode_nfs4_stateid(xdr, &stateid);
        } else
-               xdr_encode_opaque_fixed(p, zero_stateid.data, NFS4_STATEID_SIZE);
+               encode_nfs4_stateid(xdr, &zero_stateid);
 }
 
 static void encode_read(struct xdr_stream *xdr, const struct nfs_readargs *args, struct compound_hdr *hdr)
 {
        __be32 *p;
 
-       p = reserve_space(xdr, 4);
-       *p = cpu_to_be32(OP_READ);
-
-       encode_stateid(xdr, args->context, args->lock_context,
-                      hdr->minorversion);
+       encode_op_hdr(xdr, OP_READ, decode_read_maxsz, hdr);
+       encode_open_stateid(xdr, args->context, args->lock_context,
+                       FMODE_READ, hdr->minorversion);
 
        p = reserve_space(xdr, 12);
        p = xdr_encode_hyper(p, args->offset);
        *p = cpu_to_be32(args->count);
-       hdr->nops++;
-       hdr->replen += decode_read_maxsz;
 }
 
 static void encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg *readdir, struct rpc_rqst *req, struct compound_hdr *hdr)
@@ -1551,7 +1529,7 @@ static void encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg
                FATTR4_WORD1_MOUNTED_ON_FILEID,
        };
        uint32_t dircount = readdir->count >> 1;
-       __be32 *p;
+       __be32 *p, verf[2];
 
        if (readdir->plus) {
                attrs[0] |= FATTR4_WORD0_TYPE|FATTR4_WORD0_CHANGE|FATTR4_WORD0_SIZE|
@@ -1566,80 +1544,54 @@ static void encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg
        if (!(readdir->bitmask[1] & FATTR4_WORD1_MOUNTED_ON_FILEID))
                attrs[0] |= FATTR4_WORD0_FILEID;
 
-       p = reserve_space(xdr, 12+NFS4_VERIFIER_SIZE+20);
-       *p++ = cpu_to_be32(OP_READDIR);
-       p = xdr_encode_hyper(p, readdir->cookie);
-       p = xdr_encode_opaque_fixed(p, readdir->verifier.data, NFS4_VERIFIER_SIZE);
+       encode_op_hdr(xdr, OP_READDIR, decode_readdir_maxsz, hdr);
+       encode_uint64(xdr, readdir->cookie);
+       encode_nfs4_verifier(xdr, &readdir->verifier);
+       p = reserve_space(xdr, 20);
        *p++ = cpu_to_be32(dircount);
        *p++ = cpu_to_be32(readdir->count);
        *p++ = cpu_to_be32(2);
 
        *p++ = cpu_to_be32(attrs[0] & readdir->bitmask[0]);
        *p = cpu_to_be32(attrs[1] & readdir->bitmask[1]);
-       hdr->nops++;
-       hdr->replen += decode_readdir_maxsz;
+       memcpy(verf, readdir->verifier.data, sizeof(verf));
        dprintk("%s: cookie = %Lu, verifier = %08x:%08x, bitmap = %08x:%08x\n",
                        __func__,
                        (unsigned long long)readdir->cookie,
-                       ((u32 *)readdir->verifier.data)[0],
-                       ((u32 *)readdir->verifier.data)[1],
+                       verf[0], verf[1],
                        attrs[0] & readdir->bitmask[0],
                        attrs[1] & readdir->bitmask[1]);
 }
 
 static void encode_readlink(struct xdr_stream *xdr, const struct nfs4_readlink *readlink, struct rpc_rqst *req, struct compound_hdr *hdr)
 {
-       __be32 *p;
-
-       p = reserve_space(xdr, 4);
-       *p = cpu_to_be32(OP_READLINK);
-       hdr->nops++;
-       hdr->replen += decode_readlink_maxsz;
+       encode_op_hdr(xdr, OP_READLINK, decode_readlink_maxsz, hdr);
 }
 
 static void encode_remove(struct xdr_stream *xdr, const struct qstr *name, struct compound_hdr *hdr)
 {
-       __be32 *p;
-
-       p = reserve_space(xdr, 8 + name->len);
-       *p++ = cpu_to_be32(OP_REMOVE);
-       xdr_encode_opaque(p, name->name, name->len);
-       hdr->nops++;
-       hdr->replen += decode_remove_maxsz;
+       encode_op_hdr(xdr, OP_REMOVE, decode_remove_maxsz, hdr);
+       encode_string(xdr, name->len, name->name);
 }
 
 static void encode_rename(struct xdr_stream *xdr, const struct qstr *oldname, const struct qstr *newname, struct compound_hdr *hdr)
 {
-       __be32 *p;
-
-       p = reserve_space(xdr, 4);
-       *p = cpu_to_be32(OP_RENAME);
+       encode_op_hdr(xdr, OP_RENAME, decode_rename_maxsz, hdr);
        encode_string(xdr, oldname->len, oldname->name);
        encode_string(xdr, newname->len, newname->name);
-       hdr->nops++;
-       hdr->replen += decode_rename_maxsz;
 }
 
-static void encode_renew(struct xdr_stream *xdr, const struct nfs_client *client_stateid, struct compound_hdr *hdr)
+static void encode_renew(struct xdr_stream *xdr, clientid4 clid,
+                        struct compound_hdr *hdr)
 {
-       __be32 *p;
-
-       p = reserve_space(xdr, 12);
-       *p++ = cpu_to_be32(OP_RENEW);
-       xdr_encode_hyper(p, client_stateid->cl_clientid);
-       hdr->nops++;
-       hdr->replen += decode_renew_maxsz;
+       encode_op_hdr(xdr, OP_RENEW, decode_renew_maxsz, hdr);
+       encode_uint64(xdr, clid);
 }
 
 static void
 encode_restorefh(struct xdr_stream *xdr, struct compound_hdr *hdr)
 {
-       __be32 *p;
-
-       p = reserve_space(xdr, 4);
-       *p = cpu_to_be32(OP_RESTOREFH);
-       hdr->nops++;
-       hdr->replen += decode_restorefh_maxsz;
+       encode_op_hdr(xdr, OP_RESTOREFH, decode_restorefh_maxsz, hdr);
 }
 
 static void
@@ -1647,9 +1599,8 @@ encode_setacl(struct xdr_stream *xdr, struct nfs_setaclargs *arg, struct compoun
 {
        __be32 *p;
 
-       p = reserve_space(xdr, 4+NFS4_STATEID_SIZE);
-       *p++ = cpu_to_be32(OP_SETATTR);
-       xdr_encode_opaque_fixed(p, zero_stateid.data, NFS4_STATEID_SIZE);
+       encode_op_hdr(xdr, OP_SETATTR, decode_setacl_maxsz, hdr);
+       encode_nfs4_stateid(xdr, &zero_stateid);
        p = reserve_space(xdr, 2*4);
        *p++ = cpu_to_be32(1);
        *p = cpu_to_be32(FATTR4_WORD0_ACL);
@@ -1657,30 +1608,18 @@ encode_setacl(struct xdr_stream *xdr, struct nfs_setaclargs *arg, struct compoun
        p = reserve_space(xdr, 4);
        *p = cpu_to_be32(arg->acl_len);
        xdr_write_pages(xdr, arg->acl_pages, arg->acl_pgbase, arg->acl_len);
-       hdr->nops++;
-       hdr->replen += decode_setacl_maxsz;
 }
 
 static void
 encode_savefh(struct xdr_stream *xdr, struct compound_hdr *hdr)
 {
-       __be32 *p;
-
-       p = reserve_space(xdr, 4);
-       *p = cpu_to_be32(OP_SAVEFH);
-       hdr->nops++;
-       hdr->replen += decode_savefh_maxsz;
+       encode_op_hdr(xdr, OP_SAVEFH, decode_savefh_maxsz, hdr);
 }
 
 static void encode_setattr(struct xdr_stream *xdr, const struct nfs_setattrargs *arg, const struct nfs_server *server, struct compound_hdr *hdr)
 {
-       __be32 *p;
-
-       p = reserve_space(xdr, 4+NFS4_STATEID_SIZE);
-       *p++ = cpu_to_be32(OP_SETATTR);
-       xdr_encode_opaque_fixed(p, arg->stateid.data, NFS4_STATEID_SIZE);
-       hdr->nops++;
-       hdr->replen += decode_setattr_maxsz;
+       encode_op_hdr(xdr, OP_SETATTR, decode_setattr_maxsz, hdr);
+       encode_nfs4_stateid(xdr, &arg->stateid);
        encode_attrs(xdr, arg->iap, server);
 }
 
@@ -1688,9 +1627,8 @@ static void encode_setclientid(struct xdr_stream *xdr, const struct nfs4_setclie
 {
        __be32 *p;
 
-       p = reserve_space(xdr, 4 + NFS4_VERIFIER_SIZE);
-       *p++ = cpu_to_be32(OP_SETCLIENTID);
-       xdr_encode_opaque_fixed(p, setclientid->sc_verifier->data, NFS4_VERIFIER_SIZE);
+       encode_op_hdr(xdr, OP_SETCLIENTID, decode_setclientid_maxsz, hdr);
+       encode_nfs4_verifier(xdr, setclientid->sc_verifier);
 
        encode_string(xdr, setclientid->sc_name_len, setclientid->sc_name);
        p = reserve_space(xdr, 4);
@@ -1699,31 +1637,23 @@ static void encode_setclientid(struct xdr_stream *xdr, const struct nfs4_setclie
        encode_string(xdr, setclientid->sc_uaddr_len, setclientid->sc_uaddr);
        p = reserve_space(xdr, 4);
        *p = cpu_to_be32(setclientid->sc_cb_ident);
-       hdr->nops++;
-       hdr->replen += decode_setclientid_maxsz;
 }
 
 static void encode_setclientid_confirm(struct xdr_stream *xdr, const struct nfs4_setclientid_res *arg, struct compound_hdr *hdr)
 {
-       __be32 *p;
-
-       p = reserve_space(xdr, 12 + NFS4_VERIFIER_SIZE);
-       *p++ = cpu_to_be32(OP_SETCLIENTID_CONFIRM);
-       p = xdr_encode_hyper(p, arg->clientid);
-       xdr_encode_opaque_fixed(p, arg->confirm.data, NFS4_VERIFIER_SIZE);
-       hdr->nops++;
-       hdr->replen += decode_setclientid_confirm_maxsz;
+       encode_op_hdr(xdr, OP_SETCLIENTID_CONFIRM,
+                       decode_setclientid_confirm_maxsz, hdr);
+       encode_uint64(xdr, arg->clientid);
+       encode_nfs4_verifier(xdr, &arg->confirm);
 }
 
 static void encode_write(struct xdr_stream *xdr, const struct nfs_writeargs *args, struct compound_hdr *hdr)
 {
        __be32 *p;
 
-       p = reserve_space(xdr, 4);
-       *p = cpu_to_be32(OP_WRITE);
-
-       encode_stateid(xdr, args->context, args->lock_context,
-                      hdr->minorversion);
+       encode_op_hdr(xdr, OP_WRITE, decode_write_maxsz, hdr);
+       encode_open_stateid(xdr, args->context, args->lock_context,
+                       FMODE_WRITE, hdr->minorversion);
 
        p = reserve_space(xdr, 16);
        p = xdr_encode_hyper(p, args->offset);
@@ -1731,32 +1661,18 @@ static void encode_write(struct xdr_stream *xdr, const struct nfs_writeargs *arg
        *p = cpu_to_be32(args->count);
 
        xdr_write_pages(xdr, args->pages, args->pgbase, args->count);
-       hdr->nops++;
-       hdr->replen += decode_write_maxsz;
 }
 
 static void encode_delegreturn(struct xdr_stream *xdr, const nfs4_stateid *stateid, struct compound_hdr *hdr)
 {
-       __be32 *p;
-
-       p = reserve_space(xdr, 4+NFS4_STATEID_SIZE);
-
-       *p++ = cpu_to_be32(OP_DELEGRETURN);
-       xdr_encode_opaque_fixed(p, stateid->data, NFS4_STATEID_SIZE);
-       hdr->nops++;
-       hdr->replen += decode_delegreturn_maxsz;
+       encode_op_hdr(xdr, OP_DELEGRETURN, decode_delegreturn_maxsz, hdr);
+       encode_nfs4_stateid(xdr, stateid);
 }
 
 static void encode_secinfo(struct xdr_stream *xdr, const struct qstr *name, struct compound_hdr *hdr)
 {
-       int len = name->len;
-       __be32 *p;
-
-       p = reserve_space(xdr, 8 + len);
-       *p++ = cpu_to_be32(OP_SECINFO);
-       xdr_encode_opaque(p, name->name, len);
-       hdr->nops++;
-       hdr->replen += decode_secinfo_maxsz;
+       encode_op_hdr(xdr, OP_SECINFO, decode_secinfo_maxsz, hdr);
+       encode_string(xdr, name->len, name->name);
 }
 
 #if defined(CONFIG_NFS_V4_1)
@@ -1766,19 +1682,39 @@ static void encode_exchange_id(struct xdr_stream *xdr,
                               struct compound_hdr *hdr)
 {
        __be32 *p;
+       char impl_name[NFS4_OPAQUE_LIMIT];
+       int len = 0;
 
-       p = reserve_space(xdr, 4 + sizeof(args->verifier->data));
-       *p++ = cpu_to_be32(OP_EXCHANGE_ID);
-       xdr_encode_opaque_fixed(p, args->verifier->data, sizeof(args->verifier->data));
+       encode_op_hdr(xdr, OP_EXCHANGE_ID, decode_exchange_id_maxsz, hdr);
+       encode_nfs4_verifier(xdr, args->verifier);
 
        encode_string(xdr, args->id_len, args->id);
 
        p = reserve_space(xdr, 12);
        *p++ = cpu_to_be32(args->flags);
        *p++ = cpu_to_be32(0);  /* zero length state_protect4_a */
-       *p = cpu_to_be32(0);    /* zero length implementation id array */
-       hdr->nops++;
-       hdr->replen += decode_exchange_id_maxsz;
+
+       if (send_implementation_id &&
+           sizeof(CONFIG_NFS_V4_1_IMPLEMENTATION_ID_DOMAIN) > 1 &&
+           sizeof(CONFIG_NFS_V4_1_IMPLEMENTATION_ID_DOMAIN)
+               <= NFS4_OPAQUE_LIMIT + 1)
+               len = snprintf(impl_name, sizeof(impl_name), "%s %s %s %s",
+                              utsname()->sysname, utsname()->release,
+                              utsname()->version, utsname()->machine);
+
+       if (len > 0) {
+               *p = cpu_to_be32(1);    /* implementation id array length=1 */
+
+               encode_string(xdr,
+                       sizeof(CONFIG_NFS_V4_1_IMPLEMENTATION_ID_DOMAIN) - 1,
+                       CONFIG_NFS_V4_1_IMPLEMENTATION_ID_DOMAIN);
+               encode_string(xdr, len, impl_name);
+               /* just send zeros for nii_date - the date is in nii_name */
+               p = reserve_space(xdr, 12);
+               p = xdr_encode_hyper(p, 0);
+               *p = cpu_to_be32(0);
+       } else
+               *p = cpu_to_be32(0);    /* implementation id array length=0 */
 }
 
 static void encode_create_session(struct xdr_stream *xdr,
@@ -1801,8 +1737,8 @@ static void encode_create_session(struct xdr_stream *xdr,
        len = scnprintf(machine_name, sizeof(machine_name), "%s",
                        clp->cl_ipaddr);
 
-       p = reserve_space(xdr, 20 + 2*28 + 20 + len + 12);
-       *p++ = cpu_to_be32(OP_CREATE_SESSION);
+       encode_op_hdr(xdr, OP_CREATE_SESSION, decode_create_session_maxsz, hdr);
+       p = reserve_space(xdr, 16 + 2*28 + 20 + len + 12);
        p = xdr_encode_hyper(p, clp->cl_clientid);
        *p++ = cpu_to_be32(clp->cl_seqid);                      /*Sequence id */
        *p++ = cpu_to_be32(args->flags);                        /*flags */
@@ -1835,33 +1771,22 @@ static void encode_create_session(struct xdr_stream *xdr,
        *p++ = cpu_to_be32(0);                          /* UID */
        *p++ = cpu_to_be32(0);                          /* GID */
        *p = cpu_to_be32(0);                            /* No more gids */
-       hdr->nops++;
-       hdr->replen += decode_create_session_maxsz;
 }
 
 static void encode_destroy_session(struct xdr_stream *xdr,
                                   struct nfs4_session *session,
                                   struct compound_hdr *hdr)
 {
-       __be32 *p;
-       p = reserve_space(xdr, 4 + NFS4_MAX_SESSIONID_LEN);
-       *p++ = cpu_to_be32(OP_DESTROY_SESSION);
-       xdr_encode_opaque_fixed(p, session->sess_id.data, NFS4_MAX_SESSIONID_LEN);
-       hdr->nops++;
-       hdr->replen += decode_destroy_session_maxsz;
+       encode_op_hdr(xdr, OP_DESTROY_SESSION, decode_destroy_session_maxsz, hdr);
+       encode_opaque_fixed(xdr, session->sess_id.data, NFS4_MAX_SESSIONID_LEN);
 }
 
 static void encode_reclaim_complete(struct xdr_stream *xdr,
                                    struct nfs41_reclaim_complete_args *args,
                                    struct compound_hdr *hdr)
 {
-       __be32 *p;
-
-       p = reserve_space(xdr, 8);
-       *p++ = cpu_to_be32(OP_RECLAIM_COMPLETE);
-       *p++ = cpu_to_be32(args->one_fs);
-       hdr->nops++;
-       hdr->replen += decode_reclaim_complete_maxsz;
+       encode_op_hdr(xdr, OP_RECLAIM_COMPLETE, decode_reclaim_complete_maxsz, hdr);
+       encode_uint32(xdr, args->one_fs);
 }
 #endif /* CONFIG_NFS_V4_1 */
 
@@ -1883,8 +1808,7 @@ static void encode_sequence(struct xdr_stream *xdr,
        WARN_ON(args->sa_slotid == NFS4_MAX_SLOT_TABLE);
        slot = tp->slots + args->sa_slotid;
 
-       p = reserve_space(xdr, 4 + NFS4_MAX_SESSIONID_LEN + 16);
-       *p++ = cpu_to_be32(OP_SEQUENCE);
+       encode_op_hdr(xdr, OP_SEQUENCE, decode_sequence_maxsz, hdr);
 
        /*
         * Sessionid + seqid + slotid + max slotid + cache_this
@@ -1898,13 +1822,12 @@ static void encode_sequence(struct xdr_stream *xdr,
                ((u32 *)session->sess_id.data)[3],
                slot->seq_nr, args->sa_slotid,
                tp->highest_used_slotid, args->sa_cache_this);
+       p = reserve_space(xdr, NFS4_MAX_SESSIONID_LEN + 16);
        p = xdr_encode_opaque_fixed(p, session->sess_id.data, NFS4_MAX_SESSIONID_LEN);
        *p++ = cpu_to_be32(slot->seq_nr);
        *p++ = cpu_to_be32(args->sa_slotid);
        *p++ = cpu_to_be32(tp->highest_used_slotid);
        *p = cpu_to_be32(args->sa_cache_this);
-       hdr->nops++;
-       hdr->replen += decode_sequence_maxsz;
 #endif /* CONFIG_NFS_V4_1 */
 }
 
@@ -1919,14 +1842,12 @@ encode_getdevicelist(struct xdr_stream *xdr,
                .data = "dummmmmy",
        };
 
-       p = reserve_space(xdr, 20);
-       *p++ = cpu_to_be32(OP_GETDEVICELIST);
+       encode_op_hdr(xdr, OP_GETDEVICELIST, decode_getdevicelist_maxsz, hdr);
+       p = reserve_space(xdr, 16);
        *p++ = cpu_to_be32(args->layoutclass);
        *p++ = cpu_to_be32(NFS4_PNFS_GETDEVLIST_MAXNUM);
        xdr_encode_hyper(p, 0ULL);                          /* cookie */
        encode_nfs4_verifier(xdr, &dummy);
-       hdr->nops++;
-       hdr->replen += decode_getdevicelist_maxsz;
 }
 
 static void
@@ -1936,15 +1857,13 @@ encode_getdeviceinfo(struct xdr_stream *xdr,
 {
        __be32 *p;
 
-       p = reserve_space(xdr, 16 + NFS4_DEVICEID4_SIZE);
-       *p++ = cpu_to_be32(OP_GETDEVICEINFO);
+       encode_op_hdr(xdr, OP_GETDEVICEINFO, decode_getdeviceinfo_maxsz, hdr);
+       p = reserve_space(xdr, 12 + NFS4_DEVICEID4_SIZE);
        p = xdr_encode_opaque_fixed(p, args->pdev->dev_id.data,
                                    NFS4_DEVICEID4_SIZE);
        *p++ = cpu_to_be32(args->pdev->layout_type);
        *p++ = cpu_to_be32(args->pdev->pglen);          /* gdia_maxcount */
        *p++ = cpu_to_be32(0);                          /* bitmap length 0 */
-       hdr->nops++;
-       hdr->replen += decode_getdeviceinfo_maxsz;
 }
 
 static void
@@ -1954,16 +1873,16 @@ encode_layoutget(struct xdr_stream *xdr,
 {
        __be32 *p;
 
-       p = reserve_space(xdr, 44 + NFS4_STATEID_SIZE);
-       *p++ = cpu_to_be32(OP_LAYOUTGET);
+       encode_op_hdr(xdr, OP_LAYOUTGET, decode_layoutget_maxsz, hdr);
+       p = reserve_space(xdr, 36);
        *p++ = cpu_to_be32(0);     /* Signal layout available */
        *p++ = cpu_to_be32(args->type);
        *p++ = cpu_to_be32(args->range.iomode);
        p = xdr_encode_hyper(p, args->range.offset);
        p = xdr_encode_hyper(p, args->range.length);
        p = xdr_encode_hyper(p, args->minlength);
-       p = xdr_encode_opaque_fixed(p, &args->stateid.data, NFS4_STATEID_SIZE);
-       *p = cpu_to_be32(args->maxcount);
+       encode_nfs4_stateid(xdr, &args->stateid);
+       encode_uint32(xdr, args->maxcount);
 
        dprintk("%s: 1st type:0x%x iomode:%d off:%lu len:%lu mc:%d\n",
                __func__,
@@ -1972,8 +1891,6 @@ encode_layoutget(struct xdr_stream *xdr,
                (unsigned long)args->range.offset,
                (unsigned long)args->range.length,
                args->maxcount);
-       hdr->nops++;
-       hdr->replen += decode_layoutget_maxsz;
 }
 
 static int
@@ -1987,13 +1904,14 @@ encode_layoutcommit(struct xdr_stream *xdr,
        dprintk("%s: lbw: %llu type: %d\n", __func__, args->lastbytewritten,
                NFS_SERVER(args->inode)->pnfs_curr_ld->id);
 
-       p = reserve_space(xdr, 44 + NFS4_STATEID_SIZE);
-       *p++ = cpu_to_be32(OP_LAYOUTCOMMIT);
+       encode_op_hdr(xdr, OP_LAYOUTCOMMIT, decode_layoutcommit_maxsz, hdr);
+       p = reserve_space(xdr, 20);
        /* Only whole file layouts */
        p = xdr_encode_hyper(p, 0); /* offset */
        p = xdr_encode_hyper(p, args->lastbytewritten + 1);     /* length */
-       *p++ = cpu_to_be32(0); /* reclaim */
-       p = xdr_encode_opaque_fixed(p, args->stateid.data, NFS4_STATEID_SIZE);
+       *p = cpu_to_be32(0); /* reclaim */
+       encode_nfs4_stateid(xdr, &args->stateid);
+       p = reserve_space(xdr, 20);
        *p++ = cpu_to_be32(1); /* newoffset = TRUE */
        p = xdr_encode_hyper(p, args->lastbytewritten);
        *p++ = cpu_to_be32(0); /* Never send time_modify_changed */
@@ -2002,13 +1920,9 @@ encode_layoutcommit(struct xdr_stream *xdr,
        if (NFS_SERVER(inode)->pnfs_curr_ld->encode_layoutcommit)
                NFS_SERVER(inode)->pnfs_curr_ld->encode_layoutcommit(
                        NFS_I(inode)->layout, xdr, args);
-       else {
-               p = reserve_space(xdr, 4);
-               *p = cpu_to_be32(0); /* no layout-type payload */
-       }
+       else
+               encode_uint32(xdr, 0); /* no layout-type payload */
 
-       hdr->nops++;
-       hdr->replen += decode_layoutcommit_maxsz;
        return 0;
 }
 
@@ -2019,27 +1933,23 @@ encode_layoutreturn(struct xdr_stream *xdr,
 {
        __be32 *p;
 
-       p = reserve_space(xdr, 20);
-       *p++ = cpu_to_be32(OP_LAYOUTRETURN);
+       encode_op_hdr(xdr, OP_LAYOUTRETURN, decode_layoutreturn_maxsz, hdr);
+       p = reserve_space(xdr, 16);
        *p++ = cpu_to_be32(0);          /* reclaim. always 0 for now */
        *p++ = cpu_to_be32(args->layout_type);
        *p++ = cpu_to_be32(IOMODE_ANY);
        *p = cpu_to_be32(RETURN_FILE);
-       p = reserve_space(xdr, 16 + NFS4_STATEID_SIZE);
+       p = reserve_space(xdr, 16);
        p = xdr_encode_hyper(p, 0);
        p = xdr_encode_hyper(p, NFS4_MAX_UINT64);
        spin_lock(&args->inode->i_lock);
-       xdr_encode_opaque_fixed(p, &args->stateid.data, NFS4_STATEID_SIZE);
+       encode_nfs4_stateid(xdr, &args->stateid);
        spin_unlock(&args->inode->i_lock);
        if (NFS_SERVER(args->inode)->pnfs_curr_ld->encode_layoutreturn) {
                NFS_SERVER(args->inode)->pnfs_curr_ld->encode_layoutreturn(
                        NFS_I(args->inode)->layout, xdr, args);
-       } else {
-               p = reserve_space(xdr, 4);
-               *p = cpu_to_be32(0);
-       }
-       hdr->nops++;
-       hdr->replen += decode_layoutreturn_maxsz;
+       } else
+               encode_uint32(xdr, 0);
 }
 
 static int
@@ -2047,12 +1957,8 @@ encode_secinfo_no_name(struct xdr_stream *xdr,
                       const struct nfs41_secinfo_no_name_args *args,
                       struct compound_hdr *hdr)
 {
-       __be32 *p;
-       p = reserve_space(xdr, 8);
-       *p++ = cpu_to_be32(OP_SECINFO_NO_NAME);
-       *p++ = cpu_to_be32(args->style);
-       hdr->nops++;
-       hdr->replen += decode_secinfo_no_name_maxsz;
+       encode_op_hdr(xdr, OP_SECINFO_NO_NAME, decode_secinfo_no_name_maxsz, hdr);
+       encode_uint32(xdr, args->style);
        return 0;
 }
 
@@ -2060,26 +1966,17 @@ static void encode_test_stateid(struct xdr_stream *xdr,
                                struct nfs41_test_stateid_args *args,
                                struct compound_hdr *hdr)
 {
-       __be32 *p;
-
-       p = reserve_space(xdr, 8 + NFS4_STATEID_SIZE);
-       *p++ = cpu_to_be32(OP_TEST_STATEID);
-       *p++ = cpu_to_be32(1);
-       xdr_encode_opaque_fixed(p, args->stateid->data, NFS4_STATEID_SIZE);
-       hdr->nops++;
-       hdr->replen += decode_test_stateid_maxsz;
+       encode_op_hdr(xdr, OP_TEST_STATEID, decode_test_stateid_maxsz, hdr);
+       encode_uint32(xdr, 1);
+       encode_nfs4_stateid(xdr, args->stateid);
 }
 
 static void encode_free_stateid(struct xdr_stream *xdr,
                                struct nfs41_free_stateid_args *args,
                                struct compound_hdr *hdr)
 {
-       __be32 *p;
-       p = reserve_space(xdr, 4 + NFS4_STATEID_SIZE);
-       *p++ = cpu_to_be32(OP_FREE_STATEID);
-       xdr_encode_opaque_fixed(p, args->stateid->data, NFS4_STATEID_SIZE);
-       hdr->nops++;
-       hdr->replen += decode_free_stateid_maxsz;
+       encode_op_hdr(xdr, OP_FREE_STATEID, decode_free_stateid_maxsz, hdr);
+       encode_nfs4_stateid(xdr, args->stateid);
 }
 #endif /* CONFIG_NFS_V4_1 */
 
@@ -2633,6 +2530,7 @@ static void nfs4_xdr_enc_server_caps(struct rpc_rqst *req,
        encode_sequence(xdr, &args->seq_args, &hdr);
        encode_putfh(xdr, args->fhandle, &hdr);
        encode_getattr_one(xdr, FATTR4_WORD0_SUPPORTED_ATTRS|
+                          FATTR4_WORD0_FH_EXPIRE_TYPE|
                           FATTR4_WORD0_LINK_SUPPORT|
                           FATTR4_WORD0_SYMLINK_SUPPORT|
                           FATTR4_WORD0_ACLSUPPORT, &hdr);
@@ -2650,7 +2548,7 @@ static void nfs4_xdr_enc_renew(struct rpc_rqst *req, struct xdr_stream *xdr,
        };
 
        encode_compound_hdr(xdr, req, &hdr);
-       encode_renew(xdr, clp, &hdr);
+       encode_renew(xdr, clp->cl_clientid, &hdr);
        encode_nops(&hdr);
 }
 
@@ -3180,6 +3078,28 @@ out_overflow:
        return -EIO;
 }
 
+static int decode_attr_fh_expire_type(struct xdr_stream *xdr,
+                                     uint32_t *bitmap, uint32_t *type)
+{
+       __be32 *p;
+
+       *type = 0;
+       if (unlikely(bitmap[0] & (FATTR4_WORD0_FH_EXPIRE_TYPE - 1U)))
+               return -EIO;
+       if (likely(bitmap[0] & FATTR4_WORD0_FH_EXPIRE_TYPE)) {
+               p = xdr_inline_decode(xdr, 4);
+               if (unlikely(!p))
+                       goto out_overflow;
+               *type = be32_to_cpup(p);
+               bitmap[0] &= ~FATTR4_WORD0_FH_EXPIRE_TYPE;
+       }
+       dprintk("%s: expire type=0x%x\n", __func__, *type);
+       return 0;
+out_overflow:
+       print_overflow_msg(__func__, xdr);
+       return -EIO;
+}
+
 static int decode_attr_change(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *change)
 {
        __be32 *p;
@@ -3513,16 +3433,17 @@ static int decode_pathname(struct xdr_stream *xdr, struct nfs4_pathname *path)
        n = be32_to_cpup(p);
        if (n == 0)
                goto root_path;
-       dprintk("path ");
+       dprintk("pathname4: ");
        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);
+               ifdebug (XDR)
+                       pr_cont("%s%.*s ",
+                               (path->ncomponents != n ? "/ " : ""),
+                               component->len, component->data);
                if (path->ncomponents < NFS4_PATHNAME_MAXCOMPONENTS)
                        path->ncomponents++;
                else {
@@ -3531,14 +3452,13 @@ static int decode_pathname(struct xdr_stream *xdr, struct nfs4_pathname *path)
                }
        }
 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");
+       dprintk("pathname4: /\n");
        goto out;
 out_eio:
        dprintk(" status %d", status);
@@ -3560,7 +3480,11 @@ static int decode_attr_fs_locations(struct xdr_stream *xdr, uint32_t *bitmap, st
        status = 0;
        if (unlikely(!(bitmap[0] & FATTR4_WORD0_FS_LOCATIONS)))
                goto out;
-       dprintk("%s: fsroot ", __func__);
+       status = -EIO;
+       /* Ignore borken servers that return unrequested attrs */
+       if (unlikely(res == NULL))
+               goto out;
+       dprintk("%s: fsroot:\n", __func__);
        status = decode_pathname(xdr, &res->fs_path);
        if (unlikely(status != 0))
                goto out;
@@ -3581,7 +3505,7 @@ static int decode_attr_fs_locations(struct xdr_stream *xdr, uint32_t *bitmap, st
                m = be32_to_cpup(p);
 
                loc->nservers = 0;
-               dprintk("%s: servers ", __func__);
+               dprintk("%s: servers:\n", __func__);
                while (loc->nservers < m) {
                        struct nfs4_string *server = &loc->servers[loc->nservers];
                        status = decode_opaque_inline(xdr, &server->len, &server->data);
@@ -3613,7 +3537,7 @@ static int decode_attr_fs_locations(struct xdr_stream *xdr, uint32_t *bitmap, st
                        res->nlocations++;
        }
        if (res->nlocations != 0)
-               status = NFS_ATTR_FATTR_V4_REFERRAL;
+               status = NFS_ATTR_FATTR_V4_LOCATIONS;
 out:
        dprintk("%s: fs_locations done, error = %d\n", __func__, status);
        return status;
@@ -4157,7 +4081,7 @@ static int decode_opaque_fixed(struct xdr_stream *xdr, void *buf, size_t len)
 
 static int decode_stateid(struct xdr_stream *xdr, nfs4_stateid *stateid)
 {
-       return decode_opaque_fixed(xdr, stateid->data, NFS4_STATEID_SIZE);
+       return decode_opaque_fixed(xdr, stateid, NFS4_STATEID_SIZE);
 }
 
 static int decode_close(struct xdr_stream *xdr, struct nfs_closeres *res)
@@ -4174,7 +4098,7 @@ static int decode_close(struct xdr_stream *xdr, struct nfs_closeres *res)
 
 static int decode_verifier(struct xdr_stream *xdr, void *verifier)
 {
-       return decode_opaque_fixed(xdr, verifier, 8);
+       return decode_opaque_fixed(xdr, verifier, NFS4_VERIFIER_SIZE);
 }
 
 static int decode_commit(struct xdr_stream *xdr, struct nfs_writeres *res)
@@ -4224,6 +4148,9 @@ static int decode_server_caps(struct xdr_stream *xdr, struct nfs4_server_caps_re
                goto xdr_error;
        if ((status = decode_attr_supported(xdr, bitmap, res->attr_bitmask)) != 0)
                goto xdr_error;
+       if ((status = decode_attr_fh_expire_type(xdr, bitmap,
+                                                &res->fh_expire_type)) != 0)
+               goto xdr_error;
        if ((status = decode_attr_link_support(xdr, bitmap, &res->has_links)) != 0)
                goto xdr_error;
        if ((status = decode_attr_symlink_support(xdr, bitmap, &res->has_symlinks)) != 0)
@@ -4294,6 +4221,7 @@ xdr_error:
 
 static int decode_getfattr_attrs(struct xdr_stream *xdr, uint32_t *bitmap,
                struct nfs_fattr *fattr, struct nfs_fh *fh,
+               struct nfs4_fs_locations *fs_loc,
                const struct nfs_server *server)
 {
        int status;
@@ -4341,9 +4269,7 @@ static int decode_getfattr_attrs(struct xdr_stream *xdr, uint32_t *bitmap,
                goto xdr_error;
        fattr->valid |= status;
 
-       status = decode_attr_fs_locations(xdr, bitmap, container_of(fattr,
-                                               struct nfs4_fs_locations,
-                                               fattr));
+       status = decode_attr_fs_locations(xdr, bitmap, fs_loc);
        if (status < 0)
                goto xdr_error;
        fattr->valid |= status;
@@ -4407,7 +4333,8 @@ xdr_error:
 }
 
 static int decode_getfattr_generic(struct xdr_stream *xdr, struct nfs_fattr *fattr,
-               struct nfs_fh *fh, const struct nfs_server *server)
+               struct nfs_fh *fh, struct nfs4_fs_locations *fs_loc,
+               const struct nfs_server *server)
 {
        __be32 *savep;
        uint32_t attrlen,
@@ -4426,7 +4353,7 @@ static int decode_getfattr_generic(struct xdr_stream *xdr, struct nfs_fattr *fat
        if (status < 0)
                goto xdr_error;
 
-       status = decode_getfattr_attrs(xdr, bitmap, fattr, fh, server);
+       status = decode_getfattr_attrs(xdr, bitmap, fattr, fh, fs_loc, server);
        if (status < 0)
                goto xdr_error;
 
@@ -4439,7 +4366,7 @@ xdr_error:
 static int decode_getfattr(struct xdr_stream *xdr, struct nfs_fattr *fattr,
                const struct nfs_server *server)
 {
-       return decode_getfattr_generic(xdr, fattr, NULL, server);
+       return decode_getfattr_generic(xdr, fattr, NULL, NULL, server);
 }
 
 /*
@@ -4463,8 +4390,8 @@ static int decode_first_pnfs_layout_type(struct xdr_stream *xdr,
                return 0;
        }
        if (num > 1)
-               printk(KERN_INFO "%s: Warning: Multiple pNFS layout drivers "
-                       "per filesystem not supported\n", __func__);
+               printk(KERN_INFO "NFS: %s: Warning: Multiple pNFS layout "
+                       "drivers per filesystem not supported\n", __func__);
 
        /* Decode and set first layout type, move xdr->p past unused types */
        p = xdr_inline_decode(xdr, num * 4);
@@ -4863,17 +4790,16 @@ static int decode_readdir(struct xdr_stream *xdr, struct rpc_rqst *req, struct n
        size_t          hdrlen;
        u32             recvd, pglen = rcvbuf->page_len;
        int             status;
+       __be32          verf[2];
 
        status = decode_op_hdr(xdr, OP_READDIR);
        if (!status)
                status = decode_verifier(xdr, readdir->verifier.data);
        if (unlikely(status))
                return status;
+       memcpy(verf, readdir->verifier.data, sizeof(verf));
        dprintk("%s: verifier = %08x:%08x\n",
-                       __func__,
-                       ((u32 *)readdir->verifier.data)[0],
-                       ((u32 *)readdir->verifier.data)[1]);
-
+                       __func__, verf[0], verf[1]);
 
        hdrlen = (char *) xdr->p - (char *) iov->iov_base;
        recvd = rcvbuf->len - hdrlen;
@@ -5120,7 +5046,7 @@ static int decode_write(struct xdr_stream *xdr, struct nfs_writeres *res)
                goto out_overflow;
        res->count = be32_to_cpup(p++);
        res->verf->committed = be32_to_cpup(p++);
-       memcpy(res->verf->verifier, p, 8);
+       memcpy(res->verf->verifier, p, NFS4_VERIFIER_SIZE);
        return 0;
 out_overflow:
        print_overflow_msg(__func__, xdr);
@@ -5214,6 +5140,7 @@ static int decode_exchange_id(struct xdr_stream *xdr,
        char *dummy_str;
        int status;
        struct nfs_client *clp = res->client;
+       uint32_t impl_id_count;
 
        status = decode_op_hdr(xdr, OP_EXCHANGE_ID);
        if (status)
@@ -5255,11 +5182,38 @@ static int decode_exchange_id(struct xdr_stream *xdr,
        memcpy(res->server_scope->server_scope, dummy_str, dummy);
        res->server_scope->server_scope_sz = dummy;
 
-       /* Throw away Implementation id array */
-       status = decode_opaque_inline(xdr, &dummy, &dummy_str);
-       if (unlikely(status))
-               return status;
+       /* Implementation Id */
+       p = xdr_inline_decode(xdr, 4);
+       if (unlikely(!p))
+               goto out_overflow;
+       impl_id_count = be32_to_cpup(p++);
+
+       if (impl_id_count) {
+               /* nii_domain */
+               status = decode_opaque_inline(xdr, &dummy, &dummy_str);
+               if (unlikely(status))
+                       return status;
+               if (unlikely(dummy > NFS4_OPAQUE_LIMIT))
+                       return -EIO;
+               memcpy(res->impl_id->domain, dummy_str, dummy);
 
+               /* nii_name */
+               status = decode_opaque_inline(xdr, &dummy, &dummy_str);
+               if (unlikely(status))
+                       return status;
+               if (unlikely(dummy > NFS4_OPAQUE_LIMIT))
+                       return -EIO;
+               memcpy(res->impl_id->name, dummy_str, dummy);
+
+               /* nii_date */
+               p = xdr_inline_decode(xdr, 12);
+               if (unlikely(!p))
+                       goto out_overflow;
+               p = xdr_decode_hyper(p, &res->impl_id->date.seconds);
+               res->impl_id->date.nseconds = be32_to_cpup(p);
+
+               /* if there's more than one entry, ignore the rest */
+       }
        return 0;
 out_overflow:
        print_overflow_msg(__func__, xdr);
@@ -5285,8 +5239,8 @@ static int decode_chan_attrs(struct xdr_stream *xdr,
        attrs->max_reqs = be32_to_cpup(p++);
        nr_attrs = be32_to_cpup(p);
        if (unlikely(nr_attrs > 1)) {
-               printk(KERN_WARNING "%s: Invalid rdma channel attrs count %u\n",
-                       __func__, nr_attrs);
+               printk(KERN_WARNING "NFS: %s: Invalid rdma channel attrs "
+                       "count %u\n", __func__, nr_attrs);
                return -EINVAL;
        }
        if (nr_attrs == 1) {
@@ -5436,14 +5390,14 @@ static int decode_getdevicelist(struct xdr_stream *xdr,
        p += 2;
 
        /* Read verifier */
-       p = xdr_decode_opaque_fixed(p, verftemp.verifier, 8);
+       p = xdr_decode_opaque_fixed(p, verftemp.verifier, NFS4_VERIFIER_SIZE);
 
        res->num_devs = be32_to_cpup(p);
 
        dprintk("%s: num_dev %d\n", __func__, res->num_devs);
 
        if (res->num_devs > NFS4_PNFS_GETDEVLIST_MAXNUM) {
-               printk(KERN_ERR "%s too many result dev_num %u\n",
+               printk(KERN_ERR "NFS: %s too many result dev_num %u\n",
                                __func__, res->num_devs);
                return -EIO;
        }
@@ -5537,11 +5491,14 @@ static int decode_layoutget(struct xdr_stream *xdr, struct rpc_rqst *req,
        status = decode_op_hdr(xdr, OP_LAYOUTGET);
        if (status)
                return status;
-       p = xdr_inline_decode(xdr, 8 + NFS4_STATEID_SIZE);
+       p = xdr_inline_decode(xdr, 4);
+       if (unlikely(!p))
+               goto out_overflow;
+       res->return_on_close = be32_to_cpup(p);
+       decode_stateid(xdr, &res->stateid);
+       p = xdr_inline_decode(xdr, 4);
        if (unlikely(!p))
                goto out_overflow;
-       res->return_on_close = be32_to_cpup(p++);
-       p = xdr_decode_opaque_fixed(p, res->stateid.data, NFS4_STATEID_SIZE);
        layout_count = be32_to_cpup(p);
        if (!layout_count) {
                dprintk("%s: server responded with empty layout array\n",
@@ -5666,7 +5623,8 @@ static int decode_test_stateid(struct xdr_stream *xdr,
        if (unlikely(!p))
                goto out_overflow;
        res->status = be32_to_cpup(p++);
-       return res->status;
+
+       return status;
 out_overflow:
        print_overflow_msg(__func__, xdr);
 out:
@@ -6583,8 +6541,9 @@ static int nfs4_xdr_dec_fs_locations(struct rpc_rqst *req,
        if (status)
                goto out;
        xdr_enter_page(xdr, PAGE_SIZE);
-       status = decode_getfattr(xdr, &res->fs_locations->fattr,
-                                res->fs_locations->server);
+       status = decode_getfattr_generic(xdr, &res->fs_locations->fattr,
+                                        NULL, res->fs_locations,
+                                        res->fs_locations->server);
 out:
        return status;
 }
@@ -6964,7 +6923,7 @@ int nfs4_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry,
                goto out_overflow;
 
        if (decode_getfattr_attrs(xdr, bitmap, entry->fattr, entry->fh,
-                                       entry->server) < 0)
+                                 NULL, entry->server) < 0)
                goto out_overflow;
        if (entry->fattr->valid & NFS_ATTR_FATTR_MOUNTED_ON_FILEID)
                entry->ino = entry->fattr->mounted_on_fileid;
@@ -7112,7 +7071,7 @@ struct rpc_procinfo       nfs4_procedures[] = {
 #endif /* CONFIG_NFS_V4_1 */
 };
 
-struct rpc_version             nfs_version4 = {
+const struct rpc_version nfs_version4 = {
        .number                 = 4,
        .nrprocs                = ARRAY_SIZE(nfs4_procedures),
        .procs                  = nfs4_procedures