xref: /openbmc/linux/fs/nfs/nfs3xdr.c (revision bf269551)
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_diropargs_sz	(NFS3_fh_sz+NFS3_filename_sz)
46ad96b5b5SChuck Lever 
47ad96b5b5SChuck Lever #define NFS3_getattrargs_sz	(NFS3_fh_sz)
48ad96b5b5SChuck Lever #define NFS3_setattrargs_sz	(NFS3_fh_sz+NFS3_sattr_sz+3)
49ad96b5b5SChuck Lever #define NFS3_lookupargs_sz	(NFS3_fh_sz+NFS3_filename_sz)
501da177e4SLinus Torvalds #define NFS3_accessargs_sz	(NFS3_fh_sz+1)
511da177e4SLinus Torvalds #define NFS3_readlinkargs_sz	(NFS3_fh_sz)
521da177e4SLinus Torvalds #define NFS3_readargs_sz	(NFS3_fh_sz+3)
531da177e4SLinus Torvalds #define NFS3_writeargs_sz	(NFS3_fh_sz+5)
541da177e4SLinus Torvalds #define NFS3_createargs_sz	(NFS3_diropargs_sz+NFS3_sattr_sz)
551da177e4SLinus Torvalds #define NFS3_mkdirargs_sz	(NFS3_diropargs_sz+NFS3_sattr_sz)
5694a6d753SChuck Lever #define NFS3_symlinkargs_sz	(NFS3_diropargs_sz+1+NFS3_sattr_sz)
571da177e4SLinus Torvalds #define NFS3_mknodargs_sz	(NFS3_diropargs_sz+2+NFS3_sattr_sz)
58ad96b5b5SChuck Lever #define NFS3_removeargs_sz	(NFS3_fh_sz+NFS3_filename_sz)
591da177e4SLinus Torvalds #define NFS3_renameargs_sz	(NFS3_diropargs_sz+NFS3_diropargs_sz)
601da177e4SLinus Torvalds #define NFS3_linkargs_sz		(NFS3_fh_sz+NFS3_diropargs_sz)
61d9c407b1SChuck Lever #define NFS3_readdirargs_sz	(NFS3_fh_sz+NFS3_cookieverf_sz+3)
62d9c407b1SChuck Lever #define NFS3_readdirplusargs_sz	(NFS3_fh_sz+NFS3_cookieverf_sz+4)
631da177e4SLinus Torvalds #define NFS3_commitargs_sz	(NFS3_fh_sz+3)
641da177e4SLinus Torvalds 
65f5fc3c50SChuck Lever #define NFS3_getattrres_sz	(1+NFS3_fattr_sz)
66f5fc3c50SChuck Lever #define NFS3_setattrres_sz	(1+NFS3_wcc_data_sz)
67f5fc3c50SChuck Lever #define NFS3_removeres_sz	(NFS3_setattrres_sz)
681da177e4SLinus Torvalds #define NFS3_lookupres_sz	(1+NFS3_fh_sz+(2 * NFS3_post_op_attr_sz))
691da177e4SLinus Torvalds #define NFS3_accessres_sz	(1+NFS3_post_op_attr_sz+1)
701da177e4SLinus Torvalds #define NFS3_readlinkres_sz	(1+NFS3_post_op_attr_sz+1)
711da177e4SLinus Torvalds #define NFS3_readres_sz		(1+NFS3_post_op_attr_sz+3)
721da177e4SLinus Torvalds #define NFS3_writeres_sz	(1+NFS3_wcc_data_sz+4)
731da177e4SLinus Torvalds #define NFS3_createres_sz	(1+NFS3_fh_sz+NFS3_post_op_attr_sz+NFS3_wcc_data_sz)
741da177e4SLinus Torvalds #define NFS3_renameres_sz	(1+(2 * NFS3_wcc_data_sz))
751da177e4SLinus Torvalds #define NFS3_linkres_sz		(1+NFS3_post_op_attr_sz+NFS3_wcc_data_sz)
761da177e4SLinus Torvalds #define NFS3_readdirres_sz	(1+NFS3_post_op_attr_sz+2)
771da177e4SLinus Torvalds #define NFS3_fsstatres_sz	(1+NFS3_post_op_attr_sz+13)
781da177e4SLinus Torvalds #define NFS3_fsinfores_sz	(1+NFS3_post_op_attr_sz+12)
791da177e4SLinus Torvalds #define NFS3_pathconfres_sz	(1+NFS3_post_op_attr_sz+6)
801da177e4SLinus Torvalds #define NFS3_commitres_sz	(1+NFS3_wcc_data_sz+2)
811da177e4SLinus Torvalds 
82b7fa0554SAndreas Gruenbacher #define ACL3_getaclargs_sz	(NFS3_fh_sz+1)
83ae46141fSTrond Myklebust #define ACL3_setaclargs_sz	(NFS3_fh_sz+1+ \
84ae46141fSTrond Myklebust 				XDR_QUADLEN(NFS_ACL_INLINE_BUFSIZE))
85ae46141fSTrond Myklebust #define ACL3_getaclres_sz	(1+NFS3_post_op_attr_sz+1+ \
86ae46141fSTrond Myklebust 				XDR_QUADLEN(NFS_ACL_INLINE_BUFSIZE))
87b7fa0554SAndreas Gruenbacher #define ACL3_setaclres_sz	(1+NFS3_post_op_attr_sz)
88b7fa0554SAndreas Gruenbacher 
891da177e4SLinus Torvalds /*
901da177e4SLinus Torvalds  * Map file type to S_IFMT bits
911da177e4SLinus Torvalds  */
92bca79478STrond Myklebust static const umode_t nfs_type2fmt[] = {
93bca79478STrond Myklebust 	[NF3BAD] = 0,
94bca79478STrond Myklebust 	[NF3REG] = S_IFREG,
95bca79478STrond Myklebust 	[NF3DIR] = S_IFDIR,
96bca79478STrond Myklebust 	[NF3BLK] = S_IFBLK,
97bca79478STrond Myklebust 	[NF3CHR] = S_IFCHR,
98bca79478STrond Myklebust 	[NF3LNK] = S_IFLNK,
99bca79478STrond Myklebust 	[NF3SOCK] = S_IFSOCK,
100bca79478STrond Myklebust 	[NF3FIFO] = S_IFIFO,
1011da177e4SLinus Torvalds };
1021da177e4SLinus Torvalds 
1031da177e4SLinus Torvalds /*
104d9c407b1SChuck Lever  * While encoding arguments, set up the reply buffer in advance to
105d9c407b1SChuck Lever  * receive reply data directly into the page cache.
106d9c407b1SChuck Lever  */
107d9c407b1SChuck Lever static void prepare_reply_buffer(struct rpc_rqst *req, struct page **pages,
108d9c407b1SChuck Lever 				 unsigned int base, unsigned int len,
109d9c407b1SChuck Lever 				 unsigned int bufsize)
110d9c407b1SChuck Lever {
111d9c407b1SChuck Lever 	struct rpc_auth	*auth = req->rq_cred->cr_auth;
112d9c407b1SChuck Lever 	unsigned int replen;
113d9c407b1SChuck Lever 
114d9c407b1SChuck Lever 	replen = RPC_REPHDRSIZE + auth->au_rslack + bufsize;
115d9c407b1SChuck Lever 	xdr_inline_pages(&req->rq_rcv_buf, replen << 2, pages, base, len);
116d9c407b1SChuck Lever }
117d9c407b1SChuck Lever 
118e4f93234SChuck Lever /*
119e4f93234SChuck Lever  * Handle decode buffer overflows out-of-line.
120e4f93234SChuck Lever  */
121e4f93234SChuck Lever static void print_overflow_msg(const char *func, const struct xdr_stream *xdr)
122e4f93234SChuck Lever {
123e4f93234SChuck Lever 	dprintk("NFS: %s prematurely hit the end of our receive buffer. "
124e4f93234SChuck Lever 		"Remaining buffer length is %tu words.\n",
125e4f93234SChuck Lever 		func, xdr->end - xdr->p);
126e4f93234SChuck Lever }
127e4f93234SChuck Lever 
128d9c407b1SChuck Lever 
129d9c407b1SChuck Lever /*
130d9c407b1SChuck Lever  * Encode/decode NFSv3 basic data types
131d9c407b1SChuck Lever  *
132d9c407b1SChuck Lever  * Basic NFSv3 data types are defined in section 2.5 of RFC 1813:
133d9c407b1SChuck Lever  * "NFS Version 3 Protocol Specification".
134d9c407b1SChuck Lever  *
135d9c407b1SChuck Lever  * Not all basic data types have their own encoding and decoding
136d9c407b1SChuck Lever  * functions.  For run-time efficiency, some data types are encoded
137d9c407b1SChuck Lever  * or decoded inline.
138d9c407b1SChuck Lever  */
139d9c407b1SChuck Lever 
140d9c407b1SChuck Lever static void encode_uint32(struct xdr_stream *xdr, u32 value)
141d9c407b1SChuck Lever {
142d9c407b1SChuck Lever 	__be32 *p = xdr_reserve_space(xdr, 4);
143d9c407b1SChuck Lever 	*p = cpu_to_be32(value);
144d9c407b1SChuck Lever }
145d9c407b1SChuck Lever 
146e4f93234SChuck Lever static int decode_uint32(struct xdr_stream *xdr, u32 *value)
147e4f93234SChuck Lever {
148e4f93234SChuck Lever 	__be32 *p;
149e4f93234SChuck Lever 
150e4f93234SChuck Lever 	p = xdr_inline_decode(xdr, 4);
151e4f93234SChuck Lever 	if (unlikely(p == NULL))
152e4f93234SChuck Lever 		goto out_overflow;
153e4f93234SChuck Lever 	*value = be32_to_cpup(p);
154e4f93234SChuck Lever 	return 0;
155e4f93234SChuck Lever out_overflow:
156e4f93234SChuck Lever 	print_overflow_msg(__func__, xdr);
157e4f93234SChuck Lever 	return -EIO;
158e4f93234SChuck Lever }
159e4f93234SChuck Lever 
160e4f93234SChuck Lever static int decode_uint64(struct xdr_stream *xdr, u64 *value)
161e4f93234SChuck Lever {
162e4f93234SChuck Lever 	__be32 *p;
163e4f93234SChuck Lever 
164e4f93234SChuck Lever 	p = xdr_inline_decode(xdr, 8);
165e4f93234SChuck Lever 	if (unlikely(p == NULL))
166e4f93234SChuck Lever 		goto out_overflow;
167e4f93234SChuck Lever 	xdr_decode_hyper(p, value);
168e4f93234SChuck Lever 	return 0;
169e4f93234SChuck Lever out_overflow:
170e4f93234SChuck Lever 	print_overflow_msg(__func__, xdr);
171e4f93234SChuck Lever 	return -EIO;
172e4f93234SChuck Lever }
173e4f93234SChuck Lever 
174e4f93234SChuck Lever /*
175e4f93234SChuck Lever  * fileid3
176e4f93234SChuck Lever  *
177e4f93234SChuck Lever  *	typedef uint64 fileid3;
178e4f93234SChuck Lever  */
179f6048709SChuck Lever static __be32 *xdr_decode_fileid3(__be32 *p, u64 *fileid)
180f6048709SChuck Lever {
181f6048709SChuck Lever 	return xdr_decode_hyper(p, fileid);
182f6048709SChuck Lever }
183f6048709SChuck Lever 
184e4f93234SChuck Lever static int decode_fileid3(struct xdr_stream *xdr, u64 *fileid)
185e4f93234SChuck Lever {
186e4f93234SChuck Lever 	return decode_uint64(xdr, fileid);
187e4f93234SChuck Lever }
188e4f93234SChuck Lever 
189d9c407b1SChuck Lever /*
190d9c407b1SChuck Lever  * filename3
191d9c407b1SChuck Lever  *
192d9c407b1SChuck Lever  *	typedef string filename3<>;
193d9c407b1SChuck Lever  */
194d9c407b1SChuck Lever static void encode_filename3(struct xdr_stream *xdr,
195d9c407b1SChuck Lever 			     const char *name, u32 length)
196d9c407b1SChuck Lever {
197d9c407b1SChuck Lever 	__be32 *p;
198d9c407b1SChuck Lever 
199d9c407b1SChuck Lever 	BUG_ON(length > NFS3_MAXNAMLEN);
200d9c407b1SChuck Lever 	p = xdr_reserve_space(xdr, 4 + length);
201d9c407b1SChuck Lever 	xdr_encode_opaque(p, name, length);
202d9c407b1SChuck Lever }
203d9c407b1SChuck Lever 
204e4f93234SChuck Lever static int decode_inline_filename3(struct xdr_stream *xdr,
205e4f93234SChuck Lever 				   const char **name, u32 *length)
206e4f93234SChuck Lever {
207e4f93234SChuck Lever 	__be32 *p;
208e4f93234SChuck Lever 	u32 count;
209e4f93234SChuck Lever 
210e4f93234SChuck Lever 	p = xdr_inline_decode(xdr, 4);
211e4f93234SChuck Lever 	if (unlikely(p == NULL))
212e4f93234SChuck Lever 		goto out_overflow;
213e4f93234SChuck Lever 	count = be32_to_cpup(p);
214e4f93234SChuck Lever 	if (count > NFS3_MAXNAMLEN)
215e4f93234SChuck Lever 		goto out_nametoolong;
216e4f93234SChuck Lever 	p = xdr_inline_decode(xdr, count);
217e4f93234SChuck Lever 	if (unlikely(p == NULL))
218e4f93234SChuck Lever 		goto out_overflow;
219e4f93234SChuck Lever 	*name = (const char *)p;
220e4f93234SChuck Lever 	*length = count;
221e4f93234SChuck Lever 	return 0;
222e4f93234SChuck Lever 
223e4f93234SChuck Lever out_nametoolong:
224e4f93234SChuck Lever 	dprintk("NFS: returned filename too long: %u\n", count);
225e4f93234SChuck Lever 	return -ENAMETOOLONG;
226e4f93234SChuck Lever out_overflow:
227e4f93234SChuck Lever 	print_overflow_msg(__func__, xdr);
228e4f93234SChuck Lever 	return -EIO;
229e4f93234SChuck Lever }
230e4f93234SChuck Lever 
231d9c407b1SChuck Lever /*
232d9c407b1SChuck Lever  * nfspath3
233d9c407b1SChuck Lever  *
234d9c407b1SChuck Lever  *	typedef string nfspath3<>;
235d9c407b1SChuck Lever  */
236d9c407b1SChuck Lever static void encode_nfspath3(struct xdr_stream *xdr, struct page **pages,
237d9c407b1SChuck Lever 			    const u32 length)
238d9c407b1SChuck Lever {
239d9c407b1SChuck Lever 	BUG_ON(length > NFS3_MAXPATHLEN);
240d9c407b1SChuck Lever 	encode_uint32(xdr, length);
241d9c407b1SChuck Lever 	xdr_write_pages(xdr, pages, 0, length);
242d9c407b1SChuck Lever }
243d9c407b1SChuck Lever 
244e4f93234SChuck Lever static int decode_nfspath3(struct xdr_stream *xdr)
245e4f93234SChuck Lever {
246e4f93234SChuck Lever 	u32 recvd, count;
247e4f93234SChuck Lever 	size_t hdrlen;
248e4f93234SChuck Lever 	__be32 *p;
249e4f93234SChuck Lever 
250e4f93234SChuck Lever 	p = xdr_inline_decode(xdr, 4);
251e4f93234SChuck Lever 	if (unlikely(p == NULL))
252e4f93234SChuck Lever 		goto out_overflow;
253e4f93234SChuck Lever 	count = be32_to_cpup(p);
254e4f93234SChuck Lever 	if (unlikely(count >= xdr->buf->page_len || count > NFS3_MAXPATHLEN))
255e4f93234SChuck Lever 		goto out_nametoolong;
256e4f93234SChuck Lever 	hdrlen = (u8 *)xdr->p - (u8 *)xdr->iov->iov_base;
257e4f93234SChuck Lever 	recvd = xdr->buf->len - hdrlen;
258e4f93234SChuck Lever 	if (unlikely(count > recvd))
259e4f93234SChuck Lever 		goto out_cheating;
260e4f93234SChuck Lever 
261e4f93234SChuck Lever 	xdr_read_pages(xdr, count);
262e4f93234SChuck Lever 	xdr_terminate_string(xdr->buf, count);
263e4f93234SChuck Lever 	return 0;
264e4f93234SChuck Lever 
265e4f93234SChuck Lever out_nametoolong:
266e4f93234SChuck Lever 	dprintk("NFS: returned pathname too long: %u\n", count);
267e4f93234SChuck Lever 	return -ENAMETOOLONG;
268e4f93234SChuck Lever out_cheating:
269e4f93234SChuck Lever 	dprintk("NFS: server cheating in pathname result: "
270e4f93234SChuck Lever 		"count %u > recvd %u\n", count, recvd);
271e4f93234SChuck Lever 	return -EIO;
272e4f93234SChuck Lever out_overflow:
273e4f93234SChuck Lever 	print_overflow_msg(__func__, xdr);
274e4f93234SChuck Lever 	return -EIO;
275e4f93234SChuck Lever }
276e4f93234SChuck Lever 
277d9c407b1SChuck Lever /*
278d9c407b1SChuck Lever  * cookie3
279d9c407b1SChuck Lever  *
280d9c407b1SChuck Lever  *	typedef uint64 cookie3
281d9c407b1SChuck Lever  */
282d9c407b1SChuck Lever static __be32 *xdr_encode_cookie3(__be32 *p, u64 cookie)
283d9c407b1SChuck Lever {
284d9c407b1SChuck Lever 	return xdr_encode_hyper(p, cookie);
285d9c407b1SChuck Lever }
286d9c407b1SChuck Lever 
287e4f93234SChuck Lever static int decode_cookie3(struct xdr_stream *xdr, u64 *cookie)
288e4f93234SChuck Lever {
289e4f93234SChuck Lever 	return decode_uint64(xdr, cookie);
290e4f93234SChuck Lever }
291e4f93234SChuck Lever 
292d9c407b1SChuck Lever /*
293d9c407b1SChuck Lever  * cookieverf3
294d9c407b1SChuck Lever  *
295d9c407b1SChuck Lever  *	typedef opaque cookieverf3[NFS3_COOKIEVERFSIZE];
296d9c407b1SChuck Lever  */
297d9c407b1SChuck Lever static __be32 *xdr_encode_cookieverf3(__be32 *p, const __be32 *verifier)
298d9c407b1SChuck Lever {
299d9c407b1SChuck Lever 	memcpy(p, verifier, NFS3_COOKIEVERFSIZE);
300d9c407b1SChuck Lever 	return p + XDR_QUADLEN(NFS3_COOKIEVERFSIZE);
301d9c407b1SChuck Lever }
302d9c407b1SChuck Lever 
303e4f93234SChuck Lever static int decode_cookieverf3(struct xdr_stream *xdr, __be32 *verifier)
304e4f93234SChuck Lever {
305e4f93234SChuck Lever 	__be32 *p;
306e4f93234SChuck Lever 
307e4f93234SChuck Lever 	p = xdr_inline_decode(xdr, NFS3_COOKIEVERFSIZE);
308e4f93234SChuck Lever 	if (unlikely(p == NULL))
309e4f93234SChuck Lever 		goto out_overflow;
310e4f93234SChuck Lever 	memcpy(verifier, p, NFS3_COOKIEVERFSIZE);
311e4f93234SChuck Lever 	return 0;
312e4f93234SChuck Lever out_overflow:
313e4f93234SChuck Lever 	print_overflow_msg(__func__, xdr);
314e4f93234SChuck Lever 	return -EIO;
315e4f93234SChuck Lever }
316e4f93234SChuck Lever 
317d9c407b1SChuck Lever /*
318d9c407b1SChuck Lever  * createverf3
319d9c407b1SChuck Lever  *
320d9c407b1SChuck Lever  *	typedef opaque createverf3[NFS3_CREATEVERFSIZE];
321d9c407b1SChuck Lever  */
322d9c407b1SChuck Lever static void encode_createverf3(struct xdr_stream *xdr, const __be32 *verifier)
323d9c407b1SChuck Lever {
324d9c407b1SChuck Lever 	__be32 *p;
325d9c407b1SChuck Lever 
326d9c407b1SChuck Lever 	p = xdr_reserve_space(xdr, NFS3_CREATEVERFSIZE);
327d9c407b1SChuck Lever 	memcpy(p, verifier, NFS3_CREATEVERFSIZE);
328d9c407b1SChuck Lever }
329d9c407b1SChuck Lever 
330e4f93234SChuck Lever static int decode_writeverf3(struct xdr_stream *xdr, __be32 *verifier)
331e4f93234SChuck Lever {
332e4f93234SChuck Lever 	__be32 *p;
333e4f93234SChuck Lever 
334e4f93234SChuck Lever 	p = xdr_inline_decode(xdr, NFS3_WRITEVERFSIZE);
335e4f93234SChuck Lever 	if (unlikely(p == NULL))
336e4f93234SChuck Lever 		goto out_overflow;
337e4f93234SChuck Lever 	memcpy(verifier, p, NFS3_WRITEVERFSIZE);
338e4f93234SChuck Lever 	return 0;
339e4f93234SChuck Lever out_overflow:
340e4f93234SChuck Lever 	print_overflow_msg(__func__, xdr);
341e4f93234SChuck Lever 	return -EIO;
342e4f93234SChuck Lever }
343e4f93234SChuck Lever 
344e4f93234SChuck Lever /*
345e4f93234SChuck Lever  * size3
346e4f93234SChuck Lever  *
347e4f93234SChuck Lever  *	typedef uint64 size3;
348e4f93234SChuck Lever  */
349e4f93234SChuck Lever static __be32 *xdr_decode_size3(__be32 *p, u64 *size)
350e4f93234SChuck Lever {
351e4f93234SChuck Lever 	return xdr_decode_hyper(p, size);
352e4f93234SChuck Lever }
353e4f93234SChuck Lever 
354e4f93234SChuck Lever /*
355e4f93234SChuck Lever  * nfsstat3
356e4f93234SChuck Lever  *
357e4f93234SChuck Lever  *	enum nfsstat3 {
358e4f93234SChuck Lever  *		NFS3_OK = 0,
359e4f93234SChuck Lever  *		...
360e4f93234SChuck Lever  *	}
361e4f93234SChuck Lever  */
362e4f93234SChuck Lever #define NFS3_OK		NFS_OK
363e4f93234SChuck Lever 
364e4f93234SChuck Lever static int decode_nfsstat3(struct xdr_stream *xdr, enum nfs_stat *status)
365e4f93234SChuck Lever {
366e4f93234SChuck Lever 	__be32 *p;
367e4f93234SChuck Lever 
368e4f93234SChuck Lever 	p = xdr_inline_decode(xdr, 4);
369e4f93234SChuck Lever 	if (unlikely(p == NULL))
370e4f93234SChuck Lever 		goto out_overflow;
371e4f93234SChuck Lever 	*status = be32_to_cpup(p);
372e4f93234SChuck Lever 	return 0;
373e4f93234SChuck Lever out_overflow:
374e4f93234SChuck Lever 	print_overflow_msg(__func__, xdr);
375e4f93234SChuck Lever 	return -EIO;
376e4f93234SChuck Lever }
377e4f93234SChuck Lever 
378d9c407b1SChuck Lever /*
379d9c407b1SChuck Lever  * ftype3
380d9c407b1SChuck Lever  *
381d9c407b1SChuck Lever  *	enum ftype3 {
382d9c407b1SChuck Lever  *		NF3REG	= 1,
383d9c407b1SChuck Lever  *		NF3DIR	= 2,
384d9c407b1SChuck Lever  *		NF3BLK	= 3,
385d9c407b1SChuck Lever  *		NF3CHR	= 4,
386d9c407b1SChuck Lever  *		NF3LNK	= 5,
387d9c407b1SChuck Lever  *		NF3SOCK	= 6,
388d9c407b1SChuck Lever  *		NF3FIFO	= 7
389d9c407b1SChuck Lever  *	};
390d9c407b1SChuck Lever  */
391d9c407b1SChuck Lever static void encode_ftype3(struct xdr_stream *xdr, const u32 type)
392d9c407b1SChuck Lever {
393d9c407b1SChuck Lever 	BUG_ON(type > NF3FIFO);
394d9c407b1SChuck Lever 	encode_uint32(xdr, type);
395d9c407b1SChuck Lever }
396d9c407b1SChuck Lever 
397f6048709SChuck Lever static __be32 *xdr_decode_ftype3(__be32 *p, umode_t *mode)
398f6048709SChuck Lever {
399f6048709SChuck Lever 	u32 type;
400f6048709SChuck Lever 
401f6048709SChuck Lever 	type = be32_to_cpup(p++);
402f6048709SChuck Lever 	if (type > NF3FIFO)
403f6048709SChuck Lever 		type = NF3NON;
404f6048709SChuck Lever 	*mode = nfs_type2fmt[type];
405f6048709SChuck Lever 	return p;
406f6048709SChuck Lever }
407f6048709SChuck Lever 
408d9c407b1SChuck Lever /*
409d9c407b1SChuck Lever  * specdata3
410d9c407b1SChuck Lever  *
411d9c407b1SChuck Lever  *     struct specdata3 {
412d9c407b1SChuck Lever  *             uint32  specdata1;
413d9c407b1SChuck Lever  *             uint32  specdata2;
414d9c407b1SChuck Lever  *     };
415d9c407b1SChuck Lever  */
416d9c407b1SChuck Lever static void encode_specdata3(struct xdr_stream *xdr, const dev_t rdev)
417d9c407b1SChuck Lever {
418d9c407b1SChuck Lever 	__be32 *p;
419d9c407b1SChuck Lever 
420d9c407b1SChuck Lever 	p = xdr_reserve_space(xdr, 8);
421d9c407b1SChuck Lever 	*p++ = cpu_to_be32(MAJOR(rdev));
422d9c407b1SChuck Lever 	*p = cpu_to_be32(MINOR(rdev));
423d9c407b1SChuck Lever }
424d9c407b1SChuck Lever 
425f6048709SChuck Lever static __be32 *xdr_decode_specdata3(__be32 *p, dev_t *rdev)
426f6048709SChuck Lever {
427f6048709SChuck Lever 	unsigned int major, minor;
428f6048709SChuck Lever 
429f6048709SChuck Lever 	major = be32_to_cpup(p++);
430f6048709SChuck Lever 	minor = be32_to_cpup(p++);
431f6048709SChuck Lever 	*rdev = MKDEV(major, minor);
432f6048709SChuck Lever 	if (MAJOR(*rdev) != major || MINOR(*rdev) != minor)
433f6048709SChuck Lever 		*rdev = 0;
434f6048709SChuck Lever 	return p;
435f6048709SChuck Lever }
436f6048709SChuck Lever 
437d9c407b1SChuck Lever /*
438d9c407b1SChuck Lever  * nfs_fh3
439d9c407b1SChuck Lever  *
440d9c407b1SChuck Lever  *	struct nfs_fh3 {
441d9c407b1SChuck Lever  *		opaque       data<NFS3_FHSIZE>;
442d9c407b1SChuck Lever  *	};
443d9c407b1SChuck Lever  */
444d9c407b1SChuck Lever static void encode_nfs_fh3(struct xdr_stream *xdr, const struct nfs_fh *fh)
445d9c407b1SChuck Lever {
446d9c407b1SChuck Lever 	__be32 *p;
447d9c407b1SChuck Lever 
448d9c407b1SChuck Lever 	BUG_ON(fh->size > NFS3_FHSIZE);
449d9c407b1SChuck Lever 	p = xdr_reserve_space(xdr, 4 + fh->size);
450d9c407b1SChuck Lever 	xdr_encode_opaque(p, fh->data, fh->size);
451d9c407b1SChuck Lever }
452d9c407b1SChuck Lever 
453e4f93234SChuck Lever static int decode_nfs_fh3(struct xdr_stream *xdr, struct nfs_fh *fh)
454e4f93234SChuck Lever {
455e4f93234SChuck Lever 	u32 length;
456e4f93234SChuck Lever 	__be32 *p;
457e4f93234SChuck Lever 
458e4f93234SChuck Lever 	p = xdr_inline_decode(xdr, 4);
459e4f93234SChuck Lever 	if (unlikely(p == NULL))
460e4f93234SChuck Lever 		goto out_overflow;
461e4f93234SChuck Lever 	length = be32_to_cpup(p++);
462e4f93234SChuck Lever 	if (unlikely(length > NFS3_FHSIZE))
463e4f93234SChuck Lever 		goto out_toobig;
464e4f93234SChuck Lever 	p = xdr_inline_decode(xdr, length);
465e4f93234SChuck Lever 	if (unlikely(p == NULL))
466e4f93234SChuck Lever 		goto out_overflow;
467e4f93234SChuck Lever 	fh->size = length;
468e4f93234SChuck Lever 	memcpy(fh->data, p, length);
469e4f93234SChuck Lever 	return 0;
470e4f93234SChuck Lever out_toobig:
471e4f93234SChuck Lever 	dprintk("NFS: file handle size (%u) too big\n", length);
472e4f93234SChuck Lever 	return -E2BIG;
473e4f93234SChuck Lever out_overflow:
474e4f93234SChuck Lever 	print_overflow_msg(__func__, xdr);
475e4f93234SChuck Lever 	return -EIO;
476e4f93234SChuck Lever }
477e4f93234SChuck Lever 
478e4f93234SChuck Lever static void zero_nfs_fh3(struct nfs_fh *fh)
479e4f93234SChuck Lever {
480e4f93234SChuck Lever 	memset(fh, 0, sizeof(*fh));
481e4f93234SChuck Lever }
482e4f93234SChuck Lever 
483d9c407b1SChuck Lever /*
4849d5a6434SChuck Lever  * nfstime3
4859d5a6434SChuck Lever  *
4869d5a6434SChuck Lever  *	struct nfstime3 {
4879d5a6434SChuck Lever  *		uint32	seconds;
4889d5a6434SChuck Lever  *		uint32	nseconds;
4899d5a6434SChuck Lever  *	};
4909d5a6434SChuck Lever  */
4919d5a6434SChuck Lever static __be32 *xdr_encode_nfstime3(__be32 *p, const struct timespec *timep)
4929d5a6434SChuck Lever {
4939d5a6434SChuck Lever 	*p++ = cpu_to_be32(timep->tv_sec);
4949d5a6434SChuck Lever 	*p++ = cpu_to_be32(timep->tv_nsec);
4959d5a6434SChuck Lever 	return p;
4969d5a6434SChuck Lever }
4979d5a6434SChuck Lever 
498f6048709SChuck Lever static __be32 *xdr_decode_nfstime3(__be32 *p, struct timespec *timep)
499f6048709SChuck Lever {
500f6048709SChuck Lever 	timep->tv_sec = be32_to_cpup(p++);
501f6048709SChuck Lever 	timep->tv_nsec = be32_to_cpup(p++);
502f6048709SChuck Lever 	return p;
503f6048709SChuck Lever }
504f6048709SChuck Lever 
5059d5a6434SChuck Lever /*
506d9c407b1SChuck Lever  * sattr3
507d9c407b1SChuck Lever  *
508d9c407b1SChuck Lever  *	enum time_how {
509d9c407b1SChuck Lever  *		DONT_CHANGE		= 0,
510d9c407b1SChuck Lever  *		SET_TO_SERVER_TIME	= 1,
511d9c407b1SChuck Lever  *		SET_TO_CLIENT_TIME	= 2
512d9c407b1SChuck Lever  *	};
513d9c407b1SChuck Lever  *
514d9c407b1SChuck Lever  *	union set_mode3 switch (bool set_it) {
515d9c407b1SChuck Lever  *	case TRUE:
516d9c407b1SChuck Lever  *		mode3	mode;
517d9c407b1SChuck Lever  *	default:
518d9c407b1SChuck Lever  *		void;
519d9c407b1SChuck Lever  *	};
520d9c407b1SChuck Lever  *
521d9c407b1SChuck Lever  *	union set_uid3 switch (bool set_it) {
522d9c407b1SChuck Lever  *	case TRUE:
523d9c407b1SChuck Lever  *		uid3	uid;
524d9c407b1SChuck Lever  *	default:
525d9c407b1SChuck Lever  *		void;
526d9c407b1SChuck Lever  *	};
527d9c407b1SChuck Lever  *
528d9c407b1SChuck Lever  *	union set_gid3 switch (bool set_it) {
529d9c407b1SChuck Lever  *	case TRUE:
530d9c407b1SChuck Lever  *		gid3	gid;
531d9c407b1SChuck Lever  *	default:
532d9c407b1SChuck Lever  *		void;
533d9c407b1SChuck Lever  *	};
534d9c407b1SChuck Lever  *
535d9c407b1SChuck Lever  *	union set_size3 switch (bool set_it) {
536d9c407b1SChuck Lever  *	case TRUE:
537d9c407b1SChuck Lever  *		size3	size;
538d9c407b1SChuck Lever  *	default:
539d9c407b1SChuck Lever  *		void;
540d9c407b1SChuck Lever  *	};
541d9c407b1SChuck Lever  *
542d9c407b1SChuck Lever  *	union set_atime switch (time_how set_it) {
543d9c407b1SChuck Lever  *	case SET_TO_CLIENT_TIME:
544d9c407b1SChuck Lever  *		nfstime3	atime;
545d9c407b1SChuck Lever  *	default:
546d9c407b1SChuck Lever  *		void;
547d9c407b1SChuck Lever  *	};
548d9c407b1SChuck Lever  *
549d9c407b1SChuck Lever  *	union set_mtime switch (time_how set_it) {
550d9c407b1SChuck Lever  *	case SET_TO_CLIENT_TIME:
551d9c407b1SChuck Lever  *		nfstime3  mtime;
552d9c407b1SChuck Lever  *	default:
553d9c407b1SChuck Lever  *		void;
554d9c407b1SChuck Lever  *	};
555d9c407b1SChuck Lever  *
556d9c407b1SChuck Lever  *	struct sattr3 {
557d9c407b1SChuck Lever  *		set_mode3	mode;
558d9c407b1SChuck Lever  *		set_uid3	uid;
559d9c407b1SChuck Lever  *		set_gid3	gid;
560d9c407b1SChuck Lever  *		set_size3	size;
561d9c407b1SChuck Lever  *		set_atime	atime;
562d9c407b1SChuck Lever  *		set_mtime	mtime;
563d9c407b1SChuck Lever  *	};
564d9c407b1SChuck Lever  */
565d9c407b1SChuck Lever static void encode_sattr3(struct xdr_stream *xdr, const struct iattr *attr)
566d9c407b1SChuck Lever {
567d9c407b1SChuck Lever 	u32 nbytes;
568d9c407b1SChuck Lever 	__be32 *p;
569d9c407b1SChuck Lever 
570d9c407b1SChuck Lever 	/*
571d9c407b1SChuck Lever 	 * In order to make only a single xdr_reserve_space() call,
572d9c407b1SChuck Lever 	 * pre-compute the total number of bytes to be reserved.
573d9c407b1SChuck Lever 	 * Six boolean values, one for each set_foo field, are always
574d9c407b1SChuck Lever 	 * present in the encoded result, so start there.
575d9c407b1SChuck Lever 	 */
576d9c407b1SChuck Lever 	nbytes = 6 * 4;
577d9c407b1SChuck Lever 	if (attr->ia_valid & ATTR_MODE)
578d9c407b1SChuck Lever 		nbytes += 4;
579d9c407b1SChuck Lever 	if (attr->ia_valid & ATTR_UID)
580d9c407b1SChuck Lever 		nbytes += 4;
581d9c407b1SChuck Lever 	if (attr->ia_valid & ATTR_GID)
582d9c407b1SChuck Lever 		nbytes += 4;
583d9c407b1SChuck Lever 	if (attr->ia_valid & ATTR_SIZE)
584d9c407b1SChuck Lever 		nbytes += 8;
585d9c407b1SChuck Lever 	if (attr->ia_valid & ATTR_ATIME_SET)
586d9c407b1SChuck Lever 		nbytes += 8;
587d9c407b1SChuck Lever 	if (attr->ia_valid & ATTR_MTIME_SET)
588d9c407b1SChuck Lever 		nbytes += 8;
589d9c407b1SChuck Lever 	p = xdr_reserve_space(xdr, nbytes);
590d9c407b1SChuck Lever 
5919d5a6434SChuck Lever 	if (attr->ia_valid & ATTR_MODE) {
5929d5a6434SChuck Lever 		*p++ = xdr_one;
5939d5a6434SChuck Lever 		*p++ = cpu_to_be32(attr->ia_mode & S_IALLUGO);
5949d5a6434SChuck Lever 	} else
5959d5a6434SChuck Lever 		*p++ = xdr_zero;
5969d5a6434SChuck Lever 
5979d5a6434SChuck Lever 	if (attr->ia_valid & ATTR_UID) {
5989d5a6434SChuck Lever 		*p++ = xdr_one;
5999d5a6434SChuck Lever 		*p++ = cpu_to_be32(attr->ia_uid);
6009d5a6434SChuck Lever 	} else
6019d5a6434SChuck Lever 		*p++ = xdr_zero;
6029d5a6434SChuck Lever 
6039d5a6434SChuck Lever 	if (attr->ia_valid & ATTR_GID) {
6049d5a6434SChuck Lever 		*p++ = xdr_one;
6059d5a6434SChuck Lever 		*p++ = cpu_to_be32(attr->ia_gid);
6069d5a6434SChuck Lever 	} else
6079d5a6434SChuck Lever 		*p++ = xdr_zero;
6089d5a6434SChuck Lever 
6099d5a6434SChuck Lever 	if (attr->ia_valid & ATTR_SIZE) {
6109d5a6434SChuck Lever 		*p++ = xdr_one;
6119d5a6434SChuck Lever 		p = xdr_encode_hyper(p, (u64)attr->ia_size);
6129d5a6434SChuck Lever 	} else
6139d5a6434SChuck Lever 		*p++ = xdr_zero;
6149d5a6434SChuck Lever 
6159d5a6434SChuck Lever 	if (attr->ia_valid & ATTR_ATIME_SET) {
6169d5a6434SChuck Lever 		*p++ = xdr_two;
6179d5a6434SChuck Lever 		p = xdr_encode_nfstime3(p, &attr->ia_atime);
6189d5a6434SChuck Lever 	} else if (attr->ia_valid & ATTR_ATIME) {
6199d5a6434SChuck Lever 		*p++ = xdr_one;
6209d5a6434SChuck Lever 	} else
6219d5a6434SChuck Lever 		*p++ = xdr_zero;
6229d5a6434SChuck Lever 
6239d5a6434SChuck Lever 	if (attr->ia_valid & ATTR_MTIME_SET) {
6249d5a6434SChuck Lever 		*p++ = xdr_two;
6259d5a6434SChuck Lever 		xdr_encode_nfstime3(p, &attr->ia_mtime);
6269d5a6434SChuck Lever 	} else if (attr->ia_valid & ATTR_MTIME) {
6279d5a6434SChuck Lever 		*p = xdr_one;
6289d5a6434SChuck Lever 	} else
6299d5a6434SChuck Lever 		*p = xdr_zero;
630d9c407b1SChuck Lever }
631d9c407b1SChuck Lever 
632d9c407b1SChuck Lever /*
633e4f93234SChuck Lever  * fattr3
634e4f93234SChuck Lever  *
635e4f93234SChuck Lever  *	struct fattr3 {
636e4f93234SChuck Lever  *		ftype3		type;
637e4f93234SChuck Lever  *		mode3		mode;
638e4f93234SChuck Lever  *		uint32		nlink;
639e4f93234SChuck Lever  *		uid3		uid;
640e4f93234SChuck Lever  *		gid3		gid;
641e4f93234SChuck Lever  *		size3		size;
642e4f93234SChuck Lever  *		size3		used;
643e4f93234SChuck Lever  *		specdata3	rdev;
644e4f93234SChuck Lever  *		uint64		fsid;
645e4f93234SChuck Lever  *		fileid3		fileid;
646e4f93234SChuck Lever  *		nfstime3	atime;
647e4f93234SChuck Lever  *		nfstime3	mtime;
648e4f93234SChuck Lever  *		nfstime3	ctime;
649e4f93234SChuck Lever  *	};
650e4f93234SChuck Lever  */
651e4f93234SChuck Lever static int decode_fattr3(struct xdr_stream *xdr, struct nfs_fattr *fattr)
652e4f93234SChuck Lever {
653f6048709SChuck Lever 	umode_t fmode;
654e4f93234SChuck Lever 	__be32 *p;
655e4f93234SChuck Lever 
656e4f93234SChuck Lever 	p = xdr_inline_decode(xdr, NFS3_fattr_sz << 2);
657e4f93234SChuck Lever 	if (unlikely(p == NULL))
658e4f93234SChuck Lever 		goto out_overflow;
659f6048709SChuck Lever 
660f6048709SChuck Lever 	p = xdr_decode_ftype3(p, &fmode);
661f6048709SChuck Lever 
662f6048709SChuck Lever 	fattr->mode = (be32_to_cpup(p++) & ~S_IFMT) | fmode;
663f6048709SChuck Lever 	fattr->nlink = be32_to_cpup(p++);
664f6048709SChuck Lever 	fattr->uid = be32_to_cpup(p++);
665f6048709SChuck Lever 	fattr->gid = be32_to_cpup(p++);
666f6048709SChuck Lever 
667f6048709SChuck Lever 	p = xdr_decode_size3(p, &fattr->size);
668f6048709SChuck Lever 	p = xdr_decode_size3(p, &fattr->du.nfs3.used);
669f6048709SChuck Lever 	p = xdr_decode_specdata3(p, &fattr->rdev);
670f6048709SChuck Lever 
671f6048709SChuck Lever 	p = xdr_decode_hyper(p, &fattr->fsid.major);
672f6048709SChuck Lever 	fattr->fsid.minor = 0;
673f6048709SChuck Lever 
674f6048709SChuck Lever 	p = xdr_decode_fileid3(p, &fattr->fileid);
675f6048709SChuck Lever 	p = xdr_decode_nfstime3(p, &fattr->atime);
676f6048709SChuck Lever 	p = xdr_decode_nfstime3(p, &fattr->mtime);
677f6048709SChuck Lever 	xdr_decode_nfstime3(p, &fattr->ctime);
678f6048709SChuck Lever 
679f6048709SChuck Lever 	fattr->valid |= NFS_ATTR_FATTR_V3;
680e4f93234SChuck Lever 	return 0;
681e4f93234SChuck Lever out_overflow:
682e4f93234SChuck Lever 	print_overflow_msg(__func__, xdr);
683e4f93234SChuck Lever 	return -EIO;
684e4f93234SChuck Lever }
685e4f93234SChuck Lever 
686e4f93234SChuck Lever /*
687e4f93234SChuck Lever  * post_op_attr
688e4f93234SChuck Lever  *
689e4f93234SChuck Lever  *	union post_op_attr switch (bool attributes_follow) {
690e4f93234SChuck Lever  *	case TRUE:
691e4f93234SChuck Lever  *		fattr3	attributes;
692e4f93234SChuck Lever  *	case FALSE:
693e4f93234SChuck Lever  *		void;
694e4f93234SChuck Lever  *	};
695e4f93234SChuck Lever  */
696e4f93234SChuck Lever static int decode_post_op_attr(struct xdr_stream *xdr, struct nfs_fattr *fattr)
697e4f93234SChuck Lever {
698e4f93234SChuck Lever 	__be32 *p;
699e4f93234SChuck Lever 
700e4f93234SChuck Lever 	p = xdr_inline_decode(xdr, 4);
701e4f93234SChuck Lever 	if (unlikely(p == NULL))
702e4f93234SChuck Lever 		goto out_overflow;
703e4f93234SChuck Lever 	if (*p != xdr_zero)
704e4f93234SChuck Lever 		return decode_fattr3(xdr, fattr);
705e4f93234SChuck Lever 	return 0;
706e4f93234SChuck Lever out_overflow:
707e4f93234SChuck Lever 	print_overflow_msg(__func__, xdr);
708e4f93234SChuck Lever 	return -EIO;
709e4f93234SChuck Lever }
710e4f93234SChuck Lever 
711e4f93234SChuck Lever /*
712e4f93234SChuck Lever  * wcc_attr
713e4f93234SChuck Lever  *	struct wcc_attr {
714e4f93234SChuck Lever  *		size3		size;
715e4f93234SChuck Lever  *		nfstime3	mtime;
716e4f93234SChuck Lever  *		nfstime3	ctime;
717e4f93234SChuck Lever  *	};
718e4f93234SChuck Lever  */
719e4f93234SChuck Lever static int decode_wcc_attr(struct xdr_stream *xdr, struct nfs_fattr *fattr)
720e4f93234SChuck Lever {
721e4f93234SChuck Lever 	__be32 *p;
722e4f93234SChuck Lever 
723e4f93234SChuck Lever 	p = xdr_inline_decode(xdr, NFS3_wcc_attr_sz << 2);
724e4f93234SChuck Lever 	if (unlikely(p == NULL))
725e4f93234SChuck Lever 		goto out_overflow;
726f6048709SChuck Lever 
727f6048709SChuck Lever 	fattr->valid |= NFS_ATTR_FATTR_PRESIZE
728f6048709SChuck Lever 		| NFS_ATTR_FATTR_PREMTIME
729f6048709SChuck Lever 		| NFS_ATTR_FATTR_PRECTIME;
730f6048709SChuck Lever 
731f6048709SChuck Lever 	p = xdr_decode_size3(p, &fattr->pre_size);
732f6048709SChuck Lever 	p = xdr_decode_nfstime3(p, &fattr->pre_mtime);
733f6048709SChuck Lever 	xdr_decode_nfstime3(p, &fattr->pre_ctime);
734f6048709SChuck Lever 
735e4f93234SChuck Lever 	return 0;
736e4f93234SChuck Lever out_overflow:
737e4f93234SChuck Lever 	print_overflow_msg(__func__, xdr);
738e4f93234SChuck Lever 	return -EIO;
739e4f93234SChuck Lever }
740e4f93234SChuck Lever 
741e4f93234SChuck Lever /*
742e4f93234SChuck Lever  * pre_op_attr
743e4f93234SChuck Lever  *	union pre_op_attr switch (bool attributes_follow) {
744e4f93234SChuck Lever  *	case TRUE:
745e4f93234SChuck Lever  *		wcc_attr	attributes;
746e4f93234SChuck Lever  *	case FALSE:
747e4f93234SChuck Lever  *		void;
748e4f93234SChuck Lever  *	};
749e4f93234SChuck Lever  *
750e4f93234SChuck Lever  * wcc_data
751e4f93234SChuck Lever  *
752e4f93234SChuck Lever  *	struct wcc_data {
753e4f93234SChuck Lever  *		pre_op_attr	before;
754e4f93234SChuck Lever  *		post_op_attr	after;
755e4f93234SChuck Lever  *	};
756e4f93234SChuck Lever  */
757e4f93234SChuck Lever static int decode_pre_op_attr(struct xdr_stream *xdr, struct nfs_fattr *fattr)
758e4f93234SChuck Lever {
759e4f93234SChuck Lever 	__be32 *p;
760e4f93234SChuck Lever 
761e4f93234SChuck Lever 	p = xdr_inline_decode(xdr, 4);
762e4f93234SChuck Lever 	if (unlikely(p == NULL))
763e4f93234SChuck Lever 		goto out_overflow;
764e4f93234SChuck Lever 	if (*p != xdr_zero)
765e4f93234SChuck Lever 		return decode_wcc_attr(xdr, fattr);
766e4f93234SChuck Lever 	return 0;
767e4f93234SChuck Lever out_overflow:
768e4f93234SChuck Lever 	print_overflow_msg(__func__, xdr);
769e4f93234SChuck Lever 	return -EIO;
770e4f93234SChuck Lever }
771e4f93234SChuck Lever 
772e4f93234SChuck Lever static int decode_wcc_data(struct xdr_stream *xdr, struct nfs_fattr *fattr)
773e4f93234SChuck Lever {
774e4f93234SChuck Lever 	int error;
775e4f93234SChuck Lever 
776e4f93234SChuck Lever 	error = decode_pre_op_attr(xdr, fattr);
777e4f93234SChuck Lever 	if (unlikely(error))
778e4f93234SChuck Lever 		goto out;
779e4f93234SChuck Lever 	error = decode_post_op_attr(xdr, fattr);
780e4f93234SChuck Lever out:
781e4f93234SChuck Lever 	return error;
782e4f93234SChuck Lever }
783e4f93234SChuck Lever 
784e4f93234SChuck Lever /*
785e4f93234SChuck Lever  * post_op_fh3
786e4f93234SChuck Lever  *
787e4f93234SChuck Lever  *	union post_op_fh3 switch (bool handle_follows) {
788e4f93234SChuck Lever  *	case TRUE:
789e4f93234SChuck Lever  *		nfs_fh3  handle;
790e4f93234SChuck Lever  *	case FALSE:
791e4f93234SChuck Lever  *		void;
792e4f93234SChuck Lever  *	};
793e4f93234SChuck Lever  */
794e4f93234SChuck Lever static int decode_post_op_fh3(struct xdr_stream *xdr, struct nfs_fh *fh)
795e4f93234SChuck Lever {
796e4f93234SChuck Lever 	__be32 *p = xdr_inline_decode(xdr, 4);
797e4f93234SChuck Lever 	if (unlikely(p == NULL))
798e4f93234SChuck Lever 		goto out_overflow;
799e4f93234SChuck Lever 	if (*p != xdr_zero)
800e4f93234SChuck Lever 		return decode_nfs_fh3(xdr, fh);
801e4f93234SChuck Lever 	zero_nfs_fh3(fh);
802e4f93234SChuck Lever 	return 0;
803e4f93234SChuck Lever out_overflow:
804e4f93234SChuck Lever 	print_overflow_msg(__func__, xdr);
805e4f93234SChuck Lever 	return -EIO;
806e4f93234SChuck Lever }
807e4f93234SChuck Lever 
808e4f93234SChuck Lever /*
809d9c407b1SChuck Lever  * diropargs3
810d9c407b1SChuck Lever  *
811d9c407b1SChuck Lever  *	struct diropargs3 {
812d9c407b1SChuck Lever  *		nfs_fh3		dir;
813d9c407b1SChuck Lever  *		filename3	name;
814d9c407b1SChuck Lever  *	};
815d9c407b1SChuck Lever  */
816d9c407b1SChuck Lever static void encode_diropargs3(struct xdr_stream *xdr, const struct nfs_fh *fh,
817d9c407b1SChuck Lever 			      const char *name, u32 length)
818d9c407b1SChuck Lever {
819d9c407b1SChuck Lever 	encode_nfs_fh3(xdr, fh);
820d9c407b1SChuck Lever 	encode_filename3(xdr, name, length);
821d9c407b1SChuck Lever }
822d9c407b1SChuck Lever 
823d9c407b1SChuck Lever 
8241da177e4SLinus Torvalds /*
825499ff710SChuck Lever  * NFSv3 XDR encode functions
826499ff710SChuck Lever  *
827499ff710SChuck Lever  * NFSv3 argument types are defined in section 3.3 of RFC 1813:
828499ff710SChuck Lever  * "NFS Version 3 Protocol Specification".
8291da177e4SLinus Torvalds  */
8301da177e4SLinus Torvalds 
8311da177e4SLinus Torvalds /*
832d9c407b1SChuck Lever  * 3.3.1  GETATTR3args
833d9c407b1SChuck Lever  *
834d9c407b1SChuck Lever  *	struct GETATTR3args {
835d9c407b1SChuck Lever  *		nfs_fh3  object;
836d9c407b1SChuck Lever  *	};
837d9c407b1SChuck Lever  */
8389f06c719SChuck Lever static void nfs3_xdr_enc_getattr3args(struct rpc_rqst *req,
8399f06c719SChuck Lever 				      struct xdr_stream *xdr,
840d9c407b1SChuck Lever 				      const struct nfs_fh *fh)
841d9c407b1SChuck Lever {
8429f06c719SChuck Lever 	encode_nfs_fh3(xdr, fh);
843d9c407b1SChuck Lever }
844d9c407b1SChuck Lever 
845d9c407b1SChuck Lever /*
846d9c407b1SChuck Lever  * 3.3.2  SETATTR3args
847d9c407b1SChuck Lever  *
848d9c407b1SChuck Lever  *	union sattrguard3 switch (bool check) {
849d9c407b1SChuck Lever  *	case TRUE:
850d9c407b1SChuck Lever  *		nfstime3  obj_ctime;
851d9c407b1SChuck Lever  *	case FALSE:
852d9c407b1SChuck Lever  *		void;
853d9c407b1SChuck Lever  *	};
854d9c407b1SChuck Lever  *
855d9c407b1SChuck Lever  *	struct SETATTR3args {
856d9c407b1SChuck Lever  *		nfs_fh3		object;
857d9c407b1SChuck Lever  *		sattr3		new_attributes;
858d9c407b1SChuck Lever  *		sattrguard3	guard;
859d9c407b1SChuck Lever  *	};
860d9c407b1SChuck Lever  */
861d9c407b1SChuck Lever static void encode_sattrguard3(struct xdr_stream *xdr,
862d9c407b1SChuck Lever 			       const struct nfs3_sattrargs *args)
863d9c407b1SChuck Lever {
864d9c407b1SChuck Lever 	__be32 *p;
865d9c407b1SChuck Lever 
866d9c407b1SChuck Lever 	if (args->guard) {
867d9c407b1SChuck Lever 		p = xdr_reserve_space(xdr, 4 + 8);
868d9c407b1SChuck Lever 		*p++ = xdr_one;
8699d5a6434SChuck Lever 		xdr_encode_nfstime3(p, &args->guardtime);
870d9c407b1SChuck Lever 	} else {
871d9c407b1SChuck Lever 		p = xdr_reserve_space(xdr, 4);
872d9c407b1SChuck Lever 		*p = xdr_zero;
873d9c407b1SChuck Lever 	}
874d9c407b1SChuck Lever }
875d9c407b1SChuck Lever 
8769f06c719SChuck Lever static void nfs3_xdr_enc_setattr3args(struct rpc_rqst *req,
8779f06c719SChuck Lever 				      struct xdr_stream *xdr,
878d9c407b1SChuck Lever 				      const struct nfs3_sattrargs *args)
879d9c407b1SChuck Lever {
8809f06c719SChuck Lever 	encode_nfs_fh3(xdr, args->fh);
8819f06c719SChuck Lever 	encode_sattr3(xdr, args->sattr);
8829f06c719SChuck Lever 	encode_sattrguard3(xdr, args);
883d9c407b1SChuck Lever }
884d9c407b1SChuck Lever 
885d9c407b1SChuck Lever /*
886d9c407b1SChuck Lever  * 3.3.3  LOOKUP3args
887d9c407b1SChuck Lever  *
888d9c407b1SChuck Lever  *	struct LOOKUP3args {
889d9c407b1SChuck Lever  *		diropargs3  what;
890d9c407b1SChuck Lever  *	};
891d9c407b1SChuck Lever  */
8929f06c719SChuck Lever static void nfs3_xdr_enc_lookup3args(struct rpc_rqst *req,
8939f06c719SChuck Lever 				     struct xdr_stream *xdr,
894d9c407b1SChuck Lever 				     const struct nfs3_diropargs *args)
895d9c407b1SChuck Lever {
8969f06c719SChuck Lever 	encode_diropargs3(xdr, args->fh, args->name, args->len);
897d9c407b1SChuck Lever }
898d9c407b1SChuck Lever 
899d9c407b1SChuck Lever /*
900d9c407b1SChuck Lever  * 3.3.4  ACCESS3args
901d9c407b1SChuck Lever  *
902d9c407b1SChuck Lever  *	struct ACCESS3args {
903d9c407b1SChuck Lever  *		nfs_fh3		object;
904d9c407b1SChuck Lever  *		uint32		access;
905d9c407b1SChuck Lever  *	};
906d9c407b1SChuck Lever  */
907d9c407b1SChuck Lever static void encode_access3args(struct xdr_stream *xdr,
908d9c407b1SChuck Lever 			       const struct nfs3_accessargs *args)
909d9c407b1SChuck Lever {
910d9c407b1SChuck Lever 	encode_nfs_fh3(xdr, args->fh);
911d9c407b1SChuck Lever 	encode_uint32(xdr, args->access);
912d9c407b1SChuck Lever }
913d9c407b1SChuck Lever 
9149f06c719SChuck Lever static void nfs3_xdr_enc_access3args(struct rpc_rqst *req,
9159f06c719SChuck Lever 				     struct xdr_stream *xdr,
916d9c407b1SChuck Lever 				     const struct nfs3_accessargs *args)
917d9c407b1SChuck Lever {
9189f06c719SChuck Lever 	encode_access3args(xdr, args);
919d9c407b1SChuck Lever }
920d9c407b1SChuck Lever 
921d9c407b1SChuck Lever /*
922d9c407b1SChuck Lever  * 3.3.5  READLINK3args
923d9c407b1SChuck Lever  *
924d9c407b1SChuck Lever  *	struct READLINK3args {
925d9c407b1SChuck Lever  *		nfs_fh3	symlink;
926d9c407b1SChuck Lever  *	};
927d9c407b1SChuck Lever  */
9289f06c719SChuck Lever static void nfs3_xdr_enc_readlink3args(struct rpc_rqst *req,
9299f06c719SChuck Lever 				       struct xdr_stream *xdr,
930d9c407b1SChuck Lever 				       const struct nfs3_readlinkargs *args)
931d9c407b1SChuck Lever {
9329f06c719SChuck Lever 	encode_nfs_fh3(xdr, args->fh);
933d9c407b1SChuck Lever 	prepare_reply_buffer(req, args->pages, args->pgbase,
934d9c407b1SChuck Lever 					args->pglen, NFS3_readlinkres_sz);
935d9c407b1SChuck Lever }
936d9c407b1SChuck Lever 
937d9c407b1SChuck Lever /*
938d9c407b1SChuck Lever  * 3.3.6  READ3args
939d9c407b1SChuck Lever  *
940d9c407b1SChuck Lever  *	struct READ3args {
941d9c407b1SChuck Lever  *		nfs_fh3		file;
942d9c407b1SChuck Lever  *		offset3		offset;
943d9c407b1SChuck Lever  *		count3		count;
944d9c407b1SChuck Lever  *	};
945d9c407b1SChuck Lever  */
946d9c407b1SChuck Lever static void encode_read3args(struct xdr_stream *xdr,
947d9c407b1SChuck Lever 			     const struct nfs_readargs *args)
948d9c407b1SChuck Lever {
949d9c407b1SChuck Lever 	__be32 *p;
950d9c407b1SChuck Lever 
951d9c407b1SChuck Lever 	encode_nfs_fh3(xdr, args->fh);
952d9c407b1SChuck Lever 
953d9c407b1SChuck Lever 	p = xdr_reserve_space(xdr, 8 + 4);
954d9c407b1SChuck Lever 	p = xdr_encode_hyper(p, args->offset);
955d9c407b1SChuck Lever 	*p = cpu_to_be32(args->count);
956d9c407b1SChuck Lever }
957d9c407b1SChuck Lever 
9589f06c719SChuck Lever static void nfs3_xdr_enc_read3args(struct rpc_rqst *req,
9599f06c719SChuck Lever 				   struct xdr_stream *xdr,
960d9c407b1SChuck Lever 				   const struct nfs_readargs *args)
961d9c407b1SChuck Lever {
9629f06c719SChuck Lever 	encode_read3args(xdr, args);
963d9c407b1SChuck Lever 	prepare_reply_buffer(req, args->pages, args->pgbase,
964d9c407b1SChuck Lever 					args->count, NFS3_readres_sz);
965d9c407b1SChuck Lever 	req->rq_rcv_buf.flags |= XDRBUF_READ;
966d9c407b1SChuck Lever }
967d9c407b1SChuck Lever 
968d9c407b1SChuck Lever /*
969d9c407b1SChuck Lever  * 3.3.7  WRITE3args
970d9c407b1SChuck Lever  *
971d9c407b1SChuck Lever  *	enum stable_how {
972d9c407b1SChuck Lever  *		UNSTABLE  = 0,
973d9c407b1SChuck Lever  *		DATA_SYNC = 1,
974d9c407b1SChuck Lever  *		FILE_SYNC = 2
975d9c407b1SChuck Lever  *	};
976d9c407b1SChuck Lever  *
977d9c407b1SChuck Lever  *	struct WRITE3args {
978d9c407b1SChuck Lever  *		nfs_fh3		file;
979d9c407b1SChuck Lever  *		offset3		offset;
980d9c407b1SChuck Lever  *		count3		count;
981d9c407b1SChuck Lever  *		stable_how	stable;
982d9c407b1SChuck Lever  *		opaque		data<>;
983d9c407b1SChuck Lever  *	};
984d9c407b1SChuck Lever  */
985d9c407b1SChuck Lever static void encode_write3args(struct xdr_stream *xdr,
986d9c407b1SChuck Lever 			      const struct nfs_writeargs *args)
987d9c407b1SChuck Lever {
988d9c407b1SChuck Lever 	__be32 *p;
989d9c407b1SChuck Lever 
990d9c407b1SChuck Lever 	encode_nfs_fh3(xdr, args->fh);
991d9c407b1SChuck Lever 
992d9c407b1SChuck Lever 	p = xdr_reserve_space(xdr, 8 + 4 + 4 + 4);
993d9c407b1SChuck Lever 	p = xdr_encode_hyper(p, args->offset);
994d9c407b1SChuck Lever 	*p++ = cpu_to_be32(args->count);
995d9c407b1SChuck Lever 	*p++ = cpu_to_be32(args->stable);
996d9c407b1SChuck Lever 	*p = cpu_to_be32(args->count);
997d9c407b1SChuck Lever 	xdr_write_pages(xdr, args->pages, args->pgbase, args->count);
998d9c407b1SChuck Lever }
999d9c407b1SChuck Lever 
10009f06c719SChuck Lever static void nfs3_xdr_enc_write3args(struct rpc_rqst *req,
10019f06c719SChuck Lever 				    struct xdr_stream *xdr,
1002d9c407b1SChuck Lever 				    const struct nfs_writeargs *args)
1003d9c407b1SChuck Lever {
10049f06c719SChuck Lever 	encode_write3args(xdr, args);
10059f06c719SChuck Lever 	xdr->buf->flags |= XDRBUF_WRITE;
1006d9c407b1SChuck Lever }
1007d9c407b1SChuck Lever 
1008d9c407b1SChuck Lever /*
1009d9c407b1SChuck Lever  * 3.3.8  CREATE3args
1010d9c407b1SChuck Lever  *
1011d9c407b1SChuck Lever  *	enum createmode3 {
1012d9c407b1SChuck Lever  *		UNCHECKED = 0,
1013d9c407b1SChuck Lever  *		GUARDED   = 1,
1014d9c407b1SChuck Lever  *		EXCLUSIVE = 2
1015d9c407b1SChuck Lever  *	};
1016d9c407b1SChuck Lever  *
1017d9c407b1SChuck Lever  *	union createhow3 switch (createmode3 mode) {
1018d9c407b1SChuck Lever  *	case UNCHECKED:
1019d9c407b1SChuck Lever  *	case GUARDED:
1020d9c407b1SChuck Lever  *		sattr3       obj_attributes;
1021d9c407b1SChuck Lever  *	case EXCLUSIVE:
1022d9c407b1SChuck Lever  *		createverf3  verf;
1023d9c407b1SChuck Lever  *	};
1024d9c407b1SChuck Lever  *
1025d9c407b1SChuck Lever  *	struct CREATE3args {
1026d9c407b1SChuck Lever  *		diropargs3	where;
1027d9c407b1SChuck Lever  *		createhow3	how;
1028d9c407b1SChuck Lever  *	};
1029d9c407b1SChuck Lever  */
1030d9c407b1SChuck Lever static void encode_createhow3(struct xdr_stream *xdr,
1031d9c407b1SChuck Lever 			      const struct nfs3_createargs *args)
1032d9c407b1SChuck Lever {
1033d9c407b1SChuck Lever 	encode_uint32(xdr, args->createmode);
1034d9c407b1SChuck Lever 	switch (args->createmode) {
1035d9c407b1SChuck Lever 	case NFS3_CREATE_UNCHECKED:
1036d9c407b1SChuck Lever 	case NFS3_CREATE_GUARDED:
1037d9c407b1SChuck Lever 		encode_sattr3(xdr, args->sattr);
1038d9c407b1SChuck Lever 		break;
1039d9c407b1SChuck Lever 	case NFS3_CREATE_EXCLUSIVE:
1040d9c407b1SChuck Lever 		encode_createverf3(xdr, args->verifier);
1041d9c407b1SChuck Lever 		break;
1042d9c407b1SChuck Lever 	default:
1043d9c407b1SChuck Lever 		BUG();
1044d9c407b1SChuck Lever 	}
1045d9c407b1SChuck Lever }
1046d9c407b1SChuck Lever 
10479f06c719SChuck Lever static void nfs3_xdr_enc_create3args(struct rpc_rqst *req,
10489f06c719SChuck Lever 				     struct xdr_stream *xdr,
1049d9c407b1SChuck Lever 				     const struct nfs3_createargs *args)
1050d9c407b1SChuck Lever {
10519f06c719SChuck Lever 	encode_diropargs3(xdr, args->fh, args->name, args->len);
10529f06c719SChuck Lever 	encode_createhow3(xdr, args);
1053d9c407b1SChuck Lever }
1054d9c407b1SChuck Lever 
1055d9c407b1SChuck Lever /*
1056d9c407b1SChuck Lever  * 3.3.9  MKDIR3args
1057d9c407b1SChuck Lever  *
1058d9c407b1SChuck Lever  *	struct MKDIR3args {
1059d9c407b1SChuck Lever  *		diropargs3	where;
1060d9c407b1SChuck Lever  *		sattr3		attributes;
1061d9c407b1SChuck Lever  *	};
1062d9c407b1SChuck Lever  */
10639f06c719SChuck Lever static void nfs3_xdr_enc_mkdir3args(struct rpc_rqst *req,
10649f06c719SChuck Lever 				    struct xdr_stream *xdr,
1065d9c407b1SChuck Lever 				    const struct nfs3_mkdirargs *args)
1066d9c407b1SChuck Lever {
10679f06c719SChuck Lever 	encode_diropargs3(xdr, args->fh, args->name, args->len);
10689f06c719SChuck Lever 	encode_sattr3(xdr, args->sattr);
1069d9c407b1SChuck Lever }
1070d9c407b1SChuck Lever 
1071d9c407b1SChuck Lever /*
1072d9c407b1SChuck Lever  * 3.3.10  SYMLINK3args
1073d9c407b1SChuck Lever  *
1074d9c407b1SChuck Lever  *	struct symlinkdata3 {
1075d9c407b1SChuck Lever  *		sattr3		symlink_attributes;
1076d9c407b1SChuck Lever  *		nfspath3	symlink_data;
1077d9c407b1SChuck Lever  *	};
1078d9c407b1SChuck Lever  *
1079d9c407b1SChuck Lever  *	struct SYMLINK3args {
1080d9c407b1SChuck Lever  *		diropargs3	where;
1081d9c407b1SChuck Lever  *		symlinkdata3	symlink;
1082d9c407b1SChuck Lever  *	};
1083d9c407b1SChuck Lever  */
1084d9c407b1SChuck Lever static void encode_symlinkdata3(struct xdr_stream *xdr,
1085d9c407b1SChuck Lever 				const struct nfs3_symlinkargs *args)
1086d9c407b1SChuck Lever {
1087d9c407b1SChuck Lever 	encode_sattr3(xdr, args->sattr);
1088d9c407b1SChuck Lever 	encode_nfspath3(xdr, args->pages, args->pathlen);
1089d9c407b1SChuck Lever }
1090d9c407b1SChuck Lever 
10919f06c719SChuck Lever static void nfs3_xdr_enc_symlink3args(struct rpc_rqst *req,
10929f06c719SChuck Lever 				      struct xdr_stream *xdr,
1093d9c407b1SChuck Lever 				      const struct nfs3_symlinkargs *args)
1094d9c407b1SChuck Lever {
10959f06c719SChuck Lever 	encode_diropargs3(xdr, args->fromfh, args->fromname, args->fromlen);
10969f06c719SChuck Lever 	encode_symlinkdata3(xdr, args);
1097d9c407b1SChuck Lever }
1098d9c407b1SChuck Lever 
1099d9c407b1SChuck Lever /*
1100d9c407b1SChuck Lever  * 3.3.11  MKNOD3args
1101d9c407b1SChuck Lever  *
1102d9c407b1SChuck Lever  *	struct devicedata3 {
1103d9c407b1SChuck Lever  *		sattr3		dev_attributes;
1104d9c407b1SChuck Lever  *		specdata3	spec;
1105d9c407b1SChuck Lever  *	};
1106d9c407b1SChuck Lever  *
1107d9c407b1SChuck Lever  *	union mknoddata3 switch (ftype3 type) {
1108d9c407b1SChuck Lever  *	case NF3CHR:
1109d9c407b1SChuck Lever  *	case NF3BLK:
1110d9c407b1SChuck Lever  *		devicedata3	device;
1111d9c407b1SChuck Lever  *	case NF3SOCK:
1112d9c407b1SChuck Lever  *	case NF3FIFO:
1113d9c407b1SChuck Lever  *		sattr3		pipe_attributes;
1114d9c407b1SChuck Lever  *	default:
1115d9c407b1SChuck Lever  *		void;
1116d9c407b1SChuck Lever  *	};
1117d9c407b1SChuck Lever  *
1118d9c407b1SChuck Lever  *	struct MKNOD3args {
1119d9c407b1SChuck Lever  *		diropargs3	where;
1120d9c407b1SChuck Lever  *		mknoddata3	what;
1121d9c407b1SChuck Lever  *	};
1122d9c407b1SChuck Lever  */
1123d9c407b1SChuck Lever static void encode_devicedata3(struct xdr_stream *xdr,
1124d9c407b1SChuck Lever 			       const struct nfs3_mknodargs *args)
1125d9c407b1SChuck Lever {
1126d9c407b1SChuck Lever 	encode_sattr3(xdr, args->sattr);
1127d9c407b1SChuck Lever 	encode_specdata3(xdr, args->rdev);
1128d9c407b1SChuck Lever }
1129d9c407b1SChuck Lever 
1130d9c407b1SChuck Lever static void encode_mknoddata3(struct xdr_stream *xdr,
1131d9c407b1SChuck Lever 			      const struct nfs3_mknodargs *args)
1132d9c407b1SChuck Lever {
1133d9c407b1SChuck Lever 	encode_ftype3(xdr, args->type);
1134d9c407b1SChuck Lever 	switch (args->type) {
1135d9c407b1SChuck Lever 	case NF3CHR:
1136d9c407b1SChuck Lever 	case NF3BLK:
1137d9c407b1SChuck Lever 		encode_devicedata3(xdr, args);
1138d9c407b1SChuck Lever 		break;
1139d9c407b1SChuck Lever 	case NF3SOCK:
1140d9c407b1SChuck Lever 	case NF3FIFO:
1141d9c407b1SChuck Lever 		encode_sattr3(xdr, args->sattr);
1142d9c407b1SChuck Lever 		break;
1143d9c407b1SChuck Lever 	case NF3REG:
1144d9c407b1SChuck Lever 	case NF3DIR:
1145d9c407b1SChuck Lever 		break;
1146d9c407b1SChuck Lever 	default:
1147d9c407b1SChuck Lever 		BUG();
1148d9c407b1SChuck Lever 	}
1149d9c407b1SChuck Lever }
1150d9c407b1SChuck Lever 
11519f06c719SChuck Lever static void nfs3_xdr_enc_mknod3args(struct rpc_rqst *req,
11529f06c719SChuck Lever 				    struct xdr_stream *xdr,
1153d9c407b1SChuck Lever 				    const struct nfs3_mknodargs *args)
1154d9c407b1SChuck Lever {
11559f06c719SChuck Lever 	encode_diropargs3(xdr, args->fh, args->name, args->len);
11569f06c719SChuck Lever 	encode_mknoddata3(xdr, args);
1157d9c407b1SChuck Lever }
1158d9c407b1SChuck Lever 
1159d9c407b1SChuck Lever /*
1160d9c407b1SChuck Lever  * 3.3.12  REMOVE3args
1161d9c407b1SChuck Lever  *
1162d9c407b1SChuck Lever  *	struct REMOVE3args {
1163d9c407b1SChuck Lever  *		diropargs3  object;
1164d9c407b1SChuck Lever  *	};
1165d9c407b1SChuck Lever  */
11669f06c719SChuck Lever static void nfs3_xdr_enc_remove3args(struct rpc_rqst *req,
11679f06c719SChuck Lever 				     struct xdr_stream *xdr,
1168d9c407b1SChuck Lever 				     const struct nfs_removeargs *args)
1169d9c407b1SChuck Lever {
11709f06c719SChuck Lever 	encode_diropargs3(xdr, args->fh, args->name.name, args->name.len);
1171d9c407b1SChuck Lever }
1172d9c407b1SChuck Lever 
1173d9c407b1SChuck Lever /*
1174d9c407b1SChuck Lever  * 3.3.14  RENAME3args
1175d9c407b1SChuck Lever  *
1176d9c407b1SChuck Lever  *	struct RENAME3args {
1177d9c407b1SChuck Lever  *		diropargs3	from;
1178d9c407b1SChuck Lever  *		diropargs3	to;
1179d9c407b1SChuck Lever  *	};
1180d9c407b1SChuck Lever  */
11819f06c719SChuck Lever static void nfs3_xdr_enc_rename3args(struct rpc_rqst *req,
11829f06c719SChuck Lever 				     struct xdr_stream *xdr,
1183d9c407b1SChuck Lever 				     const struct nfs_renameargs *args)
1184d9c407b1SChuck Lever {
1185d9c407b1SChuck Lever 	const struct qstr *old = args->old_name;
1186d9c407b1SChuck Lever 	const struct qstr *new = args->new_name;
1187d9c407b1SChuck Lever 
11889f06c719SChuck Lever 	encode_diropargs3(xdr, args->old_dir, old->name, old->len);
11899f06c719SChuck Lever 	encode_diropargs3(xdr, args->new_dir, new->name, new->len);
1190d9c407b1SChuck Lever }
1191d9c407b1SChuck Lever 
1192d9c407b1SChuck Lever /*
1193d9c407b1SChuck Lever  * 3.3.15  LINK3args
1194d9c407b1SChuck Lever  *
1195d9c407b1SChuck Lever  *	struct LINK3args {
1196d9c407b1SChuck Lever  *		nfs_fh3		file;
1197d9c407b1SChuck Lever  *		diropargs3	link;
1198d9c407b1SChuck Lever  *	};
1199d9c407b1SChuck Lever  */
12009f06c719SChuck Lever static void nfs3_xdr_enc_link3args(struct rpc_rqst *req,
12019f06c719SChuck Lever 				   struct xdr_stream *xdr,
1202d9c407b1SChuck Lever 				   const struct nfs3_linkargs *args)
1203d9c407b1SChuck Lever {
12049f06c719SChuck Lever 	encode_nfs_fh3(xdr, args->fromfh);
12059f06c719SChuck Lever 	encode_diropargs3(xdr, args->tofh, args->toname, args->tolen);
1206d9c407b1SChuck Lever }
1207d9c407b1SChuck Lever 
1208d9c407b1SChuck Lever /*
1209d9c407b1SChuck Lever  * 3.3.16  READDIR3args
1210d9c407b1SChuck Lever  *
1211d9c407b1SChuck Lever  *	struct READDIR3args {
1212d9c407b1SChuck Lever  *		nfs_fh3		dir;
1213d9c407b1SChuck Lever  *		cookie3		cookie;
1214d9c407b1SChuck Lever  *		cookieverf3	cookieverf;
1215d9c407b1SChuck Lever  *		count3		count;
1216d9c407b1SChuck Lever  *	};
1217d9c407b1SChuck Lever  */
1218d9c407b1SChuck Lever static void encode_readdir3args(struct xdr_stream *xdr,
1219d9c407b1SChuck Lever 				const struct nfs3_readdirargs *args)
1220d9c407b1SChuck Lever {
1221d9c407b1SChuck Lever 	__be32 *p;
1222d9c407b1SChuck Lever 
1223d9c407b1SChuck Lever 	encode_nfs_fh3(xdr, args->fh);
1224d9c407b1SChuck Lever 
1225d9c407b1SChuck Lever 	p = xdr_reserve_space(xdr, 8 + NFS3_COOKIEVERFSIZE + 4);
1226d9c407b1SChuck Lever 	p = xdr_encode_cookie3(p, args->cookie);
1227d9c407b1SChuck Lever 	p = xdr_encode_cookieverf3(p, args->verf);
1228d9c407b1SChuck Lever 	*p = cpu_to_be32(args->count);
1229d9c407b1SChuck Lever }
1230d9c407b1SChuck Lever 
12319f06c719SChuck Lever static void nfs3_xdr_enc_readdir3args(struct rpc_rqst *req,
12329f06c719SChuck Lever 				      struct xdr_stream *xdr,
1233d9c407b1SChuck Lever 				      const struct nfs3_readdirargs *args)
1234d9c407b1SChuck Lever {
12359f06c719SChuck Lever 	encode_readdir3args(xdr, args);
1236d9c407b1SChuck Lever 	prepare_reply_buffer(req, args->pages, 0,
1237d9c407b1SChuck Lever 				args->count, NFS3_readdirres_sz);
1238d9c407b1SChuck Lever }
1239d9c407b1SChuck Lever 
1240d9c407b1SChuck Lever /*
1241d9c407b1SChuck Lever  * 3.3.17  READDIRPLUS3args
1242d9c407b1SChuck Lever  *
1243d9c407b1SChuck Lever  *	struct READDIRPLUS3args {
1244d9c407b1SChuck Lever  *		nfs_fh3		dir;
1245d9c407b1SChuck Lever  *		cookie3		cookie;
1246d9c407b1SChuck Lever  *		cookieverf3	cookieverf;
1247d9c407b1SChuck Lever  *		count3		dircount;
1248d9c407b1SChuck Lever  *		count3		maxcount;
1249d9c407b1SChuck Lever  *	};
1250d9c407b1SChuck Lever  */
1251d9c407b1SChuck Lever static void encode_readdirplus3args(struct xdr_stream *xdr,
1252d9c407b1SChuck Lever 				    const struct nfs3_readdirargs *args)
1253d9c407b1SChuck Lever {
1254d9c407b1SChuck Lever 	__be32 *p;
1255d9c407b1SChuck Lever 
1256d9c407b1SChuck Lever 	encode_nfs_fh3(xdr, args->fh);
1257d9c407b1SChuck Lever 
1258d9c407b1SChuck Lever 	p = xdr_reserve_space(xdr, 8 + NFS3_COOKIEVERFSIZE + 4 + 4);
1259d9c407b1SChuck Lever 	p = xdr_encode_cookie3(p, args->cookie);
1260d9c407b1SChuck Lever 	p = xdr_encode_cookieverf3(p, args->verf);
1261d9c407b1SChuck Lever 
1262d9c407b1SChuck Lever 	/*
1263d9c407b1SChuck Lever 	 * readdirplus: need dircount + buffer size.
1264d9c407b1SChuck Lever 	 * We just make sure we make dircount big enough
1265d9c407b1SChuck Lever 	 */
1266d9c407b1SChuck Lever 	*p++ = cpu_to_be32(args->count >> 3);
1267d9c407b1SChuck Lever 
1268d9c407b1SChuck Lever 	*p = cpu_to_be32(args->count);
1269d9c407b1SChuck Lever }
1270d9c407b1SChuck Lever 
12719f06c719SChuck Lever static void nfs3_xdr_enc_readdirplus3args(struct rpc_rqst *req,
12729f06c719SChuck Lever 					  struct xdr_stream *xdr,
1273d9c407b1SChuck Lever 					  const struct nfs3_readdirargs *args)
1274d9c407b1SChuck Lever {
12759f06c719SChuck Lever 	encode_readdirplus3args(xdr, args);
1276d9c407b1SChuck Lever 	prepare_reply_buffer(req, args->pages, 0,
1277d9c407b1SChuck Lever 				args->count, NFS3_readdirres_sz);
1278d9c407b1SChuck Lever }
1279d9c407b1SChuck Lever 
1280d9c407b1SChuck Lever /*
1281d9c407b1SChuck Lever  * 3.3.21  COMMIT3args
1282d9c407b1SChuck Lever  *
1283d9c407b1SChuck Lever  *	struct COMMIT3args {
1284d9c407b1SChuck Lever  *		nfs_fh3		file;
1285d9c407b1SChuck Lever  *		offset3		offset;
1286d9c407b1SChuck Lever  *		count3		count;
1287d9c407b1SChuck Lever  *	};
1288d9c407b1SChuck Lever  */
1289d9c407b1SChuck Lever static void encode_commit3args(struct xdr_stream *xdr,
1290d9c407b1SChuck Lever 			       const struct nfs_writeargs *args)
1291d9c407b1SChuck Lever {
1292d9c407b1SChuck Lever 	__be32 *p;
1293d9c407b1SChuck Lever 
1294d9c407b1SChuck Lever 	encode_nfs_fh3(xdr, args->fh);
1295d9c407b1SChuck Lever 
1296d9c407b1SChuck Lever 	p = xdr_reserve_space(xdr, 8 + 4);
1297d9c407b1SChuck Lever 	p = xdr_encode_hyper(p, args->offset);
1298d9c407b1SChuck Lever 	*p = cpu_to_be32(args->count);
1299d9c407b1SChuck Lever }
1300d9c407b1SChuck Lever 
13019f06c719SChuck Lever static void nfs3_xdr_enc_commit3args(struct rpc_rqst *req,
13029f06c719SChuck Lever 				     struct xdr_stream *xdr,
1303d9c407b1SChuck Lever 				     const struct nfs_writeargs *args)
1304d9c407b1SChuck Lever {
13059f06c719SChuck Lever 	encode_commit3args(xdr, args);
1306d9c407b1SChuck Lever }
1307d9c407b1SChuck Lever 
1308b7fa0554SAndreas Gruenbacher #ifdef CONFIG_NFS_V3_ACL
1309b7fa0554SAndreas Gruenbacher 
13109f06c719SChuck Lever static void nfs3_xdr_enc_getacl3args(struct rpc_rqst *req,
13119f06c719SChuck Lever 				     struct xdr_stream *xdr,
1312d9c407b1SChuck Lever 				     const struct nfs3_getaclargs *args)
1313d9c407b1SChuck Lever {
13149f06c719SChuck Lever 	encode_nfs_fh3(xdr, args->fh);
13159f06c719SChuck Lever 	encode_uint32(xdr, args->mask);
1316d9c407b1SChuck Lever 	if (args->mask & (NFS_ACL | NFS_DFACL))
1317d9c407b1SChuck Lever 		prepare_reply_buffer(req, args->pages, 0,
1318d9c407b1SChuck Lever 					NFSACL_MAXPAGES << PAGE_SHIFT,
1319d9c407b1SChuck Lever 					ACL3_getaclres_sz);
1320d9c407b1SChuck Lever }
1321d9c407b1SChuck Lever 
13229f06c719SChuck Lever static void nfs3_xdr_enc_setacl3args(struct rpc_rqst *req,
13239f06c719SChuck Lever 				     struct xdr_stream *xdr,
1324d9c407b1SChuck Lever 				     const struct nfs3_setaclargs *args)
1325d9c407b1SChuck Lever {
1326d9c407b1SChuck Lever 	unsigned int base;
1327d9c407b1SChuck Lever 	int error;
1328d9c407b1SChuck Lever 
13299f06c719SChuck Lever 	encode_nfs_fh3(xdr, NFS_FH(args->inode));
13309f06c719SChuck Lever 	encode_uint32(xdr, args->mask);
1331d9c407b1SChuck Lever 	if (args->npages != 0)
13329f06c719SChuck Lever 		xdr_write_pages(xdr, args->pages, 0, args->len);
1333d9c407b1SChuck Lever 
1334d9c407b1SChuck Lever 	base = req->rq_slen;
13359f06c719SChuck Lever 	error = nfsacl_encode(xdr->buf, base, args->inode,
1336d9c407b1SChuck Lever 			    (args->mask & NFS_ACL) ?
1337d9c407b1SChuck Lever 			    args->acl_access : NULL, 1, 0);
1338d9c407b1SChuck Lever 	BUG_ON(error < 0);
13399f06c719SChuck Lever 	error = nfsacl_encode(xdr->buf, base + error, args->inode,
1340d9c407b1SChuck Lever 			    (args->mask & NFS_DFACL) ?
1341d9c407b1SChuck Lever 			    args->acl_default : NULL, 1,
1342d9c407b1SChuck Lever 			    NFS_ACL_DEFAULT);
1343d9c407b1SChuck Lever 	BUG_ON(error < 0);
1344d9c407b1SChuck Lever }
1345d9c407b1SChuck Lever 
1346b7fa0554SAndreas Gruenbacher #endif  /* CONFIG_NFS_V3_ACL */
1347b7fa0554SAndreas Gruenbacher 
13481da177e4SLinus Torvalds /*
1349b2cdd9c9SChuck Lever  * NFSv3 XDR decode functions
1350b2cdd9c9SChuck Lever  *
1351b2cdd9c9SChuck Lever  * NFSv3 result types are defined in section 3.3 of RFC 1813:
1352b2cdd9c9SChuck Lever  * "NFS Version 3 Protocol Specification".
13531da177e4SLinus Torvalds  */
13541da177e4SLinus Torvalds 
13551da177e4SLinus Torvalds /*
1356e4f93234SChuck Lever  * 3.3.1  GETATTR3res
1357e4f93234SChuck Lever  *
1358e4f93234SChuck Lever  *	struct GETATTR3resok {
1359e4f93234SChuck Lever  *		fattr3		obj_attributes;
1360e4f93234SChuck Lever  *	};
1361e4f93234SChuck Lever  *
1362e4f93234SChuck Lever  *	union GETATTR3res switch (nfsstat3 status) {
1363e4f93234SChuck Lever  *	case NFS3_OK:
1364e4f93234SChuck Lever  *		GETATTR3resok  resok;
1365e4f93234SChuck Lever  *	default:
1366e4f93234SChuck Lever  *		void;
1367e4f93234SChuck Lever  *	};
1368e4f93234SChuck Lever  */
1369bf269551SChuck Lever static int nfs3_xdr_dec_getattr3res(struct rpc_rqst *req,
1370bf269551SChuck Lever 				    struct xdr_stream *xdr,
1371e4f93234SChuck Lever 				    struct nfs_fattr *result)
1372e4f93234SChuck Lever {
1373e4f93234SChuck Lever 	enum nfs_stat status;
1374e4f93234SChuck Lever 	int error;
1375e4f93234SChuck Lever 
1376bf269551SChuck Lever 	error = decode_nfsstat3(xdr, &status);
1377e4f93234SChuck Lever 	if (unlikely(error))
1378e4f93234SChuck Lever 		goto out;
1379e4f93234SChuck Lever 	if (status != NFS3_OK)
1380e4f93234SChuck Lever 		goto out_default;
1381bf269551SChuck Lever 	error = decode_fattr3(xdr, result);
1382e4f93234SChuck Lever out:
1383e4f93234SChuck Lever 	return error;
1384e4f93234SChuck Lever out_default:
1385e4f93234SChuck Lever 	return nfs_stat_to_errno(status);
1386e4f93234SChuck Lever }
1387e4f93234SChuck Lever 
1388e4f93234SChuck Lever /*
1389e4f93234SChuck Lever  * 3.3.2  SETATTR3res
1390e4f93234SChuck Lever  *
1391e4f93234SChuck Lever  *	struct SETATTR3resok {
1392e4f93234SChuck Lever  *		wcc_data  obj_wcc;
1393e4f93234SChuck Lever  *	};
1394e4f93234SChuck Lever  *
1395e4f93234SChuck Lever  *	struct SETATTR3resfail {
1396e4f93234SChuck Lever  *		wcc_data  obj_wcc;
1397e4f93234SChuck Lever  *	};
1398e4f93234SChuck Lever  *
1399e4f93234SChuck Lever  *	union SETATTR3res switch (nfsstat3 status) {
1400e4f93234SChuck Lever  *	case NFS3_OK:
1401e4f93234SChuck Lever  *		SETATTR3resok   resok;
1402e4f93234SChuck Lever  *	default:
1403e4f93234SChuck Lever  *		SETATTR3resfail resfail;
1404e4f93234SChuck Lever  *	};
1405e4f93234SChuck Lever  */
1406bf269551SChuck Lever static int nfs3_xdr_dec_setattr3res(struct rpc_rqst *req,
1407bf269551SChuck Lever 				    struct xdr_stream *xdr,
1408e4f93234SChuck Lever 				    struct nfs_fattr *result)
1409e4f93234SChuck Lever {
1410e4f93234SChuck Lever 	enum nfs_stat status;
1411e4f93234SChuck Lever 	int error;
1412e4f93234SChuck Lever 
1413bf269551SChuck Lever 	error = decode_nfsstat3(xdr, &status);
1414e4f93234SChuck Lever 	if (unlikely(error))
1415e4f93234SChuck Lever 		goto out;
1416bf269551SChuck Lever 	error = decode_wcc_data(xdr, result);
1417e4f93234SChuck Lever 	if (unlikely(error))
1418e4f93234SChuck Lever 		goto out;
1419e4f93234SChuck Lever 	if (status != NFS3_OK)
1420e4f93234SChuck Lever 		goto out_status;
1421e4f93234SChuck Lever out:
1422e4f93234SChuck Lever 	return error;
1423e4f93234SChuck Lever out_status:
1424e4f93234SChuck Lever 	return nfs_stat_to_errno(status);
1425e4f93234SChuck Lever }
1426e4f93234SChuck Lever 
14271da177e4SLinus Torvalds /*
1428e4f93234SChuck Lever  * 3.3.3  LOOKUP3res
1429e4f93234SChuck Lever  *
1430e4f93234SChuck Lever  *	struct LOOKUP3resok {
1431e4f93234SChuck Lever  *		nfs_fh3		object;
1432e4f93234SChuck Lever  *		post_op_attr	obj_attributes;
1433e4f93234SChuck Lever  *		post_op_attr	dir_attributes;
1434e4f93234SChuck Lever  *	};
1435e4f93234SChuck Lever  *
1436e4f93234SChuck Lever  *	struct LOOKUP3resfail {
1437e4f93234SChuck Lever  *		post_op_attr	dir_attributes;
1438e4f93234SChuck Lever  *	};
1439e4f93234SChuck Lever  *
1440e4f93234SChuck Lever  *	union LOOKUP3res switch (nfsstat3 status) {
1441e4f93234SChuck Lever  *	case NFS3_OK:
1442e4f93234SChuck Lever  *		LOOKUP3resok	resok;
1443e4f93234SChuck Lever  *	default:
1444e4f93234SChuck Lever  *		LOOKUP3resfail	resfail;
1445e4f93234SChuck Lever  *	};
1446e4f93234SChuck Lever  */
1447bf269551SChuck Lever static int nfs3_xdr_dec_lookup3res(struct rpc_rqst *req,
1448bf269551SChuck Lever 				   struct xdr_stream *xdr,
1449e4f93234SChuck Lever 				   struct nfs3_diropres *result)
1450e4f93234SChuck Lever {
1451e4f93234SChuck Lever 	enum nfs_stat status;
1452e4f93234SChuck Lever 	int error;
1453e4f93234SChuck Lever 
1454bf269551SChuck Lever 	error = decode_nfsstat3(xdr, &status);
1455e4f93234SChuck Lever 	if (unlikely(error))
1456e4f93234SChuck Lever 		goto out;
1457e4f93234SChuck Lever 	if (status != NFS3_OK)
1458e4f93234SChuck Lever 		goto out_default;
1459bf269551SChuck Lever 	error = decode_nfs_fh3(xdr, result->fh);
1460e4f93234SChuck Lever 	if (unlikely(error))
1461e4f93234SChuck Lever 		goto out;
1462bf269551SChuck Lever 	error = decode_post_op_attr(xdr, result->fattr);
1463e4f93234SChuck Lever 	if (unlikely(error))
1464e4f93234SChuck Lever 		goto out;
1465bf269551SChuck Lever 	error = decode_post_op_attr(xdr, result->dir_attr);
1466e4f93234SChuck Lever out:
1467e4f93234SChuck Lever 	return error;
1468e4f93234SChuck Lever out_default:
1469bf269551SChuck Lever 	error = decode_post_op_attr(xdr, result->dir_attr);
1470e4f93234SChuck Lever 	if (unlikely(error))
1471e4f93234SChuck Lever 		goto out;
1472e4f93234SChuck Lever 	return nfs_stat_to_errno(status);
1473e4f93234SChuck Lever }
1474e4f93234SChuck Lever 
1475e4f93234SChuck Lever /*
1476e4f93234SChuck Lever  * 3.3.4  ACCESS3res
1477e4f93234SChuck Lever  *
1478e4f93234SChuck Lever  *	struct ACCESS3resok {
1479e4f93234SChuck Lever  *		post_op_attr	obj_attributes;
1480e4f93234SChuck Lever  *		uint32		access;
1481e4f93234SChuck Lever  *	};
1482e4f93234SChuck Lever  *
1483e4f93234SChuck Lever  *	struct ACCESS3resfail {
1484e4f93234SChuck Lever  *		post_op_attr	obj_attributes;
1485e4f93234SChuck Lever  *	};
1486e4f93234SChuck Lever  *
1487e4f93234SChuck Lever  *	union ACCESS3res switch (nfsstat3 status) {
1488e4f93234SChuck Lever  *	case NFS3_OK:
1489e4f93234SChuck Lever  *		ACCESS3resok	resok;
1490e4f93234SChuck Lever  *	default:
1491e4f93234SChuck Lever  *		ACCESS3resfail	resfail;
1492e4f93234SChuck Lever  *	};
1493e4f93234SChuck Lever  */
1494bf269551SChuck Lever static int nfs3_xdr_dec_access3res(struct rpc_rqst *req,
1495bf269551SChuck Lever 				   struct xdr_stream *xdr,
1496e4f93234SChuck Lever 				   struct nfs3_accessres *result)
1497e4f93234SChuck Lever {
1498e4f93234SChuck Lever 	enum nfs_stat status;
1499e4f93234SChuck Lever 	int error;
1500e4f93234SChuck Lever 
1501bf269551SChuck Lever 	error = decode_nfsstat3(xdr, &status);
1502e4f93234SChuck Lever 	if (unlikely(error))
1503e4f93234SChuck Lever 		goto out;
1504bf269551SChuck Lever 	error = decode_post_op_attr(xdr, result->fattr);
1505e4f93234SChuck Lever 	if (unlikely(error))
1506e4f93234SChuck Lever 		goto out;
1507e4f93234SChuck Lever 	if (status != NFS3_OK)
1508e4f93234SChuck Lever 		goto out_default;
1509bf269551SChuck Lever 	error = decode_uint32(xdr, &result->access);
1510e4f93234SChuck Lever out:
1511e4f93234SChuck Lever 	return error;
1512e4f93234SChuck Lever out_default:
1513e4f93234SChuck Lever 	return nfs_stat_to_errno(status);
1514e4f93234SChuck Lever }
1515e4f93234SChuck Lever 
1516e4f93234SChuck Lever /*
1517e4f93234SChuck Lever  * 3.3.5  READLINK3res
1518e4f93234SChuck Lever  *
1519e4f93234SChuck Lever  *	struct READLINK3resok {
1520e4f93234SChuck Lever  *		post_op_attr	symlink_attributes;
1521e4f93234SChuck Lever  *		nfspath3	data;
1522e4f93234SChuck Lever  *	};
1523e4f93234SChuck Lever  *
1524e4f93234SChuck Lever  *	struct READLINK3resfail {
1525e4f93234SChuck Lever  *		post_op_attr	symlink_attributes;
1526e4f93234SChuck Lever  *	};
1527e4f93234SChuck Lever  *
1528e4f93234SChuck Lever  *	union READLINK3res switch (nfsstat3 status) {
1529e4f93234SChuck Lever  *	case NFS3_OK:
1530e4f93234SChuck Lever  *		READLINK3resok	resok;
1531e4f93234SChuck Lever  *	default:
1532e4f93234SChuck Lever  *		READLINK3resfail resfail;
1533e4f93234SChuck Lever  *	};
1534e4f93234SChuck Lever  */
1535bf269551SChuck Lever static int nfs3_xdr_dec_readlink3res(struct rpc_rqst *req,
1536bf269551SChuck Lever 				     struct xdr_stream *xdr,
1537e4f93234SChuck Lever 				     struct nfs_fattr *result)
1538e4f93234SChuck Lever {
1539e4f93234SChuck Lever 	enum nfs_stat status;
1540e4f93234SChuck Lever 	int error;
1541e4f93234SChuck Lever 
1542bf269551SChuck Lever 	error = decode_nfsstat3(xdr, &status);
1543e4f93234SChuck Lever 	if (unlikely(error))
1544e4f93234SChuck Lever 		goto out;
1545bf269551SChuck Lever 	error = decode_post_op_attr(xdr, result);
1546e4f93234SChuck Lever 	if (unlikely(error))
1547e4f93234SChuck Lever 		goto out;
1548e4f93234SChuck Lever 	if (status != NFS3_OK)
1549e4f93234SChuck Lever 		goto out_default;
1550bf269551SChuck Lever 	error = decode_nfspath3(xdr);
1551e4f93234SChuck Lever out:
1552e4f93234SChuck Lever 	return error;
1553e4f93234SChuck Lever out_default:
1554e4f93234SChuck Lever 	return nfs_stat_to_errno(status);
1555e4f93234SChuck Lever }
1556e4f93234SChuck Lever 
1557e4f93234SChuck Lever /*
1558e4f93234SChuck Lever  * 3.3.6  READ3res
1559e4f93234SChuck Lever  *
1560e4f93234SChuck Lever  *	struct READ3resok {
1561e4f93234SChuck Lever  *		post_op_attr	file_attributes;
1562e4f93234SChuck Lever  *		count3		count;
1563e4f93234SChuck Lever  *		bool		eof;
1564e4f93234SChuck Lever  *		opaque		data<>;
1565e4f93234SChuck Lever  *	};
1566e4f93234SChuck Lever  *
1567e4f93234SChuck Lever  *	struct READ3resfail {
1568e4f93234SChuck Lever  *		post_op_attr	file_attributes;
1569e4f93234SChuck Lever  *	};
1570e4f93234SChuck Lever  *
1571e4f93234SChuck Lever  *	union READ3res switch (nfsstat3 status) {
1572e4f93234SChuck Lever  *	case NFS3_OK:
1573e4f93234SChuck Lever  *		READ3resok	resok;
1574e4f93234SChuck Lever  *	default:
1575e4f93234SChuck Lever  *		READ3resfail	resfail;
1576e4f93234SChuck Lever  *	};
1577e4f93234SChuck Lever  */
1578e4f93234SChuck Lever static int decode_read3resok(struct xdr_stream *xdr,
1579e4f93234SChuck Lever 			     struct nfs_readres *result)
1580e4f93234SChuck Lever {
1581e4f93234SChuck Lever 	u32 eof, count, ocount, recvd;
1582e4f93234SChuck Lever 	size_t hdrlen;
1583e4f93234SChuck Lever 	__be32 *p;
1584e4f93234SChuck Lever 
1585e4f93234SChuck Lever 	p = xdr_inline_decode(xdr, 4 + 4 + 4);
1586e4f93234SChuck Lever 	if (unlikely(p == NULL))
1587e4f93234SChuck Lever 		goto out_overflow;
1588e4f93234SChuck Lever 	count = be32_to_cpup(p++);
1589e4f93234SChuck Lever 	eof = be32_to_cpup(p++);
1590e4f93234SChuck Lever 	ocount = be32_to_cpup(p++);
1591e4f93234SChuck Lever 	if (unlikely(ocount != count))
1592e4f93234SChuck Lever 		goto out_mismatch;
1593e4f93234SChuck Lever 	hdrlen = (u8 *)xdr->p - (u8 *)xdr->iov->iov_base;
1594e4f93234SChuck Lever 	recvd = xdr->buf->len - hdrlen;
1595e4f93234SChuck Lever 	if (unlikely(count > recvd))
1596e4f93234SChuck Lever 		goto out_cheating;
1597e4f93234SChuck Lever 
1598e4f93234SChuck Lever out:
1599e4f93234SChuck Lever 	xdr_read_pages(xdr, count);
1600e4f93234SChuck Lever 	result->eof = eof;
1601e4f93234SChuck Lever 	result->count = count;
1602e4f93234SChuck Lever 	return count;
1603e4f93234SChuck Lever out_mismatch:
1604e4f93234SChuck Lever 	dprintk("NFS: READ count doesn't match length of opaque: "
1605e4f93234SChuck Lever 		"count %u != ocount %u\n", count, ocount);
1606e4f93234SChuck Lever 	return -EIO;
1607e4f93234SChuck Lever out_cheating:
1608e4f93234SChuck Lever 	dprintk("NFS: server cheating in read result: "
1609e4f93234SChuck Lever 		"count %u > recvd %u\n", count, recvd);
1610e4f93234SChuck Lever 	count = recvd;
1611e4f93234SChuck Lever 	eof = 0;
1612e4f93234SChuck Lever 	goto out;
1613e4f93234SChuck Lever out_overflow:
1614e4f93234SChuck Lever 	print_overflow_msg(__func__, xdr);
1615e4f93234SChuck Lever 	return -EIO;
1616e4f93234SChuck Lever }
1617e4f93234SChuck Lever 
1618bf269551SChuck Lever static int nfs3_xdr_dec_read3res(struct rpc_rqst *req, struct xdr_stream *xdr,
1619e4f93234SChuck Lever 				 struct nfs_readres *result)
1620e4f93234SChuck Lever {
1621e4f93234SChuck Lever 	enum nfs_stat status;
1622e4f93234SChuck Lever 	int error;
1623e4f93234SChuck Lever 
1624bf269551SChuck Lever 	error = decode_nfsstat3(xdr, &status);
1625e4f93234SChuck Lever 	if (unlikely(error))
1626e4f93234SChuck Lever 		goto out;
1627bf269551SChuck Lever 	error = decode_post_op_attr(xdr, result->fattr);
1628e4f93234SChuck Lever 	if (unlikely(error))
1629e4f93234SChuck Lever 		goto out;
1630e4f93234SChuck Lever 	if (status != NFS3_OK)
1631e4f93234SChuck Lever 		goto out_status;
1632bf269551SChuck Lever 	error = decode_read3resok(xdr, result);
1633e4f93234SChuck Lever out:
1634e4f93234SChuck Lever 	return error;
1635e4f93234SChuck Lever out_status:
1636e4f93234SChuck Lever 	return nfs_stat_to_errno(status);
1637e4f93234SChuck Lever }
1638e4f93234SChuck Lever 
1639e4f93234SChuck Lever /*
1640e4f93234SChuck Lever  * 3.3.7  WRITE3res
1641e4f93234SChuck Lever  *
1642e4f93234SChuck Lever  *	enum stable_how {
1643e4f93234SChuck Lever  *		UNSTABLE  = 0,
1644e4f93234SChuck Lever  *		DATA_SYNC = 1,
1645e4f93234SChuck Lever  *		FILE_SYNC = 2
1646e4f93234SChuck Lever  *	};
1647e4f93234SChuck Lever  *
1648e4f93234SChuck Lever  *	struct WRITE3resok {
1649e4f93234SChuck Lever  *		wcc_data	file_wcc;
1650e4f93234SChuck Lever  *		count3		count;
1651e4f93234SChuck Lever  *		stable_how	committed;
1652e4f93234SChuck Lever  *		writeverf3	verf;
1653e4f93234SChuck Lever  *	};
1654e4f93234SChuck Lever  *
1655e4f93234SChuck Lever  *	struct WRITE3resfail {
1656e4f93234SChuck Lever  *		wcc_data	file_wcc;
1657e4f93234SChuck Lever  *	};
1658e4f93234SChuck Lever  *
1659e4f93234SChuck Lever  *	union WRITE3res switch (nfsstat3 status) {
1660e4f93234SChuck Lever  *	case NFS3_OK:
1661e4f93234SChuck Lever  *		WRITE3resok	resok;
1662e4f93234SChuck Lever  *	default:
1663e4f93234SChuck Lever  *		WRITE3resfail	resfail;
1664e4f93234SChuck Lever  *	};
1665e4f93234SChuck Lever  */
1666e4f93234SChuck Lever static int decode_write3resok(struct xdr_stream *xdr,
1667e4f93234SChuck Lever 			      struct nfs_writeres *result)
1668e4f93234SChuck Lever {
1669e4f93234SChuck Lever 	__be32 *p;
1670e4f93234SChuck Lever 
1671e4f93234SChuck Lever 	p = xdr_inline_decode(xdr, 4 + 4 + NFS3_WRITEVERFSIZE);
1672e4f93234SChuck Lever 	if (unlikely(p == NULL))
1673e4f93234SChuck Lever 		goto out_overflow;
1674e4f93234SChuck Lever 	result->count = be32_to_cpup(p++);
1675e4f93234SChuck Lever 	result->verf->committed = be32_to_cpup(p++);
1676e4f93234SChuck Lever 	if (unlikely(result->verf->committed > NFS_FILE_SYNC))
1677e4f93234SChuck Lever 		goto out_badvalue;
1678e4f93234SChuck Lever 	memcpy(result->verf->verifier, p, NFS3_WRITEVERFSIZE);
1679e4f93234SChuck Lever 	return result->count;
1680e4f93234SChuck Lever out_badvalue:
1681e4f93234SChuck Lever 	dprintk("NFS: bad stable_how value: %u\n", result->verf->committed);
1682e4f93234SChuck Lever 	return -EIO;
1683e4f93234SChuck Lever out_overflow:
1684e4f93234SChuck Lever 	print_overflow_msg(__func__, xdr);
1685e4f93234SChuck Lever 	return -EIO;
1686e4f93234SChuck Lever }
1687e4f93234SChuck Lever 
1688bf269551SChuck Lever static int nfs3_xdr_dec_write3res(struct rpc_rqst *req, struct xdr_stream *xdr,
1689e4f93234SChuck Lever 				  struct nfs_writeres *result)
1690e4f93234SChuck Lever {
1691e4f93234SChuck Lever 	enum nfs_stat status;
1692e4f93234SChuck Lever 	int error;
1693e4f93234SChuck Lever 
1694bf269551SChuck Lever 	error = decode_nfsstat3(xdr, &status);
1695e4f93234SChuck Lever 	if (unlikely(error))
1696e4f93234SChuck Lever 		goto out;
1697bf269551SChuck Lever 	error = decode_wcc_data(xdr, result->fattr);
1698e4f93234SChuck Lever 	if (unlikely(error))
1699e4f93234SChuck Lever 		goto out;
1700e4f93234SChuck Lever 	if (status != NFS3_OK)
1701e4f93234SChuck Lever 		goto out_status;
1702bf269551SChuck Lever 	error = decode_write3resok(xdr, result);
1703e4f93234SChuck Lever out:
1704e4f93234SChuck Lever 	return error;
1705e4f93234SChuck Lever out_status:
1706e4f93234SChuck Lever 	return nfs_stat_to_errno(status);
1707e4f93234SChuck Lever }
1708e4f93234SChuck Lever 
1709e4f93234SChuck Lever /*
1710e4f93234SChuck Lever  * 3.3.8  CREATE3res
1711e4f93234SChuck Lever  *
1712e4f93234SChuck Lever  *	struct CREATE3resok {
1713e4f93234SChuck Lever  *		post_op_fh3	obj;
1714e4f93234SChuck Lever  *		post_op_attr	obj_attributes;
1715e4f93234SChuck Lever  *		wcc_data	dir_wcc;
1716e4f93234SChuck Lever  *	};
1717e4f93234SChuck Lever  *
1718e4f93234SChuck Lever  *	struct CREATE3resfail {
1719e4f93234SChuck Lever  *		wcc_data	dir_wcc;
1720e4f93234SChuck Lever  *	};
1721e4f93234SChuck Lever  *
1722e4f93234SChuck Lever  *	union CREATE3res switch (nfsstat3 status) {
1723e4f93234SChuck Lever  *	case NFS3_OK:
1724e4f93234SChuck Lever  *		CREATE3resok	resok;
1725e4f93234SChuck Lever  *	default:
1726e4f93234SChuck Lever  *		CREATE3resfail	resfail;
1727e4f93234SChuck Lever  *	};
1728e4f93234SChuck Lever  */
1729e4f93234SChuck Lever static int decode_create3resok(struct xdr_stream *xdr,
1730e4f93234SChuck Lever 			       struct nfs3_diropres *result)
1731e4f93234SChuck Lever {
1732e4f93234SChuck Lever 	int error;
1733e4f93234SChuck Lever 
1734e4f93234SChuck Lever 	error = decode_post_op_fh3(xdr, result->fh);
1735e4f93234SChuck Lever 	if (unlikely(error))
1736e4f93234SChuck Lever 		goto out;
1737e4f93234SChuck Lever 	error = decode_post_op_attr(xdr, result->fattr);
1738e4f93234SChuck Lever 	if (unlikely(error))
1739e4f93234SChuck Lever 		goto out;
1740e4f93234SChuck Lever 	/* The server isn't required to return a file handle.
1741e4f93234SChuck Lever 	 * If it didn't, force the client to perform a LOOKUP
1742e4f93234SChuck Lever 	 * to determine the correct file handle and attribute
1743e4f93234SChuck Lever 	 * values for the new object. */
1744e4f93234SChuck Lever 	if (result->fh->size == 0)
1745e4f93234SChuck Lever 		result->fattr->valid = 0;
1746e4f93234SChuck Lever 	error = decode_wcc_data(xdr, result->dir_attr);
1747e4f93234SChuck Lever out:
1748e4f93234SChuck Lever 	return error;
1749e4f93234SChuck Lever }
1750e4f93234SChuck Lever 
1751bf269551SChuck Lever static int nfs3_xdr_dec_create3res(struct rpc_rqst *req,
1752bf269551SChuck Lever 				   struct xdr_stream *xdr,
1753e4f93234SChuck Lever 				   struct nfs3_diropres *result)
1754e4f93234SChuck Lever {
1755e4f93234SChuck Lever 	enum nfs_stat status;
1756e4f93234SChuck Lever 	int error;
1757e4f93234SChuck Lever 
1758bf269551SChuck Lever 	error = decode_nfsstat3(xdr, &status);
1759e4f93234SChuck Lever 	if (unlikely(error))
1760e4f93234SChuck Lever 		goto out;
1761e4f93234SChuck Lever 	if (status != NFS3_OK)
1762e4f93234SChuck Lever 		goto out_default;
1763bf269551SChuck Lever 	error = decode_create3resok(xdr, result);
1764e4f93234SChuck Lever out:
1765e4f93234SChuck Lever 	return error;
1766e4f93234SChuck Lever out_default:
1767bf269551SChuck Lever 	error = decode_wcc_data(xdr, result->dir_attr);
1768e4f93234SChuck Lever 	if (unlikely(error))
1769e4f93234SChuck Lever 		goto out;
1770e4f93234SChuck Lever 	return nfs_stat_to_errno(status);
1771e4f93234SChuck Lever }
1772e4f93234SChuck Lever 
1773e4f93234SChuck Lever /*
1774e4f93234SChuck Lever  * 3.3.12  REMOVE3res
1775e4f93234SChuck Lever  *
1776e4f93234SChuck Lever  *	struct REMOVE3resok {
1777e4f93234SChuck Lever  *		wcc_data    dir_wcc;
1778e4f93234SChuck Lever  *	};
1779e4f93234SChuck Lever  *
1780e4f93234SChuck Lever  *	struct REMOVE3resfail {
1781e4f93234SChuck Lever  *		wcc_data    dir_wcc;
1782e4f93234SChuck Lever  *	};
1783e4f93234SChuck Lever  *
1784e4f93234SChuck Lever  *	union REMOVE3res switch (nfsstat3 status) {
1785e4f93234SChuck Lever  *	case NFS3_OK:
1786e4f93234SChuck Lever  *		REMOVE3resok   resok;
1787e4f93234SChuck Lever  *	default:
1788e4f93234SChuck Lever  *		REMOVE3resfail resfail;
1789e4f93234SChuck Lever  *	};
1790e4f93234SChuck Lever  */
1791bf269551SChuck Lever static int nfs3_xdr_dec_remove3res(struct rpc_rqst *req,
1792bf269551SChuck Lever 				   struct xdr_stream *xdr,
1793e4f93234SChuck Lever 				   struct nfs_removeres *result)
1794e4f93234SChuck Lever {
1795e4f93234SChuck Lever 	enum nfs_stat status;
1796e4f93234SChuck Lever 	int error;
1797e4f93234SChuck Lever 
1798bf269551SChuck Lever 	error = decode_nfsstat3(xdr, &status);
1799e4f93234SChuck Lever 	if (unlikely(error))
1800e4f93234SChuck Lever 		goto out;
1801bf269551SChuck Lever 	error = decode_wcc_data(xdr, result->dir_attr);
1802e4f93234SChuck Lever 	if (unlikely(error))
1803e4f93234SChuck Lever 		goto out;
1804e4f93234SChuck Lever 	if (status != NFS3_OK)
1805e4f93234SChuck Lever 		goto out_status;
1806e4f93234SChuck Lever out:
1807e4f93234SChuck Lever 	return error;
1808e4f93234SChuck Lever out_status:
1809e4f93234SChuck Lever 	return nfs_stat_to_errno(status);
1810e4f93234SChuck Lever }
1811e4f93234SChuck Lever 
1812e4f93234SChuck Lever /*
1813e4f93234SChuck Lever  * 3.3.14  RENAME3res
1814e4f93234SChuck Lever  *
1815e4f93234SChuck Lever  *	struct RENAME3resok {
1816e4f93234SChuck Lever  *		wcc_data	fromdir_wcc;
1817e4f93234SChuck Lever  *		wcc_data	todir_wcc;
1818e4f93234SChuck Lever  *	};
1819e4f93234SChuck Lever  *
1820e4f93234SChuck Lever  *	struct RENAME3resfail {
1821e4f93234SChuck Lever  *		wcc_data	fromdir_wcc;
1822e4f93234SChuck Lever  *		wcc_data	todir_wcc;
1823e4f93234SChuck Lever  *	};
1824e4f93234SChuck Lever  *
1825e4f93234SChuck Lever  *	union RENAME3res switch (nfsstat3 status) {
1826e4f93234SChuck Lever  *	case NFS3_OK:
1827e4f93234SChuck Lever  *		RENAME3resok   resok;
1828e4f93234SChuck Lever  *	default:
1829e4f93234SChuck Lever  *		RENAME3resfail resfail;
1830e4f93234SChuck Lever  *	};
1831e4f93234SChuck Lever  */
1832bf269551SChuck Lever static int nfs3_xdr_dec_rename3res(struct rpc_rqst *req,
1833bf269551SChuck Lever 				   struct xdr_stream *xdr,
1834e4f93234SChuck Lever 				   struct nfs_renameres *result)
1835e4f93234SChuck Lever {
1836e4f93234SChuck Lever 	enum nfs_stat status;
1837e4f93234SChuck Lever 	int error;
1838e4f93234SChuck Lever 
1839bf269551SChuck Lever 	error = decode_nfsstat3(xdr, &status);
1840e4f93234SChuck Lever 	if (unlikely(error))
1841e4f93234SChuck Lever 		goto out;
1842bf269551SChuck Lever 	error = decode_wcc_data(xdr, result->old_fattr);
1843e4f93234SChuck Lever 	if (unlikely(error))
1844e4f93234SChuck Lever 		goto out;
1845bf269551SChuck Lever 	error = decode_wcc_data(xdr, result->new_fattr);
1846e4f93234SChuck Lever 	if (unlikely(error))
1847e4f93234SChuck Lever 		goto out;
1848e4f93234SChuck Lever 	if (status != NFS3_OK)
1849e4f93234SChuck Lever 		goto out_status;
1850e4f93234SChuck Lever out:
1851e4f93234SChuck Lever 	return error;
1852e4f93234SChuck Lever out_status:
1853e4f93234SChuck Lever 	return nfs_stat_to_errno(status);
1854e4f93234SChuck Lever }
1855e4f93234SChuck Lever 
1856e4f93234SChuck Lever /*
1857e4f93234SChuck Lever  * 3.3.15  LINK3res
1858e4f93234SChuck Lever  *
1859e4f93234SChuck Lever  *	struct LINK3resok {
1860e4f93234SChuck Lever  *		post_op_attr	file_attributes;
1861e4f93234SChuck Lever  *		wcc_data	linkdir_wcc;
1862e4f93234SChuck Lever  *	};
1863e4f93234SChuck Lever  *
1864e4f93234SChuck Lever  *	struct LINK3resfail {
1865e4f93234SChuck Lever  *		post_op_attr	file_attributes;
1866e4f93234SChuck Lever  *		wcc_data	linkdir_wcc;
1867e4f93234SChuck Lever  *	};
1868e4f93234SChuck Lever  *
1869e4f93234SChuck Lever  *	union LINK3res switch (nfsstat3 status) {
1870e4f93234SChuck Lever  *	case NFS3_OK:
1871e4f93234SChuck Lever  *		LINK3resok	resok;
1872e4f93234SChuck Lever  *	default:
1873e4f93234SChuck Lever  *		LINK3resfail	resfail;
1874e4f93234SChuck Lever  *	};
1875e4f93234SChuck Lever  */
1876bf269551SChuck Lever static int nfs3_xdr_dec_link3res(struct rpc_rqst *req, struct xdr_stream *xdr,
1877e4f93234SChuck Lever 				 struct nfs3_linkres *result)
1878e4f93234SChuck Lever {
1879e4f93234SChuck Lever 	enum nfs_stat status;
1880e4f93234SChuck Lever 	int error;
1881e4f93234SChuck Lever 
1882bf269551SChuck Lever 	error = decode_nfsstat3(xdr, &status);
1883e4f93234SChuck Lever 	if (unlikely(error))
1884e4f93234SChuck Lever 		goto out;
1885bf269551SChuck Lever 	error = decode_post_op_attr(xdr, result->fattr);
1886e4f93234SChuck Lever 	if (unlikely(error))
1887e4f93234SChuck Lever 		goto out;
1888bf269551SChuck Lever 	error = decode_wcc_data(xdr, result->dir_attr);
1889e4f93234SChuck Lever 	if (unlikely(error))
1890e4f93234SChuck Lever 		goto out;
1891e4f93234SChuck Lever 	if (status != NFS3_OK)
1892e4f93234SChuck Lever 		goto out_status;
1893e4f93234SChuck Lever out:
1894e4f93234SChuck Lever 	return error;
1895e4f93234SChuck Lever out_status:
1896e4f93234SChuck Lever 	return nfs_stat_to_errno(status);
1897e4f93234SChuck Lever }
1898e4f93234SChuck Lever 
1899e4f93234SChuck Lever /**
1900e4f93234SChuck Lever  * nfs3_decode_dirent - Decode a single NFSv3 directory entry stored in
1901e4f93234SChuck Lever  *			the local page cache
1902e4f93234SChuck Lever  * @xdr: XDR stream where entry resides
1903e4f93234SChuck Lever  * @entry: buffer to fill in with entry data
1904e4f93234SChuck Lever  * @plus: boolean indicating whether this should be a readdirplus entry
1905e4f93234SChuck Lever  *
1906573c4e1eSChuck Lever  * Returns zero if successful, otherwise a negative errno value is
1907573c4e1eSChuck Lever  * returned.
1908e4f93234SChuck Lever  *
1909e4f93234SChuck Lever  * This function is not invoked during READDIR reply decoding, but
1910e4f93234SChuck Lever  * rather whenever an application invokes the getdents(2) system call
1911e4f93234SChuck Lever  * on a directory already in our cache.
1912e4f93234SChuck Lever  *
1913e4f93234SChuck Lever  * 3.3.16  entry3
1914e4f93234SChuck Lever  *
1915e4f93234SChuck Lever  *	struct entry3 {
1916e4f93234SChuck Lever  *		fileid3		fileid;
1917e4f93234SChuck Lever  *		filename3	name;
1918e4f93234SChuck Lever  *		cookie3		cookie;
1919e4f93234SChuck Lever  *		fhandle3	filehandle;
1920e4f93234SChuck Lever  *		post_op_attr3	attributes;
1921e4f93234SChuck Lever  *		entry3		*nextentry;
1922e4f93234SChuck Lever  *	};
1923e4f93234SChuck Lever  *
1924e4f93234SChuck Lever  * 3.3.17  entryplus3
1925e4f93234SChuck Lever  *	struct entryplus3 {
1926e4f93234SChuck Lever  *		fileid3		fileid;
1927e4f93234SChuck Lever  *		filename3	name;
1928e4f93234SChuck Lever  *		cookie3		cookie;
1929e4f93234SChuck Lever  *		post_op_attr	name_attributes;
1930e4f93234SChuck Lever  *		post_op_fh3	name_handle;
1931e4f93234SChuck Lever  *		entryplus3	*nextentry;
1932e4f93234SChuck Lever  *	};
1933e4f93234SChuck Lever  */
1934573c4e1eSChuck Lever int nfs3_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry,
1935573c4e1eSChuck Lever 		       int plus)
1936e4f93234SChuck Lever {
1937e4f93234SChuck Lever 	struct nfs_entry old = *entry;
1938e4f93234SChuck Lever 	__be32 *p;
1939e4f93234SChuck Lever 	int error;
1940e4f93234SChuck Lever 
1941e4f93234SChuck Lever 	p = xdr_inline_decode(xdr, 4);
1942e4f93234SChuck Lever 	if (unlikely(p == NULL))
1943e4f93234SChuck Lever 		goto out_overflow;
1944e4f93234SChuck Lever 	if (*p == xdr_zero) {
1945e4f93234SChuck Lever 		p = xdr_inline_decode(xdr, 4);
1946e4f93234SChuck Lever 		if (unlikely(p == NULL))
1947e4f93234SChuck Lever 			goto out_overflow;
1948e4f93234SChuck Lever 		if (*p == xdr_zero)
1949573c4e1eSChuck Lever 			return -EAGAIN;
1950e4f93234SChuck Lever 		entry->eof = 1;
1951573c4e1eSChuck Lever 		return -EBADCOOKIE;
1952e4f93234SChuck Lever 	}
1953e4f93234SChuck Lever 
1954e4f93234SChuck Lever 	error = decode_fileid3(xdr, &entry->ino);
1955e4f93234SChuck Lever 	if (unlikely(error))
1956573c4e1eSChuck Lever 		return error;
1957e4f93234SChuck Lever 
1958e4f93234SChuck Lever 	error = decode_inline_filename3(xdr, &entry->name, &entry->len);
1959e4f93234SChuck Lever 	if (unlikely(error))
1960573c4e1eSChuck Lever 		return error;
1961e4f93234SChuck Lever 
1962e4f93234SChuck Lever 	entry->prev_cookie = entry->cookie;
1963e4f93234SChuck Lever 	error = decode_cookie3(xdr, &entry->cookie);
1964e4f93234SChuck Lever 	if (unlikely(error))
1965573c4e1eSChuck Lever 		return error;
1966e4f93234SChuck Lever 
1967e4f93234SChuck Lever 	entry->d_type = DT_UNKNOWN;
1968e4f93234SChuck Lever 
1969e4f93234SChuck Lever 	if (plus) {
1970e4f93234SChuck Lever 		entry->fattr->valid = 0;
1971e4f93234SChuck Lever 		error = decode_post_op_attr(xdr, entry->fattr);
1972e4f93234SChuck Lever 		if (unlikely(error))
1973573c4e1eSChuck Lever 			return error;
1974e4f93234SChuck Lever 		if (entry->fattr->valid & NFS_ATTR_FATTR_V3)
1975e4f93234SChuck Lever 			entry->d_type = nfs_umode_to_dtype(entry->fattr->mode);
1976e4f93234SChuck Lever 
1977e4f93234SChuck Lever 		/* In fact, a post_op_fh3: */
1978e4f93234SChuck Lever 		p = xdr_inline_decode(xdr, 4);
1979e4f93234SChuck Lever 		if (unlikely(p == NULL))
1980e4f93234SChuck Lever 			goto out_overflow;
1981e4f93234SChuck Lever 		if (*p != xdr_zero) {
1982e4f93234SChuck Lever 			error = decode_nfs_fh3(xdr, entry->fh);
1983e4f93234SChuck Lever 			if (unlikely(error)) {
1984e4f93234SChuck Lever 				if (error == -E2BIG)
1985e4f93234SChuck Lever 					goto out_truncated;
1986573c4e1eSChuck Lever 				return error;
1987e4f93234SChuck Lever 			}
1988e4f93234SChuck Lever 		} else
1989e4f93234SChuck Lever 			zero_nfs_fh3(entry->fh);
1990e4f93234SChuck Lever 	}
1991e4f93234SChuck Lever 
1992e4f93234SChuck Lever 	/* Peek at the next entry to see if we're at EOD */
1993e4f93234SChuck Lever 	p = xdr_inline_peek(xdr, 4 + 4);
1994e4f93234SChuck Lever 	entry->eof = 0;
1995e4f93234SChuck Lever 	if (p != NULL)
1996e4f93234SChuck Lever 		entry->eof = (p[0] == xdr_zero) && (p[1] != xdr_zero);
1997573c4e1eSChuck Lever 	return 0;
1998e4f93234SChuck Lever 
1999e4f93234SChuck Lever out_overflow:
2000e4f93234SChuck Lever 	print_overflow_msg(__func__, xdr);
2001573c4e1eSChuck Lever 	return -EAGAIN;
2002e4f93234SChuck Lever out_truncated:
2003e4f93234SChuck Lever 	dprintk("NFS: directory entry contains invalid file handle\n");
2004e4f93234SChuck Lever 	*entry = old;
2005573c4e1eSChuck Lever 	return -EAGAIN;
2006e4f93234SChuck Lever }
2007e4f93234SChuck Lever 
2008e4f93234SChuck Lever /*
2009e4f93234SChuck Lever  * 3.3.16  READDIR3res
2010e4f93234SChuck Lever  *
2011e4f93234SChuck Lever  *	struct dirlist3 {
2012e4f93234SChuck Lever  *		entry3		*entries;
2013e4f93234SChuck Lever  *		bool		eof;
2014e4f93234SChuck Lever  *	};
2015e4f93234SChuck Lever  *
2016e4f93234SChuck Lever  *	struct READDIR3resok {
2017e4f93234SChuck Lever  *		post_op_attr	dir_attributes;
2018e4f93234SChuck Lever  *		cookieverf3	cookieverf;
2019e4f93234SChuck Lever  *		dirlist3	reply;
2020e4f93234SChuck Lever  *	};
2021e4f93234SChuck Lever  *
2022e4f93234SChuck Lever  *	struct READDIR3resfail {
2023e4f93234SChuck Lever  *		post_op_attr	dir_attributes;
2024e4f93234SChuck Lever  *	};
2025e4f93234SChuck Lever  *
2026e4f93234SChuck Lever  *	union READDIR3res switch (nfsstat3 status) {
2027e4f93234SChuck Lever  *	case NFS3_OK:
2028e4f93234SChuck Lever  *		READDIR3resok	resok;
2029e4f93234SChuck Lever  *	default:
2030e4f93234SChuck Lever  *		READDIR3resfail	resfail;
2031e4f93234SChuck Lever  *	};
2032e4f93234SChuck Lever  *
2033e4f93234SChuck Lever  * Read the directory contents into the page cache, but otherwise
2034e4f93234SChuck Lever  * don't touch them.  The actual decoding is done by nfs3_decode_entry()
2035e4f93234SChuck Lever  * during subsequent nfs_readdir() calls.
2036e4f93234SChuck Lever  */
2037e4f93234SChuck Lever static int decode_dirlist3(struct xdr_stream *xdr)
2038e4f93234SChuck Lever {
2039e4f93234SChuck Lever 	u32 recvd, pglen;
2040e4f93234SChuck Lever 	size_t hdrlen;
2041e4f93234SChuck Lever 
2042e4f93234SChuck Lever 	pglen = xdr->buf->page_len;
2043e4f93234SChuck Lever 	hdrlen = (u8 *)xdr->p - (u8 *)xdr->iov->iov_base;
2044e4f93234SChuck Lever 	recvd = xdr->buf->len - hdrlen;
2045e4f93234SChuck Lever 	if (unlikely(pglen > recvd))
2046e4f93234SChuck Lever 		goto out_cheating;
2047e4f93234SChuck Lever out:
2048e4f93234SChuck Lever 	xdr_read_pages(xdr, pglen);
2049e4f93234SChuck Lever 	return pglen;
2050e4f93234SChuck Lever out_cheating:
2051e4f93234SChuck Lever 	dprintk("NFS: server cheating in readdir result: "
2052e4f93234SChuck Lever 		"pglen %u > recvd %u\n", pglen, recvd);
2053e4f93234SChuck Lever 	pglen = recvd;
2054e4f93234SChuck Lever 	goto out;
2055e4f93234SChuck Lever }
2056e4f93234SChuck Lever 
2057e4f93234SChuck Lever static int decode_readdir3resok(struct xdr_stream *xdr,
2058e4f93234SChuck Lever 				struct nfs3_readdirres *result)
2059e4f93234SChuck Lever {
2060e4f93234SChuck Lever 	int error;
2061e4f93234SChuck Lever 
2062e4f93234SChuck Lever 	error = decode_post_op_attr(xdr, result->dir_attr);
2063e4f93234SChuck Lever 	if (unlikely(error))
2064e4f93234SChuck Lever 		goto out;
2065e4f93234SChuck Lever 	/* XXX: do we need to check if result->verf != NULL ? */
2066e4f93234SChuck Lever 	error = decode_cookieverf3(xdr, result->verf);
2067e4f93234SChuck Lever 	if (unlikely(error))
2068e4f93234SChuck Lever 		goto out;
2069e4f93234SChuck Lever 	error = decode_dirlist3(xdr);
2070e4f93234SChuck Lever out:
2071e4f93234SChuck Lever 	return error;
2072e4f93234SChuck Lever }
2073e4f93234SChuck Lever 
2074bf269551SChuck Lever static int nfs3_xdr_dec_readdir3res(struct rpc_rqst *req,
2075bf269551SChuck Lever 				    struct xdr_stream *xdr,
2076e4f93234SChuck Lever 				    struct nfs3_readdirres *result)
2077e4f93234SChuck Lever {
2078e4f93234SChuck Lever 	enum nfs_stat status;
2079e4f93234SChuck Lever 	int error;
2080e4f93234SChuck Lever 
2081bf269551SChuck Lever 	error = decode_nfsstat3(xdr, &status);
2082e4f93234SChuck Lever 	if (unlikely(error))
2083e4f93234SChuck Lever 		goto out;
2084e4f93234SChuck Lever 	if (status != NFS3_OK)
2085e4f93234SChuck Lever 		goto out_default;
2086bf269551SChuck Lever 	error = decode_readdir3resok(xdr, result);
2087e4f93234SChuck Lever out:
2088e4f93234SChuck Lever 	return error;
2089e4f93234SChuck Lever out_default:
2090bf269551SChuck Lever 	error = decode_post_op_attr(xdr, result->dir_attr);
2091e4f93234SChuck Lever 	if (unlikely(error))
2092e4f93234SChuck Lever 		goto out;
2093e4f93234SChuck Lever 	return nfs_stat_to_errno(status);
2094e4f93234SChuck Lever }
2095e4f93234SChuck Lever 
2096e4f93234SChuck Lever /*
2097e4f93234SChuck Lever  * 3.3.18  FSSTAT3res
2098e4f93234SChuck Lever  *
2099e4f93234SChuck Lever  *	struct FSSTAT3resok {
2100e4f93234SChuck Lever  *		post_op_attr	obj_attributes;
2101e4f93234SChuck Lever  *		size3		tbytes;
2102e4f93234SChuck Lever  *		size3		fbytes;
2103e4f93234SChuck Lever  *		size3		abytes;
2104e4f93234SChuck Lever  *		size3		tfiles;
2105e4f93234SChuck Lever  *		size3		ffiles;
2106e4f93234SChuck Lever  *		size3		afiles;
2107e4f93234SChuck Lever  *		uint32		invarsec;
2108e4f93234SChuck Lever  *	};
2109e4f93234SChuck Lever  *
2110e4f93234SChuck Lever  *	struct FSSTAT3resfail {
2111e4f93234SChuck Lever  *		post_op_attr	obj_attributes;
2112e4f93234SChuck Lever  *	};
2113e4f93234SChuck Lever  *
2114e4f93234SChuck Lever  *	union FSSTAT3res switch (nfsstat3 status) {
2115e4f93234SChuck Lever  *	case NFS3_OK:
2116e4f93234SChuck Lever  *		FSSTAT3resok	resok;
2117e4f93234SChuck Lever  *	default:
2118e4f93234SChuck Lever  *		FSSTAT3resfail	resfail;
2119e4f93234SChuck Lever  *	};
2120e4f93234SChuck Lever  */
2121e4f93234SChuck Lever static int decode_fsstat3resok(struct xdr_stream *xdr,
2122e4f93234SChuck Lever 			       struct nfs_fsstat *result)
2123e4f93234SChuck Lever {
2124e4f93234SChuck Lever 	__be32 *p;
2125e4f93234SChuck Lever 
2126e4f93234SChuck Lever 	p = xdr_inline_decode(xdr, 8 * 6 + 4);
2127e4f93234SChuck Lever 	if (unlikely(p == NULL))
2128e4f93234SChuck Lever 		goto out_overflow;
2129e4f93234SChuck Lever 	p = xdr_decode_size3(p, &result->tbytes);
2130e4f93234SChuck Lever 	p = xdr_decode_size3(p, &result->fbytes);
2131e4f93234SChuck Lever 	p = xdr_decode_size3(p, &result->abytes);
2132e4f93234SChuck Lever 	p = xdr_decode_size3(p, &result->tfiles);
2133e4f93234SChuck Lever 	p = xdr_decode_size3(p, &result->ffiles);
2134e4f93234SChuck Lever 	xdr_decode_size3(p, &result->afiles);
2135e4f93234SChuck Lever 	/* ignore invarsec */
2136e4f93234SChuck Lever 	return 0;
2137e4f93234SChuck Lever out_overflow:
2138e4f93234SChuck Lever 	print_overflow_msg(__func__, xdr);
2139e4f93234SChuck Lever 	return -EIO;
2140e4f93234SChuck Lever }
2141e4f93234SChuck Lever 
2142bf269551SChuck Lever static int nfs3_xdr_dec_fsstat3res(struct rpc_rqst *req,
2143bf269551SChuck Lever 				   struct xdr_stream *xdr,
2144e4f93234SChuck Lever 				   struct nfs_fsstat *result)
2145e4f93234SChuck Lever {
2146e4f93234SChuck Lever 	enum nfs_stat status;
2147e4f93234SChuck Lever 	int error;
2148e4f93234SChuck Lever 
2149bf269551SChuck Lever 	error = decode_nfsstat3(xdr, &status);
2150e4f93234SChuck Lever 	if (unlikely(error))
2151e4f93234SChuck Lever 		goto out;
2152bf269551SChuck Lever 	error = decode_post_op_attr(xdr, result->fattr);
2153e4f93234SChuck Lever 	if (unlikely(error))
2154e4f93234SChuck Lever 		goto out;
2155e4f93234SChuck Lever 	if (status != NFS3_OK)
2156e4f93234SChuck Lever 		goto out_status;
2157bf269551SChuck Lever 	error = decode_fsstat3resok(xdr, result);
2158e4f93234SChuck Lever out:
2159e4f93234SChuck Lever 	return error;
2160e4f93234SChuck Lever out_status:
2161e4f93234SChuck Lever 	return nfs_stat_to_errno(status);
2162e4f93234SChuck Lever }
2163e4f93234SChuck Lever 
2164e4f93234SChuck Lever /*
2165e4f93234SChuck Lever  * 3.3.19  FSINFO3res
2166e4f93234SChuck Lever  *
2167e4f93234SChuck Lever  *	struct FSINFO3resok {
2168e4f93234SChuck Lever  *		post_op_attr	obj_attributes;
2169e4f93234SChuck Lever  *		uint32		rtmax;
2170e4f93234SChuck Lever  *		uint32		rtpref;
2171e4f93234SChuck Lever  *		uint32		rtmult;
2172e4f93234SChuck Lever  *		uint32		wtmax;
2173e4f93234SChuck Lever  *		uint32		wtpref;
2174e4f93234SChuck Lever  *		uint32		wtmult;
2175e4f93234SChuck Lever  *		uint32		dtpref;
2176e4f93234SChuck Lever  *		size3		maxfilesize;
2177e4f93234SChuck Lever  *		nfstime3	time_delta;
2178e4f93234SChuck Lever  *		uint32		properties;
2179e4f93234SChuck Lever  *	};
2180e4f93234SChuck Lever  *
2181e4f93234SChuck Lever  *	struct FSINFO3resfail {
2182e4f93234SChuck Lever  *		post_op_attr	obj_attributes;
2183e4f93234SChuck Lever  *	};
2184e4f93234SChuck Lever  *
2185e4f93234SChuck Lever  *	union FSINFO3res switch (nfsstat3 status) {
2186e4f93234SChuck Lever  *	case NFS3_OK:
2187e4f93234SChuck Lever  *		FSINFO3resok	resok;
2188e4f93234SChuck Lever  *	default:
2189e4f93234SChuck Lever  *		FSINFO3resfail	resfail;
2190e4f93234SChuck Lever  *	};
2191e4f93234SChuck Lever  */
2192e4f93234SChuck Lever static int decode_fsinfo3resok(struct xdr_stream *xdr,
2193e4f93234SChuck Lever 			       struct nfs_fsinfo *result)
2194e4f93234SChuck Lever {
2195e4f93234SChuck Lever 	__be32 *p;
2196e4f93234SChuck Lever 
2197e4f93234SChuck Lever 	p = xdr_inline_decode(xdr, 4 * 7 + 8 + 8 + 4);
2198e4f93234SChuck Lever 	if (unlikely(p == NULL))
2199e4f93234SChuck Lever 		goto out_overflow;
2200e4f93234SChuck Lever 	result->rtmax  = be32_to_cpup(p++);
2201e4f93234SChuck Lever 	result->rtpref = be32_to_cpup(p++);
2202e4f93234SChuck Lever 	result->rtmult = be32_to_cpup(p++);
2203e4f93234SChuck Lever 	result->wtmax  = be32_to_cpup(p++);
2204e4f93234SChuck Lever 	result->wtpref = be32_to_cpup(p++);
2205e4f93234SChuck Lever 	result->wtmult = be32_to_cpup(p++);
2206e4f93234SChuck Lever 	result->dtpref = be32_to_cpup(p++);
2207e4f93234SChuck Lever 	p = xdr_decode_size3(p, &result->maxfilesize);
2208f6048709SChuck Lever 	xdr_decode_nfstime3(p, &result->time_delta);
2209e4f93234SChuck Lever 
2210e4f93234SChuck Lever 	/* ignore properties */
2211e4f93234SChuck Lever 	result->lease_time = 0;
2212e4f93234SChuck Lever 	return 0;
2213e4f93234SChuck Lever out_overflow:
2214e4f93234SChuck Lever 	print_overflow_msg(__func__, xdr);
2215e4f93234SChuck Lever 	return -EIO;
2216e4f93234SChuck Lever }
2217e4f93234SChuck Lever 
2218bf269551SChuck Lever static int nfs3_xdr_dec_fsinfo3res(struct rpc_rqst *req,
2219bf269551SChuck Lever 				   struct xdr_stream *xdr,
2220e4f93234SChuck Lever 				   struct nfs_fsinfo *result)
2221e4f93234SChuck Lever {
2222e4f93234SChuck Lever 	enum nfs_stat status;
2223e4f93234SChuck Lever 	int error;
2224e4f93234SChuck Lever 
2225bf269551SChuck Lever 	error = decode_nfsstat3(xdr, &status);
2226e4f93234SChuck Lever 	if (unlikely(error))
2227e4f93234SChuck Lever 		goto out;
2228bf269551SChuck Lever 	error = decode_post_op_attr(xdr, result->fattr);
2229e4f93234SChuck Lever 	if (unlikely(error))
2230e4f93234SChuck Lever 		goto out;
2231e4f93234SChuck Lever 	if (status != NFS3_OK)
2232e4f93234SChuck Lever 		goto out_status;
2233bf269551SChuck Lever 	error = decode_fsinfo3resok(xdr, result);
2234e4f93234SChuck Lever out:
2235e4f93234SChuck Lever 	return error;
2236e4f93234SChuck Lever out_status:
2237e4f93234SChuck Lever 	return nfs_stat_to_errno(status);
2238e4f93234SChuck Lever }
2239e4f93234SChuck Lever 
2240e4f93234SChuck Lever /*
2241e4f93234SChuck Lever  * 3.3.20  PATHCONF3res
2242e4f93234SChuck Lever  *
2243e4f93234SChuck Lever  *	struct PATHCONF3resok {
2244e4f93234SChuck Lever  *		post_op_attr	obj_attributes;
2245e4f93234SChuck Lever  *		uint32		linkmax;
2246e4f93234SChuck Lever  *		uint32		name_max;
2247e4f93234SChuck Lever  *		bool		no_trunc;
2248e4f93234SChuck Lever  *		bool		chown_restricted;
2249e4f93234SChuck Lever  *		bool		case_insensitive;
2250e4f93234SChuck Lever  *		bool		case_preserving;
2251e4f93234SChuck Lever  *	};
2252e4f93234SChuck Lever  *
2253e4f93234SChuck Lever  *	struct PATHCONF3resfail {
2254e4f93234SChuck Lever  *		post_op_attr	obj_attributes;
2255e4f93234SChuck Lever  *	};
2256e4f93234SChuck Lever  *
2257e4f93234SChuck Lever  *	union PATHCONF3res switch (nfsstat3 status) {
2258e4f93234SChuck Lever  *	case NFS3_OK:
2259e4f93234SChuck Lever  *		PATHCONF3resok	resok;
2260e4f93234SChuck Lever  *	default:
2261e4f93234SChuck Lever  *		PATHCONF3resfail resfail;
2262e4f93234SChuck Lever  *	};
2263e4f93234SChuck Lever  */
2264e4f93234SChuck Lever static int decode_pathconf3resok(struct xdr_stream *xdr,
2265e4f93234SChuck Lever 				 struct nfs_pathconf *result)
2266e4f93234SChuck Lever {
2267e4f93234SChuck Lever 	__be32 *p;
2268e4f93234SChuck Lever 
2269e4f93234SChuck Lever 	p = xdr_inline_decode(xdr, 4 * 6);
2270e4f93234SChuck Lever 	if (unlikely(p == NULL))
2271e4f93234SChuck Lever 		goto out_overflow;
2272e4f93234SChuck Lever 	result->max_link = be32_to_cpup(p++);
2273e4f93234SChuck Lever 	result->max_namelen = be32_to_cpup(p);
2274e4f93234SChuck Lever 	/* ignore remaining fields */
2275e4f93234SChuck Lever 	return 0;
2276e4f93234SChuck Lever out_overflow:
2277e4f93234SChuck Lever 	print_overflow_msg(__func__, xdr);
2278e4f93234SChuck Lever 	return -EIO;
2279e4f93234SChuck Lever }
2280e4f93234SChuck Lever 
2281bf269551SChuck Lever static int nfs3_xdr_dec_pathconf3res(struct rpc_rqst *req,
2282bf269551SChuck Lever 				     struct xdr_stream *xdr,
2283e4f93234SChuck Lever 				     struct nfs_pathconf *result)
2284e4f93234SChuck Lever {
2285e4f93234SChuck Lever 	enum nfs_stat status;
2286e4f93234SChuck Lever 	int error;
2287e4f93234SChuck Lever 
2288bf269551SChuck Lever 	error = decode_nfsstat3(xdr, &status);
2289e4f93234SChuck Lever 	if (unlikely(error))
2290e4f93234SChuck Lever 		goto out;
2291bf269551SChuck Lever 	error = decode_post_op_attr(xdr, result->fattr);
2292e4f93234SChuck Lever 	if (unlikely(error))
2293e4f93234SChuck Lever 		goto out;
2294e4f93234SChuck Lever 	if (status != NFS3_OK)
2295e4f93234SChuck Lever 		goto out_status;
2296bf269551SChuck Lever 	error = decode_pathconf3resok(xdr, result);
2297e4f93234SChuck Lever out:
2298e4f93234SChuck Lever 	return error;
2299e4f93234SChuck Lever out_status:
2300e4f93234SChuck Lever 	return nfs_stat_to_errno(status);
2301e4f93234SChuck Lever }
2302e4f93234SChuck Lever 
2303e4f93234SChuck Lever /*
2304e4f93234SChuck Lever  * 3.3.21  COMMIT3res
2305e4f93234SChuck Lever  *
2306e4f93234SChuck Lever  *	struct COMMIT3resok {
2307e4f93234SChuck Lever  *		wcc_data	file_wcc;
2308e4f93234SChuck Lever  *		writeverf3	verf;
2309e4f93234SChuck Lever  *	};
2310e4f93234SChuck Lever  *
2311e4f93234SChuck Lever  *	struct COMMIT3resfail {
2312e4f93234SChuck Lever  *		wcc_data	file_wcc;
2313e4f93234SChuck Lever  *	};
2314e4f93234SChuck Lever  *
2315e4f93234SChuck Lever  *	union COMMIT3res switch (nfsstat3 status) {
2316e4f93234SChuck Lever  *	case NFS3_OK:
2317e4f93234SChuck Lever  *		COMMIT3resok	resok;
2318e4f93234SChuck Lever  *	default:
2319e4f93234SChuck Lever  *		COMMIT3resfail	resfail;
2320e4f93234SChuck Lever  *	};
2321e4f93234SChuck Lever  */
2322bf269551SChuck Lever static int nfs3_xdr_dec_commit3res(struct rpc_rqst *req,
2323bf269551SChuck Lever 				   struct xdr_stream *xdr,
2324e4f93234SChuck Lever 				   struct nfs_writeres *result)
2325e4f93234SChuck Lever {
2326e4f93234SChuck Lever 	enum nfs_stat status;
2327e4f93234SChuck Lever 	int error;
2328e4f93234SChuck Lever 
2329bf269551SChuck Lever 	error = decode_nfsstat3(xdr, &status);
2330e4f93234SChuck Lever 	if (unlikely(error))
2331e4f93234SChuck Lever 		goto out;
2332bf269551SChuck Lever 	error = decode_wcc_data(xdr, result->fattr);
2333e4f93234SChuck Lever 	if (unlikely(error))
2334e4f93234SChuck Lever 		goto out;
2335e4f93234SChuck Lever 	if (status != NFS3_OK)
2336e4f93234SChuck Lever 		goto out_status;
2337bf269551SChuck Lever 	error = decode_writeverf3(xdr, result->verf->verifier);
2338e4f93234SChuck Lever out:
2339e4f93234SChuck Lever 	return error;
2340e4f93234SChuck Lever out_status:
2341e4f93234SChuck Lever 	return nfs_stat_to_errno(status);
2342e4f93234SChuck Lever }
2343e4f93234SChuck Lever 
2344b7fa0554SAndreas Gruenbacher #ifdef CONFIG_NFS_V3_ACL
2345b7fa0554SAndreas Gruenbacher 
2346e4f93234SChuck Lever static inline int decode_getacl3resok(struct xdr_stream *xdr,
2347e4f93234SChuck Lever 				      struct nfs3_getaclres *result)
2348e4f93234SChuck Lever {
2349e4f93234SChuck Lever 	struct posix_acl **acl;
2350e4f93234SChuck Lever 	unsigned int *aclcnt;
2351e4f93234SChuck Lever 	size_t hdrlen;
2352e4f93234SChuck Lever 	int error;
2353e4f93234SChuck Lever 
2354e4f93234SChuck Lever 	error = decode_post_op_attr(xdr, result->fattr);
2355e4f93234SChuck Lever 	if (unlikely(error))
2356e4f93234SChuck Lever 		goto out;
2357e4f93234SChuck Lever 	error = decode_uint32(xdr, &result->mask);
2358e4f93234SChuck Lever 	if (unlikely(error))
2359e4f93234SChuck Lever 		goto out;
2360e4f93234SChuck Lever 	error = -EINVAL;
2361e4f93234SChuck Lever 	if (result->mask & ~(NFS_ACL|NFS_ACLCNT|NFS_DFACL|NFS_DFACLCNT))
2362e4f93234SChuck Lever 		goto out;
2363e4f93234SChuck Lever 
2364e4f93234SChuck Lever 	hdrlen = (u8 *)xdr->p - (u8 *)xdr->iov->iov_base;
2365e4f93234SChuck Lever 
2366e4f93234SChuck Lever 	acl = NULL;
2367e4f93234SChuck Lever 	if (result->mask & NFS_ACL)
2368e4f93234SChuck Lever 		acl = &result->acl_access;
2369e4f93234SChuck Lever 	aclcnt = NULL;
2370e4f93234SChuck Lever 	if (result->mask & NFS_ACLCNT)
2371e4f93234SChuck Lever 		aclcnt = &result->acl_access_count;
2372e4f93234SChuck Lever 	error = nfsacl_decode(xdr->buf, hdrlen, aclcnt, acl);
2373e4f93234SChuck Lever 	if (unlikely(error <= 0))
2374e4f93234SChuck Lever 		goto out;
2375e4f93234SChuck Lever 
2376e4f93234SChuck Lever 	acl = NULL;
2377e4f93234SChuck Lever 	if (result->mask & NFS_DFACL)
2378e4f93234SChuck Lever 		acl = &result->acl_default;
2379e4f93234SChuck Lever 	aclcnt = NULL;
2380e4f93234SChuck Lever 	if (result->mask & NFS_DFACLCNT)
2381e4f93234SChuck Lever 		aclcnt = &result->acl_default_count;
2382e4f93234SChuck Lever 	error = nfsacl_decode(xdr->buf, hdrlen + error, aclcnt, acl);
2383e4f93234SChuck Lever 	if (unlikely(error <= 0))
2384e4f93234SChuck Lever 		return error;
2385e4f93234SChuck Lever 	error = 0;
2386e4f93234SChuck Lever out:
2387e4f93234SChuck Lever 	return error;
2388e4f93234SChuck Lever }
2389e4f93234SChuck Lever 
2390bf269551SChuck Lever static int nfs3_xdr_dec_getacl3res(struct rpc_rqst *req,
2391bf269551SChuck Lever 				   struct xdr_stream *xdr,
2392e4f93234SChuck Lever 				   struct nfs3_getaclres *result)
2393e4f93234SChuck Lever {
2394e4f93234SChuck Lever 	enum nfs_stat status;
2395e4f93234SChuck Lever 	int error;
2396e4f93234SChuck Lever 
2397bf269551SChuck Lever 	error = decode_nfsstat3(xdr, &status);
2398e4f93234SChuck Lever 	if (unlikely(error))
2399e4f93234SChuck Lever 		goto out;
2400e4f93234SChuck Lever 	if (status != NFS3_OK)
2401e4f93234SChuck Lever 		goto out_default;
2402bf269551SChuck Lever 	error = decode_getacl3resok(xdr, result);
2403e4f93234SChuck Lever out:
2404e4f93234SChuck Lever 	return error;
2405e4f93234SChuck Lever out_default:
2406e4f93234SChuck Lever 	return nfs_stat_to_errno(status);
2407e4f93234SChuck Lever }
2408e4f93234SChuck Lever 
2409bf269551SChuck Lever static int nfs3_xdr_dec_setacl3res(struct rpc_rqst *req,
2410bf269551SChuck Lever 				   struct xdr_stream *xdr,
2411e4f93234SChuck Lever 				   struct nfs_fattr *result)
2412e4f93234SChuck Lever {
2413e4f93234SChuck Lever 	enum nfs_stat status;
2414e4f93234SChuck Lever 	int error;
2415e4f93234SChuck Lever 
2416bf269551SChuck Lever 	error = decode_nfsstat3(xdr, &status);
2417e4f93234SChuck Lever 	if (unlikely(error))
2418e4f93234SChuck Lever 		goto out;
2419e4f93234SChuck Lever 	if (status != NFS3_OK)
2420e4f93234SChuck Lever 		goto out_default;
2421bf269551SChuck Lever 	error = decode_post_op_attr(xdr, result);
2422e4f93234SChuck Lever out:
2423e4f93234SChuck Lever 	return error;
2424e4f93234SChuck Lever out_default:
2425e4f93234SChuck Lever 	return nfs_stat_to_errno(status);
2426e4f93234SChuck Lever }
2427e4f93234SChuck Lever 
2428b7fa0554SAndreas Gruenbacher #endif  /* CONFIG_NFS_V3_ACL */
2429b7fa0554SAndreas Gruenbacher 
24301da177e4SLinus Torvalds #define PROC(proc, argtype, restype, timer)				\
24311da177e4SLinus Torvalds [NFS3PROC_##proc] = {							\
24321da177e4SLinus Torvalds 	.p_proc      = NFS3PROC_##proc,					\
24339f06c719SChuck Lever 	.p_encode    = (kxdreproc_t)nfs3_xdr_enc_##argtype##3args,	\
2434bf269551SChuck Lever 	.p_decode    = (kxdrdproc_t)nfs3_xdr_dec_##restype##3res,	\
2435ad96b5b5SChuck Lever 	.p_arglen    = NFS3_##argtype##args_sz,				\
2436f5fc3c50SChuck Lever 	.p_replen    = NFS3_##restype##res_sz,				\
2437cc0175c1SChuck Lever 	.p_timer     = timer,						\
2438cc0175c1SChuck Lever 	.p_statidx   = NFS3PROC_##proc,					\
2439cc0175c1SChuck Lever 	.p_name      = #proc,						\
24401da177e4SLinus Torvalds 	}
24411da177e4SLinus Torvalds 
24421da177e4SLinus Torvalds struct rpc_procinfo	nfs3_procedures[] = {
2443f5fc3c50SChuck Lever 	PROC(GETATTR,		getattr,	getattr,	1),
2444f5fc3c50SChuck Lever 	PROC(SETATTR,		setattr,	setattr,	0),
2445f5fc3c50SChuck Lever 	PROC(LOOKUP,		lookup,		lookup,		2),
2446f5fc3c50SChuck Lever 	PROC(ACCESS,		access,		access,		1),
2447f5fc3c50SChuck Lever 	PROC(READLINK,		readlink,	readlink,	3),
2448f5fc3c50SChuck Lever 	PROC(READ,		read,		read,		3),
2449f5fc3c50SChuck Lever 	PROC(WRITE,		write,		write,		4),
2450f5fc3c50SChuck Lever 	PROC(CREATE,		create,		create,		0),
2451f5fc3c50SChuck Lever 	PROC(MKDIR,		mkdir,		create,		0),
2452f5fc3c50SChuck Lever 	PROC(SYMLINK,		symlink,	create,		0),
2453f5fc3c50SChuck Lever 	PROC(MKNOD,		mknod,		create,		0),
2454f5fc3c50SChuck Lever 	PROC(REMOVE,		remove,		remove,		0),
2455f5fc3c50SChuck Lever 	PROC(RMDIR,		lookup,		setattr,	0),
2456f5fc3c50SChuck Lever 	PROC(RENAME,		rename,		rename,		0),
2457f5fc3c50SChuck Lever 	PROC(LINK,		link,		link,		0),
2458f5fc3c50SChuck Lever 	PROC(READDIR,		readdir,	readdir,	3),
2459f5fc3c50SChuck Lever 	PROC(READDIRPLUS,	readdirplus,	readdir,	3),
2460f5fc3c50SChuck Lever 	PROC(FSSTAT,		getattr,	fsstat,		0),
2461f5fc3c50SChuck Lever 	PROC(FSINFO,		getattr,	fsinfo,		0),
2462f5fc3c50SChuck Lever 	PROC(PATHCONF,		getattr,	pathconf,	0),
2463f5fc3c50SChuck Lever 	PROC(COMMIT,		commit,		commit,		5),
24641da177e4SLinus Torvalds };
24651da177e4SLinus Torvalds 
24661da177e4SLinus Torvalds struct rpc_version		nfs_version3 = {
24671da177e4SLinus Torvalds 	.number			= 3,
2468e8c96f8cSTobias Klauser 	.nrprocs		= ARRAY_SIZE(nfs3_procedures),
24691da177e4SLinus Torvalds 	.procs			= nfs3_procedures
24701da177e4SLinus Torvalds };
24711da177e4SLinus Torvalds 
2472b7fa0554SAndreas Gruenbacher #ifdef CONFIG_NFS_V3_ACL
2473b7fa0554SAndreas Gruenbacher static struct rpc_procinfo	nfs3_acl_procedures[] = {
2474b7fa0554SAndreas Gruenbacher 	[ACLPROC3_GETACL] = {
2475b7fa0554SAndreas Gruenbacher 		.p_proc = ACLPROC3_GETACL,
24769f06c719SChuck Lever 		.p_encode = (kxdreproc_t)nfs3_xdr_enc_getacl3args,
2477bf269551SChuck Lever 		.p_decode = (kxdrdproc_t)nfs3_xdr_dec_getacl3res,
24782bea90d4SChuck Lever 		.p_arglen = ACL3_getaclargs_sz,
24792bea90d4SChuck Lever 		.p_replen = ACL3_getaclres_sz,
2480b7fa0554SAndreas Gruenbacher 		.p_timer = 1,
2481cc0175c1SChuck Lever 		.p_name = "GETACL",
2482b7fa0554SAndreas Gruenbacher 	},
2483b7fa0554SAndreas Gruenbacher 	[ACLPROC3_SETACL] = {
2484b7fa0554SAndreas Gruenbacher 		.p_proc = ACLPROC3_SETACL,
24859f06c719SChuck Lever 		.p_encode = (kxdreproc_t)nfs3_xdr_enc_setacl3args,
2486bf269551SChuck Lever 		.p_decode = (kxdrdproc_t)nfs3_xdr_dec_setacl3res,
24872bea90d4SChuck Lever 		.p_arglen = ACL3_setaclargs_sz,
24882bea90d4SChuck Lever 		.p_replen = ACL3_setaclres_sz,
2489b7fa0554SAndreas Gruenbacher 		.p_timer = 0,
2490cc0175c1SChuck Lever 		.p_name = "SETACL",
2491b7fa0554SAndreas Gruenbacher 	},
2492b7fa0554SAndreas Gruenbacher };
2493b7fa0554SAndreas Gruenbacher 
2494b7fa0554SAndreas Gruenbacher struct rpc_version		nfsacl_version3 = {
2495b7fa0554SAndreas Gruenbacher 	.number			= 3,
2496b7fa0554SAndreas Gruenbacher 	.nrprocs		= sizeof(nfs3_acl_procedures)/
2497b7fa0554SAndreas Gruenbacher 				  sizeof(nfs3_acl_procedures[0]),
2498b7fa0554SAndreas Gruenbacher 	.procs			= nfs3_acl_procedures,
2499b7fa0554SAndreas Gruenbacher };
2500b7fa0554SAndreas Gruenbacher #endif  /* CONFIG_NFS_V3_ACL */
2501