xref: /openbmc/linux/fs/nfs/nfs2xdr.c (revision f67b55b6)
1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds  * linux/fs/nfs/nfs2xdr.c
41da177e4SLinus Torvalds  *
51da177e4SLinus Torvalds  * XDR functions to encode/decode NFS RPC arguments and results.
61da177e4SLinus Torvalds  *
71da177e4SLinus Torvalds  * Copyright (C) 1992, 1993, 1994  Rick Sladkey
81da177e4SLinus Torvalds  * Copyright (C) 1996 Olaf Kirch
91da177e4SLinus Torvalds  * 04 Aug 1998  Ion Badulescu <ionut@cs.columbia.edu>
101da177e4SLinus Torvalds  * 		FIFO's need special handling in NFSv2
111da177e4SLinus Torvalds  */
121da177e4SLinus Torvalds 
131da177e4SLinus Torvalds #include <linux/param.h>
141da177e4SLinus Torvalds #include <linux/time.h>
151da177e4SLinus Torvalds #include <linux/mm.h>
161da177e4SLinus Torvalds #include <linux/errno.h>
171da177e4SLinus Torvalds #include <linux/string.h>
181da177e4SLinus Torvalds #include <linux/in.h>
191da177e4SLinus Torvalds #include <linux/pagemap.h>
201da177e4SLinus Torvalds #include <linux/proc_fs.h>
211da177e4SLinus Torvalds #include <linux/sunrpc/clnt.h>
221da177e4SLinus Torvalds #include <linux/nfs.h>
231da177e4SLinus Torvalds #include <linux/nfs2.h>
241da177e4SLinus Torvalds #include <linux/nfs_fs.h>
25f23f6584SChuck Lever #include "nfstrace.h"
26816724e6STrond Myklebust #include "internal.h"
271da177e4SLinus Torvalds 
281da177e4SLinus Torvalds #define NFSDBG_FACILITY		NFSDBG_XDR
291da177e4SLinus Torvalds 
301da177e4SLinus Torvalds /* Mapping from NFS error code to "errno" error code. */
311da177e4SLinus Torvalds #define errno_NFSERR_IO		EIO
321da177e4SLinus Torvalds 
331da177e4SLinus Torvalds /*
341da177e4SLinus Torvalds  * Declare the space requirements for NFS arguments and replies as
351da177e4SLinus Torvalds  * number of 32bit-words
361da177e4SLinus Torvalds  */
379ed5af26STrond Myklebust #define NFS_pagepad_sz		(1) /* Page padding */
381da177e4SLinus Torvalds #define NFS_fhandle_sz		(8)
391da177e4SLinus Torvalds #define NFS_sattr_sz		(8)
401da177e4SLinus Torvalds #define NFS_filename_sz		(1+(NFS2_MAXNAMLEN>>2))
411da177e4SLinus Torvalds #define NFS_path_sz		(1+(NFS2_MAXPATHLEN>>2))
421da177e4SLinus Torvalds #define NFS_fattr_sz		(17)
431da177e4SLinus Torvalds #define NFS_info_sz		(5)
441da177e4SLinus Torvalds #define NFS_entry_sz		(NFS_filename_sz+3)
451da177e4SLinus Torvalds 
461da177e4SLinus Torvalds #define NFS_diropargs_sz	(NFS_fhandle_sz+NFS_filename_sz)
474fdc17b2STrond Myklebust #define NFS_removeargs_sz	(NFS_fhandle_sz+NFS_filename_sz)
481da177e4SLinus Torvalds #define NFS_sattrargs_sz	(NFS_fhandle_sz+NFS_sattr_sz)
491da177e4SLinus Torvalds #define NFS_readlinkargs_sz	(NFS_fhandle_sz)
501da177e4SLinus Torvalds #define NFS_readargs_sz		(NFS_fhandle_sz+3)
511da177e4SLinus Torvalds #define NFS_writeargs_sz	(NFS_fhandle_sz+4)
521da177e4SLinus Torvalds #define NFS_createargs_sz	(NFS_diropargs_sz+NFS_sattr_sz)
531da177e4SLinus Torvalds #define NFS_renameargs_sz	(NFS_diropargs_sz+NFS_diropargs_sz)
541da177e4SLinus Torvalds #define NFS_linkargs_sz		(NFS_fhandle_sz+NFS_diropargs_sz)
5594a6d753SChuck Lever #define NFS_symlinkargs_sz	(NFS_diropargs_sz+1+NFS_sattr_sz)
561da177e4SLinus Torvalds #define NFS_readdirargs_sz	(NFS_fhandle_sz+2)
571da177e4SLinus Torvalds 
581da177e4SLinus Torvalds #define NFS_attrstat_sz		(1+NFS_fattr_sz)
591da177e4SLinus Torvalds #define NFS_diropres_sz		(1+NFS_fhandle_sz+NFS_fattr_sz)
609ed5af26STrond Myklebust #define NFS_readlinkres_sz	(2+NFS_pagepad_sz)
619ed5af26STrond Myklebust #define NFS_readres_sz		(1+NFS_fattr_sz+1+NFS_pagepad_sz)
621da177e4SLinus Torvalds #define NFS_writeres_sz         (NFS_attrstat_sz)
631da177e4SLinus Torvalds #define NFS_stat_sz		(1)
649ed5af26STrond Myklebust #define NFS_readdirres_sz	(1+NFS_pagepad_sz)
651da177e4SLinus Torvalds #define NFS_statfsres_sz	(1+NFS_info_sz)
661da177e4SLinus Torvalds 
675e7e5a0dSBryan Schumaker static int nfs_stat_to_errno(enum nfs_stat);
6825a0866cSChuck Lever 
6925a0866cSChuck Lever /*
7025a0866cSChuck Lever  * Encode/decode NFSv2 basic data types
7125a0866cSChuck Lever  *
7225a0866cSChuck Lever  * Basic NFSv2 data types are defined in section 2.3 of RFC 1094:
7325a0866cSChuck Lever  * "NFS: Network File System Protocol Specification".
7425a0866cSChuck Lever  *
7525a0866cSChuck Lever  * Not all basic data types have their own encoding and decoding
7625a0866cSChuck Lever  * functions.  For run-time efficiency, some data types are encoded
7725a0866cSChuck Lever  * or decoded inline.
7825a0866cSChuck Lever  */
7925a0866cSChuck Lever 
rpc_userns(const struct rpc_clnt * clnt)80c207db2fSTrond Myklebust static struct user_namespace *rpc_userns(const struct rpc_clnt *clnt)
81c207db2fSTrond Myklebust {
82c207db2fSTrond Myklebust 	if (clnt && clnt->cl_cred)
83c207db2fSTrond Myklebust 		return clnt->cl_cred->user_ns;
84c207db2fSTrond Myklebust 	return &init_user_ns;
85c207db2fSTrond Myklebust }
86c207db2fSTrond Myklebust 
rpc_rqst_userns(const struct rpc_rqst * rqstp)87c207db2fSTrond Myklebust static struct user_namespace *rpc_rqst_userns(const struct rpc_rqst *rqstp)
88c207db2fSTrond Myklebust {
89c207db2fSTrond Myklebust 	if (rqstp->rq_task)
90c207db2fSTrond Myklebust 		return rpc_userns(rqstp->rq_task->tk_client);
91c207db2fSTrond Myklebust 	return &init_user_ns;
92c207db2fSTrond Myklebust }
93c207db2fSTrond Myklebust 
9425a0866cSChuck Lever /*
95f796f8b3SChuck Lever  *	typedef opaque	nfsdata<>;
96f796f8b3SChuck Lever  */
decode_nfsdata(struct xdr_stream * xdr,struct nfs_pgio_res * result)979137bdf3SAnna Schumaker static int decode_nfsdata(struct xdr_stream *xdr, struct nfs_pgio_res *result)
98f796f8b3SChuck Lever {
99f796f8b3SChuck Lever 	u32 recvd, count;
100f796f8b3SChuck Lever 	__be32 *p;
101f796f8b3SChuck Lever 
102f796f8b3SChuck Lever 	p = xdr_inline_decode(xdr, 4);
103eb72f484SChuck Lever 	if (unlikely(!p))
104eb72f484SChuck Lever 		return -EIO;
105f796f8b3SChuck Lever 	count = be32_to_cpup(p);
10664bd577eSTrond Myklebust 	recvd = xdr_read_pages(xdr, count);
107f796f8b3SChuck Lever 	if (unlikely(count > recvd))
108f796f8b3SChuck Lever 		goto out_cheating;
109f796f8b3SChuck Lever out:
110f796f8b3SChuck Lever 	result->eof = 0;	/* NFSv2 does not pass EOF flag on the wire. */
111f796f8b3SChuck Lever 	result->count = count;
112f796f8b3SChuck Lever 	return count;
113f796f8b3SChuck Lever out_cheating:
114f796f8b3SChuck Lever 	dprintk("NFS: server cheating in read result: "
115f796f8b3SChuck Lever 		"count %u > recvd %u\n", count, recvd);
116f796f8b3SChuck Lever 	count = recvd;
117f796f8b3SChuck Lever 	goto out;
118f796f8b3SChuck Lever }
119f796f8b3SChuck Lever 
120f796f8b3SChuck Lever /*
121f796f8b3SChuck Lever  *	enum stat {
122f796f8b3SChuck Lever  *		NFS_OK = 0,
123f796f8b3SChuck Lever  *		NFSERR_PERM = 1,
124f796f8b3SChuck Lever  *		NFSERR_NOENT = 2,
125f796f8b3SChuck Lever  *		NFSERR_IO = 5,
126f796f8b3SChuck Lever  *		NFSERR_NXIO = 6,
127f796f8b3SChuck Lever  *		NFSERR_ACCES = 13,
128f796f8b3SChuck Lever  *		NFSERR_EXIST = 17,
129f796f8b3SChuck Lever  *		NFSERR_NODEV = 19,
130f796f8b3SChuck Lever  *		NFSERR_NOTDIR = 20,
131f796f8b3SChuck Lever  *		NFSERR_ISDIR = 21,
132f796f8b3SChuck Lever  *		NFSERR_FBIG = 27,
133f796f8b3SChuck Lever  *		NFSERR_NOSPC = 28,
134f796f8b3SChuck Lever  *		NFSERR_ROFS = 30,
135f796f8b3SChuck Lever  *		NFSERR_NAMETOOLONG = 63,
136f796f8b3SChuck Lever  *		NFSERR_NOTEMPTY = 66,
137f796f8b3SChuck Lever  *		NFSERR_DQUOT = 69,
138f796f8b3SChuck Lever  *		NFSERR_STALE = 70,
139f796f8b3SChuck Lever  *		NFSERR_WFLUSH = 99
140f796f8b3SChuck Lever  *	};
141f796f8b3SChuck Lever  */
decode_stat(struct xdr_stream * xdr,enum nfs_stat * status)142f796f8b3SChuck Lever static int decode_stat(struct xdr_stream *xdr, enum nfs_stat *status)
143f796f8b3SChuck Lever {
144f796f8b3SChuck Lever 	__be32 *p;
145f796f8b3SChuck Lever 
146f796f8b3SChuck Lever 	p = xdr_inline_decode(xdr, 4);
147eb72f484SChuck Lever 	if (unlikely(!p))
148eb72f484SChuck Lever 		return -EIO;
149f23f6584SChuck Lever 	if (unlikely(*p != cpu_to_be32(NFS_OK)))
150f23f6584SChuck Lever 		goto out_status;
151f23f6584SChuck Lever 	*status = 0;
152f23f6584SChuck Lever 	return 0;
153f23f6584SChuck Lever out_status:
154f796f8b3SChuck Lever 	*status = be32_to_cpup(p);
15562a92ba9SChuck Lever 	trace_nfs_xdr_status(xdr, (int)*status);
156f796f8b3SChuck Lever 	return 0;
157f796f8b3SChuck Lever }
158f796f8b3SChuck Lever 
159f796f8b3SChuck Lever /*
1605f96e5e3SChuck Lever  * 2.3.2.  ftype
1615f96e5e3SChuck Lever  *
1625f96e5e3SChuck Lever  *	enum ftype {
1635f96e5e3SChuck Lever  *		NFNON = 0,
1645f96e5e3SChuck Lever  *		NFREG = 1,
1655f96e5e3SChuck Lever  *		NFDIR = 2,
1665f96e5e3SChuck Lever  *		NFBLK = 3,
1675f96e5e3SChuck Lever  *		NFCHR = 4,
1685f96e5e3SChuck Lever  *		NFLNK = 5
1695f96e5e3SChuck Lever  *	};
1705f96e5e3SChuck Lever  *
1715f96e5e3SChuck Lever  */
xdr_decode_ftype(__be32 * p,u32 * type)1725f96e5e3SChuck Lever static __be32 *xdr_decode_ftype(__be32 *p, u32 *type)
1735f96e5e3SChuck Lever {
1745f96e5e3SChuck Lever 	*type = be32_to_cpup(p++);
1755f96e5e3SChuck Lever 	if (unlikely(*type > NF2FIFO))
1765f96e5e3SChuck Lever 		*type = NFBAD;
1775f96e5e3SChuck Lever 	return p;
1785f96e5e3SChuck Lever }
1795f96e5e3SChuck Lever 
1805f96e5e3SChuck Lever /*
18125a0866cSChuck Lever  * 2.3.3.  fhandle
18225a0866cSChuck Lever  *
18325a0866cSChuck Lever  *	typedef opaque fhandle[FHSIZE];
18425a0866cSChuck Lever  */
encode_fhandle(struct xdr_stream * xdr,const struct nfs_fh * fh)18525a0866cSChuck Lever static void encode_fhandle(struct xdr_stream *xdr, const struct nfs_fh *fh)
18625a0866cSChuck Lever {
18725a0866cSChuck Lever 	__be32 *p;
18825a0866cSChuck Lever 
18925a0866cSChuck Lever 	p = xdr_reserve_space(xdr, NFS2_FHSIZE);
19025a0866cSChuck Lever 	memcpy(p, fh->data, NFS2_FHSIZE);
19125a0866cSChuck Lever }
19225a0866cSChuck Lever 
decode_fhandle(struct xdr_stream * xdr,struct nfs_fh * fh)193f796f8b3SChuck Lever static int decode_fhandle(struct xdr_stream *xdr, struct nfs_fh *fh)
194f796f8b3SChuck Lever {
195f796f8b3SChuck Lever 	__be32 *p;
196f796f8b3SChuck Lever 
197f796f8b3SChuck Lever 	p = xdr_inline_decode(xdr, NFS2_FHSIZE);
198eb72f484SChuck Lever 	if (unlikely(!p))
199eb72f484SChuck Lever 		return -EIO;
200f796f8b3SChuck Lever 	fh->size = NFS2_FHSIZE;
201f796f8b3SChuck Lever 	memcpy(fh->data, p, NFS2_FHSIZE);
202f796f8b3SChuck Lever 	return 0;
203f796f8b3SChuck Lever }
204f796f8b3SChuck Lever 
20525a0866cSChuck Lever /*
206282ac2a5SChuck Lever  * 2.3.4.  timeval
207282ac2a5SChuck Lever  *
208282ac2a5SChuck Lever  *	struct timeval {
209282ac2a5SChuck Lever  *		unsigned int seconds;
210282ac2a5SChuck Lever  *		unsigned int useconds;
211282ac2a5SChuck Lever  *	};
212282ac2a5SChuck Lever  */
xdr_encode_time(__be32 * p,const struct timespec64 * timep)213c9dbfd96STrond Myklebust static __be32 *xdr_encode_time(__be32 *p, const struct timespec64 *timep)
214282ac2a5SChuck Lever {
215c9dbfd96STrond Myklebust 	*p++ = cpu_to_be32((u32)timep->tv_sec);
216282ac2a5SChuck Lever 	if (timep->tv_nsec != 0)
217282ac2a5SChuck Lever 		*p++ = cpu_to_be32(timep->tv_nsec / NSEC_PER_USEC);
218282ac2a5SChuck Lever 	else
219282ac2a5SChuck Lever 		*p++ = cpu_to_be32(0);
220282ac2a5SChuck Lever 	return p;
221282ac2a5SChuck Lever }
222282ac2a5SChuck Lever 
223282ac2a5SChuck Lever /*
224282ac2a5SChuck Lever  * Passing the invalid value useconds=1000000 is a Sun convention for
225282ac2a5SChuck Lever  * "set to current server time".  It's needed to make permissions checks
226282ac2a5SChuck Lever  * for the "touch" program across v2 mounts to Solaris and Irix servers
227282ac2a5SChuck Lever  * work correctly.  See description of sattr in section 6.1 of "NFS
228282ac2a5SChuck Lever  * Illustrated" by Brent Callaghan, Addison-Wesley, ISBN 0-201-32750-5.
229282ac2a5SChuck Lever  */
xdr_encode_current_server_time(__be32 * p,const struct timespec64 * timep)230282ac2a5SChuck Lever static __be32 *xdr_encode_current_server_time(__be32 *p,
231c9dbfd96STrond Myklebust 					      const struct timespec64 *timep)
232282ac2a5SChuck Lever {
233282ac2a5SChuck Lever 	*p++ = cpu_to_be32(timep->tv_sec);
234282ac2a5SChuck Lever 	*p++ = cpu_to_be32(1000000);
235282ac2a5SChuck Lever 	return p;
236282ac2a5SChuck Lever }
237282ac2a5SChuck Lever 
xdr_decode_time(__be32 * p,struct timespec64 * timep)238e86d5a02STrond Myklebust static __be32 *xdr_decode_time(__be32 *p, struct timespec64 *timep)
2395f96e5e3SChuck Lever {
2405f96e5e3SChuck Lever 	timep->tv_sec = be32_to_cpup(p++);
2415f96e5e3SChuck Lever 	timep->tv_nsec = be32_to_cpup(p++) * NSEC_PER_USEC;
2425f96e5e3SChuck Lever 	return p;
2435f96e5e3SChuck Lever }
2445f96e5e3SChuck Lever 
245282ac2a5SChuck Lever /*
246f796f8b3SChuck Lever  * 2.3.5.  fattr
247f796f8b3SChuck Lever  *
248f796f8b3SChuck Lever  *	struct fattr {
249f796f8b3SChuck Lever  *		ftype		type;
250f796f8b3SChuck Lever  *		unsigned int	mode;
251f796f8b3SChuck Lever  *		unsigned int	nlink;
252f796f8b3SChuck Lever  *		unsigned int	uid;
253f796f8b3SChuck Lever  *		unsigned int	gid;
254f796f8b3SChuck Lever  *		unsigned int	size;
255f796f8b3SChuck Lever  *		unsigned int	blocksize;
256f796f8b3SChuck Lever  *		unsigned int	rdev;
257f796f8b3SChuck Lever  *		unsigned int	blocks;
258f796f8b3SChuck Lever  *		unsigned int	fsid;
259f796f8b3SChuck Lever  *		unsigned int	fileid;
260f796f8b3SChuck Lever  *		timeval		atime;
261f796f8b3SChuck Lever  *		timeval		mtime;
262f796f8b3SChuck Lever  *		timeval		ctime;
263f796f8b3SChuck Lever  *	};
264f796f8b3SChuck Lever  *
265f796f8b3SChuck Lever  */
decode_fattr(struct xdr_stream * xdr,struct nfs_fattr * fattr,struct user_namespace * userns)266c207db2fSTrond Myklebust static int decode_fattr(struct xdr_stream *xdr, struct nfs_fattr *fattr,
267c207db2fSTrond Myklebust 		struct user_namespace *userns)
268f796f8b3SChuck Lever {
2695f96e5e3SChuck Lever 	u32 rdev, type;
270f796f8b3SChuck Lever 	__be32 *p;
271f796f8b3SChuck Lever 
272f796f8b3SChuck Lever 	p = xdr_inline_decode(xdr, NFS_fattr_sz << 2);
273eb72f484SChuck Lever 	if (unlikely(!p))
274eb72f484SChuck Lever 		return -EIO;
2755f96e5e3SChuck Lever 
2765f96e5e3SChuck Lever 	fattr->valid |= NFS_ATTR_FATTR_V2;
2775f96e5e3SChuck Lever 
2785f96e5e3SChuck Lever 	p = xdr_decode_ftype(p, &type);
2795f96e5e3SChuck Lever 
2805f96e5e3SChuck Lever 	fattr->mode = be32_to_cpup(p++);
2815f96e5e3SChuck Lever 	fattr->nlink = be32_to_cpup(p++);
282c207db2fSTrond Myklebust 	fattr->uid = make_kuid(userns, be32_to_cpup(p++));
283cfa0898dSEric W. Biederman 	if (!uid_valid(fattr->uid))
284cfa0898dSEric W. Biederman 		goto out_uid;
285c207db2fSTrond Myklebust 	fattr->gid = make_kgid(userns, be32_to_cpup(p++));
286cfa0898dSEric W. Biederman 	if (!gid_valid(fattr->gid))
287cfa0898dSEric W. Biederman 		goto out_gid;
288cfa0898dSEric W. Biederman 
2895f96e5e3SChuck Lever 	fattr->size = be32_to_cpup(p++);
2905f96e5e3SChuck Lever 	fattr->du.nfs2.blocksize = be32_to_cpup(p++);
2915f96e5e3SChuck Lever 
2925f96e5e3SChuck Lever 	rdev = be32_to_cpup(p++);
2935f96e5e3SChuck Lever 	fattr->rdev = new_decode_dev(rdev);
2945f96e5e3SChuck Lever 	if (type == (u32)NFCHR && rdev == (u32)NFS2_FIFO_DEV) {
2955f96e5e3SChuck Lever 		fattr->mode = (fattr->mode & ~S_IFMT) | S_IFIFO;
2965f96e5e3SChuck Lever 		fattr->rdev = 0;
2975f96e5e3SChuck Lever 	}
2985f96e5e3SChuck Lever 
2995f96e5e3SChuck Lever 	fattr->du.nfs2.blocks = be32_to_cpup(p++);
3005f96e5e3SChuck Lever 	fattr->fsid.major = be32_to_cpup(p++);
3015f96e5e3SChuck Lever 	fattr->fsid.minor = 0;
3025f96e5e3SChuck Lever 	fattr->fileid = be32_to_cpup(p++);
3035f96e5e3SChuck Lever 
3045f96e5e3SChuck Lever 	p = xdr_decode_time(p, &fattr->atime);
3055f96e5e3SChuck Lever 	p = xdr_decode_time(p, &fattr->mtime);
3065f96e5e3SChuck Lever 	xdr_decode_time(p, &fattr->ctime);
3073a1556e8STrond Myklebust 	fattr->change_attr = nfs_timespec_to_change_attr(&fattr->ctime);
3083a1556e8STrond Myklebust 
309f796f8b3SChuck Lever 	return 0;
310cfa0898dSEric W. Biederman out_uid:
311cfa0898dSEric W. Biederman 	dprintk("NFS: returned invalid uid\n");
312cfa0898dSEric W. Biederman 	return -EINVAL;
313cfa0898dSEric W. Biederman out_gid:
314cfa0898dSEric W. Biederman 	dprintk("NFS: returned invalid gid\n");
315cfa0898dSEric W. Biederman 	return -EINVAL;
316f796f8b3SChuck Lever }
317f796f8b3SChuck Lever 
318f796f8b3SChuck Lever /*
31925a0866cSChuck Lever  * 2.3.6.  sattr
32025a0866cSChuck Lever  *
32125a0866cSChuck Lever  *	struct sattr {
32225a0866cSChuck Lever  *		unsigned int	mode;
32325a0866cSChuck Lever  *		unsigned int	uid;
32425a0866cSChuck Lever  *		unsigned int	gid;
32525a0866cSChuck Lever  *		unsigned int	size;
32625a0866cSChuck Lever  *		timeval		atime;
32725a0866cSChuck Lever  *		timeval		mtime;
32825a0866cSChuck Lever  *	};
32925a0866cSChuck Lever  */
33025a0866cSChuck Lever 
33125a0866cSChuck Lever #define NFS2_SATTR_NOT_SET	(0xffffffff)
33225a0866cSChuck Lever 
xdr_time_not_set(__be32 * p)33325a0866cSChuck Lever static __be32 *xdr_time_not_set(__be32 *p)
33425a0866cSChuck Lever {
33525a0866cSChuck Lever 	*p++ = cpu_to_be32(NFS2_SATTR_NOT_SET);
33625a0866cSChuck Lever 	*p++ = cpu_to_be32(NFS2_SATTR_NOT_SET);
33725a0866cSChuck Lever 	return p;
33825a0866cSChuck Lever }
33925a0866cSChuck Lever 
encode_sattr(struct xdr_stream * xdr,const struct iattr * attr,struct user_namespace * userns)340c207db2fSTrond Myklebust static void encode_sattr(struct xdr_stream *xdr, const struct iattr *attr,
341c207db2fSTrond Myklebust 		struct user_namespace *userns)
34225a0866cSChuck Lever {
34325a0866cSChuck Lever 	__be32 *p;
34425a0866cSChuck Lever 
34525a0866cSChuck Lever 	p = xdr_reserve_space(xdr, NFS_sattr_sz << 2);
34625a0866cSChuck Lever 
34725a0866cSChuck Lever 	if (attr->ia_valid & ATTR_MODE)
34825a0866cSChuck Lever 		*p++ = cpu_to_be32(attr->ia_mode);
34925a0866cSChuck Lever 	else
35025a0866cSChuck Lever 		*p++ = cpu_to_be32(NFS2_SATTR_NOT_SET);
35125a0866cSChuck Lever 	if (attr->ia_valid & ATTR_UID)
352c207db2fSTrond Myklebust 		*p++ = cpu_to_be32(from_kuid_munged(userns, attr->ia_uid));
35325a0866cSChuck Lever 	else
35425a0866cSChuck Lever 		*p++ = cpu_to_be32(NFS2_SATTR_NOT_SET);
35525a0866cSChuck Lever 	if (attr->ia_valid & ATTR_GID)
356c207db2fSTrond Myklebust 		*p++ = cpu_to_be32(from_kgid_munged(userns, attr->ia_gid));
35725a0866cSChuck Lever 	else
35825a0866cSChuck Lever 		*p++ = cpu_to_be32(NFS2_SATTR_NOT_SET);
35925a0866cSChuck Lever 	if (attr->ia_valid & ATTR_SIZE)
36025a0866cSChuck Lever 		*p++ = cpu_to_be32((u32)attr->ia_size);
36125a0866cSChuck Lever 	else
36225a0866cSChuck Lever 		*p++ = cpu_to_be32(NFS2_SATTR_NOT_SET);
36325a0866cSChuck Lever 
364e5189e9aSArnd Bergmann 	if (attr->ia_valid & ATTR_ATIME_SET)
365c9dbfd96STrond Myklebust 		p = xdr_encode_time(p, &attr->ia_atime);
366e5189e9aSArnd Bergmann 	else if (attr->ia_valid & ATTR_ATIME)
367c9dbfd96STrond Myklebust 		p = xdr_encode_current_server_time(p, &attr->ia_atime);
368e5189e9aSArnd Bergmann 	else
36925a0866cSChuck Lever 		p = xdr_time_not_set(p);
370e5189e9aSArnd Bergmann 	if (attr->ia_valid & ATTR_MTIME_SET)
371c9dbfd96STrond Myklebust 		xdr_encode_time(p, &attr->ia_mtime);
372e5189e9aSArnd Bergmann 	else if (attr->ia_valid & ATTR_MTIME)
373c9dbfd96STrond Myklebust 		xdr_encode_current_server_time(p, &attr->ia_mtime);
374e5189e9aSArnd Bergmann 	else
37525a0866cSChuck Lever 		xdr_time_not_set(p);
37625a0866cSChuck Lever }
37725a0866cSChuck Lever 
37825a0866cSChuck Lever /*
37925a0866cSChuck Lever  * 2.3.7.  filename
38025a0866cSChuck Lever  *
38125a0866cSChuck Lever  *	typedef string filename<MAXNAMLEN>;
38225a0866cSChuck Lever  */
encode_filename(struct xdr_stream * xdr,const char * name,u32 length)38325a0866cSChuck Lever static void encode_filename(struct xdr_stream *xdr,
38425a0866cSChuck Lever 			    const char *name, u32 length)
38525a0866cSChuck Lever {
38625a0866cSChuck Lever 	__be32 *p;
38725a0866cSChuck Lever 
3887fc38846STrond Myklebust 	WARN_ON_ONCE(length > NFS2_MAXNAMLEN);
38925a0866cSChuck Lever 	p = xdr_reserve_space(xdr, 4 + length);
39025a0866cSChuck Lever 	xdr_encode_opaque(p, name, length);
39125a0866cSChuck Lever }
39225a0866cSChuck Lever 
decode_filename_inline(struct xdr_stream * xdr,const char ** name,u32 * length)393f796f8b3SChuck Lever static int decode_filename_inline(struct xdr_stream *xdr,
394f796f8b3SChuck Lever 				  const char **name, u32 *length)
395f796f8b3SChuck Lever {
396f796f8b3SChuck Lever 	__be32 *p;
397f796f8b3SChuck Lever 	u32 count;
398f796f8b3SChuck Lever 
399f796f8b3SChuck Lever 	p = xdr_inline_decode(xdr, 4);
400eb72f484SChuck Lever 	if (unlikely(!p))
401eb72f484SChuck Lever 		return -EIO;
402f796f8b3SChuck Lever 	count = be32_to_cpup(p);
403f796f8b3SChuck Lever 	if (count > NFS3_MAXNAMLEN)
404f796f8b3SChuck Lever 		goto out_nametoolong;
405f796f8b3SChuck Lever 	p = xdr_inline_decode(xdr, count);
406eb72f484SChuck Lever 	if (unlikely(!p))
407eb72f484SChuck Lever 		return -EIO;
408f796f8b3SChuck Lever 	*name = (const char *)p;
409f796f8b3SChuck Lever 	*length = count;
410f796f8b3SChuck Lever 	return 0;
411f796f8b3SChuck Lever out_nametoolong:
412f796f8b3SChuck Lever 	dprintk("NFS: returned filename too long: %u\n", count);
413f796f8b3SChuck Lever 	return -ENAMETOOLONG;
414f796f8b3SChuck Lever }
415f796f8b3SChuck Lever 
41625a0866cSChuck Lever /*
41725a0866cSChuck Lever  * 2.3.8.  path
41825a0866cSChuck Lever  *
41925a0866cSChuck Lever  *	typedef string path<MAXPATHLEN>;
42025a0866cSChuck Lever  */
encode_path(struct xdr_stream * xdr,struct page ** pages,u32 length)42125a0866cSChuck Lever static void encode_path(struct xdr_stream *xdr, struct page **pages, u32 length)
42225a0866cSChuck Lever {
42325a0866cSChuck Lever 	__be32 *p;
42425a0866cSChuck Lever 
42525a0866cSChuck Lever 	p = xdr_reserve_space(xdr, 4);
42625a0866cSChuck Lever 	*p = cpu_to_be32(length);
42725a0866cSChuck Lever 	xdr_write_pages(xdr, pages, 0, length);
42825a0866cSChuck Lever }
42925a0866cSChuck Lever 
decode_path(struct xdr_stream * xdr)430f796f8b3SChuck Lever static int decode_path(struct xdr_stream *xdr)
431f796f8b3SChuck Lever {
432f796f8b3SChuck Lever 	u32 length, recvd;
433f796f8b3SChuck Lever 	__be32 *p;
434f796f8b3SChuck Lever 
435f796f8b3SChuck Lever 	p = xdr_inline_decode(xdr, 4);
436eb72f484SChuck Lever 	if (unlikely(!p))
437eb72f484SChuck Lever 		return -EIO;
438f796f8b3SChuck Lever 	length = be32_to_cpup(p);
439f796f8b3SChuck Lever 	if (unlikely(length >= xdr->buf->page_len || length > NFS_MAXPATHLEN))
440f796f8b3SChuck Lever 		goto out_size;
44164bd577eSTrond Myklebust 	recvd = xdr_read_pages(xdr, length);
442f796f8b3SChuck Lever 	if (unlikely(length > recvd))
443f796f8b3SChuck Lever 		goto out_cheating;
444f796f8b3SChuck Lever 	xdr_terminate_string(xdr->buf, length);
445f796f8b3SChuck Lever 	return 0;
446f796f8b3SChuck Lever out_size:
447f796f8b3SChuck Lever 	dprintk("NFS: returned pathname too long: %u\n", length);
448f796f8b3SChuck Lever 	return -ENAMETOOLONG;
449f796f8b3SChuck Lever out_cheating:
450f796f8b3SChuck Lever 	dprintk("NFS: server cheating in pathname result: "
451f796f8b3SChuck Lever 		"length %u > received %u\n", length, recvd);
452f796f8b3SChuck Lever 	return -EIO;
453f796f8b3SChuck Lever }
454f796f8b3SChuck Lever 
455f796f8b3SChuck Lever /*
456f796f8b3SChuck Lever  * 2.3.9.  attrstat
457f796f8b3SChuck Lever  *
458f796f8b3SChuck Lever  *	union attrstat switch (stat status) {
459f796f8b3SChuck Lever  *	case NFS_OK:
460f796f8b3SChuck Lever  *		fattr attributes;
461f796f8b3SChuck Lever  *	default:
462f796f8b3SChuck Lever  *		void;
463f796f8b3SChuck Lever  *	};
464f796f8b3SChuck Lever  */
decode_attrstat(struct xdr_stream * xdr,struct nfs_fattr * result,__u32 * op_status,struct user_namespace * userns)465aabff4ddSPeng Tao static int decode_attrstat(struct xdr_stream *xdr, struct nfs_fattr *result,
466c207db2fSTrond Myklebust 			   __u32 *op_status,
467c207db2fSTrond Myklebust 			   struct user_namespace *userns)
468f796f8b3SChuck Lever {
469f796f8b3SChuck Lever 	enum nfs_stat status;
470f796f8b3SChuck Lever 	int error;
471f796f8b3SChuck Lever 
472f796f8b3SChuck Lever 	error = decode_stat(xdr, &status);
473f796f8b3SChuck Lever 	if (unlikely(error))
474f796f8b3SChuck Lever 		goto out;
475aabff4ddSPeng Tao 	if (op_status)
476aabff4ddSPeng Tao 		*op_status = status;
477f796f8b3SChuck Lever 	if (status != NFS_OK)
478f796f8b3SChuck Lever 		goto out_default;
479c207db2fSTrond Myklebust 	error = decode_fattr(xdr, result, userns);
480f796f8b3SChuck Lever out:
481f796f8b3SChuck Lever 	return error;
482f796f8b3SChuck Lever out_default:
483f796f8b3SChuck Lever 	return nfs_stat_to_errno(status);
484f796f8b3SChuck Lever }
485f796f8b3SChuck Lever 
48625a0866cSChuck Lever /*
48725a0866cSChuck Lever  * 2.3.10.  diropargs
48825a0866cSChuck Lever  *
48925a0866cSChuck Lever  *	struct diropargs {
49025a0866cSChuck Lever  *		fhandle  dir;
49125a0866cSChuck Lever  *		filename name;
49225a0866cSChuck Lever  *	};
49325a0866cSChuck Lever  */
encode_diropargs(struct xdr_stream * xdr,const struct nfs_fh * fh,const char * name,u32 length)49425a0866cSChuck Lever static void encode_diropargs(struct xdr_stream *xdr, const struct nfs_fh *fh,
49525a0866cSChuck Lever 			     const char *name, u32 length)
49625a0866cSChuck Lever {
49725a0866cSChuck Lever 	encode_fhandle(xdr, fh);
49825a0866cSChuck Lever 	encode_filename(xdr, name, length);
49925a0866cSChuck Lever }
50025a0866cSChuck Lever 
501f796f8b3SChuck Lever /*
502f796f8b3SChuck Lever  * 2.3.11.  diropres
503f796f8b3SChuck Lever  *
504f796f8b3SChuck Lever  *	union diropres switch (stat status) {
505f796f8b3SChuck Lever  *	case NFS_OK:
506f796f8b3SChuck Lever  *		struct {
507f796f8b3SChuck Lever  *			fhandle file;
508f796f8b3SChuck Lever  *			fattr   attributes;
509f796f8b3SChuck Lever  *		} diropok;
510f796f8b3SChuck Lever  *	default:
511f796f8b3SChuck Lever  *		void;
512f796f8b3SChuck Lever  *	};
513f796f8b3SChuck Lever  */
decode_diropok(struct xdr_stream * xdr,struct nfs_diropok * result,struct user_namespace * userns)514c207db2fSTrond Myklebust static int decode_diropok(struct xdr_stream *xdr, struct nfs_diropok *result,
515c207db2fSTrond Myklebust 		struct user_namespace *userns)
516f796f8b3SChuck Lever {
517f796f8b3SChuck Lever 	int error;
518f796f8b3SChuck Lever 
519f796f8b3SChuck Lever 	error = decode_fhandle(xdr, result->fh);
520f796f8b3SChuck Lever 	if (unlikely(error))
521f796f8b3SChuck Lever 		goto out;
522c207db2fSTrond Myklebust 	error = decode_fattr(xdr, result->fattr, userns);
523f796f8b3SChuck Lever out:
524f796f8b3SChuck Lever 	return error;
525f796f8b3SChuck Lever }
526f796f8b3SChuck Lever 
decode_diropres(struct xdr_stream * xdr,struct nfs_diropok * result,struct user_namespace * userns)527c207db2fSTrond Myklebust static int decode_diropres(struct xdr_stream *xdr, struct nfs_diropok *result,
528c207db2fSTrond Myklebust 		struct user_namespace *userns)
529f796f8b3SChuck Lever {
530f796f8b3SChuck Lever 	enum nfs_stat status;
531f796f8b3SChuck Lever 	int error;
532f796f8b3SChuck Lever 
533f796f8b3SChuck Lever 	error = decode_stat(xdr, &status);
534f796f8b3SChuck Lever 	if (unlikely(error))
535f796f8b3SChuck Lever 		goto out;
536f796f8b3SChuck Lever 	if (status != NFS_OK)
537f796f8b3SChuck Lever 		goto out_default;
538c207db2fSTrond Myklebust 	error = decode_diropok(xdr, result, userns);
539f796f8b3SChuck Lever out:
540f796f8b3SChuck Lever 	return error;
541f796f8b3SChuck Lever out_default:
542f796f8b3SChuck Lever 	return nfs_stat_to_errno(status);
543f796f8b3SChuck Lever }
544f796f8b3SChuck Lever 
54525a0866cSChuck Lever 
54625a0866cSChuck Lever /*
5472d70f533SChuck Lever  * NFSv2 XDR encode functions
5482d70f533SChuck Lever  *
5492d70f533SChuck Lever  * NFSv2 argument types are defined in section 2.2 of RFC 1094:
5502d70f533SChuck Lever  * "NFS: Network File System Protocol Specification".
5511da177e4SLinus Torvalds  */
5521da177e4SLinus Torvalds 
nfs2_xdr_enc_fhandle(struct rpc_rqst * req,struct xdr_stream * xdr,const void * data)5539f06c719SChuck Lever static void nfs2_xdr_enc_fhandle(struct rpc_rqst *req,
5549f06c719SChuck Lever 				 struct xdr_stream *xdr,
555fcc85819SChristoph Hellwig 				 const void *data)
55625a0866cSChuck Lever {
557fcc85819SChristoph Hellwig 	const struct nfs_fh *fh = data;
558fcc85819SChristoph Hellwig 
5599f06c719SChuck Lever 	encode_fhandle(xdr, fh);
56025a0866cSChuck Lever }
56125a0866cSChuck Lever 
5621da177e4SLinus Torvalds /*
56325a0866cSChuck Lever  * 2.2.3.  sattrargs
56425a0866cSChuck Lever  *
56525a0866cSChuck Lever  *	struct sattrargs {
56625a0866cSChuck Lever  *		fhandle file;
56725a0866cSChuck Lever  *		sattr attributes;
56825a0866cSChuck Lever  *	};
56925a0866cSChuck Lever  */
nfs2_xdr_enc_sattrargs(struct rpc_rqst * req,struct xdr_stream * xdr,const void * data)5709f06c719SChuck Lever static void nfs2_xdr_enc_sattrargs(struct rpc_rqst *req,
5719f06c719SChuck Lever 				   struct xdr_stream *xdr,
572fcc85819SChristoph Hellwig 				   const void *data)
57325a0866cSChuck Lever {
574fcc85819SChristoph Hellwig 	const struct nfs_sattrargs *args = data;
575fcc85819SChristoph Hellwig 
5769f06c719SChuck Lever 	encode_fhandle(xdr, args->fh);
577c207db2fSTrond Myklebust 	encode_sattr(xdr, args->sattr, rpc_rqst_userns(req));
57825a0866cSChuck Lever }
57925a0866cSChuck Lever 
nfs2_xdr_enc_diropargs(struct rpc_rqst * req,struct xdr_stream * xdr,const void * data)5809f06c719SChuck Lever static void nfs2_xdr_enc_diropargs(struct rpc_rqst *req,
5819f06c719SChuck Lever 				   struct xdr_stream *xdr,
582fcc85819SChristoph Hellwig 				   const void *data)
58325a0866cSChuck Lever {
584fcc85819SChristoph Hellwig 	const struct nfs_diropargs *args = data;
585fcc85819SChristoph Hellwig 
5869f06c719SChuck Lever 	encode_diropargs(xdr, args->fh, args->name, args->len);
58725a0866cSChuck Lever }
58825a0866cSChuck Lever 
nfs2_xdr_enc_readlinkargs(struct rpc_rqst * req,struct xdr_stream * xdr,const void * data)5899f06c719SChuck Lever static void nfs2_xdr_enc_readlinkargs(struct rpc_rqst *req,
5909f06c719SChuck Lever 				      struct xdr_stream *xdr,
591fcc85819SChristoph Hellwig 				      const void *data)
59225a0866cSChuck Lever {
593fcc85819SChristoph Hellwig 	const struct nfs_readlinkargs *args = data;
594fcc85819SChristoph Hellwig 
5959f06c719SChuck Lever 	encode_fhandle(xdr, args->fh);
5969ed5af26STrond Myklebust 	rpc_prepare_reply_pages(req, args->pages, args->pgbase, args->pglen,
5979ed5af26STrond Myklebust 				NFS_readlinkres_sz - NFS_pagepad_sz);
59825a0866cSChuck Lever }
59925a0866cSChuck Lever 
6004fdc17b2STrond Myklebust /*
60125a0866cSChuck Lever  * 2.2.7.  readargs
60225a0866cSChuck Lever  *
60325a0866cSChuck Lever  *	struct readargs {
60425a0866cSChuck Lever  *		fhandle file;
60525a0866cSChuck Lever  *		unsigned offset;
60625a0866cSChuck Lever  *		unsigned count;
60725a0866cSChuck Lever  *		unsigned totalcount;
60825a0866cSChuck Lever  *	};
60925a0866cSChuck Lever  */
encode_readargs(struct xdr_stream * xdr,const struct nfs_pgio_args * args)61025a0866cSChuck Lever static void encode_readargs(struct xdr_stream *xdr,
6113c6b899cSAnna Schumaker 			    const struct nfs_pgio_args *args)
61225a0866cSChuck Lever {
61325a0866cSChuck Lever 	u32 offset = args->offset;
61425a0866cSChuck Lever 	u32 count = args->count;
61525a0866cSChuck Lever 	__be32 *p;
61625a0866cSChuck Lever 
61725a0866cSChuck Lever 	encode_fhandle(xdr, args->fh);
61825a0866cSChuck Lever 
61925a0866cSChuck Lever 	p = xdr_reserve_space(xdr, 4 + 4 + 4);
62025a0866cSChuck Lever 	*p++ = cpu_to_be32(offset);
62125a0866cSChuck Lever 	*p++ = cpu_to_be32(count);
62225a0866cSChuck Lever 	*p = cpu_to_be32(count);
62325a0866cSChuck Lever }
62425a0866cSChuck Lever 
nfs2_xdr_enc_readargs(struct rpc_rqst * req,struct xdr_stream * xdr,const void * data)6259f06c719SChuck Lever static void nfs2_xdr_enc_readargs(struct rpc_rqst *req,
6269f06c719SChuck Lever 				  struct xdr_stream *xdr,
627fcc85819SChristoph Hellwig 				  const void *data)
62825a0866cSChuck Lever {
629fcc85819SChristoph Hellwig 	const struct nfs_pgio_args *args = data;
630fcc85819SChristoph Hellwig 
6319f06c719SChuck Lever 	encode_readargs(xdr, args);
6329ed5af26STrond Myklebust 	rpc_prepare_reply_pages(req, args->pages, args->pgbase, args->count,
6339ed5af26STrond Myklebust 				NFS_readres_sz - NFS_pagepad_sz);
63425a0866cSChuck Lever 	req->rq_rcv_buf.flags |= XDRBUF_READ;
63525a0866cSChuck Lever }
63625a0866cSChuck Lever 
63725a0866cSChuck Lever /*
63825a0866cSChuck Lever  * 2.2.9.  writeargs
63925a0866cSChuck Lever  *
64025a0866cSChuck Lever  *	struct writeargs {
64125a0866cSChuck Lever  *		fhandle file;
64225a0866cSChuck Lever  *		unsigned beginoffset;
64325a0866cSChuck Lever  *		unsigned offset;
64425a0866cSChuck Lever  *		unsigned totalcount;
64525a0866cSChuck Lever  *		nfsdata data;
64625a0866cSChuck Lever  *	};
64725a0866cSChuck Lever  */
encode_writeargs(struct xdr_stream * xdr,const struct nfs_pgio_args * args)64825a0866cSChuck Lever static void encode_writeargs(struct xdr_stream *xdr,
6493c6b899cSAnna Schumaker 			     const struct nfs_pgio_args *args)
65025a0866cSChuck Lever {
65125a0866cSChuck Lever 	u32 offset = args->offset;
65225a0866cSChuck Lever 	u32 count = args->count;
65325a0866cSChuck Lever 	__be32 *p;
65425a0866cSChuck Lever 
65525a0866cSChuck Lever 	encode_fhandle(xdr, args->fh);
65625a0866cSChuck Lever 
65725a0866cSChuck Lever 	p = xdr_reserve_space(xdr, 4 + 4 + 4 + 4);
65825a0866cSChuck Lever 	*p++ = cpu_to_be32(offset);
65925a0866cSChuck Lever 	*p++ = cpu_to_be32(offset);
66025a0866cSChuck Lever 	*p++ = cpu_to_be32(count);
66125a0866cSChuck Lever 
66225a0866cSChuck Lever 	/* nfsdata */
66325a0866cSChuck Lever 	*p = cpu_to_be32(count);
66425a0866cSChuck Lever 	xdr_write_pages(xdr, args->pages, args->pgbase, count);
66525a0866cSChuck Lever }
66625a0866cSChuck Lever 
nfs2_xdr_enc_writeargs(struct rpc_rqst * req,struct xdr_stream * xdr,const void * data)6679f06c719SChuck Lever static void nfs2_xdr_enc_writeargs(struct rpc_rqst *req,
6689f06c719SChuck Lever 				   struct xdr_stream *xdr,
669fcc85819SChristoph Hellwig 				   const void *data)
67025a0866cSChuck Lever {
671fcc85819SChristoph Hellwig 	const struct nfs_pgio_args *args = data;
672fcc85819SChristoph Hellwig 
6739f06c719SChuck Lever 	encode_writeargs(xdr, args);
6749f06c719SChuck Lever 	xdr->buf->flags |= XDRBUF_WRITE;
67525a0866cSChuck Lever }
67625a0866cSChuck Lever 
67725a0866cSChuck Lever /*
67825a0866cSChuck Lever  * 2.2.10.  createargs
67925a0866cSChuck Lever  *
68025a0866cSChuck Lever  *	struct createargs {
68125a0866cSChuck Lever  *		diropargs where;
68225a0866cSChuck Lever  *		sattr attributes;
68325a0866cSChuck Lever  *	};
68425a0866cSChuck Lever  */
nfs2_xdr_enc_createargs(struct rpc_rqst * req,struct xdr_stream * xdr,const void * data)6859f06c719SChuck Lever static void nfs2_xdr_enc_createargs(struct rpc_rqst *req,
6869f06c719SChuck Lever 				    struct xdr_stream *xdr,
687fcc85819SChristoph Hellwig 				    const void *data)
68825a0866cSChuck Lever {
689fcc85819SChristoph Hellwig 	const struct nfs_createargs *args = data;
690fcc85819SChristoph Hellwig 
6919f06c719SChuck Lever 	encode_diropargs(xdr, args->fh, args->name, args->len);
692c207db2fSTrond Myklebust 	encode_sattr(xdr, args->sattr, rpc_rqst_userns(req));
69325a0866cSChuck Lever }
69425a0866cSChuck Lever 
nfs2_xdr_enc_removeargs(struct rpc_rqst * req,struct xdr_stream * xdr,const void * data)6959f06c719SChuck Lever static void nfs2_xdr_enc_removeargs(struct rpc_rqst *req,
6969f06c719SChuck Lever 				    struct xdr_stream *xdr,
697fcc85819SChristoph Hellwig 				    const void *data)
69825a0866cSChuck Lever {
699fcc85819SChristoph Hellwig 	const struct nfs_removeargs *args = data;
700fcc85819SChristoph Hellwig 
7019f06c719SChuck Lever 	encode_diropargs(xdr, args->fh, args->name.name, args->name.len);
70225a0866cSChuck Lever }
70325a0866cSChuck Lever 
70425a0866cSChuck Lever /*
70525a0866cSChuck Lever  * 2.2.12.  renameargs
70625a0866cSChuck Lever  *
70725a0866cSChuck Lever  *	struct renameargs {
70825a0866cSChuck Lever  *		diropargs from;
70925a0866cSChuck Lever  *		diropargs to;
71025a0866cSChuck Lever  *	};
71125a0866cSChuck Lever  */
nfs2_xdr_enc_renameargs(struct rpc_rqst * req,struct xdr_stream * xdr,const void * data)7129f06c719SChuck Lever static void nfs2_xdr_enc_renameargs(struct rpc_rqst *req,
7139f06c719SChuck Lever 				    struct xdr_stream *xdr,
714fcc85819SChristoph Hellwig 				    const void *data)
71525a0866cSChuck Lever {
716fcc85819SChristoph Hellwig 	const struct nfs_renameargs *args = data;
71725a0866cSChuck Lever 	const struct qstr *old = args->old_name;
71825a0866cSChuck Lever 	const struct qstr *new = args->new_name;
71925a0866cSChuck Lever 
7209f06c719SChuck Lever 	encode_diropargs(xdr, args->old_dir, old->name, old->len);
7219f06c719SChuck Lever 	encode_diropargs(xdr, args->new_dir, new->name, new->len);
72225a0866cSChuck Lever }
72325a0866cSChuck Lever 
72425a0866cSChuck Lever /*
72525a0866cSChuck Lever  * 2.2.13.  linkargs
72625a0866cSChuck Lever  *
72725a0866cSChuck Lever  *	struct linkargs {
72825a0866cSChuck Lever  *		fhandle from;
72925a0866cSChuck Lever  *		diropargs to;
73025a0866cSChuck Lever  *	};
73125a0866cSChuck Lever  */
nfs2_xdr_enc_linkargs(struct rpc_rqst * req,struct xdr_stream * xdr,const void * data)7329f06c719SChuck Lever static void nfs2_xdr_enc_linkargs(struct rpc_rqst *req,
7339f06c719SChuck Lever 				  struct xdr_stream *xdr,
734fcc85819SChristoph Hellwig 				  const void *data)
73525a0866cSChuck Lever {
736fcc85819SChristoph Hellwig 	const struct nfs_linkargs *args = data;
737fcc85819SChristoph Hellwig 
7389f06c719SChuck Lever 	encode_fhandle(xdr, args->fromfh);
7399f06c719SChuck Lever 	encode_diropargs(xdr, args->tofh, args->toname, args->tolen);
74025a0866cSChuck Lever }
74125a0866cSChuck Lever 
74225a0866cSChuck Lever /*
74325a0866cSChuck Lever  * 2.2.14.  symlinkargs
74425a0866cSChuck Lever  *
74525a0866cSChuck Lever  *	struct symlinkargs {
74625a0866cSChuck Lever  *		diropargs from;
74725a0866cSChuck Lever  *		path to;
74825a0866cSChuck Lever  *		sattr attributes;
74925a0866cSChuck Lever  *	};
75025a0866cSChuck Lever  */
nfs2_xdr_enc_symlinkargs(struct rpc_rqst * req,struct xdr_stream * xdr,const void * data)7519f06c719SChuck Lever static void nfs2_xdr_enc_symlinkargs(struct rpc_rqst *req,
7529f06c719SChuck Lever 				     struct xdr_stream *xdr,
753fcc85819SChristoph Hellwig 				     const void *data)
75425a0866cSChuck Lever {
755fcc85819SChristoph Hellwig 	const struct nfs_symlinkargs *args = data;
756fcc85819SChristoph Hellwig 
7579f06c719SChuck Lever 	encode_diropargs(xdr, args->fromfh, args->fromname, args->fromlen);
7589f06c719SChuck Lever 	encode_path(xdr, args->pages, args->pathlen);
759c207db2fSTrond Myklebust 	encode_sattr(xdr, args->sattr, rpc_rqst_userns(req));
76025a0866cSChuck Lever }
76125a0866cSChuck Lever 
76225a0866cSChuck Lever /*
76325a0866cSChuck Lever  * 2.2.17.  readdirargs
76425a0866cSChuck Lever  *
76525a0866cSChuck Lever  *	struct readdirargs {
76625a0866cSChuck Lever  *		fhandle dir;
76725a0866cSChuck Lever  *		nfscookie cookie;
76825a0866cSChuck Lever  *		unsigned count;
76925a0866cSChuck Lever  *	};
77025a0866cSChuck Lever  */
encode_readdirargs(struct xdr_stream * xdr,const struct nfs_readdirargs * args)77125a0866cSChuck Lever static void encode_readdirargs(struct xdr_stream *xdr,
77225a0866cSChuck Lever 			       const struct nfs_readdirargs *args)
77325a0866cSChuck Lever {
77425a0866cSChuck Lever 	__be32 *p;
77525a0866cSChuck Lever 
77625a0866cSChuck Lever 	encode_fhandle(xdr, args->fh);
77725a0866cSChuck Lever 
77825a0866cSChuck Lever 	p = xdr_reserve_space(xdr, 4 + 4);
77925a0866cSChuck Lever 	*p++ = cpu_to_be32(args->cookie);
78025a0866cSChuck Lever 	*p = cpu_to_be32(args->count);
78125a0866cSChuck Lever }
78225a0866cSChuck Lever 
nfs2_xdr_enc_readdirargs(struct rpc_rqst * req,struct xdr_stream * xdr,const void * data)7839f06c719SChuck Lever static void nfs2_xdr_enc_readdirargs(struct rpc_rqst *req,
7849f06c719SChuck Lever 				     struct xdr_stream *xdr,
785fcc85819SChristoph Hellwig 				     const void *data)
78625a0866cSChuck Lever {
787fcc85819SChristoph Hellwig 	const struct nfs_readdirargs *args = data;
788fcc85819SChristoph Hellwig 
7899f06c719SChuck Lever 	encode_readdirargs(xdr, args);
7909ed5af26STrond Myklebust 	rpc_prepare_reply_pages(req, args->pages, 0, args->count,
7919ed5af26STrond Myklebust 				NFS_readdirres_sz - NFS_pagepad_sz);
79225a0866cSChuck Lever }
79325a0866cSChuck Lever 
79425a0866cSChuck Lever /*
795661ad423SChuck Lever  * NFSv2 XDR decode functions
796661ad423SChuck Lever  *
797661ad423SChuck Lever  * NFSv2 result types are defined in section 2.2 of RFC 1094:
798661ad423SChuck Lever  * "NFS: Network File System Protocol Specification".
7991da177e4SLinus Torvalds  */
8001da177e4SLinus Torvalds 
nfs2_xdr_dec_stat(struct rpc_rqst * req,struct xdr_stream * xdr,void * __unused)801bf269551SChuck Lever static int nfs2_xdr_dec_stat(struct rpc_rqst *req, struct xdr_stream *xdr,
802f796f8b3SChuck Lever 			     void *__unused)
803f796f8b3SChuck Lever {
804f796f8b3SChuck Lever 	enum nfs_stat status;
805f796f8b3SChuck Lever 	int error;
806f796f8b3SChuck Lever 
807bf269551SChuck Lever 	error = decode_stat(xdr, &status);
808f796f8b3SChuck Lever 	if (unlikely(error))
809f796f8b3SChuck Lever 		goto out;
810f796f8b3SChuck Lever 	if (status != NFS_OK)
811f796f8b3SChuck Lever 		goto out_default;
812f796f8b3SChuck Lever out:
813f796f8b3SChuck Lever 	return error;
814f796f8b3SChuck Lever out_default:
815f796f8b3SChuck Lever 	return nfs_stat_to_errno(status);
816f796f8b3SChuck Lever }
817f796f8b3SChuck Lever 
nfs2_xdr_dec_attrstat(struct rpc_rqst * req,struct xdr_stream * xdr,void * result)818bf269551SChuck Lever static int nfs2_xdr_dec_attrstat(struct rpc_rqst *req, struct xdr_stream *xdr,
819fc016483SChristoph Hellwig 				 void *result)
820f796f8b3SChuck Lever {
821c207db2fSTrond Myklebust 	return decode_attrstat(xdr, result, NULL, rpc_rqst_userns(req));
822f796f8b3SChuck Lever }
823f796f8b3SChuck Lever 
nfs2_xdr_dec_diropres(struct rpc_rqst * req,struct xdr_stream * xdr,void * result)824bf269551SChuck Lever static int nfs2_xdr_dec_diropres(struct rpc_rqst *req, struct xdr_stream *xdr,
825fc016483SChristoph Hellwig 				 void *result)
826f796f8b3SChuck Lever {
827c207db2fSTrond Myklebust 	return decode_diropres(xdr, result, rpc_rqst_userns(req));
828f796f8b3SChuck Lever }
829f796f8b3SChuck Lever 
8301da177e4SLinus Torvalds /*
831f796f8b3SChuck Lever  * 2.2.6.  readlinkres
832f796f8b3SChuck Lever  *
833f796f8b3SChuck Lever  *	union readlinkres switch (stat status) {
834f796f8b3SChuck Lever  *	case NFS_OK:
835f796f8b3SChuck Lever  *		path data;
836f796f8b3SChuck Lever  *	default:
837f796f8b3SChuck Lever  *		void;
838f796f8b3SChuck Lever  *	};
839f796f8b3SChuck Lever  */
nfs2_xdr_dec_readlinkres(struct rpc_rqst * req,struct xdr_stream * xdr,void * __unused)840bf269551SChuck Lever static int nfs2_xdr_dec_readlinkres(struct rpc_rqst *req,
841bf269551SChuck Lever 				    struct xdr_stream *xdr, void *__unused)
842f796f8b3SChuck Lever {
843f796f8b3SChuck Lever 	enum nfs_stat status;
844f796f8b3SChuck Lever 	int error;
845f796f8b3SChuck Lever 
846bf269551SChuck Lever 	error = decode_stat(xdr, &status);
847f796f8b3SChuck Lever 	if (unlikely(error))
848f796f8b3SChuck Lever 		goto out;
849f796f8b3SChuck Lever 	if (status != NFS_OK)
850f796f8b3SChuck Lever 		goto out_default;
851bf269551SChuck Lever 	error = decode_path(xdr);
852f796f8b3SChuck Lever out:
853f796f8b3SChuck Lever 	return error;
854f796f8b3SChuck Lever out_default:
855f796f8b3SChuck Lever 	return nfs_stat_to_errno(status);
856f796f8b3SChuck Lever }
857f796f8b3SChuck Lever 
858f796f8b3SChuck Lever /*
859f796f8b3SChuck Lever  * 2.2.7.  readres
860f796f8b3SChuck Lever  *
861f796f8b3SChuck Lever  *	union readres switch (stat status) {
862f796f8b3SChuck Lever  *	case NFS_OK:
863f796f8b3SChuck Lever  *		fattr attributes;
864f796f8b3SChuck Lever  *		nfsdata data;
865f796f8b3SChuck Lever  *	default:
866f796f8b3SChuck Lever  *		void;
867f796f8b3SChuck Lever  *	};
868f796f8b3SChuck Lever  */
nfs2_xdr_dec_readres(struct rpc_rqst * req,struct xdr_stream * xdr,void * data)869bf269551SChuck Lever static int nfs2_xdr_dec_readres(struct rpc_rqst *req, struct xdr_stream *xdr,
870fc016483SChristoph Hellwig 				void *data)
871f796f8b3SChuck Lever {
872fc016483SChristoph Hellwig 	struct nfs_pgio_res *result = data;
873f796f8b3SChuck Lever 	enum nfs_stat status;
874f796f8b3SChuck Lever 	int error;
875f796f8b3SChuck Lever 
876bf269551SChuck Lever 	error = decode_stat(xdr, &status);
877f796f8b3SChuck Lever 	if (unlikely(error))
878f796f8b3SChuck Lever 		goto out;
879aabff4ddSPeng Tao 	result->op_status = status;
880f796f8b3SChuck Lever 	if (status != NFS_OK)
881f796f8b3SChuck Lever 		goto out_default;
882c207db2fSTrond Myklebust 	error = decode_fattr(xdr, result->fattr, rpc_rqst_userns(req));
883f796f8b3SChuck Lever 	if (unlikely(error))
884f796f8b3SChuck Lever 		goto out;
885bf269551SChuck Lever 	error = decode_nfsdata(xdr, result);
886f796f8b3SChuck Lever out:
887f796f8b3SChuck Lever 	return error;
888f796f8b3SChuck Lever out_default:
889f796f8b3SChuck Lever 	return nfs_stat_to_errno(status);
890f796f8b3SChuck Lever }
891f796f8b3SChuck Lever 
nfs2_xdr_dec_writeres(struct rpc_rqst * req,struct xdr_stream * xdr,void * data)892bf269551SChuck Lever static int nfs2_xdr_dec_writeres(struct rpc_rqst *req, struct xdr_stream *xdr,
893fc016483SChristoph Hellwig 				 void *data)
894f796f8b3SChuck Lever {
895fc016483SChristoph Hellwig 	struct nfs_pgio_res *result = data;
896fc016483SChristoph Hellwig 
897f796f8b3SChuck Lever 	/* All NFSv2 writes are "file sync" writes */
898f796f8b3SChuck Lever 	result->verf->committed = NFS_FILE_SYNC;
899c207db2fSTrond Myklebust 	return decode_attrstat(xdr, result->fattr, &result->op_status,
900c207db2fSTrond Myklebust 			rpc_rqst_userns(req));
901f796f8b3SChuck Lever }
902f796f8b3SChuck Lever 
903f796f8b3SChuck Lever /**
904f796f8b3SChuck Lever  * nfs2_decode_dirent - Decode a single NFSv2 directory entry stored in
905f796f8b3SChuck Lever  *                      the local page cache.
906f796f8b3SChuck Lever  * @xdr: XDR stream where entry resides
907f796f8b3SChuck Lever  * @entry: buffer to fill in with entry data
908f796f8b3SChuck Lever  * @plus: boolean indicating whether this should be a readdirplus entry
909f796f8b3SChuck Lever  *
910573c4e1eSChuck Lever  * Returns zero if successful, otherwise a negative errno value is
911573c4e1eSChuck Lever  * returned.
912f796f8b3SChuck Lever  *
913f796f8b3SChuck Lever  * This function is not invoked during READDIR reply decoding, but
914f796f8b3SChuck Lever  * rather whenever an application invokes the getdents(2) system call
915f796f8b3SChuck Lever  * on a directory already in our cache.
916f796f8b3SChuck Lever  *
917f796f8b3SChuck Lever  * 2.2.17.  entry
918f796f8b3SChuck Lever  *
919f796f8b3SChuck Lever  *	struct entry {
920f796f8b3SChuck Lever  *		unsigned	fileid;
921f796f8b3SChuck Lever  *		filename	name;
922f796f8b3SChuck Lever  *		nfscookie	cookie;
923f796f8b3SChuck Lever  *		entry		*nextentry;
924f796f8b3SChuck Lever  *	};
925f796f8b3SChuck Lever  */
nfs2_decode_dirent(struct xdr_stream * xdr,struct nfs_entry * entry,bool plus)926573c4e1eSChuck Lever int nfs2_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry,
927a7a3b1e9SBenjamin Coddington 		       bool plus)
928f796f8b3SChuck Lever {
929f796f8b3SChuck Lever 	__be32 *p;
930f796f8b3SChuck Lever 	int error;
931f796f8b3SChuck Lever 
932f796f8b3SChuck Lever 	p = xdr_inline_decode(xdr, 4);
933eb72f484SChuck Lever 	if (unlikely(!p))
934eb72f484SChuck Lever 		return -EAGAIN;
935f796f8b3SChuck Lever 	if (*p++ == xdr_zero) {
936f796f8b3SChuck Lever 		p = xdr_inline_decode(xdr, 4);
937eb72f484SChuck Lever 		if (unlikely(!p))
938eb72f484SChuck Lever 			return -EAGAIN;
939f796f8b3SChuck Lever 		if (*p++ == xdr_zero)
940573c4e1eSChuck Lever 			return -EAGAIN;
941f796f8b3SChuck Lever 		entry->eof = 1;
942573c4e1eSChuck Lever 		return -EBADCOOKIE;
943f796f8b3SChuck Lever 	}
944f796f8b3SChuck Lever 
945f796f8b3SChuck Lever 	p = xdr_inline_decode(xdr, 4);
946eb72f484SChuck Lever 	if (unlikely(!p))
947eb72f484SChuck Lever 		return -EAGAIN;
948f796f8b3SChuck Lever 	entry->ino = be32_to_cpup(p);
949f796f8b3SChuck Lever 
950f796f8b3SChuck Lever 	error = decode_filename_inline(xdr, &entry->name, &entry->len);
951f796f8b3SChuck Lever 	if (unlikely(error))
952*f67b55b6SBenjamin Coddington 		return error == -ENAMETOOLONG ? -ENAMETOOLONG : -EAGAIN;
953f796f8b3SChuck Lever 
954f796f8b3SChuck Lever 	/*
955f796f8b3SChuck Lever 	 * The type (size and byte order) of nfscookie isn't defined in
956f796f8b3SChuck Lever 	 * RFC 1094.  This implementation assumes that it's an XDR uint32.
957f796f8b3SChuck Lever 	 */
958f796f8b3SChuck Lever 	p = xdr_inline_decode(xdr, 4);
959eb72f484SChuck Lever 	if (unlikely(!p))
960eb72f484SChuck Lever 		return -EAGAIN;
961f796f8b3SChuck Lever 	entry->cookie = be32_to_cpup(p);
962f796f8b3SChuck Lever 
963f796f8b3SChuck Lever 	entry->d_type = DT_UNKNOWN;
964f796f8b3SChuck Lever 
965573c4e1eSChuck Lever 	return 0;
966f796f8b3SChuck Lever }
967f796f8b3SChuck Lever 
968f796f8b3SChuck Lever /*
969f796f8b3SChuck Lever  * 2.2.17.  readdirres
970f796f8b3SChuck Lever  *
971f796f8b3SChuck Lever  *	union readdirres switch (stat status) {
972f796f8b3SChuck Lever  *	case NFS_OK:
973f796f8b3SChuck Lever  *		struct {
974f796f8b3SChuck Lever  *			entry *entries;
975f796f8b3SChuck Lever  *			bool eof;
976f796f8b3SChuck Lever  *		} readdirok;
977f796f8b3SChuck Lever  *	default:
978f796f8b3SChuck Lever  *		void;
979f796f8b3SChuck Lever  *	};
980f796f8b3SChuck Lever  *
981f796f8b3SChuck Lever  * Read the directory contents into the page cache, but don't
982f796f8b3SChuck Lever  * touch them.  The actual decoding is done by nfs2_decode_dirent()
983f796f8b3SChuck Lever  * during subsequent nfs_readdir() calls.
984f796f8b3SChuck Lever  */
decode_readdirok(struct xdr_stream * xdr)985f796f8b3SChuck Lever static int decode_readdirok(struct xdr_stream *xdr)
986f796f8b3SChuck Lever {
98764bd577eSTrond Myklebust 	return xdr_read_pages(xdr, xdr->buf->page_len);
988f796f8b3SChuck Lever }
989f796f8b3SChuck Lever 
nfs2_xdr_dec_readdirres(struct rpc_rqst * req,struct xdr_stream * xdr,void * __unused)990bf269551SChuck Lever static int nfs2_xdr_dec_readdirres(struct rpc_rqst *req,
991bf269551SChuck Lever 				   struct xdr_stream *xdr, void *__unused)
992f796f8b3SChuck Lever {
993f796f8b3SChuck Lever 	enum nfs_stat status;
994f796f8b3SChuck Lever 	int error;
995f796f8b3SChuck Lever 
996bf269551SChuck Lever 	error = decode_stat(xdr, &status);
997f796f8b3SChuck Lever 	if (unlikely(error))
998f796f8b3SChuck Lever 		goto out;
999f796f8b3SChuck Lever 	if (status != NFS_OK)
1000f796f8b3SChuck Lever 		goto out_default;
1001bf269551SChuck Lever 	error = decode_readdirok(xdr);
1002f796f8b3SChuck Lever out:
1003f796f8b3SChuck Lever 	return error;
1004f796f8b3SChuck Lever out_default:
1005f796f8b3SChuck Lever 	return nfs_stat_to_errno(status);
1006f796f8b3SChuck Lever }
1007f796f8b3SChuck Lever 
10081da177e4SLinus Torvalds /*
1009f796f8b3SChuck Lever  * 2.2.18.  statfsres
1010f796f8b3SChuck Lever  *
1011f796f8b3SChuck Lever  *	union statfsres (stat status) {
1012f796f8b3SChuck Lever  *	case NFS_OK:
1013f796f8b3SChuck Lever  *		struct {
1014f796f8b3SChuck Lever  *			unsigned tsize;
1015f796f8b3SChuck Lever  *			unsigned bsize;
1016f796f8b3SChuck Lever  *			unsigned blocks;
1017f796f8b3SChuck Lever  *			unsigned bfree;
1018f796f8b3SChuck Lever  *			unsigned bavail;
1019f796f8b3SChuck Lever  *		} info;
1020f796f8b3SChuck Lever  *	default:
1021f796f8b3SChuck Lever  *		void;
1022f796f8b3SChuck Lever  *	};
1023f796f8b3SChuck Lever  */
decode_info(struct xdr_stream * xdr,struct nfs2_fsstat * result)1024f796f8b3SChuck Lever static int decode_info(struct xdr_stream *xdr, struct nfs2_fsstat *result)
1025f796f8b3SChuck Lever {
1026f796f8b3SChuck Lever 	__be32 *p;
1027f796f8b3SChuck Lever 
1028f796f8b3SChuck Lever 	p = xdr_inline_decode(xdr, NFS_info_sz << 2);
1029eb72f484SChuck Lever 	if (unlikely(!p))
1030eb72f484SChuck Lever 		return -EIO;
1031f796f8b3SChuck Lever 	result->tsize  = be32_to_cpup(p++);
1032f796f8b3SChuck Lever 	result->bsize  = be32_to_cpup(p++);
1033f796f8b3SChuck Lever 	result->blocks = be32_to_cpup(p++);
1034f796f8b3SChuck Lever 	result->bfree  = be32_to_cpup(p++);
1035f796f8b3SChuck Lever 	result->bavail = be32_to_cpup(p);
1036f796f8b3SChuck Lever 	return 0;
1037f796f8b3SChuck Lever }
1038f796f8b3SChuck Lever 
nfs2_xdr_dec_statfsres(struct rpc_rqst * req,struct xdr_stream * xdr,void * result)1039bf269551SChuck Lever static int nfs2_xdr_dec_statfsres(struct rpc_rqst *req, struct xdr_stream *xdr,
1040fc016483SChristoph Hellwig 				  void *result)
1041f796f8b3SChuck Lever {
1042f796f8b3SChuck Lever 	enum nfs_stat status;
1043f796f8b3SChuck Lever 	int error;
1044f796f8b3SChuck Lever 
1045bf269551SChuck Lever 	error = decode_stat(xdr, &status);
1046f796f8b3SChuck Lever 	if (unlikely(error))
1047f796f8b3SChuck Lever 		goto out;
1048f796f8b3SChuck Lever 	if (status != NFS_OK)
1049f796f8b3SChuck Lever 		goto out_default;
1050bf269551SChuck Lever 	error = decode_info(xdr, result);
1051f796f8b3SChuck Lever out:
1052f796f8b3SChuck Lever 	return error;
1053f796f8b3SChuck Lever out_default:
1054f796f8b3SChuck Lever 	return nfs_stat_to_errno(status);
1055f796f8b3SChuck Lever }
1056f796f8b3SChuck Lever 
1057f796f8b3SChuck Lever 
1058f796f8b3SChuck Lever /*
10591da177e4SLinus Torvalds  * We need to translate between nfs status return values and
10601da177e4SLinus Torvalds  * the local errno values which may not be the same.
10611da177e4SLinus Torvalds  */
106285828493SChuck Lever static const struct {
10631da177e4SLinus Torvalds 	int stat;
10641da177e4SLinus Torvalds 	int errno;
10651da177e4SLinus Torvalds } nfs_errtbl[] = {
10661da177e4SLinus Torvalds 	{ NFS_OK,		0		},
1067856dff3dSBenny Halevy 	{ NFSERR_PERM,		-EPERM		},
1068856dff3dSBenny Halevy 	{ NFSERR_NOENT,		-ENOENT		},
1069856dff3dSBenny Halevy 	{ NFSERR_IO,		-errno_NFSERR_IO},
1070856dff3dSBenny Halevy 	{ NFSERR_NXIO,		-ENXIO		},
1071856dff3dSBenny Halevy /*	{ NFSERR_EAGAIN,	-EAGAIN		}, */
1072856dff3dSBenny Halevy 	{ NFSERR_ACCES,		-EACCES		},
1073856dff3dSBenny Halevy 	{ NFSERR_EXIST,		-EEXIST		},
1074856dff3dSBenny Halevy 	{ NFSERR_XDEV,		-EXDEV		},
1075856dff3dSBenny Halevy 	{ NFSERR_NODEV,		-ENODEV		},
1076856dff3dSBenny Halevy 	{ NFSERR_NOTDIR,	-ENOTDIR	},
1077856dff3dSBenny Halevy 	{ NFSERR_ISDIR,		-EISDIR		},
1078856dff3dSBenny Halevy 	{ NFSERR_INVAL,		-EINVAL		},
1079856dff3dSBenny Halevy 	{ NFSERR_FBIG,		-EFBIG		},
1080856dff3dSBenny Halevy 	{ NFSERR_NOSPC,		-ENOSPC		},
1081856dff3dSBenny Halevy 	{ NFSERR_ROFS,		-EROFS		},
1082856dff3dSBenny Halevy 	{ NFSERR_MLINK,		-EMLINK		},
1083856dff3dSBenny Halevy 	{ NFSERR_NAMETOOLONG,	-ENAMETOOLONG	},
1084856dff3dSBenny Halevy 	{ NFSERR_NOTEMPTY,	-ENOTEMPTY	},
1085856dff3dSBenny Halevy 	{ NFSERR_DQUOT,		-EDQUOT		},
1086856dff3dSBenny Halevy 	{ NFSERR_STALE,		-ESTALE		},
1087856dff3dSBenny Halevy 	{ NFSERR_REMOTE,	-EREMOTE	},
10881da177e4SLinus Torvalds #ifdef EWFLUSH
1089856dff3dSBenny Halevy 	{ NFSERR_WFLUSH,	-EWFLUSH	},
10901da177e4SLinus Torvalds #endif
1091856dff3dSBenny Halevy 	{ NFSERR_BADHANDLE,	-EBADHANDLE	},
1092856dff3dSBenny Halevy 	{ NFSERR_NOT_SYNC,	-ENOTSYNC	},
1093856dff3dSBenny Halevy 	{ NFSERR_BAD_COOKIE,	-EBADCOOKIE	},
1094856dff3dSBenny Halevy 	{ NFSERR_NOTSUPP,	-ENOTSUPP	},
1095856dff3dSBenny Halevy 	{ NFSERR_TOOSMALL,	-ETOOSMALL	},
1096fdcb4577STrond Myklebust 	{ NFSERR_SERVERFAULT,	-EREMOTEIO	},
1097856dff3dSBenny Halevy 	{ NFSERR_BADTYPE,	-EBADTYPE	},
1098856dff3dSBenny Halevy 	{ NFSERR_JUKEBOX,	-EJUKEBOX	},
1099856dff3dSBenny Halevy 	{ -1,			-EIO		}
11001da177e4SLinus Torvalds };
11011da177e4SLinus Torvalds 
110285828493SChuck Lever /**
110385828493SChuck Lever  * nfs_stat_to_errno - convert an NFS status code to a local errno
110485828493SChuck Lever  * @status: NFS status code to convert
110585828493SChuck Lever  *
110685828493SChuck Lever  * Returns a local errno value, or -EIO if the NFS status code is
110785828493SChuck Lever  * not recognized.  This function is used jointly by NFSv2 and NFSv3.
11081da177e4SLinus Torvalds  */
nfs_stat_to_errno(enum nfs_stat status)11095e7e5a0dSBryan Schumaker static int nfs_stat_to_errno(enum nfs_stat status)
11101da177e4SLinus Torvalds {
11111da177e4SLinus Torvalds 	int i;
11121da177e4SLinus Torvalds 
11131da177e4SLinus Torvalds 	for (i = 0; nfs_errtbl[i].stat != -1; i++) {
111485828493SChuck Lever 		if (nfs_errtbl[i].stat == (int)status)
11151da177e4SLinus Torvalds 			return nfs_errtbl[i].errno;
11161da177e4SLinus Torvalds 	}
111785828493SChuck Lever 	dprintk("NFS: Unrecognized nfs status value: %u\n", status);
11181da177e4SLinus Torvalds 	return nfs_errtbl[i].errno;
11191da177e4SLinus Torvalds }
11201da177e4SLinus Torvalds 
11211da177e4SLinus Torvalds #define PROC(proc, argtype, restype, timer)				\
11221da177e4SLinus Torvalds [NFSPROC_##proc] = {							\
11231da177e4SLinus Torvalds 	.p_proc	    =  NFSPROC_##proc,					\
1124fcc85819SChristoph Hellwig 	.p_encode   =  nfs2_xdr_enc_##argtype,				\
1125fc016483SChristoph Hellwig 	.p_decode   =  nfs2_xdr_dec_##restype,				\
11262bea90d4SChuck Lever 	.p_arglen   =  NFS_##argtype##_sz,				\
11272bea90d4SChuck Lever 	.p_replen   =  NFS_##restype##_sz,				\
1128cc0175c1SChuck Lever 	.p_timer    =  timer,						\
1129cc0175c1SChuck Lever 	.p_statidx  =  NFSPROC_##proc,					\
1130cc0175c1SChuck Lever 	.p_name     =  #proc,						\
11311da177e4SLinus Torvalds 	}
1132511e936bSChristoph Hellwig const struct rpc_procinfo nfs_procedures[] = {
11331da177e4SLinus Torvalds 	PROC(GETATTR,	fhandle,	attrstat,	1),
11341da177e4SLinus Torvalds 	PROC(SETATTR,	sattrargs,	attrstat,	0),
11351da177e4SLinus Torvalds 	PROC(LOOKUP,	diropargs,	diropres,	2),
11361da177e4SLinus Torvalds 	PROC(READLINK,	readlinkargs,	readlinkres,	3),
11371da177e4SLinus Torvalds 	PROC(READ,	readargs,	readres,	3),
11381da177e4SLinus Torvalds 	PROC(WRITE,	writeargs,	writeres,	4),
11391da177e4SLinus Torvalds 	PROC(CREATE,	createargs,	diropres,	0),
11404fdc17b2STrond Myklebust 	PROC(REMOVE,	removeargs,	stat,		0),
11411da177e4SLinus Torvalds 	PROC(RENAME,	renameargs,	stat,		0),
11421da177e4SLinus Torvalds 	PROC(LINK,	linkargs,	stat,		0),
11431da177e4SLinus Torvalds 	PROC(SYMLINK,	symlinkargs,	stat,		0),
11441da177e4SLinus Torvalds 	PROC(MKDIR,	createargs,	diropres,	0),
11451da177e4SLinus Torvalds 	PROC(RMDIR,	diropargs,	stat,		0),
11461da177e4SLinus Torvalds 	PROC(READDIR,	readdirargs,	readdirres,	3),
11471da177e4SLinus Torvalds 	PROC(STATFS,	fhandle,	statfsres,	0),
11481da177e4SLinus Torvalds };
11491da177e4SLinus Torvalds 
1150c551858aSChristoph Hellwig static unsigned int nfs_version2_counts[ARRAY_SIZE(nfs_procedures)];
1151a613fa16STrond Myklebust const struct rpc_version nfs_version2 = {
11521da177e4SLinus Torvalds 	.number			= 2,
1153e8c96f8cSTobias Klauser 	.nrprocs		= ARRAY_SIZE(nfs_procedures),
1154c551858aSChristoph Hellwig 	.procs			= nfs_procedures,
1155c551858aSChristoph Hellwig 	.counts			= nfs_version2_counts,
11561da177e4SLinus Torvalds };
1157