diff options
Diffstat (limited to 'fs/nfs/nfs4xdr.c')
| -rw-r--r-- | fs/nfs/nfs4xdr.c | 702 | 
1 files changed, 332 insertions, 370 deletions
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 95e92e43840..c74fdb114b4 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -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 */ @@ -2522,7 +2419,6 @@ static void nfs4_xdr_enc_getacl(struct rpc_rqst *req, struct xdr_stream *xdr,  	xdr_inline_pages(&req->rq_rcv_buf, replen << 2,  		args->acl_pages, args->acl_pgbase, args->acl_len); -	xdr_set_scratch_buffer(xdr, page_address(args->acl_scratch), PAGE_SIZE);  	encode_nops(&hdr);  } @@ -2634,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); @@ -2651,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);  } @@ -3181,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; @@ -3514,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 { @@ -3532,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); @@ -3561,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; @@ -3582,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); @@ -3614,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; @@ -4158,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) @@ -4175,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) @@ -4225,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) @@ -4295,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; @@ -4342,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; @@ -4408,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, @@ -4427,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; @@ -4440,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);  }  /* @@ -4464,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); @@ -4864,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; @@ -5121,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); @@ -5215,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) @@ -5256,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); @@ -5286,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) { @@ -5437,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;  	} @@ -5538,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", @@ -5667,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: @@ -6032,6 +5989,10 @@ nfs4_xdr_dec_getacl(struct rpc_rqst *rqstp, struct xdr_stream *xdr,  	struct compound_hdr hdr;  	int status; +	if (res->acl_scratch != NULL) { +		void *p = page_address(res->acl_scratch); +		xdr_set_scratch_buffer(xdr, p, PAGE_SIZE); +	}  	status = decode_compound_hdr(xdr, &hdr);  	if (status)  		goto out; @@ -6580,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;  } @@ -6961,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; @@ -7109,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  |