xref: /openbmc/linux/fs/nfs/nfs3xdr.c (revision d9c407b1)
11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds  * linux/fs/nfs/nfs3xdr.c
31da177e4SLinus Torvalds  *
41da177e4SLinus Torvalds  * XDR functions to encode/decode NFSv3 RPC arguments and results.
51da177e4SLinus Torvalds  *
61da177e4SLinus Torvalds  * Copyright (C) 1996, 1997 Olaf Kirch
71da177e4SLinus Torvalds  */
81da177e4SLinus Torvalds 
91da177e4SLinus Torvalds #include <linux/param.h>
101da177e4SLinus Torvalds #include <linux/time.h>
111da177e4SLinus Torvalds #include <linux/mm.h>
121da177e4SLinus Torvalds #include <linux/errno.h>
131da177e4SLinus Torvalds #include <linux/string.h>
141da177e4SLinus Torvalds #include <linux/in.h>
151da177e4SLinus Torvalds #include <linux/pagemap.h>
161da177e4SLinus Torvalds #include <linux/proc_fs.h>
171da177e4SLinus Torvalds #include <linux/kdev_t.h>
181da177e4SLinus Torvalds #include <linux/sunrpc/clnt.h>
191da177e4SLinus Torvalds #include <linux/nfs.h>
201da177e4SLinus Torvalds #include <linux/nfs3.h>
211da177e4SLinus Torvalds #include <linux/nfs_fs.h>
22b7fa0554SAndreas Gruenbacher #include <linux/nfsacl.h>
23f7b422b1SDavid Howells #include "internal.h"
241da177e4SLinus Torvalds 
251da177e4SLinus Torvalds #define NFSDBG_FACILITY		NFSDBG_XDR
261da177e4SLinus Torvalds 
271da177e4SLinus Torvalds /* Mapping from NFS error code to "errno" error code. */
281da177e4SLinus Torvalds #define errno_NFSERR_IO		EIO
291da177e4SLinus Torvalds 
301da177e4SLinus Torvalds /*
311da177e4SLinus Torvalds  * Declare the space requirements for NFS arguments and replies as
321da177e4SLinus Torvalds  * number of 32bit-words
331da177e4SLinus Torvalds  */
341da177e4SLinus Torvalds #define NFS3_fhandle_sz		(1+16)
351da177e4SLinus Torvalds #define NFS3_fh_sz		(NFS3_fhandle_sz)	/* shorthand */
361da177e4SLinus Torvalds #define NFS3_sattr_sz		(15)
371da177e4SLinus Torvalds #define NFS3_filename_sz	(1+(NFS3_MAXNAMLEN>>2))
381da177e4SLinus Torvalds #define NFS3_path_sz		(1+(NFS3_MAXPATHLEN>>2))
391da177e4SLinus Torvalds #define NFS3_fattr_sz		(21)
40d9c407b1SChuck Lever #define NFS3_cookieverf_sz	(NFS3_COOKIEVERFSIZE>>2)
411da177e4SLinus Torvalds #define NFS3_wcc_attr_sz		(6)
421da177e4SLinus Torvalds #define NFS3_pre_op_attr_sz	(1+NFS3_wcc_attr_sz)
431da177e4SLinus Torvalds #define NFS3_post_op_attr_sz	(1+NFS3_fattr_sz)
441da177e4SLinus Torvalds #define NFS3_wcc_data_sz		(NFS3_pre_op_attr_sz+NFS3_post_op_attr_sz)
451da177e4SLinus Torvalds #define NFS3_fsstat_sz
461da177e4SLinus Torvalds #define NFS3_fsinfo_sz
471da177e4SLinus Torvalds #define NFS3_pathconf_sz
481da177e4SLinus Torvalds #define NFS3_entry_sz		(NFS3_filename_sz+3)
491da177e4SLinus Torvalds 
501da177e4SLinus Torvalds #define NFS3_sattrargs_sz	(NFS3_fh_sz+NFS3_sattr_sz+3)
511da177e4SLinus Torvalds #define NFS3_diropargs_sz	(NFS3_fh_sz+NFS3_filename_sz)
524fdc17b2STrond Myklebust #define NFS3_removeargs_sz	(NFS3_fh_sz+NFS3_filename_sz)
531da177e4SLinus Torvalds #define NFS3_accessargs_sz	(NFS3_fh_sz+1)
541da177e4SLinus Torvalds #define NFS3_readlinkargs_sz	(NFS3_fh_sz)
551da177e4SLinus Torvalds #define NFS3_readargs_sz	(NFS3_fh_sz+3)
561da177e4SLinus Torvalds #define NFS3_writeargs_sz	(NFS3_fh_sz+5)
571da177e4SLinus Torvalds #define NFS3_createargs_sz	(NFS3_diropargs_sz+NFS3_sattr_sz)
581da177e4SLinus Torvalds #define NFS3_mkdirargs_sz	(NFS3_diropargs_sz+NFS3_sattr_sz)
5994a6d753SChuck Lever #define NFS3_symlinkargs_sz	(NFS3_diropargs_sz+1+NFS3_sattr_sz)
601da177e4SLinus Torvalds #define NFS3_mknodargs_sz	(NFS3_diropargs_sz+2+NFS3_sattr_sz)
611da177e4SLinus Torvalds #define NFS3_renameargs_sz	(NFS3_diropargs_sz+NFS3_diropargs_sz)
621da177e4SLinus Torvalds #define NFS3_linkargs_sz		(NFS3_fh_sz+NFS3_diropargs_sz)
63d9c407b1SChuck Lever #define NFS3_readdirargs_sz	(NFS3_fh_sz+NFS3_cookieverf_sz+3)
64d9c407b1SChuck Lever #define NFS3_readdirplusargs_sz	(NFS3_fh_sz+NFS3_cookieverf_sz+4)
651da177e4SLinus Torvalds #define NFS3_commitargs_sz	(NFS3_fh_sz+3)
661da177e4SLinus Torvalds 
671da177e4SLinus Torvalds #define NFS3_attrstat_sz	(1+NFS3_fattr_sz)
681da177e4SLinus Torvalds #define NFS3_wccstat_sz		(1+NFS3_wcc_data_sz)
694fdc17b2STrond Myklebust #define NFS3_removeres_sz	(NFS3_wccstat_sz)
701da177e4SLinus Torvalds #define NFS3_lookupres_sz	(1+NFS3_fh_sz+(2 * NFS3_post_op_attr_sz))
711da177e4SLinus Torvalds #define NFS3_accessres_sz	(1+NFS3_post_op_attr_sz+1)
721da177e4SLinus Torvalds #define NFS3_readlinkres_sz	(1+NFS3_post_op_attr_sz+1)
731da177e4SLinus Torvalds #define NFS3_readres_sz		(1+NFS3_post_op_attr_sz+3)
741da177e4SLinus Torvalds #define NFS3_writeres_sz	(1+NFS3_wcc_data_sz+4)
751da177e4SLinus Torvalds #define NFS3_createres_sz	(1+NFS3_fh_sz+NFS3_post_op_attr_sz+NFS3_wcc_data_sz)
761da177e4SLinus Torvalds #define NFS3_renameres_sz	(1+(2 * NFS3_wcc_data_sz))
771da177e4SLinus Torvalds #define NFS3_linkres_sz		(1+NFS3_post_op_attr_sz+NFS3_wcc_data_sz)
781da177e4SLinus Torvalds #define NFS3_readdirres_sz	(1+NFS3_post_op_attr_sz+2)
791da177e4SLinus Torvalds #define NFS3_fsstatres_sz	(1+NFS3_post_op_attr_sz+13)
801da177e4SLinus Torvalds #define NFS3_fsinfores_sz	(1+NFS3_post_op_attr_sz+12)
811da177e4SLinus Torvalds #define NFS3_pathconfres_sz	(1+NFS3_post_op_attr_sz+6)
821da177e4SLinus Torvalds #define NFS3_commitres_sz	(1+NFS3_wcc_data_sz+2)
831da177e4SLinus Torvalds 
84b7fa0554SAndreas Gruenbacher #define ACL3_getaclargs_sz	(NFS3_fh_sz+1)
85ae46141fSTrond Myklebust #define ACL3_setaclargs_sz	(NFS3_fh_sz+1+ \
86ae46141fSTrond Myklebust 				XDR_QUADLEN(NFS_ACL_INLINE_BUFSIZE))
87ae46141fSTrond Myklebust #define ACL3_getaclres_sz	(1+NFS3_post_op_attr_sz+1+ \
88ae46141fSTrond Myklebust 				XDR_QUADLEN(NFS_ACL_INLINE_BUFSIZE))
89b7fa0554SAndreas Gruenbacher #define ACL3_setaclres_sz	(1+NFS3_post_op_attr_sz)
90b7fa0554SAndreas Gruenbacher 
911da177e4SLinus Torvalds /*
921da177e4SLinus Torvalds  * Map file type to S_IFMT bits
931da177e4SLinus Torvalds  */
94bca79478STrond Myklebust static const umode_t nfs_type2fmt[] = {
95bca79478STrond Myklebust 	[NF3BAD] = 0,
96bca79478STrond Myklebust 	[NF3REG] = S_IFREG,
97bca79478STrond Myklebust 	[NF3DIR] = S_IFDIR,
98bca79478STrond Myklebust 	[NF3BLK] = S_IFBLK,
99bca79478STrond Myklebust 	[NF3CHR] = S_IFCHR,
100bca79478STrond Myklebust 	[NF3LNK] = S_IFLNK,
101bca79478STrond Myklebust 	[NF3SOCK] = S_IFSOCK,
102bca79478STrond Myklebust 	[NF3FIFO] = S_IFIFO,
1031da177e4SLinus Torvalds };
1041da177e4SLinus Torvalds 
105babddc72SBryan Schumaker static void print_overflow_msg(const char *func, const struct xdr_stream *xdr)
106babddc72SBryan Schumaker {
107babddc72SBryan Schumaker 	dprintk("nfs: %s: prematurely hit end of receive buffer. "
108babddc72SBryan Schumaker 		"Remaining buffer length is %tu words.\n",
109babddc72SBryan Schumaker 		func, xdr->end - xdr->p);
110babddc72SBryan Schumaker }
111babddc72SBryan Schumaker 
1121da177e4SLinus Torvalds /*
113d9c407b1SChuck Lever  * While encoding arguments, set up the reply buffer in advance to
114d9c407b1SChuck Lever  * receive reply data directly into the page cache.
115d9c407b1SChuck Lever  */
116d9c407b1SChuck Lever static void prepare_reply_buffer(struct rpc_rqst *req, struct page **pages,
117d9c407b1SChuck Lever 				 unsigned int base, unsigned int len,
118d9c407b1SChuck Lever 				 unsigned int bufsize)
119d9c407b1SChuck Lever {
120d9c407b1SChuck Lever 	struct rpc_auth	*auth = req->rq_cred->cr_auth;
121d9c407b1SChuck Lever 	unsigned int replen;
122d9c407b1SChuck Lever 
123d9c407b1SChuck Lever 	replen = RPC_REPHDRSIZE + auth->au_rslack + bufsize;
124d9c407b1SChuck Lever 	xdr_inline_pages(&req->rq_rcv_buf, replen << 2, pages, base, len);
125d9c407b1SChuck Lever }
126d9c407b1SChuck Lever 
127d9c407b1SChuck Lever 
128d9c407b1SChuck Lever /*
1291da177e4SLinus Torvalds  * Common NFS XDR functions as inlines
1301da177e4SLinus Torvalds  */
131d61005a6SAl Viro static inline __be32 *
1324fdc17b2STrond Myklebust xdr_encode_fhandle(__be32 *p, const struct nfs_fh *fh)
1331da177e4SLinus Torvalds {
1341da177e4SLinus Torvalds 	return xdr_encode_array(p, fh->data, fh->size);
1351da177e4SLinus Torvalds }
1361da177e4SLinus Torvalds 
137d61005a6SAl Viro static inline __be32 *
138d61005a6SAl Viro xdr_decode_fhandle(__be32 *p, struct nfs_fh *fh)
1391da177e4SLinus Torvalds {
1401da177e4SLinus Torvalds 	if ((fh->size = ntohl(*p++)) <= NFS3_FHSIZE) {
1411da177e4SLinus Torvalds 		memcpy(fh->data, p, fh->size);
1421da177e4SLinus Torvalds 		return p + XDR_QUADLEN(fh->size);
1431da177e4SLinus Torvalds 	}
1441da177e4SLinus Torvalds 	return NULL;
1451da177e4SLinus Torvalds }
1461da177e4SLinus Torvalds 
147babddc72SBryan Schumaker static inline __be32 *
148babddc72SBryan Schumaker xdr_decode_fhandle_stream(struct xdr_stream *xdr, struct nfs_fh *fh)
149babddc72SBryan Schumaker {
150babddc72SBryan Schumaker 	__be32 *p;
151babddc72SBryan Schumaker 	p = xdr_inline_decode(xdr, 4);
152babddc72SBryan Schumaker 	if (unlikely(!p))
153babddc72SBryan Schumaker 		goto out_overflow;
154babddc72SBryan Schumaker 	fh->size = ntohl(*p++);
155babddc72SBryan Schumaker 
156babddc72SBryan Schumaker 	if (fh->size <= NFS3_FHSIZE) {
157babddc72SBryan Schumaker 		p = xdr_inline_decode(xdr, fh->size);
158babddc72SBryan Schumaker 		if (unlikely(!p))
159babddc72SBryan Schumaker 			goto out_overflow;
160babddc72SBryan Schumaker 		memcpy(fh->data, p, fh->size);
161babddc72SBryan Schumaker 		return p + XDR_QUADLEN(fh->size);
162babddc72SBryan Schumaker 	}
163babddc72SBryan Schumaker 	return NULL;
164babddc72SBryan Schumaker 
165babddc72SBryan Schumaker out_overflow:
166babddc72SBryan Schumaker 	print_overflow_msg(__func__, xdr);
167babddc72SBryan Schumaker 	return ERR_PTR(-EIO);
168babddc72SBryan Schumaker }
169babddc72SBryan Schumaker 
1701da177e4SLinus Torvalds /*
1711da177e4SLinus Torvalds  * Encode/decode time.
1721da177e4SLinus Torvalds  */
173d61005a6SAl Viro static inline __be32 *
174d9c407b1SChuck Lever xdr_encode_time3(__be32 *p, const struct timespec *timep)
1751da177e4SLinus Torvalds {
1761da177e4SLinus Torvalds 	*p++ = htonl(timep->tv_sec);
1771da177e4SLinus Torvalds 	*p++ = htonl(timep->tv_nsec);
1781da177e4SLinus Torvalds 	return p;
1791da177e4SLinus Torvalds }
1801da177e4SLinus Torvalds 
181d61005a6SAl Viro static inline __be32 *
182d61005a6SAl Viro xdr_decode_time3(__be32 *p, struct timespec *timep)
1831da177e4SLinus Torvalds {
1841da177e4SLinus Torvalds 	timep->tv_sec = ntohl(*p++);
1851da177e4SLinus Torvalds 	timep->tv_nsec = ntohl(*p++);
1861da177e4SLinus Torvalds 	return p;
1871da177e4SLinus Torvalds }
1881da177e4SLinus Torvalds 
189d61005a6SAl Viro static __be32 *
190d61005a6SAl Viro xdr_decode_fattr(__be32 *p, struct nfs_fattr *fattr)
1911da177e4SLinus Torvalds {
1921da177e4SLinus Torvalds 	unsigned int	type, major, minor;
193bca79478STrond Myklebust 	umode_t		fmode;
1941da177e4SLinus Torvalds 
1951da177e4SLinus Torvalds 	type = ntohl(*p++);
196bca79478STrond Myklebust 	if (type > NF3FIFO)
197bca79478STrond Myklebust 		type = NF3NON;
198bca79478STrond Myklebust 	fmode = nfs_type2fmt[type];
1991da177e4SLinus Torvalds 	fattr->mode = (ntohl(*p++) & ~S_IFMT) | fmode;
2001da177e4SLinus Torvalds 	fattr->nlink = ntohl(*p++);
2011da177e4SLinus Torvalds 	fattr->uid = ntohl(*p++);
2021da177e4SLinus Torvalds 	fattr->gid = ntohl(*p++);
2031da177e4SLinus Torvalds 	p = xdr_decode_hyper(p, &fattr->size);
2041da177e4SLinus Torvalds 	p = xdr_decode_hyper(p, &fattr->du.nfs3.used);
2051da177e4SLinus Torvalds 
2061da177e4SLinus Torvalds 	/* Turn remote device info into Linux-specific dev_t */
2071da177e4SLinus Torvalds 	major = ntohl(*p++);
2081da177e4SLinus Torvalds 	minor = ntohl(*p++);
2091da177e4SLinus Torvalds 	fattr->rdev = MKDEV(major, minor);
2101da177e4SLinus Torvalds 	if (MAJOR(fattr->rdev) != major || MINOR(fattr->rdev) != minor)
2111da177e4SLinus Torvalds 		fattr->rdev = 0;
2121da177e4SLinus Torvalds 
2138b4bdcf8STrond Myklebust 	p = xdr_decode_hyper(p, &fattr->fsid.major);
2148b4bdcf8STrond Myklebust 	fattr->fsid.minor = 0;
2151da177e4SLinus Torvalds 	p = xdr_decode_hyper(p, &fattr->fileid);
2161da177e4SLinus Torvalds 	p = xdr_decode_time3(p, &fattr->atime);
2171da177e4SLinus Torvalds 	p = xdr_decode_time3(p, &fattr->mtime);
2181da177e4SLinus Torvalds 	p = xdr_decode_time3(p, &fattr->ctime);
2191da177e4SLinus Torvalds 
2201da177e4SLinus Torvalds 	/* Update the mode bits */
2219e6e70f8STrond Myklebust 	fattr->valid |= NFS_ATTR_FATTR_V3;
2221da177e4SLinus Torvalds 	return p;
2231da177e4SLinus Torvalds }
2241da177e4SLinus Torvalds 
225d61005a6SAl Viro static inline __be32 *
226d9c407b1SChuck Lever xdr_encode_sattr(__be32 *p, const struct iattr *attr)
2271da177e4SLinus Torvalds {
2281da177e4SLinus Torvalds 	if (attr->ia_valid & ATTR_MODE) {
2291da177e4SLinus Torvalds 		*p++ = xdr_one;
230cf3fff54STrond Myklebust 		*p++ = htonl(attr->ia_mode & S_IALLUGO);
2311da177e4SLinus Torvalds 	} else {
2321da177e4SLinus Torvalds 		*p++ = xdr_zero;
2331da177e4SLinus Torvalds 	}
2341da177e4SLinus Torvalds 	if (attr->ia_valid & ATTR_UID) {
2351da177e4SLinus Torvalds 		*p++ = xdr_one;
2361da177e4SLinus Torvalds 		*p++ = htonl(attr->ia_uid);
2371da177e4SLinus Torvalds 	} else {
2381da177e4SLinus Torvalds 		*p++ = xdr_zero;
2391da177e4SLinus Torvalds 	}
2401da177e4SLinus Torvalds 	if (attr->ia_valid & ATTR_GID) {
2411da177e4SLinus Torvalds 		*p++ = xdr_one;
2421da177e4SLinus Torvalds 		*p++ = htonl(attr->ia_gid);
2431da177e4SLinus Torvalds 	} else {
2441da177e4SLinus Torvalds 		*p++ = xdr_zero;
2451da177e4SLinus Torvalds 	}
2461da177e4SLinus Torvalds 	if (attr->ia_valid & ATTR_SIZE) {
2471da177e4SLinus Torvalds 		*p++ = xdr_one;
2481da177e4SLinus Torvalds 		p = xdr_encode_hyper(p, (__u64) attr->ia_size);
2491da177e4SLinus Torvalds 	} else {
2501da177e4SLinus Torvalds 		*p++ = xdr_zero;
2511da177e4SLinus Torvalds 	}
2521da177e4SLinus Torvalds 	if (attr->ia_valid & ATTR_ATIME_SET) {
2531da177e4SLinus Torvalds 		*p++ = xdr_two;
2541da177e4SLinus Torvalds 		p = xdr_encode_time3(p, &attr->ia_atime);
2551da177e4SLinus Torvalds 	} else if (attr->ia_valid & ATTR_ATIME) {
2561da177e4SLinus Torvalds 		*p++ = xdr_one;
2571da177e4SLinus Torvalds 	} else {
2581da177e4SLinus Torvalds 		*p++ = xdr_zero;
2591da177e4SLinus Torvalds 	}
2601da177e4SLinus Torvalds 	if (attr->ia_valid & ATTR_MTIME_SET) {
2611da177e4SLinus Torvalds 		*p++ = xdr_two;
2621da177e4SLinus Torvalds 		p = xdr_encode_time3(p, &attr->ia_mtime);
2631da177e4SLinus Torvalds 	} else if (attr->ia_valid & ATTR_MTIME) {
2641da177e4SLinus Torvalds 		*p++ = xdr_one;
2651da177e4SLinus Torvalds 	} else {
2661da177e4SLinus Torvalds 		*p++ = xdr_zero;
2671da177e4SLinus Torvalds 	}
2681da177e4SLinus Torvalds 	return p;
2691da177e4SLinus Torvalds }
2701da177e4SLinus Torvalds 
271d61005a6SAl Viro static inline __be32 *
272d61005a6SAl Viro xdr_decode_wcc_attr(__be32 *p, struct nfs_fattr *fattr)
2731da177e4SLinus Torvalds {
2741da177e4SLinus Torvalds 	p = xdr_decode_hyper(p, &fattr->pre_size);
2751da177e4SLinus Torvalds 	p = xdr_decode_time3(p, &fattr->pre_mtime);
2761da177e4SLinus Torvalds 	p = xdr_decode_time3(p, &fattr->pre_ctime);
2779e6e70f8STrond Myklebust 	fattr->valid |= NFS_ATTR_FATTR_PRESIZE
2789e6e70f8STrond Myklebust 		| NFS_ATTR_FATTR_PREMTIME
2799e6e70f8STrond Myklebust 		| NFS_ATTR_FATTR_PRECTIME;
2801da177e4SLinus Torvalds 	return p;
2811da177e4SLinus Torvalds }
2821da177e4SLinus Torvalds 
283d61005a6SAl Viro static inline __be32 *
284d61005a6SAl Viro xdr_decode_post_op_attr(__be32 *p, struct nfs_fattr *fattr)
2851da177e4SLinus Torvalds {
2861da177e4SLinus Torvalds 	if (*p++)
2871da177e4SLinus Torvalds 		p = xdr_decode_fattr(p, fattr);
2881da177e4SLinus Torvalds 	return p;
2891da177e4SLinus Torvalds }
2901da177e4SLinus Torvalds 
291d61005a6SAl Viro static inline __be32 *
292babddc72SBryan Schumaker xdr_decode_post_op_attr_stream(struct xdr_stream *xdr, struct nfs_fattr *fattr)
293babddc72SBryan Schumaker {
294babddc72SBryan Schumaker 	__be32 *p;
295babddc72SBryan Schumaker 
296babddc72SBryan Schumaker 	p = xdr_inline_decode(xdr, 4);
297babddc72SBryan Schumaker 	if (unlikely(!p))
298babddc72SBryan Schumaker 		goto out_overflow;
299babddc72SBryan Schumaker 	if (ntohl(*p++)) {
300babddc72SBryan Schumaker 		p = xdr_inline_decode(xdr, 84);
301babddc72SBryan Schumaker 		if (unlikely(!p))
302babddc72SBryan Schumaker 			goto out_overflow;
303babddc72SBryan Schumaker 		p = xdr_decode_fattr(p, fattr);
304babddc72SBryan Schumaker 	}
305babddc72SBryan Schumaker 	return p;
306babddc72SBryan Schumaker out_overflow:
307babddc72SBryan Schumaker 	print_overflow_msg(__func__, xdr);
308babddc72SBryan Schumaker 	return ERR_PTR(-EIO);
309babddc72SBryan Schumaker }
310babddc72SBryan Schumaker 
311babddc72SBryan Schumaker static inline __be32 *
312d61005a6SAl Viro xdr_decode_pre_op_attr(__be32 *p, struct nfs_fattr *fattr)
3131da177e4SLinus Torvalds {
3141da177e4SLinus Torvalds 	if (*p++)
3151da177e4SLinus Torvalds 		return xdr_decode_wcc_attr(p, fattr);
3161da177e4SLinus Torvalds 	return p;
3171da177e4SLinus Torvalds }
3181da177e4SLinus Torvalds 
3191da177e4SLinus Torvalds 
320d61005a6SAl Viro static inline __be32 *
321d61005a6SAl Viro xdr_decode_wcc_data(__be32 *p, struct nfs_fattr *fattr)
3221da177e4SLinus Torvalds {
3231da177e4SLinus Torvalds 	p = xdr_decode_pre_op_attr(p, fattr);
3241da177e4SLinus Torvalds 	return xdr_decode_post_op_attr(p, fattr);
3251da177e4SLinus Torvalds }
3261da177e4SLinus Torvalds 
327d9c407b1SChuck Lever 
328d9c407b1SChuck Lever /*
329d9c407b1SChuck Lever  * Encode/decode NFSv3 basic data types
330d9c407b1SChuck Lever  *
331d9c407b1SChuck Lever  * Basic NFSv3 data types are defined in section 2.5 of RFC 1813:
332d9c407b1SChuck Lever  * "NFS Version 3 Protocol Specification".
333d9c407b1SChuck Lever  *
334d9c407b1SChuck Lever  * Not all basic data types have their own encoding and decoding
335d9c407b1SChuck Lever  * functions.  For run-time efficiency, some data types are encoded
336d9c407b1SChuck Lever  * or decoded inline.
337d9c407b1SChuck Lever  */
338d9c407b1SChuck Lever 
339d9c407b1SChuck Lever static void encode_uint32(struct xdr_stream *xdr, u32 value)
340d9c407b1SChuck Lever {
341d9c407b1SChuck Lever 	__be32 *p = xdr_reserve_space(xdr, 4);
342d9c407b1SChuck Lever 	*p = cpu_to_be32(value);
343d9c407b1SChuck Lever }
344d9c407b1SChuck Lever 
345d9c407b1SChuck Lever /*
346d9c407b1SChuck Lever  * filename3
347d9c407b1SChuck Lever  *
348d9c407b1SChuck Lever  *	typedef string filename3<>;
349d9c407b1SChuck Lever  */
350d9c407b1SChuck Lever static void encode_filename3(struct xdr_stream *xdr,
351d9c407b1SChuck Lever 			     const char *name, u32 length)
352d9c407b1SChuck Lever {
353d9c407b1SChuck Lever 	__be32 *p;
354d9c407b1SChuck Lever 
355d9c407b1SChuck Lever 	BUG_ON(length > NFS3_MAXNAMLEN);
356d9c407b1SChuck Lever 	p = xdr_reserve_space(xdr, 4 + length);
357d9c407b1SChuck Lever 	xdr_encode_opaque(p, name, length);
358d9c407b1SChuck Lever }
359d9c407b1SChuck Lever 
360d9c407b1SChuck Lever /*
361d9c407b1SChuck Lever  * nfspath3
362d9c407b1SChuck Lever  *
363d9c407b1SChuck Lever  *	typedef string nfspath3<>;
364d9c407b1SChuck Lever  */
365d9c407b1SChuck Lever static void encode_nfspath3(struct xdr_stream *xdr, struct page **pages,
366d9c407b1SChuck Lever 			    const u32 length)
367d9c407b1SChuck Lever {
368d9c407b1SChuck Lever 	BUG_ON(length > NFS3_MAXPATHLEN);
369d9c407b1SChuck Lever 	encode_uint32(xdr, length);
370d9c407b1SChuck Lever 	xdr_write_pages(xdr, pages, 0, length);
371d9c407b1SChuck Lever }
372d9c407b1SChuck Lever 
373d9c407b1SChuck Lever /*
374d9c407b1SChuck Lever  * cookie3
375d9c407b1SChuck Lever  *
376d9c407b1SChuck Lever  *	typedef uint64 cookie3
377d9c407b1SChuck Lever  */
378d9c407b1SChuck Lever static __be32 *xdr_encode_cookie3(__be32 *p, u64 cookie)
379d9c407b1SChuck Lever {
380d9c407b1SChuck Lever 	return xdr_encode_hyper(p, cookie);
381d9c407b1SChuck Lever }
382d9c407b1SChuck Lever 
383d9c407b1SChuck Lever /*
384d9c407b1SChuck Lever  * cookieverf3
385d9c407b1SChuck Lever  *
386d9c407b1SChuck Lever  *	typedef opaque cookieverf3[NFS3_COOKIEVERFSIZE];
387d9c407b1SChuck Lever  */
388d9c407b1SChuck Lever static __be32 *xdr_encode_cookieverf3(__be32 *p, const __be32 *verifier)
389d9c407b1SChuck Lever {
390d9c407b1SChuck Lever 	memcpy(p, verifier, NFS3_COOKIEVERFSIZE);
391d9c407b1SChuck Lever 	return p + XDR_QUADLEN(NFS3_COOKIEVERFSIZE);
392d9c407b1SChuck Lever }
393d9c407b1SChuck Lever 
394d9c407b1SChuck Lever /*
395d9c407b1SChuck Lever  * createverf3
396d9c407b1SChuck Lever  *
397d9c407b1SChuck Lever  *	typedef opaque createverf3[NFS3_CREATEVERFSIZE];
398d9c407b1SChuck Lever  */
399d9c407b1SChuck Lever static void encode_createverf3(struct xdr_stream *xdr, const __be32 *verifier)
400d9c407b1SChuck Lever {
401d9c407b1SChuck Lever 	__be32 *p;
402d9c407b1SChuck Lever 
403d9c407b1SChuck Lever 	p = xdr_reserve_space(xdr, NFS3_CREATEVERFSIZE);
404d9c407b1SChuck Lever 	memcpy(p, verifier, NFS3_CREATEVERFSIZE);
405d9c407b1SChuck Lever }
406d9c407b1SChuck Lever 
407d9c407b1SChuck Lever /*
408d9c407b1SChuck Lever  * ftype3
409d9c407b1SChuck Lever  *
410d9c407b1SChuck Lever  *	enum ftype3 {
411d9c407b1SChuck Lever  *		NF3REG	= 1,
412d9c407b1SChuck Lever  *		NF3DIR	= 2,
413d9c407b1SChuck Lever  *		NF3BLK	= 3,
414d9c407b1SChuck Lever  *		NF3CHR	= 4,
415d9c407b1SChuck Lever  *		NF3LNK	= 5,
416d9c407b1SChuck Lever  *		NF3SOCK	= 6,
417d9c407b1SChuck Lever  *		NF3FIFO	= 7
418d9c407b1SChuck Lever  *	};
419d9c407b1SChuck Lever  */
420d9c407b1SChuck Lever static void encode_ftype3(struct xdr_stream *xdr, const u32 type)
421d9c407b1SChuck Lever {
422d9c407b1SChuck Lever 	BUG_ON(type > NF3FIFO);
423d9c407b1SChuck Lever 	encode_uint32(xdr, type);
424d9c407b1SChuck Lever }
425d9c407b1SChuck Lever 
426d9c407b1SChuck Lever /*
427d9c407b1SChuck Lever  * specdata3
428d9c407b1SChuck Lever  *
429d9c407b1SChuck Lever  *     struct specdata3 {
430d9c407b1SChuck Lever  *             uint32  specdata1;
431d9c407b1SChuck Lever  *             uint32  specdata2;
432d9c407b1SChuck Lever  *     };
433d9c407b1SChuck Lever  */
434d9c407b1SChuck Lever static void encode_specdata3(struct xdr_stream *xdr, const dev_t rdev)
435d9c407b1SChuck Lever {
436d9c407b1SChuck Lever 	__be32 *p;
437d9c407b1SChuck Lever 
438d9c407b1SChuck Lever 	p = xdr_reserve_space(xdr, 8);
439d9c407b1SChuck Lever 	*p++ = cpu_to_be32(MAJOR(rdev));
440d9c407b1SChuck Lever 	*p = cpu_to_be32(MINOR(rdev));
441d9c407b1SChuck Lever }
442d9c407b1SChuck Lever 
443d9c407b1SChuck Lever /*
444d9c407b1SChuck Lever  * nfs_fh3
445d9c407b1SChuck Lever  *
446d9c407b1SChuck Lever  *	struct nfs_fh3 {
447d9c407b1SChuck Lever  *		opaque       data<NFS3_FHSIZE>;
448d9c407b1SChuck Lever  *	};
449d9c407b1SChuck Lever  */
450d9c407b1SChuck Lever static void encode_nfs_fh3(struct xdr_stream *xdr, const struct nfs_fh *fh)
451d9c407b1SChuck Lever {
452d9c407b1SChuck Lever 	__be32 *p;
453d9c407b1SChuck Lever 
454d9c407b1SChuck Lever 	BUG_ON(fh->size > NFS3_FHSIZE);
455d9c407b1SChuck Lever 	p = xdr_reserve_space(xdr, 4 + fh->size);
456d9c407b1SChuck Lever 	xdr_encode_opaque(p, fh->data, fh->size);
457d9c407b1SChuck Lever }
458d9c407b1SChuck Lever 
459d9c407b1SChuck Lever /*
460d9c407b1SChuck Lever  * sattr3
461d9c407b1SChuck Lever  *
462d9c407b1SChuck Lever  *	enum time_how {
463d9c407b1SChuck Lever  *		DONT_CHANGE		= 0,
464d9c407b1SChuck Lever  *		SET_TO_SERVER_TIME	= 1,
465d9c407b1SChuck Lever  *		SET_TO_CLIENT_TIME	= 2
466d9c407b1SChuck Lever  *	};
467d9c407b1SChuck Lever  *
468d9c407b1SChuck Lever  *	union set_mode3 switch (bool set_it) {
469d9c407b1SChuck Lever  *	case TRUE:
470d9c407b1SChuck Lever  *		mode3	mode;
471d9c407b1SChuck Lever  *	default:
472d9c407b1SChuck Lever  *		void;
473d9c407b1SChuck Lever  *	};
474d9c407b1SChuck Lever  *
475d9c407b1SChuck Lever  *	union set_uid3 switch (bool set_it) {
476d9c407b1SChuck Lever  *	case TRUE:
477d9c407b1SChuck Lever  *		uid3	uid;
478d9c407b1SChuck Lever  *	default:
479d9c407b1SChuck Lever  *		void;
480d9c407b1SChuck Lever  *	};
481d9c407b1SChuck Lever  *
482d9c407b1SChuck Lever  *	union set_gid3 switch (bool set_it) {
483d9c407b1SChuck Lever  *	case TRUE:
484d9c407b1SChuck Lever  *		gid3	gid;
485d9c407b1SChuck Lever  *	default:
486d9c407b1SChuck Lever  *		void;
487d9c407b1SChuck Lever  *	};
488d9c407b1SChuck Lever  *
489d9c407b1SChuck Lever  *	union set_size3 switch (bool set_it) {
490d9c407b1SChuck Lever  *	case TRUE:
491d9c407b1SChuck Lever  *		size3	size;
492d9c407b1SChuck Lever  *	default:
493d9c407b1SChuck Lever  *		void;
494d9c407b1SChuck Lever  *	};
495d9c407b1SChuck Lever  *
496d9c407b1SChuck Lever  *	union set_atime switch (time_how set_it) {
497d9c407b1SChuck Lever  *	case SET_TO_CLIENT_TIME:
498d9c407b1SChuck Lever  *		nfstime3	atime;
499d9c407b1SChuck Lever  *	default:
500d9c407b1SChuck Lever  *		void;
501d9c407b1SChuck Lever  *	};
502d9c407b1SChuck Lever  *
503d9c407b1SChuck Lever  *	union set_mtime switch (time_how set_it) {
504d9c407b1SChuck Lever  *	case SET_TO_CLIENT_TIME:
505d9c407b1SChuck Lever  *		nfstime3  mtime;
506d9c407b1SChuck Lever  *	default:
507d9c407b1SChuck Lever  *		void;
508d9c407b1SChuck Lever  *	};
509d9c407b1SChuck Lever  *
510d9c407b1SChuck Lever  *	struct sattr3 {
511d9c407b1SChuck Lever  *		set_mode3	mode;
512d9c407b1SChuck Lever  *		set_uid3	uid;
513d9c407b1SChuck Lever  *		set_gid3	gid;
514d9c407b1SChuck Lever  *		set_size3	size;
515d9c407b1SChuck Lever  *		set_atime	atime;
516d9c407b1SChuck Lever  *		set_mtime	mtime;
517d9c407b1SChuck Lever  *	};
518d9c407b1SChuck Lever  */
519d9c407b1SChuck Lever static void encode_sattr3(struct xdr_stream *xdr, const struct iattr *attr)
520d9c407b1SChuck Lever {
521d9c407b1SChuck Lever 	u32 nbytes;
522d9c407b1SChuck Lever 	__be32 *p;
523d9c407b1SChuck Lever 
524d9c407b1SChuck Lever 	/*
525d9c407b1SChuck Lever 	 * In order to make only a single xdr_reserve_space() call,
526d9c407b1SChuck Lever 	 * pre-compute the total number of bytes to be reserved.
527d9c407b1SChuck Lever 	 * Six boolean values, one for each set_foo field, are always
528d9c407b1SChuck Lever 	 * present in the encoded result, so start there.
529d9c407b1SChuck Lever 	 */
530d9c407b1SChuck Lever 	nbytes = 6 * 4;
531d9c407b1SChuck Lever 	if (attr->ia_valid & ATTR_MODE)
532d9c407b1SChuck Lever 		nbytes += 4;
533d9c407b1SChuck Lever 	if (attr->ia_valid & ATTR_UID)
534d9c407b1SChuck Lever 		nbytes += 4;
535d9c407b1SChuck Lever 	if (attr->ia_valid & ATTR_GID)
536d9c407b1SChuck Lever 		nbytes += 4;
537d9c407b1SChuck Lever 	if (attr->ia_valid & ATTR_SIZE)
538d9c407b1SChuck Lever 		nbytes += 8;
539d9c407b1SChuck Lever 	if (attr->ia_valid & ATTR_ATIME_SET)
540d9c407b1SChuck Lever 		nbytes += 8;
541d9c407b1SChuck Lever 	if (attr->ia_valid & ATTR_MTIME_SET)
542d9c407b1SChuck Lever 		nbytes += 8;
543d9c407b1SChuck Lever 	p = xdr_reserve_space(xdr, nbytes);
544d9c407b1SChuck Lever 
545d9c407b1SChuck Lever 	xdr_encode_sattr(p, attr);
546d9c407b1SChuck Lever }
547d9c407b1SChuck Lever 
548d9c407b1SChuck Lever /*
549d9c407b1SChuck Lever  * diropargs3
550d9c407b1SChuck Lever  *
551d9c407b1SChuck Lever  *	struct diropargs3 {
552d9c407b1SChuck Lever  *		nfs_fh3		dir;
553d9c407b1SChuck Lever  *		filename3	name;
554d9c407b1SChuck Lever  *	};
555d9c407b1SChuck Lever  */
556d9c407b1SChuck Lever static void encode_diropargs3(struct xdr_stream *xdr, const struct nfs_fh *fh,
557d9c407b1SChuck Lever 			      const char *name, u32 length)
558d9c407b1SChuck Lever {
559d9c407b1SChuck Lever 	encode_nfs_fh3(xdr, fh);
560d9c407b1SChuck Lever 	encode_filename3(xdr, name, length);
561d9c407b1SChuck Lever }
562d9c407b1SChuck Lever 
563d9c407b1SChuck Lever 
5641da177e4SLinus Torvalds /*
5651da177e4SLinus Torvalds  * NFS encode functions
5661da177e4SLinus Torvalds  */
5671da177e4SLinus Torvalds 
5681da177e4SLinus Torvalds /*
5691da177e4SLinus Torvalds  * Encode file handle argument
5701da177e4SLinus Torvalds  */
5711da177e4SLinus Torvalds static int
572d61005a6SAl Viro nfs3_xdr_fhandle(struct rpc_rqst *req, __be32 *p, struct nfs_fh *fh)
5731da177e4SLinus Torvalds {
5741da177e4SLinus Torvalds 	p = xdr_encode_fhandle(p, fh);
5751da177e4SLinus Torvalds 	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
5761da177e4SLinus Torvalds 	return 0;
5771da177e4SLinus Torvalds }
5781da177e4SLinus Torvalds 
5791da177e4SLinus Torvalds /*
580d9c407b1SChuck Lever  * 3.3.1  GETATTR3args
581d9c407b1SChuck Lever  *
582d9c407b1SChuck Lever  *	struct GETATTR3args {
583d9c407b1SChuck Lever  *		nfs_fh3  object;
584d9c407b1SChuck Lever  *	};
585d9c407b1SChuck Lever  */
586d9c407b1SChuck Lever static int nfs3_xdr_enc_getattr3args(struct rpc_rqst *req, __be32 *p,
587d9c407b1SChuck Lever 				     const struct nfs_fh *fh)
588d9c407b1SChuck Lever {
589d9c407b1SChuck Lever 	struct xdr_stream xdr;
590d9c407b1SChuck Lever 
591d9c407b1SChuck Lever 	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
592d9c407b1SChuck Lever 	encode_nfs_fh3(&xdr, fh);
593d9c407b1SChuck Lever 	return 0;
594d9c407b1SChuck Lever }
595d9c407b1SChuck Lever 
596d9c407b1SChuck Lever /*
5971da177e4SLinus Torvalds  * Encode SETATTR arguments
5981da177e4SLinus Torvalds  */
5991da177e4SLinus Torvalds static int
600d61005a6SAl Viro nfs3_xdr_sattrargs(struct rpc_rqst *req, __be32 *p, struct nfs3_sattrargs *args)
6011da177e4SLinus Torvalds {
6021da177e4SLinus Torvalds 	p = xdr_encode_fhandle(p, args->fh);
6031da177e4SLinus Torvalds 	p = xdr_encode_sattr(p, args->sattr);
6041da177e4SLinus Torvalds 	*p++ = htonl(args->guard);
6051da177e4SLinus Torvalds 	if (args->guard)
6061da177e4SLinus Torvalds 		p = xdr_encode_time3(p, &args->guardtime);
6071da177e4SLinus Torvalds 	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
6081da177e4SLinus Torvalds 	return 0;
6091da177e4SLinus Torvalds }
6101da177e4SLinus Torvalds 
6111da177e4SLinus Torvalds /*
612d9c407b1SChuck Lever  * 3.3.2  SETATTR3args
613d9c407b1SChuck Lever  *
614d9c407b1SChuck Lever  *	union sattrguard3 switch (bool check) {
615d9c407b1SChuck Lever  *	case TRUE:
616d9c407b1SChuck Lever  *		nfstime3  obj_ctime;
617d9c407b1SChuck Lever  *	case FALSE:
618d9c407b1SChuck Lever  *		void;
619d9c407b1SChuck Lever  *	};
620d9c407b1SChuck Lever  *
621d9c407b1SChuck Lever  *	struct SETATTR3args {
622d9c407b1SChuck Lever  *		nfs_fh3		object;
623d9c407b1SChuck Lever  *		sattr3		new_attributes;
624d9c407b1SChuck Lever  *		sattrguard3	guard;
625d9c407b1SChuck Lever  *	};
626d9c407b1SChuck Lever  */
627d9c407b1SChuck Lever static void encode_sattrguard3(struct xdr_stream *xdr,
628d9c407b1SChuck Lever 			       const struct nfs3_sattrargs *args)
629d9c407b1SChuck Lever {
630d9c407b1SChuck Lever 	__be32 *p;
631d9c407b1SChuck Lever 
632d9c407b1SChuck Lever 	if (args->guard) {
633d9c407b1SChuck Lever 		p = xdr_reserve_space(xdr, 4 + 8);
634d9c407b1SChuck Lever 		*p++ = xdr_one;
635d9c407b1SChuck Lever 		xdr_encode_time3(p, &args->guardtime);
636d9c407b1SChuck Lever 	} else {
637d9c407b1SChuck Lever 		p = xdr_reserve_space(xdr, 4);
638d9c407b1SChuck Lever 		*p = xdr_zero;
639d9c407b1SChuck Lever 	}
640d9c407b1SChuck Lever }
641d9c407b1SChuck Lever 
642d9c407b1SChuck Lever static int nfs3_xdr_enc_setattr3args(struct rpc_rqst *req, __be32 *p,
643d9c407b1SChuck Lever 				     const struct nfs3_sattrargs *args)
644d9c407b1SChuck Lever {
645d9c407b1SChuck Lever 	struct xdr_stream xdr;
646d9c407b1SChuck Lever 
647d9c407b1SChuck Lever 	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
648d9c407b1SChuck Lever 	encode_nfs_fh3(&xdr, args->fh);
649d9c407b1SChuck Lever 	encode_sattr3(&xdr, args->sattr);
650d9c407b1SChuck Lever 	encode_sattrguard3(&xdr, args);
651d9c407b1SChuck Lever 	return 0;
652d9c407b1SChuck Lever }
653d9c407b1SChuck Lever 
654d9c407b1SChuck Lever /*
6551da177e4SLinus Torvalds  * Encode directory ops argument
6561da177e4SLinus Torvalds  */
6571da177e4SLinus Torvalds static int
658d61005a6SAl Viro nfs3_xdr_diropargs(struct rpc_rqst *req, __be32 *p, struct nfs3_diropargs *args)
6591da177e4SLinus Torvalds {
6601da177e4SLinus Torvalds 	p = xdr_encode_fhandle(p, args->fh);
6611da177e4SLinus Torvalds 	p = xdr_encode_array(p, args->name, args->len);
6621da177e4SLinus Torvalds 	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
6631da177e4SLinus Torvalds 	return 0;
6641da177e4SLinus Torvalds }
6651da177e4SLinus Torvalds 
6661da177e4SLinus Torvalds /*
667d9c407b1SChuck Lever  * 3.3.3  LOOKUP3args
668d9c407b1SChuck Lever  *
669d9c407b1SChuck Lever  *	struct LOOKUP3args {
670d9c407b1SChuck Lever  *		diropargs3  what;
671d9c407b1SChuck Lever  *	};
672d9c407b1SChuck Lever  */
673d9c407b1SChuck Lever static int nfs3_xdr_enc_lookup3args(struct rpc_rqst *req, __be32 *p,
674d9c407b1SChuck Lever 				    const struct nfs3_diropargs *args)
675d9c407b1SChuck Lever {
676d9c407b1SChuck Lever 	struct xdr_stream xdr;
677d9c407b1SChuck Lever 
678d9c407b1SChuck Lever 	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
679d9c407b1SChuck Lever 	encode_diropargs3(&xdr, args->fh, args->name, args->len);
680d9c407b1SChuck Lever 	return 0;
681d9c407b1SChuck Lever }
682d9c407b1SChuck Lever 
683d9c407b1SChuck Lever /*
6844fdc17b2STrond Myklebust  * Encode REMOVE argument
6854fdc17b2STrond Myklebust  */
6864fdc17b2STrond Myklebust static int
6874fdc17b2STrond Myklebust nfs3_xdr_removeargs(struct rpc_rqst *req, __be32 *p, const struct nfs_removeargs *args)
6884fdc17b2STrond Myklebust {
6894fdc17b2STrond Myklebust 	p = xdr_encode_fhandle(p, args->fh);
6904fdc17b2STrond Myklebust 	p = xdr_encode_array(p, args->name.name, args->name.len);
6914fdc17b2STrond Myklebust 	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
6924fdc17b2STrond Myklebust 	return 0;
6934fdc17b2STrond Myklebust }
6944fdc17b2STrond Myklebust 
6954fdc17b2STrond Myklebust /*
6961da177e4SLinus Torvalds  * Encode access() argument
6971da177e4SLinus Torvalds  */
6981da177e4SLinus Torvalds static int
699d61005a6SAl Viro nfs3_xdr_accessargs(struct rpc_rqst *req, __be32 *p, struct nfs3_accessargs *args)
7001da177e4SLinus Torvalds {
7011da177e4SLinus Torvalds 	p = xdr_encode_fhandle(p, args->fh);
7021da177e4SLinus Torvalds 	*p++ = htonl(args->access);
7031da177e4SLinus Torvalds 	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
7041da177e4SLinus Torvalds 	return 0;
7051da177e4SLinus Torvalds }
7061da177e4SLinus Torvalds 
7071da177e4SLinus Torvalds /*
708d9c407b1SChuck Lever  * 3.3.4  ACCESS3args
709d9c407b1SChuck Lever  *
710d9c407b1SChuck Lever  *	struct ACCESS3args {
711d9c407b1SChuck Lever  *		nfs_fh3		object;
712d9c407b1SChuck Lever  *		uint32		access;
713d9c407b1SChuck Lever  *	};
714d9c407b1SChuck Lever  */
715d9c407b1SChuck Lever static void encode_access3args(struct xdr_stream *xdr,
716d9c407b1SChuck Lever 			       const struct nfs3_accessargs *args)
717d9c407b1SChuck Lever {
718d9c407b1SChuck Lever 	encode_nfs_fh3(xdr, args->fh);
719d9c407b1SChuck Lever 	encode_uint32(xdr, args->access);
720d9c407b1SChuck Lever }
721d9c407b1SChuck Lever 
722d9c407b1SChuck Lever static int nfs3_xdr_enc_access3args(struct rpc_rqst *req, __be32 *p,
723d9c407b1SChuck Lever 				    const struct nfs3_accessargs *args)
724d9c407b1SChuck Lever {
725d9c407b1SChuck Lever 	struct xdr_stream xdr;
726d9c407b1SChuck Lever 
727d9c407b1SChuck Lever 	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
728d9c407b1SChuck Lever 	encode_access3args(&xdr, args);
729d9c407b1SChuck Lever 	return 0;
730d9c407b1SChuck Lever }
731d9c407b1SChuck Lever 
732d9c407b1SChuck Lever /*
733d9c407b1SChuck Lever  * 3.3.5  READLINK3args
734d9c407b1SChuck Lever  *
735d9c407b1SChuck Lever  *	struct READLINK3args {
736d9c407b1SChuck Lever  *		nfs_fh3	symlink;
737d9c407b1SChuck Lever  *	};
738d9c407b1SChuck Lever  */
739d9c407b1SChuck Lever static int nfs3_xdr_enc_readlink3args(struct rpc_rqst *req, __be32 *p,
740d9c407b1SChuck Lever 				      const struct nfs3_readlinkargs *args)
741d9c407b1SChuck Lever {
742d9c407b1SChuck Lever 	struct xdr_stream xdr;
743d9c407b1SChuck Lever 
744d9c407b1SChuck Lever 	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
745d9c407b1SChuck Lever 	encode_nfs_fh3(&xdr, args->fh);
746d9c407b1SChuck Lever 	prepare_reply_buffer(req, args->pages, args->pgbase,
747d9c407b1SChuck Lever 					args->pglen, NFS3_readlinkres_sz);
748d9c407b1SChuck Lever 	return 0;
749d9c407b1SChuck Lever }
750d9c407b1SChuck Lever 
751d9c407b1SChuck Lever /*
7521da177e4SLinus Torvalds  * Arguments to a READ call. Since we read data directly into the page
7531da177e4SLinus Torvalds  * cache, we also set up the reply iovec here so that iov[1] points
7541da177e4SLinus Torvalds  * exactly to the page we want to fetch.
7551da177e4SLinus Torvalds  */
7561da177e4SLinus Torvalds static int
757d61005a6SAl Viro nfs3_xdr_readargs(struct rpc_rqst *req, __be32 *p, struct nfs_readargs *args)
7581da177e4SLinus Torvalds {
759a17c2153STrond Myklebust 	struct rpc_auth	*auth = req->rq_cred->cr_auth;
7601da177e4SLinus Torvalds 	unsigned int replen;
7611da177e4SLinus Torvalds 	u32 count = args->count;
7621da177e4SLinus Torvalds 
7631da177e4SLinus Torvalds 	p = xdr_encode_fhandle(p, args->fh);
7641da177e4SLinus Torvalds 	p = xdr_encode_hyper(p, args->offset);
7651da177e4SLinus Torvalds 	*p++ = htonl(count);
7661da177e4SLinus Torvalds 	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
7671da177e4SLinus Torvalds 
7681da177e4SLinus Torvalds 	/* Inline the page array */
7691da177e4SLinus Torvalds 	replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS3_readres_sz) << 2;
7701da177e4SLinus Torvalds 	xdr_inline_pages(&req->rq_rcv_buf, replen,
7711da177e4SLinus Torvalds 			 args->pages, args->pgbase, count);
7724f22ccc3S\"Talpey, Thomas\ 	req->rq_rcv_buf.flags |= XDRBUF_READ;
7731da177e4SLinus Torvalds 	return 0;
7741da177e4SLinus Torvalds }
7751da177e4SLinus Torvalds 
7761da177e4SLinus Torvalds /*
777d9c407b1SChuck Lever  * 3.3.6  READ3args
778d9c407b1SChuck Lever  *
779d9c407b1SChuck Lever  *	struct READ3args {
780d9c407b1SChuck Lever  *		nfs_fh3		file;
781d9c407b1SChuck Lever  *		offset3		offset;
782d9c407b1SChuck Lever  *		count3		count;
783d9c407b1SChuck Lever  *	};
784d9c407b1SChuck Lever  */
785d9c407b1SChuck Lever static void encode_read3args(struct xdr_stream *xdr,
786d9c407b1SChuck Lever 			     const struct nfs_readargs *args)
787d9c407b1SChuck Lever {
788d9c407b1SChuck Lever 	__be32 *p;
789d9c407b1SChuck Lever 
790d9c407b1SChuck Lever 	encode_nfs_fh3(xdr, args->fh);
791d9c407b1SChuck Lever 
792d9c407b1SChuck Lever 	p = xdr_reserve_space(xdr, 8 + 4);
793d9c407b1SChuck Lever 	p = xdr_encode_hyper(p, args->offset);
794d9c407b1SChuck Lever 	*p = cpu_to_be32(args->count);
795d9c407b1SChuck Lever }
796d9c407b1SChuck Lever 
797d9c407b1SChuck Lever static int nfs3_xdr_enc_read3args(struct rpc_rqst *req, __be32 *p,
798d9c407b1SChuck Lever 				  const struct nfs_readargs *args)
799d9c407b1SChuck Lever {
800d9c407b1SChuck Lever 	struct xdr_stream xdr;
801d9c407b1SChuck Lever 
802d9c407b1SChuck Lever 	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
803d9c407b1SChuck Lever 	encode_read3args(&xdr, args);
804d9c407b1SChuck Lever 	prepare_reply_buffer(req, args->pages, args->pgbase,
805d9c407b1SChuck Lever 					args->count, NFS3_readres_sz);
806d9c407b1SChuck Lever 	req->rq_rcv_buf.flags |= XDRBUF_READ;
807d9c407b1SChuck Lever 	return 0;
808d9c407b1SChuck Lever }
809d9c407b1SChuck Lever 
810d9c407b1SChuck Lever /*
8111da177e4SLinus Torvalds  * Write arguments. Splice the buffer to be written into the iovec.
8121da177e4SLinus Torvalds  */
8131da177e4SLinus Torvalds static int
814d61005a6SAl Viro nfs3_xdr_writeargs(struct rpc_rqst *req, __be32 *p, struct nfs_writeargs *args)
8151da177e4SLinus Torvalds {
8161da177e4SLinus Torvalds 	struct xdr_buf *sndbuf = &req->rq_snd_buf;
8171da177e4SLinus Torvalds 	u32 count = args->count;
8181da177e4SLinus Torvalds 
8191da177e4SLinus Torvalds 	p = xdr_encode_fhandle(p, args->fh);
8201da177e4SLinus Torvalds 	p = xdr_encode_hyper(p, args->offset);
8211da177e4SLinus Torvalds 	*p++ = htonl(count);
8221da177e4SLinus Torvalds 	*p++ = htonl(args->stable);
8231da177e4SLinus Torvalds 	*p++ = htonl(count);
8241da177e4SLinus Torvalds 	sndbuf->len = xdr_adjust_iovec(sndbuf->head, p);
8251da177e4SLinus Torvalds 
8261da177e4SLinus Torvalds 	/* Copy the page array */
8271da177e4SLinus Torvalds 	xdr_encode_pages(sndbuf, args->pages, args->pgbase, count);
8284f22ccc3S\"Talpey, Thomas\ 	sndbuf->flags |= XDRBUF_WRITE;
8291da177e4SLinus Torvalds 	return 0;
8301da177e4SLinus Torvalds }
8311da177e4SLinus Torvalds 
8321da177e4SLinus Torvalds /*
833d9c407b1SChuck Lever  * 3.3.7  WRITE3args
834d9c407b1SChuck Lever  *
835d9c407b1SChuck Lever  *	enum stable_how {
836d9c407b1SChuck Lever  *		UNSTABLE  = 0,
837d9c407b1SChuck Lever  *		DATA_SYNC = 1,
838d9c407b1SChuck Lever  *		FILE_SYNC = 2
839d9c407b1SChuck Lever  *	};
840d9c407b1SChuck Lever  *
841d9c407b1SChuck Lever  *	struct WRITE3args {
842d9c407b1SChuck Lever  *		nfs_fh3		file;
843d9c407b1SChuck Lever  *		offset3		offset;
844d9c407b1SChuck Lever  *		count3		count;
845d9c407b1SChuck Lever  *		stable_how	stable;
846d9c407b1SChuck Lever  *		opaque		data<>;
847d9c407b1SChuck Lever  *	};
848d9c407b1SChuck Lever  */
849d9c407b1SChuck Lever static void encode_write3args(struct xdr_stream *xdr,
850d9c407b1SChuck Lever 			      const struct nfs_writeargs *args)
851d9c407b1SChuck Lever {
852d9c407b1SChuck Lever 	__be32 *p;
853d9c407b1SChuck Lever 
854d9c407b1SChuck Lever 	encode_nfs_fh3(xdr, args->fh);
855d9c407b1SChuck Lever 
856d9c407b1SChuck Lever 	p = xdr_reserve_space(xdr, 8 + 4 + 4 + 4);
857d9c407b1SChuck Lever 	p = xdr_encode_hyper(p, args->offset);
858d9c407b1SChuck Lever 	*p++ = cpu_to_be32(args->count);
859d9c407b1SChuck Lever 
860d9c407b1SChuck Lever 	BUG_ON(args->stable > NFS_FILE_SYNC);
861d9c407b1SChuck Lever 	*p++ = cpu_to_be32(args->stable);
862d9c407b1SChuck Lever 
863d9c407b1SChuck Lever 	*p = cpu_to_be32(args->count);
864d9c407b1SChuck Lever 	xdr_write_pages(xdr, args->pages, args->pgbase, args->count);
865d9c407b1SChuck Lever }
866d9c407b1SChuck Lever 
867d9c407b1SChuck Lever static int nfs3_xdr_enc_write3args(struct rpc_rqst *req, __be32 *p,
868d9c407b1SChuck Lever 				   const struct nfs_writeargs *args)
869d9c407b1SChuck Lever {
870d9c407b1SChuck Lever 	struct xdr_stream xdr;
871d9c407b1SChuck Lever 
872d9c407b1SChuck Lever 	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
873d9c407b1SChuck Lever 	encode_write3args(&xdr, args);
874d9c407b1SChuck Lever 	xdr.buf->flags |= XDRBUF_WRITE;
875d9c407b1SChuck Lever 	return 0;
876d9c407b1SChuck Lever }
877d9c407b1SChuck Lever 
878d9c407b1SChuck Lever /*
8791da177e4SLinus Torvalds  * Encode CREATE arguments
8801da177e4SLinus Torvalds  */
8811da177e4SLinus Torvalds static int
882d61005a6SAl Viro nfs3_xdr_createargs(struct rpc_rqst *req, __be32 *p, struct nfs3_createargs *args)
8831da177e4SLinus Torvalds {
8841da177e4SLinus Torvalds 	p = xdr_encode_fhandle(p, args->fh);
8851da177e4SLinus Torvalds 	p = xdr_encode_array(p, args->name, args->len);
8861da177e4SLinus Torvalds 
8871da177e4SLinus Torvalds 	*p++ = htonl(args->createmode);
8881da177e4SLinus Torvalds 	if (args->createmode == NFS3_CREATE_EXCLUSIVE) {
8891da177e4SLinus Torvalds 		*p++ = args->verifier[0];
8901da177e4SLinus Torvalds 		*p++ = args->verifier[1];
8911da177e4SLinus Torvalds 	} else
8921da177e4SLinus Torvalds 		p = xdr_encode_sattr(p, args->sattr);
8931da177e4SLinus Torvalds 
8941da177e4SLinus Torvalds 	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
8951da177e4SLinus Torvalds 	return 0;
8961da177e4SLinus Torvalds }
8971da177e4SLinus Torvalds 
8981da177e4SLinus Torvalds /*
899d9c407b1SChuck Lever  * 3.3.8  CREATE3args
900d9c407b1SChuck Lever  *
901d9c407b1SChuck Lever  *	enum createmode3 {
902d9c407b1SChuck Lever  *		UNCHECKED = 0,
903d9c407b1SChuck Lever  *		GUARDED   = 1,
904d9c407b1SChuck Lever  *		EXCLUSIVE = 2
905d9c407b1SChuck Lever  *	};
906d9c407b1SChuck Lever  *
907d9c407b1SChuck Lever  *	union createhow3 switch (createmode3 mode) {
908d9c407b1SChuck Lever  *	case UNCHECKED:
909d9c407b1SChuck Lever  *	case GUARDED:
910d9c407b1SChuck Lever  *		sattr3       obj_attributes;
911d9c407b1SChuck Lever  *	case EXCLUSIVE:
912d9c407b1SChuck Lever  *		createverf3  verf;
913d9c407b1SChuck Lever  *	};
914d9c407b1SChuck Lever  *
915d9c407b1SChuck Lever  *	struct CREATE3args {
916d9c407b1SChuck Lever  *		diropargs3	where;
917d9c407b1SChuck Lever  *		createhow3	how;
918d9c407b1SChuck Lever  *	};
919d9c407b1SChuck Lever  */
920d9c407b1SChuck Lever static void encode_createhow3(struct xdr_stream *xdr,
921d9c407b1SChuck Lever 			      const struct nfs3_createargs *args)
922d9c407b1SChuck Lever {
923d9c407b1SChuck Lever 	encode_uint32(xdr, args->createmode);
924d9c407b1SChuck Lever 	switch (args->createmode) {
925d9c407b1SChuck Lever 	case NFS3_CREATE_UNCHECKED:
926d9c407b1SChuck Lever 	case NFS3_CREATE_GUARDED:
927d9c407b1SChuck Lever 		encode_sattr3(xdr, args->sattr);
928d9c407b1SChuck Lever 		break;
929d9c407b1SChuck Lever 	case NFS3_CREATE_EXCLUSIVE:
930d9c407b1SChuck Lever 		encode_createverf3(xdr, args->verifier);
931d9c407b1SChuck Lever 		break;
932d9c407b1SChuck Lever 	default:
933d9c407b1SChuck Lever 		BUG();
934d9c407b1SChuck Lever 	}
935d9c407b1SChuck Lever }
936d9c407b1SChuck Lever 
937d9c407b1SChuck Lever static int nfs3_xdr_enc_create3args(struct rpc_rqst *req, __be32 *p,
938d9c407b1SChuck Lever 				    const struct nfs3_createargs *args)
939d9c407b1SChuck Lever {
940d9c407b1SChuck Lever 	struct xdr_stream xdr;
941d9c407b1SChuck Lever 
942d9c407b1SChuck Lever 	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
943d9c407b1SChuck Lever 	encode_diropargs3(&xdr, args->fh, args->name, args->len);
944d9c407b1SChuck Lever 	encode_createhow3(&xdr, args);
945d9c407b1SChuck Lever 	return 0;
946d9c407b1SChuck Lever }
947d9c407b1SChuck Lever 
948d9c407b1SChuck Lever /*
9491da177e4SLinus Torvalds  * Encode MKDIR arguments
9501da177e4SLinus Torvalds  */
9511da177e4SLinus Torvalds static int
952d61005a6SAl Viro nfs3_xdr_mkdirargs(struct rpc_rqst *req, __be32 *p, struct nfs3_mkdirargs *args)
9531da177e4SLinus Torvalds {
9541da177e4SLinus Torvalds 	p = xdr_encode_fhandle(p, args->fh);
9551da177e4SLinus Torvalds 	p = xdr_encode_array(p, args->name, args->len);
9561da177e4SLinus Torvalds 	p = xdr_encode_sattr(p, args->sattr);
9571da177e4SLinus Torvalds 	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
9581da177e4SLinus Torvalds 	return 0;
9591da177e4SLinus Torvalds }
9601da177e4SLinus Torvalds 
9611da177e4SLinus Torvalds /*
962d9c407b1SChuck Lever  * 3.3.9  MKDIR3args
963d9c407b1SChuck Lever  *
964d9c407b1SChuck Lever  *	struct MKDIR3args {
965d9c407b1SChuck Lever  *		diropargs3	where;
966d9c407b1SChuck Lever  *		sattr3		attributes;
967d9c407b1SChuck Lever  *	};
968d9c407b1SChuck Lever  */
969d9c407b1SChuck Lever static int nfs3_xdr_enc_mkdir3args(struct rpc_rqst *req, __be32 *p,
970d9c407b1SChuck Lever 				   const struct nfs3_mkdirargs *args)
971d9c407b1SChuck Lever {
972d9c407b1SChuck Lever 	struct xdr_stream xdr;
973d9c407b1SChuck Lever 
974d9c407b1SChuck Lever 	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
975d9c407b1SChuck Lever 	encode_diropargs3(&xdr, args->fh, args->name, args->len);
976d9c407b1SChuck Lever 	encode_sattr3(&xdr, args->sattr);
977d9c407b1SChuck Lever 	return 0;
978d9c407b1SChuck Lever }
979d9c407b1SChuck Lever 
980d9c407b1SChuck Lever /*
9811da177e4SLinus Torvalds  * Encode SYMLINK arguments
9821da177e4SLinus Torvalds  */
9831da177e4SLinus Torvalds static int
984d61005a6SAl Viro nfs3_xdr_symlinkargs(struct rpc_rqst *req, __be32 *p, struct nfs3_symlinkargs *args)
9851da177e4SLinus Torvalds {
9861da177e4SLinus Torvalds 	p = xdr_encode_fhandle(p, args->fromfh);
9871da177e4SLinus Torvalds 	p = xdr_encode_array(p, args->fromname, args->fromlen);
9881da177e4SLinus Torvalds 	p = xdr_encode_sattr(p, args->sattr);
98994a6d753SChuck Lever 	*p++ = htonl(args->pathlen);
9901da177e4SLinus Torvalds 	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
99194a6d753SChuck Lever 
99294a6d753SChuck Lever 	/* Copy the page */
99394a6d753SChuck Lever 	xdr_encode_pages(&req->rq_snd_buf, args->pages, 0, args->pathlen);
9941da177e4SLinus Torvalds 	return 0;
9951da177e4SLinus Torvalds }
9961da177e4SLinus Torvalds 
9971da177e4SLinus Torvalds /*
998d9c407b1SChuck Lever  * 3.3.10  SYMLINK3args
999d9c407b1SChuck Lever  *
1000d9c407b1SChuck Lever  *	struct symlinkdata3 {
1001d9c407b1SChuck Lever  *		sattr3		symlink_attributes;
1002d9c407b1SChuck Lever  *		nfspath3	symlink_data;
1003d9c407b1SChuck Lever  *	};
1004d9c407b1SChuck Lever  *
1005d9c407b1SChuck Lever  *	struct SYMLINK3args {
1006d9c407b1SChuck Lever  *		diropargs3	where;
1007d9c407b1SChuck Lever  *		symlinkdata3	symlink;
1008d9c407b1SChuck Lever  *	};
1009d9c407b1SChuck Lever  */
1010d9c407b1SChuck Lever static void encode_symlinkdata3(struct xdr_stream *xdr,
1011d9c407b1SChuck Lever 				const struct nfs3_symlinkargs *args)
1012d9c407b1SChuck Lever {
1013d9c407b1SChuck Lever 	encode_sattr3(xdr, args->sattr);
1014d9c407b1SChuck Lever 	encode_nfspath3(xdr, args->pages, args->pathlen);
1015d9c407b1SChuck Lever }
1016d9c407b1SChuck Lever 
1017d9c407b1SChuck Lever static int nfs3_xdr_enc_symlink3args(struct rpc_rqst *req, __be32 *p,
1018d9c407b1SChuck Lever 				     const struct nfs3_symlinkargs *args)
1019d9c407b1SChuck Lever {
1020d9c407b1SChuck Lever 	struct xdr_stream xdr;
1021d9c407b1SChuck Lever 
1022d9c407b1SChuck Lever 	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1023d9c407b1SChuck Lever 	encode_diropargs3(&xdr, args->fromfh, args->fromname, args->fromlen);
1024d9c407b1SChuck Lever 	encode_symlinkdata3(&xdr, args);
1025d9c407b1SChuck Lever 	return 0;
1026d9c407b1SChuck Lever }
1027d9c407b1SChuck Lever 
1028d9c407b1SChuck Lever /*
10291da177e4SLinus Torvalds  * Encode MKNOD arguments
10301da177e4SLinus Torvalds  */
10311da177e4SLinus Torvalds static int
1032d61005a6SAl Viro nfs3_xdr_mknodargs(struct rpc_rqst *req, __be32 *p, struct nfs3_mknodargs *args)
10331da177e4SLinus Torvalds {
10341da177e4SLinus Torvalds 	p = xdr_encode_fhandle(p, args->fh);
10351da177e4SLinus Torvalds 	p = xdr_encode_array(p, args->name, args->len);
10361da177e4SLinus Torvalds 	*p++ = htonl(args->type);
10371da177e4SLinus Torvalds 	p = xdr_encode_sattr(p, args->sattr);
10381da177e4SLinus Torvalds 	if (args->type == NF3CHR || args->type == NF3BLK) {
10391da177e4SLinus Torvalds 		*p++ = htonl(MAJOR(args->rdev));
10401da177e4SLinus Torvalds 		*p++ = htonl(MINOR(args->rdev));
10411da177e4SLinus Torvalds 	}
10421da177e4SLinus Torvalds 
10431da177e4SLinus Torvalds 	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
10441da177e4SLinus Torvalds 	return 0;
10451da177e4SLinus Torvalds }
10461da177e4SLinus Torvalds 
10471da177e4SLinus Torvalds /*
1048d9c407b1SChuck Lever  * 3.3.11  MKNOD3args
1049d9c407b1SChuck Lever  *
1050d9c407b1SChuck Lever  *	struct devicedata3 {
1051d9c407b1SChuck Lever  *		sattr3		dev_attributes;
1052d9c407b1SChuck Lever  *		specdata3	spec;
1053d9c407b1SChuck Lever  *	};
1054d9c407b1SChuck Lever  *
1055d9c407b1SChuck Lever  *	union mknoddata3 switch (ftype3 type) {
1056d9c407b1SChuck Lever  *	case NF3CHR:
1057d9c407b1SChuck Lever  *	case NF3BLK:
1058d9c407b1SChuck Lever  *		devicedata3	device;
1059d9c407b1SChuck Lever  *	case NF3SOCK:
1060d9c407b1SChuck Lever  *	case NF3FIFO:
1061d9c407b1SChuck Lever  *		sattr3		pipe_attributes;
1062d9c407b1SChuck Lever  *	default:
1063d9c407b1SChuck Lever  *		void;
1064d9c407b1SChuck Lever  *	};
1065d9c407b1SChuck Lever  *
1066d9c407b1SChuck Lever  *	struct MKNOD3args {
1067d9c407b1SChuck Lever  *		diropargs3	where;
1068d9c407b1SChuck Lever  *		mknoddata3	what;
1069d9c407b1SChuck Lever  *	};
1070d9c407b1SChuck Lever  */
1071d9c407b1SChuck Lever static void encode_devicedata3(struct xdr_stream *xdr,
1072d9c407b1SChuck Lever 			       const struct nfs3_mknodargs *args)
1073d9c407b1SChuck Lever {
1074d9c407b1SChuck Lever 	encode_sattr3(xdr, args->sattr);
1075d9c407b1SChuck Lever 	encode_specdata3(xdr, args->rdev);
1076d9c407b1SChuck Lever }
1077d9c407b1SChuck Lever 
1078d9c407b1SChuck Lever static void encode_mknoddata3(struct xdr_stream *xdr,
1079d9c407b1SChuck Lever 			      const struct nfs3_mknodargs *args)
1080d9c407b1SChuck Lever {
1081d9c407b1SChuck Lever 	encode_ftype3(xdr, args->type);
1082d9c407b1SChuck Lever 	switch (args->type) {
1083d9c407b1SChuck Lever 	case NF3CHR:
1084d9c407b1SChuck Lever 	case NF3BLK:
1085d9c407b1SChuck Lever 		encode_devicedata3(xdr, args);
1086d9c407b1SChuck Lever 		break;
1087d9c407b1SChuck Lever 	case NF3SOCK:
1088d9c407b1SChuck Lever 	case NF3FIFO:
1089d9c407b1SChuck Lever 		encode_sattr3(xdr, args->sattr);
1090d9c407b1SChuck Lever 		break;
1091d9c407b1SChuck Lever 	case NF3REG:
1092d9c407b1SChuck Lever 	case NF3DIR:
1093d9c407b1SChuck Lever 		break;
1094d9c407b1SChuck Lever 	default:
1095d9c407b1SChuck Lever 		BUG();
1096d9c407b1SChuck Lever 	}
1097d9c407b1SChuck Lever }
1098d9c407b1SChuck Lever 
1099d9c407b1SChuck Lever static int nfs3_xdr_enc_mknod3args(struct rpc_rqst *req, __be32 *p,
1100d9c407b1SChuck Lever 				   const struct nfs3_mknodargs *args)
1101d9c407b1SChuck Lever {
1102d9c407b1SChuck Lever 	struct xdr_stream xdr;
1103d9c407b1SChuck Lever 
1104d9c407b1SChuck Lever 	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1105d9c407b1SChuck Lever 	encode_diropargs3(&xdr, args->fh, args->name, args->len);
1106d9c407b1SChuck Lever 	encode_mknoddata3(&xdr, args);
1107d9c407b1SChuck Lever 	return 0;
1108d9c407b1SChuck Lever }
1109d9c407b1SChuck Lever 
1110d9c407b1SChuck Lever /*
1111d9c407b1SChuck Lever  * 3.3.12  REMOVE3args
1112d9c407b1SChuck Lever  *
1113d9c407b1SChuck Lever  *	struct REMOVE3args {
1114d9c407b1SChuck Lever  *		diropargs3  object;
1115d9c407b1SChuck Lever  *	};
1116d9c407b1SChuck Lever  */
1117d9c407b1SChuck Lever static int nfs3_xdr_enc_remove3args(struct rpc_rqst *req, __be32 *p,
1118d9c407b1SChuck Lever 				    const struct nfs_removeargs *args)
1119d9c407b1SChuck Lever {
1120d9c407b1SChuck Lever 	struct xdr_stream xdr;
1121d9c407b1SChuck Lever 
1122d9c407b1SChuck Lever 	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1123d9c407b1SChuck Lever 	encode_diropargs3(&xdr, args->fh, args->name.name, args->name.len);
1124d9c407b1SChuck Lever 	return 0;
1125d9c407b1SChuck Lever }
1126d9c407b1SChuck Lever 
1127d9c407b1SChuck Lever /*
11281da177e4SLinus Torvalds  * Encode RENAME arguments
11291da177e4SLinus Torvalds  */
11301da177e4SLinus Torvalds static int
1131920769f0SJeff Layton nfs3_xdr_renameargs(struct rpc_rqst *req, __be32 *p, struct nfs_renameargs *args)
11321da177e4SLinus Torvalds {
1133920769f0SJeff Layton 	p = xdr_encode_fhandle(p, args->old_dir);
1134920769f0SJeff Layton 	p = xdr_encode_array(p, args->old_name->name, args->old_name->len);
1135920769f0SJeff Layton 	p = xdr_encode_fhandle(p, args->new_dir);
1136920769f0SJeff Layton 	p = xdr_encode_array(p, args->new_name->name, args->new_name->len);
11371da177e4SLinus Torvalds 	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
11381da177e4SLinus Torvalds 	return 0;
11391da177e4SLinus Torvalds }
11401da177e4SLinus Torvalds 
11411da177e4SLinus Torvalds /*
1142d9c407b1SChuck Lever  * 3.3.14  RENAME3args
1143d9c407b1SChuck Lever  *
1144d9c407b1SChuck Lever  *	struct RENAME3args {
1145d9c407b1SChuck Lever  *		diropargs3	from;
1146d9c407b1SChuck Lever  *		diropargs3	to;
1147d9c407b1SChuck Lever  *	};
1148d9c407b1SChuck Lever  */
1149d9c407b1SChuck Lever static int nfs3_xdr_enc_rename3args(struct rpc_rqst *req, __be32 *p,
1150d9c407b1SChuck Lever 				    const struct nfs_renameargs *args)
1151d9c407b1SChuck Lever {
1152d9c407b1SChuck Lever 	const struct qstr *old = args->old_name;
1153d9c407b1SChuck Lever 	const struct qstr *new = args->new_name;
1154d9c407b1SChuck Lever 	struct xdr_stream xdr;
1155d9c407b1SChuck Lever 
1156d9c407b1SChuck Lever 	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1157d9c407b1SChuck Lever 	encode_diropargs3(&xdr, args->old_dir, old->name, old->len);
1158d9c407b1SChuck Lever 	encode_diropargs3(&xdr, args->new_dir, new->name, new->len);
1159d9c407b1SChuck Lever 	return 0;
1160d9c407b1SChuck Lever }
1161d9c407b1SChuck Lever 
1162d9c407b1SChuck Lever /*
11631da177e4SLinus Torvalds  * Encode LINK arguments
11641da177e4SLinus Torvalds  */
11651da177e4SLinus Torvalds static int
1166d61005a6SAl Viro nfs3_xdr_linkargs(struct rpc_rqst *req, __be32 *p, struct nfs3_linkargs *args)
11671da177e4SLinus Torvalds {
11681da177e4SLinus Torvalds 	p = xdr_encode_fhandle(p, args->fromfh);
11691da177e4SLinus Torvalds 	p = xdr_encode_fhandle(p, args->tofh);
11701da177e4SLinus Torvalds 	p = xdr_encode_array(p, args->toname, args->tolen);
11711da177e4SLinus Torvalds 	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
11721da177e4SLinus Torvalds 	return 0;
11731da177e4SLinus Torvalds }
11741da177e4SLinus Torvalds 
11751da177e4SLinus Torvalds /*
1176d9c407b1SChuck Lever  * 3.3.15  LINK3args
1177d9c407b1SChuck Lever  *
1178d9c407b1SChuck Lever  *	struct LINK3args {
1179d9c407b1SChuck Lever  *		nfs_fh3		file;
1180d9c407b1SChuck Lever  *		diropargs3	link;
1181d9c407b1SChuck Lever  *	};
1182d9c407b1SChuck Lever  */
1183d9c407b1SChuck Lever static int nfs3_xdr_enc_link3args(struct rpc_rqst *req, __be32 *p,
1184d9c407b1SChuck Lever 				  const struct nfs3_linkargs *args)
1185d9c407b1SChuck Lever {
1186d9c407b1SChuck Lever 	struct xdr_stream xdr;
1187d9c407b1SChuck Lever 
1188d9c407b1SChuck Lever 	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1189d9c407b1SChuck Lever 	encode_nfs_fh3(&xdr, args->fromfh);
1190d9c407b1SChuck Lever 	encode_diropargs3(&xdr, args->tofh, args->toname, args->tolen);
1191d9c407b1SChuck Lever 	return 0;
1192d9c407b1SChuck Lever }
1193d9c407b1SChuck Lever 
1194d9c407b1SChuck Lever /*
11951da177e4SLinus Torvalds  * Encode arguments to readdir call
11961da177e4SLinus Torvalds  */
11971da177e4SLinus Torvalds static int
1198d61005a6SAl Viro nfs3_xdr_readdirargs(struct rpc_rqst *req, __be32 *p, struct nfs3_readdirargs *args)
11991da177e4SLinus Torvalds {
1200a17c2153STrond Myklebust 	struct rpc_auth	*auth = req->rq_cred->cr_auth;
12011da177e4SLinus Torvalds 	unsigned int replen;
12021da177e4SLinus Torvalds 	u32 count = args->count;
12031da177e4SLinus Torvalds 
12041da177e4SLinus Torvalds 	p = xdr_encode_fhandle(p, args->fh);
12051da177e4SLinus Torvalds 	p = xdr_encode_hyper(p, args->cookie);
12061da177e4SLinus Torvalds 	*p++ = args->verf[0];
12071da177e4SLinus Torvalds 	*p++ = args->verf[1];
12081da177e4SLinus Torvalds 	if (args->plus) {
12091da177e4SLinus Torvalds 		/* readdirplus: need dircount + buffer size.
12101da177e4SLinus Torvalds 		 * We just make sure we make dircount big enough */
12111da177e4SLinus Torvalds 		*p++ = htonl(count >> 3);
12121da177e4SLinus Torvalds 	}
12131da177e4SLinus Torvalds 	*p++ = htonl(count);
12141da177e4SLinus Torvalds 	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
12151da177e4SLinus Torvalds 
12161da177e4SLinus Torvalds 	/* Inline the page array */
12171da177e4SLinus Torvalds 	replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS3_readdirres_sz) << 2;
12181da177e4SLinus Torvalds 	xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, 0, count);
12191da177e4SLinus Torvalds 	return 0;
12201da177e4SLinus Torvalds }
12211da177e4SLinus Torvalds 
12221da177e4SLinus Torvalds /*
1223d9c407b1SChuck Lever  * 3.3.16  READDIR3args
1224d9c407b1SChuck Lever  *
1225d9c407b1SChuck Lever  *	struct READDIR3args {
1226d9c407b1SChuck Lever  *		nfs_fh3		dir;
1227d9c407b1SChuck Lever  *		cookie3		cookie;
1228d9c407b1SChuck Lever  *		cookieverf3	cookieverf;
1229d9c407b1SChuck Lever  *		count3		count;
1230d9c407b1SChuck Lever  *	};
1231d9c407b1SChuck Lever  */
1232d9c407b1SChuck Lever static void encode_readdir3args(struct xdr_stream *xdr,
1233d9c407b1SChuck Lever 				const struct nfs3_readdirargs *args)
1234d9c407b1SChuck Lever {
1235d9c407b1SChuck Lever 	__be32 *p;
1236d9c407b1SChuck Lever 
1237d9c407b1SChuck Lever 	encode_nfs_fh3(xdr, args->fh);
1238d9c407b1SChuck Lever 
1239d9c407b1SChuck Lever 	p = xdr_reserve_space(xdr, 8 + NFS3_COOKIEVERFSIZE + 4);
1240d9c407b1SChuck Lever 	p = xdr_encode_cookie3(p, args->cookie);
1241d9c407b1SChuck Lever 	p = xdr_encode_cookieverf3(p, args->verf);
1242d9c407b1SChuck Lever 	*p = cpu_to_be32(args->count);
1243d9c407b1SChuck Lever }
1244d9c407b1SChuck Lever 
1245d9c407b1SChuck Lever static int nfs3_xdr_enc_readdir3args(struct rpc_rqst *req, __be32 *p,
1246d9c407b1SChuck Lever 				     const struct nfs3_readdirargs *args)
1247d9c407b1SChuck Lever {
1248d9c407b1SChuck Lever 	struct xdr_stream xdr;
1249d9c407b1SChuck Lever 
1250d9c407b1SChuck Lever 	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1251d9c407b1SChuck Lever 	encode_readdir3args(&xdr, args);
1252d9c407b1SChuck Lever 	prepare_reply_buffer(req, args->pages, 0,
1253d9c407b1SChuck Lever 				args->count, NFS3_readdirres_sz);
1254d9c407b1SChuck Lever 	return 0;
1255d9c407b1SChuck Lever }
1256d9c407b1SChuck Lever 
1257d9c407b1SChuck Lever /*
1258d9c407b1SChuck Lever  * 3.3.17  READDIRPLUS3args
1259d9c407b1SChuck Lever  *
1260d9c407b1SChuck Lever  *	struct READDIRPLUS3args {
1261d9c407b1SChuck Lever  *		nfs_fh3		dir;
1262d9c407b1SChuck Lever  *		cookie3		cookie;
1263d9c407b1SChuck Lever  *		cookieverf3	cookieverf;
1264d9c407b1SChuck Lever  *		count3		dircount;
1265d9c407b1SChuck Lever  *		count3		maxcount;
1266d9c407b1SChuck Lever  *	};
1267d9c407b1SChuck Lever  */
1268d9c407b1SChuck Lever static void encode_readdirplus3args(struct xdr_stream *xdr,
1269d9c407b1SChuck Lever 				    const struct nfs3_readdirargs *args)
1270d9c407b1SChuck Lever {
1271d9c407b1SChuck Lever 	__be32 *p;
1272d9c407b1SChuck Lever 
1273d9c407b1SChuck Lever 	encode_nfs_fh3(xdr, args->fh);
1274d9c407b1SChuck Lever 
1275d9c407b1SChuck Lever 	p = xdr_reserve_space(xdr, 8 + NFS3_COOKIEVERFSIZE + 4 + 4);
1276d9c407b1SChuck Lever 	p = xdr_encode_cookie3(p, args->cookie);
1277d9c407b1SChuck Lever 	p = xdr_encode_cookieverf3(p, args->verf);
1278d9c407b1SChuck Lever 
1279d9c407b1SChuck Lever 	/*
1280d9c407b1SChuck Lever 	 * readdirplus: need dircount + buffer size.
1281d9c407b1SChuck Lever 	 * We just make sure we make dircount big enough
1282d9c407b1SChuck Lever 	 */
1283d9c407b1SChuck Lever 	*p++ = cpu_to_be32(args->count >> 3);
1284d9c407b1SChuck Lever 
1285d9c407b1SChuck Lever 	*p = cpu_to_be32(args->count);
1286d9c407b1SChuck Lever }
1287d9c407b1SChuck Lever 
1288d9c407b1SChuck Lever static int nfs3_xdr_enc_readdirplus3args(struct rpc_rqst *req, __be32 *p,
1289d9c407b1SChuck Lever 					 const struct nfs3_readdirargs *args)
1290d9c407b1SChuck Lever {
1291d9c407b1SChuck Lever 	struct xdr_stream xdr;
1292d9c407b1SChuck Lever 
1293d9c407b1SChuck Lever 	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1294d9c407b1SChuck Lever 	encode_readdirplus3args(&xdr, args);
1295d9c407b1SChuck Lever 	prepare_reply_buffer(req, args->pages, 0,
1296d9c407b1SChuck Lever 				args->count, NFS3_readdirres_sz);
1297d9c407b1SChuck Lever 	return 0;
1298d9c407b1SChuck Lever }
1299d9c407b1SChuck Lever 
1300d9c407b1SChuck Lever /*
13011da177e4SLinus Torvalds  * Decode the result of a readdir call.
13021da177e4SLinus Torvalds  * We just check for syntactical correctness.
13031da177e4SLinus Torvalds  */
13041da177e4SLinus Torvalds static int
1305d61005a6SAl Viro nfs3_xdr_readdirres(struct rpc_rqst *req, __be32 *p, struct nfs3_readdirres *res)
13061da177e4SLinus Torvalds {
13071da177e4SLinus Torvalds 	struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
13081da177e4SLinus Torvalds 	struct kvec *iov = rcvbuf->head;
13091da177e4SLinus Torvalds 	struct page **page;
1310c957c526SChuck Lever 	size_t hdrlen;
1311afa8ccc9SBryan Schumaker 	u32 recvd, pglen;
1312ac396128STrond Myklebust 	int status;
13131da177e4SLinus Torvalds 
13141da177e4SLinus Torvalds 	status = ntohl(*p++);
13151da177e4SLinus Torvalds 	/* Decode post_op_attrs */
13161da177e4SLinus Torvalds 	p = xdr_decode_post_op_attr(p, res->dir_attr);
13171da177e4SLinus Torvalds 	if (status)
1318856dff3dSBenny Halevy 		return nfs_stat_to_errno(status);
13191da177e4SLinus Torvalds 	/* Decode verifier cookie */
13201da177e4SLinus Torvalds 	if (res->verf) {
13211da177e4SLinus Torvalds 		res->verf[0] = *p++;
13221da177e4SLinus Torvalds 		res->verf[1] = *p++;
13231da177e4SLinus Torvalds 	} else {
13241da177e4SLinus Torvalds 		p += 2;
13251da177e4SLinus Torvalds 	}
13261da177e4SLinus Torvalds 
13271da177e4SLinus Torvalds 	hdrlen = (u8 *) p - (u8 *) iov->iov_base;
13281da177e4SLinus Torvalds 	if (iov->iov_len < hdrlen) {
1329fe82a183SChuck Lever 		dprintk("NFS: READDIR reply header overflowed:"
1330c957c526SChuck Lever 				"length %Zu > %Zu\n", hdrlen, iov->iov_len);
13311da177e4SLinus Torvalds 		return -errno_NFSERR_IO;
13321da177e4SLinus Torvalds 	} else if (iov->iov_len != hdrlen) {
13331da177e4SLinus Torvalds 		dprintk("NFS: READDIR header is short. iovec will be shifted.\n");
13341da177e4SLinus Torvalds 		xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen);
13351da177e4SLinus Torvalds 	}
13361da177e4SLinus Torvalds 
13371da177e4SLinus Torvalds 	pglen = rcvbuf->page_len;
13381da177e4SLinus Torvalds 	recvd = rcvbuf->len - hdrlen;
13391da177e4SLinus Torvalds 	if (pglen > recvd)
13401da177e4SLinus Torvalds 		pglen = recvd;
13411da177e4SLinus Torvalds 	page = rcvbuf->pages;
1342643f8111SJeff Layton 
1343ac396128STrond Myklebust 	return pglen;
13441da177e4SLinus Torvalds }
13451da177e4SLinus Torvalds 
13460dbb4c67SAl Viro __be32 *
134782f2e547SBryan Schumaker nfs3_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry, struct nfs_server *server, int plus)
13481da177e4SLinus Torvalds {
1349babddc72SBryan Schumaker 	__be32 *p;
13501da177e4SLinus Torvalds 	struct nfs_entry old = *entry;
13511da177e4SLinus Torvalds 
1352babddc72SBryan Schumaker 	p = xdr_inline_decode(xdr, 4);
1353babddc72SBryan Schumaker 	if (unlikely(!p))
1354babddc72SBryan Schumaker 		goto out_overflow;
1355babddc72SBryan Schumaker 	if (!ntohl(*p++)) {
1356babddc72SBryan Schumaker 		p = xdr_inline_decode(xdr, 4);
1357babddc72SBryan Schumaker 		if (unlikely(!p))
1358babddc72SBryan Schumaker 			goto out_overflow;
1359babddc72SBryan Schumaker 		if (!ntohl(*p++))
13601da177e4SLinus Torvalds 			return ERR_PTR(-EAGAIN);
13611da177e4SLinus Torvalds 		entry->eof = 1;
13621da177e4SLinus Torvalds 		return ERR_PTR(-EBADCOOKIE);
13631da177e4SLinus Torvalds 	}
13641da177e4SLinus Torvalds 
1365babddc72SBryan Schumaker 	p = xdr_inline_decode(xdr, 12);
1366babddc72SBryan Schumaker 	if (unlikely(!p))
1367babddc72SBryan Schumaker 		goto out_overflow;
13681da177e4SLinus Torvalds 	p = xdr_decode_hyper(p, &entry->ino);
13691da177e4SLinus Torvalds 	entry->len  = ntohl(*p++);
1370babddc72SBryan Schumaker 
1371babddc72SBryan Schumaker 	p = xdr_inline_decode(xdr, entry->len + 8);
1372babddc72SBryan Schumaker 	if (unlikely(!p))
1373babddc72SBryan Schumaker 		goto out_overflow;
13741da177e4SLinus Torvalds 	entry->name = (const char *) p;
13751da177e4SLinus Torvalds 	p += XDR_QUADLEN(entry->len);
13761da177e4SLinus Torvalds 	entry->prev_cookie = entry->cookie;
13771da177e4SLinus Torvalds 	p = xdr_decode_hyper(p, &entry->cookie);
13781da177e4SLinus Torvalds 
13790b26a0bfSTrond Myklebust 	entry->d_type = DT_UNKNOWN;
13801da177e4SLinus Torvalds 	if (plus) {
13811da177e4SLinus Torvalds 		entry->fattr->valid = 0;
1382babddc72SBryan Schumaker 		p = xdr_decode_post_op_attr_stream(xdr, entry->fattr);
1383babddc72SBryan Schumaker 		if (IS_ERR(p))
1384babddc72SBryan Schumaker 			goto out_overflow_exit;
13850b26a0bfSTrond Myklebust 		entry->d_type = nfs_umode_to_dtype(entry->fattr->mode);
13861da177e4SLinus Torvalds 		/* In fact, a post_op_fh3: */
1387babddc72SBryan Schumaker 		p = xdr_inline_decode(xdr, 4);
1388babddc72SBryan Schumaker 		if (unlikely(!p))
1389babddc72SBryan Schumaker 			goto out_overflow;
13901da177e4SLinus Torvalds 		if (*p++) {
1391babddc72SBryan Schumaker 			p = xdr_decode_fhandle_stream(xdr, entry->fh);
1392babddc72SBryan Schumaker 			if (IS_ERR(p))
1393babddc72SBryan Schumaker 				goto out_overflow_exit;
13941da177e4SLinus Torvalds 			/* Ugh -- server reply was truncated */
13951da177e4SLinus Torvalds 			if (p == NULL) {
13961da177e4SLinus Torvalds 				dprintk("NFS: FH truncated\n");
13971da177e4SLinus Torvalds 				*entry = old;
13981da177e4SLinus Torvalds 				return ERR_PTR(-EAGAIN);
13991da177e4SLinus Torvalds 			}
14001da177e4SLinus Torvalds 		} else
14011da177e4SLinus Torvalds 			memset((u8*)(entry->fh), 0, sizeof(*entry->fh));
14021da177e4SLinus Torvalds 	}
14031da177e4SLinus Torvalds 
1404babddc72SBryan Schumaker 	p = xdr_inline_peek(xdr, 8);
1405babddc72SBryan Schumaker 	if (p != NULL)
14061da177e4SLinus Torvalds 		entry->eof = !p[0] && p[1];
1407babddc72SBryan Schumaker 	else
1408babddc72SBryan Schumaker 		entry->eof = 0;
1409babddc72SBryan Schumaker 
14101da177e4SLinus Torvalds 	return p;
1411babddc72SBryan Schumaker 
1412babddc72SBryan Schumaker out_overflow:
1413babddc72SBryan Schumaker 	print_overflow_msg(__func__, xdr);
1414babddc72SBryan Schumaker out_overflow_exit:
1415463a376eSTrond Myklebust 	return ERR_PTR(-EAGAIN);
14161da177e4SLinus Torvalds }
14171da177e4SLinus Torvalds 
14181da177e4SLinus Torvalds /*
14191da177e4SLinus Torvalds  * Encode COMMIT arguments
14201da177e4SLinus Torvalds  */
14211da177e4SLinus Torvalds static int
1422d61005a6SAl Viro nfs3_xdr_commitargs(struct rpc_rqst *req, __be32 *p, struct nfs_writeargs *args)
14231da177e4SLinus Torvalds {
14241da177e4SLinus Torvalds 	p = xdr_encode_fhandle(p, args->fh);
14251da177e4SLinus Torvalds 	p = xdr_encode_hyper(p, args->offset);
14261da177e4SLinus Torvalds 	*p++ = htonl(args->count);
14271da177e4SLinus Torvalds 	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
14281da177e4SLinus Torvalds 	return 0;
14291da177e4SLinus Torvalds }
14301da177e4SLinus Torvalds 
1431d9c407b1SChuck Lever /*
1432d9c407b1SChuck Lever  * 3.3.21  COMMIT3args
1433d9c407b1SChuck Lever  *
1434d9c407b1SChuck Lever  *	struct COMMIT3args {
1435d9c407b1SChuck Lever  *		nfs_fh3		file;
1436d9c407b1SChuck Lever  *		offset3		offset;
1437d9c407b1SChuck Lever  *		count3		count;
1438d9c407b1SChuck Lever  *	};
1439d9c407b1SChuck Lever  */
1440d9c407b1SChuck Lever static void encode_commit3args(struct xdr_stream *xdr,
1441d9c407b1SChuck Lever 			       const struct nfs_writeargs *args)
1442d9c407b1SChuck Lever {
1443d9c407b1SChuck Lever 	__be32 *p;
1444d9c407b1SChuck Lever 
1445d9c407b1SChuck Lever 	encode_nfs_fh3(xdr, args->fh);
1446d9c407b1SChuck Lever 
1447d9c407b1SChuck Lever 	p = xdr_reserve_space(xdr, 8 + 4);
1448d9c407b1SChuck Lever 	p = xdr_encode_hyper(p, args->offset);
1449d9c407b1SChuck Lever 	*p = cpu_to_be32(args->count);
1450d9c407b1SChuck Lever }
1451d9c407b1SChuck Lever 
1452d9c407b1SChuck Lever static int nfs3_xdr_enc_commit3args(struct rpc_rqst *req, __be32 *p,
1453d9c407b1SChuck Lever 				    const struct nfs_writeargs *args)
1454d9c407b1SChuck Lever {
1455d9c407b1SChuck Lever 	struct xdr_stream xdr;
1456d9c407b1SChuck Lever 
1457d9c407b1SChuck Lever 	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1458d9c407b1SChuck Lever 	encode_commit3args(&xdr, args);
1459d9c407b1SChuck Lever 	return 0;
1460d9c407b1SChuck Lever }
1461d9c407b1SChuck Lever 
1462b7fa0554SAndreas Gruenbacher #ifdef CONFIG_NFS_V3_ACL
1463b7fa0554SAndreas Gruenbacher /*
1464b7fa0554SAndreas Gruenbacher  * Encode GETACL arguments
1465b7fa0554SAndreas Gruenbacher  */
1466b7fa0554SAndreas Gruenbacher static int
1467d61005a6SAl Viro nfs3_xdr_getaclargs(struct rpc_rqst *req, __be32 *p,
1468b7fa0554SAndreas Gruenbacher 		    struct nfs3_getaclargs *args)
1469b7fa0554SAndreas Gruenbacher {
1470a17c2153STrond Myklebust 	struct rpc_auth	*auth = req->rq_cred->cr_auth;
1471b7fa0554SAndreas Gruenbacher 	unsigned int replen;
1472b7fa0554SAndreas Gruenbacher 
1473b7fa0554SAndreas Gruenbacher 	p = xdr_encode_fhandle(p, args->fh);
1474b7fa0554SAndreas Gruenbacher 	*p++ = htonl(args->mask);
1475b7fa0554SAndreas Gruenbacher 	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
1476b7fa0554SAndreas Gruenbacher 
1477b7fa0554SAndreas Gruenbacher 	if (args->mask & (NFS_ACL | NFS_DFACL)) {
1478b7fa0554SAndreas Gruenbacher 		/* Inline the page array */
1479b7fa0554SAndreas Gruenbacher 		replen = (RPC_REPHDRSIZE + auth->au_rslack +
1480b7fa0554SAndreas Gruenbacher 			  ACL3_getaclres_sz) << 2;
1481b7fa0554SAndreas Gruenbacher 		xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, 0,
1482b7fa0554SAndreas Gruenbacher 				 NFSACL_MAXPAGES << PAGE_SHIFT);
1483b7fa0554SAndreas Gruenbacher 	}
1484b7fa0554SAndreas Gruenbacher 	return 0;
1485b7fa0554SAndreas Gruenbacher }
1486b7fa0554SAndreas Gruenbacher 
1487d9c407b1SChuck Lever static int nfs3_xdr_enc_getacl3args(struct rpc_rqst *req, __be32 *p,
1488d9c407b1SChuck Lever 				    const struct nfs3_getaclargs *args)
1489d9c407b1SChuck Lever {
1490d9c407b1SChuck Lever 	struct xdr_stream xdr;
1491d9c407b1SChuck Lever 
1492d9c407b1SChuck Lever 	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1493d9c407b1SChuck Lever 	encode_nfs_fh3(&xdr, args->fh);
1494d9c407b1SChuck Lever 	encode_uint32(&xdr, args->mask);
1495d9c407b1SChuck Lever 	if (args->mask & (NFS_ACL | NFS_DFACL))
1496d9c407b1SChuck Lever 		prepare_reply_buffer(req, args->pages, 0,
1497d9c407b1SChuck Lever 					NFSACL_MAXPAGES << PAGE_SHIFT,
1498d9c407b1SChuck Lever 					ACL3_getaclres_sz);
1499d9c407b1SChuck Lever 	return 0;
1500d9c407b1SChuck Lever }
1501d9c407b1SChuck Lever 
1502b7fa0554SAndreas Gruenbacher /*
1503b7fa0554SAndreas Gruenbacher  * Encode SETACL arguments
1504b7fa0554SAndreas Gruenbacher  */
1505b7fa0554SAndreas Gruenbacher static int
1506d61005a6SAl Viro nfs3_xdr_setaclargs(struct rpc_rqst *req, __be32 *p,
1507b7fa0554SAndreas Gruenbacher                    struct nfs3_setaclargs *args)
1508b7fa0554SAndreas Gruenbacher {
1509b7fa0554SAndreas Gruenbacher 	struct xdr_buf *buf = &req->rq_snd_buf;
1510ae46141fSTrond Myklebust 	unsigned int base;
1511ae46141fSTrond Myklebust 	int err;
1512b7fa0554SAndreas Gruenbacher 
1513b7fa0554SAndreas Gruenbacher 	p = xdr_encode_fhandle(p, NFS_FH(args->inode));
1514b7fa0554SAndreas Gruenbacher 	*p++ = htonl(args->mask);
1515ae46141fSTrond Myklebust 	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
1516ae46141fSTrond Myklebust 	base = req->rq_slen;
1517b7fa0554SAndreas Gruenbacher 
1518ae46141fSTrond Myklebust 	if (args->npages != 0)
1519ae46141fSTrond Myklebust 		xdr_encode_pages(buf, args->pages, 0, args->len);
1520ae46141fSTrond Myklebust 	else
152183404372STrond Myklebust 		req->rq_slen = xdr_adjust_iovec(req->rq_svec,
152283404372STrond Myklebust 				p + XDR_QUADLEN(args->len));
1523b7fa0554SAndreas Gruenbacher 
1524b7fa0554SAndreas Gruenbacher 	err = nfsacl_encode(buf, base, args->inode,
1525b7fa0554SAndreas Gruenbacher 			    (args->mask & NFS_ACL) ?
1526b7fa0554SAndreas Gruenbacher 			    args->acl_access : NULL, 1, 0);
1527b7fa0554SAndreas Gruenbacher 	if (err > 0)
1528b7fa0554SAndreas Gruenbacher 		err = nfsacl_encode(buf, base + err, args->inode,
1529b7fa0554SAndreas Gruenbacher 				    (args->mask & NFS_DFACL) ?
1530b7fa0554SAndreas Gruenbacher 				    args->acl_default : NULL, 1,
1531b7fa0554SAndreas Gruenbacher 				    NFS_ACL_DEFAULT);
1532b7fa0554SAndreas Gruenbacher 	return (err > 0) ? 0 : err;
1533b7fa0554SAndreas Gruenbacher }
1534d9c407b1SChuck Lever 
1535d9c407b1SChuck Lever static int nfs3_xdr_enc_setacl3args(struct rpc_rqst *req, __be32 *p,
1536d9c407b1SChuck Lever 				    const struct nfs3_setaclargs *args)
1537d9c407b1SChuck Lever {
1538d9c407b1SChuck Lever 	struct xdr_stream xdr;
1539d9c407b1SChuck Lever 	unsigned int base;
1540d9c407b1SChuck Lever 	int error;
1541d9c407b1SChuck Lever 
1542d9c407b1SChuck Lever 	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1543d9c407b1SChuck Lever 	encode_nfs_fh3(&xdr, NFS_FH(args->inode));
1544d9c407b1SChuck Lever 	encode_uint32(&xdr, args->mask);
1545d9c407b1SChuck Lever 	if (args->npages != 0)
1546d9c407b1SChuck Lever 		xdr_write_pages(&xdr, args->pages, 0, args->len);
1547d9c407b1SChuck Lever 
1548d9c407b1SChuck Lever 	base = req->rq_slen;
1549d9c407b1SChuck Lever 	error = nfsacl_encode(xdr.buf, base, args->inode,
1550d9c407b1SChuck Lever 			    (args->mask & NFS_ACL) ?
1551d9c407b1SChuck Lever 			    args->acl_access : NULL, 1, 0);
1552d9c407b1SChuck Lever 	BUG_ON(error < 0);
1553d9c407b1SChuck Lever 	error = nfsacl_encode(xdr.buf, base + error, args->inode,
1554d9c407b1SChuck Lever 			    (args->mask & NFS_DFACL) ?
1555d9c407b1SChuck Lever 			    args->acl_default : NULL, 1,
1556d9c407b1SChuck Lever 			    NFS_ACL_DEFAULT);
1557d9c407b1SChuck Lever 	BUG_ON(error < 0);
1558d9c407b1SChuck Lever 	return 0;
1559d9c407b1SChuck Lever }
1560d9c407b1SChuck Lever 
1561b7fa0554SAndreas Gruenbacher #endif  /* CONFIG_NFS_V3_ACL */
1562b7fa0554SAndreas Gruenbacher 
15631da177e4SLinus Torvalds /*
15641da177e4SLinus Torvalds  * NFS XDR decode functions
15651da177e4SLinus Torvalds  */
15661da177e4SLinus Torvalds 
15671da177e4SLinus Torvalds /*
15681da177e4SLinus Torvalds  * Decode attrstat reply.
15691da177e4SLinus Torvalds  */
15701da177e4SLinus Torvalds static int
1571d61005a6SAl Viro nfs3_xdr_attrstat(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
15721da177e4SLinus Torvalds {
15731da177e4SLinus Torvalds 	int	status;
15741da177e4SLinus Torvalds 
15751da177e4SLinus Torvalds 	if ((status = ntohl(*p++)))
1576856dff3dSBenny Halevy 		return nfs_stat_to_errno(status);
15771da177e4SLinus Torvalds 	xdr_decode_fattr(p, fattr);
15781da177e4SLinus Torvalds 	return 0;
15791da177e4SLinus Torvalds }
15801da177e4SLinus Torvalds 
15811da177e4SLinus Torvalds /*
15821da177e4SLinus Torvalds  * Decode status+wcc_data reply
15831da177e4SLinus Torvalds  * SATTR, REMOVE, RMDIR
15841da177e4SLinus Torvalds  */
15851da177e4SLinus Torvalds static int
1586d61005a6SAl Viro nfs3_xdr_wccstat(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
15871da177e4SLinus Torvalds {
15881da177e4SLinus Torvalds 	int	status;
15891da177e4SLinus Torvalds 
15901da177e4SLinus Torvalds 	if ((status = ntohl(*p++)))
1591856dff3dSBenny Halevy 		status = nfs_stat_to_errno(status);
15921da177e4SLinus Torvalds 	xdr_decode_wcc_data(p, fattr);
15931da177e4SLinus Torvalds 	return status;
15941da177e4SLinus Torvalds }
15951da177e4SLinus Torvalds 
15964fdc17b2STrond Myklebust static int
15974fdc17b2STrond Myklebust nfs3_xdr_removeres(struct rpc_rqst *req, __be32 *p, struct nfs_removeres *res)
15984fdc17b2STrond Myklebust {
1599d346890bSTrond Myklebust 	return nfs3_xdr_wccstat(req, p, res->dir_attr);
16004fdc17b2STrond Myklebust }
16014fdc17b2STrond Myklebust 
16021da177e4SLinus Torvalds /*
16031da177e4SLinus Torvalds  * Decode LOOKUP reply
16041da177e4SLinus Torvalds  */
16051da177e4SLinus Torvalds static int
1606d61005a6SAl Viro nfs3_xdr_lookupres(struct rpc_rqst *req, __be32 *p, struct nfs3_diropres *res)
16071da177e4SLinus Torvalds {
16081da177e4SLinus Torvalds 	int	status;
16091da177e4SLinus Torvalds 
16101da177e4SLinus Torvalds 	if ((status = ntohl(*p++))) {
1611856dff3dSBenny Halevy 		status = nfs_stat_to_errno(status);
16121da177e4SLinus Torvalds 	} else {
16131da177e4SLinus Torvalds 		if (!(p = xdr_decode_fhandle(p, res->fh)))
16141da177e4SLinus Torvalds 			return -errno_NFSERR_IO;
16151da177e4SLinus Torvalds 		p = xdr_decode_post_op_attr(p, res->fattr);
16161da177e4SLinus Torvalds 	}
16171da177e4SLinus Torvalds 	xdr_decode_post_op_attr(p, res->dir_attr);
16181da177e4SLinus Torvalds 	return status;
16191da177e4SLinus Torvalds }
16201da177e4SLinus Torvalds 
16211da177e4SLinus Torvalds /*
16221da177e4SLinus Torvalds  * Decode ACCESS reply
16231da177e4SLinus Torvalds  */
16241da177e4SLinus Torvalds static int
1625d61005a6SAl Viro nfs3_xdr_accessres(struct rpc_rqst *req, __be32 *p, struct nfs3_accessres *res)
16261da177e4SLinus Torvalds {
16271da177e4SLinus Torvalds 	int	status = ntohl(*p++);
16281da177e4SLinus Torvalds 
16291da177e4SLinus Torvalds 	p = xdr_decode_post_op_attr(p, res->fattr);
16301da177e4SLinus Torvalds 	if (status)
1631856dff3dSBenny Halevy 		return nfs_stat_to_errno(status);
16321da177e4SLinus Torvalds 	res->access = ntohl(*p++);
16331da177e4SLinus Torvalds 	return 0;
16341da177e4SLinus Torvalds }
16351da177e4SLinus Torvalds 
16361da177e4SLinus Torvalds static int
1637d61005a6SAl Viro nfs3_xdr_readlinkargs(struct rpc_rqst *req, __be32 *p, struct nfs3_readlinkargs *args)
16381da177e4SLinus Torvalds {
1639a17c2153STrond Myklebust 	struct rpc_auth	*auth = req->rq_cred->cr_auth;
16401da177e4SLinus Torvalds 	unsigned int replen;
16411da177e4SLinus Torvalds 
16421da177e4SLinus Torvalds 	p = xdr_encode_fhandle(p, args->fh);
16431da177e4SLinus Torvalds 	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
16441da177e4SLinus Torvalds 
16451da177e4SLinus Torvalds 	/* Inline the page array */
16461da177e4SLinus Torvalds 	replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS3_readlinkres_sz) << 2;
16471da177e4SLinus Torvalds 	xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, args->pgbase, args->pglen);
16481da177e4SLinus Torvalds 	return 0;
16491da177e4SLinus Torvalds }
16501da177e4SLinus Torvalds 
16511da177e4SLinus Torvalds /*
16521da177e4SLinus Torvalds  * Decode READLINK reply
16531da177e4SLinus Torvalds  */
16541da177e4SLinus Torvalds static int
1655d61005a6SAl Viro nfs3_xdr_readlinkres(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
16561da177e4SLinus Torvalds {
16571da177e4SLinus Torvalds 	struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
16581da177e4SLinus Torvalds 	struct kvec *iov = rcvbuf->head;
1659c957c526SChuck Lever 	size_t hdrlen;
1660c957c526SChuck Lever 	u32 len, recvd;
16611da177e4SLinus Torvalds 	int	status;
16621da177e4SLinus Torvalds 
16631da177e4SLinus Torvalds 	status = ntohl(*p++);
16641da177e4SLinus Torvalds 	p = xdr_decode_post_op_attr(p, fattr);
16651da177e4SLinus Torvalds 
16661da177e4SLinus Torvalds 	if (status != 0)
1667856dff3dSBenny Halevy 		return nfs_stat_to_errno(status);
16681da177e4SLinus Torvalds 
16691da177e4SLinus Torvalds 	/* Convert length of symlink */
16701da177e4SLinus Torvalds 	len = ntohl(*p++);
1671c957c526SChuck Lever 	if (len >= rcvbuf->page_len) {
1672fe82a183SChuck Lever 		dprintk("nfs: server returned giant symlink!\n");
16731da177e4SLinus Torvalds 		return -ENAMETOOLONG;
16741da177e4SLinus Torvalds 	}
16751da177e4SLinus Torvalds 
16761da177e4SLinus Torvalds 	hdrlen = (u8 *) p - (u8 *) iov->iov_base;
16771da177e4SLinus Torvalds 	if (iov->iov_len < hdrlen) {
1678fe82a183SChuck Lever 		dprintk("NFS: READLINK reply header overflowed:"
1679c957c526SChuck Lever 				"length %Zu > %Zu\n", hdrlen, iov->iov_len);
16801da177e4SLinus Torvalds 		return -errno_NFSERR_IO;
16811da177e4SLinus Torvalds 	} else if (iov->iov_len != hdrlen) {
1682fe82a183SChuck Lever 		dprintk("NFS: READLINK header is short. "
1683fe82a183SChuck Lever 			"iovec will be shifted.\n");
16841da177e4SLinus Torvalds 		xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen);
16851da177e4SLinus Torvalds 	}
16861da177e4SLinus Torvalds 	recvd = req->rq_rcv_buf.len - hdrlen;
16871da177e4SLinus Torvalds 	if (recvd < len) {
1688fe82a183SChuck Lever 		dprintk("NFS: server cheating in readlink reply: "
16891da177e4SLinus Torvalds 				"count %u > recvd %u\n", len, recvd);
16901da177e4SLinus Torvalds 		return -EIO;
16911da177e4SLinus Torvalds 	}
16921da177e4SLinus Torvalds 
1693b4687da7SChuck Lever 	xdr_terminate_string(rcvbuf, len);
16941da177e4SLinus Torvalds 	return 0;
16951da177e4SLinus Torvalds }
16961da177e4SLinus Torvalds 
16971da177e4SLinus Torvalds /*
16981da177e4SLinus Torvalds  * Decode READ reply
16991da177e4SLinus Torvalds  */
17001da177e4SLinus Torvalds static int
1701d61005a6SAl Viro nfs3_xdr_readres(struct rpc_rqst *req, __be32 *p, struct nfs_readres *res)
17021da177e4SLinus Torvalds {
17031da177e4SLinus Torvalds 	struct kvec *iov = req->rq_rcv_buf.head;
1704c957c526SChuck Lever 	size_t hdrlen;
1705c957c526SChuck Lever 	u32 count, ocount, recvd;
1706c957c526SChuck Lever 	int status;
17071da177e4SLinus Torvalds 
17081da177e4SLinus Torvalds 	status = ntohl(*p++);
17091da177e4SLinus Torvalds 	p = xdr_decode_post_op_attr(p, res->fattr);
17101da177e4SLinus Torvalds 
17111da177e4SLinus Torvalds 	if (status != 0)
1712856dff3dSBenny Halevy 		return nfs_stat_to_errno(status);
17131da177e4SLinus Torvalds 
1714c957c526SChuck Lever 	/* Decode reply count and EOF flag. NFSv3 is somewhat redundant
17151da177e4SLinus Torvalds 	 * in that it puts the count both in the res struct and in the
17161da177e4SLinus Torvalds 	 * opaque data count. */
17171da177e4SLinus Torvalds 	count    = ntohl(*p++);
17181da177e4SLinus Torvalds 	res->eof = ntohl(*p++);
17191da177e4SLinus Torvalds 	ocount   = ntohl(*p++);
17201da177e4SLinus Torvalds 
17211da177e4SLinus Torvalds 	if (ocount != count) {
1722fe82a183SChuck Lever 		dprintk("NFS: READ count doesn't match RPC opaque count.\n");
17231da177e4SLinus Torvalds 		return -errno_NFSERR_IO;
17241da177e4SLinus Torvalds 	}
17251da177e4SLinus Torvalds 
17261da177e4SLinus Torvalds 	hdrlen = (u8 *) p - (u8 *) iov->iov_base;
17271da177e4SLinus Torvalds 	if (iov->iov_len < hdrlen) {
1728fe82a183SChuck Lever 		dprintk("NFS: READ reply header overflowed:"
1729c957c526SChuck Lever 				"length %Zu > %Zu\n", hdrlen, iov->iov_len);
17301da177e4SLinus Torvalds        		return -errno_NFSERR_IO;
17311da177e4SLinus Torvalds 	} else if (iov->iov_len != hdrlen) {
17321da177e4SLinus Torvalds 		dprintk("NFS: READ header is short. iovec will be shifted.\n");
17331da177e4SLinus Torvalds 		xdr_shift_buf(&req->rq_rcv_buf, iov->iov_len - hdrlen);
17341da177e4SLinus Torvalds 	}
17351da177e4SLinus Torvalds 
17361da177e4SLinus Torvalds 	recvd = req->rq_rcv_buf.len - hdrlen;
17371da177e4SLinus Torvalds 	if (count > recvd) {
1738fe82a183SChuck Lever 		dprintk("NFS: server cheating in read reply: "
1739c957c526SChuck Lever 			"count %u > recvd %u\n", count, recvd);
17401da177e4SLinus Torvalds 		count = recvd;
17411da177e4SLinus Torvalds 		res->eof = 0;
17421da177e4SLinus Torvalds 	}
17431da177e4SLinus Torvalds 
17441da177e4SLinus Torvalds 	if (count < res->count)
17451da177e4SLinus Torvalds 		res->count = count;
17461da177e4SLinus Torvalds 
17471da177e4SLinus Torvalds 	return count;
17481da177e4SLinus Torvalds }
17491da177e4SLinus Torvalds 
17501da177e4SLinus Torvalds /*
17511da177e4SLinus Torvalds  * Decode WRITE response
17521da177e4SLinus Torvalds  */
17531da177e4SLinus Torvalds static int
1754d61005a6SAl Viro nfs3_xdr_writeres(struct rpc_rqst *req, __be32 *p, struct nfs_writeres *res)
17551da177e4SLinus Torvalds {
17561da177e4SLinus Torvalds 	int	status;
17571da177e4SLinus Torvalds 
17581da177e4SLinus Torvalds 	status = ntohl(*p++);
17591da177e4SLinus Torvalds 	p = xdr_decode_wcc_data(p, res->fattr);
17601da177e4SLinus Torvalds 
17611da177e4SLinus Torvalds 	if (status != 0)
1762856dff3dSBenny Halevy 		return nfs_stat_to_errno(status);
17631da177e4SLinus Torvalds 
17641da177e4SLinus Torvalds 	res->count = ntohl(*p++);
17651da177e4SLinus Torvalds 	res->verf->committed = (enum nfs3_stable_how)ntohl(*p++);
17661da177e4SLinus Torvalds 	res->verf->verifier[0] = *p++;
17671da177e4SLinus Torvalds 	res->verf->verifier[1] = *p++;
17681da177e4SLinus Torvalds 
17691da177e4SLinus Torvalds 	return res->count;
17701da177e4SLinus Torvalds }
17711da177e4SLinus Torvalds 
17721da177e4SLinus Torvalds /*
17731da177e4SLinus Torvalds  * Decode a CREATE response
17741da177e4SLinus Torvalds  */
17751da177e4SLinus Torvalds static int
1776d61005a6SAl Viro nfs3_xdr_createres(struct rpc_rqst *req, __be32 *p, struct nfs3_diropres *res)
17771da177e4SLinus Torvalds {
17781da177e4SLinus Torvalds 	int	status;
17791da177e4SLinus Torvalds 
17801da177e4SLinus Torvalds 	status = ntohl(*p++);
17811da177e4SLinus Torvalds 	if (status == 0) {
17821da177e4SLinus Torvalds 		if (*p++) {
17831da177e4SLinus Torvalds 			if (!(p = xdr_decode_fhandle(p, res->fh)))
17841da177e4SLinus Torvalds 				return -errno_NFSERR_IO;
17851da177e4SLinus Torvalds 			p = xdr_decode_post_op_attr(p, res->fattr);
17861da177e4SLinus Torvalds 		} else {
17871da177e4SLinus Torvalds 			memset(res->fh, 0, sizeof(*res->fh));
17881da177e4SLinus Torvalds 			/* Do decode post_op_attr but set it to NULL */
17891da177e4SLinus Torvalds 			p = xdr_decode_post_op_attr(p, res->fattr);
17901da177e4SLinus Torvalds 			res->fattr->valid = 0;
17911da177e4SLinus Torvalds 		}
17921da177e4SLinus Torvalds 	} else {
1793856dff3dSBenny Halevy 		status = nfs_stat_to_errno(status);
17941da177e4SLinus Torvalds 	}
17951da177e4SLinus Torvalds 	p = xdr_decode_wcc_data(p, res->dir_attr);
17961da177e4SLinus Torvalds 	return status;
17971da177e4SLinus Torvalds }
17981da177e4SLinus Torvalds 
17991da177e4SLinus Torvalds /*
18001da177e4SLinus Torvalds  * Decode RENAME reply
18011da177e4SLinus Torvalds  */
18021da177e4SLinus Torvalds static int
1803e8582a8bSJeff Layton nfs3_xdr_renameres(struct rpc_rqst *req, __be32 *p, struct nfs_renameres *res)
18041da177e4SLinus Torvalds {
18051da177e4SLinus Torvalds 	int	status;
18061da177e4SLinus Torvalds 
18071da177e4SLinus Torvalds 	if ((status = ntohl(*p++)) != 0)
1808856dff3dSBenny Halevy 		status = nfs_stat_to_errno(status);
1809e8582a8bSJeff Layton 	p = xdr_decode_wcc_data(p, res->old_fattr);
1810e8582a8bSJeff Layton 	p = xdr_decode_wcc_data(p, res->new_fattr);
18111da177e4SLinus Torvalds 	return status;
18121da177e4SLinus Torvalds }
18131da177e4SLinus Torvalds 
18141da177e4SLinus Torvalds /*
18151da177e4SLinus Torvalds  * Decode LINK reply
18161da177e4SLinus Torvalds  */
18171da177e4SLinus Torvalds static int
1818d61005a6SAl Viro nfs3_xdr_linkres(struct rpc_rqst *req, __be32 *p, struct nfs3_linkres *res)
18191da177e4SLinus Torvalds {
18201da177e4SLinus Torvalds 	int	status;
18211da177e4SLinus Torvalds 
18221da177e4SLinus Torvalds 	if ((status = ntohl(*p++)) != 0)
1823856dff3dSBenny Halevy 		status = nfs_stat_to_errno(status);
18241da177e4SLinus Torvalds 	p = xdr_decode_post_op_attr(p, res->fattr);
18251da177e4SLinus Torvalds 	p = xdr_decode_wcc_data(p, res->dir_attr);
18261da177e4SLinus Torvalds 	return status;
18271da177e4SLinus Torvalds }
18281da177e4SLinus Torvalds 
18291da177e4SLinus Torvalds /*
18301da177e4SLinus Torvalds  * Decode FSSTAT reply
18311da177e4SLinus Torvalds  */
18321da177e4SLinus Torvalds static int
1833d61005a6SAl Viro nfs3_xdr_fsstatres(struct rpc_rqst *req, __be32 *p, struct nfs_fsstat *res)
18341da177e4SLinus Torvalds {
18351da177e4SLinus Torvalds 	int		status;
18361da177e4SLinus Torvalds 
18371da177e4SLinus Torvalds 	status = ntohl(*p++);
18381da177e4SLinus Torvalds 
18391da177e4SLinus Torvalds 	p = xdr_decode_post_op_attr(p, res->fattr);
18401da177e4SLinus Torvalds 	if (status != 0)
1841856dff3dSBenny Halevy 		return nfs_stat_to_errno(status);
18421da177e4SLinus Torvalds 
18431da177e4SLinus Torvalds 	p = xdr_decode_hyper(p, &res->tbytes);
18441da177e4SLinus Torvalds 	p = xdr_decode_hyper(p, &res->fbytes);
18451da177e4SLinus Torvalds 	p = xdr_decode_hyper(p, &res->abytes);
18461da177e4SLinus Torvalds 	p = xdr_decode_hyper(p, &res->tfiles);
18471da177e4SLinus Torvalds 	p = xdr_decode_hyper(p, &res->ffiles);
18481da177e4SLinus Torvalds 	p = xdr_decode_hyper(p, &res->afiles);
18491da177e4SLinus Torvalds 
18501da177e4SLinus Torvalds 	/* ignore invarsec */
18511da177e4SLinus Torvalds 	return 0;
18521da177e4SLinus Torvalds }
18531da177e4SLinus Torvalds 
18541da177e4SLinus Torvalds /*
18551da177e4SLinus Torvalds  * Decode FSINFO reply
18561da177e4SLinus Torvalds  */
18571da177e4SLinus Torvalds static int
1858d61005a6SAl Viro nfs3_xdr_fsinfores(struct rpc_rqst *req, __be32 *p, struct nfs_fsinfo *res)
18591da177e4SLinus Torvalds {
18601da177e4SLinus Torvalds 	int		status;
18611da177e4SLinus Torvalds 
18621da177e4SLinus Torvalds 	status = ntohl(*p++);
18631da177e4SLinus Torvalds 
18641da177e4SLinus Torvalds 	p = xdr_decode_post_op_attr(p, res->fattr);
18651da177e4SLinus Torvalds 	if (status != 0)
1866856dff3dSBenny Halevy 		return nfs_stat_to_errno(status);
18671da177e4SLinus Torvalds 
18681da177e4SLinus Torvalds 	res->rtmax  = ntohl(*p++);
18691da177e4SLinus Torvalds 	res->rtpref = ntohl(*p++);
18701da177e4SLinus Torvalds 	res->rtmult = ntohl(*p++);
18711da177e4SLinus Torvalds 	res->wtmax  = ntohl(*p++);
18721da177e4SLinus Torvalds 	res->wtpref = ntohl(*p++);
18731da177e4SLinus Torvalds 	res->wtmult = ntohl(*p++);
18741da177e4SLinus Torvalds 	res->dtpref = ntohl(*p++);
18751da177e4SLinus Torvalds 	p = xdr_decode_hyper(p, &res->maxfilesize);
18766b96724eSRicardo Labiaga 	p = xdr_decode_time3(p, &res->time_delta);
18771da177e4SLinus Torvalds 
18786b96724eSRicardo Labiaga 	/* ignore properties */
18791da177e4SLinus Torvalds 	res->lease_time = 0;
18801da177e4SLinus Torvalds 	return 0;
18811da177e4SLinus Torvalds }
18821da177e4SLinus Torvalds 
18831da177e4SLinus Torvalds /*
18841da177e4SLinus Torvalds  * Decode PATHCONF reply
18851da177e4SLinus Torvalds  */
18861da177e4SLinus Torvalds static int
1887d61005a6SAl Viro nfs3_xdr_pathconfres(struct rpc_rqst *req, __be32 *p, struct nfs_pathconf *res)
18881da177e4SLinus Torvalds {
18891da177e4SLinus Torvalds 	int		status;
18901da177e4SLinus Torvalds 
18911da177e4SLinus Torvalds 	status = ntohl(*p++);
18921da177e4SLinus Torvalds 
18931da177e4SLinus Torvalds 	p = xdr_decode_post_op_attr(p, res->fattr);
18941da177e4SLinus Torvalds 	if (status != 0)
1895856dff3dSBenny Halevy 		return nfs_stat_to_errno(status);
18961da177e4SLinus Torvalds 	res->max_link = ntohl(*p++);
18971da177e4SLinus Torvalds 	res->max_namelen = ntohl(*p++);
18981da177e4SLinus Torvalds 
18991da177e4SLinus Torvalds 	/* ignore remaining fields */
19001da177e4SLinus Torvalds 	return 0;
19011da177e4SLinus Torvalds }
19021da177e4SLinus Torvalds 
19031da177e4SLinus Torvalds /*
19041da177e4SLinus Torvalds  * Decode COMMIT reply
19051da177e4SLinus Torvalds  */
19061da177e4SLinus Torvalds static int
1907d61005a6SAl Viro nfs3_xdr_commitres(struct rpc_rqst *req, __be32 *p, struct nfs_writeres *res)
19081da177e4SLinus Torvalds {
19091da177e4SLinus Torvalds 	int		status;
19101da177e4SLinus Torvalds 
19111da177e4SLinus Torvalds 	status = ntohl(*p++);
19121da177e4SLinus Torvalds 	p = xdr_decode_wcc_data(p, res->fattr);
19131da177e4SLinus Torvalds 	if (status != 0)
1914856dff3dSBenny Halevy 		return nfs_stat_to_errno(status);
19151da177e4SLinus Torvalds 
19161da177e4SLinus Torvalds 	res->verf->verifier[0] = *p++;
19171da177e4SLinus Torvalds 	res->verf->verifier[1] = *p++;
19181da177e4SLinus Torvalds 	return 0;
19191da177e4SLinus Torvalds }
19201da177e4SLinus Torvalds 
1921b7fa0554SAndreas Gruenbacher #ifdef CONFIG_NFS_V3_ACL
1922b7fa0554SAndreas Gruenbacher /*
1923b7fa0554SAndreas Gruenbacher  * Decode GETACL reply
1924b7fa0554SAndreas Gruenbacher  */
1925b7fa0554SAndreas Gruenbacher static int
1926d61005a6SAl Viro nfs3_xdr_getaclres(struct rpc_rqst *req, __be32 *p,
1927b7fa0554SAndreas Gruenbacher 		   struct nfs3_getaclres *res)
1928b7fa0554SAndreas Gruenbacher {
1929b7fa0554SAndreas Gruenbacher 	struct xdr_buf *buf = &req->rq_rcv_buf;
1930b7fa0554SAndreas Gruenbacher 	int status = ntohl(*p++);
1931b7fa0554SAndreas Gruenbacher 	struct posix_acl **acl;
1932b7fa0554SAndreas Gruenbacher 	unsigned int *aclcnt;
1933b7fa0554SAndreas Gruenbacher 	int err, base;
1934b7fa0554SAndreas Gruenbacher 
1935b7fa0554SAndreas Gruenbacher 	if (status != 0)
1936856dff3dSBenny Halevy 		return nfs_stat_to_errno(status);
1937b7fa0554SAndreas Gruenbacher 	p = xdr_decode_post_op_attr(p, res->fattr);
1938b7fa0554SAndreas Gruenbacher 	res->mask = ntohl(*p++);
1939b7fa0554SAndreas Gruenbacher 	if (res->mask & ~(NFS_ACL|NFS_ACLCNT|NFS_DFACL|NFS_DFACLCNT))
1940b7fa0554SAndreas Gruenbacher 		return -EINVAL;
1941b7fa0554SAndreas Gruenbacher 	base = (char *)p - (char *)req->rq_rcv_buf.head->iov_base;
1942b7fa0554SAndreas Gruenbacher 
1943b7fa0554SAndreas Gruenbacher 	acl = (res->mask & NFS_ACL) ? &res->acl_access : NULL;
1944b7fa0554SAndreas Gruenbacher 	aclcnt = (res->mask & NFS_ACLCNT) ? &res->acl_access_count : NULL;
1945b7fa0554SAndreas Gruenbacher 	err = nfsacl_decode(buf, base, aclcnt, acl);
1946b7fa0554SAndreas Gruenbacher 
1947b7fa0554SAndreas Gruenbacher 	acl = (res->mask & NFS_DFACL) ? &res->acl_default : NULL;
1948b7fa0554SAndreas Gruenbacher 	aclcnt = (res->mask & NFS_DFACLCNT) ? &res->acl_default_count : NULL;
1949b7fa0554SAndreas Gruenbacher 	if (err > 0)
1950b7fa0554SAndreas Gruenbacher 		err = nfsacl_decode(buf, base + err, aclcnt, acl);
1951b7fa0554SAndreas Gruenbacher 	return (err > 0) ? 0 : err;
1952b7fa0554SAndreas Gruenbacher }
1953b7fa0554SAndreas Gruenbacher 
1954b7fa0554SAndreas Gruenbacher /*
1955b7fa0554SAndreas Gruenbacher  * Decode setacl reply.
1956b7fa0554SAndreas Gruenbacher  */
1957b7fa0554SAndreas Gruenbacher static int
1958d61005a6SAl Viro nfs3_xdr_setaclres(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
1959b7fa0554SAndreas Gruenbacher {
1960b7fa0554SAndreas Gruenbacher 	int status = ntohl(*p++);
1961b7fa0554SAndreas Gruenbacher 
1962b7fa0554SAndreas Gruenbacher 	if (status)
1963856dff3dSBenny Halevy 		return nfs_stat_to_errno(status);
1964b7fa0554SAndreas Gruenbacher 	xdr_decode_post_op_attr(p, fattr);
1965b7fa0554SAndreas Gruenbacher 	return 0;
1966b7fa0554SAndreas Gruenbacher }
1967b7fa0554SAndreas Gruenbacher #endif  /* CONFIG_NFS_V3_ACL */
1968b7fa0554SAndreas Gruenbacher 
19691da177e4SLinus Torvalds #define PROC(proc, argtype, restype, timer)				\
19701da177e4SLinus Torvalds [NFS3PROC_##proc] = {							\
19711da177e4SLinus Torvalds 	.p_proc      = NFS3PROC_##proc,					\
19721da177e4SLinus Torvalds 	.p_encode    = (kxdrproc_t) nfs3_xdr_##argtype,			\
19731da177e4SLinus Torvalds 	.p_decode    = (kxdrproc_t) nfs3_xdr_##restype,			\
19742bea90d4SChuck Lever 	.p_arglen    = NFS3_##argtype##_sz,				\
19752bea90d4SChuck Lever 	.p_replen    = NFS3_##restype##_sz,				\
1976cc0175c1SChuck Lever 	.p_timer     = timer,						\
1977cc0175c1SChuck Lever 	.p_statidx   = NFS3PROC_##proc,					\
1978cc0175c1SChuck Lever 	.p_name      = #proc,						\
19791da177e4SLinus Torvalds 	}
19801da177e4SLinus Torvalds 
19811da177e4SLinus Torvalds struct rpc_procinfo	nfs3_procedures[] = {
19821da177e4SLinus Torvalds   PROC(GETATTR,		fhandle,	attrstat, 1),
19831da177e4SLinus Torvalds   PROC(SETATTR, 	sattrargs,	wccstat, 0),
19841da177e4SLinus Torvalds   PROC(LOOKUP,		diropargs,	lookupres, 2),
19851da177e4SLinus Torvalds   PROC(ACCESS,		accessargs,	accessres, 1),
19861da177e4SLinus Torvalds   PROC(READLINK,	readlinkargs,	readlinkres, 3),
19871da177e4SLinus Torvalds   PROC(READ,		readargs,	readres, 3),
19881da177e4SLinus Torvalds   PROC(WRITE,		writeargs,	writeres, 4),
19891da177e4SLinus Torvalds   PROC(CREATE,		createargs,	createres, 0),
19901da177e4SLinus Torvalds   PROC(MKDIR,		mkdirargs,	createres, 0),
19911da177e4SLinus Torvalds   PROC(SYMLINK,		symlinkargs,	createres, 0),
19921da177e4SLinus Torvalds   PROC(MKNOD,		mknodargs,	createres, 0),
19934fdc17b2STrond Myklebust   PROC(REMOVE,		removeargs,	removeres, 0),
19941da177e4SLinus Torvalds   PROC(RMDIR,		diropargs,	wccstat, 0),
19951da177e4SLinus Torvalds   PROC(RENAME,		renameargs,	renameres, 0),
19961da177e4SLinus Torvalds   PROC(LINK,		linkargs,	linkres, 0),
19971da177e4SLinus Torvalds   PROC(READDIR,		readdirargs,	readdirres, 3),
19981da177e4SLinus Torvalds   PROC(READDIRPLUS,	readdirargs,	readdirres, 3),
19991da177e4SLinus Torvalds   PROC(FSSTAT,		fhandle,	fsstatres, 0),
20001da177e4SLinus Torvalds   PROC(FSINFO,  	fhandle,	fsinfores, 0),
20011da177e4SLinus Torvalds   PROC(PATHCONF,	fhandle,	pathconfres, 0),
20021da177e4SLinus Torvalds   PROC(COMMIT,		commitargs,	commitres, 5),
20031da177e4SLinus Torvalds };
20041da177e4SLinus Torvalds 
20051da177e4SLinus Torvalds struct rpc_version		nfs_version3 = {
20061da177e4SLinus Torvalds 	.number			= 3,
2007e8c96f8cSTobias Klauser 	.nrprocs		= ARRAY_SIZE(nfs3_procedures),
20081da177e4SLinus Torvalds 	.procs			= nfs3_procedures
20091da177e4SLinus Torvalds };
20101da177e4SLinus Torvalds 
2011b7fa0554SAndreas Gruenbacher #ifdef CONFIG_NFS_V3_ACL
2012b7fa0554SAndreas Gruenbacher static struct rpc_procinfo	nfs3_acl_procedures[] = {
2013b7fa0554SAndreas Gruenbacher 	[ACLPROC3_GETACL] = {
2014b7fa0554SAndreas Gruenbacher 		.p_proc = ACLPROC3_GETACL,
2015b7fa0554SAndreas Gruenbacher 		.p_encode = (kxdrproc_t) nfs3_xdr_getaclargs,
2016b7fa0554SAndreas Gruenbacher 		.p_decode = (kxdrproc_t) nfs3_xdr_getaclres,
20172bea90d4SChuck Lever 		.p_arglen = ACL3_getaclargs_sz,
20182bea90d4SChuck Lever 		.p_replen = ACL3_getaclres_sz,
2019b7fa0554SAndreas Gruenbacher 		.p_timer = 1,
2020cc0175c1SChuck Lever 		.p_name = "GETACL",
2021b7fa0554SAndreas Gruenbacher 	},
2022b7fa0554SAndreas Gruenbacher 	[ACLPROC3_SETACL] = {
2023b7fa0554SAndreas Gruenbacher 		.p_proc = ACLPROC3_SETACL,
2024b7fa0554SAndreas Gruenbacher 		.p_encode = (kxdrproc_t) nfs3_xdr_setaclargs,
2025b7fa0554SAndreas Gruenbacher 		.p_decode = (kxdrproc_t) nfs3_xdr_setaclres,
20262bea90d4SChuck Lever 		.p_arglen = ACL3_setaclargs_sz,
20272bea90d4SChuck Lever 		.p_replen = ACL3_setaclres_sz,
2028b7fa0554SAndreas Gruenbacher 		.p_timer = 0,
2029cc0175c1SChuck Lever 		.p_name = "SETACL",
2030b7fa0554SAndreas Gruenbacher 	},
2031b7fa0554SAndreas Gruenbacher };
2032b7fa0554SAndreas Gruenbacher 
2033b7fa0554SAndreas Gruenbacher struct rpc_version		nfsacl_version3 = {
2034b7fa0554SAndreas Gruenbacher 	.number			= 3,
2035b7fa0554SAndreas Gruenbacher 	.nrprocs		= sizeof(nfs3_acl_procedures)/
2036b7fa0554SAndreas Gruenbacher 				  sizeof(nfs3_acl_procedures[0]),
2037b7fa0554SAndreas Gruenbacher 	.procs			= nfs3_acl_procedures,
2038b7fa0554SAndreas Gruenbacher };
2039b7fa0554SAndreas Gruenbacher #endif  /* CONFIG_NFS_V3_ACL */
2040