xref: /openbmc/linux/fs/nfs/nfs3xdr.c (revision ad96b5b5)
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 #define NFS3_diropargs_sz	(NFS3_fh_sz+NFS3_filename_sz)
50ad96b5b5SChuck Lever 
51ad96b5b5SChuck Lever #define NFS3_getattrargs_sz	(NFS3_fh_sz)
52ad96b5b5SChuck Lever #define NFS3_setattrargs_sz	(NFS3_fh_sz+NFS3_sattr_sz+3)
53ad96b5b5SChuck Lever #define NFS3_lookupargs_sz	(NFS3_fh_sz+NFS3_filename_sz)
541da177e4SLinus Torvalds #define NFS3_accessargs_sz	(NFS3_fh_sz+1)
551da177e4SLinus Torvalds #define NFS3_readlinkargs_sz	(NFS3_fh_sz)
561da177e4SLinus Torvalds #define NFS3_readargs_sz	(NFS3_fh_sz+3)
571da177e4SLinus Torvalds #define NFS3_writeargs_sz	(NFS3_fh_sz+5)
581da177e4SLinus Torvalds #define NFS3_createargs_sz	(NFS3_diropargs_sz+NFS3_sattr_sz)
591da177e4SLinus Torvalds #define NFS3_mkdirargs_sz	(NFS3_diropargs_sz+NFS3_sattr_sz)
6094a6d753SChuck Lever #define NFS3_symlinkargs_sz	(NFS3_diropargs_sz+1+NFS3_sattr_sz)
611da177e4SLinus Torvalds #define NFS3_mknodargs_sz	(NFS3_diropargs_sz+2+NFS3_sattr_sz)
62ad96b5b5SChuck Lever #define NFS3_removeargs_sz	(NFS3_fh_sz+NFS3_filename_sz)
631da177e4SLinus Torvalds #define NFS3_renameargs_sz	(NFS3_diropargs_sz+NFS3_diropargs_sz)
641da177e4SLinus Torvalds #define NFS3_linkargs_sz		(NFS3_fh_sz+NFS3_diropargs_sz)
65d9c407b1SChuck Lever #define NFS3_readdirargs_sz	(NFS3_fh_sz+NFS3_cookieverf_sz+3)
66d9c407b1SChuck Lever #define NFS3_readdirplusargs_sz	(NFS3_fh_sz+NFS3_cookieverf_sz+4)
671da177e4SLinus Torvalds #define NFS3_commitargs_sz	(NFS3_fh_sz+3)
681da177e4SLinus Torvalds 
691da177e4SLinus Torvalds #define NFS3_attrstat_sz	(1+NFS3_fattr_sz)
701da177e4SLinus Torvalds #define NFS3_wccstat_sz		(1+NFS3_wcc_data_sz)
714fdc17b2STrond Myklebust #define NFS3_removeres_sz	(NFS3_wccstat_sz)
721da177e4SLinus Torvalds #define NFS3_lookupres_sz	(1+NFS3_fh_sz+(2 * NFS3_post_op_attr_sz))
731da177e4SLinus Torvalds #define NFS3_accessres_sz	(1+NFS3_post_op_attr_sz+1)
741da177e4SLinus Torvalds #define NFS3_readlinkres_sz	(1+NFS3_post_op_attr_sz+1)
751da177e4SLinus Torvalds #define NFS3_readres_sz		(1+NFS3_post_op_attr_sz+3)
761da177e4SLinus Torvalds #define NFS3_writeres_sz	(1+NFS3_wcc_data_sz+4)
771da177e4SLinus Torvalds #define NFS3_createres_sz	(1+NFS3_fh_sz+NFS3_post_op_attr_sz+NFS3_wcc_data_sz)
781da177e4SLinus Torvalds #define NFS3_renameres_sz	(1+(2 * NFS3_wcc_data_sz))
791da177e4SLinus Torvalds #define NFS3_linkres_sz		(1+NFS3_post_op_attr_sz+NFS3_wcc_data_sz)
801da177e4SLinus Torvalds #define NFS3_readdirres_sz	(1+NFS3_post_op_attr_sz+2)
811da177e4SLinus Torvalds #define NFS3_fsstatres_sz	(1+NFS3_post_op_attr_sz+13)
821da177e4SLinus Torvalds #define NFS3_fsinfores_sz	(1+NFS3_post_op_attr_sz+12)
831da177e4SLinus Torvalds #define NFS3_pathconfres_sz	(1+NFS3_post_op_attr_sz+6)
841da177e4SLinus Torvalds #define NFS3_commitres_sz	(1+NFS3_wcc_data_sz+2)
851da177e4SLinus Torvalds 
86b7fa0554SAndreas Gruenbacher #define ACL3_getaclargs_sz	(NFS3_fh_sz+1)
87ae46141fSTrond Myklebust #define ACL3_setaclargs_sz	(NFS3_fh_sz+1+ \
88ae46141fSTrond Myklebust 				XDR_QUADLEN(NFS_ACL_INLINE_BUFSIZE))
89ae46141fSTrond Myklebust #define ACL3_getaclres_sz	(1+NFS3_post_op_attr_sz+1+ \
90ae46141fSTrond Myklebust 				XDR_QUADLEN(NFS_ACL_INLINE_BUFSIZE))
91b7fa0554SAndreas Gruenbacher #define ACL3_setaclres_sz	(1+NFS3_post_op_attr_sz)
92b7fa0554SAndreas Gruenbacher 
931da177e4SLinus Torvalds /*
941da177e4SLinus Torvalds  * Map file type to S_IFMT bits
951da177e4SLinus Torvalds  */
96bca79478STrond Myklebust static const umode_t nfs_type2fmt[] = {
97bca79478STrond Myklebust 	[NF3BAD] = 0,
98bca79478STrond Myklebust 	[NF3REG] = S_IFREG,
99bca79478STrond Myklebust 	[NF3DIR] = S_IFDIR,
100bca79478STrond Myklebust 	[NF3BLK] = S_IFBLK,
101bca79478STrond Myklebust 	[NF3CHR] = S_IFCHR,
102bca79478STrond Myklebust 	[NF3LNK] = S_IFLNK,
103bca79478STrond Myklebust 	[NF3SOCK] = S_IFSOCK,
104bca79478STrond Myklebust 	[NF3FIFO] = S_IFIFO,
1051da177e4SLinus Torvalds };
1061da177e4SLinus Torvalds 
107babddc72SBryan Schumaker static void print_overflow_msg(const char *func, const struct xdr_stream *xdr)
108babddc72SBryan Schumaker {
109babddc72SBryan Schumaker 	dprintk("nfs: %s: prematurely hit end of receive buffer. "
110babddc72SBryan Schumaker 		"Remaining buffer length is %tu words.\n",
111babddc72SBryan Schumaker 		func, xdr->end - xdr->p);
112babddc72SBryan Schumaker }
113babddc72SBryan Schumaker 
1141da177e4SLinus Torvalds /*
115d9c407b1SChuck Lever  * While encoding arguments, set up the reply buffer in advance to
116d9c407b1SChuck Lever  * receive reply data directly into the page cache.
117d9c407b1SChuck Lever  */
118d9c407b1SChuck Lever static void prepare_reply_buffer(struct rpc_rqst *req, struct page **pages,
119d9c407b1SChuck Lever 				 unsigned int base, unsigned int len,
120d9c407b1SChuck Lever 				 unsigned int bufsize)
121d9c407b1SChuck Lever {
122d9c407b1SChuck Lever 	struct rpc_auth	*auth = req->rq_cred->cr_auth;
123d9c407b1SChuck Lever 	unsigned int replen;
124d9c407b1SChuck Lever 
125d9c407b1SChuck Lever 	replen = RPC_REPHDRSIZE + auth->au_rslack + bufsize;
126d9c407b1SChuck Lever 	xdr_inline_pages(&req->rq_rcv_buf, replen << 2, pages, base, len);
127d9c407b1SChuck Lever }
128d9c407b1SChuck Lever 
129d9c407b1SChuck Lever 
130d9c407b1SChuck Lever /*
1311da177e4SLinus Torvalds  * Common NFS XDR functions as inlines
1321da177e4SLinus Torvalds  */
133d61005a6SAl Viro static inline __be32 *
1344fdc17b2STrond Myklebust xdr_encode_fhandle(__be32 *p, const struct nfs_fh *fh)
1351da177e4SLinus Torvalds {
1361da177e4SLinus Torvalds 	return xdr_encode_array(p, fh->data, fh->size);
1371da177e4SLinus Torvalds }
1381da177e4SLinus Torvalds 
139d61005a6SAl Viro static inline __be32 *
140d61005a6SAl Viro xdr_decode_fhandle(__be32 *p, struct nfs_fh *fh)
1411da177e4SLinus Torvalds {
1421da177e4SLinus Torvalds 	if ((fh->size = ntohl(*p++)) <= NFS3_FHSIZE) {
1431da177e4SLinus Torvalds 		memcpy(fh->data, p, fh->size);
1441da177e4SLinus Torvalds 		return p + XDR_QUADLEN(fh->size);
1451da177e4SLinus Torvalds 	}
1461da177e4SLinus Torvalds 	return NULL;
1471da177e4SLinus Torvalds }
1481da177e4SLinus Torvalds 
149babddc72SBryan Schumaker static inline __be32 *
150babddc72SBryan Schumaker xdr_decode_fhandle_stream(struct xdr_stream *xdr, struct nfs_fh *fh)
151babddc72SBryan Schumaker {
152babddc72SBryan Schumaker 	__be32 *p;
153babddc72SBryan Schumaker 	p = xdr_inline_decode(xdr, 4);
154babddc72SBryan Schumaker 	if (unlikely(!p))
155babddc72SBryan Schumaker 		goto out_overflow;
156babddc72SBryan Schumaker 	fh->size = ntohl(*p++);
157babddc72SBryan Schumaker 
158babddc72SBryan Schumaker 	if (fh->size <= NFS3_FHSIZE) {
159babddc72SBryan Schumaker 		p = xdr_inline_decode(xdr, fh->size);
160babddc72SBryan Schumaker 		if (unlikely(!p))
161babddc72SBryan Schumaker 			goto out_overflow;
162babddc72SBryan Schumaker 		memcpy(fh->data, p, fh->size);
163babddc72SBryan Schumaker 		return p + XDR_QUADLEN(fh->size);
164babddc72SBryan Schumaker 	}
165babddc72SBryan Schumaker 	return NULL;
166babddc72SBryan Schumaker 
167babddc72SBryan Schumaker out_overflow:
168babddc72SBryan Schumaker 	print_overflow_msg(__func__, xdr);
169babddc72SBryan Schumaker 	return ERR_PTR(-EIO);
170babddc72SBryan Schumaker }
171babddc72SBryan Schumaker 
1721da177e4SLinus Torvalds /*
1731da177e4SLinus Torvalds  * Encode/decode time.
1741da177e4SLinus Torvalds  */
175d61005a6SAl Viro static inline __be32 *
176d9c407b1SChuck Lever xdr_encode_time3(__be32 *p, const struct timespec *timep)
1771da177e4SLinus Torvalds {
1781da177e4SLinus Torvalds 	*p++ = htonl(timep->tv_sec);
1791da177e4SLinus Torvalds 	*p++ = htonl(timep->tv_nsec);
1801da177e4SLinus Torvalds 	return p;
1811da177e4SLinus Torvalds }
1821da177e4SLinus Torvalds 
183d61005a6SAl Viro static inline __be32 *
184d61005a6SAl Viro xdr_decode_time3(__be32 *p, struct timespec *timep)
1851da177e4SLinus Torvalds {
1861da177e4SLinus Torvalds 	timep->tv_sec = ntohl(*p++);
1871da177e4SLinus Torvalds 	timep->tv_nsec = ntohl(*p++);
1881da177e4SLinus Torvalds 	return p;
1891da177e4SLinus Torvalds }
1901da177e4SLinus Torvalds 
191d61005a6SAl Viro static __be32 *
192d61005a6SAl Viro xdr_decode_fattr(__be32 *p, struct nfs_fattr *fattr)
1931da177e4SLinus Torvalds {
1941da177e4SLinus Torvalds 	unsigned int	type, major, minor;
195bca79478STrond Myklebust 	umode_t		fmode;
1961da177e4SLinus Torvalds 
1971da177e4SLinus Torvalds 	type = ntohl(*p++);
198bca79478STrond Myklebust 	if (type > NF3FIFO)
199bca79478STrond Myklebust 		type = NF3NON;
200bca79478STrond Myklebust 	fmode = nfs_type2fmt[type];
2011da177e4SLinus Torvalds 	fattr->mode = (ntohl(*p++) & ~S_IFMT) | fmode;
2021da177e4SLinus Torvalds 	fattr->nlink = ntohl(*p++);
2031da177e4SLinus Torvalds 	fattr->uid = ntohl(*p++);
2041da177e4SLinus Torvalds 	fattr->gid = ntohl(*p++);
2051da177e4SLinus Torvalds 	p = xdr_decode_hyper(p, &fattr->size);
2061da177e4SLinus Torvalds 	p = xdr_decode_hyper(p, &fattr->du.nfs3.used);
2071da177e4SLinus Torvalds 
2081da177e4SLinus Torvalds 	/* Turn remote device info into Linux-specific dev_t */
2091da177e4SLinus Torvalds 	major = ntohl(*p++);
2101da177e4SLinus Torvalds 	minor = ntohl(*p++);
2111da177e4SLinus Torvalds 	fattr->rdev = MKDEV(major, minor);
2121da177e4SLinus Torvalds 	if (MAJOR(fattr->rdev) != major || MINOR(fattr->rdev) != minor)
2131da177e4SLinus Torvalds 		fattr->rdev = 0;
2141da177e4SLinus Torvalds 
2158b4bdcf8STrond Myklebust 	p = xdr_decode_hyper(p, &fattr->fsid.major);
2168b4bdcf8STrond Myklebust 	fattr->fsid.minor = 0;
2171da177e4SLinus Torvalds 	p = xdr_decode_hyper(p, &fattr->fileid);
2181da177e4SLinus Torvalds 	p = xdr_decode_time3(p, &fattr->atime);
2191da177e4SLinus Torvalds 	p = xdr_decode_time3(p, &fattr->mtime);
2201da177e4SLinus Torvalds 	p = xdr_decode_time3(p, &fattr->ctime);
2211da177e4SLinus Torvalds 
2221da177e4SLinus Torvalds 	/* Update the mode bits */
2239e6e70f8STrond Myklebust 	fattr->valid |= NFS_ATTR_FATTR_V3;
2241da177e4SLinus Torvalds 	return p;
2251da177e4SLinus Torvalds }
2261da177e4SLinus Torvalds 
227d61005a6SAl Viro static inline __be32 *
228d9c407b1SChuck Lever xdr_encode_sattr(__be32 *p, const struct iattr *attr)
2291da177e4SLinus Torvalds {
2301da177e4SLinus Torvalds 	if (attr->ia_valid & ATTR_MODE) {
2311da177e4SLinus Torvalds 		*p++ = xdr_one;
232cf3fff54STrond Myklebust 		*p++ = htonl(attr->ia_mode & S_IALLUGO);
2331da177e4SLinus Torvalds 	} else {
2341da177e4SLinus Torvalds 		*p++ = xdr_zero;
2351da177e4SLinus Torvalds 	}
2361da177e4SLinus Torvalds 	if (attr->ia_valid & ATTR_UID) {
2371da177e4SLinus Torvalds 		*p++ = xdr_one;
2381da177e4SLinus Torvalds 		*p++ = htonl(attr->ia_uid);
2391da177e4SLinus Torvalds 	} else {
2401da177e4SLinus Torvalds 		*p++ = xdr_zero;
2411da177e4SLinus Torvalds 	}
2421da177e4SLinus Torvalds 	if (attr->ia_valid & ATTR_GID) {
2431da177e4SLinus Torvalds 		*p++ = xdr_one;
2441da177e4SLinus Torvalds 		*p++ = htonl(attr->ia_gid);
2451da177e4SLinus Torvalds 	} else {
2461da177e4SLinus Torvalds 		*p++ = xdr_zero;
2471da177e4SLinus Torvalds 	}
2481da177e4SLinus Torvalds 	if (attr->ia_valid & ATTR_SIZE) {
2491da177e4SLinus Torvalds 		*p++ = xdr_one;
2501da177e4SLinus Torvalds 		p = xdr_encode_hyper(p, (__u64) attr->ia_size);
2511da177e4SLinus Torvalds 	} else {
2521da177e4SLinus Torvalds 		*p++ = xdr_zero;
2531da177e4SLinus Torvalds 	}
2541da177e4SLinus Torvalds 	if (attr->ia_valid & ATTR_ATIME_SET) {
2551da177e4SLinus Torvalds 		*p++ = xdr_two;
2561da177e4SLinus Torvalds 		p = xdr_encode_time3(p, &attr->ia_atime);
2571da177e4SLinus Torvalds 	} else if (attr->ia_valid & ATTR_ATIME) {
2581da177e4SLinus Torvalds 		*p++ = xdr_one;
2591da177e4SLinus Torvalds 	} else {
2601da177e4SLinus Torvalds 		*p++ = xdr_zero;
2611da177e4SLinus Torvalds 	}
2621da177e4SLinus Torvalds 	if (attr->ia_valid & ATTR_MTIME_SET) {
2631da177e4SLinus Torvalds 		*p++ = xdr_two;
2641da177e4SLinus Torvalds 		p = xdr_encode_time3(p, &attr->ia_mtime);
2651da177e4SLinus Torvalds 	} else if (attr->ia_valid & ATTR_MTIME) {
2661da177e4SLinus Torvalds 		*p++ = xdr_one;
2671da177e4SLinus Torvalds 	} else {
2681da177e4SLinus Torvalds 		*p++ = xdr_zero;
2691da177e4SLinus Torvalds 	}
2701da177e4SLinus Torvalds 	return p;
2711da177e4SLinus Torvalds }
2721da177e4SLinus Torvalds 
273d61005a6SAl Viro static inline __be32 *
274d61005a6SAl Viro xdr_decode_wcc_attr(__be32 *p, struct nfs_fattr *fattr)
2751da177e4SLinus Torvalds {
2761da177e4SLinus Torvalds 	p = xdr_decode_hyper(p, &fattr->pre_size);
2771da177e4SLinus Torvalds 	p = xdr_decode_time3(p, &fattr->pre_mtime);
2781da177e4SLinus Torvalds 	p = xdr_decode_time3(p, &fattr->pre_ctime);
2799e6e70f8STrond Myklebust 	fattr->valid |= NFS_ATTR_FATTR_PRESIZE
2809e6e70f8STrond Myklebust 		| NFS_ATTR_FATTR_PREMTIME
2819e6e70f8STrond Myklebust 		| NFS_ATTR_FATTR_PRECTIME;
2821da177e4SLinus Torvalds 	return p;
2831da177e4SLinus Torvalds }
2841da177e4SLinus Torvalds 
285d61005a6SAl Viro static inline __be32 *
286d61005a6SAl Viro xdr_decode_post_op_attr(__be32 *p, struct nfs_fattr *fattr)
2871da177e4SLinus Torvalds {
2881da177e4SLinus Torvalds 	if (*p++)
2891da177e4SLinus Torvalds 		p = xdr_decode_fattr(p, fattr);
2901da177e4SLinus Torvalds 	return p;
2911da177e4SLinus Torvalds }
2921da177e4SLinus Torvalds 
293d61005a6SAl Viro static inline __be32 *
294babddc72SBryan Schumaker xdr_decode_post_op_attr_stream(struct xdr_stream *xdr, struct nfs_fattr *fattr)
295babddc72SBryan Schumaker {
296babddc72SBryan Schumaker 	__be32 *p;
297babddc72SBryan Schumaker 
298babddc72SBryan Schumaker 	p = xdr_inline_decode(xdr, 4);
299babddc72SBryan Schumaker 	if (unlikely(!p))
300babddc72SBryan Schumaker 		goto out_overflow;
301babddc72SBryan Schumaker 	if (ntohl(*p++)) {
302babddc72SBryan Schumaker 		p = xdr_inline_decode(xdr, 84);
303babddc72SBryan Schumaker 		if (unlikely(!p))
304babddc72SBryan Schumaker 			goto out_overflow;
305babddc72SBryan Schumaker 		p = xdr_decode_fattr(p, fattr);
306babddc72SBryan Schumaker 	}
307babddc72SBryan Schumaker 	return p;
308babddc72SBryan Schumaker out_overflow:
309babddc72SBryan Schumaker 	print_overflow_msg(__func__, xdr);
310babddc72SBryan Schumaker 	return ERR_PTR(-EIO);
311babddc72SBryan Schumaker }
312babddc72SBryan Schumaker 
313babddc72SBryan Schumaker static inline __be32 *
314d61005a6SAl Viro xdr_decode_pre_op_attr(__be32 *p, struct nfs_fattr *fattr)
3151da177e4SLinus Torvalds {
3161da177e4SLinus Torvalds 	if (*p++)
3171da177e4SLinus Torvalds 		return xdr_decode_wcc_attr(p, fattr);
3181da177e4SLinus Torvalds 	return p;
3191da177e4SLinus Torvalds }
3201da177e4SLinus Torvalds 
3211da177e4SLinus Torvalds 
322d61005a6SAl Viro static inline __be32 *
323d61005a6SAl Viro xdr_decode_wcc_data(__be32 *p, struct nfs_fattr *fattr)
3241da177e4SLinus Torvalds {
3251da177e4SLinus Torvalds 	p = xdr_decode_pre_op_attr(p, fattr);
3261da177e4SLinus Torvalds 	return xdr_decode_post_op_attr(p, fattr);
3271da177e4SLinus Torvalds }
3281da177e4SLinus Torvalds 
329d9c407b1SChuck Lever 
330d9c407b1SChuck Lever /*
331d9c407b1SChuck Lever  * Encode/decode NFSv3 basic data types
332d9c407b1SChuck Lever  *
333d9c407b1SChuck Lever  * Basic NFSv3 data types are defined in section 2.5 of RFC 1813:
334d9c407b1SChuck Lever  * "NFS Version 3 Protocol Specification".
335d9c407b1SChuck Lever  *
336d9c407b1SChuck Lever  * Not all basic data types have their own encoding and decoding
337d9c407b1SChuck Lever  * functions.  For run-time efficiency, some data types are encoded
338d9c407b1SChuck Lever  * or decoded inline.
339d9c407b1SChuck Lever  */
340d9c407b1SChuck Lever 
341d9c407b1SChuck Lever static void encode_uint32(struct xdr_stream *xdr, u32 value)
342d9c407b1SChuck Lever {
343d9c407b1SChuck Lever 	__be32 *p = xdr_reserve_space(xdr, 4);
344d9c407b1SChuck Lever 	*p = cpu_to_be32(value);
345d9c407b1SChuck Lever }
346d9c407b1SChuck Lever 
347d9c407b1SChuck Lever /*
348d9c407b1SChuck Lever  * filename3
349d9c407b1SChuck Lever  *
350d9c407b1SChuck Lever  *	typedef string filename3<>;
351d9c407b1SChuck Lever  */
352d9c407b1SChuck Lever static void encode_filename3(struct xdr_stream *xdr,
353d9c407b1SChuck Lever 			     const char *name, u32 length)
354d9c407b1SChuck Lever {
355d9c407b1SChuck Lever 	__be32 *p;
356d9c407b1SChuck Lever 
357d9c407b1SChuck Lever 	BUG_ON(length > NFS3_MAXNAMLEN);
358d9c407b1SChuck Lever 	p = xdr_reserve_space(xdr, 4 + length);
359d9c407b1SChuck Lever 	xdr_encode_opaque(p, name, length);
360d9c407b1SChuck Lever }
361d9c407b1SChuck Lever 
362d9c407b1SChuck Lever /*
363d9c407b1SChuck Lever  * nfspath3
364d9c407b1SChuck Lever  *
365d9c407b1SChuck Lever  *	typedef string nfspath3<>;
366d9c407b1SChuck Lever  */
367d9c407b1SChuck Lever static void encode_nfspath3(struct xdr_stream *xdr, struct page **pages,
368d9c407b1SChuck Lever 			    const u32 length)
369d9c407b1SChuck Lever {
370d9c407b1SChuck Lever 	BUG_ON(length > NFS3_MAXPATHLEN);
371d9c407b1SChuck Lever 	encode_uint32(xdr, length);
372d9c407b1SChuck Lever 	xdr_write_pages(xdr, pages, 0, length);
373d9c407b1SChuck Lever }
374d9c407b1SChuck Lever 
375d9c407b1SChuck Lever /*
376d9c407b1SChuck Lever  * cookie3
377d9c407b1SChuck Lever  *
378d9c407b1SChuck Lever  *	typedef uint64 cookie3
379d9c407b1SChuck Lever  */
380d9c407b1SChuck Lever static __be32 *xdr_encode_cookie3(__be32 *p, u64 cookie)
381d9c407b1SChuck Lever {
382d9c407b1SChuck Lever 	return xdr_encode_hyper(p, cookie);
383d9c407b1SChuck Lever }
384d9c407b1SChuck Lever 
385d9c407b1SChuck Lever /*
386d9c407b1SChuck Lever  * cookieverf3
387d9c407b1SChuck Lever  *
388d9c407b1SChuck Lever  *	typedef opaque cookieverf3[NFS3_COOKIEVERFSIZE];
389d9c407b1SChuck Lever  */
390d9c407b1SChuck Lever static __be32 *xdr_encode_cookieverf3(__be32 *p, const __be32 *verifier)
391d9c407b1SChuck Lever {
392d9c407b1SChuck Lever 	memcpy(p, verifier, NFS3_COOKIEVERFSIZE);
393d9c407b1SChuck Lever 	return p + XDR_QUADLEN(NFS3_COOKIEVERFSIZE);
394d9c407b1SChuck Lever }
395d9c407b1SChuck Lever 
396d9c407b1SChuck Lever /*
397d9c407b1SChuck Lever  * createverf3
398d9c407b1SChuck Lever  *
399d9c407b1SChuck Lever  *	typedef opaque createverf3[NFS3_CREATEVERFSIZE];
400d9c407b1SChuck Lever  */
401d9c407b1SChuck Lever static void encode_createverf3(struct xdr_stream *xdr, const __be32 *verifier)
402d9c407b1SChuck Lever {
403d9c407b1SChuck Lever 	__be32 *p;
404d9c407b1SChuck Lever 
405d9c407b1SChuck Lever 	p = xdr_reserve_space(xdr, NFS3_CREATEVERFSIZE);
406d9c407b1SChuck Lever 	memcpy(p, verifier, NFS3_CREATEVERFSIZE);
407d9c407b1SChuck Lever }
408d9c407b1SChuck Lever 
409d9c407b1SChuck Lever /*
410d9c407b1SChuck Lever  * ftype3
411d9c407b1SChuck Lever  *
412d9c407b1SChuck Lever  *	enum ftype3 {
413d9c407b1SChuck Lever  *		NF3REG	= 1,
414d9c407b1SChuck Lever  *		NF3DIR	= 2,
415d9c407b1SChuck Lever  *		NF3BLK	= 3,
416d9c407b1SChuck Lever  *		NF3CHR	= 4,
417d9c407b1SChuck Lever  *		NF3LNK	= 5,
418d9c407b1SChuck Lever  *		NF3SOCK	= 6,
419d9c407b1SChuck Lever  *		NF3FIFO	= 7
420d9c407b1SChuck Lever  *	};
421d9c407b1SChuck Lever  */
422d9c407b1SChuck Lever static void encode_ftype3(struct xdr_stream *xdr, const u32 type)
423d9c407b1SChuck Lever {
424d9c407b1SChuck Lever 	BUG_ON(type > NF3FIFO);
425d9c407b1SChuck Lever 	encode_uint32(xdr, type);
426d9c407b1SChuck Lever }
427d9c407b1SChuck Lever 
428d9c407b1SChuck Lever /*
429d9c407b1SChuck Lever  * specdata3
430d9c407b1SChuck Lever  *
431d9c407b1SChuck Lever  *     struct specdata3 {
432d9c407b1SChuck Lever  *             uint32  specdata1;
433d9c407b1SChuck Lever  *             uint32  specdata2;
434d9c407b1SChuck Lever  *     };
435d9c407b1SChuck Lever  */
436d9c407b1SChuck Lever static void encode_specdata3(struct xdr_stream *xdr, const dev_t rdev)
437d9c407b1SChuck Lever {
438d9c407b1SChuck Lever 	__be32 *p;
439d9c407b1SChuck Lever 
440d9c407b1SChuck Lever 	p = xdr_reserve_space(xdr, 8);
441d9c407b1SChuck Lever 	*p++ = cpu_to_be32(MAJOR(rdev));
442d9c407b1SChuck Lever 	*p = cpu_to_be32(MINOR(rdev));
443d9c407b1SChuck Lever }
444d9c407b1SChuck Lever 
445d9c407b1SChuck Lever /*
446d9c407b1SChuck Lever  * nfs_fh3
447d9c407b1SChuck Lever  *
448d9c407b1SChuck Lever  *	struct nfs_fh3 {
449d9c407b1SChuck Lever  *		opaque       data<NFS3_FHSIZE>;
450d9c407b1SChuck Lever  *	};
451d9c407b1SChuck Lever  */
452d9c407b1SChuck Lever static void encode_nfs_fh3(struct xdr_stream *xdr, const struct nfs_fh *fh)
453d9c407b1SChuck Lever {
454d9c407b1SChuck Lever 	__be32 *p;
455d9c407b1SChuck Lever 
456d9c407b1SChuck Lever 	BUG_ON(fh->size > NFS3_FHSIZE);
457d9c407b1SChuck Lever 	p = xdr_reserve_space(xdr, 4 + fh->size);
458d9c407b1SChuck Lever 	xdr_encode_opaque(p, fh->data, fh->size);
459d9c407b1SChuck Lever }
460d9c407b1SChuck Lever 
461d9c407b1SChuck Lever /*
462d9c407b1SChuck Lever  * sattr3
463d9c407b1SChuck Lever  *
464d9c407b1SChuck Lever  *	enum time_how {
465d9c407b1SChuck Lever  *		DONT_CHANGE		= 0,
466d9c407b1SChuck Lever  *		SET_TO_SERVER_TIME	= 1,
467d9c407b1SChuck Lever  *		SET_TO_CLIENT_TIME	= 2
468d9c407b1SChuck Lever  *	};
469d9c407b1SChuck Lever  *
470d9c407b1SChuck Lever  *	union set_mode3 switch (bool set_it) {
471d9c407b1SChuck Lever  *	case TRUE:
472d9c407b1SChuck Lever  *		mode3	mode;
473d9c407b1SChuck Lever  *	default:
474d9c407b1SChuck Lever  *		void;
475d9c407b1SChuck Lever  *	};
476d9c407b1SChuck Lever  *
477d9c407b1SChuck Lever  *	union set_uid3 switch (bool set_it) {
478d9c407b1SChuck Lever  *	case TRUE:
479d9c407b1SChuck Lever  *		uid3	uid;
480d9c407b1SChuck Lever  *	default:
481d9c407b1SChuck Lever  *		void;
482d9c407b1SChuck Lever  *	};
483d9c407b1SChuck Lever  *
484d9c407b1SChuck Lever  *	union set_gid3 switch (bool set_it) {
485d9c407b1SChuck Lever  *	case TRUE:
486d9c407b1SChuck Lever  *		gid3	gid;
487d9c407b1SChuck Lever  *	default:
488d9c407b1SChuck Lever  *		void;
489d9c407b1SChuck Lever  *	};
490d9c407b1SChuck Lever  *
491d9c407b1SChuck Lever  *	union set_size3 switch (bool set_it) {
492d9c407b1SChuck Lever  *	case TRUE:
493d9c407b1SChuck Lever  *		size3	size;
494d9c407b1SChuck Lever  *	default:
495d9c407b1SChuck Lever  *		void;
496d9c407b1SChuck Lever  *	};
497d9c407b1SChuck Lever  *
498d9c407b1SChuck Lever  *	union set_atime switch (time_how set_it) {
499d9c407b1SChuck Lever  *	case SET_TO_CLIENT_TIME:
500d9c407b1SChuck Lever  *		nfstime3	atime;
501d9c407b1SChuck Lever  *	default:
502d9c407b1SChuck Lever  *		void;
503d9c407b1SChuck Lever  *	};
504d9c407b1SChuck Lever  *
505d9c407b1SChuck Lever  *	union set_mtime switch (time_how set_it) {
506d9c407b1SChuck Lever  *	case SET_TO_CLIENT_TIME:
507d9c407b1SChuck Lever  *		nfstime3  mtime;
508d9c407b1SChuck Lever  *	default:
509d9c407b1SChuck Lever  *		void;
510d9c407b1SChuck Lever  *	};
511d9c407b1SChuck Lever  *
512d9c407b1SChuck Lever  *	struct sattr3 {
513d9c407b1SChuck Lever  *		set_mode3	mode;
514d9c407b1SChuck Lever  *		set_uid3	uid;
515d9c407b1SChuck Lever  *		set_gid3	gid;
516d9c407b1SChuck Lever  *		set_size3	size;
517d9c407b1SChuck Lever  *		set_atime	atime;
518d9c407b1SChuck Lever  *		set_mtime	mtime;
519d9c407b1SChuck Lever  *	};
520d9c407b1SChuck Lever  */
521d9c407b1SChuck Lever static void encode_sattr3(struct xdr_stream *xdr, const struct iattr *attr)
522d9c407b1SChuck Lever {
523d9c407b1SChuck Lever 	u32 nbytes;
524d9c407b1SChuck Lever 	__be32 *p;
525d9c407b1SChuck Lever 
526d9c407b1SChuck Lever 	/*
527d9c407b1SChuck Lever 	 * In order to make only a single xdr_reserve_space() call,
528d9c407b1SChuck Lever 	 * pre-compute the total number of bytes to be reserved.
529d9c407b1SChuck Lever 	 * Six boolean values, one for each set_foo field, are always
530d9c407b1SChuck Lever 	 * present in the encoded result, so start there.
531d9c407b1SChuck Lever 	 */
532d9c407b1SChuck Lever 	nbytes = 6 * 4;
533d9c407b1SChuck Lever 	if (attr->ia_valid & ATTR_MODE)
534d9c407b1SChuck Lever 		nbytes += 4;
535d9c407b1SChuck Lever 	if (attr->ia_valid & ATTR_UID)
536d9c407b1SChuck Lever 		nbytes += 4;
537d9c407b1SChuck Lever 	if (attr->ia_valid & ATTR_GID)
538d9c407b1SChuck Lever 		nbytes += 4;
539d9c407b1SChuck Lever 	if (attr->ia_valid & ATTR_SIZE)
540d9c407b1SChuck Lever 		nbytes += 8;
541d9c407b1SChuck Lever 	if (attr->ia_valid & ATTR_ATIME_SET)
542d9c407b1SChuck Lever 		nbytes += 8;
543d9c407b1SChuck Lever 	if (attr->ia_valid & ATTR_MTIME_SET)
544d9c407b1SChuck Lever 		nbytes += 8;
545d9c407b1SChuck Lever 	p = xdr_reserve_space(xdr, nbytes);
546d9c407b1SChuck Lever 
547d9c407b1SChuck Lever 	xdr_encode_sattr(p, attr);
548d9c407b1SChuck Lever }
549d9c407b1SChuck Lever 
550d9c407b1SChuck Lever /*
551d9c407b1SChuck Lever  * diropargs3
552d9c407b1SChuck Lever  *
553d9c407b1SChuck Lever  *	struct diropargs3 {
554d9c407b1SChuck Lever  *		nfs_fh3		dir;
555d9c407b1SChuck Lever  *		filename3	name;
556d9c407b1SChuck Lever  *	};
557d9c407b1SChuck Lever  */
558d9c407b1SChuck Lever static void encode_diropargs3(struct xdr_stream *xdr, const struct nfs_fh *fh,
559d9c407b1SChuck Lever 			      const char *name, u32 length)
560d9c407b1SChuck Lever {
561d9c407b1SChuck Lever 	encode_nfs_fh3(xdr, fh);
562d9c407b1SChuck Lever 	encode_filename3(xdr, name, length);
563d9c407b1SChuck Lever }
564d9c407b1SChuck Lever 
565d9c407b1SChuck Lever 
5661da177e4SLinus Torvalds /*
5671da177e4SLinus Torvalds  * NFS encode functions
5681da177e4SLinus Torvalds  */
5691da177e4SLinus Torvalds 
5701da177e4SLinus Torvalds /*
5711da177e4SLinus Torvalds  * Encode file handle argument
5721da177e4SLinus Torvalds  */
5731da177e4SLinus Torvalds static int
574d61005a6SAl Viro nfs3_xdr_fhandle(struct rpc_rqst *req, __be32 *p, struct nfs_fh *fh)
5751da177e4SLinus Torvalds {
5761da177e4SLinus Torvalds 	p = xdr_encode_fhandle(p, fh);
5771da177e4SLinus Torvalds 	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
5781da177e4SLinus Torvalds 	return 0;
5791da177e4SLinus Torvalds }
5801da177e4SLinus Torvalds 
5811da177e4SLinus Torvalds /*
582d9c407b1SChuck Lever  * 3.3.1  GETATTR3args
583d9c407b1SChuck Lever  *
584d9c407b1SChuck Lever  *	struct GETATTR3args {
585d9c407b1SChuck Lever  *		nfs_fh3  object;
586d9c407b1SChuck Lever  *	};
587d9c407b1SChuck Lever  */
588d9c407b1SChuck Lever static int nfs3_xdr_enc_getattr3args(struct rpc_rqst *req, __be32 *p,
589d9c407b1SChuck Lever 				     const struct nfs_fh *fh)
590d9c407b1SChuck Lever {
591d9c407b1SChuck Lever 	struct xdr_stream xdr;
592d9c407b1SChuck Lever 
593d9c407b1SChuck Lever 	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
594d9c407b1SChuck Lever 	encode_nfs_fh3(&xdr, fh);
595d9c407b1SChuck Lever 	return 0;
596d9c407b1SChuck Lever }
597d9c407b1SChuck Lever 
598d9c407b1SChuck Lever /*
5991da177e4SLinus Torvalds  * Encode SETATTR arguments
6001da177e4SLinus Torvalds  */
6011da177e4SLinus Torvalds static int
602d61005a6SAl Viro nfs3_xdr_sattrargs(struct rpc_rqst *req, __be32 *p, struct nfs3_sattrargs *args)
6031da177e4SLinus Torvalds {
6041da177e4SLinus Torvalds 	p = xdr_encode_fhandle(p, args->fh);
6051da177e4SLinus Torvalds 	p = xdr_encode_sattr(p, args->sattr);
6061da177e4SLinus Torvalds 	*p++ = htonl(args->guard);
6071da177e4SLinus Torvalds 	if (args->guard)
6081da177e4SLinus Torvalds 		p = xdr_encode_time3(p, &args->guardtime);
6091da177e4SLinus Torvalds 	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
6101da177e4SLinus Torvalds 	return 0;
6111da177e4SLinus Torvalds }
6121da177e4SLinus Torvalds 
6131da177e4SLinus Torvalds /*
614d9c407b1SChuck Lever  * 3.3.2  SETATTR3args
615d9c407b1SChuck Lever  *
616d9c407b1SChuck Lever  *	union sattrguard3 switch (bool check) {
617d9c407b1SChuck Lever  *	case TRUE:
618d9c407b1SChuck Lever  *		nfstime3  obj_ctime;
619d9c407b1SChuck Lever  *	case FALSE:
620d9c407b1SChuck Lever  *		void;
621d9c407b1SChuck Lever  *	};
622d9c407b1SChuck Lever  *
623d9c407b1SChuck Lever  *	struct SETATTR3args {
624d9c407b1SChuck Lever  *		nfs_fh3		object;
625d9c407b1SChuck Lever  *		sattr3		new_attributes;
626d9c407b1SChuck Lever  *		sattrguard3	guard;
627d9c407b1SChuck Lever  *	};
628d9c407b1SChuck Lever  */
629d9c407b1SChuck Lever static void encode_sattrguard3(struct xdr_stream *xdr,
630d9c407b1SChuck Lever 			       const struct nfs3_sattrargs *args)
631d9c407b1SChuck Lever {
632d9c407b1SChuck Lever 	__be32 *p;
633d9c407b1SChuck Lever 
634d9c407b1SChuck Lever 	if (args->guard) {
635d9c407b1SChuck Lever 		p = xdr_reserve_space(xdr, 4 + 8);
636d9c407b1SChuck Lever 		*p++ = xdr_one;
637d9c407b1SChuck Lever 		xdr_encode_time3(p, &args->guardtime);
638d9c407b1SChuck Lever 	} else {
639d9c407b1SChuck Lever 		p = xdr_reserve_space(xdr, 4);
640d9c407b1SChuck Lever 		*p = xdr_zero;
641d9c407b1SChuck Lever 	}
642d9c407b1SChuck Lever }
643d9c407b1SChuck Lever 
644d9c407b1SChuck Lever static int nfs3_xdr_enc_setattr3args(struct rpc_rqst *req, __be32 *p,
645d9c407b1SChuck Lever 				     const struct nfs3_sattrargs *args)
646d9c407b1SChuck Lever {
647d9c407b1SChuck Lever 	struct xdr_stream xdr;
648d9c407b1SChuck Lever 
649d9c407b1SChuck Lever 	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
650d9c407b1SChuck Lever 	encode_nfs_fh3(&xdr, args->fh);
651d9c407b1SChuck Lever 	encode_sattr3(&xdr, args->sattr);
652d9c407b1SChuck Lever 	encode_sattrguard3(&xdr, args);
653d9c407b1SChuck Lever 	return 0;
654d9c407b1SChuck Lever }
655d9c407b1SChuck Lever 
656d9c407b1SChuck Lever /*
6571da177e4SLinus Torvalds  * Encode directory ops argument
6581da177e4SLinus Torvalds  */
6591da177e4SLinus Torvalds static int
660d61005a6SAl Viro nfs3_xdr_diropargs(struct rpc_rqst *req, __be32 *p, struct nfs3_diropargs *args)
6611da177e4SLinus Torvalds {
6621da177e4SLinus Torvalds 	p = xdr_encode_fhandle(p, args->fh);
6631da177e4SLinus Torvalds 	p = xdr_encode_array(p, args->name, args->len);
6641da177e4SLinus Torvalds 	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
6651da177e4SLinus Torvalds 	return 0;
6661da177e4SLinus Torvalds }
6671da177e4SLinus Torvalds 
6681da177e4SLinus Torvalds /*
669d9c407b1SChuck Lever  * 3.3.3  LOOKUP3args
670d9c407b1SChuck Lever  *
671d9c407b1SChuck Lever  *	struct LOOKUP3args {
672d9c407b1SChuck Lever  *		diropargs3  what;
673d9c407b1SChuck Lever  *	};
674d9c407b1SChuck Lever  */
675d9c407b1SChuck Lever static int nfs3_xdr_enc_lookup3args(struct rpc_rqst *req, __be32 *p,
676d9c407b1SChuck Lever 				    const struct nfs3_diropargs *args)
677d9c407b1SChuck Lever {
678d9c407b1SChuck Lever 	struct xdr_stream xdr;
679d9c407b1SChuck Lever 
680d9c407b1SChuck Lever 	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
681d9c407b1SChuck Lever 	encode_diropargs3(&xdr, args->fh, args->name, args->len);
682d9c407b1SChuck Lever 	return 0;
683d9c407b1SChuck Lever }
684d9c407b1SChuck Lever 
685d9c407b1SChuck Lever /*
6864fdc17b2STrond Myklebust  * Encode REMOVE argument
6874fdc17b2STrond Myklebust  */
6884fdc17b2STrond Myklebust static int
6894fdc17b2STrond Myklebust nfs3_xdr_removeargs(struct rpc_rqst *req, __be32 *p, const struct nfs_removeargs *args)
6904fdc17b2STrond Myklebust {
6914fdc17b2STrond Myklebust 	p = xdr_encode_fhandle(p, args->fh);
6924fdc17b2STrond Myklebust 	p = xdr_encode_array(p, args->name.name, args->name.len);
6934fdc17b2STrond Myklebust 	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
6944fdc17b2STrond Myklebust 	return 0;
6954fdc17b2STrond Myklebust }
6964fdc17b2STrond Myklebust 
6974fdc17b2STrond Myklebust /*
6981da177e4SLinus Torvalds  * Encode access() argument
6991da177e4SLinus Torvalds  */
7001da177e4SLinus Torvalds static int
701d61005a6SAl Viro nfs3_xdr_accessargs(struct rpc_rqst *req, __be32 *p, struct nfs3_accessargs *args)
7021da177e4SLinus Torvalds {
7031da177e4SLinus Torvalds 	p = xdr_encode_fhandle(p, args->fh);
7041da177e4SLinus Torvalds 	*p++ = htonl(args->access);
7051da177e4SLinus Torvalds 	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
7061da177e4SLinus Torvalds 	return 0;
7071da177e4SLinus Torvalds }
7081da177e4SLinus Torvalds 
7091da177e4SLinus Torvalds /*
710d9c407b1SChuck Lever  * 3.3.4  ACCESS3args
711d9c407b1SChuck Lever  *
712d9c407b1SChuck Lever  *	struct ACCESS3args {
713d9c407b1SChuck Lever  *		nfs_fh3		object;
714d9c407b1SChuck Lever  *		uint32		access;
715d9c407b1SChuck Lever  *	};
716d9c407b1SChuck Lever  */
717d9c407b1SChuck Lever static void encode_access3args(struct xdr_stream *xdr,
718d9c407b1SChuck Lever 			       const struct nfs3_accessargs *args)
719d9c407b1SChuck Lever {
720d9c407b1SChuck Lever 	encode_nfs_fh3(xdr, args->fh);
721d9c407b1SChuck Lever 	encode_uint32(xdr, args->access);
722d9c407b1SChuck Lever }
723d9c407b1SChuck Lever 
724d9c407b1SChuck Lever static int nfs3_xdr_enc_access3args(struct rpc_rqst *req, __be32 *p,
725d9c407b1SChuck Lever 				    const struct nfs3_accessargs *args)
726d9c407b1SChuck Lever {
727d9c407b1SChuck Lever 	struct xdr_stream xdr;
728d9c407b1SChuck Lever 
729d9c407b1SChuck Lever 	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
730d9c407b1SChuck Lever 	encode_access3args(&xdr, args);
731d9c407b1SChuck Lever 	return 0;
732d9c407b1SChuck Lever }
733d9c407b1SChuck Lever 
734d9c407b1SChuck Lever /*
735d9c407b1SChuck Lever  * 3.3.5  READLINK3args
736d9c407b1SChuck Lever  *
737d9c407b1SChuck Lever  *	struct READLINK3args {
738d9c407b1SChuck Lever  *		nfs_fh3	symlink;
739d9c407b1SChuck Lever  *	};
740d9c407b1SChuck Lever  */
741d9c407b1SChuck Lever static int nfs3_xdr_enc_readlink3args(struct rpc_rqst *req, __be32 *p,
742d9c407b1SChuck Lever 				      const struct nfs3_readlinkargs *args)
743d9c407b1SChuck Lever {
744d9c407b1SChuck Lever 	struct xdr_stream xdr;
745d9c407b1SChuck Lever 
746d9c407b1SChuck Lever 	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
747d9c407b1SChuck Lever 	encode_nfs_fh3(&xdr, args->fh);
748d9c407b1SChuck Lever 	prepare_reply_buffer(req, args->pages, args->pgbase,
749d9c407b1SChuck Lever 					args->pglen, NFS3_readlinkres_sz);
750d9c407b1SChuck Lever 	return 0;
751d9c407b1SChuck Lever }
752d9c407b1SChuck Lever 
753d9c407b1SChuck Lever /*
7541da177e4SLinus Torvalds  * Arguments to a READ call. Since we read data directly into the page
7551da177e4SLinus Torvalds  * cache, we also set up the reply iovec here so that iov[1] points
7561da177e4SLinus Torvalds  * exactly to the page we want to fetch.
7571da177e4SLinus Torvalds  */
7581da177e4SLinus Torvalds static int
759d61005a6SAl Viro nfs3_xdr_readargs(struct rpc_rqst *req, __be32 *p, struct nfs_readargs *args)
7601da177e4SLinus Torvalds {
761a17c2153STrond Myklebust 	struct rpc_auth	*auth = req->rq_cred->cr_auth;
7621da177e4SLinus Torvalds 	unsigned int replen;
7631da177e4SLinus Torvalds 	u32 count = args->count;
7641da177e4SLinus Torvalds 
7651da177e4SLinus Torvalds 	p = xdr_encode_fhandle(p, args->fh);
7661da177e4SLinus Torvalds 	p = xdr_encode_hyper(p, args->offset);
7671da177e4SLinus Torvalds 	*p++ = htonl(count);
7681da177e4SLinus Torvalds 	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
7691da177e4SLinus Torvalds 
7701da177e4SLinus Torvalds 	/* Inline the page array */
7711da177e4SLinus Torvalds 	replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS3_readres_sz) << 2;
7721da177e4SLinus Torvalds 	xdr_inline_pages(&req->rq_rcv_buf, replen,
7731da177e4SLinus Torvalds 			 args->pages, args->pgbase, count);
7744f22ccc3S\"Talpey, Thomas\ 	req->rq_rcv_buf.flags |= XDRBUF_READ;
7751da177e4SLinus Torvalds 	return 0;
7761da177e4SLinus Torvalds }
7771da177e4SLinus Torvalds 
7781da177e4SLinus Torvalds /*
779d9c407b1SChuck Lever  * 3.3.6  READ3args
780d9c407b1SChuck Lever  *
781d9c407b1SChuck Lever  *	struct READ3args {
782d9c407b1SChuck Lever  *		nfs_fh3		file;
783d9c407b1SChuck Lever  *		offset3		offset;
784d9c407b1SChuck Lever  *		count3		count;
785d9c407b1SChuck Lever  *	};
786d9c407b1SChuck Lever  */
787d9c407b1SChuck Lever static void encode_read3args(struct xdr_stream *xdr,
788d9c407b1SChuck Lever 			     const struct nfs_readargs *args)
789d9c407b1SChuck Lever {
790d9c407b1SChuck Lever 	__be32 *p;
791d9c407b1SChuck Lever 
792d9c407b1SChuck Lever 	encode_nfs_fh3(xdr, args->fh);
793d9c407b1SChuck Lever 
794d9c407b1SChuck Lever 	p = xdr_reserve_space(xdr, 8 + 4);
795d9c407b1SChuck Lever 	p = xdr_encode_hyper(p, args->offset);
796d9c407b1SChuck Lever 	*p = cpu_to_be32(args->count);
797d9c407b1SChuck Lever }
798d9c407b1SChuck Lever 
799d9c407b1SChuck Lever static int nfs3_xdr_enc_read3args(struct rpc_rqst *req, __be32 *p,
800d9c407b1SChuck Lever 				  const struct nfs_readargs *args)
801d9c407b1SChuck Lever {
802d9c407b1SChuck Lever 	struct xdr_stream xdr;
803d9c407b1SChuck Lever 
804d9c407b1SChuck Lever 	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
805d9c407b1SChuck Lever 	encode_read3args(&xdr, args);
806d9c407b1SChuck Lever 	prepare_reply_buffer(req, args->pages, args->pgbase,
807d9c407b1SChuck Lever 					args->count, NFS3_readres_sz);
808d9c407b1SChuck Lever 	req->rq_rcv_buf.flags |= XDRBUF_READ;
809d9c407b1SChuck Lever 	return 0;
810d9c407b1SChuck Lever }
811d9c407b1SChuck Lever 
812d9c407b1SChuck Lever /*
8131da177e4SLinus Torvalds  * Write arguments. Splice the buffer to be written into the iovec.
8141da177e4SLinus Torvalds  */
8151da177e4SLinus Torvalds static int
816d61005a6SAl Viro nfs3_xdr_writeargs(struct rpc_rqst *req, __be32 *p, struct nfs_writeargs *args)
8171da177e4SLinus Torvalds {
8181da177e4SLinus Torvalds 	struct xdr_buf *sndbuf = &req->rq_snd_buf;
8191da177e4SLinus Torvalds 	u32 count = args->count;
8201da177e4SLinus Torvalds 
8211da177e4SLinus Torvalds 	p = xdr_encode_fhandle(p, args->fh);
8221da177e4SLinus Torvalds 	p = xdr_encode_hyper(p, args->offset);
8231da177e4SLinus Torvalds 	*p++ = htonl(count);
8241da177e4SLinus Torvalds 	*p++ = htonl(args->stable);
8251da177e4SLinus Torvalds 	*p++ = htonl(count);
8261da177e4SLinus Torvalds 	sndbuf->len = xdr_adjust_iovec(sndbuf->head, p);
8271da177e4SLinus Torvalds 
8281da177e4SLinus Torvalds 	/* Copy the page array */
8291da177e4SLinus Torvalds 	xdr_encode_pages(sndbuf, args->pages, args->pgbase, count);
8304f22ccc3S\"Talpey, Thomas\ 	sndbuf->flags |= XDRBUF_WRITE;
8311da177e4SLinus Torvalds 	return 0;
8321da177e4SLinus Torvalds }
8331da177e4SLinus Torvalds 
8341da177e4SLinus Torvalds /*
835d9c407b1SChuck Lever  * 3.3.7  WRITE3args
836d9c407b1SChuck Lever  *
837d9c407b1SChuck Lever  *	enum stable_how {
838d9c407b1SChuck Lever  *		UNSTABLE  = 0,
839d9c407b1SChuck Lever  *		DATA_SYNC = 1,
840d9c407b1SChuck Lever  *		FILE_SYNC = 2
841d9c407b1SChuck Lever  *	};
842d9c407b1SChuck Lever  *
843d9c407b1SChuck Lever  *	struct WRITE3args {
844d9c407b1SChuck Lever  *		nfs_fh3		file;
845d9c407b1SChuck Lever  *		offset3		offset;
846d9c407b1SChuck Lever  *		count3		count;
847d9c407b1SChuck Lever  *		stable_how	stable;
848d9c407b1SChuck Lever  *		opaque		data<>;
849d9c407b1SChuck Lever  *	};
850d9c407b1SChuck Lever  */
851d9c407b1SChuck Lever static void encode_write3args(struct xdr_stream *xdr,
852d9c407b1SChuck Lever 			      const struct nfs_writeargs *args)
853d9c407b1SChuck Lever {
854d9c407b1SChuck Lever 	__be32 *p;
855d9c407b1SChuck Lever 
856d9c407b1SChuck Lever 	encode_nfs_fh3(xdr, args->fh);
857d9c407b1SChuck Lever 
858d9c407b1SChuck Lever 	p = xdr_reserve_space(xdr, 8 + 4 + 4 + 4);
859d9c407b1SChuck Lever 	p = xdr_encode_hyper(p, args->offset);
860d9c407b1SChuck Lever 	*p++ = cpu_to_be32(args->count);
861d9c407b1SChuck Lever 
862d9c407b1SChuck Lever 	BUG_ON(args->stable > NFS_FILE_SYNC);
863d9c407b1SChuck Lever 	*p++ = cpu_to_be32(args->stable);
864d9c407b1SChuck Lever 
865d9c407b1SChuck Lever 	*p = cpu_to_be32(args->count);
866d9c407b1SChuck Lever 	xdr_write_pages(xdr, args->pages, args->pgbase, args->count);
867d9c407b1SChuck Lever }
868d9c407b1SChuck Lever 
869d9c407b1SChuck Lever static int nfs3_xdr_enc_write3args(struct rpc_rqst *req, __be32 *p,
870d9c407b1SChuck Lever 				   const struct nfs_writeargs *args)
871d9c407b1SChuck Lever {
872d9c407b1SChuck Lever 	struct xdr_stream xdr;
873d9c407b1SChuck Lever 
874d9c407b1SChuck Lever 	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
875d9c407b1SChuck Lever 	encode_write3args(&xdr, args);
876d9c407b1SChuck Lever 	xdr.buf->flags |= XDRBUF_WRITE;
877d9c407b1SChuck Lever 	return 0;
878d9c407b1SChuck Lever }
879d9c407b1SChuck Lever 
880d9c407b1SChuck Lever /*
8811da177e4SLinus Torvalds  * Encode CREATE arguments
8821da177e4SLinus Torvalds  */
8831da177e4SLinus Torvalds static int
884d61005a6SAl Viro nfs3_xdr_createargs(struct rpc_rqst *req, __be32 *p, struct nfs3_createargs *args)
8851da177e4SLinus Torvalds {
8861da177e4SLinus Torvalds 	p = xdr_encode_fhandle(p, args->fh);
8871da177e4SLinus Torvalds 	p = xdr_encode_array(p, args->name, args->len);
8881da177e4SLinus Torvalds 
8891da177e4SLinus Torvalds 	*p++ = htonl(args->createmode);
8901da177e4SLinus Torvalds 	if (args->createmode == NFS3_CREATE_EXCLUSIVE) {
8911da177e4SLinus Torvalds 		*p++ = args->verifier[0];
8921da177e4SLinus Torvalds 		*p++ = args->verifier[1];
8931da177e4SLinus Torvalds 	} else
8941da177e4SLinus Torvalds 		p = xdr_encode_sattr(p, args->sattr);
8951da177e4SLinus Torvalds 
8961da177e4SLinus Torvalds 	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
8971da177e4SLinus Torvalds 	return 0;
8981da177e4SLinus Torvalds }
8991da177e4SLinus Torvalds 
9001da177e4SLinus Torvalds /*
901d9c407b1SChuck Lever  * 3.3.8  CREATE3args
902d9c407b1SChuck Lever  *
903d9c407b1SChuck Lever  *	enum createmode3 {
904d9c407b1SChuck Lever  *		UNCHECKED = 0,
905d9c407b1SChuck Lever  *		GUARDED   = 1,
906d9c407b1SChuck Lever  *		EXCLUSIVE = 2
907d9c407b1SChuck Lever  *	};
908d9c407b1SChuck Lever  *
909d9c407b1SChuck Lever  *	union createhow3 switch (createmode3 mode) {
910d9c407b1SChuck Lever  *	case UNCHECKED:
911d9c407b1SChuck Lever  *	case GUARDED:
912d9c407b1SChuck Lever  *		sattr3       obj_attributes;
913d9c407b1SChuck Lever  *	case EXCLUSIVE:
914d9c407b1SChuck Lever  *		createverf3  verf;
915d9c407b1SChuck Lever  *	};
916d9c407b1SChuck Lever  *
917d9c407b1SChuck Lever  *	struct CREATE3args {
918d9c407b1SChuck Lever  *		diropargs3	where;
919d9c407b1SChuck Lever  *		createhow3	how;
920d9c407b1SChuck Lever  *	};
921d9c407b1SChuck Lever  */
922d9c407b1SChuck Lever static void encode_createhow3(struct xdr_stream *xdr,
923d9c407b1SChuck Lever 			      const struct nfs3_createargs *args)
924d9c407b1SChuck Lever {
925d9c407b1SChuck Lever 	encode_uint32(xdr, args->createmode);
926d9c407b1SChuck Lever 	switch (args->createmode) {
927d9c407b1SChuck Lever 	case NFS3_CREATE_UNCHECKED:
928d9c407b1SChuck Lever 	case NFS3_CREATE_GUARDED:
929d9c407b1SChuck Lever 		encode_sattr3(xdr, args->sattr);
930d9c407b1SChuck Lever 		break;
931d9c407b1SChuck Lever 	case NFS3_CREATE_EXCLUSIVE:
932d9c407b1SChuck Lever 		encode_createverf3(xdr, args->verifier);
933d9c407b1SChuck Lever 		break;
934d9c407b1SChuck Lever 	default:
935d9c407b1SChuck Lever 		BUG();
936d9c407b1SChuck Lever 	}
937d9c407b1SChuck Lever }
938d9c407b1SChuck Lever 
939d9c407b1SChuck Lever static int nfs3_xdr_enc_create3args(struct rpc_rqst *req, __be32 *p,
940d9c407b1SChuck Lever 				    const struct nfs3_createargs *args)
941d9c407b1SChuck Lever {
942d9c407b1SChuck Lever 	struct xdr_stream xdr;
943d9c407b1SChuck Lever 
944d9c407b1SChuck Lever 	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
945d9c407b1SChuck Lever 	encode_diropargs3(&xdr, args->fh, args->name, args->len);
946d9c407b1SChuck Lever 	encode_createhow3(&xdr, args);
947d9c407b1SChuck Lever 	return 0;
948d9c407b1SChuck Lever }
949d9c407b1SChuck Lever 
950d9c407b1SChuck Lever /*
9511da177e4SLinus Torvalds  * Encode MKDIR arguments
9521da177e4SLinus Torvalds  */
9531da177e4SLinus Torvalds static int
954d61005a6SAl Viro nfs3_xdr_mkdirargs(struct rpc_rqst *req, __be32 *p, struct nfs3_mkdirargs *args)
9551da177e4SLinus Torvalds {
9561da177e4SLinus Torvalds 	p = xdr_encode_fhandle(p, args->fh);
9571da177e4SLinus Torvalds 	p = xdr_encode_array(p, args->name, args->len);
9581da177e4SLinus Torvalds 	p = xdr_encode_sattr(p, args->sattr);
9591da177e4SLinus Torvalds 	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
9601da177e4SLinus Torvalds 	return 0;
9611da177e4SLinus Torvalds }
9621da177e4SLinus Torvalds 
9631da177e4SLinus Torvalds /*
964d9c407b1SChuck Lever  * 3.3.9  MKDIR3args
965d9c407b1SChuck Lever  *
966d9c407b1SChuck Lever  *	struct MKDIR3args {
967d9c407b1SChuck Lever  *		diropargs3	where;
968d9c407b1SChuck Lever  *		sattr3		attributes;
969d9c407b1SChuck Lever  *	};
970d9c407b1SChuck Lever  */
971d9c407b1SChuck Lever static int nfs3_xdr_enc_mkdir3args(struct rpc_rqst *req, __be32 *p,
972d9c407b1SChuck Lever 				   const struct nfs3_mkdirargs *args)
973d9c407b1SChuck Lever {
974d9c407b1SChuck Lever 	struct xdr_stream xdr;
975d9c407b1SChuck Lever 
976d9c407b1SChuck Lever 	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
977d9c407b1SChuck Lever 	encode_diropargs3(&xdr, args->fh, args->name, args->len);
978d9c407b1SChuck Lever 	encode_sattr3(&xdr, args->sattr);
979d9c407b1SChuck Lever 	return 0;
980d9c407b1SChuck Lever }
981d9c407b1SChuck Lever 
982d9c407b1SChuck Lever /*
9831da177e4SLinus Torvalds  * Encode SYMLINK arguments
9841da177e4SLinus Torvalds  */
9851da177e4SLinus Torvalds static int
986d61005a6SAl Viro nfs3_xdr_symlinkargs(struct rpc_rqst *req, __be32 *p, struct nfs3_symlinkargs *args)
9871da177e4SLinus Torvalds {
9881da177e4SLinus Torvalds 	p = xdr_encode_fhandle(p, args->fromfh);
9891da177e4SLinus Torvalds 	p = xdr_encode_array(p, args->fromname, args->fromlen);
9901da177e4SLinus Torvalds 	p = xdr_encode_sattr(p, args->sattr);
99194a6d753SChuck Lever 	*p++ = htonl(args->pathlen);
9921da177e4SLinus Torvalds 	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
99394a6d753SChuck Lever 
99494a6d753SChuck Lever 	/* Copy the page */
99594a6d753SChuck Lever 	xdr_encode_pages(&req->rq_snd_buf, args->pages, 0, args->pathlen);
9961da177e4SLinus Torvalds 	return 0;
9971da177e4SLinus Torvalds }
9981da177e4SLinus Torvalds 
9991da177e4SLinus Torvalds /*
1000d9c407b1SChuck Lever  * 3.3.10  SYMLINK3args
1001d9c407b1SChuck Lever  *
1002d9c407b1SChuck Lever  *	struct symlinkdata3 {
1003d9c407b1SChuck Lever  *		sattr3		symlink_attributes;
1004d9c407b1SChuck Lever  *		nfspath3	symlink_data;
1005d9c407b1SChuck Lever  *	};
1006d9c407b1SChuck Lever  *
1007d9c407b1SChuck Lever  *	struct SYMLINK3args {
1008d9c407b1SChuck Lever  *		diropargs3	where;
1009d9c407b1SChuck Lever  *		symlinkdata3	symlink;
1010d9c407b1SChuck Lever  *	};
1011d9c407b1SChuck Lever  */
1012d9c407b1SChuck Lever static void encode_symlinkdata3(struct xdr_stream *xdr,
1013d9c407b1SChuck Lever 				const struct nfs3_symlinkargs *args)
1014d9c407b1SChuck Lever {
1015d9c407b1SChuck Lever 	encode_sattr3(xdr, args->sattr);
1016d9c407b1SChuck Lever 	encode_nfspath3(xdr, args->pages, args->pathlen);
1017d9c407b1SChuck Lever }
1018d9c407b1SChuck Lever 
1019d9c407b1SChuck Lever static int nfs3_xdr_enc_symlink3args(struct rpc_rqst *req, __be32 *p,
1020d9c407b1SChuck Lever 				     const struct nfs3_symlinkargs *args)
1021d9c407b1SChuck Lever {
1022d9c407b1SChuck Lever 	struct xdr_stream xdr;
1023d9c407b1SChuck Lever 
1024d9c407b1SChuck Lever 	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1025d9c407b1SChuck Lever 	encode_diropargs3(&xdr, args->fromfh, args->fromname, args->fromlen);
1026d9c407b1SChuck Lever 	encode_symlinkdata3(&xdr, args);
1027d9c407b1SChuck Lever 	return 0;
1028d9c407b1SChuck Lever }
1029d9c407b1SChuck Lever 
1030d9c407b1SChuck Lever /*
10311da177e4SLinus Torvalds  * Encode MKNOD arguments
10321da177e4SLinus Torvalds  */
10331da177e4SLinus Torvalds static int
1034d61005a6SAl Viro nfs3_xdr_mknodargs(struct rpc_rqst *req, __be32 *p, struct nfs3_mknodargs *args)
10351da177e4SLinus Torvalds {
10361da177e4SLinus Torvalds 	p = xdr_encode_fhandle(p, args->fh);
10371da177e4SLinus Torvalds 	p = xdr_encode_array(p, args->name, args->len);
10381da177e4SLinus Torvalds 	*p++ = htonl(args->type);
10391da177e4SLinus Torvalds 	p = xdr_encode_sattr(p, args->sattr);
10401da177e4SLinus Torvalds 	if (args->type == NF3CHR || args->type == NF3BLK) {
10411da177e4SLinus Torvalds 		*p++ = htonl(MAJOR(args->rdev));
10421da177e4SLinus Torvalds 		*p++ = htonl(MINOR(args->rdev));
10431da177e4SLinus Torvalds 	}
10441da177e4SLinus Torvalds 
10451da177e4SLinus Torvalds 	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
10461da177e4SLinus Torvalds 	return 0;
10471da177e4SLinus Torvalds }
10481da177e4SLinus Torvalds 
10491da177e4SLinus Torvalds /*
1050d9c407b1SChuck Lever  * 3.3.11  MKNOD3args
1051d9c407b1SChuck Lever  *
1052d9c407b1SChuck Lever  *	struct devicedata3 {
1053d9c407b1SChuck Lever  *		sattr3		dev_attributes;
1054d9c407b1SChuck Lever  *		specdata3	spec;
1055d9c407b1SChuck Lever  *	};
1056d9c407b1SChuck Lever  *
1057d9c407b1SChuck Lever  *	union mknoddata3 switch (ftype3 type) {
1058d9c407b1SChuck Lever  *	case NF3CHR:
1059d9c407b1SChuck Lever  *	case NF3BLK:
1060d9c407b1SChuck Lever  *		devicedata3	device;
1061d9c407b1SChuck Lever  *	case NF3SOCK:
1062d9c407b1SChuck Lever  *	case NF3FIFO:
1063d9c407b1SChuck Lever  *		sattr3		pipe_attributes;
1064d9c407b1SChuck Lever  *	default:
1065d9c407b1SChuck Lever  *		void;
1066d9c407b1SChuck Lever  *	};
1067d9c407b1SChuck Lever  *
1068d9c407b1SChuck Lever  *	struct MKNOD3args {
1069d9c407b1SChuck Lever  *		diropargs3	where;
1070d9c407b1SChuck Lever  *		mknoddata3	what;
1071d9c407b1SChuck Lever  *	};
1072d9c407b1SChuck Lever  */
1073d9c407b1SChuck Lever static void encode_devicedata3(struct xdr_stream *xdr,
1074d9c407b1SChuck Lever 			       const struct nfs3_mknodargs *args)
1075d9c407b1SChuck Lever {
1076d9c407b1SChuck Lever 	encode_sattr3(xdr, args->sattr);
1077d9c407b1SChuck Lever 	encode_specdata3(xdr, args->rdev);
1078d9c407b1SChuck Lever }
1079d9c407b1SChuck Lever 
1080d9c407b1SChuck Lever static void encode_mknoddata3(struct xdr_stream *xdr,
1081d9c407b1SChuck Lever 			      const struct nfs3_mknodargs *args)
1082d9c407b1SChuck Lever {
1083d9c407b1SChuck Lever 	encode_ftype3(xdr, args->type);
1084d9c407b1SChuck Lever 	switch (args->type) {
1085d9c407b1SChuck Lever 	case NF3CHR:
1086d9c407b1SChuck Lever 	case NF3BLK:
1087d9c407b1SChuck Lever 		encode_devicedata3(xdr, args);
1088d9c407b1SChuck Lever 		break;
1089d9c407b1SChuck Lever 	case NF3SOCK:
1090d9c407b1SChuck Lever 	case NF3FIFO:
1091d9c407b1SChuck Lever 		encode_sattr3(xdr, args->sattr);
1092d9c407b1SChuck Lever 		break;
1093d9c407b1SChuck Lever 	case NF3REG:
1094d9c407b1SChuck Lever 	case NF3DIR:
1095d9c407b1SChuck Lever 		break;
1096d9c407b1SChuck Lever 	default:
1097d9c407b1SChuck Lever 		BUG();
1098d9c407b1SChuck Lever 	}
1099d9c407b1SChuck Lever }
1100d9c407b1SChuck Lever 
1101d9c407b1SChuck Lever static int nfs3_xdr_enc_mknod3args(struct rpc_rqst *req, __be32 *p,
1102d9c407b1SChuck Lever 				   const struct nfs3_mknodargs *args)
1103d9c407b1SChuck Lever {
1104d9c407b1SChuck Lever 	struct xdr_stream xdr;
1105d9c407b1SChuck Lever 
1106d9c407b1SChuck Lever 	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1107d9c407b1SChuck Lever 	encode_diropargs3(&xdr, args->fh, args->name, args->len);
1108d9c407b1SChuck Lever 	encode_mknoddata3(&xdr, args);
1109d9c407b1SChuck Lever 	return 0;
1110d9c407b1SChuck Lever }
1111d9c407b1SChuck Lever 
1112d9c407b1SChuck Lever /*
1113d9c407b1SChuck Lever  * 3.3.12  REMOVE3args
1114d9c407b1SChuck Lever  *
1115d9c407b1SChuck Lever  *	struct REMOVE3args {
1116d9c407b1SChuck Lever  *		diropargs3  object;
1117d9c407b1SChuck Lever  *	};
1118d9c407b1SChuck Lever  */
1119d9c407b1SChuck Lever static int nfs3_xdr_enc_remove3args(struct rpc_rqst *req, __be32 *p,
1120d9c407b1SChuck Lever 				    const struct nfs_removeargs *args)
1121d9c407b1SChuck Lever {
1122d9c407b1SChuck Lever 	struct xdr_stream xdr;
1123d9c407b1SChuck Lever 
1124d9c407b1SChuck Lever 	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1125d9c407b1SChuck Lever 	encode_diropargs3(&xdr, args->fh, args->name.name, args->name.len);
1126d9c407b1SChuck Lever 	return 0;
1127d9c407b1SChuck Lever }
1128d9c407b1SChuck Lever 
1129d9c407b1SChuck Lever /*
11301da177e4SLinus Torvalds  * Encode RENAME arguments
11311da177e4SLinus Torvalds  */
11321da177e4SLinus Torvalds static int
1133920769f0SJeff Layton nfs3_xdr_renameargs(struct rpc_rqst *req, __be32 *p, struct nfs_renameargs *args)
11341da177e4SLinus Torvalds {
1135920769f0SJeff Layton 	p = xdr_encode_fhandle(p, args->old_dir);
1136920769f0SJeff Layton 	p = xdr_encode_array(p, args->old_name->name, args->old_name->len);
1137920769f0SJeff Layton 	p = xdr_encode_fhandle(p, args->new_dir);
1138920769f0SJeff Layton 	p = xdr_encode_array(p, args->new_name->name, args->new_name->len);
11391da177e4SLinus Torvalds 	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
11401da177e4SLinus Torvalds 	return 0;
11411da177e4SLinus Torvalds }
11421da177e4SLinus Torvalds 
11431da177e4SLinus Torvalds /*
1144d9c407b1SChuck Lever  * 3.3.14  RENAME3args
1145d9c407b1SChuck Lever  *
1146d9c407b1SChuck Lever  *	struct RENAME3args {
1147d9c407b1SChuck Lever  *		diropargs3	from;
1148d9c407b1SChuck Lever  *		diropargs3	to;
1149d9c407b1SChuck Lever  *	};
1150d9c407b1SChuck Lever  */
1151d9c407b1SChuck Lever static int nfs3_xdr_enc_rename3args(struct rpc_rqst *req, __be32 *p,
1152d9c407b1SChuck Lever 				    const struct nfs_renameargs *args)
1153d9c407b1SChuck Lever {
1154d9c407b1SChuck Lever 	const struct qstr *old = args->old_name;
1155d9c407b1SChuck Lever 	const struct qstr *new = args->new_name;
1156d9c407b1SChuck Lever 	struct xdr_stream xdr;
1157d9c407b1SChuck Lever 
1158d9c407b1SChuck Lever 	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1159d9c407b1SChuck Lever 	encode_diropargs3(&xdr, args->old_dir, old->name, old->len);
1160d9c407b1SChuck Lever 	encode_diropargs3(&xdr, args->new_dir, new->name, new->len);
1161d9c407b1SChuck Lever 	return 0;
1162d9c407b1SChuck Lever }
1163d9c407b1SChuck Lever 
1164d9c407b1SChuck Lever /*
11651da177e4SLinus Torvalds  * Encode LINK arguments
11661da177e4SLinus Torvalds  */
11671da177e4SLinus Torvalds static int
1168d61005a6SAl Viro nfs3_xdr_linkargs(struct rpc_rqst *req, __be32 *p, struct nfs3_linkargs *args)
11691da177e4SLinus Torvalds {
11701da177e4SLinus Torvalds 	p = xdr_encode_fhandle(p, args->fromfh);
11711da177e4SLinus Torvalds 	p = xdr_encode_fhandle(p, args->tofh);
11721da177e4SLinus Torvalds 	p = xdr_encode_array(p, args->toname, args->tolen);
11731da177e4SLinus Torvalds 	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
11741da177e4SLinus Torvalds 	return 0;
11751da177e4SLinus Torvalds }
11761da177e4SLinus Torvalds 
11771da177e4SLinus Torvalds /*
1178d9c407b1SChuck Lever  * 3.3.15  LINK3args
1179d9c407b1SChuck Lever  *
1180d9c407b1SChuck Lever  *	struct LINK3args {
1181d9c407b1SChuck Lever  *		nfs_fh3		file;
1182d9c407b1SChuck Lever  *		diropargs3	link;
1183d9c407b1SChuck Lever  *	};
1184d9c407b1SChuck Lever  */
1185d9c407b1SChuck Lever static int nfs3_xdr_enc_link3args(struct rpc_rqst *req, __be32 *p,
1186d9c407b1SChuck Lever 				  const struct nfs3_linkargs *args)
1187d9c407b1SChuck Lever {
1188d9c407b1SChuck Lever 	struct xdr_stream xdr;
1189d9c407b1SChuck Lever 
1190d9c407b1SChuck Lever 	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1191d9c407b1SChuck Lever 	encode_nfs_fh3(&xdr, args->fromfh);
1192d9c407b1SChuck Lever 	encode_diropargs3(&xdr, args->tofh, args->toname, args->tolen);
1193d9c407b1SChuck Lever 	return 0;
1194d9c407b1SChuck Lever }
1195d9c407b1SChuck Lever 
1196d9c407b1SChuck Lever /*
11971da177e4SLinus Torvalds  * Encode arguments to readdir call
11981da177e4SLinus Torvalds  */
11991da177e4SLinus Torvalds static int
1200d61005a6SAl Viro nfs3_xdr_readdirargs(struct rpc_rqst *req, __be32 *p, struct nfs3_readdirargs *args)
12011da177e4SLinus Torvalds {
1202a17c2153STrond Myklebust 	struct rpc_auth	*auth = req->rq_cred->cr_auth;
12031da177e4SLinus Torvalds 	unsigned int replen;
12041da177e4SLinus Torvalds 	u32 count = args->count;
12051da177e4SLinus Torvalds 
12061da177e4SLinus Torvalds 	p = xdr_encode_fhandle(p, args->fh);
12071da177e4SLinus Torvalds 	p = xdr_encode_hyper(p, args->cookie);
12081da177e4SLinus Torvalds 	*p++ = args->verf[0];
12091da177e4SLinus Torvalds 	*p++ = args->verf[1];
12101da177e4SLinus Torvalds 	if (args->plus) {
12111da177e4SLinus Torvalds 		/* readdirplus: need dircount + buffer size.
12121da177e4SLinus Torvalds 		 * We just make sure we make dircount big enough */
12131da177e4SLinus Torvalds 		*p++ = htonl(count >> 3);
12141da177e4SLinus Torvalds 	}
12151da177e4SLinus Torvalds 	*p++ = htonl(count);
12161da177e4SLinus Torvalds 	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
12171da177e4SLinus Torvalds 
12181da177e4SLinus Torvalds 	/* Inline the page array */
12191da177e4SLinus Torvalds 	replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS3_readdirres_sz) << 2;
12201da177e4SLinus Torvalds 	xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, 0, count);
12211da177e4SLinus Torvalds 	return 0;
12221da177e4SLinus Torvalds }
12231da177e4SLinus Torvalds 
12241da177e4SLinus Torvalds /*
1225d9c407b1SChuck Lever  * 3.3.16  READDIR3args
1226d9c407b1SChuck Lever  *
1227d9c407b1SChuck Lever  *	struct READDIR3args {
1228d9c407b1SChuck Lever  *		nfs_fh3		dir;
1229d9c407b1SChuck Lever  *		cookie3		cookie;
1230d9c407b1SChuck Lever  *		cookieverf3	cookieverf;
1231d9c407b1SChuck Lever  *		count3		count;
1232d9c407b1SChuck Lever  *	};
1233d9c407b1SChuck Lever  */
1234d9c407b1SChuck Lever static void encode_readdir3args(struct xdr_stream *xdr,
1235d9c407b1SChuck Lever 				const struct nfs3_readdirargs *args)
1236d9c407b1SChuck Lever {
1237d9c407b1SChuck Lever 	__be32 *p;
1238d9c407b1SChuck Lever 
1239d9c407b1SChuck Lever 	encode_nfs_fh3(xdr, args->fh);
1240d9c407b1SChuck Lever 
1241d9c407b1SChuck Lever 	p = xdr_reserve_space(xdr, 8 + NFS3_COOKIEVERFSIZE + 4);
1242d9c407b1SChuck Lever 	p = xdr_encode_cookie3(p, args->cookie);
1243d9c407b1SChuck Lever 	p = xdr_encode_cookieverf3(p, args->verf);
1244d9c407b1SChuck Lever 	*p = cpu_to_be32(args->count);
1245d9c407b1SChuck Lever }
1246d9c407b1SChuck Lever 
1247d9c407b1SChuck Lever static int nfs3_xdr_enc_readdir3args(struct rpc_rqst *req, __be32 *p,
1248d9c407b1SChuck Lever 				     const struct nfs3_readdirargs *args)
1249d9c407b1SChuck Lever {
1250d9c407b1SChuck Lever 	struct xdr_stream xdr;
1251d9c407b1SChuck Lever 
1252d9c407b1SChuck Lever 	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1253d9c407b1SChuck Lever 	encode_readdir3args(&xdr, args);
1254d9c407b1SChuck Lever 	prepare_reply_buffer(req, args->pages, 0,
1255d9c407b1SChuck Lever 				args->count, NFS3_readdirres_sz);
1256d9c407b1SChuck Lever 	return 0;
1257d9c407b1SChuck Lever }
1258d9c407b1SChuck Lever 
1259d9c407b1SChuck Lever /*
1260d9c407b1SChuck Lever  * 3.3.17  READDIRPLUS3args
1261d9c407b1SChuck Lever  *
1262d9c407b1SChuck Lever  *	struct READDIRPLUS3args {
1263d9c407b1SChuck Lever  *		nfs_fh3		dir;
1264d9c407b1SChuck Lever  *		cookie3		cookie;
1265d9c407b1SChuck Lever  *		cookieverf3	cookieverf;
1266d9c407b1SChuck Lever  *		count3		dircount;
1267d9c407b1SChuck Lever  *		count3		maxcount;
1268d9c407b1SChuck Lever  *	};
1269d9c407b1SChuck Lever  */
1270d9c407b1SChuck Lever static void encode_readdirplus3args(struct xdr_stream *xdr,
1271d9c407b1SChuck Lever 				    const struct nfs3_readdirargs *args)
1272d9c407b1SChuck Lever {
1273d9c407b1SChuck Lever 	__be32 *p;
1274d9c407b1SChuck Lever 
1275d9c407b1SChuck Lever 	encode_nfs_fh3(xdr, args->fh);
1276d9c407b1SChuck Lever 
1277d9c407b1SChuck Lever 	p = xdr_reserve_space(xdr, 8 + NFS3_COOKIEVERFSIZE + 4 + 4);
1278d9c407b1SChuck Lever 	p = xdr_encode_cookie3(p, args->cookie);
1279d9c407b1SChuck Lever 	p = xdr_encode_cookieverf3(p, args->verf);
1280d9c407b1SChuck Lever 
1281d9c407b1SChuck Lever 	/*
1282d9c407b1SChuck Lever 	 * readdirplus: need dircount + buffer size.
1283d9c407b1SChuck Lever 	 * We just make sure we make dircount big enough
1284d9c407b1SChuck Lever 	 */
1285d9c407b1SChuck Lever 	*p++ = cpu_to_be32(args->count >> 3);
1286d9c407b1SChuck Lever 
1287d9c407b1SChuck Lever 	*p = cpu_to_be32(args->count);
1288d9c407b1SChuck Lever }
1289d9c407b1SChuck Lever 
1290d9c407b1SChuck Lever static int nfs3_xdr_enc_readdirplus3args(struct rpc_rqst *req, __be32 *p,
1291d9c407b1SChuck Lever 					 const struct nfs3_readdirargs *args)
1292d9c407b1SChuck Lever {
1293d9c407b1SChuck Lever 	struct xdr_stream xdr;
1294d9c407b1SChuck Lever 
1295d9c407b1SChuck Lever 	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1296d9c407b1SChuck Lever 	encode_readdirplus3args(&xdr, args);
1297d9c407b1SChuck Lever 	prepare_reply_buffer(req, args->pages, 0,
1298d9c407b1SChuck Lever 				args->count, NFS3_readdirres_sz);
1299d9c407b1SChuck Lever 	return 0;
1300d9c407b1SChuck Lever }
1301d9c407b1SChuck Lever 
1302d9c407b1SChuck Lever /*
13031da177e4SLinus Torvalds  * Decode the result of a readdir call.
13041da177e4SLinus Torvalds  * We just check for syntactical correctness.
13051da177e4SLinus Torvalds  */
13061da177e4SLinus Torvalds static int
1307d61005a6SAl Viro nfs3_xdr_readdirres(struct rpc_rqst *req, __be32 *p, struct nfs3_readdirres *res)
13081da177e4SLinus Torvalds {
13091da177e4SLinus Torvalds 	struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
13101da177e4SLinus Torvalds 	struct kvec *iov = rcvbuf->head;
13111da177e4SLinus Torvalds 	struct page **page;
1312c957c526SChuck Lever 	size_t hdrlen;
1313afa8ccc9SBryan Schumaker 	u32 recvd, pglen;
1314ac396128STrond Myklebust 	int status;
13151da177e4SLinus Torvalds 
13161da177e4SLinus Torvalds 	status = ntohl(*p++);
13171da177e4SLinus Torvalds 	/* Decode post_op_attrs */
13181da177e4SLinus Torvalds 	p = xdr_decode_post_op_attr(p, res->dir_attr);
13191da177e4SLinus Torvalds 	if (status)
1320856dff3dSBenny Halevy 		return nfs_stat_to_errno(status);
13211da177e4SLinus Torvalds 	/* Decode verifier cookie */
13221da177e4SLinus Torvalds 	if (res->verf) {
13231da177e4SLinus Torvalds 		res->verf[0] = *p++;
13241da177e4SLinus Torvalds 		res->verf[1] = *p++;
13251da177e4SLinus Torvalds 	} else {
13261da177e4SLinus Torvalds 		p += 2;
13271da177e4SLinus Torvalds 	}
13281da177e4SLinus Torvalds 
13291da177e4SLinus Torvalds 	hdrlen = (u8 *) p - (u8 *) iov->iov_base;
13301da177e4SLinus Torvalds 	if (iov->iov_len < hdrlen) {
1331fe82a183SChuck Lever 		dprintk("NFS: READDIR reply header overflowed:"
1332c957c526SChuck Lever 				"length %Zu > %Zu\n", hdrlen, iov->iov_len);
13331da177e4SLinus Torvalds 		return -errno_NFSERR_IO;
13341da177e4SLinus Torvalds 	} else if (iov->iov_len != hdrlen) {
13351da177e4SLinus Torvalds 		dprintk("NFS: READDIR header is short. iovec will be shifted.\n");
13361da177e4SLinus Torvalds 		xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen);
13371da177e4SLinus Torvalds 	}
13381da177e4SLinus Torvalds 
13391da177e4SLinus Torvalds 	pglen = rcvbuf->page_len;
13401da177e4SLinus Torvalds 	recvd = rcvbuf->len - hdrlen;
13411da177e4SLinus Torvalds 	if (pglen > recvd)
13421da177e4SLinus Torvalds 		pglen = recvd;
13431da177e4SLinus Torvalds 	page = rcvbuf->pages;
1344643f8111SJeff Layton 
1345ac396128STrond Myklebust 	return pglen;
13461da177e4SLinus Torvalds }
13471da177e4SLinus Torvalds 
13480dbb4c67SAl Viro __be32 *
134982f2e547SBryan Schumaker nfs3_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry, struct nfs_server *server, int plus)
13501da177e4SLinus Torvalds {
1351babddc72SBryan Schumaker 	__be32 *p;
13521da177e4SLinus Torvalds 	struct nfs_entry old = *entry;
13531da177e4SLinus Torvalds 
1354babddc72SBryan Schumaker 	p = xdr_inline_decode(xdr, 4);
1355babddc72SBryan Schumaker 	if (unlikely(!p))
1356babddc72SBryan Schumaker 		goto out_overflow;
1357babddc72SBryan Schumaker 	if (!ntohl(*p++)) {
1358babddc72SBryan Schumaker 		p = xdr_inline_decode(xdr, 4);
1359babddc72SBryan Schumaker 		if (unlikely(!p))
1360babddc72SBryan Schumaker 			goto out_overflow;
1361babddc72SBryan Schumaker 		if (!ntohl(*p++))
13621da177e4SLinus Torvalds 			return ERR_PTR(-EAGAIN);
13631da177e4SLinus Torvalds 		entry->eof = 1;
13641da177e4SLinus Torvalds 		return ERR_PTR(-EBADCOOKIE);
13651da177e4SLinus Torvalds 	}
13661da177e4SLinus Torvalds 
1367babddc72SBryan Schumaker 	p = xdr_inline_decode(xdr, 12);
1368babddc72SBryan Schumaker 	if (unlikely(!p))
1369babddc72SBryan Schumaker 		goto out_overflow;
13701da177e4SLinus Torvalds 	p = xdr_decode_hyper(p, &entry->ino);
13711da177e4SLinus Torvalds 	entry->len  = ntohl(*p++);
1372babddc72SBryan Schumaker 
1373babddc72SBryan Schumaker 	p = xdr_inline_decode(xdr, entry->len + 8);
1374babddc72SBryan Schumaker 	if (unlikely(!p))
1375babddc72SBryan Schumaker 		goto out_overflow;
13761da177e4SLinus Torvalds 	entry->name = (const char *) p;
13771da177e4SLinus Torvalds 	p += XDR_QUADLEN(entry->len);
13781da177e4SLinus Torvalds 	entry->prev_cookie = entry->cookie;
13791da177e4SLinus Torvalds 	p = xdr_decode_hyper(p, &entry->cookie);
13801da177e4SLinus Torvalds 
13810b26a0bfSTrond Myklebust 	entry->d_type = DT_UNKNOWN;
13821da177e4SLinus Torvalds 	if (plus) {
13831da177e4SLinus Torvalds 		entry->fattr->valid = 0;
1384babddc72SBryan Schumaker 		p = xdr_decode_post_op_attr_stream(xdr, entry->fattr);
1385babddc72SBryan Schumaker 		if (IS_ERR(p))
1386babddc72SBryan Schumaker 			goto out_overflow_exit;
13870b26a0bfSTrond Myklebust 		entry->d_type = nfs_umode_to_dtype(entry->fattr->mode);
13881da177e4SLinus Torvalds 		/* In fact, a post_op_fh3: */
1389babddc72SBryan Schumaker 		p = xdr_inline_decode(xdr, 4);
1390babddc72SBryan Schumaker 		if (unlikely(!p))
1391babddc72SBryan Schumaker 			goto out_overflow;
13921da177e4SLinus Torvalds 		if (*p++) {
1393babddc72SBryan Schumaker 			p = xdr_decode_fhandle_stream(xdr, entry->fh);
1394babddc72SBryan Schumaker 			if (IS_ERR(p))
1395babddc72SBryan Schumaker 				goto out_overflow_exit;
13961da177e4SLinus Torvalds 			/* Ugh -- server reply was truncated */
13971da177e4SLinus Torvalds 			if (p == NULL) {
13981da177e4SLinus Torvalds 				dprintk("NFS: FH truncated\n");
13991da177e4SLinus Torvalds 				*entry = old;
14001da177e4SLinus Torvalds 				return ERR_PTR(-EAGAIN);
14011da177e4SLinus Torvalds 			}
14021da177e4SLinus Torvalds 		} else
14031da177e4SLinus Torvalds 			memset((u8*)(entry->fh), 0, sizeof(*entry->fh));
14041da177e4SLinus Torvalds 	}
14051da177e4SLinus Torvalds 
1406babddc72SBryan Schumaker 	p = xdr_inline_peek(xdr, 8);
1407babddc72SBryan Schumaker 	if (p != NULL)
14081da177e4SLinus Torvalds 		entry->eof = !p[0] && p[1];
1409babddc72SBryan Schumaker 	else
1410babddc72SBryan Schumaker 		entry->eof = 0;
1411babddc72SBryan Schumaker 
14121da177e4SLinus Torvalds 	return p;
1413babddc72SBryan Schumaker 
1414babddc72SBryan Schumaker out_overflow:
1415babddc72SBryan Schumaker 	print_overflow_msg(__func__, xdr);
1416babddc72SBryan Schumaker out_overflow_exit:
1417463a376eSTrond Myklebust 	return ERR_PTR(-EAGAIN);
14181da177e4SLinus Torvalds }
14191da177e4SLinus Torvalds 
14201da177e4SLinus Torvalds /*
14211da177e4SLinus Torvalds  * Encode COMMIT arguments
14221da177e4SLinus Torvalds  */
14231da177e4SLinus Torvalds static int
1424d61005a6SAl Viro nfs3_xdr_commitargs(struct rpc_rqst *req, __be32 *p, struct nfs_writeargs *args)
14251da177e4SLinus Torvalds {
14261da177e4SLinus Torvalds 	p = xdr_encode_fhandle(p, args->fh);
14271da177e4SLinus Torvalds 	p = xdr_encode_hyper(p, args->offset);
14281da177e4SLinus Torvalds 	*p++ = htonl(args->count);
14291da177e4SLinus Torvalds 	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
14301da177e4SLinus Torvalds 	return 0;
14311da177e4SLinus Torvalds }
14321da177e4SLinus Torvalds 
1433d9c407b1SChuck Lever /*
1434d9c407b1SChuck Lever  * 3.3.21  COMMIT3args
1435d9c407b1SChuck Lever  *
1436d9c407b1SChuck Lever  *	struct COMMIT3args {
1437d9c407b1SChuck Lever  *		nfs_fh3		file;
1438d9c407b1SChuck Lever  *		offset3		offset;
1439d9c407b1SChuck Lever  *		count3		count;
1440d9c407b1SChuck Lever  *	};
1441d9c407b1SChuck Lever  */
1442d9c407b1SChuck Lever static void encode_commit3args(struct xdr_stream *xdr,
1443d9c407b1SChuck Lever 			       const struct nfs_writeargs *args)
1444d9c407b1SChuck Lever {
1445d9c407b1SChuck Lever 	__be32 *p;
1446d9c407b1SChuck Lever 
1447d9c407b1SChuck Lever 	encode_nfs_fh3(xdr, args->fh);
1448d9c407b1SChuck Lever 
1449d9c407b1SChuck Lever 	p = xdr_reserve_space(xdr, 8 + 4);
1450d9c407b1SChuck Lever 	p = xdr_encode_hyper(p, args->offset);
1451d9c407b1SChuck Lever 	*p = cpu_to_be32(args->count);
1452d9c407b1SChuck Lever }
1453d9c407b1SChuck Lever 
1454d9c407b1SChuck Lever static int nfs3_xdr_enc_commit3args(struct rpc_rqst *req, __be32 *p,
1455d9c407b1SChuck Lever 				    const struct nfs_writeargs *args)
1456d9c407b1SChuck Lever {
1457d9c407b1SChuck Lever 	struct xdr_stream xdr;
1458d9c407b1SChuck Lever 
1459d9c407b1SChuck Lever 	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1460d9c407b1SChuck Lever 	encode_commit3args(&xdr, args);
1461d9c407b1SChuck Lever 	return 0;
1462d9c407b1SChuck Lever }
1463d9c407b1SChuck Lever 
1464b7fa0554SAndreas Gruenbacher #ifdef CONFIG_NFS_V3_ACL
1465b7fa0554SAndreas Gruenbacher /*
1466b7fa0554SAndreas Gruenbacher  * Encode GETACL arguments
1467b7fa0554SAndreas Gruenbacher  */
1468b7fa0554SAndreas Gruenbacher static int
1469d61005a6SAl Viro nfs3_xdr_getaclargs(struct rpc_rqst *req, __be32 *p,
1470b7fa0554SAndreas Gruenbacher 		    struct nfs3_getaclargs *args)
1471b7fa0554SAndreas Gruenbacher {
1472a17c2153STrond Myklebust 	struct rpc_auth	*auth = req->rq_cred->cr_auth;
1473b7fa0554SAndreas Gruenbacher 	unsigned int replen;
1474b7fa0554SAndreas Gruenbacher 
1475b7fa0554SAndreas Gruenbacher 	p = xdr_encode_fhandle(p, args->fh);
1476b7fa0554SAndreas Gruenbacher 	*p++ = htonl(args->mask);
1477b7fa0554SAndreas Gruenbacher 	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
1478b7fa0554SAndreas Gruenbacher 
1479b7fa0554SAndreas Gruenbacher 	if (args->mask & (NFS_ACL | NFS_DFACL)) {
1480b7fa0554SAndreas Gruenbacher 		/* Inline the page array */
1481b7fa0554SAndreas Gruenbacher 		replen = (RPC_REPHDRSIZE + auth->au_rslack +
1482b7fa0554SAndreas Gruenbacher 			  ACL3_getaclres_sz) << 2;
1483b7fa0554SAndreas Gruenbacher 		xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, 0,
1484b7fa0554SAndreas Gruenbacher 				 NFSACL_MAXPAGES << PAGE_SHIFT);
1485b7fa0554SAndreas Gruenbacher 	}
1486b7fa0554SAndreas Gruenbacher 	return 0;
1487b7fa0554SAndreas Gruenbacher }
1488b7fa0554SAndreas Gruenbacher 
1489d9c407b1SChuck Lever static int nfs3_xdr_enc_getacl3args(struct rpc_rqst *req, __be32 *p,
1490d9c407b1SChuck Lever 				    const struct nfs3_getaclargs *args)
1491d9c407b1SChuck Lever {
1492d9c407b1SChuck Lever 	struct xdr_stream xdr;
1493d9c407b1SChuck Lever 
1494d9c407b1SChuck Lever 	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1495d9c407b1SChuck Lever 	encode_nfs_fh3(&xdr, args->fh);
1496d9c407b1SChuck Lever 	encode_uint32(&xdr, args->mask);
1497d9c407b1SChuck Lever 	if (args->mask & (NFS_ACL | NFS_DFACL))
1498d9c407b1SChuck Lever 		prepare_reply_buffer(req, args->pages, 0,
1499d9c407b1SChuck Lever 					NFSACL_MAXPAGES << PAGE_SHIFT,
1500d9c407b1SChuck Lever 					ACL3_getaclres_sz);
1501d9c407b1SChuck Lever 	return 0;
1502d9c407b1SChuck Lever }
1503d9c407b1SChuck Lever 
1504b7fa0554SAndreas Gruenbacher /*
1505b7fa0554SAndreas Gruenbacher  * Encode SETACL arguments
1506b7fa0554SAndreas Gruenbacher  */
1507b7fa0554SAndreas Gruenbacher static int
1508d61005a6SAl Viro nfs3_xdr_setaclargs(struct rpc_rqst *req, __be32 *p,
1509b7fa0554SAndreas Gruenbacher                    struct nfs3_setaclargs *args)
1510b7fa0554SAndreas Gruenbacher {
1511b7fa0554SAndreas Gruenbacher 	struct xdr_buf *buf = &req->rq_snd_buf;
1512ae46141fSTrond Myklebust 	unsigned int base;
1513ae46141fSTrond Myklebust 	int err;
1514b7fa0554SAndreas Gruenbacher 
1515b7fa0554SAndreas Gruenbacher 	p = xdr_encode_fhandle(p, NFS_FH(args->inode));
1516b7fa0554SAndreas Gruenbacher 	*p++ = htonl(args->mask);
1517ae46141fSTrond Myklebust 	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
1518ae46141fSTrond Myklebust 	base = req->rq_slen;
1519b7fa0554SAndreas Gruenbacher 
1520ae46141fSTrond Myklebust 	if (args->npages != 0)
1521ae46141fSTrond Myklebust 		xdr_encode_pages(buf, args->pages, 0, args->len);
1522ae46141fSTrond Myklebust 	else
152383404372STrond Myklebust 		req->rq_slen = xdr_adjust_iovec(req->rq_svec,
152483404372STrond Myklebust 				p + XDR_QUADLEN(args->len));
1525b7fa0554SAndreas Gruenbacher 
1526b7fa0554SAndreas Gruenbacher 	err = nfsacl_encode(buf, base, args->inode,
1527b7fa0554SAndreas Gruenbacher 			    (args->mask & NFS_ACL) ?
1528b7fa0554SAndreas Gruenbacher 			    args->acl_access : NULL, 1, 0);
1529b7fa0554SAndreas Gruenbacher 	if (err > 0)
1530b7fa0554SAndreas Gruenbacher 		err = nfsacl_encode(buf, base + err, args->inode,
1531b7fa0554SAndreas Gruenbacher 				    (args->mask & NFS_DFACL) ?
1532b7fa0554SAndreas Gruenbacher 				    args->acl_default : NULL, 1,
1533b7fa0554SAndreas Gruenbacher 				    NFS_ACL_DEFAULT);
1534b7fa0554SAndreas Gruenbacher 	return (err > 0) ? 0 : err;
1535b7fa0554SAndreas Gruenbacher }
1536d9c407b1SChuck Lever 
1537d9c407b1SChuck Lever static int nfs3_xdr_enc_setacl3args(struct rpc_rqst *req, __be32 *p,
1538d9c407b1SChuck Lever 				    const struct nfs3_setaclargs *args)
1539d9c407b1SChuck Lever {
1540d9c407b1SChuck Lever 	struct xdr_stream xdr;
1541d9c407b1SChuck Lever 	unsigned int base;
1542d9c407b1SChuck Lever 	int error;
1543d9c407b1SChuck Lever 
1544d9c407b1SChuck Lever 	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1545d9c407b1SChuck Lever 	encode_nfs_fh3(&xdr, NFS_FH(args->inode));
1546d9c407b1SChuck Lever 	encode_uint32(&xdr, args->mask);
1547d9c407b1SChuck Lever 	if (args->npages != 0)
1548d9c407b1SChuck Lever 		xdr_write_pages(&xdr, args->pages, 0, args->len);
1549d9c407b1SChuck Lever 
1550d9c407b1SChuck Lever 	base = req->rq_slen;
1551d9c407b1SChuck Lever 	error = nfsacl_encode(xdr.buf, base, args->inode,
1552d9c407b1SChuck Lever 			    (args->mask & NFS_ACL) ?
1553d9c407b1SChuck Lever 			    args->acl_access : NULL, 1, 0);
1554d9c407b1SChuck Lever 	BUG_ON(error < 0);
1555d9c407b1SChuck Lever 	error = nfsacl_encode(xdr.buf, base + error, args->inode,
1556d9c407b1SChuck Lever 			    (args->mask & NFS_DFACL) ?
1557d9c407b1SChuck Lever 			    args->acl_default : NULL, 1,
1558d9c407b1SChuck Lever 			    NFS_ACL_DEFAULT);
1559d9c407b1SChuck Lever 	BUG_ON(error < 0);
1560d9c407b1SChuck Lever 	return 0;
1561d9c407b1SChuck Lever }
1562d9c407b1SChuck Lever 
1563b7fa0554SAndreas Gruenbacher #endif  /* CONFIG_NFS_V3_ACL */
1564b7fa0554SAndreas Gruenbacher 
15651da177e4SLinus Torvalds /*
15661da177e4SLinus Torvalds  * NFS XDR decode functions
15671da177e4SLinus Torvalds  */
15681da177e4SLinus Torvalds 
15691da177e4SLinus Torvalds /*
15701da177e4SLinus Torvalds  * Decode attrstat reply.
15711da177e4SLinus Torvalds  */
15721da177e4SLinus Torvalds static int
1573d61005a6SAl Viro nfs3_xdr_attrstat(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
15741da177e4SLinus Torvalds {
15751da177e4SLinus Torvalds 	int	status;
15761da177e4SLinus Torvalds 
15771da177e4SLinus Torvalds 	if ((status = ntohl(*p++)))
1578856dff3dSBenny Halevy 		return nfs_stat_to_errno(status);
15791da177e4SLinus Torvalds 	xdr_decode_fattr(p, fattr);
15801da177e4SLinus Torvalds 	return 0;
15811da177e4SLinus Torvalds }
15821da177e4SLinus Torvalds 
15831da177e4SLinus Torvalds /*
15841da177e4SLinus Torvalds  * Decode status+wcc_data reply
15851da177e4SLinus Torvalds  * SATTR, REMOVE, RMDIR
15861da177e4SLinus Torvalds  */
15871da177e4SLinus Torvalds static int
1588d61005a6SAl Viro nfs3_xdr_wccstat(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
15891da177e4SLinus Torvalds {
15901da177e4SLinus Torvalds 	int	status;
15911da177e4SLinus Torvalds 
15921da177e4SLinus Torvalds 	if ((status = ntohl(*p++)))
1593856dff3dSBenny Halevy 		status = nfs_stat_to_errno(status);
15941da177e4SLinus Torvalds 	xdr_decode_wcc_data(p, fattr);
15951da177e4SLinus Torvalds 	return status;
15961da177e4SLinus Torvalds }
15971da177e4SLinus Torvalds 
15984fdc17b2STrond Myklebust static int
15994fdc17b2STrond Myklebust nfs3_xdr_removeres(struct rpc_rqst *req, __be32 *p, struct nfs_removeres *res)
16004fdc17b2STrond Myklebust {
1601d346890bSTrond Myklebust 	return nfs3_xdr_wccstat(req, p, res->dir_attr);
16024fdc17b2STrond Myklebust }
16034fdc17b2STrond Myklebust 
16041da177e4SLinus Torvalds /*
16051da177e4SLinus Torvalds  * Decode LOOKUP reply
16061da177e4SLinus Torvalds  */
16071da177e4SLinus Torvalds static int
1608d61005a6SAl Viro nfs3_xdr_lookupres(struct rpc_rqst *req, __be32 *p, struct nfs3_diropres *res)
16091da177e4SLinus Torvalds {
16101da177e4SLinus Torvalds 	int	status;
16111da177e4SLinus Torvalds 
16121da177e4SLinus Torvalds 	if ((status = ntohl(*p++))) {
1613856dff3dSBenny Halevy 		status = nfs_stat_to_errno(status);
16141da177e4SLinus Torvalds 	} else {
16151da177e4SLinus Torvalds 		if (!(p = xdr_decode_fhandle(p, res->fh)))
16161da177e4SLinus Torvalds 			return -errno_NFSERR_IO;
16171da177e4SLinus Torvalds 		p = xdr_decode_post_op_attr(p, res->fattr);
16181da177e4SLinus Torvalds 	}
16191da177e4SLinus Torvalds 	xdr_decode_post_op_attr(p, res->dir_attr);
16201da177e4SLinus Torvalds 	return status;
16211da177e4SLinus Torvalds }
16221da177e4SLinus Torvalds 
16231da177e4SLinus Torvalds /*
16241da177e4SLinus Torvalds  * Decode ACCESS reply
16251da177e4SLinus Torvalds  */
16261da177e4SLinus Torvalds static int
1627d61005a6SAl Viro nfs3_xdr_accessres(struct rpc_rqst *req, __be32 *p, struct nfs3_accessres *res)
16281da177e4SLinus Torvalds {
16291da177e4SLinus Torvalds 	int	status = ntohl(*p++);
16301da177e4SLinus Torvalds 
16311da177e4SLinus Torvalds 	p = xdr_decode_post_op_attr(p, res->fattr);
16321da177e4SLinus Torvalds 	if (status)
1633856dff3dSBenny Halevy 		return nfs_stat_to_errno(status);
16341da177e4SLinus Torvalds 	res->access = ntohl(*p++);
16351da177e4SLinus Torvalds 	return 0;
16361da177e4SLinus Torvalds }
16371da177e4SLinus Torvalds 
16381da177e4SLinus Torvalds static int
1639d61005a6SAl Viro nfs3_xdr_readlinkargs(struct rpc_rqst *req, __be32 *p, struct nfs3_readlinkargs *args)
16401da177e4SLinus Torvalds {
1641a17c2153STrond Myklebust 	struct rpc_auth	*auth = req->rq_cred->cr_auth;
16421da177e4SLinus Torvalds 	unsigned int replen;
16431da177e4SLinus Torvalds 
16441da177e4SLinus Torvalds 	p = xdr_encode_fhandle(p, args->fh);
16451da177e4SLinus Torvalds 	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
16461da177e4SLinus Torvalds 
16471da177e4SLinus Torvalds 	/* Inline the page array */
16481da177e4SLinus Torvalds 	replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS3_readlinkres_sz) << 2;
16491da177e4SLinus Torvalds 	xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, args->pgbase, args->pglen);
16501da177e4SLinus Torvalds 	return 0;
16511da177e4SLinus Torvalds }
16521da177e4SLinus Torvalds 
16531da177e4SLinus Torvalds /*
16541da177e4SLinus Torvalds  * Decode READLINK reply
16551da177e4SLinus Torvalds  */
16561da177e4SLinus Torvalds static int
1657d61005a6SAl Viro nfs3_xdr_readlinkres(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
16581da177e4SLinus Torvalds {
16591da177e4SLinus Torvalds 	struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
16601da177e4SLinus Torvalds 	struct kvec *iov = rcvbuf->head;
1661c957c526SChuck Lever 	size_t hdrlen;
1662c957c526SChuck Lever 	u32 len, recvd;
16631da177e4SLinus Torvalds 	int	status;
16641da177e4SLinus Torvalds 
16651da177e4SLinus Torvalds 	status = ntohl(*p++);
16661da177e4SLinus Torvalds 	p = xdr_decode_post_op_attr(p, fattr);
16671da177e4SLinus Torvalds 
16681da177e4SLinus Torvalds 	if (status != 0)
1669856dff3dSBenny Halevy 		return nfs_stat_to_errno(status);
16701da177e4SLinus Torvalds 
16711da177e4SLinus Torvalds 	/* Convert length of symlink */
16721da177e4SLinus Torvalds 	len = ntohl(*p++);
1673c957c526SChuck Lever 	if (len >= rcvbuf->page_len) {
1674fe82a183SChuck Lever 		dprintk("nfs: server returned giant symlink!\n");
16751da177e4SLinus Torvalds 		return -ENAMETOOLONG;
16761da177e4SLinus Torvalds 	}
16771da177e4SLinus Torvalds 
16781da177e4SLinus Torvalds 	hdrlen = (u8 *) p - (u8 *) iov->iov_base;
16791da177e4SLinus Torvalds 	if (iov->iov_len < hdrlen) {
1680fe82a183SChuck Lever 		dprintk("NFS: READLINK reply header overflowed:"
1681c957c526SChuck Lever 				"length %Zu > %Zu\n", hdrlen, iov->iov_len);
16821da177e4SLinus Torvalds 		return -errno_NFSERR_IO;
16831da177e4SLinus Torvalds 	} else if (iov->iov_len != hdrlen) {
1684fe82a183SChuck Lever 		dprintk("NFS: READLINK header is short. "
1685fe82a183SChuck Lever 			"iovec will be shifted.\n");
16861da177e4SLinus Torvalds 		xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen);
16871da177e4SLinus Torvalds 	}
16881da177e4SLinus Torvalds 	recvd = req->rq_rcv_buf.len - hdrlen;
16891da177e4SLinus Torvalds 	if (recvd < len) {
1690fe82a183SChuck Lever 		dprintk("NFS: server cheating in readlink reply: "
16911da177e4SLinus Torvalds 				"count %u > recvd %u\n", len, recvd);
16921da177e4SLinus Torvalds 		return -EIO;
16931da177e4SLinus Torvalds 	}
16941da177e4SLinus Torvalds 
1695b4687da7SChuck Lever 	xdr_terminate_string(rcvbuf, len);
16961da177e4SLinus Torvalds 	return 0;
16971da177e4SLinus Torvalds }
16981da177e4SLinus Torvalds 
16991da177e4SLinus Torvalds /*
17001da177e4SLinus Torvalds  * Decode READ reply
17011da177e4SLinus Torvalds  */
17021da177e4SLinus Torvalds static int
1703d61005a6SAl Viro nfs3_xdr_readres(struct rpc_rqst *req, __be32 *p, struct nfs_readres *res)
17041da177e4SLinus Torvalds {
17051da177e4SLinus Torvalds 	struct kvec *iov = req->rq_rcv_buf.head;
1706c957c526SChuck Lever 	size_t hdrlen;
1707c957c526SChuck Lever 	u32 count, ocount, recvd;
1708c957c526SChuck Lever 	int status;
17091da177e4SLinus Torvalds 
17101da177e4SLinus Torvalds 	status = ntohl(*p++);
17111da177e4SLinus Torvalds 	p = xdr_decode_post_op_attr(p, res->fattr);
17121da177e4SLinus Torvalds 
17131da177e4SLinus Torvalds 	if (status != 0)
1714856dff3dSBenny Halevy 		return nfs_stat_to_errno(status);
17151da177e4SLinus Torvalds 
1716c957c526SChuck Lever 	/* Decode reply count and EOF flag. NFSv3 is somewhat redundant
17171da177e4SLinus Torvalds 	 * in that it puts the count both in the res struct and in the
17181da177e4SLinus Torvalds 	 * opaque data count. */
17191da177e4SLinus Torvalds 	count    = ntohl(*p++);
17201da177e4SLinus Torvalds 	res->eof = ntohl(*p++);
17211da177e4SLinus Torvalds 	ocount   = ntohl(*p++);
17221da177e4SLinus Torvalds 
17231da177e4SLinus Torvalds 	if (ocount != count) {
1724fe82a183SChuck Lever 		dprintk("NFS: READ count doesn't match RPC opaque count.\n");
17251da177e4SLinus Torvalds 		return -errno_NFSERR_IO;
17261da177e4SLinus Torvalds 	}
17271da177e4SLinus Torvalds 
17281da177e4SLinus Torvalds 	hdrlen = (u8 *) p - (u8 *) iov->iov_base;
17291da177e4SLinus Torvalds 	if (iov->iov_len < hdrlen) {
1730fe82a183SChuck Lever 		dprintk("NFS: READ reply header overflowed:"
1731c957c526SChuck Lever 				"length %Zu > %Zu\n", hdrlen, iov->iov_len);
17321da177e4SLinus Torvalds        		return -errno_NFSERR_IO;
17331da177e4SLinus Torvalds 	} else if (iov->iov_len != hdrlen) {
17341da177e4SLinus Torvalds 		dprintk("NFS: READ header is short. iovec will be shifted.\n");
17351da177e4SLinus Torvalds 		xdr_shift_buf(&req->rq_rcv_buf, iov->iov_len - hdrlen);
17361da177e4SLinus Torvalds 	}
17371da177e4SLinus Torvalds 
17381da177e4SLinus Torvalds 	recvd = req->rq_rcv_buf.len - hdrlen;
17391da177e4SLinus Torvalds 	if (count > recvd) {
1740fe82a183SChuck Lever 		dprintk("NFS: server cheating in read reply: "
1741c957c526SChuck Lever 			"count %u > recvd %u\n", count, recvd);
17421da177e4SLinus Torvalds 		count = recvd;
17431da177e4SLinus Torvalds 		res->eof = 0;
17441da177e4SLinus Torvalds 	}
17451da177e4SLinus Torvalds 
17461da177e4SLinus Torvalds 	if (count < res->count)
17471da177e4SLinus Torvalds 		res->count = count;
17481da177e4SLinus Torvalds 
17491da177e4SLinus Torvalds 	return count;
17501da177e4SLinus Torvalds }
17511da177e4SLinus Torvalds 
17521da177e4SLinus Torvalds /*
17531da177e4SLinus Torvalds  * Decode WRITE response
17541da177e4SLinus Torvalds  */
17551da177e4SLinus Torvalds static int
1756d61005a6SAl Viro nfs3_xdr_writeres(struct rpc_rqst *req, __be32 *p, struct nfs_writeres *res)
17571da177e4SLinus Torvalds {
17581da177e4SLinus Torvalds 	int	status;
17591da177e4SLinus Torvalds 
17601da177e4SLinus Torvalds 	status = ntohl(*p++);
17611da177e4SLinus Torvalds 	p = xdr_decode_wcc_data(p, res->fattr);
17621da177e4SLinus Torvalds 
17631da177e4SLinus Torvalds 	if (status != 0)
1764856dff3dSBenny Halevy 		return nfs_stat_to_errno(status);
17651da177e4SLinus Torvalds 
17661da177e4SLinus Torvalds 	res->count = ntohl(*p++);
17671da177e4SLinus Torvalds 	res->verf->committed = (enum nfs3_stable_how)ntohl(*p++);
17681da177e4SLinus Torvalds 	res->verf->verifier[0] = *p++;
17691da177e4SLinus Torvalds 	res->verf->verifier[1] = *p++;
17701da177e4SLinus Torvalds 
17711da177e4SLinus Torvalds 	return res->count;
17721da177e4SLinus Torvalds }
17731da177e4SLinus Torvalds 
17741da177e4SLinus Torvalds /*
17751da177e4SLinus Torvalds  * Decode a CREATE response
17761da177e4SLinus Torvalds  */
17771da177e4SLinus Torvalds static int
1778d61005a6SAl Viro nfs3_xdr_createres(struct rpc_rqst *req, __be32 *p, struct nfs3_diropres *res)
17791da177e4SLinus Torvalds {
17801da177e4SLinus Torvalds 	int	status;
17811da177e4SLinus Torvalds 
17821da177e4SLinus Torvalds 	status = ntohl(*p++);
17831da177e4SLinus Torvalds 	if (status == 0) {
17841da177e4SLinus Torvalds 		if (*p++) {
17851da177e4SLinus Torvalds 			if (!(p = xdr_decode_fhandle(p, res->fh)))
17861da177e4SLinus Torvalds 				return -errno_NFSERR_IO;
17871da177e4SLinus Torvalds 			p = xdr_decode_post_op_attr(p, res->fattr);
17881da177e4SLinus Torvalds 		} else {
17891da177e4SLinus Torvalds 			memset(res->fh, 0, sizeof(*res->fh));
17901da177e4SLinus Torvalds 			/* Do decode post_op_attr but set it to NULL */
17911da177e4SLinus Torvalds 			p = xdr_decode_post_op_attr(p, res->fattr);
17921da177e4SLinus Torvalds 			res->fattr->valid = 0;
17931da177e4SLinus Torvalds 		}
17941da177e4SLinus Torvalds 	} else {
1795856dff3dSBenny Halevy 		status = nfs_stat_to_errno(status);
17961da177e4SLinus Torvalds 	}
17971da177e4SLinus Torvalds 	p = xdr_decode_wcc_data(p, res->dir_attr);
17981da177e4SLinus Torvalds 	return status;
17991da177e4SLinus Torvalds }
18001da177e4SLinus Torvalds 
18011da177e4SLinus Torvalds /*
18021da177e4SLinus Torvalds  * Decode RENAME reply
18031da177e4SLinus Torvalds  */
18041da177e4SLinus Torvalds static int
1805e8582a8bSJeff Layton nfs3_xdr_renameres(struct rpc_rqst *req, __be32 *p, struct nfs_renameres *res)
18061da177e4SLinus Torvalds {
18071da177e4SLinus Torvalds 	int	status;
18081da177e4SLinus Torvalds 
18091da177e4SLinus Torvalds 	if ((status = ntohl(*p++)) != 0)
1810856dff3dSBenny Halevy 		status = nfs_stat_to_errno(status);
1811e8582a8bSJeff Layton 	p = xdr_decode_wcc_data(p, res->old_fattr);
1812e8582a8bSJeff Layton 	p = xdr_decode_wcc_data(p, res->new_fattr);
18131da177e4SLinus Torvalds 	return status;
18141da177e4SLinus Torvalds }
18151da177e4SLinus Torvalds 
18161da177e4SLinus Torvalds /*
18171da177e4SLinus Torvalds  * Decode LINK reply
18181da177e4SLinus Torvalds  */
18191da177e4SLinus Torvalds static int
1820d61005a6SAl Viro nfs3_xdr_linkres(struct rpc_rqst *req, __be32 *p, struct nfs3_linkres *res)
18211da177e4SLinus Torvalds {
18221da177e4SLinus Torvalds 	int	status;
18231da177e4SLinus Torvalds 
18241da177e4SLinus Torvalds 	if ((status = ntohl(*p++)) != 0)
1825856dff3dSBenny Halevy 		status = nfs_stat_to_errno(status);
18261da177e4SLinus Torvalds 	p = xdr_decode_post_op_attr(p, res->fattr);
18271da177e4SLinus Torvalds 	p = xdr_decode_wcc_data(p, res->dir_attr);
18281da177e4SLinus Torvalds 	return status;
18291da177e4SLinus Torvalds }
18301da177e4SLinus Torvalds 
18311da177e4SLinus Torvalds /*
18321da177e4SLinus Torvalds  * Decode FSSTAT reply
18331da177e4SLinus Torvalds  */
18341da177e4SLinus Torvalds static int
1835d61005a6SAl Viro nfs3_xdr_fsstatres(struct rpc_rqst *req, __be32 *p, struct nfs_fsstat *res)
18361da177e4SLinus Torvalds {
18371da177e4SLinus Torvalds 	int		status;
18381da177e4SLinus Torvalds 
18391da177e4SLinus Torvalds 	status = ntohl(*p++);
18401da177e4SLinus Torvalds 
18411da177e4SLinus Torvalds 	p = xdr_decode_post_op_attr(p, res->fattr);
18421da177e4SLinus Torvalds 	if (status != 0)
1843856dff3dSBenny Halevy 		return nfs_stat_to_errno(status);
18441da177e4SLinus Torvalds 
18451da177e4SLinus Torvalds 	p = xdr_decode_hyper(p, &res->tbytes);
18461da177e4SLinus Torvalds 	p = xdr_decode_hyper(p, &res->fbytes);
18471da177e4SLinus Torvalds 	p = xdr_decode_hyper(p, &res->abytes);
18481da177e4SLinus Torvalds 	p = xdr_decode_hyper(p, &res->tfiles);
18491da177e4SLinus Torvalds 	p = xdr_decode_hyper(p, &res->ffiles);
18501da177e4SLinus Torvalds 	p = xdr_decode_hyper(p, &res->afiles);
18511da177e4SLinus Torvalds 
18521da177e4SLinus Torvalds 	/* ignore invarsec */
18531da177e4SLinus Torvalds 	return 0;
18541da177e4SLinus Torvalds }
18551da177e4SLinus Torvalds 
18561da177e4SLinus Torvalds /*
18571da177e4SLinus Torvalds  * Decode FSINFO reply
18581da177e4SLinus Torvalds  */
18591da177e4SLinus Torvalds static int
1860d61005a6SAl Viro nfs3_xdr_fsinfores(struct rpc_rqst *req, __be32 *p, struct nfs_fsinfo *res)
18611da177e4SLinus Torvalds {
18621da177e4SLinus Torvalds 	int		status;
18631da177e4SLinus Torvalds 
18641da177e4SLinus Torvalds 	status = ntohl(*p++);
18651da177e4SLinus Torvalds 
18661da177e4SLinus Torvalds 	p = xdr_decode_post_op_attr(p, res->fattr);
18671da177e4SLinus Torvalds 	if (status != 0)
1868856dff3dSBenny Halevy 		return nfs_stat_to_errno(status);
18691da177e4SLinus Torvalds 
18701da177e4SLinus Torvalds 	res->rtmax  = ntohl(*p++);
18711da177e4SLinus Torvalds 	res->rtpref = ntohl(*p++);
18721da177e4SLinus Torvalds 	res->rtmult = ntohl(*p++);
18731da177e4SLinus Torvalds 	res->wtmax  = ntohl(*p++);
18741da177e4SLinus Torvalds 	res->wtpref = ntohl(*p++);
18751da177e4SLinus Torvalds 	res->wtmult = ntohl(*p++);
18761da177e4SLinus Torvalds 	res->dtpref = ntohl(*p++);
18771da177e4SLinus Torvalds 	p = xdr_decode_hyper(p, &res->maxfilesize);
18786b96724eSRicardo Labiaga 	p = xdr_decode_time3(p, &res->time_delta);
18791da177e4SLinus Torvalds 
18806b96724eSRicardo Labiaga 	/* ignore properties */
18811da177e4SLinus Torvalds 	res->lease_time = 0;
18821da177e4SLinus Torvalds 	return 0;
18831da177e4SLinus Torvalds }
18841da177e4SLinus Torvalds 
18851da177e4SLinus Torvalds /*
18861da177e4SLinus Torvalds  * Decode PATHCONF reply
18871da177e4SLinus Torvalds  */
18881da177e4SLinus Torvalds static int
1889d61005a6SAl Viro nfs3_xdr_pathconfres(struct rpc_rqst *req, __be32 *p, struct nfs_pathconf *res)
18901da177e4SLinus Torvalds {
18911da177e4SLinus Torvalds 	int		status;
18921da177e4SLinus Torvalds 
18931da177e4SLinus Torvalds 	status = ntohl(*p++);
18941da177e4SLinus Torvalds 
18951da177e4SLinus Torvalds 	p = xdr_decode_post_op_attr(p, res->fattr);
18961da177e4SLinus Torvalds 	if (status != 0)
1897856dff3dSBenny Halevy 		return nfs_stat_to_errno(status);
18981da177e4SLinus Torvalds 	res->max_link = ntohl(*p++);
18991da177e4SLinus Torvalds 	res->max_namelen = ntohl(*p++);
19001da177e4SLinus Torvalds 
19011da177e4SLinus Torvalds 	/* ignore remaining fields */
19021da177e4SLinus Torvalds 	return 0;
19031da177e4SLinus Torvalds }
19041da177e4SLinus Torvalds 
19051da177e4SLinus Torvalds /*
19061da177e4SLinus Torvalds  * Decode COMMIT reply
19071da177e4SLinus Torvalds  */
19081da177e4SLinus Torvalds static int
1909d61005a6SAl Viro nfs3_xdr_commitres(struct rpc_rqst *req, __be32 *p, struct nfs_writeres *res)
19101da177e4SLinus Torvalds {
19111da177e4SLinus Torvalds 	int		status;
19121da177e4SLinus Torvalds 
19131da177e4SLinus Torvalds 	status = ntohl(*p++);
19141da177e4SLinus Torvalds 	p = xdr_decode_wcc_data(p, res->fattr);
19151da177e4SLinus Torvalds 	if (status != 0)
1916856dff3dSBenny Halevy 		return nfs_stat_to_errno(status);
19171da177e4SLinus Torvalds 
19181da177e4SLinus Torvalds 	res->verf->verifier[0] = *p++;
19191da177e4SLinus Torvalds 	res->verf->verifier[1] = *p++;
19201da177e4SLinus Torvalds 	return 0;
19211da177e4SLinus Torvalds }
19221da177e4SLinus Torvalds 
1923b7fa0554SAndreas Gruenbacher #ifdef CONFIG_NFS_V3_ACL
1924b7fa0554SAndreas Gruenbacher /*
1925b7fa0554SAndreas Gruenbacher  * Decode GETACL reply
1926b7fa0554SAndreas Gruenbacher  */
1927b7fa0554SAndreas Gruenbacher static int
1928d61005a6SAl Viro nfs3_xdr_getaclres(struct rpc_rqst *req, __be32 *p,
1929b7fa0554SAndreas Gruenbacher 		   struct nfs3_getaclres *res)
1930b7fa0554SAndreas Gruenbacher {
1931b7fa0554SAndreas Gruenbacher 	struct xdr_buf *buf = &req->rq_rcv_buf;
1932b7fa0554SAndreas Gruenbacher 	int status = ntohl(*p++);
1933b7fa0554SAndreas Gruenbacher 	struct posix_acl **acl;
1934b7fa0554SAndreas Gruenbacher 	unsigned int *aclcnt;
1935b7fa0554SAndreas Gruenbacher 	int err, base;
1936b7fa0554SAndreas Gruenbacher 
1937b7fa0554SAndreas Gruenbacher 	if (status != 0)
1938856dff3dSBenny Halevy 		return nfs_stat_to_errno(status);
1939b7fa0554SAndreas Gruenbacher 	p = xdr_decode_post_op_attr(p, res->fattr);
1940b7fa0554SAndreas Gruenbacher 	res->mask = ntohl(*p++);
1941b7fa0554SAndreas Gruenbacher 	if (res->mask & ~(NFS_ACL|NFS_ACLCNT|NFS_DFACL|NFS_DFACLCNT))
1942b7fa0554SAndreas Gruenbacher 		return -EINVAL;
1943b7fa0554SAndreas Gruenbacher 	base = (char *)p - (char *)req->rq_rcv_buf.head->iov_base;
1944b7fa0554SAndreas Gruenbacher 
1945b7fa0554SAndreas Gruenbacher 	acl = (res->mask & NFS_ACL) ? &res->acl_access : NULL;
1946b7fa0554SAndreas Gruenbacher 	aclcnt = (res->mask & NFS_ACLCNT) ? &res->acl_access_count : NULL;
1947b7fa0554SAndreas Gruenbacher 	err = nfsacl_decode(buf, base, aclcnt, acl);
1948b7fa0554SAndreas Gruenbacher 
1949b7fa0554SAndreas Gruenbacher 	acl = (res->mask & NFS_DFACL) ? &res->acl_default : NULL;
1950b7fa0554SAndreas Gruenbacher 	aclcnt = (res->mask & NFS_DFACLCNT) ? &res->acl_default_count : NULL;
1951b7fa0554SAndreas Gruenbacher 	if (err > 0)
1952b7fa0554SAndreas Gruenbacher 		err = nfsacl_decode(buf, base + err, aclcnt, acl);
1953b7fa0554SAndreas Gruenbacher 	return (err > 0) ? 0 : err;
1954b7fa0554SAndreas Gruenbacher }
1955b7fa0554SAndreas Gruenbacher 
1956b7fa0554SAndreas Gruenbacher /*
1957b7fa0554SAndreas Gruenbacher  * Decode setacl reply.
1958b7fa0554SAndreas Gruenbacher  */
1959b7fa0554SAndreas Gruenbacher static int
1960d61005a6SAl Viro nfs3_xdr_setaclres(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
1961b7fa0554SAndreas Gruenbacher {
1962b7fa0554SAndreas Gruenbacher 	int status = ntohl(*p++);
1963b7fa0554SAndreas Gruenbacher 
1964b7fa0554SAndreas Gruenbacher 	if (status)
1965856dff3dSBenny Halevy 		return nfs_stat_to_errno(status);
1966b7fa0554SAndreas Gruenbacher 	xdr_decode_post_op_attr(p, fattr);
1967b7fa0554SAndreas Gruenbacher 	return 0;
1968b7fa0554SAndreas Gruenbacher }
1969b7fa0554SAndreas Gruenbacher #endif  /* CONFIG_NFS_V3_ACL */
1970b7fa0554SAndreas Gruenbacher 
19711da177e4SLinus Torvalds #define PROC(proc, argtype, restype, timer)				\
19721da177e4SLinus Torvalds [NFS3PROC_##proc] = {							\
19731da177e4SLinus Torvalds 	.p_proc      = NFS3PROC_##proc,					\
1974ad96b5b5SChuck Lever 	.p_encode    = (kxdrproc_t)nfs3_xdr_enc_##argtype##3args,	\
19751da177e4SLinus Torvalds 	.p_decode    = (kxdrproc_t) nfs3_xdr_##restype,			\
1976ad96b5b5SChuck Lever 	.p_arglen    = NFS3_##argtype##args_sz,				\
19772bea90d4SChuck Lever 	.p_replen    = NFS3_##restype##_sz,				\
1978cc0175c1SChuck Lever 	.p_timer     = timer,						\
1979cc0175c1SChuck Lever 	.p_statidx   = NFS3PROC_##proc,					\
1980cc0175c1SChuck Lever 	.p_name      = #proc,						\
19811da177e4SLinus Torvalds 	}
19821da177e4SLinus Torvalds 
19831da177e4SLinus Torvalds struct rpc_procinfo	nfs3_procedures[] = {
1984ad96b5b5SChuck Lever 	PROC(GETATTR,		getattr,	attrstat,	1),
1985ad96b5b5SChuck Lever 	PROC(SETATTR,		setattr,	wccstat,	0),
1986ad96b5b5SChuck Lever 	PROC(LOOKUP,		lookup,		lookupres,	2),
1987ad96b5b5SChuck Lever 	PROC(ACCESS,		access,		accessres,	1),
1988ad96b5b5SChuck Lever 	PROC(READLINK,		readlink,	readlinkres,	3),
1989ad96b5b5SChuck Lever 	PROC(READ,		read,		readres,	3),
1990ad96b5b5SChuck Lever 	PROC(WRITE,		write,		writeres,	4),
1991ad96b5b5SChuck Lever 	PROC(CREATE,		create,		createres,	0),
1992ad96b5b5SChuck Lever 	PROC(MKDIR,		mkdir,		createres,	0),
1993ad96b5b5SChuck Lever 	PROC(SYMLINK,		symlink,	createres,	0),
1994ad96b5b5SChuck Lever 	PROC(MKNOD,		mknod,		createres,	0),
1995ad96b5b5SChuck Lever 	PROC(REMOVE,		remove,		removeres,	0),
1996ad96b5b5SChuck Lever 	PROC(RMDIR,		lookup,		wccstat,	0),
1997ad96b5b5SChuck Lever 	PROC(RENAME,		rename,		renameres,	0),
1998ad96b5b5SChuck Lever 	PROC(LINK,		link,		linkres,	0),
1999ad96b5b5SChuck Lever 	PROC(READDIR,		readdir,	readdirres,	3),
2000ad96b5b5SChuck Lever 	PROC(READDIRPLUS,	readdirplus,	readdirres,	3),
2001ad96b5b5SChuck Lever 	PROC(FSSTAT,		getattr,	fsstatres,	0),
2002ad96b5b5SChuck Lever 	PROC(FSINFO,		getattr,	fsinfores,	0),
2003ad96b5b5SChuck Lever 	PROC(PATHCONF,		getattr,	pathconfres,	0),
2004ad96b5b5SChuck Lever 	PROC(COMMIT,		commit,		commitres,	5),
20051da177e4SLinus Torvalds };
20061da177e4SLinus Torvalds 
20071da177e4SLinus Torvalds struct rpc_version		nfs_version3 = {
20081da177e4SLinus Torvalds 	.number			= 3,
2009e8c96f8cSTobias Klauser 	.nrprocs		= ARRAY_SIZE(nfs3_procedures),
20101da177e4SLinus Torvalds 	.procs			= nfs3_procedures
20111da177e4SLinus Torvalds };
20121da177e4SLinus Torvalds 
2013b7fa0554SAndreas Gruenbacher #ifdef CONFIG_NFS_V3_ACL
2014b7fa0554SAndreas Gruenbacher static struct rpc_procinfo	nfs3_acl_procedures[] = {
2015b7fa0554SAndreas Gruenbacher 	[ACLPROC3_GETACL] = {
2016b7fa0554SAndreas Gruenbacher 		.p_proc = ACLPROC3_GETACL,
2017ad96b5b5SChuck Lever 		.p_encode = (kxdrproc_t)nfs3_xdr_enc_getacl3args,
2018b7fa0554SAndreas Gruenbacher 		.p_decode = (kxdrproc_t) nfs3_xdr_getaclres,
20192bea90d4SChuck Lever 		.p_arglen = ACL3_getaclargs_sz,
20202bea90d4SChuck Lever 		.p_replen = ACL3_getaclres_sz,
2021b7fa0554SAndreas Gruenbacher 		.p_timer = 1,
2022cc0175c1SChuck Lever 		.p_name = "GETACL",
2023b7fa0554SAndreas Gruenbacher 	},
2024b7fa0554SAndreas Gruenbacher 	[ACLPROC3_SETACL] = {
2025b7fa0554SAndreas Gruenbacher 		.p_proc = ACLPROC3_SETACL,
2026ad96b5b5SChuck Lever 		.p_encode = (kxdrproc_t)nfs3_xdr_enc_setacl3args,
2027b7fa0554SAndreas Gruenbacher 		.p_decode = (kxdrproc_t) nfs3_xdr_setaclres,
20282bea90d4SChuck Lever 		.p_arglen = ACL3_setaclargs_sz,
20292bea90d4SChuck Lever 		.p_replen = ACL3_setaclres_sz,
2030b7fa0554SAndreas Gruenbacher 		.p_timer = 0,
2031cc0175c1SChuck Lever 		.p_name = "SETACL",
2032b7fa0554SAndreas Gruenbacher 	},
2033b7fa0554SAndreas Gruenbacher };
2034b7fa0554SAndreas Gruenbacher 
2035b7fa0554SAndreas Gruenbacher struct rpc_version		nfsacl_version3 = {
2036b7fa0554SAndreas Gruenbacher 	.number			= 3,
2037b7fa0554SAndreas Gruenbacher 	.nrprocs		= sizeof(nfs3_acl_procedures)/
2038b7fa0554SAndreas Gruenbacher 				  sizeof(nfs3_acl_procedures[0]),
2039b7fa0554SAndreas Gruenbacher 	.procs			= nfs3_acl_procedures,
2040b7fa0554SAndreas Gruenbacher };
2041b7fa0554SAndreas Gruenbacher #endif  /* CONFIG_NFS_V3_ACL */
2042