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