xref: /OK3568_Linux_fs/kernel/fs/nfs/nfs2xdr.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * linux/fs/nfs/nfs2xdr.c
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * XDR functions to encode/decode NFS RPC arguments and results.
6*4882a593Smuzhiyun  *
7*4882a593Smuzhiyun  * Copyright (C) 1992, 1993, 1994  Rick Sladkey
8*4882a593Smuzhiyun  * Copyright (C) 1996 Olaf Kirch
9*4882a593Smuzhiyun  * 04 Aug 1998  Ion Badulescu <ionut@cs.columbia.edu>
10*4882a593Smuzhiyun  * 		FIFO's need special handling in NFSv2
11*4882a593Smuzhiyun  */
12*4882a593Smuzhiyun 
13*4882a593Smuzhiyun #include <linux/param.h>
14*4882a593Smuzhiyun #include <linux/time.h>
15*4882a593Smuzhiyun #include <linux/mm.h>
16*4882a593Smuzhiyun #include <linux/errno.h>
17*4882a593Smuzhiyun #include <linux/string.h>
18*4882a593Smuzhiyun #include <linux/in.h>
19*4882a593Smuzhiyun #include <linux/pagemap.h>
20*4882a593Smuzhiyun #include <linux/proc_fs.h>
21*4882a593Smuzhiyun #include <linux/sunrpc/clnt.h>
22*4882a593Smuzhiyun #include <linux/nfs.h>
23*4882a593Smuzhiyun #include <linux/nfs2.h>
24*4882a593Smuzhiyun #include <linux/nfs_fs.h>
25*4882a593Smuzhiyun #include "nfstrace.h"
26*4882a593Smuzhiyun #include "internal.h"
27*4882a593Smuzhiyun 
28*4882a593Smuzhiyun #define NFSDBG_FACILITY		NFSDBG_XDR
29*4882a593Smuzhiyun 
30*4882a593Smuzhiyun /* Mapping from NFS error code to "errno" error code. */
31*4882a593Smuzhiyun #define errno_NFSERR_IO		EIO
32*4882a593Smuzhiyun 
33*4882a593Smuzhiyun /*
34*4882a593Smuzhiyun  * Declare the space requirements for NFS arguments and replies as
35*4882a593Smuzhiyun  * number of 32bit-words
36*4882a593Smuzhiyun  */
37*4882a593Smuzhiyun #define NFS_fhandle_sz		(8)
38*4882a593Smuzhiyun #define NFS_sattr_sz		(8)
39*4882a593Smuzhiyun #define NFS_filename_sz		(1+(NFS2_MAXNAMLEN>>2))
40*4882a593Smuzhiyun #define NFS_path_sz		(1+(NFS2_MAXPATHLEN>>2))
41*4882a593Smuzhiyun #define NFS_fattr_sz		(17)
42*4882a593Smuzhiyun #define NFS_info_sz		(5)
43*4882a593Smuzhiyun #define NFS_entry_sz		(NFS_filename_sz+3)
44*4882a593Smuzhiyun 
45*4882a593Smuzhiyun #define NFS_diropargs_sz	(NFS_fhandle_sz+NFS_filename_sz)
46*4882a593Smuzhiyun #define NFS_removeargs_sz	(NFS_fhandle_sz+NFS_filename_sz)
47*4882a593Smuzhiyun #define NFS_sattrargs_sz	(NFS_fhandle_sz+NFS_sattr_sz)
48*4882a593Smuzhiyun #define NFS_readlinkargs_sz	(NFS_fhandle_sz)
49*4882a593Smuzhiyun #define NFS_readargs_sz		(NFS_fhandle_sz+3)
50*4882a593Smuzhiyun #define NFS_writeargs_sz	(NFS_fhandle_sz+4)
51*4882a593Smuzhiyun #define NFS_createargs_sz	(NFS_diropargs_sz+NFS_sattr_sz)
52*4882a593Smuzhiyun #define NFS_renameargs_sz	(NFS_diropargs_sz+NFS_diropargs_sz)
53*4882a593Smuzhiyun #define NFS_linkargs_sz		(NFS_fhandle_sz+NFS_diropargs_sz)
54*4882a593Smuzhiyun #define NFS_symlinkargs_sz	(NFS_diropargs_sz+1+NFS_sattr_sz)
55*4882a593Smuzhiyun #define NFS_readdirargs_sz	(NFS_fhandle_sz+2)
56*4882a593Smuzhiyun 
57*4882a593Smuzhiyun #define NFS_attrstat_sz		(1+NFS_fattr_sz)
58*4882a593Smuzhiyun #define NFS_diropres_sz		(1+NFS_fhandle_sz+NFS_fattr_sz)
59*4882a593Smuzhiyun #define NFS_readlinkres_sz	(2+1)
60*4882a593Smuzhiyun #define NFS_readres_sz		(1+NFS_fattr_sz+1+1)
61*4882a593Smuzhiyun #define NFS_writeres_sz         (NFS_attrstat_sz)
62*4882a593Smuzhiyun #define NFS_stat_sz		(1)
63*4882a593Smuzhiyun #define NFS_readdirres_sz	(1+1)
64*4882a593Smuzhiyun #define NFS_statfsres_sz	(1+NFS_info_sz)
65*4882a593Smuzhiyun 
66*4882a593Smuzhiyun static int nfs_stat_to_errno(enum nfs_stat);
67*4882a593Smuzhiyun 
68*4882a593Smuzhiyun /*
69*4882a593Smuzhiyun  * Encode/decode NFSv2 basic data types
70*4882a593Smuzhiyun  *
71*4882a593Smuzhiyun  * Basic NFSv2 data types are defined in section 2.3 of RFC 1094:
72*4882a593Smuzhiyun  * "NFS: Network File System Protocol Specification".
73*4882a593Smuzhiyun  *
74*4882a593Smuzhiyun  * Not all basic data types have their own encoding and decoding
75*4882a593Smuzhiyun  * functions.  For run-time efficiency, some data types are encoded
76*4882a593Smuzhiyun  * or decoded inline.
77*4882a593Smuzhiyun  */
78*4882a593Smuzhiyun 
rpc_userns(const struct rpc_clnt * clnt)79*4882a593Smuzhiyun static struct user_namespace *rpc_userns(const struct rpc_clnt *clnt)
80*4882a593Smuzhiyun {
81*4882a593Smuzhiyun 	if (clnt && clnt->cl_cred)
82*4882a593Smuzhiyun 		return clnt->cl_cred->user_ns;
83*4882a593Smuzhiyun 	return &init_user_ns;
84*4882a593Smuzhiyun }
85*4882a593Smuzhiyun 
rpc_rqst_userns(const struct rpc_rqst * rqstp)86*4882a593Smuzhiyun static struct user_namespace *rpc_rqst_userns(const struct rpc_rqst *rqstp)
87*4882a593Smuzhiyun {
88*4882a593Smuzhiyun 	if (rqstp->rq_task)
89*4882a593Smuzhiyun 		return rpc_userns(rqstp->rq_task->tk_client);
90*4882a593Smuzhiyun 	return &init_user_ns;
91*4882a593Smuzhiyun }
92*4882a593Smuzhiyun 
93*4882a593Smuzhiyun /*
94*4882a593Smuzhiyun  *	typedef opaque	nfsdata<>;
95*4882a593Smuzhiyun  */
decode_nfsdata(struct xdr_stream * xdr,struct nfs_pgio_res * result)96*4882a593Smuzhiyun static int decode_nfsdata(struct xdr_stream *xdr, struct nfs_pgio_res *result)
97*4882a593Smuzhiyun {
98*4882a593Smuzhiyun 	u32 recvd, count;
99*4882a593Smuzhiyun 	__be32 *p;
100*4882a593Smuzhiyun 
101*4882a593Smuzhiyun 	p = xdr_inline_decode(xdr, 4);
102*4882a593Smuzhiyun 	if (unlikely(!p))
103*4882a593Smuzhiyun 		return -EIO;
104*4882a593Smuzhiyun 	count = be32_to_cpup(p);
105*4882a593Smuzhiyun 	recvd = xdr_read_pages(xdr, count);
106*4882a593Smuzhiyun 	if (unlikely(count > recvd))
107*4882a593Smuzhiyun 		goto out_cheating;
108*4882a593Smuzhiyun out:
109*4882a593Smuzhiyun 	result->eof = 0;	/* NFSv2 does not pass EOF flag on the wire. */
110*4882a593Smuzhiyun 	result->count = count;
111*4882a593Smuzhiyun 	return count;
112*4882a593Smuzhiyun out_cheating:
113*4882a593Smuzhiyun 	dprintk("NFS: server cheating in read result: "
114*4882a593Smuzhiyun 		"count %u > recvd %u\n", count, recvd);
115*4882a593Smuzhiyun 	count = recvd;
116*4882a593Smuzhiyun 	goto out;
117*4882a593Smuzhiyun }
118*4882a593Smuzhiyun 
119*4882a593Smuzhiyun /*
120*4882a593Smuzhiyun  *	enum stat {
121*4882a593Smuzhiyun  *		NFS_OK = 0,
122*4882a593Smuzhiyun  *		NFSERR_PERM = 1,
123*4882a593Smuzhiyun  *		NFSERR_NOENT = 2,
124*4882a593Smuzhiyun  *		NFSERR_IO = 5,
125*4882a593Smuzhiyun  *		NFSERR_NXIO = 6,
126*4882a593Smuzhiyun  *		NFSERR_ACCES = 13,
127*4882a593Smuzhiyun  *		NFSERR_EXIST = 17,
128*4882a593Smuzhiyun  *		NFSERR_NODEV = 19,
129*4882a593Smuzhiyun  *		NFSERR_NOTDIR = 20,
130*4882a593Smuzhiyun  *		NFSERR_ISDIR = 21,
131*4882a593Smuzhiyun  *		NFSERR_FBIG = 27,
132*4882a593Smuzhiyun  *		NFSERR_NOSPC = 28,
133*4882a593Smuzhiyun  *		NFSERR_ROFS = 30,
134*4882a593Smuzhiyun  *		NFSERR_NAMETOOLONG = 63,
135*4882a593Smuzhiyun  *		NFSERR_NOTEMPTY = 66,
136*4882a593Smuzhiyun  *		NFSERR_DQUOT = 69,
137*4882a593Smuzhiyun  *		NFSERR_STALE = 70,
138*4882a593Smuzhiyun  *		NFSERR_WFLUSH = 99
139*4882a593Smuzhiyun  *	};
140*4882a593Smuzhiyun  */
decode_stat(struct xdr_stream * xdr,enum nfs_stat * status)141*4882a593Smuzhiyun static int decode_stat(struct xdr_stream *xdr, enum nfs_stat *status)
142*4882a593Smuzhiyun {
143*4882a593Smuzhiyun 	__be32 *p;
144*4882a593Smuzhiyun 
145*4882a593Smuzhiyun 	p = xdr_inline_decode(xdr, 4);
146*4882a593Smuzhiyun 	if (unlikely(!p))
147*4882a593Smuzhiyun 		return -EIO;
148*4882a593Smuzhiyun 	if (unlikely(*p != cpu_to_be32(NFS_OK)))
149*4882a593Smuzhiyun 		goto out_status;
150*4882a593Smuzhiyun 	*status = 0;
151*4882a593Smuzhiyun 	return 0;
152*4882a593Smuzhiyun out_status:
153*4882a593Smuzhiyun 	*status = be32_to_cpup(p);
154*4882a593Smuzhiyun 	trace_nfs_xdr_status(xdr, (int)*status);
155*4882a593Smuzhiyun 	return 0;
156*4882a593Smuzhiyun }
157*4882a593Smuzhiyun 
158*4882a593Smuzhiyun /*
159*4882a593Smuzhiyun  * 2.3.2.  ftype
160*4882a593Smuzhiyun  *
161*4882a593Smuzhiyun  *	enum ftype {
162*4882a593Smuzhiyun  *		NFNON = 0,
163*4882a593Smuzhiyun  *		NFREG = 1,
164*4882a593Smuzhiyun  *		NFDIR = 2,
165*4882a593Smuzhiyun  *		NFBLK = 3,
166*4882a593Smuzhiyun  *		NFCHR = 4,
167*4882a593Smuzhiyun  *		NFLNK = 5
168*4882a593Smuzhiyun  *	};
169*4882a593Smuzhiyun  *
170*4882a593Smuzhiyun  */
xdr_decode_ftype(__be32 * p,u32 * type)171*4882a593Smuzhiyun static __be32 *xdr_decode_ftype(__be32 *p, u32 *type)
172*4882a593Smuzhiyun {
173*4882a593Smuzhiyun 	*type = be32_to_cpup(p++);
174*4882a593Smuzhiyun 	if (unlikely(*type > NF2FIFO))
175*4882a593Smuzhiyun 		*type = NFBAD;
176*4882a593Smuzhiyun 	return p;
177*4882a593Smuzhiyun }
178*4882a593Smuzhiyun 
179*4882a593Smuzhiyun /*
180*4882a593Smuzhiyun  * 2.3.3.  fhandle
181*4882a593Smuzhiyun  *
182*4882a593Smuzhiyun  *	typedef opaque fhandle[FHSIZE];
183*4882a593Smuzhiyun  */
encode_fhandle(struct xdr_stream * xdr,const struct nfs_fh * fh)184*4882a593Smuzhiyun static void encode_fhandle(struct xdr_stream *xdr, const struct nfs_fh *fh)
185*4882a593Smuzhiyun {
186*4882a593Smuzhiyun 	__be32 *p;
187*4882a593Smuzhiyun 
188*4882a593Smuzhiyun 	p = xdr_reserve_space(xdr, NFS2_FHSIZE);
189*4882a593Smuzhiyun 	memcpy(p, fh->data, NFS2_FHSIZE);
190*4882a593Smuzhiyun }
191*4882a593Smuzhiyun 
decode_fhandle(struct xdr_stream * xdr,struct nfs_fh * fh)192*4882a593Smuzhiyun static int decode_fhandle(struct xdr_stream *xdr, struct nfs_fh *fh)
193*4882a593Smuzhiyun {
194*4882a593Smuzhiyun 	__be32 *p;
195*4882a593Smuzhiyun 
196*4882a593Smuzhiyun 	p = xdr_inline_decode(xdr, NFS2_FHSIZE);
197*4882a593Smuzhiyun 	if (unlikely(!p))
198*4882a593Smuzhiyun 		return -EIO;
199*4882a593Smuzhiyun 	fh->size = NFS2_FHSIZE;
200*4882a593Smuzhiyun 	memcpy(fh->data, p, NFS2_FHSIZE);
201*4882a593Smuzhiyun 	return 0;
202*4882a593Smuzhiyun }
203*4882a593Smuzhiyun 
204*4882a593Smuzhiyun /*
205*4882a593Smuzhiyun  * 2.3.4.  timeval
206*4882a593Smuzhiyun  *
207*4882a593Smuzhiyun  *	struct timeval {
208*4882a593Smuzhiyun  *		unsigned int seconds;
209*4882a593Smuzhiyun  *		unsigned int useconds;
210*4882a593Smuzhiyun  *	};
211*4882a593Smuzhiyun  */
xdr_encode_time(__be32 * p,const struct timespec64 * timep)212*4882a593Smuzhiyun static __be32 *xdr_encode_time(__be32 *p, const struct timespec64 *timep)
213*4882a593Smuzhiyun {
214*4882a593Smuzhiyun 	*p++ = cpu_to_be32((u32)timep->tv_sec);
215*4882a593Smuzhiyun 	if (timep->tv_nsec != 0)
216*4882a593Smuzhiyun 		*p++ = cpu_to_be32(timep->tv_nsec / NSEC_PER_USEC);
217*4882a593Smuzhiyun 	else
218*4882a593Smuzhiyun 		*p++ = cpu_to_be32(0);
219*4882a593Smuzhiyun 	return p;
220*4882a593Smuzhiyun }
221*4882a593Smuzhiyun 
222*4882a593Smuzhiyun /*
223*4882a593Smuzhiyun  * Passing the invalid value useconds=1000000 is a Sun convention for
224*4882a593Smuzhiyun  * "set to current server time".  It's needed to make permissions checks
225*4882a593Smuzhiyun  * for the "touch" program across v2 mounts to Solaris and Irix servers
226*4882a593Smuzhiyun  * work correctly.  See description of sattr in section 6.1 of "NFS
227*4882a593Smuzhiyun  * Illustrated" by Brent Callaghan, Addison-Wesley, ISBN 0-201-32750-5.
228*4882a593Smuzhiyun  */
xdr_encode_current_server_time(__be32 * p,const struct timespec64 * timep)229*4882a593Smuzhiyun static __be32 *xdr_encode_current_server_time(__be32 *p,
230*4882a593Smuzhiyun 					      const struct timespec64 *timep)
231*4882a593Smuzhiyun {
232*4882a593Smuzhiyun 	*p++ = cpu_to_be32(timep->tv_sec);
233*4882a593Smuzhiyun 	*p++ = cpu_to_be32(1000000);
234*4882a593Smuzhiyun 	return p;
235*4882a593Smuzhiyun }
236*4882a593Smuzhiyun 
xdr_decode_time(__be32 * p,struct timespec64 * timep)237*4882a593Smuzhiyun static __be32 *xdr_decode_time(__be32 *p, struct timespec64 *timep)
238*4882a593Smuzhiyun {
239*4882a593Smuzhiyun 	timep->tv_sec = be32_to_cpup(p++);
240*4882a593Smuzhiyun 	timep->tv_nsec = be32_to_cpup(p++) * NSEC_PER_USEC;
241*4882a593Smuzhiyun 	return p;
242*4882a593Smuzhiyun }
243*4882a593Smuzhiyun 
244*4882a593Smuzhiyun /*
245*4882a593Smuzhiyun  * 2.3.5.  fattr
246*4882a593Smuzhiyun  *
247*4882a593Smuzhiyun  *	struct fattr {
248*4882a593Smuzhiyun  *		ftype		type;
249*4882a593Smuzhiyun  *		unsigned int	mode;
250*4882a593Smuzhiyun  *		unsigned int	nlink;
251*4882a593Smuzhiyun  *		unsigned int	uid;
252*4882a593Smuzhiyun  *		unsigned int	gid;
253*4882a593Smuzhiyun  *		unsigned int	size;
254*4882a593Smuzhiyun  *		unsigned int	blocksize;
255*4882a593Smuzhiyun  *		unsigned int	rdev;
256*4882a593Smuzhiyun  *		unsigned int	blocks;
257*4882a593Smuzhiyun  *		unsigned int	fsid;
258*4882a593Smuzhiyun  *		unsigned int	fileid;
259*4882a593Smuzhiyun  *		timeval		atime;
260*4882a593Smuzhiyun  *		timeval		mtime;
261*4882a593Smuzhiyun  *		timeval		ctime;
262*4882a593Smuzhiyun  *	};
263*4882a593Smuzhiyun  *
264*4882a593Smuzhiyun  */
decode_fattr(struct xdr_stream * xdr,struct nfs_fattr * fattr,struct user_namespace * userns)265*4882a593Smuzhiyun static int decode_fattr(struct xdr_stream *xdr, struct nfs_fattr *fattr,
266*4882a593Smuzhiyun 		struct user_namespace *userns)
267*4882a593Smuzhiyun {
268*4882a593Smuzhiyun 	u32 rdev, type;
269*4882a593Smuzhiyun 	__be32 *p;
270*4882a593Smuzhiyun 
271*4882a593Smuzhiyun 	p = xdr_inline_decode(xdr, NFS_fattr_sz << 2);
272*4882a593Smuzhiyun 	if (unlikely(!p))
273*4882a593Smuzhiyun 		return -EIO;
274*4882a593Smuzhiyun 
275*4882a593Smuzhiyun 	fattr->valid |= NFS_ATTR_FATTR_V2;
276*4882a593Smuzhiyun 
277*4882a593Smuzhiyun 	p = xdr_decode_ftype(p, &type);
278*4882a593Smuzhiyun 
279*4882a593Smuzhiyun 	fattr->mode = be32_to_cpup(p++);
280*4882a593Smuzhiyun 	fattr->nlink = be32_to_cpup(p++);
281*4882a593Smuzhiyun 	fattr->uid = make_kuid(userns, be32_to_cpup(p++));
282*4882a593Smuzhiyun 	if (!uid_valid(fattr->uid))
283*4882a593Smuzhiyun 		goto out_uid;
284*4882a593Smuzhiyun 	fattr->gid = make_kgid(userns, be32_to_cpup(p++));
285*4882a593Smuzhiyun 	if (!gid_valid(fattr->gid))
286*4882a593Smuzhiyun 		goto out_gid;
287*4882a593Smuzhiyun 
288*4882a593Smuzhiyun 	fattr->size = be32_to_cpup(p++);
289*4882a593Smuzhiyun 	fattr->du.nfs2.blocksize = be32_to_cpup(p++);
290*4882a593Smuzhiyun 
291*4882a593Smuzhiyun 	rdev = be32_to_cpup(p++);
292*4882a593Smuzhiyun 	fattr->rdev = new_decode_dev(rdev);
293*4882a593Smuzhiyun 	if (type == (u32)NFCHR && rdev == (u32)NFS2_FIFO_DEV) {
294*4882a593Smuzhiyun 		fattr->mode = (fattr->mode & ~S_IFMT) | S_IFIFO;
295*4882a593Smuzhiyun 		fattr->rdev = 0;
296*4882a593Smuzhiyun 	}
297*4882a593Smuzhiyun 
298*4882a593Smuzhiyun 	fattr->du.nfs2.blocks = be32_to_cpup(p++);
299*4882a593Smuzhiyun 	fattr->fsid.major = be32_to_cpup(p++);
300*4882a593Smuzhiyun 	fattr->fsid.minor = 0;
301*4882a593Smuzhiyun 	fattr->fileid = be32_to_cpup(p++);
302*4882a593Smuzhiyun 
303*4882a593Smuzhiyun 	p = xdr_decode_time(p, &fattr->atime);
304*4882a593Smuzhiyun 	p = xdr_decode_time(p, &fattr->mtime);
305*4882a593Smuzhiyun 	xdr_decode_time(p, &fattr->ctime);
306*4882a593Smuzhiyun 	fattr->change_attr = nfs_timespec_to_change_attr(&fattr->ctime);
307*4882a593Smuzhiyun 
308*4882a593Smuzhiyun 	return 0;
309*4882a593Smuzhiyun out_uid:
310*4882a593Smuzhiyun 	dprintk("NFS: returned invalid uid\n");
311*4882a593Smuzhiyun 	return -EINVAL;
312*4882a593Smuzhiyun out_gid:
313*4882a593Smuzhiyun 	dprintk("NFS: returned invalid gid\n");
314*4882a593Smuzhiyun 	return -EINVAL;
315*4882a593Smuzhiyun }
316*4882a593Smuzhiyun 
317*4882a593Smuzhiyun /*
318*4882a593Smuzhiyun  * 2.3.6.  sattr
319*4882a593Smuzhiyun  *
320*4882a593Smuzhiyun  *	struct sattr {
321*4882a593Smuzhiyun  *		unsigned int	mode;
322*4882a593Smuzhiyun  *		unsigned int	uid;
323*4882a593Smuzhiyun  *		unsigned int	gid;
324*4882a593Smuzhiyun  *		unsigned int	size;
325*4882a593Smuzhiyun  *		timeval		atime;
326*4882a593Smuzhiyun  *		timeval		mtime;
327*4882a593Smuzhiyun  *	};
328*4882a593Smuzhiyun  */
329*4882a593Smuzhiyun 
330*4882a593Smuzhiyun #define NFS2_SATTR_NOT_SET	(0xffffffff)
331*4882a593Smuzhiyun 
xdr_time_not_set(__be32 * p)332*4882a593Smuzhiyun static __be32 *xdr_time_not_set(__be32 *p)
333*4882a593Smuzhiyun {
334*4882a593Smuzhiyun 	*p++ = cpu_to_be32(NFS2_SATTR_NOT_SET);
335*4882a593Smuzhiyun 	*p++ = cpu_to_be32(NFS2_SATTR_NOT_SET);
336*4882a593Smuzhiyun 	return p;
337*4882a593Smuzhiyun }
338*4882a593Smuzhiyun 
encode_sattr(struct xdr_stream * xdr,const struct iattr * attr,struct user_namespace * userns)339*4882a593Smuzhiyun static void encode_sattr(struct xdr_stream *xdr, const struct iattr *attr,
340*4882a593Smuzhiyun 		struct user_namespace *userns)
341*4882a593Smuzhiyun {
342*4882a593Smuzhiyun 	__be32 *p;
343*4882a593Smuzhiyun 
344*4882a593Smuzhiyun 	p = xdr_reserve_space(xdr, NFS_sattr_sz << 2);
345*4882a593Smuzhiyun 
346*4882a593Smuzhiyun 	if (attr->ia_valid & ATTR_MODE)
347*4882a593Smuzhiyun 		*p++ = cpu_to_be32(attr->ia_mode);
348*4882a593Smuzhiyun 	else
349*4882a593Smuzhiyun 		*p++ = cpu_to_be32(NFS2_SATTR_NOT_SET);
350*4882a593Smuzhiyun 	if (attr->ia_valid & ATTR_UID)
351*4882a593Smuzhiyun 		*p++ = cpu_to_be32(from_kuid_munged(userns, attr->ia_uid));
352*4882a593Smuzhiyun 	else
353*4882a593Smuzhiyun 		*p++ = cpu_to_be32(NFS2_SATTR_NOT_SET);
354*4882a593Smuzhiyun 	if (attr->ia_valid & ATTR_GID)
355*4882a593Smuzhiyun 		*p++ = cpu_to_be32(from_kgid_munged(userns, attr->ia_gid));
356*4882a593Smuzhiyun 	else
357*4882a593Smuzhiyun 		*p++ = cpu_to_be32(NFS2_SATTR_NOT_SET);
358*4882a593Smuzhiyun 	if (attr->ia_valid & ATTR_SIZE)
359*4882a593Smuzhiyun 		*p++ = cpu_to_be32((u32)attr->ia_size);
360*4882a593Smuzhiyun 	else
361*4882a593Smuzhiyun 		*p++ = cpu_to_be32(NFS2_SATTR_NOT_SET);
362*4882a593Smuzhiyun 
363*4882a593Smuzhiyun 	if (attr->ia_valid & ATTR_ATIME_SET)
364*4882a593Smuzhiyun 		p = xdr_encode_time(p, &attr->ia_atime);
365*4882a593Smuzhiyun 	else if (attr->ia_valid & ATTR_ATIME)
366*4882a593Smuzhiyun 		p = xdr_encode_current_server_time(p, &attr->ia_atime);
367*4882a593Smuzhiyun 	else
368*4882a593Smuzhiyun 		p = xdr_time_not_set(p);
369*4882a593Smuzhiyun 	if (attr->ia_valid & ATTR_MTIME_SET)
370*4882a593Smuzhiyun 		xdr_encode_time(p, &attr->ia_mtime);
371*4882a593Smuzhiyun 	else if (attr->ia_valid & ATTR_MTIME)
372*4882a593Smuzhiyun 		xdr_encode_current_server_time(p, &attr->ia_mtime);
373*4882a593Smuzhiyun 	else
374*4882a593Smuzhiyun 		xdr_time_not_set(p);
375*4882a593Smuzhiyun }
376*4882a593Smuzhiyun 
377*4882a593Smuzhiyun /*
378*4882a593Smuzhiyun  * 2.3.7.  filename
379*4882a593Smuzhiyun  *
380*4882a593Smuzhiyun  *	typedef string filename<MAXNAMLEN>;
381*4882a593Smuzhiyun  */
encode_filename(struct xdr_stream * xdr,const char * name,u32 length)382*4882a593Smuzhiyun static void encode_filename(struct xdr_stream *xdr,
383*4882a593Smuzhiyun 			    const char *name, u32 length)
384*4882a593Smuzhiyun {
385*4882a593Smuzhiyun 	__be32 *p;
386*4882a593Smuzhiyun 
387*4882a593Smuzhiyun 	WARN_ON_ONCE(length > NFS2_MAXNAMLEN);
388*4882a593Smuzhiyun 	p = xdr_reserve_space(xdr, 4 + length);
389*4882a593Smuzhiyun 	xdr_encode_opaque(p, name, length);
390*4882a593Smuzhiyun }
391*4882a593Smuzhiyun 
decode_filename_inline(struct xdr_stream * xdr,const char ** name,u32 * length)392*4882a593Smuzhiyun static int decode_filename_inline(struct xdr_stream *xdr,
393*4882a593Smuzhiyun 				  const char **name, u32 *length)
394*4882a593Smuzhiyun {
395*4882a593Smuzhiyun 	__be32 *p;
396*4882a593Smuzhiyun 	u32 count;
397*4882a593Smuzhiyun 
398*4882a593Smuzhiyun 	p = xdr_inline_decode(xdr, 4);
399*4882a593Smuzhiyun 	if (unlikely(!p))
400*4882a593Smuzhiyun 		return -EIO;
401*4882a593Smuzhiyun 	count = be32_to_cpup(p);
402*4882a593Smuzhiyun 	if (count > NFS3_MAXNAMLEN)
403*4882a593Smuzhiyun 		goto out_nametoolong;
404*4882a593Smuzhiyun 	p = xdr_inline_decode(xdr, count);
405*4882a593Smuzhiyun 	if (unlikely(!p))
406*4882a593Smuzhiyun 		return -EIO;
407*4882a593Smuzhiyun 	*name = (const char *)p;
408*4882a593Smuzhiyun 	*length = count;
409*4882a593Smuzhiyun 	return 0;
410*4882a593Smuzhiyun out_nametoolong:
411*4882a593Smuzhiyun 	dprintk("NFS: returned filename too long: %u\n", count);
412*4882a593Smuzhiyun 	return -ENAMETOOLONG;
413*4882a593Smuzhiyun }
414*4882a593Smuzhiyun 
415*4882a593Smuzhiyun /*
416*4882a593Smuzhiyun  * 2.3.8.  path
417*4882a593Smuzhiyun  *
418*4882a593Smuzhiyun  *	typedef string path<MAXPATHLEN>;
419*4882a593Smuzhiyun  */
encode_path(struct xdr_stream * xdr,struct page ** pages,u32 length)420*4882a593Smuzhiyun static void encode_path(struct xdr_stream *xdr, struct page **pages, u32 length)
421*4882a593Smuzhiyun {
422*4882a593Smuzhiyun 	__be32 *p;
423*4882a593Smuzhiyun 
424*4882a593Smuzhiyun 	p = xdr_reserve_space(xdr, 4);
425*4882a593Smuzhiyun 	*p = cpu_to_be32(length);
426*4882a593Smuzhiyun 	xdr_write_pages(xdr, pages, 0, length);
427*4882a593Smuzhiyun }
428*4882a593Smuzhiyun 
decode_path(struct xdr_stream * xdr)429*4882a593Smuzhiyun static int decode_path(struct xdr_stream *xdr)
430*4882a593Smuzhiyun {
431*4882a593Smuzhiyun 	u32 length, recvd;
432*4882a593Smuzhiyun 	__be32 *p;
433*4882a593Smuzhiyun 
434*4882a593Smuzhiyun 	p = xdr_inline_decode(xdr, 4);
435*4882a593Smuzhiyun 	if (unlikely(!p))
436*4882a593Smuzhiyun 		return -EIO;
437*4882a593Smuzhiyun 	length = be32_to_cpup(p);
438*4882a593Smuzhiyun 	if (unlikely(length >= xdr->buf->page_len || length > NFS_MAXPATHLEN))
439*4882a593Smuzhiyun 		goto out_size;
440*4882a593Smuzhiyun 	recvd = xdr_read_pages(xdr, length);
441*4882a593Smuzhiyun 	if (unlikely(length > recvd))
442*4882a593Smuzhiyun 		goto out_cheating;
443*4882a593Smuzhiyun 	xdr_terminate_string(xdr->buf, length);
444*4882a593Smuzhiyun 	return 0;
445*4882a593Smuzhiyun out_size:
446*4882a593Smuzhiyun 	dprintk("NFS: returned pathname too long: %u\n", length);
447*4882a593Smuzhiyun 	return -ENAMETOOLONG;
448*4882a593Smuzhiyun out_cheating:
449*4882a593Smuzhiyun 	dprintk("NFS: server cheating in pathname result: "
450*4882a593Smuzhiyun 		"length %u > received %u\n", length, recvd);
451*4882a593Smuzhiyun 	return -EIO;
452*4882a593Smuzhiyun }
453*4882a593Smuzhiyun 
454*4882a593Smuzhiyun /*
455*4882a593Smuzhiyun  * 2.3.9.  attrstat
456*4882a593Smuzhiyun  *
457*4882a593Smuzhiyun  *	union attrstat switch (stat status) {
458*4882a593Smuzhiyun  *	case NFS_OK:
459*4882a593Smuzhiyun  *		fattr attributes;
460*4882a593Smuzhiyun  *	default:
461*4882a593Smuzhiyun  *		void;
462*4882a593Smuzhiyun  *	};
463*4882a593Smuzhiyun  */
decode_attrstat(struct xdr_stream * xdr,struct nfs_fattr * result,__u32 * op_status,struct user_namespace * userns)464*4882a593Smuzhiyun static int decode_attrstat(struct xdr_stream *xdr, struct nfs_fattr *result,
465*4882a593Smuzhiyun 			   __u32 *op_status,
466*4882a593Smuzhiyun 			   struct user_namespace *userns)
467*4882a593Smuzhiyun {
468*4882a593Smuzhiyun 	enum nfs_stat status;
469*4882a593Smuzhiyun 	int error;
470*4882a593Smuzhiyun 
471*4882a593Smuzhiyun 	error = decode_stat(xdr, &status);
472*4882a593Smuzhiyun 	if (unlikely(error))
473*4882a593Smuzhiyun 		goto out;
474*4882a593Smuzhiyun 	if (op_status)
475*4882a593Smuzhiyun 		*op_status = status;
476*4882a593Smuzhiyun 	if (status != NFS_OK)
477*4882a593Smuzhiyun 		goto out_default;
478*4882a593Smuzhiyun 	error = decode_fattr(xdr, result, userns);
479*4882a593Smuzhiyun out:
480*4882a593Smuzhiyun 	return error;
481*4882a593Smuzhiyun out_default:
482*4882a593Smuzhiyun 	return nfs_stat_to_errno(status);
483*4882a593Smuzhiyun }
484*4882a593Smuzhiyun 
485*4882a593Smuzhiyun /*
486*4882a593Smuzhiyun  * 2.3.10.  diropargs
487*4882a593Smuzhiyun  *
488*4882a593Smuzhiyun  *	struct diropargs {
489*4882a593Smuzhiyun  *		fhandle  dir;
490*4882a593Smuzhiyun  *		filename name;
491*4882a593Smuzhiyun  *	};
492*4882a593Smuzhiyun  */
encode_diropargs(struct xdr_stream * xdr,const struct nfs_fh * fh,const char * name,u32 length)493*4882a593Smuzhiyun static void encode_diropargs(struct xdr_stream *xdr, const struct nfs_fh *fh,
494*4882a593Smuzhiyun 			     const char *name, u32 length)
495*4882a593Smuzhiyun {
496*4882a593Smuzhiyun 	encode_fhandle(xdr, fh);
497*4882a593Smuzhiyun 	encode_filename(xdr, name, length);
498*4882a593Smuzhiyun }
499*4882a593Smuzhiyun 
500*4882a593Smuzhiyun /*
501*4882a593Smuzhiyun  * 2.3.11.  diropres
502*4882a593Smuzhiyun  *
503*4882a593Smuzhiyun  *	union diropres switch (stat status) {
504*4882a593Smuzhiyun  *	case NFS_OK:
505*4882a593Smuzhiyun  *		struct {
506*4882a593Smuzhiyun  *			fhandle file;
507*4882a593Smuzhiyun  *			fattr   attributes;
508*4882a593Smuzhiyun  *		} diropok;
509*4882a593Smuzhiyun  *	default:
510*4882a593Smuzhiyun  *		void;
511*4882a593Smuzhiyun  *	};
512*4882a593Smuzhiyun  */
decode_diropok(struct xdr_stream * xdr,struct nfs_diropok * result,struct user_namespace * userns)513*4882a593Smuzhiyun static int decode_diropok(struct xdr_stream *xdr, struct nfs_diropok *result,
514*4882a593Smuzhiyun 		struct user_namespace *userns)
515*4882a593Smuzhiyun {
516*4882a593Smuzhiyun 	int error;
517*4882a593Smuzhiyun 
518*4882a593Smuzhiyun 	error = decode_fhandle(xdr, result->fh);
519*4882a593Smuzhiyun 	if (unlikely(error))
520*4882a593Smuzhiyun 		goto out;
521*4882a593Smuzhiyun 	error = decode_fattr(xdr, result->fattr, userns);
522*4882a593Smuzhiyun out:
523*4882a593Smuzhiyun 	return error;
524*4882a593Smuzhiyun }
525*4882a593Smuzhiyun 
decode_diropres(struct xdr_stream * xdr,struct nfs_diropok * result,struct user_namespace * userns)526*4882a593Smuzhiyun static int decode_diropres(struct xdr_stream *xdr, struct nfs_diropok *result,
527*4882a593Smuzhiyun 		struct user_namespace *userns)
528*4882a593Smuzhiyun {
529*4882a593Smuzhiyun 	enum nfs_stat status;
530*4882a593Smuzhiyun 	int error;
531*4882a593Smuzhiyun 
532*4882a593Smuzhiyun 	error = decode_stat(xdr, &status);
533*4882a593Smuzhiyun 	if (unlikely(error))
534*4882a593Smuzhiyun 		goto out;
535*4882a593Smuzhiyun 	if (status != NFS_OK)
536*4882a593Smuzhiyun 		goto out_default;
537*4882a593Smuzhiyun 	error = decode_diropok(xdr, result, userns);
538*4882a593Smuzhiyun out:
539*4882a593Smuzhiyun 	return error;
540*4882a593Smuzhiyun out_default:
541*4882a593Smuzhiyun 	return nfs_stat_to_errno(status);
542*4882a593Smuzhiyun }
543*4882a593Smuzhiyun 
544*4882a593Smuzhiyun 
545*4882a593Smuzhiyun /*
546*4882a593Smuzhiyun  * NFSv2 XDR encode functions
547*4882a593Smuzhiyun  *
548*4882a593Smuzhiyun  * NFSv2 argument types are defined in section 2.2 of RFC 1094:
549*4882a593Smuzhiyun  * "NFS: Network File System Protocol Specification".
550*4882a593Smuzhiyun  */
551*4882a593Smuzhiyun 
nfs2_xdr_enc_fhandle(struct rpc_rqst * req,struct xdr_stream * xdr,const void * data)552*4882a593Smuzhiyun static void nfs2_xdr_enc_fhandle(struct rpc_rqst *req,
553*4882a593Smuzhiyun 				 struct xdr_stream *xdr,
554*4882a593Smuzhiyun 				 const void *data)
555*4882a593Smuzhiyun {
556*4882a593Smuzhiyun 	const struct nfs_fh *fh = data;
557*4882a593Smuzhiyun 
558*4882a593Smuzhiyun 	encode_fhandle(xdr, fh);
559*4882a593Smuzhiyun }
560*4882a593Smuzhiyun 
561*4882a593Smuzhiyun /*
562*4882a593Smuzhiyun  * 2.2.3.  sattrargs
563*4882a593Smuzhiyun  *
564*4882a593Smuzhiyun  *	struct sattrargs {
565*4882a593Smuzhiyun  *		fhandle file;
566*4882a593Smuzhiyun  *		sattr attributes;
567*4882a593Smuzhiyun  *	};
568*4882a593Smuzhiyun  */
nfs2_xdr_enc_sattrargs(struct rpc_rqst * req,struct xdr_stream * xdr,const void * data)569*4882a593Smuzhiyun static void nfs2_xdr_enc_sattrargs(struct rpc_rqst *req,
570*4882a593Smuzhiyun 				   struct xdr_stream *xdr,
571*4882a593Smuzhiyun 				   const void *data)
572*4882a593Smuzhiyun {
573*4882a593Smuzhiyun 	const struct nfs_sattrargs *args = data;
574*4882a593Smuzhiyun 
575*4882a593Smuzhiyun 	encode_fhandle(xdr, args->fh);
576*4882a593Smuzhiyun 	encode_sattr(xdr, args->sattr, rpc_rqst_userns(req));
577*4882a593Smuzhiyun }
578*4882a593Smuzhiyun 
nfs2_xdr_enc_diropargs(struct rpc_rqst * req,struct xdr_stream * xdr,const void * data)579*4882a593Smuzhiyun static void nfs2_xdr_enc_diropargs(struct rpc_rqst *req,
580*4882a593Smuzhiyun 				   struct xdr_stream *xdr,
581*4882a593Smuzhiyun 				   const void *data)
582*4882a593Smuzhiyun {
583*4882a593Smuzhiyun 	const struct nfs_diropargs *args = data;
584*4882a593Smuzhiyun 
585*4882a593Smuzhiyun 	encode_diropargs(xdr, args->fh, args->name, args->len);
586*4882a593Smuzhiyun }
587*4882a593Smuzhiyun 
nfs2_xdr_enc_readlinkargs(struct rpc_rqst * req,struct xdr_stream * xdr,const void * data)588*4882a593Smuzhiyun static void nfs2_xdr_enc_readlinkargs(struct rpc_rqst *req,
589*4882a593Smuzhiyun 				      struct xdr_stream *xdr,
590*4882a593Smuzhiyun 				      const void *data)
591*4882a593Smuzhiyun {
592*4882a593Smuzhiyun 	const struct nfs_readlinkargs *args = data;
593*4882a593Smuzhiyun 
594*4882a593Smuzhiyun 	encode_fhandle(xdr, args->fh);
595*4882a593Smuzhiyun 	rpc_prepare_reply_pages(req, args->pages, args->pgbase,
596*4882a593Smuzhiyun 				args->pglen, NFS_readlinkres_sz);
597*4882a593Smuzhiyun }
598*4882a593Smuzhiyun 
599*4882a593Smuzhiyun /*
600*4882a593Smuzhiyun  * 2.2.7.  readargs
601*4882a593Smuzhiyun  *
602*4882a593Smuzhiyun  *	struct readargs {
603*4882a593Smuzhiyun  *		fhandle file;
604*4882a593Smuzhiyun  *		unsigned offset;
605*4882a593Smuzhiyun  *		unsigned count;
606*4882a593Smuzhiyun  *		unsigned totalcount;
607*4882a593Smuzhiyun  *	};
608*4882a593Smuzhiyun  */
encode_readargs(struct xdr_stream * xdr,const struct nfs_pgio_args * args)609*4882a593Smuzhiyun static void encode_readargs(struct xdr_stream *xdr,
610*4882a593Smuzhiyun 			    const struct nfs_pgio_args *args)
611*4882a593Smuzhiyun {
612*4882a593Smuzhiyun 	u32 offset = args->offset;
613*4882a593Smuzhiyun 	u32 count = args->count;
614*4882a593Smuzhiyun 	__be32 *p;
615*4882a593Smuzhiyun 
616*4882a593Smuzhiyun 	encode_fhandle(xdr, args->fh);
617*4882a593Smuzhiyun 
618*4882a593Smuzhiyun 	p = xdr_reserve_space(xdr, 4 + 4 + 4);
619*4882a593Smuzhiyun 	*p++ = cpu_to_be32(offset);
620*4882a593Smuzhiyun 	*p++ = cpu_to_be32(count);
621*4882a593Smuzhiyun 	*p = cpu_to_be32(count);
622*4882a593Smuzhiyun }
623*4882a593Smuzhiyun 
nfs2_xdr_enc_readargs(struct rpc_rqst * req,struct xdr_stream * xdr,const void * data)624*4882a593Smuzhiyun static void nfs2_xdr_enc_readargs(struct rpc_rqst *req,
625*4882a593Smuzhiyun 				  struct xdr_stream *xdr,
626*4882a593Smuzhiyun 				  const void *data)
627*4882a593Smuzhiyun {
628*4882a593Smuzhiyun 	const struct nfs_pgio_args *args = data;
629*4882a593Smuzhiyun 
630*4882a593Smuzhiyun 	encode_readargs(xdr, args);
631*4882a593Smuzhiyun 	rpc_prepare_reply_pages(req, args->pages, args->pgbase,
632*4882a593Smuzhiyun 				args->count, NFS_readres_sz);
633*4882a593Smuzhiyun 	req->rq_rcv_buf.flags |= XDRBUF_READ;
634*4882a593Smuzhiyun }
635*4882a593Smuzhiyun 
636*4882a593Smuzhiyun /*
637*4882a593Smuzhiyun  * 2.2.9.  writeargs
638*4882a593Smuzhiyun  *
639*4882a593Smuzhiyun  *	struct writeargs {
640*4882a593Smuzhiyun  *		fhandle file;
641*4882a593Smuzhiyun  *		unsigned beginoffset;
642*4882a593Smuzhiyun  *		unsigned offset;
643*4882a593Smuzhiyun  *		unsigned totalcount;
644*4882a593Smuzhiyun  *		nfsdata data;
645*4882a593Smuzhiyun  *	};
646*4882a593Smuzhiyun  */
encode_writeargs(struct xdr_stream * xdr,const struct nfs_pgio_args * args)647*4882a593Smuzhiyun static void encode_writeargs(struct xdr_stream *xdr,
648*4882a593Smuzhiyun 			     const struct nfs_pgio_args *args)
649*4882a593Smuzhiyun {
650*4882a593Smuzhiyun 	u32 offset = args->offset;
651*4882a593Smuzhiyun 	u32 count = args->count;
652*4882a593Smuzhiyun 	__be32 *p;
653*4882a593Smuzhiyun 
654*4882a593Smuzhiyun 	encode_fhandle(xdr, args->fh);
655*4882a593Smuzhiyun 
656*4882a593Smuzhiyun 	p = xdr_reserve_space(xdr, 4 + 4 + 4 + 4);
657*4882a593Smuzhiyun 	*p++ = cpu_to_be32(offset);
658*4882a593Smuzhiyun 	*p++ = cpu_to_be32(offset);
659*4882a593Smuzhiyun 	*p++ = cpu_to_be32(count);
660*4882a593Smuzhiyun 
661*4882a593Smuzhiyun 	/* nfsdata */
662*4882a593Smuzhiyun 	*p = cpu_to_be32(count);
663*4882a593Smuzhiyun 	xdr_write_pages(xdr, args->pages, args->pgbase, count);
664*4882a593Smuzhiyun }
665*4882a593Smuzhiyun 
nfs2_xdr_enc_writeargs(struct rpc_rqst * req,struct xdr_stream * xdr,const void * data)666*4882a593Smuzhiyun static void nfs2_xdr_enc_writeargs(struct rpc_rqst *req,
667*4882a593Smuzhiyun 				   struct xdr_stream *xdr,
668*4882a593Smuzhiyun 				   const void *data)
669*4882a593Smuzhiyun {
670*4882a593Smuzhiyun 	const struct nfs_pgio_args *args = data;
671*4882a593Smuzhiyun 
672*4882a593Smuzhiyun 	encode_writeargs(xdr, args);
673*4882a593Smuzhiyun 	xdr->buf->flags |= XDRBUF_WRITE;
674*4882a593Smuzhiyun }
675*4882a593Smuzhiyun 
676*4882a593Smuzhiyun /*
677*4882a593Smuzhiyun  * 2.2.10.  createargs
678*4882a593Smuzhiyun  *
679*4882a593Smuzhiyun  *	struct createargs {
680*4882a593Smuzhiyun  *		diropargs where;
681*4882a593Smuzhiyun  *		sattr attributes;
682*4882a593Smuzhiyun  *	};
683*4882a593Smuzhiyun  */
nfs2_xdr_enc_createargs(struct rpc_rqst * req,struct xdr_stream * xdr,const void * data)684*4882a593Smuzhiyun static void nfs2_xdr_enc_createargs(struct rpc_rqst *req,
685*4882a593Smuzhiyun 				    struct xdr_stream *xdr,
686*4882a593Smuzhiyun 				    const void *data)
687*4882a593Smuzhiyun {
688*4882a593Smuzhiyun 	const struct nfs_createargs *args = data;
689*4882a593Smuzhiyun 
690*4882a593Smuzhiyun 	encode_diropargs(xdr, args->fh, args->name, args->len);
691*4882a593Smuzhiyun 	encode_sattr(xdr, args->sattr, rpc_rqst_userns(req));
692*4882a593Smuzhiyun }
693*4882a593Smuzhiyun 
nfs2_xdr_enc_removeargs(struct rpc_rqst * req,struct xdr_stream * xdr,const void * data)694*4882a593Smuzhiyun static void nfs2_xdr_enc_removeargs(struct rpc_rqst *req,
695*4882a593Smuzhiyun 				    struct xdr_stream *xdr,
696*4882a593Smuzhiyun 				    const void *data)
697*4882a593Smuzhiyun {
698*4882a593Smuzhiyun 	const struct nfs_removeargs *args = data;
699*4882a593Smuzhiyun 
700*4882a593Smuzhiyun 	encode_diropargs(xdr, args->fh, args->name.name, args->name.len);
701*4882a593Smuzhiyun }
702*4882a593Smuzhiyun 
703*4882a593Smuzhiyun /*
704*4882a593Smuzhiyun  * 2.2.12.  renameargs
705*4882a593Smuzhiyun  *
706*4882a593Smuzhiyun  *	struct renameargs {
707*4882a593Smuzhiyun  *		diropargs from;
708*4882a593Smuzhiyun  *		diropargs to;
709*4882a593Smuzhiyun  *	};
710*4882a593Smuzhiyun  */
nfs2_xdr_enc_renameargs(struct rpc_rqst * req,struct xdr_stream * xdr,const void * data)711*4882a593Smuzhiyun static void nfs2_xdr_enc_renameargs(struct rpc_rqst *req,
712*4882a593Smuzhiyun 				    struct xdr_stream *xdr,
713*4882a593Smuzhiyun 				    const void *data)
714*4882a593Smuzhiyun {
715*4882a593Smuzhiyun 	const struct nfs_renameargs *args = data;
716*4882a593Smuzhiyun 	const struct qstr *old = args->old_name;
717*4882a593Smuzhiyun 	const struct qstr *new = args->new_name;
718*4882a593Smuzhiyun 
719*4882a593Smuzhiyun 	encode_diropargs(xdr, args->old_dir, old->name, old->len);
720*4882a593Smuzhiyun 	encode_diropargs(xdr, args->new_dir, new->name, new->len);
721*4882a593Smuzhiyun }
722*4882a593Smuzhiyun 
723*4882a593Smuzhiyun /*
724*4882a593Smuzhiyun  * 2.2.13.  linkargs
725*4882a593Smuzhiyun  *
726*4882a593Smuzhiyun  *	struct linkargs {
727*4882a593Smuzhiyun  *		fhandle from;
728*4882a593Smuzhiyun  *		diropargs to;
729*4882a593Smuzhiyun  *	};
730*4882a593Smuzhiyun  */
nfs2_xdr_enc_linkargs(struct rpc_rqst * req,struct xdr_stream * xdr,const void * data)731*4882a593Smuzhiyun static void nfs2_xdr_enc_linkargs(struct rpc_rqst *req,
732*4882a593Smuzhiyun 				  struct xdr_stream *xdr,
733*4882a593Smuzhiyun 				  const void *data)
734*4882a593Smuzhiyun {
735*4882a593Smuzhiyun 	const struct nfs_linkargs *args = data;
736*4882a593Smuzhiyun 
737*4882a593Smuzhiyun 	encode_fhandle(xdr, args->fromfh);
738*4882a593Smuzhiyun 	encode_diropargs(xdr, args->tofh, args->toname, args->tolen);
739*4882a593Smuzhiyun }
740*4882a593Smuzhiyun 
741*4882a593Smuzhiyun /*
742*4882a593Smuzhiyun  * 2.2.14.  symlinkargs
743*4882a593Smuzhiyun  *
744*4882a593Smuzhiyun  *	struct symlinkargs {
745*4882a593Smuzhiyun  *		diropargs from;
746*4882a593Smuzhiyun  *		path to;
747*4882a593Smuzhiyun  *		sattr attributes;
748*4882a593Smuzhiyun  *	};
749*4882a593Smuzhiyun  */
nfs2_xdr_enc_symlinkargs(struct rpc_rqst * req,struct xdr_stream * xdr,const void * data)750*4882a593Smuzhiyun static void nfs2_xdr_enc_symlinkargs(struct rpc_rqst *req,
751*4882a593Smuzhiyun 				     struct xdr_stream *xdr,
752*4882a593Smuzhiyun 				     const void *data)
753*4882a593Smuzhiyun {
754*4882a593Smuzhiyun 	const struct nfs_symlinkargs *args = data;
755*4882a593Smuzhiyun 
756*4882a593Smuzhiyun 	encode_diropargs(xdr, args->fromfh, args->fromname, args->fromlen);
757*4882a593Smuzhiyun 	encode_path(xdr, args->pages, args->pathlen);
758*4882a593Smuzhiyun 	encode_sattr(xdr, args->sattr, rpc_rqst_userns(req));
759*4882a593Smuzhiyun }
760*4882a593Smuzhiyun 
761*4882a593Smuzhiyun /*
762*4882a593Smuzhiyun  * 2.2.17.  readdirargs
763*4882a593Smuzhiyun  *
764*4882a593Smuzhiyun  *	struct readdirargs {
765*4882a593Smuzhiyun  *		fhandle dir;
766*4882a593Smuzhiyun  *		nfscookie cookie;
767*4882a593Smuzhiyun  *		unsigned count;
768*4882a593Smuzhiyun  *	};
769*4882a593Smuzhiyun  */
encode_readdirargs(struct xdr_stream * xdr,const struct nfs_readdirargs * args)770*4882a593Smuzhiyun static void encode_readdirargs(struct xdr_stream *xdr,
771*4882a593Smuzhiyun 			       const struct nfs_readdirargs *args)
772*4882a593Smuzhiyun {
773*4882a593Smuzhiyun 	__be32 *p;
774*4882a593Smuzhiyun 
775*4882a593Smuzhiyun 	encode_fhandle(xdr, args->fh);
776*4882a593Smuzhiyun 
777*4882a593Smuzhiyun 	p = xdr_reserve_space(xdr, 4 + 4);
778*4882a593Smuzhiyun 	*p++ = cpu_to_be32(args->cookie);
779*4882a593Smuzhiyun 	*p = cpu_to_be32(args->count);
780*4882a593Smuzhiyun }
781*4882a593Smuzhiyun 
nfs2_xdr_enc_readdirargs(struct rpc_rqst * req,struct xdr_stream * xdr,const void * data)782*4882a593Smuzhiyun static void nfs2_xdr_enc_readdirargs(struct rpc_rqst *req,
783*4882a593Smuzhiyun 				     struct xdr_stream *xdr,
784*4882a593Smuzhiyun 				     const void *data)
785*4882a593Smuzhiyun {
786*4882a593Smuzhiyun 	const struct nfs_readdirargs *args = data;
787*4882a593Smuzhiyun 
788*4882a593Smuzhiyun 	encode_readdirargs(xdr, args);
789*4882a593Smuzhiyun 	rpc_prepare_reply_pages(req, args->pages, 0,
790*4882a593Smuzhiyun 				args->count, NFS_readdirres_sz);
791*4882a593Smuzhiyun }
792*4882a593Smuzhiyun 
793*4882a593Smuzhiyun /*
794*4882a593Smuzhiyun  * NFSv2 XDR decode functions
795*4882a593Smuzhiyun  *
796*4882a593Smuzhiyun  * NFSv2 result types are defined in section 2.2 of RFC 1094:
797*4882a593Smuzhiyun  * "NFS: Network File System Protocol Specification".
798*4882a593Smuzhiyun  */
799*4882a593Smuzhiyun 
nfs2_xdr_dec_stat(struct rpc_rqst * req,struct xdr_stream * xdr,void * __unused)800*4882a593Smuzhiyun static int nfs2_xdr_dec_stat(struct rpc_rqst *req, struct xdr_stream *xdr,
801*4882a593Smuzhiyun 			     void *__unused)
802*4882a593Smuzhiyun {
803*4882a593Smuzhiyun 	enum nfs_stat status;
804*4882a593Smuzhiyun 	int error;
805*4882a593Smuzhiyun 
806*4882a593Smuzhiyun 	error = decode_stat(xdr, &status);
807*4882a593Smuzhiyun 	if (unlikely(error))
808*4882a593Smuzhiyun 		goto out;
809*4882a593Smuzhiyun 	if (status != NFS_OK)
810*4882a593Smuzhiyun 		goto out_default;
811*4882a593Smuzhiyun out:
812*4882a593Smuzhiyun 	return error;
813*4882a593Smuzhiyun out_default:
814*4882a593Smuzhiyun 	return nfs_stat_to_errno(status);
815*4882a593Smuzhiyun }
816*4882a593Smuzhiyun 
nfs2_xdr_dec_attrstat(struct rpc_rqst * req,struct xdr_stream * xdr,void * result)817*4882a593Smuzhiyun static int nfs2_xdr_dec_attrstat(struct rpc_rqst *req, struct xdr_stream *xdr,
818*4882a593Smuzhiyun 				 void *result)
819*4882a593Smuzhiyun {
820*4882a593Smuzhiyun 	return decode_attrstat(xdr, result, NULL, rpc_rqst_userns(req));
821*4882a593Smuzhiyun }
822*4882a593Smuzhiyun 
nfs2_xdr_dec_diropres(struct rpc_rqst * req,struct xdr_stream * xdr,void * result)823*4882a593Smuzhiyun static int nfs2_xdr_dec_diropres(struct rpc_rqst *req, struct xdr_stream *xdr,
824*4882a593Smuzhiyun 				 void *result)
825*4882a593Smuzhiyun {
826*4882a593Smuzhiyun 	return decode_diropres(xdr, result, rpc_rqst_userns(req));
827*4882a593Smuzhiyun }
828*4882a593Smuzhiyun 
829*4882a593Smuzhiyun /*
830*4882a593Smuzhiyun  * 2.2.6.  readlinkres
831*4882a593Smuzhiyun  *
832*4882a593Smuzhiyun  *	union readlinkres switch (stat status) {
833*4882a593Smuzhiyun  *	case NFS_OK:
834*4882a593Smuzhiyun  *		path data;
835*4882a593Smuzhiyun  *	default:
836*4882a593Smuzhiyun  *		void;
837*4882a593Smuzhiyun  *	};
838*4882a593Smuzhiyun  */
nfs2_xdr_dec_readlinkres(struct rpc_rqst * req,struct xdr_stream * xdr,void * __unused)839*4882a593Smuzhiyun static int nfs2_xdr_dec_readlinkres(struct rpc_rqst *req,
840*4882a593Smuzhiyun 				    struct xdr_stream *xdr, void *__unused)
841*4882a593Smuzhiyun {
842*4882a593Smuzhiyun 	enum nfs_stat status;
843*4882a593Smuzhiyun 	int error;
844*4882a593Smuzhiyun 
845*4882a593Smuzhiyun 	error = decode_stat(xdr, &status);
846*4882a593Smuzhiyun 	if (unlikely(error))
847*4882a593Smuzhiyun 		goto out;
848*4882a593Smuzhiyun 	if (status != NFS_OK)
849*4882a593Smuzhiyun 		goto out_default;
850*4882a593Smuzhiyun 	error = decode_path(xdr);
851*4882a593Smuzhiyun out:
852*4882a593Smuzhiyun 	return error;
853*4882a593Smuzhiyun out_default:
854*4882a593Smuzhiyun 	return nfs_stat_to_errno(status);
855*4882a593Smuzhiyun }
856*4882a593Smuzhiyun 
857*4882a593Smuzhiyun /*
858*4882a593Smuzhiyun  * 2.2.7.  readres
859*4882a593Smuzhiyun  *
860*4882a593Smuzhiyun  *	union readres switch (stat status) {
861*4882a593Smuzhiyun  *	case NFS_OK:
862*4882a593Smuzhiyun  *		fattr attributes;
863*4882a593Smuzhiyun  *		nfsdata data;
864*4882a593Smuzhiyun  *	default:
865*4882a593Smuzhiyun  *		void;
866*4882a593Smuzhiyun  *	};
867*4882a593Smuzhiyun  */
nfs2_xdr_dec_readres(struct rpc_rqst * req,struct xdr_stream * xdr,void * data)868*4882a593Smuzhiyun static int nfs2_xdr_dec_readres(struct rpc_rqst *req, struct xdr_stream *xdr,
869*4882a593Smuzhiyun 				void *data)
870*4882a593Smuzhiyun {
871*4882a593Smuzhiyun 	struct nfs_pgio_res *result = data;
872*4882a593Smuzhiyun 	enum nfs_stat status;
873*4882a593Smuzhiyun 	int error;
874*4882a593Smuzhiyun 
875*4882a593Smuzhiyun 	error = decode_stat(xdr, &status);
876*4882a593Smuzhiyun 	if (unlikely(error))
877*4882a593Smuzhiyun 		goto out;
878*4882a593Smuzhiyun 	result->op_status = status;
879*4882a593Smuzhiyun 	if (status != NFS_OK)
880*4882a593Smuzhiyun 		goto out_default;
881*4882a593Smuzhiyun 	error = decode_fattr(xdr, result->fattr, rpc_rqst_userns(req));
882*4882a593Smuzhiyun 	if (unlikely(error))
883*4882a593Smuzhiyun 		goto out;
884*4882a593Smuzhiyun 	error = decode_nfsdata(xdr, result);
885*4882a593Smuzhiyun out:
886*4882a593Smuzhiyun 	return error;
887*4882a593Smuzhiyun out_default:
888*4882a593Smuzhiyun 	return nfs_stat_to_errno(status);
889*4882a593Smuzhiyun }
890*4882a593Smuzhiyun 
nfs2_xdr_dec_writeres(struct rpc_rqst * req,struct xdr_stream * xdr,void * data)891*4882a593Smuzhiyun static int nfs2_xdr_dec_writeres(struct rpc_rqst *req, struct xdr_stream *xdr,
892*4882a593Smuzhiyun 				 void *data)
893*4882a593Smuzhiyun {
894*4882a593Smuzhiyun 	struct nfs_pgio_res *result = data;
895*4882a593Smuzhiyun 
896*4882a593Smuzhiyun 	/* All NFSv2 writes are "file sync" writes */
897*4882a593Smuzhiyun 	result->verf->committed = NFS_FILE_SYNC;
898*4882a593Smuzhiyun 	return decode_attrstat(xdr, result->fattr, &result->op_status,
899*4882a593Smuzhiyun 			rpc_rqst_userns(req));
900*4882a593Smuzhiyun }
901*4882a593Smuzhiyun 
902*4882a593Smuzhiyun /**
903*4882a593Smuzhiyun  * nfs2_decode_dirent - Decode a single NFSv2 directory entry stored in
904*4882a593Smuzhiyun  *                      the local page cache.
905*4882a593Smuzhiyun  * @xdr: XDR stream where entry resides
906*4882a593Smuzhiyun  * @entry: buffer to fill in with entry data
907*4882a593Smuzhiyun  * @plus: boolean indicating whether this should be a readdirplus entry
908*4882a593Smuzhiyun  *
909*4882a593Smuzhiyun  * Returns zero if successful, otherwise a negative errno value is
910*4882a593Smuzhiyun  * returned.
911*4882a593Smuzhiyun  *
912*4882a593Smuzhiyun  * This function is not invoked during READDIR reply decoding, but
913*4882a593Smuzhiyun  * rather whenever an application invokes the getdents(2) system call
914*4882a593Smuzhiyun  * on a directory already in our cache.
915*4882a593Smuzhiyun  *
916*4882a593Smuzhiyun  * 2.2.17.  entry
917*4882a593Smuzhiyun  *
918*4882a593Smuzhiyun  *	struct entry {
919*4882a593Smuzhiyun  *		unsigned	fileid;
920*4882a593Smuzhiyun  *		filename	name;
921*4882a593Smuzhiyun  *		nfscookie	cookie;
922*4882a593Smuzhiyun  *		entry		*nextentry;
923*4882a593Smuzhiyun  *	};
924*4882a593Smuzhiyun  */
nfs2_decode_dirent(struct xdr_stream * xdr,struct nfs_entry * entry,bool plus)925*4882a593Smuzhiyun int nfs2_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry,
926*4882a593Smuzhiyun 		       bool plus)
927*4882a593Smuzhiyun {
928*4882a593Smuzhiyun 	__be32 *p;
929*4882a593Smuzhiyun 	int error;
930*4882a593Smuzhiyun 
931*4882a593Smuzhiyun 	p = xdr_inline_decode(xdr, 4);
932*4882a593Smuzhiyun 	if (unlikely(!p))
933*4882a593Smuzhiyun 		return -EAGAIN;
934*4882a593Smuzhiyun 	if (*p++ == xdr_zero) {
935*4882a593Smuzhiyun 		p = xdr_inline_decode(xdr, 4);
936*4882a593Smuzhiyun 		if (unlikely(!p))
937*4882a593Smuzhiyun 			return -EAGAIN;
938*4882a593Smuzhiyun 		if (*p++ == xdr_zero)
939*4882a593Smuzhiyun 			return -EAGAIN;
940*4882a593Smuzhiyun 		entry->eof = 1;
941*4882a593Smuzhiyun 		return -EBADCOOKIE;
942*4882a593Smuzhiyun 	}
943*4882a593Smuzhiyun 
944*4882a593Smuzhiyun 	p = xdr_inline_decode(xdr, 4);
945*4882a593Smuzhiyun 	if (unlikely(!p))
946*4882a593Smuzhiyun 		return -EAGAIN;
947*4882a593Smuzhiyun 	entry->ino = be32_to_cpup(p);
948*4882a593Smuzhiyun 
949*4882a593Smuzhiyun 	error = decode_filename_inline(xdr, &entry->name, &entry->len);
950*4882a593Smuzhiyun 	if (unlikely(error))
951*4882a593Smuzhiyun 		return -EAGAIN;
952*4882a593Smuzhiyun 
953*4882a593Smuzhiyun 	/*
954*4882a593Smuzhiyun 	 * The type (size and byte order) of nfscookie isn't defined in
955*4882a593Smuzhiyun 	 * RFC 1094.  This implementation assumes that it's an XDR uint32.
956*4882a593Smuzhiyun 	 */
957*4882a593Smuzhiyun 	entry->prev_cookie = entry->cookie;
958*4882a593Smuzhiyun 	p = xdr_inline_decode(xdr, 4);
959*4882a593Smuzhiyun 	if (unlikely(!p))
960*4882a593Smuzhiyun 		return -EAGAIN;
961*4882a593Smuzhiyun 	entry->cookie = be32_to_cpup(p);
962*4882a593Smuzhiyun 
963*4882a593Smuzhiyun 	entry->d_type = DT_UNKNOWN;
964*4882a593Smuzhiyun 
965*4882a593Smuzhiyun 	return 0;
966*4882a593Smuzhiyun }
967*4882a593Smuzhiyun 
968*4882a593Smuzhiyun /*
969*4882a593Smuzhiyun  * 2.2.17.  readdirres
970*4882a593Smuzhiyun  *
971*4882a593Smuzhiyun  *	union readdirres switch (stat status) {
972*4882a593Smuzhiyun  *	case NFS_OK:
973*4882a593Smuzhiyun  *		struct {
974*4882a593Smuzhiyun  *			entry *entries;
975*4882a593Smuzhiyun  *			bool eof;
976*4882a593Smuzhiyun  *		} readdirok;
977*4882a593Smuzhiyun  *	default:
978*4882a593Smuzhiyun  *		void;
979*4882a593Smuzhiyun  *	};
980*4882a593Smuzhiyun  *
981*4882a593Smuzhiyun  * Read the directory contents into the page cache, but don't
982*4882a593Smuzhiyun  * touch them.  The actual decoding is done by nfs2_decode_dirent()
983*4882a593Smuzhiyun  * during subsequent nfs_readdir() calls.
984*4882a593Smuzhiyun  */
decode_readdirok(struct xdr_stream * xdr)985*4882a593Smuzhiyun static int decode_readdirok(struct xdr_stream *xdr)
986*4882a593Smuzhiyun {
987*4882a593Smuzhiyun 	return xdr_read_pages(xdr, xdr->buf->page_len);
988*4882a593Smuzhiyun }
989*4882a593Smuzhiyun 
nfs2_xdr_dec_readdirres(struct rpc_rqst * req,struct xdr_stream * xdr,void * __unused)990*4882a593Smuzhiyun static int nfs2_xdr_dec_readdirres(struct rpc_rqst *req,
991*4882a593Smuzhiyun 				   struct xdr_stream *xdr, void *__unused)
992*4882a593Smuzhiyun {
993*4882a593Smuzhiyun 	enum nfs_stat status;
994*4882a593Smuzhiyun 	int error;
995*4882a593Smuzhiyun 
996*4882a593Smuzhiyun 	error = decode_stat(xdr, &status);
997*4882a593Smuzhiyun 	if (unlikely(error))
998*4882a593Smuzhiyun 		goto out;
999*4882a593Smuzhiyun 	if (status != NFS_OK)
1000*4882a593Smuzhiyun 		goto out_default;
1001*4882a593Smuzhiyun 	error = decode_readdirok(xdr);
1002*4882a593Smuzhiyun out:
1003*4882a593Smuzhiyun 	return error;
1004*4882a593Smuzhiyun out_default:
1005*4882a593Smuzhiyun 	return nfs_stat_to_errno(status);
1006*4882a593Smuzhiyun }
1007*4882a593Smuzhiyun 
1008*4882a593Smuzhiyun /*
1009*4882a593Smuzhiyun  * 2.2.18.  statfsres
1010*4882a593Smuzhiyun  *
1011*4882a593Smuzhiyun  *	union statfsres (stat status) {
1012*4882a593Smuzhiyun  *	case NFS_OK:
1013*4882a593Smuzhiyun  *		struct {
1014*4882a593Smuzhiyun  *			unsigned tsize;
1015*4882a593Smuzhiyun  *			unsigned bsize;
1016*4882a593Smuzhiyun  *			unsigned blocks;
1017*4882a593Smuzhiyun  *			unsigned bfree;
1018*4882a593Smuzhiyun  *			unsigned bavail;
1019*4882a593Smuzhiyun  *		} info;
1020*4882a593Smuzhiyun  *	default:
1021*4882a593Smuzhiyun  *		void;
1022*4882a593Smuzhiyun  *	};
1023*4882a593Smuzhiyun  */
decode_info(struct xdr_stream * xdr,struct nfs2_fsstat * result)1024*4882a593Smuzhiyun static int decode_info(struct xdr_stream *xdr, struct nfs2_fsstat *result)
1025*4882a593Smuzhiyun {
1026*4882a593Smuzhiyun 	__be32 *p;
1027*4882a593Smuzhiyun 
1028*4882a593Smuzhiyun 	p = xdr_inline_decode(xdr, NFS_info_sz << 2);
1029*4882a593Smuzhiyun 	if (unlikely(!p))
1030*4882a593Smuzhiyun 		return -EIO;
1031*4882a593Smuzhiyun 	result->tsize  = be32_to_cpup(p++);
1032*4882a593Smuzhiyun 	result->bsize  = be32_to_cpup(p++);
1033*4882a593Smuzhiyun 	result->blocks = be32_to_cpup(p++);
1034*4882a593Smuzhiyun 	result->bfree  = be32_to_cpup(p++);
1035*4882a593Smuzhiyun 	result->bavail = be32_to_cpup(p);
1036*4882a593Smuzhiyun 	return 0;
1037*4882a593Smuzhiyun }
1038*4882a593Smuzhiyun 
nfs2_xdr_dec_statfsres(struct rpc_rqst * req,struct xdr_stream * xdr,void * result)1039*4882a593Smuzhiyun static int nfs2_xdr_dec_statfsres(struct rpc_rqst *req, struct xdr_stream *xdr,
1040*4882a593Smuzhiyun 				  void *result)
1041*4882a593Smuzhiyun {
1042*4882a593Smuzhiyun 	enum nfs_stat status;
1043*4882a593Smuzhiyun 	int error;
1044*4882a593Smuzhiyun 
1045*4882a593Smuzhiyun 	error = decode_stat(xdr, &status);
1046*4882a593Smuzhiyun 	if (unlikely(error))
1047*4882a593Smuzhiyun 		goto out;
1048*4882a593Smuzhiyun 	if (status != NFS_OK)
1049*4882a593Smuzhiyun 		goto out_default;
1050*4882a593Smuzhiyun 	error = decode_info(xdr, result);
1051*4882a593Smuzhiyun out:
1052*4882a593Smuzhiyun 	return error;
1053*4882a593Smuzhiyun out_default:
1054*4882a593Smuzhiyun 	return nfs_stat_to_errno(status);
1055*4882a593Smuzhiyun }
1056*4882a593Smuzhiyun 
1057*4882a593Smuzhiyun 
1058*4882a593Smuzhiyun /*
1059*4882a593Smuzhiyun  * We need to translate between nfs status return values and
1060*4882a593Smuzhiyun  * the local errno values which may not be the same.
1061*4882a593Smuzhiyun  */
1062*4882a593Smuzhiyun static const struct {
1063*4882a593Smuzhiyun 	int stat;
1064*4882a593Smuzhiyun 	int errno;
1065*4882a593Smuzhiyun } nfs_errtbl[] = {
1066*4882a593Smuzhiyun 	{ NFS_OK,		0		},
1067*4882a593Smuzhiyun 	{ NFSERR_PERM,		-EPERM		},
1068*4882a593Smuzhiyun 	{ NFSERR_NOENT,		-ENOENT		},
1069*4882a593Smuzhiyun 	{ NFSERR_IO,		-errno_NFSERR_IO},
1070*4882a593Smuzhiyun 	{ NFSERR_NXIO,		-ENXIO		},
1071*4882a593Smuzhiyun /*	{ NFSERR_EAGAIN,	-EAGAIN		}, */
1072*4882a593Smuzhiyun 	{ NFSERR_ACCES,		-EACCES		},
1073*4882a593Smuzhiyun 	{ NFSERR_EXIST,		-EEXIST		},
1074*4882a593Smuzhiyun 	{ NFSERR_XDEV,		-EXDEV		},
1075*4882a593Smuzhiyun 	{ NFSERR_NODEV,		-ENODEV		},
1076*4882a593Smuzhiyun 	{ NFSERR_NOTDIR,	-ENOTDIR	},
1077*4882a593Smuzhiyun 	{ NFSERR_ISDIR,		-EISDIR		},
1078*4882a593Smuzhiyun 	{ NFSERR_INVAL,		-EINVAL		},
1079*4882a593Smuzhiyun 	{ NFSERR_FBIG,		-EFBIG		},
1080*4882a593Smuzhiyun 	{ NFSERR_NOSPC,		-ENOSPC		},
1081*4882a593Smuzhiyun 	{ NFSERR_ROFS,		-EROFS		},
1082*4882a593Smuzhiyun 	{ NFSERR_MLINK,		-EMLINK		},
1083*4882a593Smuzhiyun 	{ NFSERR_NAMETOOLONG,	-ENAMETOOLONG	},
1084*4882a593Smuzhiyun 	{ NFSERR_NOTEMPTY,	-ENOTEMPTY	},
1085*4882a593Smuzhiyun 	{ NFSERR_DQUOT,		-EDQUOT		},
1086*4882a593Smuzhiyun 	{ NFSERR_STALE,		-ESTALE		},
1087*4882a593Smuzhiyun 	{ NFSERR_REMOTE,	-EREMOTE	},
1088*4882a593Smuzhiyun #ifdef EWFLUSH
1089*4882a593Smuzhiyun 	{ NFSERR_WFLUSH,	-EWFLUSH	},
1090*4882a593Smuzhiyun #endif
1091*4882a593Smuzhiyun 	{ NFSERR_BADHANDLE,	-EBADHANDLE	},
1092*4882a593Smuzhiyun 	{ NFSERR_NOT_SYNC,	-ENOTSYNC	},
1093*4882a593Smuzhiyun 	{ NFSERR_BAD_COOKIE,	-EBADCOOKIE	},
1094*4882a593Smuzhiyun 	{ NFSERR_NOTSUPP,	-ENOTSUPP	},
1095*4882a593Smuzhiyun 	{ NFSERR_TOOSMALL,	-ETOOSMALL	},
1096*4882a593Smuzhiyun 	{ NFSERR_SERVERFAULT,	-EREMOTEIO	},
1097*4882a593Smuzhiyun 	{ NFSERR_BADTYPE,	-EBADTYPE	},
1098*4882a593Smuzhiyun 	{ NFSERR_JUKEBOX,	-EJUKEBOX	},
1099*4882a593Smuzhiyun 	{ -1,			-EIO		}
1100*4882a593Smuzhiyun };
1101*4882a593Smuzhiyun 
1102*4882a593Smuzhiyun /**
1103*4882a593Smuzhiyun  * nfs_stat_to_errno - convert an NFS status code to a local errno
1104*4882a593Smuzhiyun  * @status: NFS status code to convert
1105*4882a593Smuzhiyun  *
1106*4882a593Smuzhiyun  * Returns a local errno value, or -EIO if the NFS status code is
1107*4882a593Smuzhiyun  * not recognized.  This function is used jointly by NFSv2 and NFSv3.
1108*4882a593Smuzhiyun  */
nfs_stat_to_errno(enum nfs_stat status)1109*4882a593Smuzhiyun static int nfs_stat_to_errno(enum nfs_stat status)
1110*4882a593Smuzhiyun {
1111*4882a593Smuzhiyun 	int i;
1112*4882a593Smuzhiyun 
1113*4882a593Smuzhiyun 	for (i = 0; nfs_errtbl[i].stat != -1; i++) {
1114*4882a593Smuzhiyun 		if (nfs_errtbl[i].stat == (int)status)
1115*4882a593Smuzhiyun 			return nfs_errtbl[i].errno;
1116*4882a593Smuzhiyun 	}
1117*4882a593Smuzhiyun 	dprintk("NFS: Unrecognized nfs status value: %u\n", status);
1118*4882a593Smuzhiyun 	return nfs_errtbl[i].errno;
1119*4882a593Smuzhiyun }
1120*4882a593Smuzhiyun 
1121*4882a593Smuzhiyun #define PROC(proc, argtype, restype, timer)				\
1122*4882a593Smuzhiyun [NFSPROC_##proc] = {							\
1123*4882a593Smuzhiyun 	.p_proc	    =  NFSPROC_##proc,					\
1124*4882a593Smuzhiyun 	.p_encode   =  nfs2_xdr_enc_##argtype,				\
1125*4882a593Smuzhiyun 	.p_decode   =  nfs2_xdr_dec_##restype,				\
1126*4882a593Smuzhiyun 	.p_arglen   =  NFS_##argtype##_sz,				\
1127*4882a593Smuzhiyun 	.p_replen   =  NFS_##restype##_sz,				\
1128*4882a593Smuzhiyun 	.p_timer    =  timer,						\
1129*4882a593Smuzhiyun 	.p_statidx  =  NFSPROC_##proc,					\
1130*4882a593Smuzhiyun 	.p_name     =  #proc,						\
1131*4882a593Smuzhiyun 	}
1132*4882a593Smuzhiyun const struct rpc_procinfo nfs_procedures[] = {
1133*4882a593Smuzhiyun 	PROC(GETATTR,	fhandle,	attrstat,	1),
1134*4882a593Smuzhiyun 	PROC(SETATTR,	sattrargs,	attrstat,	0),
1135*4882a593Smuzhiyun 	PROC(LOOKUP,	diropargs,	diropres,	2),
1136*4882a593Smuzhiyun 	PROC(READLINK,	readlinkargs,	readlinkres,	3),
1137*4882a593Smuzhiyun 	PROC(READ,	readargs,	readres,	3),
1138*4882a593Smuzhiyun 	PROC(WRITE,	writeargs,	writeres,	4),
1139*4882a593Smuzhiyun 	PROC(CREATE,	createargs,	diropres,	0),
1140*4882a593Smuzhiyun 	PROC(REMOVE,	removeargs,	stat,		0),
1141*4882a593Smuzhiyun 	PROC(RENAME,	renameargs,	stat,		0),
1142*4882a593Smuzhiyun 	PROC(LINK,	linkargs,	stat,		0),
1143*4882a593Smuzhiyun 	PROC(SYMLINK,	symlinkargs,	stat,		0),
1144*4882a593Smuzhiyun 	PROC(MKDIR,	createargs,	diropres,	0),
1145*4882a593Smuzhiyun 	PROC(RMDIR,	diropargs,	stat,		0),
1146*4882a593Smuzhiyun 	PROC(READDIR,	readdirargs,	readdirres,	3),
1147*4882a593Smuzhiyun 	PROC(STATFS,	fhandle,	statfsres,	0),
1148*4882a593Smuzhiyun };
1149*4882a593Smuzhiyun 
1150*4882a593Smuzhiyun static unsigned int nfs_version2_counts[ARRAY_SIZE(nfs_procedures)];
1151*4882a593Smuzhiyun const struct rpc_version nfs_version2 = {
1152*4882a593Smuzhiyun 	.number			= 2,
1153*4882a593Smuzhiyun 	.nrprocs		= ARRAY_SIZE(nfs_procedures),
1154*4882a593Smuzhiyun 	.procs			= nfs_procedures,
1155*4882a593Smuzhiyun 	.counts			= nfs_version2_counts,
1156*4882a593Smuzhiyun };
1157