xref: /openbmc/linux/fs/nfs/nfs3xdr.c (revision f67b55b6)
1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds  * linux/fs/nfs/nfs3xdr.c
41da177e4SLinus Torvalds  *
51da177e4SLinus Torvalds  * XDR functions to encode/decode NFSv3 RPC arguments and results.
61da177e4SLinus Torvalds  *
71da177e4SLinus Torvalds  * Copyright (C) 1996, 1997 Olaf Kirch
81da177e4SLinus Torvalds  */
91da177e4SLinus Torvalds 
101da177e4SLinus Torvalds #include <linux/param.h>
111da177e4SLinus Torvalds #include <linux/time.h>
121da177e4SLinus Torvalds #include <linux/mm.h>
131da177e4SLinus Torvalds #include <linux/errno.h>
141da177e4SLinus Torvalds #include <linux/string.h>
151da177e4SLinus Torvalds #include <linux/in.h>
161da177e4SLinus Torvalds #include <linux/pagemap.h>
171da177e4SLinus Torvalds #include <linux/proc_fs.h>
181da177e4SLinus Torvalds #include <linux/kdev_t.h>
191da177e4SLinus Torvalds #include <linux/sunrpc/clnt.h>
201da177e4SLinus Torvalds #include <linux/nfs.h>
211da177e4SLinus Torvalds #include <linux/nfs3.h>
221da177e4SLinus Torvalds #include <linux/nfs_fs.h>
23b7fa0554SAndreas Gruenbacher #include <linux/nfsacl.h>
24f23f6584SChuck Lever #include "nfstrace.h"
25f7b422b1SDavid Howells #include "internal.h"
261da177e4SLinus Torvalds 
271da177e4SLinus Torvalds #define NFSDBG_FACILITY		NFSDBG_XDR
281da177e4SLinus Torvalds 
291da177e4SLinus Torvalds /* Mapping from NFS error code to "errno" error code. */
301da177e4SLinus Torvalds #define errno_NFSERR_IO		EIO
311da177e4SLinus Torvalds 
321da177e4SLinus Torvalds /*
331da177e4SLinus Torvalds  * Declare the space requirements for NFS arguments and replies as
341da177e4SLinus Torvalds  * number of 32bit-words
351da177e4SLinus Torvalds  */
369ed5af26STrond Myklebust #define NFS3_pagepad_sz		(1) /* Page padding */
371da177e4SLinus Torvalds #define NFS3_fhandle_sz		(1+16)
381da177e4SLinus Torvalds #define NFS3_fh_sz		(NFS3_fhandle_sz)	/* shorthand */
39ad3dbe35SFrank Sorenson #define NFS3_post_op_fh_sz	(1+NFS3_fh_sz)
401da177e4SLinus Torvalds #define NFS3_sattr_sz		(15)
411da177e4SLinus Torvalds #define NFS3_filename_sz	(1+(NFS3_MAXNAMLEN>>2))
421da177e4SLinus Torvalds #define NFS3_path_sz		(1+(NFS3_MAXPATHLEN>>2))
431da177e4SLinus Torvalds #define NFS3_fattr_sz		(21)
44d9c407b1SChuck Lever #define NFS3_cookieverf_sz	(NFS3_COOKIEVERFSIZE>>2)
451da177e4SLinus Torvalds #define NFS3_wcc_attr_sz	(6)
461da177e4SLinus Torvalds #define NFS3_pre_op_attr_sz	(1+NFS3_wcc_attr_sz)
471da177e4SLinus Torvalds #define NFS3_post_op_attr_sz	(1+NFS3_fattr_sz)
481da177e4SLinus Torvalds #define NFS3_wcc_data_sz	(NFS3_pre_op_attr_sz+NFS3_post_op_attr_sz)
491da177e4SLinus Torvalds #define NFS3_diropargs_sz	(NFS3_fh_sz+NFS3_filename_sz)
50ad96b5b5SChuck Lever 
51ad96b5b5SChuck Lever #define NFS3_getattrargs_sz	(NFS3_fh_sz)
52ad96b5b5SChuck Lever #define NFS3_setattrargs_sz	(NFS3_fh_sz+NFS3_sattr_sz+3)
53ad96b5b5SChuck Lever #define NFS3_lookupargs_sz	(NFS3_fh_sz+NFS3_filename_sz)
541da177e4SLinus Torvalds #define NFS3_accessargs_sz	(NFS3_fh_sz+1)
551da177e4SLinus Torvalds #define NFS3_readlinkargs_sz	(NFS3_fh_sz)
561da177e4SLinus Torvalds #define NFS3_readargs_sz	(NFS3_fh_sz+3)
571da177e4SLinus Torvalds #define NFS3_writeargs_sz	(NFS3_fh_sz+5)
581da177e4SLinus Torvalds #define NFS3_createargs_sz	(NFS3_diropargs_sz+NFS3_sattr_sz)
591da177e4SLinus Torvalds #define NFS3_mkdirargs_sz	(NFS3_diropargs_sz+NFS3_sattr_sz)
6094a6d753SChuck Lever #define NFS3_symlinkargs_sz	(NFS3_diropargs_sz+1+NFS3_sattr_sz)
611da177e4SLinus Torvalds #define NFS3_mknodargs_sz	(NFS3_diropargs_sz+2+NFS3_sattr_sz)
62ad96b5b5SChuck Lever #define NFS3_removeargs_sz	(NFS3_fh_sz+NFS3_filename_sz)
631da177e4SLinus Torvalds #define NFS3_renameargs_sz	(NFS3_diropargs_sz+NFS3_diropargs_sz)
641da177e4SLinus Torvalds #define NFS3_linkargs_sz		(NFS3_fh_sz+NFS3_diropargs_sz)
65d9c407b1SChuck Lever #define NFS3_readdirargs_sz	(NFS3_fh_sz+NFS3_cookieverf_sz+3)
66d9c407b1SChuck Lever #define NFS3_readdirplusargs_sz	(NFS3_fh_sz+NFS3_cookieverf_sz+4)
671da177e4SLinus Torvalds #define NFS3_commitargs_sz	(NFS3_fh_sz+3)
681da177e4SLinus Torvalds 
69f5fc3c50SChuck Lever #define NFS3_getattrres_sz	(1+NFS3_fattr_sz)
70f5fc3c50SChuck Lever #define NFS3_setattrres_sz	(1+NFS3_wcc_data_sz)
71f5fc3c50SChuck Lever #define NFS3_removeres_sz	(NFS3_setattrres_sz)
721da177e4SLinus Torvalds #define NFS3_lookupres_sz	(1+NFS3_fh_sz+(2 * NFS3_post_op_attr_sz))
731da177e4SLinus Torvalds #define NFS3_accessres_sz	(1+NFS3_post_op_attr_sz+1)
749ed5af26STrond Myklebust #define NFS3_readlinkres_sz	(1+NFS3_post_op_attr_sz+1+NFS3_pagepad_sz)
759ed5af26STrond Myklebust #define NFS3_readres_sz		(1+NFS3_post_op_attr_sz+3+NFS3_pagepad_sz)
761da177e4SLinus Torvalds #define NFS3_writeres_sz	(1+NFS3_wcc_data_sz+4)
77ad3dbe35SFrank Sorenson #define NFS3_createres_sz	(1+NFS3_post_op_fh_sz+NFS3_post_op_attr_sz+NFS3_wcc_data_sz)
781da177e4SLinus Torvalds #define NFS3_renameres_sz	(1+(2 * NFS3_wcc_data_sz))
791da177e4SLinus Torvalds #define NFS3_linkres_sz		(1+NFS3_post_op_attr_sz+NFS3_wcc_data_sz)
809ed5af26STrond Myklebust #define NFS3_readdirres_sz	(1+NFS3_post_op_attr_sz+2+NFS3_pagepad_sz)
811da177e4SLinus Torvalds #define NFS3_fsstatres_sz	(1+NFS3_post_op_attr_sz+13)
821da177e4SLinus Torvalds #define NFS3_fsinfores_sz	(1+NFS3_post_op_attr_sz+12)
831da177e4SLinus Torvalds #define NFS3_pathconfres_sz	(1+NFS3_post_op_attr_sz+6)
841da177e4SLinus Torvalds #define NFS3_commitres_sz	(1+NFS3_wcc_data_sz+2)
851da177e4SLinus Torvalds 
86b7fa0554SAndreas Gruenbacher #define ACL3_getaclargs_sz	(NFS3_fh_sz+1)
87ae46141fSTrond Myklebust #define ACL3_setaclargs_sz	(NFS3_fh_sz+1+ \
88ae46141fSTrond Myklebust 				XDR_QUADLEN(NFS_ACL_INLINE_BUFSIZE))
89ae46141fSTrond Myklebust #define ACL3_getaclres_sz	(1+NFS3_post_op_attr_sz+1+ \
909ed5af26STrond Myklebust 				XDR_QUADLEN(NFS_ACL_INLINE_BUFSIZE)+\
919ed5af26STrond Myklebust 				NFS3_pagepad_sz)
92b7fa0554SAndreas Gruenbacher #define ACL3_setaclres_sz	(1+NFS3_post_op_attr_sz)
93b7fa0554SAndreas Gruenbacher 
945e7e5a0dSBryan Schumaker static int nfs3_stat_to_errno(enum nfs_stat);
955e7e5a0dSBryan Schumaker 
961da177e4SLinus Torvalds /*
971da177e4SLinus Torvalds  * Map file type to S_IFMT bits
981da177e4SLinus Torvalds  */
99bca79478STrond Myklebust static const umode_t nfs_type2fmt[] = {
100bca79478STrond Myklebust 	[NF3BAD] = 0,
101bca79478STrond Myklebust 	[NF3REG] = S_IFREG,
102bca79478STrond Myklebust 	[NF3DIR] = S_IFDIR,
103bca79478STrond Myklebust 	[NF3BLK] = S_IFBLK,
104bca79478STrond Myklebust 	[NF3CHR] = S_IFCHR,
105bca79478STrond Myklebust 	[NF3LNK] = S_IFLNK,
106bca79478STrond Myklebust 	[NF3SOCK] = S_IFSOCK,
107bca79478STrond Myklebust 	[NF3FIFO] = S_IFIFO,
1081da177e4SLinus Torvalds };
1091da177e4SLinus Torvalds 
rpc_userns(const struct rpc_clnt * clnt)110264d948cSTrond Myklebust static struct user_namespace *rpc_userns(const struct rpc_clnt *clnt)
111264d948cSTrond Myklebust {
112264d948cSTrond Myklebust 	if (clnt && clnt->cl_cred)
113264d948cSTrond Myklebust 		return clnt->cl_cred->user_ns;
114264d948cSTrond Myklebust 	return &init_user_ns;
115264d948cSTrond Myklebust }
116264d948cSTrond Myklebust 
rpc_rqst_userns(const struct rpc_rqst * rqstp)117264d948cSTrond Myklebust static struct user_namespace *rpc_rqst_userns(const struct rpc_rqst *rqstp)
118264d948cSTrond Myklebust {
119264d948cSTrond Myklebust 	if (rqstp->rq_task)
120264d948cSTrond Myklebust 		return rpc_userns(rqstp->rq_task->tk_client);
121264d948cSTrond Myklebust 	return &init_user_ns;
122264d948cSTrond Myklebust }
123264d948cSTrond Myklebust 
1241da177e4SLinus Torvalds /*
125d9c407b1SChuck Lever  * Encode/decode NFSv3 basic data types
126d9c407b1SChuck Lever  *
127d9c407b1SChuck Lever  * Basic NFSv3 data types are defined in section 2.5 of RFC 1813:
128d9c407b1SChuck Lever  * "NFS Version 3 Protocol Specification".
129d9c407b1SChuck Lever  *
130d9c407b1SChuck Lever  * Not all basic data types have their own encoding and decoding
131d9c407b1SChuck Lever  * functions.  For run-time efficiency, some data types are encoded
132d9c407b1SChuck Lever  * or decoded inline.
133d9c407b1SChuck Lever  */
134d9c407b1SChuck Lever 
encode_uint32(struct xdr_stream * xdr,u32 value)135d9c407b1SChuck Lever static void encode_uint32(struct xdr_stream *xdr, u32 value)
136d9c407b1SChuck Lever {
137d9c407b1SChuck Lever 	__be32 *p = xdr_reserve_space(xdr, 4);
138d9c407b1SChuck Lever 	*p = cpu_to_be32(value);
139d9c407b1SChuck Lever }
140d9c407b1SChuck Lever 
decode_uint32(struct xdr_stream * xdr,u32 * value)141e4f93234SChuck Lever static int decode_uint32(struct xdr_stream *xdr, u32 *value)
142e4f93234SChuck Lever {
143e4f93234SChuck Lever 	__be32 *p;
144e4f93234SChuck Lever 
145e4f93234SChuck Lever 	p = xdr_inline_decode(xdr, 4);
146eb72f484SChuck Lever 	if (unlikely(!p))
147eb72f484SChuck Lever 		return -EIO;
148e4f93234SChuck Lever 	*value = be32_to_cpup(p);
149e4f93234SChuck Lever 	return 0;
150e4f93234SChuck Lever }
151e4f93234SChuck Lever 
decode_uint64(struct xdr_stream * xdr,u64 * value)152e4f93234SChuck Lever static int decode_uint64(struct xdr_stream *xdr, u64 *value)
153e4f93234SChuck Lever {
154e4f93234SChuck Lever 	__be32 *p;
155e4f93234SChuck Lever 
156e4f93234SChuck Lever 	p = xdr_inline_decode(xdr, 8);
157eb72f484SChuck Lever 	if (unlikely(!p))
158eb72f484SChuck Lever 		return -EIO;
159e4f93234SChuck Lever 	xdr_decode_hyper(p, value);
160e4f93234SChuck Lever 	return 0;
161e4f93234SChuck Lever }
162e4f93234SChuck Lever 
163e4f93234SChuck Lever /*
164e4f93234SChuck Lever  * fileid3
165e4f93234SChuck Lever  *
166e4f93234SChuck Lever  *	typedef uint64 fileid3;
167e4f93234SChuck Lever  */
xdr_decode_fileid3(__be32 * p,u64 * fileid)168f6048709SChuck Lever static __be32 *xdr_decode_fileid3(__be32 *p, u64 *fileid)
169f6048709SChuck Lever {
170f6048709SChuck Lever 	return xdr_decode_hyper(p, fileid);
171f6048709SChuck Lever }
172f6048709SChuck Lever 
decode_fileid3(struct xdr_stream * xdr,u64 * fileid)173e4f93234SChuck Lever static int decode_fileid3(struct xdr_stream *xdr, u64 *fileid)
174e4f93234SChuck Lever {
175e4f93234SChuck Lever 	return decode_uint64(xdr, fileid);
176e4f93234SChuck Lever }
177e4f93234SChuck Lever 
178d9c407b1SChuck Lever /*
179d9c407b1SChuck Lever  * filename3
180d9c407b1SChuck Lever  *
181d9c407b1SChuck Lever  *	typedef string filename3<>;
182d9c407b1SChuck Lever  */
encode_filename3(struct xdr_stream * xdr,const char * name,u32 length)183d9c407b1SChuck Lever static void encode_filename3(struct xdr_stream *xdr,
184d9c407b1SChuck Lever 			     const char *name, u32 length)
185d9c407b1SChuck Lever {
186d9c407b1SChuck Lever 	__be32 *p;
187d9c407b1SChuck Lever 
1887fc38846STrond Myklebust 	WARN_ON_ONCE(length > NFS3_MAXNAMLEN);
189d9c407b1SChuck Lever 	p = xdr_reserve_space(xdr, 4 + length);
190d9c407b1SChuck Lever 	xdr_encode_opaque(p, name, length);
191d9c407b1SChuck Lever }
192d9c407b1SChuck Lever 
decode_inline_filename3(struct xdr_stream * xdr,const char ** name,u32 * length)193e4f93234SChuck Lever static int decode_inline_filename3(struct xdr_stream *xdr,
194e4f93234SChuck Lever 				   const char **name, u32 *length)
195e4f93234SChuck Lever {
196e4f93234SChuck Lever 	__be32 *p;
197e4f93234SChuck Lever 	u32 count;
198e4f93234SChuck Lever 
199e4f93234SChuck Lever 	p = xdr_inline_decode(xdr, 4);
200eb72f484SChuck Lever 	if (unlikely(!p))
201eb72f484SChuck Lever 		return -EIO;
202e4f93234SChuck Lever 	count = be32_to_cpup(p);
203e4f93234SChuck Lever 	if (count > NFS3_MAXNAMLEN)
204e4f93234SChuck Lever 		goto out_nametoolong;
205e4f93234SChuck Lever 	p = xdr_inline_decode(xdr, count);
206eb72f484SChuck Lever 	if (unlikely(!p))
207eb72f484SChuck Lever 		return -EIO;
208e4f93234SChuck Lever 	*name = (const char *)p;
209e4f93234SChuck Lever 	*length = count;
210e4f93234SChuck Lever 	return 0;
211e4f93234SChuck Lever 
212e4f93234SChuck Lever out_nametoolong:
213e4f93234SChuck Lever 	dprintk("NFS: returned filename too long: %u\n", count);
214e4f93234SChuck Lever 	return -ENAMETOOLONG;
215e4f93234SChuck Lever }
216e4f93234SChuck Lever 
217d9c407b1SChuck Lever /*
218d9c407b1SChuck Lever  * nfspath3
219d9c407b1SChuck Lever  *
220d9c407b1SChuck Lever  *	typedef string nfspath3<>;
221d9c407b1SChuck Lever  */
encode_nfspath3(struct xdr_stream * xdr,struct page ** pages,const u32 length)222d9c407b1SChuck Lever static void encode_nfspath3(struct xdr_stream *xdr, struct page **pages,
223d9c407b1SChuck Lever 			    const u32 length)
224d9c407b1SChuck Lever {
225d9c407b1SChuck Lever 	encode_uint32(xdr, length);
226d9c407b1SChuck Lever 	xdr_write_pages(xdr, pages, 0, length);
227d9c407b1SChuck Lever }
228d9c407b1SChuck Lever 
decode_nfspath3(struct xdr_stream * xdr)229e4f93234SChuck Lever static int decode_nfspath3(struct xdr_stream *xdr)
230e4f93234SChuck Lever {
231e4f93234SChuck Lever 	u32 recvd, count;
232e4f93234SChuck Lever 	__be32 *p;
233e4f93234SChuck Lever 
234e4f93234SChuck Lever 	p = xdr_inline_decode(xdr, 4);
235eb72f484SChuck Lever 	if (unlikely(!p))
236eb72f484SChuck Lever 		return -EIO;
237e4f93234SChuck Lever 	count = be32_to_cpup(p);
238e4f93234SChuck Lever 	if (unlikely(count >= xdr->buf->page_len || count > NFS3_MAXPATHLEN))
239e4f93234SChuck Lever 		goto out_nametoolong;
24064bd577eSTrond Myklebust 	recvd = xdr_read_pages(xdr, count);
241e4f93234SChuck Lever 	if (unlikely(count > recvd))
242e4f93234SChuck Lever 		goto out_cheating;
243e4f93234SChuck Lever 	xdr_terminate_string(xdr->buf, count);
244e4f93234SChuck Lever 	return 0;
245e4f93234SChuck Lever 
246e4f93234SChuck Lever out_nametoolong:
247e4f93234SChuck Lever 	dprintk("NFS: returned pathname too long: %u\n", count);
248e4f93234SChuck Lever 	return -ENAMETOOLONG;
249e4f93234SChuck Lever out_cheating:
250e4f93234SChuck Lever 	dprintk("NFS: server cheating in pathname result: "
251e4f93234SChuck Lever 		"count %u > recvd %u\n", count, recvd);
252e4f93234SChuck Lever 	return -EIO;
253e4f93234SChuck Lever }
254e4f93234SChuck Lever 
255d9c407b1SChuck Lever /*
256d9c407b1SChuck Lever  * cookie3
257d9c407b1SChuck Lever  *
258d9c407b1SChuck Lever  *	typedef uint64 cookie3
259d9c407b1SChuck Lever  */
xdr_encode_cookie3(__be32 * p,u64 cookie)260d9c407b1SChuck Lever static __be32 *xdr_encode_cookie3(__be32 *p, u64 cookie)
261d9c407b1SChuck Lever {
262d9c407b1SChuck Lever 	return xdr_encode_hyper(p, cookie);
263d9c407b1SChuck Lever }
264d9c407b1SChuck Lever 
decode_cookie3(struct xdr_stream * xdr,u64 * cookie)265e4f93234SChuck Lever static int decode_cookie3(struct xdr_stream *xdr, u64 *cookie)
266e4f93234SChuck Lever {
267e4f93234SChuck Lever 	return decode_uint64(xdr, cookie);
268e4f93234SChuck Lever }
269e4f93234SChuck Lever 
270d9c407b1SChuck Lever /*
271d9c407b1SChuck Lever  * cookieverf3
272d9c407b1SChuck Lever  *
273d9c407b1SChuck Lever  *	typedef opaque cookieverf3[NFS3_COOKIEVERFSIZE];
274d9c407b1SChuck Lever  */
xdr_encode_cookieverf3(__be32 * p,const __be32 * verifier)275d9c407b1SChuck Lever static __be32 *xdr_encode_cookieverf3(__be32 *p, const __be32 *verifier)
276d9c407b1SChuck Lever {
277d9c407b1SChuck Lever 	memcpy(p, verifier, NFS3_COOKIEVERFSIZE);
278d9c407b1SChuck Lever 	return p + XDR_QUADLEN(NFS3_COOKIEVERFSIZE);
279d9c407b1SChuck Lever }
280d9c407b1SChuck Lever 
decode_cookieverf3(struct xdr_stream * xdr,__be32 * verifier)281e4f93234SChuck Lever static int decode_cookieverf3(struct xdr_stream *xdr, __be32 *verifier)
282e4f93234SChuck Lever {
283e4f93234SChuck Lever 	__be32 *p;
284e4f93234SChuck Lever 
285e4f93234SChuck Lever 	p = xdr_inline_decode(xdr, NFS3_COOKIEVERFSIZE);
286eb72f484SChuck Lever 	if (unlikely(!p))
287eb72f484SChuck Lever 		return -EIO;
288e4f93234SChuck Lever 	memcpy(verifier, p, NFS3_COOKIEVERFSIZE);
289e4f93234SChuck Lever 	return 0;
290e4f93234SChuck Lever }
291e4f93234SChuck Lever 
292d9c407b1SChuck Lever /*
293d9c407b1SChuck Lever  * createverf3
294d9c407b1SChuck Lever  *
295d9c407b1SChuck Lever  *	typedef opaque createverf3[NFS3_CREATEVERFSIZE];
296d9c407b1SChuck Lever  */
encode_createverf3(struct xdr_stream * xdr,const __be32 * verifier)297d9c407b1SChuck Lever static void encode_createverf3(struct xdr_stream *xdr, const __be32 *verifier)
298d9c407b1SChuck Lever {
299d9c407b1SChuck Lever 	__be32 *p;
300d9c407b1SChuck Lever 
301d9c407b1SChuck Lever 	p = xdr_reserve_space(xdr, NFS3_CREATEVERFSIZE);
302d9c407b1SChuck Lever 	memcpy(p, verifier, NFS3_CREATEVERFSIZE);
303d9c407b1SChuck Lever }
304d9c407b1SChuck Lever 
decode_writeverf3(struct xdr_stream * xdr,struct nfs_write_verifier * verifier)3052f2c63bcSTrond Myklebust static int decode_writeverf3(struct xdr_stream *xdr, struct nfs_write_verifier *verifier)
306e4f93234SChuck Lever {
307e4f93234SChuck Lever 	__be32 *p;
308e4f93234SChuck Lever 
309e4f93234SChuck Lever 	p = xdr_inline_decode(xdr, NFS3_WRITEVERFSIZE);
310eb72f484SChuck Lever 	if (unlikely(!p))
311eb72f484SChuck Lever 		return -EIO;
3122f2c63bcSTrond Myklebust 	memcpy(verifier->data, p, NFS3_WRITEVERFSIZE);
313e4f93234SChuck Lever 	return 0;
314e4f93234SChuck Lever }
315e4f93234SChuck Lever 
316e4f93234SChuck Lever /*
317e4f93234SChuck Lever  * size3
318e4f93234SChuck Lever  *
319e4f93234SChuck Lever  *	typedef uint64 size3;
320e4f93234SChuck Lever  */
xdr_decode_size3(__be32 * p,u64 * size)321e4f93234SChuck Lever static __be32 *xdr_decode_size3(__be32 *p, u64 *size)
322e4f93234SChuck Lever {
323e4f93234SChuck Lever 	return xdr_decode_hyper(p, size);
324e4f93234SChuck Lever }
325e4f93234SChuck Lever 
326e4f93234SChuck Lever /*
327e4f93234SChuck Lever  * nfsstat3
328e4f93234SChuck Lever  *
329e4f93234SChuck Lever  *	enum nfsstat3 {
330e4f93234SChuck Lever  *		NFS3_OK = 0,
331e4f93234SChuck Lever  *		...
332e4f93234SChuck Lever  *	}
333e4f93234SChuck Lever  */
334e4f93234SChuck Lever #define NFS3_OK		NFS_OK
335e4f93234SChuck Lever 
decode_nfsstat3(struct xdr_stream * xdr,enum nfs_stat * status)336e4f93234SChuck Lever static int decode_nfsstat3(struct xdr_stream *xdr, enum nfs_stat *status)
337e4f93234SChuck Lever {
338e4f93234SChuck Lever 	__be32 *p;
339e4f93234SChuck Lever 
340e4f93234SChuck Lever 	p = xdr_inline_decode(xdr, 4);
341eb72f484SChuck Lever 	if (unlikely(!p))
342eb72f484SChuck Lever 		return -EIO;
343f23f6584SChuck Lever 	if (unlikely(*p != cpu_to_be32(NFS3_OK)))
344f23f6584SChuck Lever 		goto out_status;
345f23f6584SChuck Lever 	*status = 0;
346f23f6584SChuck Lever 	return 0;
347f23f6584SChuck Lever out_status:
348e4f93234SChuck Lever 	*status = be32_to_cpup(p);
34962a92ba9SChuck Lever 	trace_nfs_xdr_status(xdr, (int)*status);
350e4f93234SChuck Lever 	return 0;
351e4f93234SChuck Lever }
352e4f93234SChuck Lever 
353d9c407b1SChuck Lever /*
354d9c407b1SChuck Lever  * ftype3
355d9c407b1SChuck Lever  *
356d9c407b1SChuck Lever  *	enum ftype3 {
357d9c407b1SChuck Lever  *		NF3REG	= 1,
358d9c407b1SChuck Lever  *		NF3DIR	= 2,
359d9c407b1SChuck Lever  *		NF3BLK	= 3,
360d9c407b1SChuck Lever  *		NF3CHR	= 4,
361d9c407b1SChuck Lever  *		NF3LNK	= 5,
362d9c407b1SChuck Lever  *		NF3SOCK	= 6,
363d9c407b1SChuck Lever  *		NF3FIFO	= 7
364d9c407b1SChuck Lever  *	};
365d9c407b1SChuck Lever  */
encode_ftype3(struct xdr_stream * xdr,const u32 type)366d9c407b1SChuck Lever static void encode_ftype3(struct xdr_stream *xdr, const u32 type)
367d9c407b1SChuck Lever {
368d9c407b1SChuck Lever 	encode_uint32(xdr, type);
369d9c407b1SChuck Lever }
370d9c407b1SChuck Lever 
xdr_decode_ftype3(__be32 * p,umode_t * mode)371f6048709SChuck Lever static __be32 *xdr_decode_ftype3(__be32 *p, umode_t *mode)
372f6048709SChuck Lever {
373f6048709SChuck Lever 	u32 type;
374f6048709SChuck Lever 
375f6048709SChuck Lever 	type = be32_to_cpup(p++);
376f6048709SChuck Lever 	if (type > NF3FIFO)
377f6048709SChuck Lever 		type = NF3NON;
378f6048709SChuck Lever 	*mode = nfs_type2fmt[type];
379f6048709SChuck Lever 	return p;
380f6048709SChuck Lever }
381f6048709SChuck Lever 
382d9c407b1SChuck Lever /*
383d9c407b1SChuck Lever  * specdata3
384d9c407b1SChuck Lever  *
385d9c407b1SChuck Lever  *     struct specdata3 {
386d9c407b1SChuck Lever  *             uint32  specdata1;
387d9c407b1SChuck Lever  *             uint32  specdata2;
388d9c407b1SChuck Lever  *     };
389d9c407b1SChuck Lever  */
encode_specdata3(struct xdr_stream * xdr,const dev_t rdev)390d9c407b1SChuck Lever static void encode_specdata3(struct xdr_stream *xdr, const dev_t rdev)
391d9c407b1SChuck Lever {
392d9c407b1SChuck Lever 	__be32 *p;
393d9c407b1SChuck Lever 
394d9c407b1SChuck Lever 	p = xdr_reserve_space(xdr, 8);
395d9c407b1SChuck Lever 	*p++ = cpu_to_be32(MAJOR(rdev));
396d9c407b1SChuck Lever 	*p = cpu_to_be32(MINOR(rdev));
397d9c407b1SChuck Lever }
398d9c407b1SChuck Lever 
xdr_decode_specdata3(__be32 * p,dev_t * rdev)399f6048709SChuck Lever static __be32 *xdr_decode_specdata3(__be32 *p, dev_t *rdev)
400f6048709SChuck Lever {
401f6048709SChuck Lever 	unsigned int major, minor;
402f6048709SChuck Lever 
403f6048709SChuck Lever 	major = be32_to_cpup(p++);
404f6048709SChuck Lever 	minor = be32_to_cpup(p++);
405f6048709SChuck Lever 	*rdev = MKDEV(major, minor);
406f6048709SChuck Lever 	if (MAJOR(*rdev) != major || MINOR(*rdev) != minor)
407f6048709SChuck Lever 		*rdev = 0;
408f6048709SChuck Lever 	return p;
409f6048709SChuck Lever }
410f6048709SChuck Lever 
411d9c407b1SChuck Lever /*
412d9c407b1SChuck Lever  * nfs_fh3
413d9c407b1SChuck Lever  *
414d9c407b1SChuck Lever  *	struct nfs_fh3 {
415d9c407b1SChuck Lever  *		opaque       data<NFS3_FHSIZE>;
416d9c407b1SChuck Lever  *	};
417d9c407b1SChuck Lever  */
encode_nfs_fh3(struct xdr_stream * xdr,const struct nfs_fh * fh)418d9c407b1SChuck Lever static void encode_nfs_fh3(struct xdr_stream *xdr, const struct nfs_fh *fh)
419d9c407b1SChuck Lever {
420d9c407b1SChuck Lever 	__be32 *p;
421d9c407b1SChuck Lever 
4227fc38846STrond Myklebust 	WARN_ON_ONCE(fh->size > NFS3_FHSIZE);
423d9c407b1SChuck Lever 	p = xdr_reserve_space(xdr, 4 + fh->size);
424d9c407b1SChuck Lever 	xdr_encode_opaque(p, fh->data, fh->size);
425d9c407b1SChuck Lever }
426d9c407b1SChuck Lever 
decode_nfs_fh3(struct xdr_stream * xdr,struct nfs_fh * fh)427e4f93234SChuck Lever static int decode_nfs_fh3(struct xdr_stream *xdr, struct nfs_fh *fh)
428e4f93234SChuck Lever {
429e4f93234SChuck Lever 	u32 length;
430e4f93234SChuck Lever 	__be32 *p;
431e4f93234SChuck Lever 
432e4f93234SChuck Lever 	p = xdr_inline_decode(xdr, 4);
433eb72f484SChuck Lever 	if (unlikely(!p))
434eb72f484SChuck Lever 		return -EIO;
435e4f93234SChuck Lever 	length = be32_to_cpup(p++);
436eb3d58c6STrond Myklebust 	if (unlikely(length > NFS3_FHSIZE || length == 0))
437e4f93234SChuck Lever 		goto out_toobig;
438e4f93234SChuck Lever 	p = xdr_inline_decode(xdr, length);
439eb72f484SChuck Lever 	if (unlikely(!p))
440eb72f484SChuck Lever 		return -EIO;
441e4f93234SChuck Lever 	fh->size = length;
442e4f93234SChuck Lever 	memcpy(fh->data, p, length);
443e4f93234SChuck Lever 	return 0;
444e4f93234SChuck Lever out_toobig:
445eb3d58c6STrond Myklebust 	trace_nfs_xdr_bad_filehandle(xdr, NFSERR_BADHANDLE);
446e4f93234SChuck Lever 	return -E2BIG;
447e4f93234SChuck Lever }
448e4f93234SChuck Lever 
zero_nfs_fh3(struct nfs_fh * fh)449e4f93234SChuck Lever static void zero_nfs_fh3(struct nfs_fh *fh)
450e4f93234SChuck Lever {
451e4f93234SChuck Lever 	memset(fh, 0, sizeof(*fh));
452e4f93234SChuck Lever }
453e4f93234SChuck Lever 
454d9c407b1SChuck Lever /*
4559d5a6434SChuck Lever  * nfstime3
4569d5a6434SChuck Lever  *
4579d5a6434SChuck Lever  *	struct nfstime3 {
4589d5a6434SChuck Lever  *		uint32	seconds;
4599d5a6434SChuck Lever  *		uint32	nseconds;
4609d5a6434SChuck Lever  *	};
4619d5a6434SChuck Lever  */
xdr_encode_nfstime3(__be32 * p,const struct timespec64 * timep)4626430b323STrond Myklebust static __be32 *xdr_encode_nfstime3(__be32 *p, const struct timespec64 *timep)
4639d5a6434SChuck Lever {
4646430b323STrond Myklebust 	*p++ = cpu_to_be32((u32)timep->tv_sec);
4659d5a6434SChuck Lever 	*p++ = cpu_to_be32(timep->tv_nsec);
4669d5a6434SChuck Lever 	return p;
4679d5a6434SChuck Lever }
4689d5a6434SChuck Lever 
xdr_decode_nfstime3(__be32 * p,struct timespec64 * timep)469e86d5a02STrond Myklebust static __be32 *xdr_decode_nfstime3(__be32 *p, struct timespec64 *timep)
470f6048709SChuck Lever {
471f6048709SChuck Lever 	timep->tv_sec = be32_to_cpup(p++);
472f6048709SChuck Lever 	timep->tv_nsec = be32_to_cpup(p++);
473f6048709SChuck Lever 	return p;
474f6048709SChuck Lever }
475f6048709SChuck Lever 
4769d5a6434SChuck Lever /*
477d9c407b1SChuck Lever  * sattr3
478d9c407b1SChuck Lever  *
479d9c407b1SChuck Lever  *	enum time_how {
480d9c407b1SChuck Lever  *		DONT_CHANGE		= 0,
481d9c407b1SChuck Lever  *		SET_TO_SERVER_TIME	= 1,
482d9c407b1SChuck Lever  *		SET_TO_CLIENT_TIME	= 2
483d9c407b1SChuck Lever  *	};
484d9c407b1SChuck Lever  *
485d9c407b1SChuck Lever  *	union set_mode3 switch (bool set_it) {
486d9c407b1SChuck Lever  *	case TRUE:
487d9c407b1SChuck Lever  *		mode3	mode;
488d9c407b1SChuck Lever  *	default:
489d9c407b1SChuck Lever  *		void;
490d9c407b1SChuck Lever  *	};
491d9c407b1SChuck Lever  *
492d9c407b1SChuck Lever  *	union set_uid3 switch (bool set_it) {
493d9c407b1SChuck Lever  *	case TRUE:
494d9c407b1SChuck Lever  *		uid3	uid;
495d9c407b1SChuck Lever  *	default:
496d9c407b1SChuck Lever  *		void;
497d9c407b1SChuck Lever  *	};
498d9c407b1SChuck Lever  *
499d9c407b1SChuck Lever  *	union set_gid3 switch (bool set_it) {
500d9c407b1SChuck Lever  *	case TRUE:
501d9c407b1SChuck Lever  *		gid3	gid;
502d9c407b1SChuck Lever  *	default:
503d9c407b1SChuck Lever  *		void;
504d9c407b1SChuck Lever  *	};
505d9c407b1SChuck Lever  *
506d9c407b1SChuck Lever  *	union set_size3 switch (bool set_it) {
507d9c407b1SChuck Lever  *	case TRUE:
508d9c407b1SChuck Lever  *		size3	size;
509d9c407b1SChuck Lever  *	default:
510d9c407b1SChuck Lever  *		void;
511d9c407b1SChuck Lever  *	};
512d9c407b1SChuck Lever  *
513d9c407b1SChuck Lever  *	union set_atime switch (time_how set_it) {
514d9c407b1SChuck Lever  *	case SET_TO_CLIENT_TIME:
515d9c407b1SChuck Lever  *		nfstime3	atime;
516d9c407b1SChuck Lever  *	default:
517d9c407b1SChuck Lever  *		void;
518d9c407b1SChuck Lever  *	};
519d9c407b1SChuck Lever  *
520d9c407b1SChuck Lever  *	union set_mtime switch (time_how set_it) {
521d9c407b1SChuck Lever  *	case SET_TO_CLIENT_TIME:
522d9c407b1SChuck Lever  *		nfstime3  mtime;
523d9c407b1SChuck Lever  *	default:
524d9c407b1SChuck Lever  *		void;
525d9c407b1SChuck Lever  *	};
526d9c407b1SChuck Lever  *
527d9c407b1SChuck Lever  *	struct sattr3 {
528d9c407b1SChuck Lever  *		set_mode3	mode;
529d9c407b1SChuck Lever  *		set_uid3	uid;
530d9c407b1SChuck Lever  *		set_gid3	gid;
531d9c407b1SChuck Lever  *		set_size3	size;
532d9c407b1SChuck Lever  *		set_atime	atime;
533d9c407b1SChuck Lever  *		set_mtime	mtime;
534d9c407b1SChuck Lever  *	};
535d9c407b1SChuck Lever  */
encode_sattr3(struct xdr_stream * xdr,const struct iattr * attr,struct user_namespace * userns)536264d948cSTrond Myklebust static void encode_sattr3(struct xdr_stream *xdr, const struct iattr *attr,
537264d948cSTrond Myklebust 		struct user_namespace *userns)
538d9c407b1SChuck Lever {
539d9c407b1SChuck Lever 	u32 nbytes;
540d9c407b1SChuck Lever 	__be32 *p;
541d9c407b1SChuck Lever 
542d9c407b1SChuck Lever 	/*
543d9c407b1SChuck Lever 	 * In order to make only a single xdr_reserve_space() call,
544d9c407b1SChuck Lever 	 * pre-compute the total number of bytes to be reserved.
545d9c407b1SChuck Lever 	 * Six boolean values, one for each set_foo field, are always
546d9c407b1SChuck Lever 	 * present in the encoded result, so start there.
547d9c407b1SChuck Lever 	 */
548d9c407b1SChuck Lever 	nbytes = 6 * 4;
549d9c407b1SChuck Lever 	if (attr->ia_valid & ATTR_MODE)
550d9c407b1SChuck Lever 		nbytes += 4;
551d9c407b1SChuck Lever 	if (attr->ia_valid & ATTR_UID)
552d9c407b1SChuck Lever 		nbytes += 4;
553d9c407b1SChuck Lever 	if (attr->ia_valid & ATTR_GID)
554d9c407b1SChuck Lever 		nbytes += 4;
555d9c407b1SChuck Lever 	if (attr->ia_valid & ATTR_SIZE)
556d9c407b1SChuck Lever 		nbytes += 8;
557d9c407b1SChuck Lever 	if (attr->ia_valid & ATTR_ATIME_SET)
558d9c407b1SChuck Lever 		nbytes += 8;
559d9c407b1SChuck Lever 	if (attr->ia_valid & ATTR_MTIME_SET)
560d9c407b1SChuck Lever 		nbytes += 8;
561d9c407b1SChuck Lever 	p = xdr_reserve_space(xdr, nbytes);
562d9c407b1SChuck Lever 
5639d5a6434SChuck Lever 	if (attr->ia_valid & ATTR_MODE) {
5649d5a6434SChuck Lever 		*p++ = xdr_one;
5659d5a6434SChuck Lever 		*p++ = cpu_to_be32(attr->ia_mode & S_IALLUGO);
5669d5a6434SChuck Lever 	} else
5679d5a6434SChuck Lever 		*p++ = xdr_zero;
5689d5a6434SChuck Lever 
5699d5a6434SChuck Lever 	if (attr->ia_valid & ATTR_UID) {
5709d5a6434SChuck Lever 		*p++ = xdr_one;
571264d948cSTrond Myklebust 		*p++ = cpu_to_be32(from_kuid_munged(userns, attr->ia_uid));
5729d5a6434SChuck Lever 	} else
5739d5a6434SChuck Lever 		*p++ = xdr_zero;
5749d5a6434SChuck Lever 
5759d5a6434SChuck Lever 	if (attr->ia_valid & ATTR_GID) {
5769d5a6434SChuck Lever 		*p++ = xdr_one;
577264d948cSTrond Myklebust 		*p++ = cpu_to_be32(from_kgid_munged(userns, attr->ia_gid));
5789d5a6434SChuck Lever 	} else
5799d5a6434SChuck Lever 		*p++ = xdr_zero;
5809d5a6434SChuck Lever 
5819d5a6434SChuck Lever 	if (attr->ia_valid & ATTR_SIZE) {
5829d5a6434SChuck Lever 		*p++ = xdr_one;
5839d5a6434SChuck Lever 		p = xdr_encode_hyper(p, (u64)attr->ia_size);
5849d5a6434SChuck Lever 	} else
5859d5a6434SChuck Lever 		*p++ = xdr_zero;
5869d5a6434SChuck Lever 
5879d5a6434SChuck Lever 	if (attr->ia_valid & ATTR_ATIME_SET) {
5889d5a6434SChuck Lever 		*p++ = xdr_two;
5896430b323STrond Myklebust 		p = xdr_encode_nfstime3(p, &attr->ia_atime);
5909d5a6434SChuck Lever 	} else if (attr->ia_valid & ATTR_ATIME) {
5919d5a6434SChuck Lever 		*p++ = xdr_one;
5929d5a6434SChuck Lever 	} else
5939d5a6434SChuck Lever 		*p++ = xdr_zero;
5949d5a6434SChuck Lever 
5959d5a6434SChuck Lever 	if (attr->ia_valid & ATTR_MTIME_SET) {
5969d5a6434SChuck Lever 		*p++ = xdr_two;
5976430b323STrond Myklebust 		xdr_encode_nfstime3(p, &attr->ia_mtime);
5989d5a6434SChuck Lever 	} else if (attr->ia_valid & ATTR_MTIME) {
5999d5a6434SChuck Lever 		*p = xdr_one;
6009d5a6434SChuck Lever 	} else
6019d5a6434SChuck Lever 		*p = xdr_zero;
602d9c407b1SChuck Lever }
603d9c407b1SChuck Lever 
604d9c407b1SChuck Lever /*
605e4f93234SChuck Lever  * fattr3
606e4f93234SChuck Lever  *
607e4f93234SChuck Lever  *	struct fattr3 {
608e4f93234SChuck Lever  *		ftype3		type;
609e4f93234SChuck Lever  *		mode3		mode;
610e4f93234SChuck Lever  *		uint32		nlink;
611e4f93234SChuck Lever  *		uid3		uid;
612e4f93234SChuck Lever  *		gid3		gid;
613e4f93234SChuck Lever  *		size3		size;
614e4f93234SChuck Lever  *		size3		used;
615e4f93234SChuck Lever  *		specdata3	rdev;
616e4f93234SChuck Lever  *		uint64		fsid;
617e4f93234SChuck Lever  *		fileid3		fileid;
618e4f93234SChuck Lever  *		nfstime3	atime;
619e4f93234SChuck Lever  *		nfstime3	mtime;
620e4f93234SChuck Lever  *		nfstime3	ctime;
621e4f93234SChuck Lever  *	};
622e4f93234SChuck Lever  */
decode_fattr3(struct xdr_stream * xdr,struct nfs_fattr * fattr,struct user_namespace * userns)623264d948cSTrond Myklebust static int decode_fattr3(struct xdr_stream *xdr, struct nfs_fattr *fattr,
624264d948cSTrond Myklebust 		struct user_namespace *userns)
625e4f93234SChuck Lever {
626f6048709SChuck Lever 	umode_t fmode;
627e4f93234SChuck Lever 	__be32 *p;
628e4f93234SChuck Lever 
629e4f93234SChuck Lever 	p = xdr_inline_decode(xdr, NFS3_fattr_sz << 2);
630eb72f484SChuck Lever 	if (unlikely(!p))
631eb72f484SChuck Lever 		return -EIO;
632f6048709SChuck Lever 
633f6048709SChuck Lever 	p = xdr_decode_ftype3(p, &fmode);
634f6048709SChuck Lever 
635f6048709SChuck Lever 	fattr->mode = (be32_to_cpup(p++) & ~S_IFMT) | fmode;
636f6048709SChuck Lever 	fattr->nlink = be32_to_cpup(p++);
637264d948cSTrond Myklebust 	fattr->uid = make_kuid(userns, be32_to_cpup(p++));
63857a38daeSEric W. Biederman 	if (!uid_valid(fattr->uid))
63957a38daeSEric W. Biederman 		goto out_uid;
640264d948cSTrond Myklebust 	fattr->gid = make_kgid(userns, be32_to_cpup(p++));
64157a38daeSEric W. Biederman 	if (!gid_valid(fattr->gid))
64257a38daeSEric W. Biederman 		goto out_gid;
643f6048709SChuck Lever 
644f6048709SChuck Lever 	p = xdr_decode_size3(p, &fattr->size);
645f6048709SChuck Lever 	p = xdr_decode_size3(p, &fattr->du.nfs3.used);
646f6048709SChuck Lever 	p = xdr_decode_specdata3(p, &fattr->rdev);
647f6048709SChuck Lever 
648f6048709SChuck Lever 	p = xdr_decode_hyper(p, &fattr->fsid.major);
649f6048709SChuck Lever 	fattr->fsid.minor = 0;
650f6048709SChuck Lever 
651f6048709SChuck Lever 	p = xdr_decode_fileid3(p, &fattr->fileid);
652f6048709SChuck Lever 	p = xdr_decode_nfstime3(p, &fattr->atime);
653f6048709SChuck Lever 	p = xdr_decode_nfstime3(p, &fattr->mtime);
654f6048709SChuck Lever 	xdr_decode_nfstime3(p, &fattr->ctime);
6553a1556e8STrond Myklebust 	fattr->change_attr = nfs_timespec_to_change_attr(&fattr->ctime);
656f6048709SChuck Lever 
657f6048709SChuck Lever 	fattr->valid |= NFS_ATTR_FATTR_V3;
658e4f93234SChuck Lever 	return 0;
65957a38daeSEric W. Biederman out_uid:
66057a38daeSEric W. Biederman 	dprintk("NFS: returned invalid uid\n");
66157a38daeSEric W. Biederman 	return -EINVAL;
66257a38daeSEric W. Biederman out_gid:
66357a38daeSEric W. Biederman 	dprintk("NFS: returned invalid gid\n");
66457a38daeSEric W. Biederman 	return -EINVAL;
665e4f93234SChuck Lever }
666e4f93234SChuck Lever 
667e4f93234SChuck Lever /*
668e4f93234SChuck Lever  * post_op_attr
669e4f93234SChuck Lever  *
670e4f93234SChuck Lever  *	union post_op_attr switch (bool attributes_follow) {
671e4f93234SChuck Lever  *	case TRUE:
672e4f93234SChuck Lever  *		fattr3	attributes;
673e4f93234SChuck Lever  *	case FALSE:
674e4f93234SChuck Lever  *		void;
675e4f93234SChuck Lever  *	};
676e4f93234SChuck Lever  */
decode_post_op_attr(struct xdr_stream * xdr,struct nfs_fattr * fattr,struct user_namespace * userns)677264d948cSTrond Myklebust static int decode_post_op_attr(struct xdr_stream *xdr, struct nfs_fattr *fattr,
678264d948cSTrond Myklebust 		struct user_namespace *userns)
679e4f93234SChuck Lever {
680e4f93234SChuck Lever 	__be32 *p;
681e4f93234SChuck Lever 
682e4f93234SChuck Lever 	p = xdr_inline_decode(xdr, 4);
683eb72f484SChuck Lever 	if (unlikely(!p))
684eb72f484SChuck Lever 		return -EIO;
685e4f93234SChuck Lever 	if (*p != xdr_zero)
686264d948cSTrond Myklebust 		return decode_fattr3(xdr, fattr, userns);
687e4f93234SChuck Lever 	return 0;
688e4f93234SChuck Lever }
689e4f93234SChuck Lever 
690e4f93234SChuck Lever /*
691e4f93234SChuck Lever  * wcc_attr
692e4f93234SChuck Lever  *	struct wcc_attr {
693e4f93234SChuck Lever  *		size3		size;
694e4f93234SChuck Lever  *		nfstime3	mtime;
695e4f93234SChuck Lever  *		nfstime3	ctime;
696e4f93234SChuck Lever  *	};
697e4f93234SChuck Lever  */
decode_wcc_attr(struct xdr_stream * xdr,struct nfs_fattr * fattr)698e4f93234SChuck Lever static int decode_wcc_attr(struct xdr_stream *xdr, struct nfs_fattr *fattr)
699e4f93234SChuck Lever {
700e4f93234SChuck Lever 	__be32 *p;
701e4f93234SChuck Lever 
702e4f93234SChuck Lever 	p = xdr_inline_decode(xdr, NFS3_wcc_attr_sz << 2);
703eb72f484SChuck Lever 	if (unlikely(!p))
704eb72f484SChuck Lever 		return -EIO;
705f6048709SChuck Lever 
706f6048709SChuck Lever 	fattr->valid |= NFS_ATTR_FATTR_PRESIZE
7073a1556e8STrond Myklebust 		| NFS_ATTR_FATTR_PRECHANGE
708f6048709SChuck Lever 		| NFS_ATTR_FATTR_PREMTIME
709f6048709SChuck Lever 		| NFS_ATTR_FATTR_PRECTIME;
710f6048709SChuck Lever 
711f6048709SChuck Lever 	p = xdr_decode_size3(p, &fattr->pre_size);
712f6048709SChuck Lever 	p = xdr_decode_nfstime3(p, &fattr->pre_mtime);
713f6048709SChuck Lever 	xdr_decode_nfstime3(p, &fattr->pre_ctime);
7143a1556e8STrond Myklebust 	fattr->pre_change_attr = nfs_timespec_to_change_attr(&fattr->pre_ctime);
715f6048709SChuck Lever 
716e4f93234SChuck Lever 	return 0;
717e4f93234SChuck Lever }
718e4f93234SChuck Lever 
719e4f93234SChuck Lever /*
720e4f93234SChuck Lever  * pre_op_attr
721e4f93234SChuck Lever  *	union pre_op_attr switch (bool attributes_follow) {
722e4f93234SChuck Lever  *	case TRUE:
723e4f93234SChuck Lever  *		wcc_attr	attributes;
724e4f93234SChuck Lever  *	case FALSE:
725e4f93234SChuck Lever  *		void;
726e4f93234SChuck Lever  *	};
727e4f93234SChuck Lever  *
728e4f93234SChuck Lever  * wcc_data
729e4f93234SChuck Lever  *
730e4f93234SChuck Lever  *	struct wcc_data {
731e4f93234SChuck Lever  *		pre_op_attr	before;
732e4f93234SChuck Lever  *		post_op_attr	after;
733e4f93234SChuck Lever  *	};
734e4f93234SChuck Lever  */
decode_pre_op_attr(struct xdr_stream * xdr,struct nfs_fattr * fattr)735e4f93234SChuck Lever static int decode_pre_op_attr(struct xdr_stream *xdr, struct nfs_fattr *fattr)
736e4f93234SChuck Lever {
737e4f93234SChuck Lever 	__be32 *p;
738e4f93234SChuck Lever 
739e4f93234SChuck Lever 	p = xdr_inline_decode(xdr, 4);
740eb72f484SChuck Lever 	if (unlikely(!p))
741eb72f484SChuck Lever 		return -EIO;
742e4f93234SChuck Lever 	if (*p != xdr_zero)
743e4f93234SChuck Lever 		return decode_wcc_attr(xdr, fattr);
744e4f93234SChuck Lever 	return 0;
745e4f93234SChuck Lever }
746e4f93234SChuck Lever 
decode_wcc_data(struct xdr_stream * xdr,struct nfs_fattr * fattr,struct user_namespace * userns)747264d948cSTrond Myklebust static int decode_wcc_data(struct xdr_stream *xdr, struct nfs_fattr *fattr,
748264d948cSTrond Myklebust 		struct user_namespace *userns)
749e4f93234SChuck Lever {
750e4f93234SChuck Lever 	int error;
751e4f93234SChuck Lever 
752e4f93234SChuck Lever 	error = decode_pre_op_attr(xdr, fattr);
753e4f93234SChuck Lever 	if (unlikely(error))
754e4f93234SChuck Lever 		goto out;
755264d948cSTrond Myklebust 	error = decode_post_op_attr(xdr, fattr, userns);
756e4f93234SChuck Lever out:
757e4f93234SChuck Lever 	return error;
758e4f93234SChuck Lever }
759e4f93234SChuck Lever 
760e4f93234SChuck Lever /*
761e4f93234SChuck Lever  * post_op_fh3
762e4f93234SChuck Lever  *
763e4f93234SChuck Lever  *	union post_op_fh3 switch (bool handle_follows) {
764e4f93234SChuck Lever  *	case TRUE:
765e4f93234SChuck Lever  *		nfs_fh3  handle;
766e4f93234SChuck Lever  *	case FALSE:
767e4f93234SChuck Lever  *		void;
768e4f93234SChuck Lever  *	};
769e4f93234SChuck Lever  */
decode_post_op_fh3(struct xdr_stream * xdr,struct nfs_fh * fh)770e4f93234SChuck Lever static int decode_post_op_fh3(struct xdr_stream *xdr, struct nfs_fh *fh)
771e4f93234SChuck Lever {
772e4f93234SChuck Lever 	__be32 *p = xdr_inline_decode(xdr, 4);
773eb72f484SChuck Lever 	if (unlikely(!p))
774eb72f484SChuck Lever 		return -EIO;
775e4f93234SChuck Lever 	if (*p != xdr_zero)
776e4f93234SChuck Lever 		return decode_nfs_fh3(xdr, fh);
777e4f93234SChuck Lever 	zero_nfs_fh3(fh);
778e4f93234SChuck Lever 	return 0;
779e4f93234SChuck Lever }
780e4f93234SChuck Lever 
781e4f93234SChuck Lever /*
782d9c407b1SChuck Lever  * diropargs3
783d9c407b1SChuck Lever  *
784d9c407b1SChuck Lever  *	struct diropargs3 {
785d9c407b1SChuck Lever  *		nfs_fh3		dir;
786d9c407b1SChuck Lever  *		filename3	name;
787d9c407b1SChuck Lever  *	};
788d9c407b1SChuck Lever  */
encode_diropargs3(struct xdr_stream * xdr,const struct nfs_fh * fh,const char * name,u32 length)789d9c407b1SChuck Lever static void encode_diropargs3(struct xdr_stream *xdr, const struct nfs_fh *fh,
790d9c407b1SChuck Lever 			      const char *name, u32 length)
791d9c407b1SChuck Lever {
792d9c407b1SChuck Lever 	encode_nfs_fh3(xdr, fh);
793d9c407b1SChuck Lever 	encode_filename3(xdr, name, length);
794d9c407b1SChuck Lever }
795d9c407b1SChuck Lever 
796d9c407b1SChuck Lever 
7971da177e4SLinus Torvalds /*
798499ff710SChuck Lever  * NFSv3 XDR encode functions
799499ff710SChuck Lever  *
800499ff710SChuck Lever  * NFSv3 argument types are defined in section 3.3 of RFC 1813:
801499ff710SChuck Lever  * "NFS Version 3 Protocol Specification".
8021da177e4SLinus Torvalds  */
8031da177e4SLinus Torvalds 
8041da177e4SLinus Torvalds /*
805d9c407b1SChuck Lever  * 3.3.1  GETATTR3args
806d9c407b1SChuck Lever  *
807d9c407b1SChuck Lever  *	struct GETATTR3args {
808d9c407b1SChuck Lever  *		nfs_fh3  object;
809d9c407b1SChuck Lever  *	};
810d9c407b1SChuck Lever  */
nfs3_xdr_enc_getattr3args(struct rpc_rqst * req,struct xdr_stream * xdr,const void * data)8119f06c719SChuck Lever static void nfs3_xdr_enc_getattr3args(struct rpc_rqst *req,
8129f06c719SChuck Lever 				      struct xdr_stream *xdr,
813fcc85819SChristoph Hellwig 				      const void *data)
814d9c407b1SChuck Lever {
815fcc85819SChristoph Hellwig 	const struct nfs_fh *fh = data;
816fcc85819SChristoph Hellwig 
8179f06c719SChuck Lever 	encode_nfs_fh3(xdr, fh);
818d9c407b1SChuck Lever }
819d9c407b1SChuck Lever 
820d9c407b1SChuck Lever /*
821d9c407b1SChuck Lever  * 3.3.2  SETATTR3args
822d9c407b1SChuck Lever  *
823d9c407b1SChuck Lever  *	union sattrguard3 switch (bool check) {
824d9c407b1SChuck Lever  *	case TRUE:
825d9c407b1SChuck Lever  *		nfstime3  obj_ctime;
826d9c407b1SChuck Lever  *	case FALSE:
827d9c407b1SChuck Lever  *		void;
828d9c407b1SChuck Lever  *	};
829d9c407b1SChuck Lever  *
830d9c407b1SChuck Lever  *	struct SETATTR3args {
831d9c407b1SChuck Lever  *		nfs_fh3		object;
832d9c407b1SChuck Lever  *		sattr3		new_attributes;
833d9c407b1SChuck Lever  *		sattrguard3	guard;
834d9c407b1SChuck Lever  *	};
835d9c407b1SChuck Lever  */
encode_sattrguard3(struct xdr_stream * xdr,const struct nfs3_sattrargs * args)836d9c407b1SChuck Lever static void encode_sattrguard3(struct xdr_stream *xdr,
837d9c407b1SChuck Lever 			       const struct nfs3_sattrargs *args)
838d9c407b1SChuck Lever {
839d9c407b1SChuck Lever 	__be32 *p;
840d9c407b1SChuck Lever 
841d9c407b1SChuck Lever 	if (args->guard) {
842d9c407b1SChuck Lever 		p = xdr_reserve_space(xdr, 4 + 8);
843d9c407b1SChuck Lever 		*p++ = xdr_one;
8449d5a6434SChuck Lever 		xdr_encode_nfstime3(p, &args->guardtime);
845d9c407b1SChuck Lever 	} else {
846d9c407b1SChuck Lever 		p = xdr_reserve_space(xdr, 4);
847d9c407b1SChuck Lever 		*p = xdr_zero;
848d9c407b1SChuck Lever 	}
849d9c407b1SChuck Lever }
850d9c407b1SChuck Lever 
nfs3_xdr_enc_setattr3args(struct rpc_rqst * req,struct xdr_stream * xdr,const void * data)8519f06c719SChuck Lever static void nfs3_xdr_enc_setattr3args(struct rpc_rqst *req,
8529f06c719SChuck Lever 				      struct xdr_stream *xdr,
853fcc85819SChristoph Hellwig 				      const void *data)
854d9c407b1SChuck Lever {
855fcc85819SChristoph Hellwig 	const struct nfs3_sattrargs *args = data;
8569f06c719SChuck Lever 	encode_nfs_fh3(xdr, args->fh);
857264d948cSTrond Myklebust 	encode_sattr3(xdr, args->sattr, rpc_rqst_userns(req));
8589f06c719SChuck Lever 	encode_sattrguard3(xdr, args);
859d9c407b1SChuck Lever }
860d9c407b1SChuck Lever 
861d9c407b1SChuck Lever /*
862d9c407b1SChuck Lever  * 3.3.3  LOOKUP3args
863d9c407b1SChuck Lever  *
864d9c407b1SChuck Lever  *	struct LOOKUP3args {
865d9c407b1SChuck Lever  *		diropargs3  what;
866d9c407b1SChuck Lever  *	};
867d9c407b1SChuck Lever  */
nfs3_xdr_enc_lookup3args(struct rpc_rqst * req,struct xdr_stream * xdr,const void * data)8689f06c719SChuck Lever static void nfs3_xdr_enc_lookup3args(struct rpc_rqst *req,
8699f06c719SChuck Lever 				     struct xdr_stream *xdr,
870fcc85819SChristoph Hellwig 				     const void *data)
871d9c407b1SChuck Lever {
872fcc85819SChristoph Hellwig 	const struct nfs3_diropargs *args = data;
873fcc85819SChristoph Hellwig 
8749f06c719SChuck Lever 	encode_diropargs3(xdr, args->fh, args->name, args->len);
875d9c407b1SChuck Lever }
876d9c407b1SChuck Lever 
877d9c407b1SChuck Lever /*
878d9c407b1SChuck Lever  * 3.3.4  ACCESS3args
879d9c407b1SChuck Lever  *
880d9c407b1SChuck Lever  *	struct ACCESS3args {
881d9c407b1SChuck Lever  *		nfs_fh3		object;
882d9c407b1SChuck Lever  *		uint32		access;
883d9c407b1SChuck Lever  *	};
884d9c407b1SChuck Lever  */
encode_access3args(struct xdr_stream * xdr,const struct nfs3_accessargs * args)885d9c407b1SChuck Lever static void encode_access3args(struct xdr_stream *xdr,
886d9c407b1SChuck Lever 			       const struct nfs3_accessargs *args)
887d9c407b1SChuck Lever {
888d9c407b1SChuck Lever 	encode_nfs_fh3(xdr, args->fh);
889d9c407b1SChuck Lever 	encode_uint32(xdr, args->access);
890d9c407b1SChuck Lever }
891d9c407b1SChuck Lever 
nfs3_xdr_enc_access3args(struct rpc_rqst * req,struct xdr_stream * xdr,const void * data)8929f06c719SChuck Lever static void nfs3_xdr_enc_access3args(struct rpc_rqst *req,
8939f06c719SChuck Lever 				     struct xdr_stream *xdr,
894fcc85819SChristoph Hellwig 				     const void *data)
895d9c407b1SChuck Lever {
896fcc85819SChristoph Hellwig 	const struct nfs3_accessargs *args = data;
897fcc85819SChristoph Hellwig 
8989f06c719SChuck Lever 	encode_access3args(xdr, args);
899d9c407b1SChuck Lever }
900d9c407b1SChuck Lever 
901d9c407b1SChuck Lever /*
902d9c407b1SChuck Lever  * 3.3.5  READLINK3args
903d9c407b1SChuck Lever  *
904d9c407b1SChuck Lever  *	struct READLINK3args {
905d9c407b1SChuck Lever  *		nfs_fh3	symlink;
906d9c407b1SChuck Lever  *	};
907d9c407b1SChuck Lever  */
nfs3_xdr_enc_readlink3args(struct rpc_rqst * req,struct xdr_stream * xdr,const void * data)9089f06c719SChuck Lever static void nfs3_xdr_enc_readlink3args(struct rpc_rqst *req,
9099f06c719SChuck Lever 				       struct xdr_stream *xdr,
910fcc85819SChristoph Hellwig 				       const void *data)
911d9c407b1SChuck Lever {
912fcc85819SChristoph Hellwig 	const struct nfs3_readlinkargs *args = data;
913fcc85819SChristoph Hellwig 
9149f06c719SChuck Lever 	encode_nfs_fh3(xdr, args->fh);
9159ed5af26STrond Myklebust 	rpc_prepare_reply_pages(req, args->pages, args->pgbase, args->pglen,
9169ed5af26STrond Myklebust 				NFS3_readlinkres_sz - NFS3_pagepad_sz);
917d9c407b1SChuck Lever }
918d9c407b1SChuck Lever 
919d9c407b1SChuck Lever /*
920d9c407b1SChuck Lever  * 3.3.6  READ3args
921d9c407b1SChuck Lever  *
922d9c407b1SChuck Lever  *	struct READ3args {
923d9c407b1SChuck Lever  *		nfs_fh3		file;
924d9c407b1SChuck Lever  *		offset3		offset;
925d9c407b1SChuck Lever  *		count3		count;
926d9c407b1SChuck Lever  *	};
927d9c407b1SChuck Lever  */
encode_read3args(struct xdr_stream * xdr,const struct nfs_pgio_args * args)928d9c407b1SChuck Lever static void encode_read3args(struct xdr_stream *xdr,
9293c6b899cSAnna Schumaker 			     const struct nfs_pgio_args *args)
930d9c407b1SChuck Lever {
931d9c407b1SChuck Lever 	__be32 *p;
932d9c407b1SChuck Lever 
933d9c407b1SChuck Lever 	encode_nfs_fh3(xdr, args->fh);
934d9c407b1SChuck Lever 
935d9c407b1SChuck Lever 	p = xdr_reserve_space(xdr, 8 + 4);
936d9c407b1SChuck Lever 	p = xdr_encode_hyper(p, args->offset);
937d9c407b1SChuck Lever 	*p = cpu_to_be32(args->count);
938d9c407b1SChuck Lever }
939d9c407b1SChuck Lever 
nfs3_xdr_enc_read3args(struct rpc_rqst * req,struct xdr_stream * xdr,const void * data)9409f06c719SChuck Lever static void nfs3_xdr_enc_read3args(struct rpc_rqst *req,
9419f06c719SChuck Lever 				   struct xdr_stream *xdr,
942fcc85819SChristoph Hellwig 				   const void *data)
943d9c407b1SChuck Lever {
944fcc85819SChristoph Hellwig 	const struct nfs_pgio_args *args = data;
9459ed5af26STrond Myklebust 	unsigned int replen = args->replen ? args->replen :
9469ed5af26STrond Myklebust 					     NFS3_readres_sz - NFS3_pagepad_sz;
947fcc85819SChristoph Hellwig 
9489f06c719SChuck Lever 	encode_read3args(xdr, args);
949cf500bacSChuck Lever 	rpc_prepare_reply_pages(req, args->pages, args->pgbase,
9508d8928d8STrond Myklebust 				args->count, replen);
951d9c407b1SChuck Lever 	req->rq_rcv_buf.flags |= XDRBUF_READ;
952d9c407b1SChuck Lever }
953d9c407b1SChuck Lever 
954d9c407b1SChuck Lever /*
955d9c407b1SChuck Lever  * 3.3.7  WRITE3args
956d9c407b1SChuck Lever  *
957d9c407b1SChuck Lever  *	enum stable_how {
958d9c407b1SChuck Lever  *		UNSTABLE  = 0,
959d9c407b1SChuck Lever  *		DATA_SYNC = 1,
960d9c407b1SChuck Lever  *		FILE_SYNC = 2
961d9c407b1SChuck Lever  *	};
962d9c407b1SChuck Lever  *
963d9c407b1SChuck Lever  *	struct WRITE3args {
964d9c407b1SChuck Lever  *		nfs_fh3		file;
965d9c407b1SChuck Lever  *		offset3		offset;
966d9c407b1SChuck Lever  *		count3		count;
967d9c407b1SChuck Lever  *		stable_how	stable;
968d9c407b1SChuck Lever  *		opaque		data<>;
969d9c407b1SChuck Lever  *	};
970d9c407b1SChuck Lever  */
encode_write3args(struct xdr_stream * xdr,const struct nfs_pgio_args * args)971d9c407b1SChuck Lever static void encode_write3args(struct xdr_stream *xdr,
9723c6b899cSAnna Schumaker 			      const struct nfs_pgio_args *args)
973d9c407b1SChuck Lever {
974d9c407b1SChuck Lever 	__be32 *p;
975d9c407b1SChuck Lever 
976d9c407b1SChuck Lever 	encode_nfs_fh3(xdr, args->fh);
977d9c407b1SChuck Lever 
978d9c407b1SChuck Lever 	p = xdr_reserve_space(xdr, 8 + 4 + 4 + 4);
979d9c407b1SChuck Lever 	p = xdr_encode_hyper(p, args->offset);
980d9c407b1SChuck Lever 	*p++ = cpu_to_be32(args->count);
981d9c407b1SChuck Lever 	*p++ = cpu_to_be32(args->stable);
982d9c407b1SChuck Lever 	*p = cpu_to_be32(args->count);
983d9c407b1SChuck Lever 	xdr_write_pages(xdr, args->pages, args->pgbase, args->count);
984d9c407b1SChuck Lever }
985d9c407b1SChuck Lever 
nfs3_xdr_enc_write3args(struct rpc_rqst * req,struct xdr_stream * xdr,const void * data)9869f06c719SChuck Lever static void nfs3_xdr_enc_write3args(struct rpc_rqst *req,
9879f06c719SChuck Lever 				    struct xdr_stream *xdr,
988fcc85819SChristoph Hellwig 				    const void *data)
989d9c407b1SChuck Lever {
990fcc85819SChristoph Hellwig 	const struct nfs_pgio_args *args = data;
991fcc85819SChristoph Hellwig 
9929f06c719SChuck Lever 	encode_write3args(xdr, args);
9939f06c719SChuck Lever 	xdr->buf->flags |= XDRBUF_WRITE;
994d9c407b1SChuck Lever }
995d9c407b1SChuck Lever 
996d9c407b1SChuck Lever /*
997d9c407b1SChuck Lever  * 3.3.8  CREATE3args
998d9c407b1SChuck Lever  *
999d9c407b1SChuck Lever  *	enum createmode3 {
1000d9c407b1SChuck Lever  *		UNCHECKED = 0,
1001d9c407b1SChuck Lever  *		GUARDED   = 1,
1002d9c407b1SChuck Lever  *		EXCLUSIVE = 2
1003d9c407b1SChuck Lever  *	};
1004d9c407b1SChuck Lever  *
1005d9c407b1SChuck Lever  *	union createhow3 switch (createmode3 mode) {
1006d9c407b1SChuck Lever  *	case UNCHECKED:
1007d9c407b1SChuck Lever  *	case GUARDED:
1008d9c407b1SChuck Lever  *		sattr3       obj_attributes;
1009d9c407b1SChuck Lever  *	case EXCLUSIVE:
1010d9c407b1SChuck Lever  *		createverf3  verf;
1011d9c407b1SChuck Lever  *	};
1012d9c407b1SChuck Lever  *
1013d9c407b1SChuck Lever  *	struct CREATE3args {
1014d9c407b1SChuck Lever  *		diropargs3	where;
1015d9c407b1SChuck Lever  *		createhow3	how;
1016d9c407b1SChuck Lever  *	};
1017d9c407b1SChuck Lever  */
encode_createhow3(struct xdr_stream * xdr,const struct nfs3_createargs * args,struct user_namespace * userns)1018d9c407b1SChuck Lever static void encode_createhow3(struct xdr_stream *xdr,
1019264d948cSTrond Myklebust 			      const struct nfs3_createargs *args,
1020264d948cSTrond Myklebust 			      struct user_namespace *userns)
1021d9c407b1SChuck Lever {
1022d9c407b1SChuck Lever 	encode_uint32(xdr, args->createmode);
1023d9c407b1SChuck Lever 	switch (args->createmode) {
1024d9c407b1SChuck Lever 	case NFS3_CREATE_UNCHECKED:
1025d9c407b1SChuck Lever 	case NFS3_CREATE_GUARDED:
1026264d948cSTrond Myklebust 		encode_sattr3(xdr, args->sattr, userns);
1027d9c407b1SChuck Lever 		break;
1028d9c407b1SChuck Lever 	case NFS3_CREATE_EXCLUSIVE:
1029d9c407b1SChuck Lever 		encode_createverf3(xdr, args->verifier);
1030d9c407b1SChuck Lever 		break;
1031d9c407b1SChuck Lever 	default:
1032d9c407b1SChuck Lever 		BUG();
1033d9c407b1SChuck Lever 	}
1034d9c407b1SChuck Lever }
1035d9c407b1SChuck Lever 
nfs3_xdr_enc_create3args(struct rpc_rqst * req,struct xdr_stream * xdr,const void * data)10369f06c719SChuck Lever static void nfs3_xdr_enc_create3args(struct rpc_rqst *req,
10379f06c719SChuck Lever 				     struct xdr_stream *xdr,
1038fcc85819SChristoph Hellwig 				     const void *data)
1039d9c407b1SChuck Lever {
1040fcc85819SChristoph Hellwig 	const struct nfs3_createargs *args = data;
1041fcc85819SChristoph Hellwig 
10429f06c719SChuck Lever 	encode_diropargs3(xdr, args->fh, args->name, args->len);
1043264d948cSTrond Myklebust 	encode_createhow3(xdr, args, rpc_rqst_userns(req));
1044d9c407b1SChuck Lever }
1045d9c407b1SChuck Lever 
1046d9c407b1SChuck Lever /*
1047d9c407b1SChuck Lever  * 3.3.9  MKDIR3args
1048d9c407b1SChuck Lever  *
1049d9c407b1SChuck Lever  *	struct MKDIR3args {
1050d9c407b1SChuck Lever  *		diropargs3	where;
1051d9c407b1SChuck Lever  *		sattr3		attributes;
1052d9c407b1SChuck Lever  *	};
1053d9c407b1SChuck Lever  */
nfs3_xdr_enc_mkdir3args(struct rpc_rqst * req,struct xdr_stream * xdr,const void * data)10549f06c719SChuck Lever static void nfs3_xdr_enc_mkdir3args(struct rpc_rqst *req,
10559f06c719SChuck Lever 				    struct xdr_stream *xdr,
1056fcc85819SChristoph Hellwig 				    const void *data)
1057d9c407b1SChuck Lever {
1058fcc85819SChristoph Hellwig 	const struct nfs3_mkdirargs *args = data;
1059fcc85819SChristoph Hellwig 
10609f06c719SChuck Lever 	encode_diropargs3(xdr, args->fh, args->name, args->len);
1061264d948cSTrond Myklebust 	encode_sattr3(xdr, args->sattr, rpc_rqst_userns(req));
1062d9c407b1SChuck Lever }
1063d9c407b1SChuck Lever 
1064d9c407b1SChuck Lever /*
1065d9c407b1SChuck Lever  * 3.3.10  SYMLINK3args
1066d9c407b1SChuck Lever  *
1067d9c407b1SChuck Lever  *	struct symlinkdata3 {
1068d9c407b1SChuck Lever  *		sattr3		symlink_attributes;
1069d9c407b1SChuck Lever  *		nfspath3	symlink_data;
1070d9c407b1SChuck Lever  *	};
1071d9c407b1SChuck Lever  *
1072d9c407b1SChuck Lever  *	struct SYMLINK3args {
1073d9c407b1SChuck Lever  *		diropargs3	where;
1074d9c407b1SChuck Lever  *		symlinkdata3	symlink;
1075d9c407b1SChuck Lever  *	};
1076d9c407b1SChuck Lever  */
encode_symlinkdata3(struct xdr_stream * xdr,const void * data,struct user_namespace * userns)1077d9c407b1SChuck Lever static void encode_symlinkdata3(struct xdr_stream *xdr,
1078264d948cSTrond Myklebust 				const void *data,
1079264d948cSTrond Myklebust 				struct user_namespace *userns)
1080d9c407b1SChuck Lever {
1081fcc85819SChristoph Hellwig 	const struct nfs3_symlinkargs *args = data;
1082fcc85819SChristoph Hellwig 
1083264d948cSTrond Myklebust 	encode_sattr3(xdr, args->sattr, userns);
1084d9c407b1SChuck Lever 	encode_nfspath3(xdr, args->pages, args->pathlen);
1085d9c407b1SChuck Lever }
1086d9c407b1SChuck Lever 
nfs3_xdr_enc_symlink3args(struct rpc_rqst * req,struct xdr_stream * xdr,const void * data)10879f06c719SChuck Lever static void nfs3_xdr_enc_symlink3args(struct rpc_rqst *req,
10889f06c719SChuck Lever 				      struct xdr_stream *xdr,
1089fcc85819SChristoph Hellwig 				      const void *data)
1090d9c407b1SChuck Lever {
1091fcc85819SChristoph Hellwig 	const struct nfs3_symlinkargs *args = data;
1092fcc85819SChristoph Hellwig 
10939f06c719SChuck Lever 	encode_diropargs3(xdr, args->fromfh, args->fromname, args->fromlen);
1094264d948cSTrond Myklebust 	encode_symlinkdata3(xdr, args, rpc_rqst_userns(req));
10952fcc213aSChuck Lever 	xdr->buf->flags |= XDRBUF_WRITE;
1096d9c407b1SChuck Lever }
1097d9c407b1SChuck Lever 
1098d9c407b1SChuck Lever /*
1099d9c407b1SChuck Lever  * 3.3.11  MKNOD3args
1100d9c407b1SChuck Lever  *
1101d9c407b1SChuck Lever  *	struct devicedata3 {
1102d9c407b1SChuck Lever  *		sattr3		dev_attributes;
1103d9c407b1SChuck Lever  *		specdata3	spec;
1104d9c407b1SChuck Lever  *	};
1105d9c407b1SChuck Lever  *
1106d9c407b1SChuck Lever  *	union mknoddata3 switch (ftype3 type) {
1107d9c407b1SChuck Lever  *	case NF3CHR:
1108d9c407b1SChuck Lever  *	case NF3BLK:
1109d9c407b1SChuck Lever  *		devicedata3	device;
1110d9c407b1SChuck Lever  *	case NF3SOCK:
1111d9c407b1SChuck Lever  *	case NF3FIFO:
1112d9c407b1SChuck Lever  *		sattr3		pipe_attributes;
1113d9c407b1SChuck Lever  *	default:
1114d9c407b1SChuck Lever  *		void;
1115d9c407b1SChuck Lever  *	};
1116d9c407b1SChuck Lever  *
1117d9c407b1SChuck Lever  *	struct MKNOD3args {
1118d9c407b1SChuck Lever  *		diropargs3	where;
1119d9c407b1SChuck Lever  *		mknoddata3	what;
1120d9c407b1SChuck Lever  *	};
1121d9c407b1SChuck Lever  */
encode_devicedata3(struct xdr_stream * xdr,const struct nfs3_mknodargs * args,struct user_namespace * userns)1122d9c407b1SChuck Lever static void encode_devicedata3(struct xdr_stream *xdr,
1123264d948cSTrond Myklebust 			       const struct nfs3_mknodargs *args,
1124264d948cSTrond Myklebust 			       struct user_namespace *userns)
1125d9c407b1SChuck Lever {
1126264d948cSTrond Myklebust 	encode_sattr3(xdr, args->sattr, userns);
1127d9c407b1SChuck Lever 	encode_specdata3(xdr, args->rdev);
1128d9c407b1SChuck Lever }
1129d9c407b1SChuck Lever 
encode_mknoddata3(struct xdr_stream * xdr,const struct nfs3_mknodargs * args,struct user_namespace * userns)1130d9c407b1SChuck Lever static void encode_mknoddata3(struct xdr_stream *xdr,
1131264d948cSTrond Myklebust 			      const struct nfs3_mknodargs *args,
1132264d948cSTrond Myklebust 			      struct user_namespace *userns)
1133d9c407b1SChuck Lever {
1134d9c407b1SChuck Lever 	encode_ftype3(xdr, args->type);
1135d9c407b1SChuck Lever 	switch (args->type) {
1136d9c407b1SChuck Lever 	case NF3CHR:
1137d9c407b1SChuck Lever 	case NF3BLK:
1138264d948cSTrond Myklebust 		encode_devicedata3(xdr, args, userns);
1139d9c407b1SChuck Lever 		break;
1140d9c407b1SChuck Lever 	case NF3SOCK:
1141d9c407b1SChuck Lever 	case NF3FIFO:
1142264d948cSTrond Myklebust 		encode_sattr3(xdr, args->sattr, userns);
1143d9c407b1SChuck Lever 		break;
1144d9c407b1SChuck Lever 	case NF3REG:
1145d9c407b1SChuck Lever 	case NF3DIR:
1146d9c407b1SChuck Lever 		break;
1147d9c407b1SChuck Lever 	default:
1148d9c407b1SChuck Lever 		BUG();
1149d9c407b1SChuck Lever 	}
1150d9c407b1SChuck Lever }
1151d9c407b1SChuck Lever 
nfs3_xdr_enc_mknod3args(struct rpc_rqst * req,struct xdr_stream * xdr,const void * data)11529f06c719SChuck Lever static void nfs3_xdr_enc_mknod3args(struct rpc_rqst *req,
11539f06c719SChuck Lever 				    struct xdr_stream *xdr,
1154fcc85819SChristoph Hellwig 				    const void *data)
1155d9c407b1SChuck Lever {
1156fcc85819SChristoph Hellwig 	const struct nfs3_mknodargs *args = data;
1157fcc85819SChristoph Hellwig 
11589f06c719SChuck Lever 	encode_diropargs3(xdr, args->fh, args->name, args->len);
1159264d948cSTrond Myklebust 	encode_mknoddata3(xdr, args, rpc_rqst_userns(req));
1160d9c407b1SChuck Lever }
1161d9c407b1SChuck Lever 
1162d9c407b1SChuck Lever /*
1163d9c407b1SChuck Lever  * 3.3.12  REMOVE3args
1164d9c407b1SChuck Lever  *
1165d9c407b1SChuck Lever  *	struct REMOVE3args {
1166d9c407b1SChuck Lever  *		diropargs3  object;
1167d9c407b1SChuck Lever  *	};
1168d9c407b1SChuck Lever  */
nfs3_xdr_enc_remove3args(struct rpc_rqst * req,struct xdr_stream * xdr,const void * data)11699f06c719SChuck Lever static void nfs3_xdr_enc_remove3args(struct rpc_rqst *req,
11709f06c719SChuck Lever 				     struct xdr_stream *xdr,
1171fcc85819SChristoph Hellwig 				     const void *data)
1172d9c407b1SChuck Lever {
1173fcc85819SChristoph Hellwig 	const struct nfs_removeargs *args = data;
1174fcc85819SChristoph Hellwig 
11759f06c719SChuck Lever 	encode_diropargs3(xdr, args->fh, args->name.name, args->name.len);
1176d9c407b1SChuck Lever }
1177d9c407b1SChuck Lever 
1178d9c407b1SChuck Lever /*
1179d9c407b1SChuck Lever  * 3.3.14  RENAME3args
1180d9c407b1SChuck Lever  *
1181d9c407b1SChuck Lever  *	struct RENAME3args {
1182d9c407b1SChuck Lever  *		diropargs3	from;
1183d9c407b1SChuck Lever  *		diropargs3	to;
1184d9c407b1SChuck Lever  *	};
1185d9c407b1SChuck Lever  */
nfs3_xdr_enc_rename3args(struct rpc_rqst * req,struct xdr_stream * xdr,const void * data)11869f06c719SChuck Lever static void nfs3_xdr_enc_rename3args(struct rpc_rqst *req,
11879f06c719SChuck Lever 				     struct xdr_stream *xdr,
1188fcc85819SChristoph Hellwig 				     const void *data)
1189d9c407b1SChuck Lever {
1190fcc85819SChristoph Hellwig 	const struct nfs_renameargs *args = data;
1191d9c407b1SChuck Lever 	const struct qstr *old = args->old_name;
1192d9c407b1SChuck Lever 	const struct qstr *new = args->new_name;
1193d9c407b1SChuck Lever 
11949f06c719SChuck Lever 	encode_diropargs3(xdr, args->old_dir, old->name, old->len);
11959f06c719SChuck Lever 	encode_diropargs3(xdr, args->new_dir, new->name, new->len);
1196d9c407b1SChuck Lever }
1197d9c407b1SChuck Lever 
1198d9c407b1SChuck Lever /*
1199d9c407b1SChuck Lever  * 3.3.15  LINK3args
1200d9c407b1SChuck Lever  *
1201d9c407b1SChuck Lever  *	struct LINK3args {
1202d9c407b1SChuck Lever  *		nfs_fh3		file;
1203d9c407b1SChuck Lever  *		diropargs3	link;
1204d9c407b1SChuck Lever  *	};
1205d9c407b1SChuck Lever  */
nfs3_xdr_enc_link3args(struct rpc_rqst * req,struct xdr_stream * xdr,const void * data)12069f06c719SChuck Lever static void nfs3_xdr_enc_link3args(struct rpc_rqst *req,
12079f06c719SChuck Lever 				   struct xdr_stream *xdr,
1208fcc85819SChristoph Hellwig 				   const void *data)
1209d9c407b1SChuck Lever {
1210fcc85819SChristoph Hellwig 	const struct nfs3_linkargs *args = data;
1211fcc85819SChristoph Hellwig 
12129f06c719SChuck Lever 	encode_nfs_fh3(xdr, args->fromfh);
12139f06c719SChuck Lever 	encode_diropargs3(xdr, args->tofh, args->toname, args->tolen);
1214d9c407b1SChuck Lever }
1215d9c407b1SChuck Lever 
1216d9c407b1SChuck Lever /*
1217d9c407b1SChuck Lever  * 3.3.16  READDIR3args
1218d9c407b1SChuck Lever  *
1219d9c407b1SChuck Lever  *	struct READDIR3args {
1220d9c407b1SChuck Lever  *		nfs_fh3		dir;
1221d9c407b1SChuck Lever  *		cookie3		cookie;
1222d9c407b1SChuck Lever  *		cookieverf3	cookieverf;
1223d9c407b1SChuck Lever  *		count3		count;
1224d9c407b1SChuck Lever  *	};
1225d9c407b1SChuck Lever  */
encode_readdir3args(struct xdr_stream * xdr,const struct nfs3_readdirargs * args)1226d9c407b1SChuck Lever static void encode_readdir3args(struct xdr_stream *xdr,
1227d9c407b1SChuck Lever 				const struct nfs3_readdirargs *args)
1228d9c407b1SChuck Lever {
1229d9c407b1SChuck Lever 	__be32 *p;
1230d9c407b1SChuck Lever 
1231d9c407b1SChuck Lever 	encode_nfs_fh3(xdr, args->fh);
1232d9c407b1SChuck Lever 
1233d9c407b1SChuck Lever 	p = xdr_reserve_space(xdr, 8 + NFS3_COOKIEVERFSIZE + 4);
1234d9c407b1SChuck Lever 	p = xdr_encode_cookie3(p, args->cookie);
1235d9c407b1SChuck Lever 	p = xdr_encode_cookieverf3(p, args->verf);
1236d9c407b1SChuck Lever 	*p = cpu_to_be32(args->count);
1237d9c407b1SChuck Lever }
1238d9c407b1SChuck Lever 
nfs3_xdr_enc_readdir3args(struct rpc_rqst * req,struct xdr_stream * xdr,const void * data)12399f06c719SChuck Lever static void nfs3_xdr_enc_readdir3args(struct rpc_rqst *req,
12409f06c719SChuck Lever 				      struct xdr_stream *xdr,
1241fcc85819SChristoph Hellwig 				      const void *data)
1242d9c407b1SChuck Lever {
1243fcc85819SChristoph Hellwig 	const struct nfs3_readdirargs *args = data;
1244fcc85819SChristoph Hellwig 
12459f06c719SChuck Lever 	encode_readdir3args(xdr, args);
12469ed5af26STrond Myklebust 	rpc_prepare_reply_pages(req, args->pages, 0, args->count,
12479ed5af26STrond Myklebust 				NFS3_readdirres_sz - NFS3_pagepad_sz);
1248d9c407b1SChuck Lever }
1249d9c407b1SChuck Lever 
1250d9c407b1SChuck Lever /*
1251d9c407b1SChuck Lever  * 3.3.17  READDIRPLUS3args
1252d9c407b1SChuck Lever  *
1253d9c407b1SChuck Lever  *	struct READDIRPLUS3args {
1254d9c407b1SChuck Lever  *		nfs_fh3		dir;
1255d9c407b1SChuck Lever  *		cookie3		cookie;
1256d9c407b1SChuck Lever  *		cookieverf3	cookieverf;
1257d9c407b1SChuck Lever  *		count3		dircount;
1258d9c407b1SChuck Lever  *		count3		maxcount;
1259d9c407b1SChuck Lever  *	};
1260d9c407b1SChuck Lever  */
encode_readdirplus3args(struct xdr_stream * xdr,const struct nfs3_readdirargs * args)1261d9c407b1SChuck Lever static void encode_readdirplus3args(struct xdr_stream *xdr,
1262d9c407b1SChuck Lever 				    const struct nfs3_readdirargs *args)
1263d9c407b1SChuck Lever {
1264c49c6894STrond Myklebust 	uint32_t dircount = args->count;
1265c49c6894STrond Myklebust 	uint32_t maxcount = args->count;
1266d9c407b1SChuck Lever 	__be32 *p;
1267d9c407b1SChuck Lever 
1268d9c407b1SChuck Lever 	encode_nfs_fh3(xdr, args->fh);
1269d9c407b1SChuck Lever 
1270d9c407b1SChuck Lever 	p = xdr_reserve_space(xdr, 8 + NFS3_COOKIEVERFSIZE + 4 + 4);
1271d9c407b1SChuck Lever 	p = xdr_encode_cookie3(p, args->cookie);
1272d9c407b1SChuck Lever 	p = xdr_encode_cookieverf3(p, args->verf);
1273d9c407b1SChuck Lever 
1274d9c407b1SChuck Lever 	/*
1275d9c407b1SChuck Lever 	 * readdirplus: need dircount + buffer size.
1276d9c407b1SChuck Lever 	 * We just make sure we make dircount big enough
1277d9c407b1SChuck Lever 	 */
1278c49c6894STrond Myklebust 	*p++ = cpu_to_be32(dircount);
1279c49c6894STrond Myklebust 	*p = cpu_to_be32(maxcount);
1280d9c407b1SChuck Lever }
1281d9c407b1SChuck Lever 
nfs3_xdr_enc_readdirplus3args(struct rpc_rqst * req,struct xdr_stream * xdr,const void * data)12829f06c719SChuck Lever static void nfs3_xdr_enc_readdirplus3args(struct rpc_rqst *req,
12839f06c719SChuck Lever 					  struct xdr_stream *xdr,
1284fcc85819SChristoph Hellwig 					  const void *data)
1285d9c407b1SChuck Lever {
1286fcc85819SChristoph Hellwig 	const struct nfs3_readdirargs *args = data;
1287fcc85819SChristoph Hellwig 
12889f06c719SChuck Lever 	encode_readdirplus3args(xdr, args);
12899ed5af26STrond Myklebust 	rpc_prepare_reply_pages(req, args->pages, 0, args->count,
12909ed5af26STrond Myklebust 				NFS3_readdirres_sz - NFS3_pagepad_sz);
1291d9c407b1SChuck Lever }
1292d9c407b1SChuck Lever 
1293d9c407b1SChuck Lever /*
1294d9c407b1SChuck Lever  * 3.3.21  COMMIT3args
1295d9c407b1SChuck Lever  *
1296d9c407b1SChuck Lever  *	struct COMMIT3args {
1297d9c407b1SChuck Lever  *		nfs_fh3		file;
1298d9c407b1SChuck Lever  *		offset3		offset;
1299d9c407b1SChuck Lever  *		count3		count;
1300d9c407b1SChuck Lever  *	};
1301d9c407b1SChuck Lever  */
encode_commit3args(struct xdr_stream * xdr,const struct nfs_commitargs * args)1302d9c407b1SChuck Lever static void encode_commit3args(struct xdr_stream *xdr,
13030b7c0153SFred Isaman 			       const struct nfs_commitargs *args)
1304d9c407b1SChuck Lever {
1305d9c407b1SChuck Lever 	__be32 *p;
1306d9c407b1SChuck Lever 
1307d9c407b1SChuck Lever 	encode_nfs_fh3(xdr, args->fh);
1308d9c407b1SChuck Lever 
1309d9c407b1SChuck Lever 	p = xdr_reserve_space(xdr, 8 + 4);
1310d9c407b1SChuck Lever 	p = xdr_encode_hyper(p, args->offset);
1311d9c407b1SChuck Lever 	*p = cpu_to_be32(args->count);
1312d9c407b1SChuck Lever }
1313d9c407b1SChuck Lever 
nfs3_xdr_enc_commit3args(struct rpc_rqst * req,struct xdr_stream * xdr,const void * data)13149f06c719SChuck Lever static void nfs3_xdr_enc_commit3args(struct rpc_rqst *req,
13159f06c719SChuck Lever 				     struct xdr_stream *xdr,
1316fcc85819SChristoph Hellwig 				     const void *data)
1317d9c407b1SChuck Lever {
1318fcc85819SChristoph Hellwig 	const struct nfs_commitargs *args = data;
1319fcc85819SChristoph Hellwig 
13209f06c719SChuck Lever 	encode_commit3args(xdr, args);
1321d9c407b1SChuck Lever }
1322d9c407b1SChuck Lever 
1323b7fa0554SAndreas Gruenbacher #ifdef CONFIG_NFS_V3_ACL
1324b7fa0554SAndreas Gruenbacher 
nfs3_xdr_enc_getacl3args(struct rpc_rqst * req,struct xdr_stream * xdr,const void * data)13259f06c719SChuck Lever static void nfs3_xdr_enc_getacl3args(struct rpc_rqst *req,
13269f06c719SChuck Lever 				     struct xdr_stream *xdr,
1327fcc85819SChristoph Hellwig 				     const void *data)
1328d9c407b1SChuck Lever {
1329fcc85819SChristoph Hellwig 	const struct nfs3_getaclargs *args = data;
1330fcc85819SChristoph Hellwig 
13319f06c719SChuck Lever 	encode_nfs_fh3(xdr, args->fh);
13329f06c719SChuck Lever 	encode_uint32(xdr, args->mask);
1333431f6eb3STrond Myklebust 	if (args->mask & (NFS_ACL | NFS_DFACL)) {
1334cf500bacSChuck Lever 		rpc_prepare_reply_pages(req, args->pages, 0,
1335d9c407b1SChuck Lever 					NFSACL_MAXPAGES << PAGE_SHIFT,
13369ed5af26STrond Myklebust 					ACL3_getaclres_sz - NFS3_pagepad_sz);
1337431f6eb3STrond Myklebust 		req->rq_rcv_buf.flags |= XDRBUF_SPARSE_PAGES;
1338431f6eb3STrond Myklebust 	}
1339d9c407b1SChuck Lever }
1340d9c407b1SChuck Lever 
nfs3_xdr_enc_setacl3args(struct rpc_rqst * req,struct xdr_stream * xdr,const void * data)13419f06c719SChuck Lever static void nfs3_xdr_enc_setacl3args(struct rpc_rqst *req,
13429f06c719SChuck Lever 				     struct xdr_stream *xdr,
1343fcc85819SChristoph Hellwig 				     const void *data)
1344d9c407b1SChuck Lever {
1345fcc85819SChristoph Hellwig 	const struct nfs3_setaclargs *args = data;
1346d9c407b1SChuck Lever 	unsigned int base;
1347d9c407b1SChuck Lever 	int error;
1348d9c407b1SChuck Lever 
13499f06c719SChuck Lever 	encode_nfs_fh3(xdr, NFS_FH(args->inode));
13509f06c719SChuck Lever 	encode_uint32(xdr, args->mask);
1351d9c407b1SChuck Lever 
1352d9c407b1SChuck Lever 	base = req->rq_slen;
1353ee5dc773SChuck Lever 	if (args->npages != 0)
1354ee5dc773SChuck Lever 		xdr_write_pages(xdr, args->pages, 0, args->len);
1355ee5dc773SChuck Lever 	else
1356d683cc49SChuck Lever 		xdr_reserve_space(xdr, args->len);
1357ee5dc773SChuck Lever 
13589f06c719SChuck Lever 	error = nfsacl_encode(xdr->buf, base, args->inode,
1359d9c407b1SChuck Lever 			    (args->mask & NFS_ACL) ?
1360d9c407b1SChuck Lever 			    args->acl_access : NULL, 1, 0);
13617fc38846STrond Myklebust 	/* FIXME: this is just broken */
1362d9c407b1SChuck Lever 	BUG_ON(error < 0);
13639f06c719SChuck Lever 	error = nfsacl_encode(xdr->buf, base + error, args->inode,
1364d9c407b1SChuck Lever 			    (args->mask & NFS_DFACL) ?
1365d9c407b1SChuck Lever 			    args->acl_default : NULL, 1,
1366d9c407b1SChuck Lever 			    NFS_ACL_DEFAULT);
1367d9c407b1SChuck Lever 	BUG_ON(error < 0);
1368d9c407b1SChuck Lever }
1369d9c407b1SChuck Lever 
1370b7fa0554SAndreas Gruenbacher #endif  /* CONFIG_NFS_V3_ACL */
1371b7fa0554SAndreas Gruenbacher 
13721da177e4SLinus Torvalds /*
1373b2cdd9c9SChuck Lever  * NFSv3 XDR decode functions
1374b2cdd9c9SChuck Lever  *
1375b2cdd9c9SChuck Lever  * NFSv3 result types are defined in section 3.3 of RFC 1813:
1376b2cdd9c9SChuck Lever  * "NFS Version 3 Protocol Specification".
13771da177e4SLinus Torvalds  */
13781da177e4SLinus Torvalds 
13791da177e4SLinus Torvalds /*
1380e4f93234SChuck Lever  * 3.3.1  GETATTR3res
1381e4f93234SChuck Lever  *
1382e4f93234SChuck Lever  *	struct GETATTR3resok {
1383e4f93234SChuck Lever  *		fattr3		obj_attributes;
1384e4f93234SChuck Lever  *	};
1385e4f93234SChuck Lever  *
1386e4f93234SChuck Lever  *	union GETATTR3res switch (nfsstat3 status) {
1387e4f93234SChuck Lever  *	case NFS3_OK:
1388e4f93234SChuck Lever  *		GETATTR3resok  resok;
1389e4f93234SChuck Lever  *	default:
1390e4f93234SChuck Lever  *		void;
1391e4f93234SChuck Lever  *	};
1392e4f93234SChuck Lever  */
nfs3_xdr_dec_getattr3res(struct rpc_rqst * req,struct xdr_stream * xdr,void * result)1393bf269551SChuck Lever static int nfs3_xdr_dec_getattr3res(struct rpc_rqst *req,
1394bf269551SChuck Lever 				    struct xdr_stream *xdr,
1395fc016483SChristoph Hellwig 				    void *result)
1396e4f93234SChuck Lever {
1397e4f93234SChuck Lever 	enum nfs_stat status;
1398e4f93234SChuck Lever 	int error;
1399e4f93234SChuck Lever 
1400bf269551SChuck Lever 	error = decode_nfsstat3(xdr, &status);
1401e4f93234SChuck Lever 	if (unlikely(error))
1402e4f93234SChuck Lever 		goto out;
1403e4f93234SChuck Lever 	if (status != NFS3_OK)
1404e4f93234SChuck Lever 		goto out_default;
1405264d948cSTrond Myklebust 	error = decode_fattr3(xdr, result, rpc_rqst_userns(req));
1406e4f93234SChuck Lever out:
1407e4f93234SChuck Lever 	return error;
1408e4f93234SChuck Lever out_default:
14095e7e5a0dSBryan Schumaker 	return nfs3_stat_to_errno(status);
1410e4f93234SChuck Lever }
1411e4f93234SChuck Lever 
1412e4f93234SChuck Lever /*
1413e4f93234SChuck Lever  * 3.3.2  SETATTR3res
1414e4f93234SChuck Lever  *
1415e4f93234SChuck Lever  *	struct SETATTR3resok {
1416e4f93234SChuck Lever  *		wcc_data  obj_wcc;
1417e4f93234SChuck Lever  *	};
1418e4f93234SChuck Lever  *
1419e4f93234SChuck Lever  *	struct SETATTR3resfail {
1420e4f93234SChuck Lever  *		wcc_data  obj_wcc;
1421e4f93234SChuck Lever  *	};
1422e4f93234SChuck Lever  *
1423e4f93234SChuck Lever  *	union SETATTR3res switch (nfsstat3 status) {
1424e4f93234SChuck Lever  *	case NFS3_OK:
1425e4f93234SChuck Lever  *		SETATTR3resok   resok;
1426e4f93234SChuck Lever  *	default:
1427e4f93234SChuck Lever  *		SETATTR3resfail resfail;
1428e4f93234SChuck Lever  *	};
1429e4f93234SChuck Lever  */
nfs3_xdr_dec_setattr3res(struct rpc_rqst * req,struct xdr_stream * xdr,void * result)1430bf269551SChuck Lever static int nfs3_xdr_dec_setattr3res(struct rpc_rqst *req,
1431bf269551SChuck Lever 				    struct xdr_stream *xdr,
1432fc016483SChristoph Hellwig 				    void *result)
1433e4f93234SChuck Lever {
1434e4f93234SChuck Lever 	enum nfs_stat status;
1435e4f93234SChuck Lever 	int error;
1436e4f93234SChuck Lever 
1437bf269551SChuck Lever 	error = decode_nfsstat3(xdr, &status);
1438e4f93234SChuck Lever 	if (unlikely(error))
1439e4f93234SChuck Lever 		goto out;
1440264d948cSTrond Myklebust 	error = decode_wcc_data(xdr, result, rpc_rqst_userns(req));
1441e4f93234SChuck Lever 	if (unlikely(error))
1442e4f93234SChuck Lever 		goto out;
1443e4f93234SChuck Lever 	if (status != NFS3_OK)
1444e4f93234SChuck Lever 		goto out_status;
1445e4f93234SChuck Lever out:
1446e4f93234SChuck Lever 	return error;
1447e4f93234SChuck Lever out_status:
14485e7e5a0dSBryan Schumaker 	return nfs3_stat_to_errno(status);
1449e4f93234SChuck Lever }
1450e4f93234SChuck Lever 
14511da177e4SLinus Torvalds /*
1452e4f93234SChuck Lever  * 3.3.3  LOOKUP3res
1453e4f93234SChuck Lever  *
1454e4f93234SChuck Lever  *	struct LOOKUP3resok {
1455e4f93234SChuck Lever  *		nfs_fh3		object;
1456e4f93234SChuck Lever  *		post_op_attr	obj_attributes;
1457e4f93234SChuck Lever  *		post_op_attr	dir_attributes;
1458e4f93234SChuck Lever  *	};
1459e4f93234SChuck Lever  *
1460e4f93234SChuck Lever  *	struct LOOKUP3resfail {
1461e4f93234SChuck Lever  *		post_op_attr	dir_attributes;
1462e4f93234SChuck Lever  *	};
1463e4f93234SChuck Lever  *
1464e4f93234SChuck Lever  *	union LOOKUP3res switch (nfsstat3 status) {
1465e4f93234SChuck Lever  *	case NFS3_OK:
1466e4f93234SChuck Lever  *		LOOKUP3resok	resok;
1467e4f93234SChuck Lever  *	default:
1468e4f93234SChuck Lever  *		LOOKUP3resfail	resfail;
1469e4f93234SChuck Lever  *	};
1470e4f93234SChuck Lever  */
nfs3_xdr_dec_lookup3res(struct rpc_rqst * req,struct xdr_stream * xdr,void * data)1471bf269551SChuck Lever static int nfs3_xdr_dec_lookup3res(struct rpc_rqst *req,
1472bf269551SChuck Lever 				   struct xdr_stream *xdr,
1473fc016483SChristoph Hellwig 				   void *data)
1474e4f93234SChuck Lever {
1475264d948cSTrond Myklebust 	struct user_namespace *userns = rpc_rqst_userns(req);
1476fc016483SChristoph Hellwig 	struct nfs3_diropres *result = data;
1477e4f93234SChuck Lever 	enum nfs_stat status;
1478e4f93234SChuck Lever 	int error;
1479e4f93234SChuck Lever 
1480bf269551SChuck Lever 	error = decode_nfsstat3(xdr, &status);
1481e4f93234SChuck Lever 	if (unlikely(error))
1482e4f93234SChuck Lever 		goto out;
1483e4f93234SChuck Lever 	if (status != NFS3_OK)
1484e4f93234SChuck Lever 		goto out_default;
1485bf269551SChuck Lever 	error = decode_nfs_fh3(xdr, result->fh);
1486e4f93234SChuck Lever 	if (unlikely(error))
1487e4f93234SChuck Lever 		goto out;
1488264d948cSTrond Myklebust 	error = decode_post_op_attr(xdr, result->fattr, userns);
1489e4f93234SChuck Lever 	if (unlikely(error))
1490e4f93234SChuck Lever 		goto out;
1491264d948cSTrond Myklebust 	error = decode_post_op_attr(xdr, result->dir_attr, userns);
1492e4f93234SChuck Lever out:
1493e4f93234SChuck Lever 	return error;
1494e4f93234SChuck Lever out_default:
1495264d948cSTrond Myklebust 	error = decode_post_op_attr(xdr, result->dir_attr, userns);
1496e4f93234SChuck Lever 	if (unlikely(error))
1497e4f93234SChuck Lever 		goto out;
14985e7e5a0dSBryan Schumaker 	return nfs3_stat_to_errno(status);
1499e4f93234SChuck Lever }
1500e4f93234SChuck Lever 
1501e4f93234SChuck Lever /*
1502e4f93234SChuck Lever  * 3.3.4  ACCESS3res
1503e4f93234SChuck Lever  *
1504e4f93234SChuck Lever  *	struct ACCESS3resok {
1505e4f93234SChuck Lever  *		post_op_attr	obj_attributes;
1506e4f93234SChuck Lever  *		uint32		access;
1507e4f93234SChuck Lever  *	};
1508e4f93234SChuck Lever  *
1509e4f93234SChuck Lever  *	struct ACCESS3resfail {
1510e4f93234SChuck Lever  *		post_op_attr	obj_attributes;
1511e4f93234SChuck Lever  *	};
1512e4f93234SChuck Lever  *
1513e4f93234SChuck Lever  *	union ACCESS3res switch (nfsstat3 status) {
1514e4f93234SChuck Lever  *	case NFS3_OK:
1515e4f93234SChuck Lever  *		ACCESS3resok	resok;
1516e4f93234SChuck Lever  *	default:
1517e4f93234SChuck Lever  *		ACCESS3resfail	resfail;
1518e4f93234SChuck Lever  *	};
1519e4f93234SChuck Lever  */
nfs3_xdr_dec_access3res(struct rpc_rqst * req,struct xdr_stream * xdr,void * data)1520bf269551SChuck Lever static int nfs3_xdr_dec_access3res(struct rpc_rqst *req,
1521bf269551SChuck Lever 				   struct xdr_stream *xdr,
1522fc016483SChristoph Hellwig 				   void *data)
1523e4f93234SChuck Lever {
1524fc016483SChristoph Hellwig 	struct nfs3_accessres *result = data;
1525e4f93234SChuck Lever 	enum nfs_stat status;
1526e4f93234SChuck Lever 	int error;
1527e4f93234SChuck Lever 
1528bf269551SChuck Lever 	error = decode_nfsstat3(xdr, &status);
1529e4f93234SChuck Lever 	if (unlikely(error))
1530e4f93234SChuck Lever 		goto out;
1531264d948cSTrond Myklebust 	error = decode_post_op_attr(xdr, result->fattr, rpc_rqst_userns(req));
1532e4f93234SChuck Lever 	if (unlikely(error))
1533e4f93234SChuck Lever 		goto out;
1534e4f93234SChuck Lever 	if (status != NFS3_OK)
1535e4f93234SChuck Lever 		goto out_default;
1536bf269551SChuck Lever 	error = decode_uint32(xdr, &result->access);
1537e4f93234SChuck Lever out:
1538e4f93234SChuck Lever 	return error;
1539e4f93234SChuck Lever out_default:
15405e7e5a0dSBryan Schumaker 	return nfs3_stat_to_errno(status);
1541e4f93234SChuck Lever }
1542e4f93234SChuck Lever 
1543e4f93234SChuck Lever /*
1544e4f93234SChuck Lever  * 3.3.5  READLINK3res
1545e4f93234SChuck Lever  *
1546e4f93234SChuck Lever  *	struct READLINK3resok {
1547e4f93234SChuck Lever  *		post_op_attr	symlink_attributes;
1548e4f93234SChuck Lever  *		nfspath3	data;
1549e4f93234SChuck Lever  *	};
1550e4f93234SChuck Lever  *
1551e4f93234SChuck Lever  *	struct READLINK3resfail {
1552e4f93234SChuck Lever  *		post_op_attr	symlink_attributes;
1553e4f93234SChuck Lever  *	};
1554e4f93234SChuck Lever  *
1555e4f93234SChuck Lever  *	union READLINK3res switch (nfsstat3 status) {
1556e4f93234SChuck Lever  *	case NFS3_OK:
1557e4f93234SChuck Lever  *		READLINK3resok	resok;
1558e4f93234SChuck Lever  *	default:
1559e4f93234SChuck Lever  *		READLINK3resfail resfail;
1560e4f93234SChuck Lever  *	};
1561e4f93234SChuck Lever  */
nfs3_xdr_dec_readlink3res(struct rpc_rqst * req,struct xdr_stream * xdr,void * result)1562bf269551SChuck Lever static int nfs3_xdr_dec_readlink3res(struct rpc_rqst *req,
1563bf269551SChuck Lever 				     struct xdr_stream *xdr,
1564fc016483SChristoph Hellwig 				     void *result)
1565e4f93234SChuck Lever {
1566e4f93234SChuck Lever 	enum nfs_stat status;
1567e4f93234SChuck Lever 	int error;
1568e4f93234SChuck Lever 
1569bf269551SChuck Lever 	error = decode_nfsstat3(xdr, &status);
1570e4f93234SChuck Lever 	if (unlikely(error))
1571e4f93234SChuck Lever 		goto out;
1572264d948cSTrond Myklebust 	error = decode_post_op_attr(xdr, result, rpc_rqst_userns(req));
1573e4f93234SChuck Lever 	if (unlikely(error))
1574e4f93234SChuck Lever 		goto out;
1575e4f93234SChuck Lever 	if (status != NFS3_OK)
1576e4f93234SChuck Lever 		goto out_default;
1577bf269551SChuck Lever 	error = decode_nfspath3(xdr);
1578e4f93234SChuck Lever out:
1579e4f93234SChuck Lever 	return error;
1580e4f93234SChuck Lever out_default:
15815e7e5a0dSBryan Schumaker 	return nfs3_stat_to_errno(status);
1582e4f93234SChuck Lever }
1583e4f93234SChuck Lever 
1584e4f93234SChuck Lever /*
1585e4f93234SChuck Lever  * 3.3.6  READ3res
1586e4f93234SChuck Lever  *
1587e4f93234SChuck Lever  *	struct READ3resok {
1588e4f93234SChuck Lever  *		post_op_attr	file_attributes;
1589e4f93234SChuck Lever  *		count3		count;
1590e4f93234SChuck Lever  *		bool		eof;
1591e4f93234SChuck Lever  *		opaque		data<>;
1592e4f93234SChuck Lever  *	};
1593e4f93234SChuck Lever  *
1594e4f93234SChuck Lever  *	struct READ3resfail {
1595e4f93234SChuck Lever  *		post_op_attr	file_attributes;
1596e4f93234SChuck Lever  *	};
1597e4f93234SChuck Lever  *
1598e4f93234SChuck Lever  *	union READ3res switch (nfsstat3 status) {
1599e4f93234SChuck Lever  *	case NFS3_OK:
1600e4f93234SChuck Lever  *		READ3resok	resok;
1601e4f93234SChuck Lever  *	default:
1602e4f93234SChuck Lever  *		READ3resfail	resfail;
1603e4f93234SChuck Lever  *	};
1604e4f93234SChuck Lever  */
decode_read3resok(struct xdr_stream * xdr,struct nfs_pgio_res * result)1605e4f93234SChuck Lever static int decode_read3resok(struct xdr_stream *xdr,
16069137bdf3SAnna Schumaker 			     struct nfs_pgio_res *result)
1607e4f93234SChuck Lever {
1608e4f93234SChuck Lever 	u32 eof, count, ocount, recvd;
1609e4f93234SChuck Lever 	__be32 *p;
1610e4f93234SChuck Lever 
1611e4f93234SChuck Lever 	p = xdr_inline_decode(xdr, 4 + 4 + 4);
1612eb72f484SChuck Lever 	if (unlikely(!p))
1613eb72f484SChuck Lever 		return -EIO;
1614e4f93234SChuck Lever 	count = be32_to_cpup(p++);
1615e4f93234SChuck Lever 	eof = be32_to_cpup(p++);
1616e4f93234SChuck Lever 	ocount = be32_to_cpup(p++);
1617e4f93234SChuck Lever 	if (unlikely(ocount != count))
1618e4f93234SChuck Lever 		goto out_mismatch;
161964bd577eSTrond Myklebust 	recvd = xdr_read_pages(xdr, count);
1620e4f93234SChuck Lever 	if (unlikely(count > recvd))
1621e4f93234SChuck Lever 		goto out_cheating;
1622e4f93234SChuck Lever out:
1623e4f93234SChuck Lever 	result->eof = eof;
1624e4f93234SChuck Lever 	result->count = count;
1625e4f93234SChuck Lever 	return count;
1626e4f93234SChuck Lever out_mismatch:
1627e4f93234SChuck Lever 	dprintk("NFS: READ count doesn't match length of opaque: "
1628e4f93234SChuck Lever 		"count %u != ocount %u\n", count, ocount);
1629e4f93234SChuck Lever 	return -EIO;
1630e4f93234SChuck Lever out_cheating:
1631e4f93234SChuck Lever 	dprintk("NFS: server cheating in read result: "
1632e4f93234SChuck Lever 		"count %u > recvd %u\n", count, recvd);
1633e4f93234SChuck Lever 	count = recvd;
1634e4f93234SChuck Lever 	eof = 0;
1635e4f93234SChuck Lever 	goto out;
1636e4f93234SChuck Lever }
1637e4f93234SChuck Lever 
nfs3_xdr_dec_read3res(struct rpc_rqst * req,struct xdr_stream * xdr,void * data)1638bf269551SChuck Lever static int nfs3_xdr_dec_read3res(struct rpc_rqst *req, struct xdr_stream *xdr,
1639fc016483SChristoph Hellwig 				 void *data)
1640e4f93234SChuck Lever {
1641fc016483SChristoph Hellwig 	struct nfs_pgio_res *result = data;
16428d8928d8STrond Myklebust 	unsigned int pos;
1643e4f93234SChuck Lever 	enum nfs_stat status;
1644e4f93234SChuck Lever 	int error;
1645e4f93234SChuck Lever 
16468d8928d8STrond Myklebust 	pos = xdr_stream_pos(xdr);
1647bf269551SChuck Lever 	error = decode_nfsstat3(xdr, &status);
1648e4f93234SChuck Lever 	if (unlikely(error))
1649e4f93234SChuck Lever 		goto out;
1650264d948cSTrond Myklebust 	error = decode_post_op_attr(xdr, result->fattr, rpc_rqst_userns(req));
1651e4f93234SChuck Lever 	if (unlikely(error))
1652e4f93234SChuck Lever 		goto out;
1653aabff4ddSPeng Tao 	result->op_status = status;
1654e4f93234SChuck Lever 	if (status != NFS3_OK)
1655e4f93234SChuck Lever 		goto out_status;
16569ed5af26STrond Myklebust 	result->replen = 3 + ((xdr_stream_pos(xdr) - pos) >> 2);
1657bf269551SChuck Lever 	error = decode_read3resok(xdr, result);
1658e4f93234SChuck Lever out:
1659e4f93234SChuck Lever 	return error;
1660e4f93234SChuck Lever out_status:
16615e7e5a0dSBryan Schumaker 	return nfs3_stat_to_errno(status);
1662e4f93234SChuck Lever }
1663e4f93234SChuck Lever 
1664e4f93234SChuck Lever /*
1665e4f93234SChuck Lever  * 3.3.7  WRITE3res
1666e4f93234SChuck Lever  *
1667e4f93234SChuck Lever  *	enum stable_how {
1668e4f93234SChuck Lever  *		UNSTABLE  = 0,
1669e4f93234SChuck Lever  *		DATA_SYNC = 1,
1670e4f93234SChuck Lever  *		FILE_SYNC = 2
1671e4f93234SChuck Lever  *	};
1672e4f93234SChuck Lever  *
1673e4f93234SChuck Lever  *	struct WRITE3resok {
1674e4f93234SChuck Lever  *		wcc_data	file_wcc;
1675e4f93234SChuck Lever  *		count3		count;
1676e4f93234SChuck Lever  *		stable_how	committed;
1677e4f93234SChuck Lever  *		writeverf3	verf;
1678e4f93234SChuck Lever  *	};
1679e4f93234SChuck Lever  *
1680e4f93234SChuck Lever  *	struct WRITE3resfail {
1681e4f93234SChuck Lever  *		wcc_data	file_wcc;
1682e4f93234SChuck Lever  *	};
1683e4f93234SChuck Lever  *
1684e4f93234SChuck Lever  *	union WRITE3res switch (nfsstat3 status) {
1685e4f93234SChuck Lever  *	case NFS3_OK:
1686e4f93234SChuck Lever  *		WRITE3resok	resok;
1687e4f93234SChuck Lever  *	default:
1688e4f93234SChuck Lever  *		WRITE3resfail	resfail;
1689e4f93234SChuck Lever  *	};
1690e4f93234SChuck Lever  */
decode_write3resok(struct xdr_stream * xdr,struct nfs_pgio_res * result)1691e4f93234SChuck Lever static int decode_write3resok(struct xdr_stream *xdr,
16929137bdf3SAnna Schumaker 			      struct nfs_pgio_res *result)
1693e4f93234SChuck Lever {
1694e4f93234SChuck Lever 	__be32 *p;
1695e4f93234SChuck Lever 
16962f2c63bcSTrond Myklebust 	p = xdr_inline_decode(xdr, 4 + 4);
1697eb72f484SChuck Lever 	if (unlikely(!p))
1698eb72f484SChuck Lever 		return -EIO;
1699e4f93234SChuck Lever 	result->count = be32_to_cpup(p++);
1700e4f93234SChuck Lever 	result->verf->committed = be32_to_cpup(p++);
1701e4f93234SChuck Lever 	if (unlikely(result->verf->committed > NFS_FILE_SYNC))
1702e4f93234SChuck Lever 		goto out_badvalue;
17032f2c63bcSTrond Myklebust 	if (decode_writeverf3(xdr, &result->verf->verifier))
1704eb72f484SChuck Lever 		return -EIO;
1705e4f93234SChuck Lever 	return result->count;
1706e4f93234SChuck Lever out_badvalue:
1707e4f93234SChuck Lever 	dprintk("NFS: bad stable_how value: %u\n", result->verf->committed);
1708e4f93234SChuck Lever 	return -EIO;
1709e4f93234SChuck Lever }
1710e4f93234SChuck Lever 
nfs3_xdr_dec_write3res(struct rpc_rqst * req,struct xdr_stream * xdr,void * data)1711bf269551SChuck Lever static int nfs3_xdr_dec_write3res(struct rpc_rqst *req, struct xdr_stream *xdr,
1712fc016483SChristoph Hellwig 				  void *data)
1713e4f93234SChuck Lever {
1714fc016483SChristoph Hellwig 	struct nfs_pgio_res *result = data;
1715e4f93234SChuck Lever 	enum nfs_stat status;
1716e4f93234SChuck Lever 	int error;
1717e4f93234SChuck Lever 
1718bf269551SChuck Lever 	error = decode_nfsstat3(xdr, &status);
1719e4f93234SChuck Lever 	if (unlikely(error))
1720e4f93234SChuck Lever 		goto out;
1721264d948cSTrond Myklebust 	error = decode_wcc_data(xdr, result->fattr, rpc_rqst_userns(req));
1722e4f93234SChuck Lever 	if (unlikely(error))
1723e4f93234SChuck Lever 		goto out;
1724aabff4ddSPeng Tao 	result->op_status = status;
1725e4f93234SChuck Lever 	if (status != NFS3_OK)
1726e4f93234SChuck Lever 		goto out_status;
1727bf269551SChuck Lever 	error = decode_write3resok(xdr, result);
1728e4f93234SChuck Lever out:
1729e4f93234SChuck Lever 	return error;
1730e4f93234SChuck Lever out_status:
17315e7e5a0dSBryan Schumaker 	return nfs3_stat_to_errno(status);
1732e4f93234SChuck Lever }
1733e4f93234SChuck Lever 
1734e4f93234SChuck Lever /*
1735e4f93234SChuck Lever  * 3.3.8  CREATE3res
1736e4f93234SChuck Lever  *
1737e4f93234SChuck Lever  *	struct CREATE3resok {
1738e4f93234SChuck Lever  *		post_op_fh3	obj;
1739e4f93234SChuck Lever  *		post_op_attr	obj_attributes;
1740e4f93234SChuck Lever  *		wcc_data	dir_wcc;
1741e4f93234SChuck Lever  *	};
1742e4f93234SChuck Lever  *
1743e4f93234SChuck Lever  *	struct CREATE3resfail {
1744e4f93234SChuck Lever  *		wcc_data	dir_wcc;
1745e4f93234SChuck Lever  *	};
1746e4f93234SChuck Lever  *
1747e4f93234SChuck Lever  *	union CREATE3res switch (nfsstat3 status) {
1748e4f93234SChuck Lever  *	case NFS3_OK:
1749e4f93234SChuck Lever  *		CREATE3resok	resok;
1750e4f93234SChuck Lever  *	default:
1751e4f93234SChuck Lever  *		CREATE3resfail	resfail;
1752e4f93234SChuck Lever  *	};
1753e4f93234SChuck Lever  */
decode_create3resok(struct xdr_stream * xdr,struct nfs3_diropres * result,struct user_namespace * userns)1754e4f93234SChuck Lever static int decode_create3resok(struct xdr_stream *xdr,
1755264d948cSTrond Myklebust 			       struct nfs3_diropres *result,
1756264d948cSTrond Myklebust 			       struct user_namespace *userns)
1757e4f93234SChuck Lever {
1758e4f93234SChuck Lever 	int error;
1759e4f93234SChuck Lever 
1760e4f93234SChuck Lever 	error = decode_post_op_fh3(xdr, result->fh);
1761e4f93234SChuck Lever 	if (unlikely(error))
1762e4f93234SChuck Lever 		goto out;
1763264d948cSTrond Myklebust 	error = decode_post_op_attr(xdr, result->fattr, userns);
1764e4f93234SChuck Lever 	if (unlikely(error))
1765e4f93234SChuck Lever 		goto out;
1766e4f93234SChuck Lever 	/* The server isn't required to return a file handle.
1767e4f93234SChuck Lever 	 * If it didn't, force the client to perform a LOOKUP
1768e4f93234SChuck Lever 	 * to determine the correct file handle and attribute
1769e4f93234SChuck Lever 	 * values for the new object. */
1770e4f93234SChuck Lever 	if (result->fh->size == 0)
1771e4f93234SChuck Lever 		result->fattr->valid = 0;
1772264d948cSTrond Myklebust 	error = decode_wcc_data(xdr, result->dir_attr, userns);
1773e4f93234SChuck Lever out:
1774e4f93234SChuck Lever 	return error;
1775e4f93234SChuck Lever }
1776e4f93234SChuck Lever 
nfs3_xdr_dec_create3res(struct rpc_rqst * req,struct xdr_stream * xdr,void * data)1777bf269551SChuck Lever static int nfs3_xdr_dec_create3res(struct rpc_rqst *req,
1778bf269551SChuck Lever 				   struct xdr_stream *xdr,
1779fc016483SChristoph Hellwig 				   void *data)
1780e4f93234SChuck Lever {
1781264d948cSTrond Myklebust 	struct user_namespace *userns = rpc_rqst_userns(req);
1782fc016483SChristoph Hellwig 	struct nfs3_diropres *result = data;
1783e4f93234SChuck Lever 	enum nfs_stat status;
1784e4f93234SChuck Lever 	int error;
1785e4f93234SChuck Lever 
1786bf269551SChuck Lever 	error = decode_nfsstat3(xdr, &status);
1787e4f93234SChuck Lever 	if (unlikely(error))
1788e4f93234SChuck Lever 		goto out;
1789e4f93234SChuck Lever 	if (status != NFS3_OK)
1790e4f93234SChuck Lever 		goto out_default;
1791264d948cSTrond Myklebust 	error = decode_create3resok(xdr, result, userns);
1792e4f93234SChuck Lever out:
1793e4f93234SChuck Lever 	return error;
1794e4f93234SChuck Lever out_default:
1795264d948cSTrond Myklebust 	error = decode_wcc_data(xdr, result->dir_attr, userns);
1796e4f93234SChuck Lever 	if (unlikely(error))
1797e4f93234SChuck Lever 		goto out;
17985e7e5a0dSBryan Schumaker 	return nfs3_stat_to_errno(status);
1799e4f93234SChuck Lever }
1800e4f93234SChuck Lever 
1801e4f93234SChuck Lever /*
1802e4f93234SChuck Lever  * 3.3.12  REMOVE3res
1803e4f93234SChuck Lever  *
1804e4f93234SChuck Lever  *	struct REMOVE3resok {
1805e4f93234SChuck Lever  *		wcc_data    dir_wcc;
1806e4f93234SChuck Lever  *	};
1807e4f93234SChuck Lever  *
1808e4f93234SChuck Lever  *	struct REMOVE3resfail {
1809e4f93234SChuck Lever  *		wcc_data    dir_wcc;
1810e4f93234SChuck Lever  *	};
1811e4f93234SChuck Lever  *
1812e4f93234SChuck Lever  *	union REMOVE3res switch (nfsstat3 status) {
1813e4f93234SChuck Lever  *	case NFS3_OK:
1814e4f93234SChuck Lever  *		REMOVE3resok   resok;
1815e4f93234SChuck Lever  *	default:
1816e4f93234SChuck Lever  *		REMOVE3resfail resfail;
1817e4f93234SChuck Lever  *	};
1818e4f93234SChuck Lever  */
nfs3_xdr_dec_remove3res(struct rpc_rqst * req,struct xdr_stream * xdr,void * data)1819bf269551SChuck Lever static int nfs3_xdr_dec_remove3res(struct rpc_rqst *req,
1820bf269551SChuck Lever 				   struct xdr_stream *xdr,
1821fc016483SChristoph Hellwig 				   void *data)
1822e4f93234SChuck Lever {
1823fc016483SChristoph Hellwig 	struct nfs_removeres *result = data;
1824e4f93234SChuck Lever 	enum nfs_stat status;
1825e4f93234SChuck Lever 	int error;
1826e4f93234SChuck Lever 
1827bf269551SChuck Lever 	error = decode_nfsstat3(xdr, &status);
1828e4f93234SChuck Lever 	if (unlikely(error))
1829e4f93234SChuck Lever 		goto out;
1830264d948cSTrond Myklebust 	error = decode_wcc_data(xdr, result->dir_attr, rpc_rqst_userns(req));
1831e4f93234SChuck Lever 	if (unlikely(error))
1832e4f93234SChuck Lever 		goto out;
1833e4f93234SChuck Lever 	if (status != NFS3_OK)
1834e4f93234SChuck Lever 		goto out_status;
1835e4f93234SChuck Lever out:
1836e4f93234SChuck Lever 	return error;
1837e4f93234SChuck Lever out_status:
18385e7e5a0dSBryan Schumaker 	return nfs3_stat_to_errno(status);
1839e4f93234SChuck Lever }
1840e4f93234SChuck Lever 
1841e4f93234SChuck Lever /*
1842e4f93234SChuck Lever  * 3.3.14  RENAME3res
1843e4f93234SChuck Lever  *
1844e4f93234SChuck Lever  *	struct RENAME3resok {
1845e4f93234SChuck Lever  *		wcc_data	fromdir_wcc;
1846e4f93234SChuck Lever  *		wcc_data	todir_wcc;
1847e4f93234SChuck Lever  *	};
1848e4f93234SChuck Lever  *
1849e4f93234SChuck Lever  *	struct RENAME3resfail {
1850e4f93234SChuck Lever  *		wcc_data	fromdir_wcc;
1851e4f93234SChuck Lever  *		wcc_data	todir_wcc;
1852e4f93234SChuck Lever  *	};
1853e4f93234SChuck Lever  *
1854e4f93234SChuck Lever  *	union RENAME3res switch (nfsstat3 status) {
1855e4f93234SChuck Lever  *	case NFS3_OK:
1856e4f93234SChuck Lever  *		RENAME3resok   resok;
1857e4f93234SChuck Lever  *	default:
1858e4f93234SChuck Lever  *		RENAME3resfail resfail;
1859e4f93234SChuck Lever  *	};
1860e4f93234SChuck Lever  */
nfs3_xdr_dec_rename3res(struct rpc_rqst * req,struct xdr_stream * xdr,void * data)1861bf269551SChuck Lever static int nfs3_xdr_dec_rename3res(struct rpc_rqst *req,
1862bf269551SChuck Lever 				   struct xdr_stream *xdr,
1863fc016483SChristoph Hellwig 				   void *data)
1864e4f93234SChuck Lever {
1865264d948cSTrond Myklebust 	struct user_namespace *userns = rpc_rqst_userns(req);
1866fc016483SChristoph Hellwig 	struct nfs_renameres *result = data;
1867e4f93234SChuck Lever 	enum nfs_stat status;
1868e4f93234SChuck Lever 	int error;
1869e4f93234SChuck Lever 
1870bf269551SChuck Lever 	error = decode_nfsstat3(xdr, &status);
1871e4f93234SChuck Lever 	if (unlikely(error))
1872e4f93234SChuck Lever 		goto out;
1873264d948cSTrond Myklebust 	error = decode_wcc_data(xdr, result->old_fattr, userns);
1874e4f93234SChuck Lever 	if (unlikely(error))
1875e4f93234SChuck Lever 		goto out;
1876264d948cSTrond Myklebust 	error = decode_wcc_data(xdr, result->new_fattr, userns);
1877e4f93234SChuck Lever 	if (unlikely(error))
1878e4f93234SChuck Lever 		goto out;
1879e4f93234SChuck Lever 	if (status != NFS3_OK)
1880e4f93234SChuck Lever 		goto out_status;
1881e4f93234SChuck Lever out:
1882e4f93234SChuck Lever 	return error;
1883e4f93234SChuck Lever out_status:
18845e7e5a0dSBryan Schumaker 	return nfs3_stat_to_errno(status);
1885e4f93234SChuck Lever }
1886e4f93234SChuck Lever 
1887e4f93234SChuck Lever /*
1888e4f93234SChuck Lever  * 3.3.15  LINK3res
1889e4f93234SChuck Lever  *
1890e4f93234SChuck Lever  *	struct LINK3resok {
1891e4f93234SChuck Lever  *		post_op_attr	file_attributes;
1892e4f93234SChuck Lever  *		wcc_data	linkdir_wcc;
1893e4f93234SChuck Lever  *	};
1894e4f93234SChuck Lever  *
1895e4f93234SChuck Lever  *	struct LINK3resfail {
1896e4f93234SChuck Lever  *		post_op_attr	file_attributes;
1897e4f93234SChuck Lever  *		wcc_data	linkdir_wcc;
1898e4f93234SChuck Lever  *	};
1899e4f93234SChuck Lever  *
1900e4f93234SChuck Lever  *	union LINK3res switch (nfsstat3 status) {
1901e4f93234SChuck Lever  *	case NFS3_OK:
1902e4f93234SChuck Lever  *		LINK3resok	resok;
1903e4f93234SChuck Lever  *	default:
1904e4f93234SChuck Lever  *		LINK3resfail	resfail;
1905e4f93234SChuck Lever  *	};
1906e4f93234SChuck Lever  */
nfs3_xdr_dec_link3res(struct rpc_rqst * req,struct xdr_stream * xdr,void * data)1907bf269551SChuck Lever static int nfs3_xdr_dec_link3res(struct rpc_rqst *req, struct xdr_stream *xdr,
1908fc016483SChristoph Hellwig 				 void *data)
1909e4f93234SChuck Lever {
1910264d948cSTrond Myklebust 	struct user_namespace *userns = rpc_rqst_userns(req);
1911fc016483SChristoph Hellwig 	struct nfs3_linkres *result = data;
1912e4f93234SChuck Lever 	enum nfs_stat status;
1913e4f93234SChuck Lever 	int error;
1914e4f93234SChuck Lever 
1915bf269551SChuck Lever 	error = decode_nfsstat3(xdr, &status);
1916e4f93234SChuck Lever 	if (unlikely(error))
1917e4f93234SChuck Lever 		goto out;
1918264d948cSTrond Myklebust 	error = decode_post_op_attr(xdr, result->fattr, userns);
1919e4f93234SChuck Lever 	if (unlikely(error))
1920e4f93234SChuck Lever 		goto out;
1921264d948cSTrond Myklebust 	error = decode_wcc_data(xdr, result->dir_attr, userns);
1922e4f93234SChuck Lever 	if (unlikely(error))
1923e4f93234SChuck Lever 		goto out;
1924e4f93234SChuck Lever 	if (status != NFS3_OK)
1925e4f93234SChuck Lever 		goto out_status;
1926e4f93234SChuck Lever out:
1927e4f93234SChuck Lever 	return error;
1928e4f93234SChuck Lever out_status:
19295e7e5a0dSBryan Schumaker 	return nfs3_stat_to_errno(status);
1930e4f93234SChuck Lever }
1931e4f93234SChuck Lever 
1932e4f93234SChuck Lever /**
1933e4f93234SChuck Lever  * nfs3_decode_dirent - Decode a single NFSv3 directory entry stored in
1934e4f93234SChuck Lever  *			the local page cache
1935e4f93234SChuck Lever  * @xdr: XDR stream where entry resides
1936e4f93234SChuck Lever  * @entry: buffer to fill in with entry data
1937e4f93234SChuck Lever  * @plus: boolean indicating whether this should be a readdirplus entry
1938e4f93234SChuck Lever  *
1939573c4e1eSChuck Lever  * Returns zero if successful, otherwise a negative errno value is
1940573c4e1eSChuck Lever  * returned.
1941e4f93234SChuck Lever  *
1942e4f93234SChuck Lever  * This function is not invoked during READDIR reply decoding, but
1943e4f93234SChuck Lever  * rather whenever an application invokes the getdents(2) system call
1944e4f93234SChuck Lever  * on a directory already in our cache.
1945e4f93234SChuck Lever  *
1946e4f93234SChuck Lever  * 3.3.16  entry3
1947e4f93234SChuck Lever  *
1948e4f93234SChuck Lever  *	struct entry3 {
1949e4f93234SChuck Lever  *		fileid3		fileid;
1950e4f93234SChuck Lever  *		filename3	name;
1951e4f93234SChuck Lever  *		cookie3		cookie;
1952e4f93234SChuck Lever  *		fhandle3	filehandle;
1953e4f93234SChuck Lever  *		post_op_attr3	attributes;
1954e4f93234SChuck Lever  *		entry3		*nextentry;
1955e4f93234SChuck Lever  *	};
1956e4f93234SChuck Lever  *
1957e4f93234SChuck Lever  * 3.3.17  entryplus3
1958e4f93234SChuck Lever  *	struct entryplus3 {
1959e4f93234SChuck Lever  *		fileid3		fileid;
1960e4f93234SChuck Lever  *		filename3	name;
1961e4f93234SChuck Lever  *		cookie3		cookie;
1962e4f93234SChuck Lever  *		post_op_attr	name_attributes;
1963e4f93234SChuck Lever  *		post_op_fh3	name_handle;
1964e4f93234SChuck Lever  *		entryplus3	*nextentry;
1965e4f93234SChuck Lever  *	};
1966e4f93234SChuck Lever  */
nfs3_decode_dirent(struct xdr_stream * xdr,struct nfs_entry * entry,bool plus)1967573c4e1eSChuck Lever int nfs3_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry,
1968a7a3b1e9SBenjamin Coddington 		       bool plus)
1969e4f93234SChuck Lever {
1970264d948cSTrond Myklebust 	struct user_namespace *userns = rpc_userns(entry->server->client);
1971e4f93234SChuck Lever 	__be32 *p;
1972e4f93234SChuck Lever 	int error;
197398de9ce6SFrank Sorenson 	u64 new_cookie;
1974e4f93234SChuck Lever 
1975e4f93234SChuck Lever 	p = xdr_inline_decode(xdr, 4);
1976eb72f484SChuck Lever 	if (unlikely(!p))
1977eb72f484SChuck Lever 		return -EAGAIN;
1978e4f93234SChuck Lever 	if (*p == xdr_zero) {
1979e4f93234SChuck Lever 		p = xdr_inline_decode(xdr, 4);
1980eb72f484SChuck Lever 		if (unlikely(!p))
1981eb72f484SChuck Lever 			return -EAGAIN;
1982e4f93234SChuck Lever 		if (*p == xdr_zero)
1983573c4e1eSChuck Lever 			return -EAGAIN;
1984e4f93234SChuck Lever 		entry->eof = 1;
1985573c4e1eSChuck Lever 		return -EBADCOOKIE;
1986e4f93234SChuck Lever 	}
1987e4f93234SChuck Lever 
1988e4f93234SChuck Lever 	error = decode_fileid3(xdr, &entry->ino);
1989e4f93234SChuck Lever 	if (unlikely(error))
199064cfca85STrond Myklebust 		return -EAGAIN;
1991e4f93234SChuck Lever 
1992e4f93234SChuck Lever 	error = decode_inline_filename3(xdr, &entry->name, &entry->len);
1993e4f93234SChuck Lever 	if (unlikely(error))
1994*f67b55b6SBenjamin Coddington 		return error == -ENAMETOOLONG ? -ENAMETOOLONG : -EAGAIN;
1995e4f93234SChuck Lever 
199698de9ce6SFrank Sorenson 	error = decode_cookie3(xdr, &new_cookie);
1997e4f93234SChuck Lever 	if (unlikely(error))
199864cfca85STrond Myklebust 		return -EAGAIN;
1999e4f93234SChuck Lever 
2000e4f93234SChuck Lever 	entry->d_type = DT_UNKNOWN;
2001e4f93234SChuck Lever 
2002e4f93234SChuck Lever 	if (plus) {
2003e4f93234SChuck Lever 		entry->fattr->valid = 0;
2004264d948cSTrond Myklebust 		error = decode_post_op_attr(xdr, entry->fattr, userns);
2005e4f93234SChuck Lever 		if (unlikely(error))
200664cfca85STrond Myklebust 			return -EAGAIN;
2007e4f93234SChuck Lever 		if (entry->fattr->valid & NFS_ATTR_FATTR_V3)
2008e4f93234SChuck Lever 			entry->d_type = nfs_umode_to_dtype(entry->fattr->mode);
2009e4f93234SChuck Lever 
20101ae04b25STrond Myklebust 		if (entry->fattr->fileid != entry->ino) {
20111ae04b25STrond Myklebust 			entry->fattr->mounted_on_fileid = entry->ino;
20121ae04b25STrond Myklebust 			entry->fattr->valid |= NFS_ATTR_FATTR_MOUNTED_ON_FILEID;
20131ae04b25STrond Myklebust 		}
20141ae04b25STrond Myklebust 
2015e4f93234SChuck Lever 		/* In fact, a post_op_fh3: */
2016e4f93234SChuck Lever 		p = xdr_inline_decode(xdr, 4);
2017eb72f484SChuck Lever 		if (unlikely(!p))
2018eb72f484SChuck Lever 			return -EAGAIN;
2019e4f93234SChuck Lever 		if (*p != xdr_zero) {
2020e4f93234SChuck Lever 			error = decode_nfs_fh3(xdr, entry->fh);
202164cfca85STrond Myklebust 			if (unlikely(error))
202264cfca85STrond Myklebust 				return -EAGAIN;
2023e4f93234SChuck Lever 		} else
2024e4f93234SChuck Lever 			zero_nfs_fh3(entry->fh);
2025e4f93234SChuck Lever 	}
2026e4f93234SChuck Lever 
202798de9ce6SFrank Sorenson 	entry->cookie = new_cookie;
202898de9ce6SFrank Sorenson 
2029573c4e1eSChuck Lever 	return 0;
2030e4f93234SChuck Lever }
2031e4f93234SChuck Lever 
2032e4f93234SChuck Lever /*
2033e4f93234SChuck Lever  * 3.3.16  READDIR3res
2034e4f93234SChuck Lever  *
2035e4f93234SChuck Lever  *	struct dirlist3 {
2036e4f93234SChuck Lever  *		entry3		*entries;
2037e4f93234SChuck Lever  *		bool		eof;
2038e4f93234SChuck Lever  *	};
2039e4f93234SChuck Lever  *
2040e4f93234SChuck Lever  *	struct READDIR3resok {
2041e4f93234SChuck Lever  *		post_op_attr	dir_attributes;
2042e4f93234SChuck Lever  *		cookieverf3	cookieverf;
2043e4f93234SChuck Lever  *		dirlist3	reply;
2044e4f93234SChuck Lever  *	};
2045e4f93234SChuck Lever  *
2046e4f93234SChuck Lever  *	struct READDIR3resfail {
2047e4f93234SChuck Lever  *		post_op_attr	dir_attributes;
2048e4f93234SChuck Lever  *	};
2049e4f93234SChuck Lever  *
2050e4f93234SChuck Lever  *	union READDIR3res switch (nfsstat3 status) {
2051e4f93234SChuck Lever  *	case NFS3_OK:
2052e4f93234SChuck Lever  *		READDIR3resok	resok;
2053e4f93234SChuck Lever  *	default:
2054e4f93234SChuck Lever  *		READDIR3resfail	resfail;
2055e4f93234SChuck Lever  *	};
2056e4f93234SChuck Lever  *
2057e4f93234SChuck Lever  * Read the directory contents into the page cache, but otherwise
2058e4f93234SChuck Lever  * don't touch them.  The actual decoding is done by nfs3_decode_entry()
2059e4f93234SChuck Lever  * during subsequent nfs_readdir() calls.
2060e4f93234SChuck Lever  */
decode_dirlist3(struct xdr_stream * xdr)2061e4f93234SChuck Lever static int decode_dirlist3(struct xdr_stream *xdr)
2062e4f93234SChuck Lever {
206364bd577eSTrond Myklebust 	return xdr_read_pages(xdr, xdr->buf->page_len);
2064e4f93234SChuck Lever }
2065e4f93234SChuck Lever 
decode_readdir3resok(struct xdr_stream * xdr,struct nfs3_readdirres * result,struct user_namespace * userns)2066e4f93234SChuck Lever static int decode_readdir3resok(struct xdr_stream *xdr,
2067264d948cSTrond Myklebust 				struct nfs3_readdirres *result,
2068264d948cSTrond Myklebust 				struct user_namespace *userns)
2069e4f93234SChuck Lever {
2070e4f93234SChuck Lever 	int error;
2071e4f93234SChuck Lever 
2072264d948cSTrond Myklebust 	error = decode_post_op_attr(xdr, result->dir_attr, userns);
2073e4f93234SChuck Lever 	if (unlikely(error))
2074e4f93234SChuck Lever 		goto out;
2075e4f93234SChuck Lever 	/* XXX: do we need to check if result->verf != NULL ? */
2076e4f93234SChuck Lever 	error = decode_cookieverf3(xdr, result->verf);
2077e4f93234SChuck Lever 	if (unlikely(error))
2078e4f93234SChuck Lever 		goto out;
2079e4f93234SChuck Lever 	error = decode_dirlist3(xdr);
2080e4f93234SChuck Lever out:
2081e4f93234SChuck Lever 	return error;
2082e4f93234SChuck Lever }
2083e4f93234SChuck Lever 
nfs3_xdr_dec_readdir3res(struct rpc_rqst * req,struct xdr_stream * xdr,void * data)2084bf269551SChuck Lever static int nfs3_xdr_dec_readdir3res(struct rpc_rqst *req,
2085bf269551SChuck Lever 				    struct xdr_stream *xdr,
2086fc016483SChristoph Hellwig 				    void *data)
2087e4f93234SChuck Lever {
2088fc016483SChristoph Hellwig 	struct nfs3_readdirres *result = data;
2089e4f93234SChuck Lever 	enum nfs_stat status;
2090e4f93234SChuck Lever 	int error;
2091e4f93234SChuck Lever 
2092bf269551SChuck Lever 	error = decode_nfsstat3(xdr, &status);
2093e4f93234SChuck Lever 	if (unlikely(error))
2094e4f93234SChuck Lever 		goto out;
2095e4f93234SChuck Lever 	if (status != NFS3_OK)
2096e4f93234SChuck Lever 		goto out_default;
2097264d948cSTrond Myklebust 	error = decode_readdir3resok(xdr, result, rpc_rqst_userns(req));
2098e4f93234SChuck Lever out:
2099e4f93234SChuck Lever 	return error;
2100e4f93234SChuck Lever out_default:
2101264d948cSTrond Myklebust 	error = decode_post_op_attr(xdr, result->dir_attr, rpc_rqst_userns(req));
2102e4f93234SChuck Lever 	if (unlikely(error))
2103e4f93234SChuck Lever 		goto out;
21045e7e5a0dSBryan Schumaker 	return nfs3_stat_to_errno(status);
2105e4f93234SChuck Lever }
2106e4f93234SChuck Lever 
2107e4f93234SChuck Lever /*
2108e4f93234SChuck Lever  * 3.3.18  FSSTAT3res
2109e4f93234SChuck Lever  *
2110e4f93234SChuck Lever  *	struct FSSTAT3resok {
2111e4f93234SChuck Lever  *		post_op_attr	obj_attributes;
2112e4f93234SChuck Lever  *		size3		tbytes;
2113e4f93234SChuck Lever  *		size3		fbytes;
2114e4f93234SChuck Lever  *		size3		abytes;
2115e4f93234SChuck Lever  *		size3		tfiles;
2116e4f93234SChuck Lever  *		size3		ffiles;
2117e4f93234SChuck Lever  *		size3		afiles;
2118e4f93234SChuck Lever  *		uint32		invarsec;
2119e4f93234SChuck Lever  *	};
2120e4f93234SChuck Lever  *
2121e4f93234SChuck Lever  *	struct FSSTAT3resfail {
2122e4f93234SChuck Lever  *		post_op_attr	obj_attributes;
2123e4f93234SChuck Lever  *	};
2124e4f93234SChuck Lever  *
2125e4f93234SChuck Lever  *	union FSSTAT3res switch (nfsstat3 status) {
2126e4f93234SChuck Lever  *	case NFS3_OK:
2127e4f93234SChuck Lever  *		FSSTAT3resok	resok;
2128e4f93234SChuck Lever  *	default:
2129e4f93234SChuck Lever  *		FSSTAT3resfail	resfail;
2130e4f93234SChuck Lever  *	};
2131e4f93234SChuck Lever  */
decode_fsstat3resok(struct xdr_stream * xdr,struct nfs_fsstat * result)2132e4f93234SChuck Lever static int decode_fsstat3resok(struct xdr_stream *xdr,
2133e4f93234SChuck Lever 			       struct nfs_fsstat *result)
2134e4f93234SChuck Lever {
2135e4f93234SChuck Lever 	__be32 *p;
2136e4f93234SChuck Lever 
2137e4f93234SChuck Lever 	p = xdr_inline_decode(xdr, 8 * 6 + 4);
2138eb72f484SChuck Lever 	if (unlikely(!p))
2139eb72f484SChuck Lever 		return -EIO;
2140e4f93234SChuck Lever 	p = xdr_decode_size3(p, &result->tbytes);
2141e4f93234SChuck Lever 	p = xdr_decode_size3(p, &result->fbytes);
2142e4f93234SChuck Lever 	p = xdr_decode_size3(p, &result->abytes);
2143e4f93234SChuck Lever 	p = xdr_decode_size3(p, &result->tfiles);
2144e4f93234SChuck Lever 	p = xdr_decode_size3(p, &result->ffiles);
2145e4f93234SChuck Lever 	xdr_decode_size3(p, &result->afiles);
2146e4f93234SChuck Lever 	/* ignore invarsec */
2147e4f93234SChuck Lever 	return 0;
2148e4f93234SChuck Lever }
2149e4f93234SChuck Lever 
nfs3_xdr_dec_fsstat3res(struct rpc_rqst * req,struct xdr_stream * xdr,void * data)2150bf269551SChuck Lever static int nfs3_xdr_dec_fsstat3res(struct rpc_rqst *req,
2151bf269551SChuck Lever 				   struct xdr_stream *xdr,
2152fc016483SChristoph Hellwig 				   void *data)
2153e4f93234SChuck Lever {
2154fc016483SChristoph Hellwig 	struct nfs_fsstat *result = data;
2155e4f93234SChuck Lever 	enum nfs_stat status;
2156e4f93234SChuck Lever 	int error;
2157e4f93234SChuck Lever 
2158bf269551SChuck Lever 	error = decode_nfsstat3(xdr, &status);
2159e4f93234SChuck Lever 	if (unlikely(error))
2160e4f93234SChuck Lever 		goto out;
2161264d948cSTrond Myklebust 	error = decode_post_op_attr(xdr, result->fattr, rpc_rqst_userns(req));
2162e4f93234SChuck Lever 	if (unlikely(error))
2163e4f93234SChuck Lever 		goto out;
2164e4f93234SChuck Lever 	if (status != NFS3_OK)
2165e4f93234SChuck Lever 		goto out_status;
2166bf269551SChuck Lever 	error = decode_fsstat3resok(xdr, result);
2167e4f93234SChuck Lever out:
2168e4f93234SChuck Lever 	return error;
2169e4f93234SChuck Lever out_status:
21705e7e5a0dSBryan Schumaker 	return nfs3_stat_to_errno(status);
2171e4f93234SChuck Lever }
2172e4f93234SChuck Lever 
2173e4f93234SChuck Lever /*
2174e4f93234SChuck Lever  * 3.3.19  FSINFO3res
2175e4f93234SChuck Lever  *
2176e4f93234SChuck Lever  *	struct FSINFO3resok {
2177e4f93234SChuck Lever  *		post_op_attr	obj_attributes;
2178e4f93234SChuck Lever  *		uint32		rtmax;
2179e4f93234SChuck Lever  *		uint32		rtpref;
2180e4f93234SChuck Lever  *		uint32		rtmult;
2181e4f93234SChuck Lever  *		uint32		wtmax;
2182e4f93234SChuck Lever  *		uint32		wtpref;
2183e4f93234SChuck Lever  *		uint32		wtmult;
2184e4f93234SChuck Lever  *		uint32		dtpref;
2185e4f93234SChuck Lever  *		size3		maxfilesize;
2186e4f93234SChuck Lever  *		nfstime3	time_delta;
2187e4f93234SChuck Lever  *		uint32		properties;
2188e4f93234SChuck Lever  *	};
2189e4f93234SChuck Lever  *
2190e4f93234SChuck Lever  *	struct FSINFO3resfail {
2191e4f93234SChuck Lever  *		post_op_attr	obj_attributes;
2192e4f93234SChuck Lever  *	};
2193e4f93234SChuck Lever  *
2194e4f93234SChuck Lever  *	union FSINFO3res switch (nfsstat3 status) {
2195e4f93234SChuck Lever  *	case NFS3_OK:
2196e4f93234SChuck Lever  *		FSINFO3resok	resok;
2197e4f93234SChuck Lever  *	default:
2198e4f93234SChuck Lever  *		FSINFO3resfail	resfail;
2199e4f93234SChuck Lever  *	};
2200e4f93234SChuck Lever  */
decode_fsinfo3resok(struct xdr_stream * xdr,struct nfs_fsinfo * result)2201e4f93234SChuck Lever static int decode_fsinfo3resok(struct xdr_stream *xdr,
2202e4f93234SChuck Lever 			       struct nfs_fsinfo *result)
2203e4f93234SChuck Lever {
2204e4f93234SChuck Lever 	__be32 *p;
2205e4f93234SChuck Lever 
2206e4f93234SChuck Lever 	p = xdr_inline_decode(xdr, 4 * 7 + 8 + 8 + 4);
2207eb72f484SChuck Lever 	if (unlikely(!p))
2208eb72f484SChuck Lever 		return -EIO;
2209e4f93234SChuck Lever 	result->rtmax  = be32_to_cpup(p++);
2210e4f93234SChuck Lever 	result->rtpref = be32_to_cpup(p++);
2211e4f93234SChuck Lever 	result->rtmult = be32_to_cpup(p++);
2212e4f93234SChuck Lever 	result->wtmax  = be32_to_cpup(p++);
2213e4f93234SChuck Lever 	result->wtpref = be32_to_cpup(p++);
2214e4f93234SChuck Lever 	result->wtmult = be32_to_cpup(p++);
2215e4f93234SChuck Lever 	result->dtpref = be32_to_cpup(p++);
2216e4f93234SChuck Lever 	p = xdr_decode_size3(p, &result->maxfilesize);
2217f6048709SChuck Lever 	xdr_decode_nfstime3(p, &result->time_delta);
2218e4f93234SChuck Lever 
2219e4f93234SChuck Lever 	/* ignore properties */
2220e4f93234SChuck Lever 	result->lease_time = 0;
2221eea41330STrond Myklebust 	result->change_attr_type = NFS4_CHANGE_TYPE_IS_UNDEFINED;
2222b622ffe1STrond Myklebust 	result->xattr_support = 0;
2223e4f93234SChuck Lever 	return 0;
2224e4f93234SChuck Lever }
2225e4f93234SChuck Lever 
nfs3_xdr_dec_fsinfo3res(struct rpc_rqst * req,struct xdr_stream * xdr,void * data)2226bf269551SChuck Lever static int nfs3_xdr_dec_fsinfo3res(struct rpc_rqst *req,
2227bf269551SChuck Lever 				   struct xdr_stream *xdr,
2228fc016483SChristoph Hellwig 				   void *data)
2229e4f93234SChuck Lever {
2230fc016483SChristoph Hellwig 	struct nfs_fsinfo *result = data;
2231e4f93234SChuck Lever 	enum nfs_stat status;
2232e4f93234SChuck Lever 	int error;
2233e4f93234SChuck Lever 
2234bf269551SChuck Lever 	error = decode_nfsstat3(xdr, &status);
2235e4f93234SChuck Lever 	if (unlikely(error))
2236e4f93234SChuck Lever 		goto out;
2237264d948cSTrond Myklebust 	error = decode_post_op_attr(xdr, result->fattr, rpc_rqst_userns(req));
2238e4f93234SChuck Lever 	if (unlikely(error))
2239e4f93234SChuck Lever 		goto out;
2240e4f93234SChuck Lever 	if (status != NFS3_OK)
2241e4f93234SChuck Lever 		goto out_status;
2242bf269551SChuck Lever 	error = decode_fsinfo3resok(xdr, result);
2243e4f93234SChuck Lever out:
2244e4f93234SChuck Lever 	return error;
2245e4f93234SChuck Lever out_status:
22465e7e5a0dSBryan Schumaker 	return nfs3_stat_to_errno(status);
2247e4f93234SChuck Lever }
2248e4f93234SChuck Lever 
2249e4f93234SChuck Lever /*
2250e4f93234SChuck Lever  * 3.3.20  PATHCONF3res
2251e4f93234SChuck Lever  *
2252e4f93234SChuck Lever  *	struct PATHCONF3resok {
2253e4f93234SChuck Lever  *		post_op_attr	obj_attributes;
2254e4f93234SChuck Lever  *		uint32		linkmax;
2255e4f93234SChuck Lever  *		uint32		name_max;
2256e4f93234SChuck Lever  *		bool		no_trunc;
2257e4f93234SChuck Lever  *		bool		chown_restricted;
2258e4f93234SChuck Lever  *		bool		case_insensitive;
2259e4f93234SChuck Lever  *		bool		case_preserving;
2260e4f93234SChuck Lever  *	};
2261e4f93234SChuck Lever  *
2262e4f93234SChuck Lever  *	struct PATHCONF3resfail {
2263e4f93234SChuck Lever  *		post_op_attr	obj_attributes;
2264e4f93234SChuck Lever  *	};
2265e4f93234SChuck Lever  *
2266e4f93234SChuck Lever  *	union PATHCONF3res switch (nfsstat3 status) {
2267e4f93234SChuck Lever  *	case NFS3_OK:
2268e4f93234SChuck Lever  *		PATHCONF3resok	resok;
2269e4f93234SChuck Lever  *	default:
2270e4f93234SChuck Lever  *		PATHCONF3resfail resfail;
2271e4f93234SChuck Lever  *	};
2272e4f93234SChuck Lever  */
decode_pathconf3resok(struct xdr_stream * xdr,struct nfs_pathconf * result)2273e4f93234SChuck Lever static int decode_pathconf3resok(struct xdr_stream *xdr,
2274e4f93234SChuck Lever 				 struct nfs_pathconf *result)
2275e4f93234SChuck Lever {
2276e4f93234SChuck Lever 	__be32 *p;
2277e4f93234SChuck Lever 
2278e4f93234SChuck Lever 	p = xdr_inline_decode(xdr, 4 * 6);
2279eb72f484SChuck Lever 	if (unlikely(!p))
2280eb72f484SChuck Lever 		return -EIO;
2281e4f93234SChuck Lever 	result->max_link = be32_to_cpup(p++);
2282e4f93234SChuck Lever 	result->max_namelen = be32_to_cpup(p);
2283e4f93234SChuck Lever 	/* ignore remaining fields */
2284e4f93234SChuck Lever 	return 0;
2285e4f93234SChuck Lever }
2286e4f93234SChuck Lever 
nfs3_xdr_dec_pathconf3res(struct rpc_rqst * req,struct xdr_stream * xdr,void * data)2287bf269551SChuck Lever static int nfs3_xdr_dec_pathconf3res(struct rpc_rqst *req,
2288bf269551SChuck Lever 				     struct xdr_stream *xdr,
2289fc016483SChristoph Hellwig 				     void *data)
2290e4f93234SChuck Lever {
2291fc016483SChristoph Hellwig 	struct nfs_pathconf *result = data;
2292e4f93234SChuck Lever 	enum nfs_stat status;
2293e4f93234SChuck Lever 	int error;
2294e4f93234SChuck Lever 
2295bf269551SChuck Lever 	error = decode_nfsstat3(xdr, &status);
2296e4f93234SChuck Lever 	if (unlikely(error))
2297e4f93234SChuck Lever 		goto out;
2298264d948cSTrond Myklebust 	error = decode_post_op_attr(xdr, result->fattr, rpc_rqst_userns(req));
2299e4f93234SChuck Lever 	if (unlikely(error))
2300e4f93234SChuck Lever 		goto out;
2301e4f93234SChuck Lever 	if (status != NFS3_OK)
2302e4f93234SChuck Lever 		goto out_status;
2303bf269551SChuck Lever 	error = decode_pathconf3resok(xdr, result);
2304e4f93234SChuck Lever out:
2305e4f93234SChuck Lever 	return error;
2306e4f93234SChuck Lever out_status:
23075e7e5a0dSBryan Schumaker 	return nfs3_stat_to_errno(status);
2308e4f93234SChuck Lever }
2309e4f93234SChuck Lever 
2310e4f93234SChuck Lever /*
2311e4f93234SChuck Lever  * 3.3.21  COMMIT3res
2312e4f93234SChuck Lever  *
2313e4f93234SChuck Lever  *	struct COMMIT3resok {
2314e4f93234SChuck Lever  *		wcc_data	file_wcc;
2315e4f93234SChuck Lever  *		writeverf3	verf;
2316e4f93234SChuck Lever  *	};
2317e4f93234SChuck Lever  *
2318e4f93234SChuck Lever  *	struct COMMIT3resfail {
2319e4f93234SChuck Lever  *		wcc_data	file_wcc;
2320e4f93234SChuck Lever  *	};
2321e4f93234SChuck Lever  *
2322e4f93234SChuck Lever  *	union COMMIT3res switch (nfsstat3 status) {
2323e4f93234SChuck Lever  *	case NFS3_OK:
2324e4f93234SChuck Lever  *		COMMIT3resok	resok;
2325e4f93234SChuck Lever  *	default:
2326e4f93234SChuck Lever  *		COMMIT3resfail	resfail;
2327e4f93234SChuck Lever  *	};
2328e4f93234SChuck Lever  */
nfs3_xdr_dec_commit3res(struct rpc_rqst * req,struct xdr_stream * xdr,void * data)2329bf269551SChuck Lever static int nfs3_xdr_dec_commit3res(struct rpc_rqst *req,
2330bf269551SChuck Lever 				   struct xdr_stream *xdr,
2331fc016483SChristoph Hellwig 				   void *data)
2332e4f93234SChuck Lever {
2333fc016483SChristoph Hellwig 	struct nfs_commitres *result = data;
2334221203ceSTrond Myklebust 	struct nfs_writeverf *verf = result->verf;
2335e4f93234SChuck Lever 	enum nfs_stat status;
2336e4f93234SChuck Lever 	int error;
2337e4f93234SChuck Lever 
2338bf269551SChuck Lever 	error = decode_nfsstat3(xdr, &status);
2339e4f93234SChuck Lever 	if (unlikely(error))
2340e4f93234SChuck Lever 		goto out;
2341264d948cSTrond Myklebust 	error = decode_wcc_data(xdr, result->fattr, rpc_rqst_userns(req));
2342e4f93234SChuck Lever 	if (unlikely(error))
2343e4f93234SChuck Lever 		goto out;
2344aabff4ddSPeng Tao 	result->op_status = status;
2345e4f93234SChuck Lever 	if (status != NFS3_OK)
2346e4f93234SChuck Lever 		goto out_status;
2347221203ceSTrond Myklebust 	error = decode_writeverf3(xdr, &verf->verifier);
2348221203ceSTrond Myklebust 	if (!error)
2349221203ceSTrond Myklebust 		verf->committed = NFS_FILE_SYNC;
2350e4f93234SChuck Lever out:
2351e4f93234SChuck Lever 	return error;
2352e4f93234SChuck Lever out_status:
23535e7e5a0dSBryan Schumaker 	return nfs3_stat_to_errno(status);
2354e4f93234SChuck Lever }
2355e4f93234SChuck Lever 
2356b7fa0554SAndreas Gruenbacher #ifdef CONFIG_NFS_V3_ACL
2357b7fa0554SAndreas Gruenbacher 
decode_getacl3resok(struct xdr_stream * xdr,struct nfs3_getaclres * result,struct user_namespace * userns)2358e4f93234SChuck Lever static inline int decode_getacl3resok(struct xdr_stream *xdr,
2359264d948cSTrond Myklebust 				      struct nfs3_getaclres *result,
2360264d948cSTrond Myklebust 				      struct user_namespace *userns)
2361e4f93234SChuck Lever {
2362e4f93234SChuck Lever 	struct posix_acl **acl;
2363e4f93234SChuck Lever 	unsigned int *aclcnt;
2364e4f93234SChuck Lever 	size_t hdrlen;
2365e4f93234SChuck Lever 	int error;
2366e4f93234SChuck Lever 
2367264d948cSTrond Myklebust 	error = decode_post_op_attr(xdr, result->fattr, userns);
2368e4f93234SChuck Lever 	if (unlikely(error))
2369e4f93234SChuck Lever 		goto out;
2370e4f93234SChuck Lever 	error = decode_uint32(xdr, &result->mask);
2371e4f93234SChuck Lever 	if (unlikely(error))
2372e4f93234SChuck Lever 		goto out;
2373e4f93234SChuck Lever 	error = -EINVAL;
2374e4f93234SChuck Lever 	if (result->mask & ~(NFS_ACL|NFS_ACLCNT|NFS_DFACL|NFS_DFACLCNT))
2375e4f93234SChuck Lever 		goto out;
2376e4f93234SChuck Lever 
23771aecca3eSTrond Myklebust 	hdrlen = xdr_stream_pos(xdr);
2378e4f93234SChuck Lever 
2379e4f93234SChuck Lever 	acl = NULL;
2380e4f93234SChuck Lever 	if (result->mask & NFS_ACL)
2381e4f93234SChuck Lever 		acl = &result->acl_access;
2382e4f93234SChuck Lever 	aclcnt = NULL;
2383e4f93234SChuck Lever 	if (result->mask & NFS_ACLCNT)
2384e4f93234SChuck Lever 		aclcnt = &result->acl_access_count;
2385e4f93234SChuck Lever 	error = nfsacl_decode(xdr->buf, hdrlen, aclcnt, acl);
2386e4f93234SChuck Lever 	if (unlikely(error <= 0))
2387e4f93234SChuck Lever 		goto out;
2388e4f93234SChuck Lever 
2389e4f93234SChuck Lever 	acl = NULL;
2390e4f93234SChuck Lever 	if (result->mask & NFS_DFACL)
2391e4f93234SChuck Lever 		acl = &result->acl_default;
2392e4f93234SChuck Lever 	aclcnt = NULL;
2393e4f93234SChuck Lever 	if (result->mask & NFS_DFACLCNT)
2394e4f93234SChuck Lever 		aclcnt = &result->acl_default_count;
2395e4f93234SChuck Lever 	error = nfsacl_decode(xdr->buf, hdrlen + error, aclcnt, acl);
2396e4f93234SChuck Lever 	if (unlikely(error <= 0))
2397e4f93234SChuck Lever 		return error;
2398e4f93234SChuck Lever 	error = 0;
2399e4f93234SChuck Lever out:
2400e4f93234SChuck Lever 	return error;
2401e4f93234SChuck Lever }
2402e4f93234SChuck Lever 
nfs3_xdr_dec_getacl3res(struct rpc_rqst * req,struct xdr_stream * xdr,void * result)2403bf269551SChuck Lever static int nfs3_xdr_dec_getacl3res(struct rpc_rqst *req,
2404bf269551SChuck Lever 				   struct xdr_stream *xdr,
2405fc016483SChristoph Hellwig 				   void *result)
2406e4f93234SChuck Lever {
2407e4f93234SChuck Lever 	enum nfs_stat status;
2408e4f93234SChuck Lever 	int error;
2409e4f93234SChuck Lever 
2410bf269551SChuck Lever 	error = decode_nfsstat3(xdr, &status);
2411e4f93234SChuck Lever 	if (unlikely(error))
2412e4f93234SChuck Lever 		goto out;
2413e4f93234SChuck Lever 	if (status != NFS3_OK)
2414e4f93234SChuck Lever 		goto out_default;
2415264d948cSTrond Myklebust 	error = decode_getacl3resok(xdr, result, rpc_rqst_userns(req));
2416e4f93234SChuck Lever out:
2417e4f93234SChuck Lever 	return error;
2418e4f93234SChuck Lever out_default:
24195e7e5a0dSBryan Schumaker 	return nfs3_stat_to_errno(status);
2420e4f93234SChuck Lever }
2421e4f93234SChuck Lever 
nfs3_xdr_dec_setacl3res(struct rpc_rqst * req,struct xdr_stream * xdr,void * result)2422bf269551SChuck Lever static int nfs3_xdr_dec_setacl3res(struct rpc_rqst *req,
2423bf269551SChuck Lever 				   struct xdr_stream *xdr,
2424fc016483SChristoph Hellwig 				   void *result)
2425e4f93234SChuck Lever {
2426e4f93234SChuck Lever 	enum nfs_stat status;
2427e4f93234SChuck Lever 	int error;
2428e4f93234SChuck Lever 
2429bf269551SChuck Lever 	error = decode_nfsstat3(xdr, &status);
2430e4f93234SChuck Lever 	if (unlikely(error))
2431e4f93234SChuck Lever 		goto out;
2432e4f93234SChuck Lever 	if (status != NFS3_OK)
2433e4f93234SChuck Lever 		goto out_default;
2434264d948cSTrond Myklebust 	error = decode_post_op_attr(xdr, result, rpc_rqst_userns(req));
2435e4f93234SChuck Lever out:
2436e4f93234SChuck Lever 	return error;
2437e4f93234SChuck Lever out_default:
24385e7e5a0dSBryan Schumaker 	return nfs3_stat_to_errno(status);
2439e4f93234SChuck Lever }
2440e4f93234SChuck Lever 
2441b7fa0554SAndreas Gruenbacher #endif  /* CONFIG_NFS_V3_ACL */
2442b7fa0554SAndreas Gruenbacher 
24435e7e5a0dSBryan Schumaker 
24445e7e5a0dSBryan Schumaker /*
24455e7e5a0dSBryan Schumaker  * We need to translate between nfs status return values and
24465e7e5a0dSBryan Schumaker  * the local errno values which may not be the same.
24475e7e5a0dSBryan Schumaker  */
24485e7e5a0dSBryan Schumaker static const struct {
24495e7e5a0dSBryan Schumaker 	int stat;
24505e7e5a0dSBryan Schumaker 	int errno;
24515e7e5a0dSBryan Schumaker } nfs_errtbl[] = {
24525e7e5a0dSBryan Schumaker 	{ NFS_OK,		0		},
24535e7e5a0dSBryan Schumaker 	{ NFSERR_PERM,		-EPERM		},
24545e7e5a0dSBryan Schumaker 	{ NFSERR_NOENT,		-ENOENT		},
24555e7e5a0dSBryan Schumaker 	{ NFSERR_IO,		-errno_NFSERR_IO},
24565e7e5a0dSBryan Schumaker 	{ NFSERR_NXIO,		-ENXIO		},
24575e7e5a0dSBryan Schumaker /*	{ NFSERR_EAGAIN,	-EAGAIN		}, */
24585e7e5a0dSBryan Schumaker 	{ NFSERR_ACCES,		-EACCES		},
24595e7e5a0dSBryan Schumaker 	{ NFSERR_EXIST,		-EEXIST		},
24605e7e5a0dSBryan Schumaker 	{ NFSERR_XDEV,		-EXDEV		},
24615e7e5a0dSBryan Schumaker 	{ NFSERR_NODEV,		-ENODEV		},
24625e7e5a0dSBryan Schumaker 	{ NFSERR_NOTDIR,	-ENOTDIR	},
24635e7e5a0dSBryan Schumaker 	{ NFSERR_ISDIR,		-EISDIR		},
24645e7e5a0dSBryan Schumaker 	{ NFSERR_INVAL,		-EINVAL		},
24655e7e5a0dSBryan Schumaker 	{ NFSERR_FBIG,		-EFBIG		},
24665e7e5a0dSBryan Schumaker 	{ NFSERR_NOSPC,		-ENOSPC		},
24675e7e5a0dSBryan Schumaker 	{ NFSERR_ROFS,		-EROFS		},
24685e7e5a0dSBryan Schumaker 	{ NFSERR_MLINK,		-EMLINK		},
24695e7e5a0dSBryan Schumaker 	{ NFSERR_NAMETOOLONG,	-ENAMETOOLONG	},
24705e7e5a0dSBryan Schumaker 	{ NFSERR_NOTEMPTY,	-ENOTEMPTY	},
24715e7e5a0dSBryan Schumaker 	{ NFSERR_DQUOT,		-EDQUOT		},
24725e7e5a0dSBryan Schumaker 	{ NFSERR_STALE,		-ESTALE		},
24735e7e5a0dSBryan Schumaker 	{ NFSERR_REMOTE,	-EREMOTE	},
24745e7e5a0dSBryan Schumaker #ifdef EWFLUSH
24755e7e5a0dSBryan Schumaker 	{ NFSERR_WFLUSH,	-EWFLUSH	},
24765e7e5a0dSBryan Schumaker #endif
24775e7e5a0dSBryan Schumaker 	{ NFSERR_BADHANDLE,	-EBADHANDLE	},
24785e7e5a0dSBryan Schumaker 	{ NFSERR_NOT_SYNC,	-ENOTSYNC	},
24795e7e5a0dSBryan Schumaker 	{ NFSERR_BAD_COOKIE,	-EBADCOOKIE	},
24805e7e5a0dSBryan Schumaker 	{ NFSERR_NOTSUPP,	-ENOTSUPP	},
24815e7e5a0dSBryan Schumaker 	{ NFSERR_TOOSMALL,	-ETOOSMALL	},
24825e7e5a0dSBryan Schumaker 	{ NFSERR_SERVERFAULT,	-EREMOTEIO	},
24835e7e5a0dSBryan Schumaker 	{ NFSERR_BADTYPE,	-EBADTYPE	},
24845e7e5a0dSBryan Schumaker 	{ NFSERR_JUKEBOX,	-EJUKEBOX	},
24855e7e5a0dSBryan Schumaker 	{ -1,			-EIO		}
24865e7e5a0dSBryan Schumaker };
24875e7e5a0dSBryan Schumaker 
24885e7e5a0dSBryan Schumaker /**
24895e7e5a0dSBryan Schumaker  * nfs3_stat_to_errno - convert an NFS status code to a local errno
24905e7e5a0dSBryan Schumaker  * @status: NFS status code to convert
24915e7e5a0dSBryan Schumaker  *
24925e7e5a0dSBryan Schumaker  * Returns a local errno value, or -EIO if the NFS status code is
24935e7e5a0dSBryan Schumaker  * not recognized.  This function is used jointly by NFSv2 and NFSv3.
24945e7e5a0dSBryan Schumaker  */
nfs3_stat_to_errno(enum nfs_stat status)24955e7e5a0dSBryan Schumaker static int nfs3_stat_to_errno(enum nfs_stat status)
24965e7e5a0dSBryan Schumaker {
24975e7e5a0dSBryan Schumaker 	int i;
24985e7e5a0dSBryan Schumaker 
24995e7e5a0dSBryan Schumaker 	for (i = 0; nfs_errtbl[i].stat != -1; i++) {
25005e7e5a0dSBryan Schumaker 		if (nfs_errtbl[i].stat == (int)status)
25015e7e5a0dSBryan Schumaker 			return nfs_errtbl[i].errno;
25025e7e5a0dSBryan Schumaker 	}
25035e7e5a0dSBryan Schumaker 	dprintk("NFS: Unrecognized nfs status value: %u\n", status);
25045e7e5a0dSBryan Schumaker 	return nfs_errtbl[i].errno;
25055e7e5a0dSBryan Schumaker }
25065e7e5a0dSBryan Schumaker 
25075e7e5a0dSBryan Schumaker 
25081da177e4SLinus Torvalds #define PROC(proc, argtype, restype, timer)				\
25091da177e4SLinus Torvalds [NFS3PROC_##proc] = {							\
25101da177e4SLinus Torvalds 	.p_proc      = NFS3PROC_##proc,					\
2511fcc85819SChristoph Hellwig 	.p_encode    = nfs3_xdr_enc_##argtype##3args,			\
2512fc016483SChristoph Hellwig 	.p_decode    = nfs3_xdr_dec_##restype##3res,			\
2513ad96b5b5SChuck Lever 	.p_arglen    = NFS3_##argtype##args_sz,				\
2514f5fc3c50SChuck Lever 	.p_replen    = NFS3_##restype##res_sz,				\
2515cc0175c1SChuck Lever 	.p_timer     = timer,						\
2516cc0175c1SChuck Lever 	.p_statidx   = NFS3PROC_##proc,					\
2517cc0175c1SChuck Lever 	.p_name      = #proc,						\
25181da177e4SLinus Torvalds 	}
25191da177e4SLinus Torvalds 
2520511e936bSChristoph Hellwig const struct rpc_procinfo nfs3_procedures[] = {
2521f5fc3c50SChuck Lever 	PROC(GETATTR,		getattr,	getattr,	1),
2522f5fc3c50SChuck Lever 	PROC(SETATTR,		setattr,	setattr,	0),
2523f5fc3c50SChuck Lever 	PROC(LOOKUP,		lookup,		lookup,		2),
2524f5fc3c50SChuck Lever 	PROC(ACCESS,		access,		access,		1),
2525f5fc3c50SChuck Lever 	PROC(READLINK,		readlink,	readlink,	3),
2526f5fc3c50SChuck Lever 	PROC(READ,		read,		read,		3),
2527f5fc3c50SChuck Lever 	PROC(WRITE,		write,		write,		4),
2528f5fc3c50SChuck Lever 	PROC(CREATE,		create,		create,		0),
2529f5fc3c50SChuck Lever 	PROC(MKDIR,		mkdir,		create,		0),
2530f5fc3c50SChuck Lever 	PROC(SYMLINK,		symlink,	create,		0),
2531f5fc3c50SChuck Lever 	PROC(MKNOD,		mknod,		create,		0),
2532f5fc3c50SChuck Lever 	PROC(REMOVE,		remove,		remove,		0),
2533f5fc3c50SChuck Lever 	PROC(RMDIR,		lookup,		setattr,	0),
2534f5fc3c50SChuck Lever 	PROC(RENAME,		rename,		rename,		0),
2535f5fc3c50SChuck Lever 	PROC(LINK,		link,		link,		0),
2536f5fc3c50SChuck Lever 	PROC(READDIR,		readdir,	readdir,	3),
2537f5fc3c50SChuck Lever 	PROC(READDIRPLUS,	readdirplus,	readdir,	3),
2538f5fc3c50SChuck Lever 	PROC(FSSTAT,		getattr,	fsstat,		0),
2539f5fc3c50SChuck Lever 	PROC(FSINFO,		getattr,	fsinfo,		0),
2540f5fc3c50SChuck Lever 	PROC(PATHCONF,		getattr,	pathconf,	0),
2541f5fc3c50SChuck Lever 	PROC(COMMIT,		commit,		commit,		5),
25421da177e4SLinus Torvalds };
25431da177e4SLinus Torvalds 
2544c551858aSChristoph Hellwig static unsigned int nfs_version3_counts[ARRAY_SIZE(nfs3_procedures)];
2545a613fa16STrond Myklebust const struct rpc_version nfs_version3 = {
25461da177e4SLinus Torvalds 	.number			= 3,
2547e8c96f8cSTobias Klauser 	.nrprocs		= ARRAY_SIZE(nfs3_procedures),
2548c551858aSChristoph Hellwig 	.procs			= nfs3_procedures,
2549c551858aSChristoph Hellwig 	.counts			= nfs_version3_counts,
25501da177e4SLinus Torvalds };
25511da177e4SLinus Torvalds 
2552b7fa0554SAndreas Gruenbacher #ifdef CONFIG_NFS_V3_ACL
2553511e936bSChristoph Hellwig static const struct rpc_procinfo nfs3_acl_procedures[] = {
2554b7fa0554SAndreas Gruenbacher 	[ACLPROC3_GETACL] = {
2555b7fa0554SAndreas Gruenbacher 		.p_proc = ACLPROC3_GETACL,
2556fcc85819SChristoph Hellwig 		.p_encode = nfs3_xdr_enc_getacl3args,
2557fc016483SChristoph Hellwig 		.p_decode = nfs3_xdr_dec_getacl3res,
25582bea90d4SChuck Lever 		.p_arglen = ACL3_getaclargs_sz,
25592bea90d4SChuck Lever 		.p_replen = ACL3_getaclres_sz,
2560b7fa0554SAndreas Gruenbacher 		.p_timer = 1,
2561cc0175c1SChuck Lever 		.p_name = "GETACL",
2562b7fa0554SAndreas Gruenbacher 	},
2563b7fa0554SAndreas Gruenbacher 	[ACLPROC3_SETACL] = {
2564b7fa0554SAndreas Gruenbacher 		.p_proc = ACLPROC3_SETACL,
2565fcc85819SChristoph Hellwig 		.p_encode = nfs3_xdr_enc_setacl3args,
2566fc016483SChristoph Hellwig 		.p_decode = nfs3_xdr_dec_setacl3res,
25672bea90d4SChuck Lever 		.p_arglen = ACL3_setaclargs_sz,
25682bea90d4SChuck Lever 		.p_replen = ACL3_setaclres_sz,
2569b7fa0554SAndreas Gruenbacher 		.p_timer = 0,
2570cc0175c1SChuck Lever 		.p_name = "SETACL",
2571b7fa0554SAndreas Gruenbacher 	},
2572b7fa0554SAndreas Gruenbacher };
2573b7fa0554SAndreas Gruenbacher 
2574c551858aSChristoph Hellwig static unsigned int nfs3_acl_counts[ARRAY_SIZE(nfs3_acl_procedures)];
2575a613fa16STrond Myklebust const struct rpc_version nfsacl_version3 = {
2576b7fa0554SAndreas Gruenbacher 	.number			= 3,
25779ae7d8ffSChristoph Hellwig 	.nrprocs		= ARRAY_SIZE(nfs3_acl_procedures),
2578b7fa0554SAndreas Gruenbacher 	.procs			= nfs3_acl_procedures,
2579c551858aSChristoph Hellwig 	.counts			= nfs3_acl_counts,
2580b7fa0554SAndreas Gruenbacher };
2581b7fa0554SAndreas Gruenbacher #endif  /* CONFIG_NFS_V3_ACL */
2582