162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * linux/fs/nfs/nfs2xdr.c
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * XDR functions to encode/decode NFS RPC arguments and results.
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * Copyright (C) 1992, 1993, 1994  Rick Sladkey
862306a36Sopenharmony_ci * Copyright (C) 1996 Olaf Kirch
962306a36Sopenharmony_ci * 04 Aug 1998  Ion Badulescu <ionut@cs.columbia.edu>
1062306a36Sopenharmony_ci * 		FIFO's need special handling in NFSv2
1162306a36Sopenharmony_ci */
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci#include <linux/param.h>
1462306a36Sopenharmony_ci#include <linux/time.h>
1562306a36Sopenharmony_ci#include <linux/mm.h>
1662306a36Sopenharmony_ci#include <linux/errno.h>
1762306a36Sopenharmony_ci#include <linux/string.h>
1862306a36Sopenharmony_ci#include <linux/in.h>
1962306a36Sopenharmony_ci#include <linux/pagemap.h>
2062306a36Sopenharmony_ci#include <linux/proc_fs.h>
2162306a36Sopenharmony_ci#include <linux/sunrpc/clnt.h>
2262306a36Sopenharmony_ci#include <linux/nfs.h>
2362306a36Sopenharmony_ci#include <linux/nfs2.h>
2462306a36Sopenharmony_ci#include <linux/nfs_fs.h>
2562306a36Sopenharmony_ci#include "nfstrace.h"
2662306a36Sopenharmony_ci#include "internal.h"
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci#define NFSDBG_FACILITY		NFSDBG_XDR
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci/* Mapping from NFS error code to "errno" error code. */
3162306a36Sopenharmony_ci#define errno_NFSERR_IO		EIO
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci/*
3462306a36Sopenharmony_ci * Declare the space requirements for NFS arguments and replies as
3562306a36Sopenharmony_ci * number of 32bit-words
3662306a36Sopenharmony_ci */
3762306a36Sopenharmony_ci#define NFS_pagepad_sz		(1) /* Page padding */
3862306a36Sopenharmony_ci#define NFS_fhandle_sz		(8)
3962306a36Sopenharmony_ci#define NFS_sattr_sz		(8)
4062306a36Sopenharmony_ci#define NFS_filename_sz		(1+(NFS2_MAXNAMLEN>>2))
4162306a36Sopenharmony_ci#define NFS_path_sz		(1+(NFS2_MAXPATHLEN>>2))
4262306a36Sopenharmony_ci#define NFS_fattr_sz		(17)
4362306a36Sopenharmony_ci#define NFS_info_sz		(5)
4462306a36Sopenharmony_ci#define NFS_entry_sz		(NFS_filename_sz+3)
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci#define NFS_diropargs_sz	(NFS_fhandle_sz+NFS_filename_sz)
4762306a36Sopenharmony_ci#define NFS_removeargs_sz	(NFS_fhandle_sz+NFS_filename_sz)
4862306a36Sopenharmony_ci#define NFS_sattrargs_sz	(NFS_fhandle_sz+NFS_sattr_sz)
4962306a36Sopenharmony_ci#define NFS_readlinkargs_sz	(NFS_fhandle_sz)
5062306a36Sopenharmony_ci#define NFS_readargs_sz		(NFS_fhandle_sz+3)
5162306a36Sopenharmony_ci#define NFS_writeargs_sz	(NFS_fhandle_sz+4)
5262306a36Sopenharmony_ci#define NFS_createargs_sz	(NFS_diropargs_sz+NFS_sattr_sz)
5362306a36Sopenharmony_ci#define NFS_renameargs_sz	(NFS_diropargs_sz+NFS_diropargs_sz)
5462306a36Sopenharmony_ci#define NFS_linkargs_sz		(NFS_fhandle_sz+NFS_diropargs_sz)
5562306a36Sopenharmony_ci#define NFS_symlinkargs_sz	(NFS_diropargs_sz+1+NFS_sattr_sz)
5662306a36Sopenharmony_ci#define NFS_readdirargs_sz	(NFS_fhandle_sz+2)
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci#define NFS_attrstat_sz		(1+NFS_fattr_sz)
5962306a36Sopenharmony_ci#define NFS_diropres_sz		(1+NFS_fhandle_sz+NFS_fattr_sz)
6062306a36Sopenharmony_ci#define NFS_readlinkres_sz	(2+NFS_pagepad_sz)
6162306a36Sopenharmony_ci#define NFS_readres_sz		(1+NFS_fattr_sz+1+NFS_pagepad_sz)
6262306a36Sopenharmony_ci#define NFS_writeres_sz         (NFS_attrstat_sz)
6362306a36Sopenharmony_ci#define NFS_stat_sz		(1)
6462306a36Sopenharmony_ci#define NFS_readdirres_sz	(1+NFS_pagepad_sz)
6562306a36Sopenharmony_ci#define NFS_statfsres_sz	(1+NFS_info_sz)
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_cistatic int nfs_stat_to_errno(enum nfs_stat);
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci/*
7062306a36Sopenharmony_ci * Encode/decode NFSv2 basic data types
7162306a36Sopenharmony_ci *
7262306a36Sopenharmony_ci * Basic NFSv2 data types are defined in section 2.3 of RFC 1094:
7362306a36Sopenharmony_ci * "NFS: Network File System Protocol Specification".
7462306a36Sopenharmony_ci *
7562306a36Sopenharmony_ci * Not all basic data types have their own encoding and decoding
7662306a36Sopenharmony_ci * functions.  For run-time efficiency, some data types are encoded
7762306a36Sopenharmony_ci * or decoded inline.
7862306a36Sopenharmony_ci */
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_cistatic struct user_namespace *rpc_userns(const struct rpc_clnt *clnt)
8162306a36Sopenharmony_ci{
8262306a36Sopenharmony_ci	if (clnt && clnt->cl_cred)
8362306a36Sopenharmony_ci		return clnt->cl_cred->user_ns;
8462306a36Sopenharmony_ci	return &init_user_ns;
8562306a36Sopenharmony_ci}
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_cistatic struct user_namespace *rpc_rqst_userns(const struct rpc_rqst *rqstp)
8862306a36Sopenharmony_ci{
8962306a36Sopenharmony_ci	if (rqstp->rq_task)
9062306a36Sopenharmony_ci		return rpc_userns(rqstp->rq_task->tk_client);
9162306a36Sopenharmony_ci	return &init_user_ns;
9262306a36Sopenharmony_ci}
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci/*
9562306a36Sopenharmony_ci *	typedef opaque	nfsdata<>;
9662306a36Sopenharmony_ci */
9762306a36Sopenharmony_cistatic int decode_nfsdata(struct xdr_stream *xdr, struct nfs_pgio_res *result)
9862306a36Sopenharmony_ci{
9962306a36Sopenharmony_ci	u32 recvd, count;
10062306a36Sopenharmony_ci	__be32 *p;
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_ci	p = xdr_inline_decode(xdr, 4);
10362306a36Sopenharmony_ci	if (unlikely(!p))
10462306a36Sopenharmony_ci		return -EIO;
10562306a36Sopenharmony_ci	count = be32_to_cpup(p);
10662306a36Sopenharmony_ci	recvd = xdr_read_pages(xdr, count);
10762306a36Sopenharmony_ci	if (unlikely(count > recvd))
10862306a36Sopenharmony_ci		goto out_cheating;
10962306a36Sopenharmony_ciout:
11062306a36Sopenharmony_ci	result->eof = 0;	/* NFSv2 does not pass EOF flag on the wire. */
11162306a36Sopenharmony_ci	result->count = count;
11262306a36Sopenharmony_ci	return count;
11362306a36Sopenharmony_ciout_cheating:
11462306a36Sopenharmony_ci	dprintk("NFS: server cheating in read result: "
11562306a36Sopenharmony_ci		"count %u > recvd %u\n", count, recvd);
11662306a36Sopenharmony_ci	count = recvd;
11762306a36Sopenharmony_ci	goto out;
11862306a36Sopenharmony_ci}
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci/*
12162306a36Sopenharmony_ci *	enum stat {
12262306a36Sopenharmony_ci *		NFS_OK = 0,
12362306a36Sopenharmony_ci *		NFSERR_PERM = 1,
12462306a36Sopenharmony_ci *		NFSERR_NOENT = 2,
12562306a36Sopenharmony_ci *		NFSERR_IO = 5,
12662306a36Sopenharmony_ci *		NFSERR_NXIO = 6,
12762306a36Sopenharmony_ci *		NFSERR_ACCES = 13,
12862306a36Sopenharmony_ci *		NFSERR_EXIST = 17,
12962306a36Sopenharmony_ci *		NFSERR_NODEV = 19,
13062306a36Sopenharmony_ci *		NFSERR_NOTDIR = 20,
13162306a36Sopenharmony_ci *		NFSERR_ISDIR = 21,
13262306a36Sopenharmony_ci *		NFSERR_FBIG = 27,
13362306a36Sopenharmony_ci *		NFSERR_NOSPC = 28,
13462306a36Sopenharmony_ci *		NFSERR_ROFS = 30,
13562306a36Sopenharmony_ci *		NFSERR_NAMETOOLONG = 63,
13662306a36Sopenharmony_ci *		NFSERR_NOTEMPTY = 66,
13762306a36Sopenharmony_ci *		NFSERR_DQUOT = 69,
13862306a36Sopenharmony_ci *		NFSERR_STALE = 70,
13962306a36Sopenharmony_ci *		NFSERR_WFLUSH = 99
14062306a36Sopenharmony_ci *	};
14162306a36Sopenharmony_ci */
14262306a36Sopenharmony_cistatic int decode_stat(struct xdr_stream *xdr, enum nfs_stat *status)
14362306a36Sopenharmony_ci{
14462306a36Sopenharmony_ci	__be32 *p;
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci	p = xdr_inline_decode(xdr, 4);
14762306a36Sopenharmony_ci	if (unlikely(!p))
14862306a36Sopenharmony_ci		return -EIO;
14962306a36Sopenharmony_ci	if (unlikely(*p != cpu_to_be32(NFS_OK)))
15062306a36Sopenharmony_ci		goto out_status;
15162306a36Sopenharmony_ci	*status = 0;
15262306a36Sopenharmony_ci	return 0;
15362306a36Sopenharmony_ciout_status:
15462306a36Sopenharmony_ci	*status = be32_to_cpup(p);
15562306a36Sopenharmony_ci	trace_nfs_xdr_status(xdr, (int)*status);
15662306a36Sopenharmony_ci	return 0;
15762306a36Sopenharmony_ci}
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci/*
16062306a36Sopenharmony_ci * 2.3.2.  ftype
16162306a36Sopenharmony_ci *
16262306a36Sopenharmony_ci *	enum ftype {
16362306a36Sopenharmony_ci *		NFNON = 0,
16462306a36Sopenharmony_ci *		NFREG = 1,
16562306a36Sopenharmony_ci *		NFDIR = 2,
16662306a36Sopenharmony_ci *		NFBLK = 3,
16762306a36Sopenharmony_ci *		NFCHR = 4,
16862306a36Sopenharmony_ci *		NFLNK = 5
16962306a36Sopenharmony_ci *	};
17062306a36Sopenharmony_ci *
17162306a36Sopenharmony_ci */
17262306a36Sopenharmony_cistatic __be32 *xdr_decode_ftype(__be32 *p, u32 *type)
17362306a36Sopenharmony_ci{
17462306a36Sopenharmony_ci	*type = be32_to_cpup(p++);
17562306a36Sopenharmony_ci	if (unlikely(*type > NF2FIFO))
17662306a36Sopenharmony_ci		*type = NFBAD;
17762306a36Sopenharmony_ci	return p;
17862306a36Sopenharmony_ci}
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ci/*
18162306a36Sopenharmony_ci * 2.3.3.  fhandle
18262306a36Sopenharmony_ci *
18362306a36Sopenharmony_ci *	typedef opaque fhandle[FHSIZE];
18462306a36Sopenharmony_ci */
18562306a36Sopenharmony_cistatic void encode_fhandle(struct xdr_stream *xdr, const struct nfs_fh *fh)
18662306a36Sopenharmony_ci{
18762306a36Sopenharmony_ci	__be32 *p;
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci	p = xdr_reserve_space(xdr, NFS2_FHSIZE);
19062306a36Sopenharmony_ci	memcpy(p, fh->data, NFS2_FHSIZE);
19162306a36Sopenharmony_ci}
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_cistatic int decode_fhandle(struct xdr_stream *xdr, struct nfs_fh *fh)
19462306a36Sopenharmony_ci{
19562306a36Sopenharmony_ci	__be32 *p;
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci	p = xdr_inline_decode(xdr, NFS2_FHSIZE);
19862306a36Sopenharmony_ci	if (unlikely(!p))
19962306a36Sopenharmony_ci		return -EIO;
20062306a36Sopenharmony_ci	fh->size = NFS2_FHSIZE;
20162306a36Sopenharmony_ci	memcpy(fh->data, p, NFS2_FHSIZE);
20262306a36Sopenharmony_ci	return 0;
20362306a36Sopenharmony_ci}
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_ci/*
20662306a36Sopenharmony_ci * 2.3.4.  timeval
20762306a36Sopenharmony_ci *
20862306a36Sopenharmony_ci *	struct timeval {
20962306a36Sopenharmony_ci *		unsigned int seconds;
21062306a36Sopenharmony_ci *		unsigned int useconds;
21162306a36Sopenharmony_ci *	};
21262306a36Sopenharmony_ci */
21362306a36Sopenharmony_cistatic __be32 *xdr_encode_time(__be32 *p, const struct timespec64 *timep)
21462306a36Sopenharmony_ci{
21562306a36Sopenharmony_ci	*p++ = cpu_to_be32((u32)timep->tv_sec);
21662306a36Sopenharmony_ci	if (timep->tv_nsec != 0)
21762306a36Sopenharmony_ci		*p++ = cpu_to_be32(timep->tv_nsec / NSEC_PER_USEC);
21862306a36Sopenharmony_ci	else
21962306a36Sopenharmony_ci		*p++ = cpu_to_be32(0);
22062306a36Sopenharmony_ci	return p;
22162306a36Sopenharmony_ci}
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_ci/*
22462306a36Sopenharmony_ci * Passing the invalid value useconds=1000000 is a Sun convention for
22562306a36Sopenharmony_ci * "set to current server time".  It's needed to make permissions checks
22662306a36Sopenharmony_ci * for the "touch" program across v2 mounts to Solaris and Irix servers
22762306a36Sopenharmony_ci * work correctly.  See description of sattr in section 6.1 of "NFS
22862306a36Sopenharmony_ci * Illustrated" by Brent Callaghan, Addison-Wesley, ISBN 0-201-32750-5.
22962306a36Sopenharmony_ci */
23062306a36Sopenharmony_cistatic __be32 *xdr_encode_current_server_time(__be32 *p,
23162306a36Sopenharmony_ci					      const struct timespec64 *timep)
23262306a36Sopenharmony_ci{
23362306a36Sopenharmony_ci	*p++ = cpu_to_be32(timep->tv_sec);
23462306a36Sopenharmony_ci	*p++ = cpu_to_be32(1000000);
23562306a36Sopenharmony_ci	return p;
23662306a36Sopenharmony_ci}
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_cistatic __be32 *xdr_decode_time(__be32 *p, struct timespec64 *timep)
23962306a36Sopenharmony_ci{
24062306a36Sopenharmony_ci	timep->tv_sec = be32_to_cpup(p++);
24162306a36Sopenharmony_ci	timep->tv_nsec = be32_to_cpup(p++) * NSEC_PER_USEC;
24262306a36Sopenharmony_ci	return p;
24362306a36Sopenharmony_ci}
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci/*
24662306a36Sopenharmony_ci * 2.3.5.  fattr
24762306a36Sopenharmony_ci *
24862306a36Sopenharmony_ci *	struct fattr {
24962306a36Sopenharmony_ci *		ftype		type;
25062306a36Sopenharmony_ci *		unsigned int	mode;
25162306a36Sopenharmony_ci *		unsigned int	nlink;
25262306a36Sopenharmony_ci *		unsigned int	uid;
25362306a36Sopenharmony_ci *		unsigned int	gid;
25462306a36Sopenharmony_ci *		unsigned int	size;
25562306a36Sopenharmony_ci *		unsigned int	blocksize;
25662306a36Sopenharmony_ci *		unsigned int	rdev;
25762306a36Sopenharmony_ci *		unsigned int	blocks;
25862306a36Sopenharmony_ci *		unsigned int	fsid;
25962306a36Sopenharmony_ci *		unsigned int	fileid;
26062306a36Sopenharmony_ci *		timeval		atime;
26162306a36Sopenharmony_ci *		timeval		mtime;
26262306a36Sopenharmony_ci *		timeval		ctime;
26362306a36Sopenharmony_ci *	};
26462306a36Sopenharmony_ci *
26562306a36Sopenharmony_ci */
26662306a36Sopenharmony_cistatic int decode_fattr(struct xdr_stream *xdr, struct nfs_fattr *fattr,
26762306a36Sopenharmony_ci		struct user_namespace *userns)
26862306a36Sopenharmony_ci{
26962306a36Sopenharmony_ci	u32 rdev, type;
27062306a36Sopenharmony_ci	__be32 *p;
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_ci	p = xdr_inline_decode(xdr, NFS_fattr_sz << 2);
27362306a36Sopenharmony_ci	if (unlikely(!p))
27462306a36Sopenharmony_ci		return -EIO;
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ci	fattr->valid |= NFS_ATTR_FATTR_V2;
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci	p = xdr_decode_ftype(p, &type);
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_ci	fattr->mode = be32_to_cpup(p++);
28162306a36Sopenharmony_ci	fattr->nlink = be32_to_cpup(p++);
28262306a36Sopenharmony_ci	fattr->uid = make_kuid(userns, be32_to_cpup(p++));
28362306a36Sopenharmony_ci	if (!uid_valid(fattr->uid))
28462306a36Sopenharmony_ci		goto out_uid;
28562306a36Sopenharmony_ci	fattr->gid = make_kgid(userns, be32_to_cpup(p++));
28662306a36Sopenharmony_ci	if (!gid_valid(fattr->gid))
28762306a36Sopenharmony_ci		goto out_gid;
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ci	fattr->size = be32_to_cpup(p++);
29062306a36Sopenharmony_ci	fattr->du.nfs2.blocksize = be32_to_cpup(p++);
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ci	rdev = be32_to_cpup(p++);
29362306a36Sopenharmony_ci	fattr->rdev = new_decode_dev(rdev);
29462306a36Sopenharmony_ci	if (type == (u32)NFCHR && rdev == (u32)NFS2_FIFO_DEV) {
29562306a36Sopenharmony_ci		fattr->mode = (fattr->mode & ~S_IFMT) | S_IFIFO;
29662306a36Sopenharmony_ci		fattr->rdev = 0;
29762306a36Sopenharmony_ci	}
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ci	fattr->du.nfs2.blocks = be32_to_cpup(p++);
30062306a36Sopenharmony_ci	fattr->fsid.major = be32_to_cpup(p++);
30162306a36Sopenharmony_ci	fattr->fsid.minor = 0;
30262306a36Sopenharmony_ci	fattr->fileid = be32_to_cpup(p++);
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_ci	p = xdr_decode_time(p, &fattr->atime);
30562306a36Sopenharmony_ci	p = xdr_decode_time(p, &fattr->mtime);
30662306a36Sopenharmony_ci	xdr_decode_time(p, &fattr->ctime);
30762306a36Sopenharmony_ci	fattr->change_attr = nfs_timespec_to_change_attr(&fattr->ctime);
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_ci	return 0;
31062306a36Sopenharmony_ciout_uid:
31162306a36Sopenharmony_ci	dprintk("NFS: returned invalid uid\n");
31262306a36Sopenharmony_ci	return -EINVAL;
31362306a36Sopenharmony_ciout_gid:
31462306a36Sopenharmony_ci	dprintk("NFS: returned invalid gid\n");
31562306a36Sopenharmony_ci	return -EINVAL;
31662306a36Sopenharmony_ci}
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_ci/*
31962306a36Sopenharmony_ci * 2.3.6.  sattr
32062306a36Sopenharmony_ci *
32162306a36Sopenharmony_ci *	struct sattr {
32262306a36Sopenharmony_ci *		unsigned int	mode;
32362306a36Sopenharmony_ci *		unsigned int	uid;
32462306a36Sopenharmony_ci *		unsigned int	gid;
32562306a36Sopenharmony_ci *		unsigned int	size;
32662306a36Sopenharmony_ci *		timeval		atime;
32762306a36Sopenharmony_ci *		timeval		mtime;
32862306a36Sopenharmony_ci *	};
32962306a36Sopenharmony_ci */
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_ci#define NFS2_SATTR_NOT_SET	(0xffffffff)
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_cistatic __be32 *xdr_time_not_set(__be32 *p)
33462306a36Sopenharmony_ci{
33562306a36Sopenharmony_ci	*p++ = cpu_to_be32(NFS2_SATTR_NOT_SET);
33662306a36Sopenharmony_ci	*p++ = cpu_to_be32(NFS2_SATTR_NOT_SET);
33762306a36Sopenharmony_ci	return p;
33862306a36Sopenharmony_ci}
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_cistatic void encode_sattr(struct xdr_stream *xdr, const struct iattr *attr,
34162306a36Sopenharmony_ci		struct user_namespace *userns)
34262306a36Sopenharmony_ci{
34362306a36Sopenharmony_ci	__be32 *p;
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci	p = xdr_reserve_space(xdr, NFS_sattr_sz << 2);
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_ci	if (attr->ia_valid & ATTR_MODE)
34862306a36Sopenharmony_ci		*p++ = cpu_to_be32(attr->ia_mode);
34962306a36Sopenharmony_ci	else
35062306a36Sopenharmony_ci		*p++ = cpu_to_be32(NFS2_SATTR_NOT_SET);
35162306a36Sopenharmony_ci	if (attr->ia_valid & ATTR_UID)
35262306a36Sopenharmony_ci		*p++ = cpu_to_be32(from_kuid_munged(userns, attr->ia_uid));
35362306a36Sopenharmony_ci	else
35462306a36Sopenharmony_ci		*p++ = cpu_to_be32(NFS2_SATTR_NOT_SET);
35562306a36Sopenharmony_ci	if (attr->ia_valid & ATTR_GID)
35662306a36Sopenharmony_ci		*p++ = cpu_to_be32(from_kgid_munged(userns, attr->ia_gid));
35762306a36Sopenharmony_ci	else
35862306a36Sopenharmony_ci		*p++ = cpu_to_be32(NFS2_SATTR_NOT_SET);
35962306a36Sopenharmony_ci	if (attr->ia_valid & ATTR_SIZE)
36062306a36Sopenharmony_ci		*p++ = cpu_to_be32((u32)attr->ia_size);
36162306a36Sopenharmony_ci	else
36262306a36Sopenharmony_ci		*p++ = cpu_to_be32(NFS2_SATTR_NOT_SET);
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_ci	if (attr->ia_valid & ATTR_ATIME_SET)
36562306a36Sopenharmony_ci		p = xdr_encode_time(p, &attr->ia_atime);
36662306a36Sopenharmony_ci	else if (attr->ia_valid & ATTR_ATIME)
36762306a36Sopenharmony_ci		p = xdr_encode_current_server_time(p, &attr->ia_atime);
36862306a36Sopenharmony_ci	else
36962306a36Sopenharmony_ci		p = xdr_time_not_set(p);
37062306a36Sopenharmony_ci	if (attr->ia_valid & ATTR_MTIME_SET)
37162306a36Sopenharmony_ci		xdr_encode_time(p, &attr->ia_mtime);
37262306a36Sopenharmony_ci	else if (attr->ia_valid & ATTR_MTIME)
37362306a36Sopenharmony_ci		xdr_encode_current_server_time(p, &attr->ia_mtime);
37462306a36Sopenharmony_ci	else
37562306a36Sopenharmony_ci		xdr_time_not_set(p);
37662306a36Sopenharmony_ci}
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_ci/*
37962306a36Sopenharmony_ci * 2.3.7.  filename
38062306a36Sopenharmony_ci *
38162306a36Sopenharmony_ci *	typedef string filename<MAXNAMLEN>;
38262306a36Sopenharmony_ci */
38362306a36Sopenharmony_cistatic void encode_filename(struct xdr_stream *xdr,
38462306a36Sopenharmony_ci			    const char *name, u32 length)
38562306a36Sopenharmony_ci{
38662306a36Sopenharmony_ci	__be32 *p;
38762306a36Sopenharmony_ci
38862306a36Sopenharmony_ci	WARN_ON_ONCE(length > NFS2_MAXNAMLEN);
38962306a36Sopenharmony_ci	p = xdr_reserve_space(xdr, 4 + length);
39062306a36Sopenharmony_ci	xdr_encode_opaque(p, name, length);
39162306a36Sopenharmony_ci}
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_cistatic int decode_filename_inline(struct xdr_stream *xdr,
39462306a36Sopenharmony_ci				  const char **name, u32 *length)
39562306a36Sopenharmony_ci{
39662306a36Sopenharmony_ci	__be32 *p;
39762306a36Sopenharmony_ci	u32 count;
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_ci	p = xdr_inline_decode(xdr, 4);
40062306a36Sopenharmony_ci	if (unlikely(!p))
40162306a36Sopenharmony_ci		return -EIO;
40262306a36Sopenharmony_ci	count = be32_to_cpup(p);
40362306a36Sopenharmony_ci	if (count > NFS3_MAXNAMLEN)
40462306a36Sopenharmony_ci		goto out_nametoolong;
40562306a36Sopenharmony_ci	p = xdr_inline_decode(xdr, count);
40662306a36Sopenharmony_ci	if (unlikely(!p))
40762306a36Sopenharmony_ci		return -EIO;
40862306a36Sopenharmony_ci	*name = (const char *)p;
40962306a36Sopenharmony_ci	*length = count;
41062306a36Sopenharmony_ci	return 0;
41162306a36Sopenharmony_ciout_nametoolong:
41262306a36Sopenharmony_ci	dprintk("NFS: returned filename too long: %u\n", count);
41362306a36Sopenharmony_ci	return -ENAMETOOLONG;
41462306a36Sopenharmony_ci}
41562306a36Sopenharmony_ci
41662306a36Sopenharmony_ci/*
41762306a36Sopenharmony_ci * 2.3.8.  path
41862306a36Sopenharmony_ci *
41962306a36Sopenharmony_ci *	typedef string path<MAXPATHLEN>;
42062306a36Sopenharmony_ci */
42162306a36Sopenharmony_cistatic void encode_path(struct xdr_stream *xdr, struct page **pages, u32 length)
42262306a36Sopenharmony_ci{
42362306a36Sopenharmony_ci	__be32 *p;
42462306a36Sopenharmony_ci
42562306a36Sopenharmony_ci	p = xdr_reserve_space(xdr, 4);
42662306a36Sopenharmony_ci	*p = cpu_to_be32(length);
42762306a36Sopenharmony_ci	xdr_write_pages(xdr, pages, 0, length);
42862306a36Sopenharmony_ci}
42962306a36Sopenharmony_ci
43062306a36Sopenharmony_cistatic int decode_path(struct xdr_stream *xdr)
43162306a36Sopenharmony_ci{
43262306a36Sopenharmony_ci	u32 length, recvd;
43362306a36Sopenharmony_ci	__be32 *p;
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_ci	p = xdr_inline_decode(xdr, 4);
43662306a36Sopenharmony_ci	if (unlikely(!p))
43762306a36Sopenharmony_ci		return -EIO;
43862306a36Sopenharmony_ci	length = be32_to_cpup(p);
43962306a36Sopenharmony_ci	if (unlikely(length >= xdr->buf->page_len || length > NFS_MAXPATHLEN))
44062306a36Sopenharmony_ci		goto out_size;
44162306a36Sopenharmony_ci	recvd = xdr_read_pages(xdr, length);
44262306a36Sopenharmony_ci	if (unlikely(length > recvd))
44362306a36Sopenharmony_ci		goto out_cheating;
44462306a36Sopenharmony_ci	xdr_terminate_string(xdr->buf, length);
44562306a36Sopenharmony_ci	return 0;
44662306a36Sopenharmony_ciout_size:
44762306a36Sopenharmony_ci	dprintk("NFS: returned pathname too long: %u\n", length);
44862306a36Sopenharmony_ci	return -ENAMETOOLONG;
44962306a36Sopenharmony_ciout_cheating:
45062306a36Sopenharmony_ci	dprintk("NFS: server cheating in pathname result: "
45162306a36Sopenharmony_ci		"length %u > received %u\n", length, recvd);
45262306a36Sopenharmony_ci	return -EIO;
45362306a36Sopenharmony_ci}
45462306a36Sopenharmony_ci
45562306a36Sopenharmony_ci/*
45662306a36Sopenharmony_ci * 2.3.9.  attrstat
45762306a36Sopenharmony_ci *
45862306a36Sopenharmony_ci *	union attrstat switch (stat status) {
45962306a36Sopenharmony_ci *	case NFS_OK:
46062306a36Sopenharmony_ci *		fattr attributes;
46162306a36Sopenharmony_ci *	default:
46262306a36Sopenharmony_ci *		void;
46362306a36Sopenharmony_ci *	};
46462306a36Sopenharmony_ci */
46562306a36Sopenharmony_cistatic int decode_attrstat(struct xdr_stream *xdr, struct nfs_fattr *result,
46662306a36Sopenharmony_ci			   __u32 *op_status,
46762306a36Sopenharmony_ci			   struct user_namespace *userns)
46862306a36Sopenharmony_ci{
46962306a36Sopenharmony_ci	enum nfs_stat status;
47062306a36Sopenharmony_ci	int error;
47162306a36Sopenharmony_ci
47262306a36Sopenharmony_ci	error = decode_stat(xdr, &status);
47362306a36Sopenharmony_ci	if (unlikely(error))
47462306a36Sopenharmony_ci		goto out;
47562306a36Sopenharmony_ci	if (op_status)
47662306a36Sopenharmony_ci		*op_status = status;
47762306a36Sopenharmony_ci	if (status != NFS_OK)
47862306a36Sopenharmony_ci		goto out_default;
47962306a36Sopenharmony_ci	error = decode_fattr(xdr, result, userns);
48062306a36Sopenharmony_ciout:
48162306a36Sopenharmony_ci	return error;
48262306a36Sopenharmony_ciout_default:
48362306a36Sopenharmony_ci	return nfs_stat_to_errno(status);
48462306a36Sopenharmony_ci}
48562306a36Sopenharmony_ci
48662306a36Sopenharmony_ci/*
48762306a36Sopenharmony_ci * 2.3.10.  diropargs
48862306a36Sopenharmony_ci *
48962306a36Sopenharmony_ci *	struct diropargs {
49062306a36Sopenharmony_ci *		fhandle  dir;
49162306a36Sopenharmony_ci *		filename name;
49262306a36Sopenharmony_ci *	};
49362306a36Sopenharmony_ci */
49462306a36Sopenharmony_cistatic void encode_diropargs(struct xdr_stream *xdr, const struct nfs_fh *fh,
49562306a36Sopenharmony_ci			     const char *name, u32 length)
49662306a36Sopenharmony_ci{
49762306a36Sopenharmony_ci	encode_fhandle(xdr, fh);
49862306a36Sopenharmony_ci	encode_filename(xdr, name, length);
49962306a36Sopenharmony_ci}
50062306a36Sopenharmony_ci
50162306a36Sopenharmony_ci/*
50262306a36Sopenharmony_ci * 2.3.11.  diropres
50362306a36Sopenharmony_ci *
50462306a36Sopenharmony_ci *	union diropres switch (stat status) {
50562306a36Sopenharmony_ci *	case NFS_OK:
50662306a36Sopenharmony_ci *		struct {
50762306a36Sopenharmony_ci *			fhandle file;
50862306a36Sopenharmony_ci *			fattr   attributes;
50962306a36Sopenharmony_ci *		} diropok;
51062306a36Sopenharmony_ci *	default:
51162306a36Sopenharmony_ci *		void;
51262306a36Sopenharmony_ci *	};
51362306a36Sopenharmony_ci */
51462306a36Sopenharmony_cistatic int decode_diropok(struct xdr_stream *xdr, struct nfs_diropok *result,
51562306a36Sopenharmony_ci		struct user_namespace *userns)
51662306a36Sopenharmony_ci{
51762306a36Sopenharmony_ci	int error;
51862306a36Sopenharmony_ci
51962306a36Sopenharmony_ci	error = decode_fhandle(xdr, result->fh);
52062306a36Sopenharmony_ci	if (unlikely(error))
52162306a36Sopenharmony_ci		goto out;
52262306a36Sopenharmony_ci	error = decode_fattr(xdr, result->fattr, userns);
52362306a36Sopenharmony_ciout:
52462306a36Sopenharmony_ci	return error;
52562306a36Sopenharmony_ci}
52662306a36Sopenharmony_ci
52762306a36Sopenharmony_cistatic int decode_diropres(struct xdr_stream *xdr, struct nfs_diropok *result,
52862306a36Sopenharmony_ci		struct user_namespace *userns)
52962306a36Sopenharmony_ci{
53062306a36Sopenharmony_ci	enum nfs_stat status;
53162306a36Sopenharmony_ci	int error;
53262306a36Sopenharmony_ci
53362306a36Sopenharmony_ci	error = decode_stat(xdr, &status);
53462306a36Sopenharmony_ci	if (unlikely(error))
53562306a36Sopenharmony_ci		goto out;
53662306a36Sopenharmony_ci	if (status != NFS_OK)
53762306a36Sopenharmony_ci		goto out_default;
53862306a36Sopenharmony_ci	error = decode_diropok(xdr, result, userns);
53962306a36Sopenharmony_ciout:
54062306a36Sopenharmony_ci	return error;
54162306a36Sopenharmony_ciout_default:
54262306a36Sopenharmony_ci	return nfs_stat_to_errno(status);
54362306a36Sopenharmony_ci}
54462306a36Sopenharmony_ci
54562306a36Sopenharmony_ci
54662306a36Sopenharmony_ci/*
54762306a36Sopenharmony_ci * NFSv2 XDR encode functions
54862306a36Sopenharmony_ci *
54962306a36Sopenharmony_ci * NFSv2 argument types are defined in section 2.2 of RFC 1094:
55062306a36Sopenharmony_ci * "NFS: Network File System Protocol Specification".
55162306a36Sopenharmony_ci */
55262306a36Sopenharmony_ci
55362306a36Sopenharmony_cistatic void nfs2_xdr_enc_fhandle(struct rpc_rqst *req,
55462306a36Sopenharmony_ci				 struct xdr_stream *xdr,
55562306a36Sopenharmony_ci				 const void *data)
55662306a36Sopenharmony_ci{
55762306a36Sopenharmony_ci	const struct nfs_fh *fh = data;
55862306a36Sopenharmony_ci
55962306a36Sopenharmony_ci	encode_fhandle(xdr, fh);
56062306a36Sopenharmony_ci}
56162306a36Sopenharmony_ci
56262306a36Sopenharmony_ci/*
56362306a36Sopenharmony_ci * 2.2.3.  sattrargs
56462306a36Sopenharmony_ci *
56562306a36Sopenharmony_ci *	struct sattrargs {
56662306a36Sopenharmony_ci *		fhandle file;
56762306a36Sopenharmony_ci *		sattr attributes;
56862306a36Sopenharmony_ci *	};
56962306a36Sopenharmony_ci */
57062306a36Sopenharmony_cistatic void nfs2_xdr_enc_sattrargs(struct rpc_rqst *req,
57162306a36Sopenharmony_ci				   struct xdr_stream *xdr,
57262306a36Sopenharmony_ci				   const void *data)
57362306a36Sopenharmony_ci{
57462306a36Sopenharmony_ci	const struct nfs_sattrargs *args = data;
57562306a36Sopenharmony_ci
57662306a36Sopenharmony_ci	encode_fhandle(xdr, args->fh);
57762306a36Sopenharmony_ci	encode_sattr(xdr, args->sattr, rpc_rqst_userns(req));
57862306a36Sopenharmony_ci}
57962306a36Sopenharmony_ci
58062306a36Sopenharmony_cistatic void nfs2_xdr_enc_diropargs(struct rpc_rqst *req,
58162306a36Sopenharmony_ci				   struct xdr_stream *xdr,
58262306a36Sopenharmony_ci				   const void *data)
58362306a36Sopenharmony_ci{
58462306a36Sopenharmony_ci	const struct nfs_diropargs *args = data;
58562306a36Sopenharmony_ci
58662306a36Sopenharmony_ci	encode_diropargs(xdr, args->fh, args->name, args->len);
58762306a36Sopenharmony_ci}
58862306a36Sopenharmony_ci
58962306a36Sopenharmony_cistatic void nfs2_xdr_enc_readlinkargs(struct rpc_rqst *req,
59062306a36Sopenharmony_ci				      struct xdr_stream *xdr,
59162306a36Sopenharmony_ci				      const void *data)
59262306a36Sopenharmony_ci{
59362306a36Sopenharmony_ci	const struct nfs_readlinkargs *args = data;
59462306a36Sopenharmony_ci
59562306a36Sopenharmony_ci	encode_fhandle(xdr, args->fh);
59662306a36Sopenharmony_ci	rpc_prepare_reply_pages(req, args->pages, args->pgbase, args->pglen,
59762306a36Sopenharmony_ci				NFS_readlinkres_sz - NFS_pagepad_sz);
59862306a36Sopenharmony_ci}
59962306a36Sopenharmony_ci
60062306a36Sopenharmony_ci/*
60162306a36Sopenharmony_ci * 2.2.7.  readargs
60262306a36Sopenharmony_ci *
60362306a36Sopenharmony_ci *	struct readargs {
60462306a36Sopenharmony_ci *		fhandle file;
60562306a36Sopenharmony_ci *		unsigned offset;
60662306a36Sopenharmony_ci *		unsigned count;
60762306a36Sopenharmony_ci *		unsigned totalcount;
60862306a36Sopenharmony_ci *	};
60962306a36Sopenharmony_ci */
61062306a36Sopenharmony_cistatic void encode_readargs(struct xdr_stream *xdr,
61162306a36Sopenharmony_ci			    const struct nfs_pgio_args *args)
61262306a36Sopenharmony_ci{
61362306a36Sopenharmony_ci	u32 offset = args->offset;
61462306a36Sopenharmony_ci	u32 count = args->count;
61562306a36Sopenharmony_ci	__be32 *p;
61662306a36Sopenharmony_ci
61762306a36Sopenharmony_ci	encode_fhandle(xdr, args->fh);
61862306a36Sopenharmony_ci
61962306a36Sopenharmony_ci	p = xdr_reserve_space(xdr, 4 + 4 + 4);
62062306a36Sopenharmony_ci	*p++ = cpu_to_be32(offset);
62162306a36Sopenharmony_ci	*p++ = cpu_to_be32(count);
62262306a36Sopenharmony_ci	*p = cpu_to_be32(count);
62362306a36Sopenharmony_ci}
62462306a36Sopenharmony_ci
62562306a36Sopenharmony_cistatic void nfs2_xdr_enc_readargs(struct rpc_rqst *req,
62662306a36Sopenharmony_ci				  struct xdr_stream *xdr,
62762306a36Sopenharmony_ci				  const void *data)
62862306a36Sopenharmony_ci{
62962306a36Sopenharmony_ci	const struct nfs_pgio_args *args = data;
63062306a36Sopenharmony_ci
63162306a36Sopenharmony_ci	encode_readargs(xdr, args);
63262306a36Sopenharmony_ci	rpc_prepare_reply_pages(req, args->pages, args->pgbase, args->count,
63362306a36Sopenharmony_ci				NFS_readres_sz - NFS_pagepad_sz);
63462306a36Sopenharmony_ci	req->rq_rcv_buf.flags |= XDRBUF_READ;
63562306a36Sopenharmony_ci}
63662306a36Sopenharmony_ci
63762306a36Sopenharmony_ci/*
63862306a36Sopenharmony_ci * 2.2.9.  writeargs
63962306a36Sopenharmony_ci *
64062306a36Sopenharmony_ci *	struct writeargs {
64162306a36Sopenharmony_ci *		fhandle file;
64262306a36Sopenharmony_ci *		unsigned beginoffset;
64362306a36Sopenharmony_ci *		unsigned offset;
64462306a36Sopenharmony_ci *		unsigned totalcount;
64562306a36Sopenharmony_ci *		nfsdata data;
64662306a36Sopenharmony_ci *	};
64762306a36Sopenharmony_ci */
64862306a36Sopenharmony_cistatic void encode_writeargs(struct xdr_stream *xdr,
64962306a36Sopenharmony_ci			     const struct nfs_pgio_args *args)
65062306a36Sopenharmony_ci{
65162306a36Sopenharmony_ci	u32 offset = args->offset;
65262306a36Sopenharmony_ci	u32 count = args->count;
65362306a36Sopenharmony_ci	__be32 *p;
65462306a36Sopenharmony_ci
65562306a36Sopenharmony_ci	encode_fhandle(xdr, args->fh);
65662306a36Sopenharmony_ci
65762306a36Sopenharmony_ci	p = xdr_reserve_space(xdr, 4 + 4 + 4 + 4);
65862306a36Sopenharmony_ci	*p++ = cpu_to_be32(offset);
65962306a36Sopenharmony_ci	*p++ = cpu_to_be32(offset);
66062306a36Sopenharmony_ci	*p++ = cpu_to_be32(count);
66162306a36Sopenharmony_ci
66262306a36Sopenharmony_ci	/* nfsdata */
66362306a36Sopenharmony_ci	*p = cpu_to_be32(count);
66462306a36Sopenharmony_ci	xdr_write_pages(xdr, args->pages, args->pgbase, count);
66562306a36Sopenharmony_ci}
66662306a36Sopenharmony_ci
66762306a36Sopenharmony_cistatic void nfs2_xdr_enc_writeargs(struct rpc_rqst *req,
66862306a36Sopenharmony_ci				   struct xdr_stream *xdr,
66962306a36Sopenharmony_ci				   const void *data)
67062306a36Sopenharmony_ci{
67162306a36Sopenharmony_ci	const struct nfs_pgio_args *args = data;
67262306a36Sopenharmony_ci
67362306a36Sopenharmony_ci	encode_writeargs(xdr, args);
67462306a36Sopenharmony_ci	xdr->buf->flags |= XDRBUF_WRITE;
67562306a36Sopenharmony_ci}
67662306a36Sopenharmony_ci
67762306a36Sopenharmony_ci/*
67862306a36Sopenharmony_ci * 2.2.10.  createargs
67962306a36Sopenharmony_ci *
68062306a36Sopenharmony_ci *	struct createargs {
68162306a36Sopenharmony_ci *		diropargs where;
68262306a36Sopenharmony_ci *		sattr attributes;
68362306a36Sopenharmony_ci *	};
68462306a36Sopenharmony_ci */
68562306a36Sopenharmony_cistatic void nfs2_xdr_enc_createargs(struct rpc_rqst *req,
68662306a36Sopenharmony_ci				    struct xdr_stream *xdr,
68762306a36Sopenharmony_ci				    const void *data)
68862306a36Sopenharmony_ci{
68962306a36Sopenharmony_ci	const struct nfs_createargs *args = data;
69062306a36Sopenharmony_ci
69162306a36Sopenharmony_ci	encode_diropargs(xdr, args->fh, args->name, args->len);
69262306a36Sopenharmony_ci	encode_sattr(xdr, args->sattr, rpc_rqst_userns(req));
69362306a36Sopenharmony_ci}
69462306a36Sopenharmony_ci
69562306a36Sopenharmony_cistatic void nfs2_xdr_enc_removeargs(struct rpc_rqst *req,
69662306a36Sopenharmony_ci				    struct xdr_stream *xdr,
69762306a36Sopenharmony_ci				    const void *data)
69862306a36Sopenharmony_ci{
69962306a36Sopenharmony_ci	const struct nfs_removeargs *args = data;
70062306a36Sopenharmony_ci
70162306a36Sopenharmony_ci	encode_diropargs(xdr, args->fh, args->name.name, args->name.len);
70262306a36Sopenharmony_ci}
70362306a36Sopenharmony_ci
70462306a36Sopenharmony_ci/*
70562306a36Sopenharmony_ci * 2.2.12.  renameargs
70662306a36Sopenharmony_ci *
70762306a36Sopenharmony_ci *	struct renameargs {
70862306a36Sopenharmony_ci *		diropargs from;
70962306a36Sopenharmony_ci *		diropargs to;
71062306a36Sopenharmony_ci *	};
71162306a36Sopenharmony_ci */
71262306a36Sopenharmony_cistatic void nfs2_xdr_enc_renameargs(struct rpc_rqst *req,
71362306a36Sopenharmony_ci				    struct xdr_stream *xdr,
71462306a36Sopenharmony_ci				    const void *data)
71562306a36Sopenharmony_ci{
71662306a36Sopenharmony_ci	const struct nfs_renameargs *args = data;
71762306a36Sopenharmony_ci	const struct qstr *old = args->old_name;
71862306a36Sopenharmony_ci	const struct qstr *new = args->new_name;
71962306a36Sopenharmony_ci
72062306a36Sopenharmony_ci	encode_diropargs(xdr, args->old_dir, old->name, old->len);
72162306a36Sopenharmony_ci	encode_diropargs(xdr, args->new_dir, new->name, new->len);
72262306a36Sopenharmony_ci}
72362306a36Sopenharmony_ci
72462306a36Sopenharmony_ci/*
72562306a36Sopenharmony_ci * 2.2.13.  linkargs
72662306a36Sopenharmony_ci *
72762306a36Sopenharmony_ci *	struct linkargs {
72862306a36Sopenharmony_ci *		fhandle from;
72962306a36Sopenharmony_ci *		diropargs to;
73062306a36Sopenharmony_ci *	};
73162306a36Sopenharmony_ci */
73262306a36Sopenharmony_cistatic void nfs2_xdr_enc_linkargs(struct rpc_rqst *req,
73362306a36Sopenharmony_ci				  struct xdr_stream *xdr,
73462306a36Sopenharmony_ci				  const void *data)
73562306a36Sopenharmony_ci{
73662306a36Sopenharmony_ci	const struct nfs_linkargs *args = data;
73762306a36Sopenharmony_ci
73862306a36Sopenharmony_ci	encode_fhandle(xdr, args->fromfh);
73962306a36Sopenharmony_ci	encode_diropargs(xdr, args->tofh, args->toname, args->tolen);
74062306a36Sopenharmony_ci}
74162306a36Sopenharmony_ci
74262306a36Sopenharmony_ci/*
74362306a36Sopenharmony_ci * 2.2.14.  symlinkargs
74462306a36Sopenharmony_ci *
74562306a36Sopenharmony_ci *	struct symlinkargs {
74662306a36Sopenharmony_ci *		diropargs from;
74762306a36Sopenharmony_ci *		path to;
74862306a36Sopenharmony_ci *		sattr attributes;
74962306a36Sopenharmony_ci *	};
75062306a36Sopenharmony_ci */
75162306a36Sopenharmony_cistatic void nfs2_xdr_enc_symlinkargs(struct rpc_rqst *req,
75262306a36Sopenharmony_ci				     struct xdr_stream *xdr,
75362306a36Sopenharmony_ci				     const void *data)
75462306a36Sopenharmony_ci{
75562306a36Sopenharmony_ci	const struct nfs_symlinkargs *args = data;
75662306a36Sopenharmony_ci
75762306a36Sopenharmony_ci	encode_diropargs(xdr, args->fromfh, args->fromname, args->fromlen);
75862306a36Sopenharmony_ci	encode_path(xdr, args->pages, args->pathlen);
75962306a36Sopenharmony_ci	encode_sattr(xdr, args->sattr, rpc_rqst_userns(req));
76062306a36Sopenharmony_ci}
76162306a36Sopenharmony_ci
76262306a36Sopenharmony_ci/*
76362306a36Sopenharmony_ci * 2.2.17.  readdirargs
76462306a36Sopenharmony_ci *
76562306a36Sopenharmony_ci *	struct readdirargs {
76662306a36Sopenharmony_ci *		fhandle dir;
76762306a36Sopenharmony_ci *		nfscookie cookie;
76862306a36Sopenharmony_ci *		unsigned count;
76962306a36Sopenharmony_ci *	};
77062306a36Sopenharmony_ci */
77162306a36Sopenharmony_cistatic void encode_readdirargs(struct xdr_stream *xdr,
77262306a36Sopenharmony_ci			       const struct nfs_readdirargs *args)
77362306a36Sopenharmony_ci{
77462306a36Sopenharmony_ci	__be32 *p;
77562306a36Sopenharmony_ci
77662306a36Sopenharmony_ci	encode_fhandle(xdr, args->fh);
77762306a36Sopenharmony_ci
77862306a36Sopenharmony_ci	p = xdr_reserve_space(xdr, 4 + 4);
77962306a36Sopenharmony_ci	*p++ = cpu_to_be32(args->cookie);
78062306a36Sopenharmony_ci	*p = cpu_to_be32(args->count);
78162306a36Sopenharmony_ci}
78262306a36Sopenharmony_ci
78362306a36Sopenharmony_cistatic void nfs2_xdr_enc_readdirargs(struct rpc_rqst *req,
78462306a36Sopenharmony_ci				     struct xdr_stream *xdr,
78562306a36Sopenharmony_ci				     const void *data)
78662306a36Sopenharmony_ci{
78762306a36Sopenharmony_ci	const struct nfs_readdirargs *args = data;
78862306a36Sopenharmony_ci
78962306a36Sopenharmony_ci	encode_readdirargs(xdr, args);
79062306a36Sopenharmony_ci	rpc_prepare_reply_pages(req, args->pages, 0, args->count,
79162306a36Sopenharmony_ci				NFS_readdirres_sz - NFS_pagepad_sz);
79262306a36Sopenharmony_ci}
79362306a36Sopenharmony_ci
79462306a36Sopenharmony_ci/*
79562306a36Sopenharmony_ci * NFSv2 XDR decode functions
79662306a36Sopenharmony_ci *
79762306a36Sopenharmony_ci * NFSv2 result types are defined in section 2.2 of RFC 1094:
79862306a36Sopenharmony_ci * "NFS: Network File System Protocol Specification".
79962306a36Sopenharmony_ci */
80062306a36Sopenharmony_ci
80162306a36Sopenharmony_cistatic int nfs2_xdr_dec_stat(struct rpc_rqst *req, struct xdr_stream *xdr,
80262306a36Sopenharmony_ci			     void *__unused)
80362306a36Sopenharmony_ci{
80462306a36Sopenharmony_ci	enum nfs_stat status;
80562306a36Sopenharmony_ci	int error;
80662306a36Sopenharmony_ci
80762306a36Sopenharmony_ci	error = decode_stat(xdr, &status);
80862306a36Sopenharmony_ci	if (unlikely(error))
80962306a36Sopenharmony_ci		goto out;
81062306a36Sopenharmony_ci	if (status != NFS_OK)
81162306a36Sopenharmony_ci		goto out_default;
81262306a36Sopenharmony_ciout:
81362306a36Sopenharmony_ci	return error;
81462306a36Sopenharmony_ciout_default:
81562306a36Sopenharmony_ci	return nfs_stat_to_errno(status);
81662306a36Sopenharmony_ci}
81762306a36Sopenharmony_ci
81862306a36Sopenharmony_cistatic int nfs2_xdr_dec_attrstat(struct rpc_rqst *req, struct xdr_stream *xdr,
81962306a36Sopenharmony_ci				 void *result)
82062306a36Sopenharmony_ci{
82162306a36Sopenharmony_ci	return decode_attrstat(xdr, result, NULL, rpc_rqst_userns(req));
82262306a36Sopenharmony_ci}
82362306a36Sopenharmony_ci
82462306a36Sopenharmony_cistatic int nfs2_xdr_dec_diropres(struct rpc_rqst *req, struct xdr_stream *xdr,
82562306a36Sopenharmony_ci				 void *result)
82662306a36Sopenharmony_ci{
82762306a36Sopenharmony_ci	return decode_diropres(xdr, result, rpc_rqst_userns(req));
82862306a36Sopenharmony_ci}
82962306a36Sopenharmony_ci
83062306a36Sopenharmony_ci/*
83162306a36Sopenharmony_ci * 2.2.6.  readlinkres
83262306a36Sopenharmony_ci *
83362306a36Sopenharmony_ci *	union readlinkres switch (stat status) {
83462306a36Sopenharmony_ci *	case NFS_OK:
83562306a36Sopenharmony_ci *		path data;
83662306a36Sopenharmony_ci *	default:
83762306a36Sopenharmony_ci *		void;
83862306a36Sopenharmony_ci *	};
83962306a36Sopenharmony_ci */
84062306a36Sopenharmony_cistatic int nfs2_xdr_dec_readlinkres(struct rpc_rqst *req,
84162306a36Sopenharmony_ci				    struct xdr_stream *xdr, void *__unused)
84262306a36Sopenharmony_ci{
84362306a36Sopenharmony_ci	enum nfs_stat status;
84462306a36Sopenharmony_ci	int error;
84562306a36Sopenharmony_ci
84662306a36Sopenharmony_ci	error = decode_stat(xdr, &status);
84762306a36Sopenharmony_ci	if (unlikely(error))
84862306a36Sopenharmony_ci		goto out;
84962306a36Sopenharmony_ci	if (status != NFS_OK)
85062306a36Sopenharmony_ci		goto out_default;
85162306a36Sopenharmony_ci	error = decode_path(xdr);
85262306a36Sopenharmony_ciout:
85362306a36Sopenharmony_ci	return error;
85462306a36Sopenharmony_ciout_default:
85562306a36Sopenharmony_ci	return nfs_stat_to_errno(status);
85662306a36Sopenharmony_ci}
85762306a36Sopenharmony_ci
85862306a36Sopenharmony_ci/*
85962306a36Sopenharmony_ci * 2.2.7.  readres
86062306a36Sopenharmony_ci *
86162306a36Sopenharmony_ci *	union readres switch (stat status) {
86262306a36Sopenharmony_ci *	case NFS_OK:
86362306a36Sopenharmony_ci *		fattr attributes;
86462306a36Sopenharmony_ci *		nfsdata data;
86562306a36Sopenharmony_ci *	default:
86662306a36Sopenharmony_ci *		void;
86762306a36Sopenharmony_ci *	};
86862306a36Sopenharmony_ci */
86962306a36Sopenharmony_cistatic int nfs2_xdr_dec_readres(struct rpc_rqst *req, struct xdr_stream *xdr,
87062306a36Sopenharmony_ci				void *data)
87162306a36Sopenharmony_ci{
87262306a36Sopenharmony_ci	struct nfs_pgio_res *result = data;
87362306a36Sopenharmony_ci	enum nfs_stat status;
87462306a36Sopenharmony_ci	int error;
87562306a36Sopenharmony_ci
87662306a36Sopenharmony_ci	error = decode_stat(xdr, &status);
87762306a36Sopenharmony_ci	if (unlikely(error))
87862306a36Sopenharmony_ci		goto out;
87962306a36Sopenharmony_ci	result->op_status = status;
88062306a36Sopenharmony_ci	if (status != NFS_OK)
88162306a36Sopenharmony_ci		goto out_default;
88262306a36Sopenharmony_ci	error = decode_fattr(xdr, result->fattr, rpc_rqst_userns(req));
88362306a36Sopenharmony_ci	if (unlikely(error))
88462306a36Sopenharmony_ci		goto out;
88562306a36Sopenharmony_ci	error = decode_nfsdata(xdr, result);
88662306a36Sopenharmony_ciout:
88762306a36Sopenharmony_ci	return error;
88862306a36Sopenharmony_ciout_default:
88962306a36Sopenharmony_ci	return nfs_stat_to_errno(status);
89062306a36Sopenharmony_ci}
89162306a36Sopenharmony_ci
89262306a36Sopenharmony_cistatic int nfs2_xdr_dec_writeres(struct rpc_rqst *req, struct xdr_stream *xdr,
89362306a36Sopenharmony_ci				 void *data)
89462306a36Sopenharmony_ci{
89562306a36Sopenharmony_ci	struct nfs_pgio_res *result = data;
89662306a36Sopenharmony_ci
89762306a36Sopenharmony_ci	/* All NFSv2 writes are "file sync" writes */
89862306a36Sopenharmony_ci	result->verf->committed = NFS_FILE_SYNC;
89962306a36Sopenharmony_ci	return decode_attrstat(xdr, result->fattr, &result->op_status,
90062306a36Sopenharmony_ci			rpc_rqst_userns(req));
90162306a36Sopenharmony_ci}
90262306a36Sopenharmony_ci
90362306a36Sopenharmony_ci/**
90462306a36Sopenharmony_ci * nfs2_decode_dirent - Decode a single NFSv2 directory entry stored in
90562306a36Sopenharmony_ci *                      the local page cache.
90662306a36Sopenharmony_ci * @xdr: XDR stream where entry resides
90762306a36Sopenharmony_ci * @entry: buffer to fill in with entry data
90862306a36Sopenharmony_ci * @plus: boolean indicating whether this should be a readdirplus entry
90962306a36Sopenharmony_ci *
91062306a36Sopenharmony_ci * Returns zero if successful, otherwise a negative errno value is
91162306a36Sopenharmony_ci * returned.
91262306a36Sopenharmony_ci *
91362306a36Sopenharmony_ci * This function is not invoked during READDIR reply decoding, but
91462306a36Sopenharmony_ci * rather whenever an application invokes the getdents(2) system call
91562306a36Sopenharmony_ci * on a directory already in our cache.
91662306a36Sopenharmony_ci *
91762306a36Sopenharmony_ci * 2.2.17.  entry
91862306a36Sopenharmony_ci *
91962306a36Sopenharmony_ci *	struct entry {
92062306a36Sopenharmony_ci *		unsigned	fileid;
92162306a36Sopenharmony_ci *		filename	name;
92262306a36Sopenharmony_ci *		nfscookie	cookie;
92362306a36Sopenharmony_ci *		entry		*nextentry;
92462306a36Sopenharmony_ci *	};
92562306a36Sopenharmony_ci */
92662306a36Sopenharmony_ciint nfs2_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry,
92762306a36Sopenharmony_ci		       bool plus)
92862306a36Sopenharmony_ci{
92962306a36Sopenharmony_ci	__be32 *p;
93062306a36Sopenharmony_ci	int error;
93162306a36Sopenharmony_ci
93262306a36Sopenharmony_ci	p = xdr_inline_decode(xdr, 4);
93362306a36Sopenharmony_ci	if (unlikely(!p))
93462306a36Sopenharmony_ci		return -EAGAIN;
93562306a36Sopenharmony_ci	if (*p++ == xdr_zero) {
93662306a36Sopenharmony_ci		p = xdr_inline_decode(xdr, 4);
93762306a36Sopenharmony_ci		if (unlikely(!p))
93862306a36Sopenharmony_ci			return -EAGAIN;
93962306a36Sopenharmony_ci		if (*p++ == xdr_zero)
94062306a36Sopenharmony_ci			return -EAGAIN;
94162306a36Sopenharmony_ci		entry->eof = 1;
94262306a36Sopenharmony_ci		return -EBADCOOKIE;
94362306a36Sopenharmony_ci	}
94462306a36Sopenharmony_ci
94562306a36Sopenharmony_ci	p = xdr_inline_decode(xdr, 4);
94662306a36Sopenharmony_ci	if (unlikely(!p))
94762306a36Sopenharmony_ci		return -EAGAIN;
94862306a36Sopenharmony_ci	entry->ino = be32_to_cpup(p);
94962306a36Sopenharmony_ci
95062306a36Sopenharmony_ci	error = decode_filename_inline(xdr, &entry->name, &entry->len);
95162306a36Sopenharmony_ci	if (unlikely(error))
95262306a36Sopenharmony_ci		return error == -ENAMETOOLONG ? -ENAMETOOLONG : -EAGAIN;
95362306a36Sopenharmony_ci
95462306a36Sopenharmony_ci	/*
95562306a36Sopenharmony_ci	 * The type (size and byte order) of nfscookie isn't defined in
95662306a36Sopenharmony_ci	 * RFC 1094.  This implementation assumes that it's an XDR uint32.
95762306a36Sopenharmony_ci	 */
95862306a36Sopenharmony_ci	p = xdr_inline_decode(xdr, 4);
95962306a36Sopenharmony_ci	if (unlikely(!p))
96062306a36Sopenharmony_ci		return -EAGAIN;
96162306a36Sopenharmony_ci	entry->cookie = be32_to_cpup(p);
96262306a36Sopenharmony_ci
96362306a36Sopenharmony_ci	entry->d_type = DT_UNKNOWN;
96462306a36Sopenharmony_ci
96562306a36Sopenharmony_ci	return 0;
96662306a36Sopenharmony_ci}
96762306a36Sopenharmony_ci
96862306a36Sopenharmony_ci/*
96962306a36Sopenharmony_ci * 2.2.17.  readdirres
97062306a36Sopenharmony_ci *
97162306a36Sopenharmony_ci *	union readdirres switch (stat status) {
97262306a36Sopenharmony_ci *	case NFS_OK:
97362306a36Sopenharmony_ci *		struct {
97462306a36Sopenharmony_ci *			entry *entries;
97562306a36Sopenharmony_ci *			bool eof;
97662306a36Sopenharmony_ci *		} readdirok;
97762306a36Sopenharmony_ci *	default:
97862306a36Sopenharmony_ci *		void;
97962306a36Sopenharmony_ci *	};
98062306a36Sopenharmony_ci *
98162306a36Sopenharmony_ci * Read the directory contents into the page cache, but don't
98262306a36Sopenharmony_ci * touch them.  The actual decoding is done by nfs2_decode_dirent()
98362306a36Sopenharmony_ci * during subsequent nfs_readdir() calls.
98462306a36Sopenharmony_ci */
98562306a36Sopenharmony_cistatic int decode_readdirok(struct xdr_stream *xdr)
98662306a36Sopenharmony_ci{
98762306a36Sopenharmony_ci	return xdr_read_pages(xdr, xdr->buf->page_len);
98862306a36Sopenharmony_ci}
98962306a36Sopenharmony_ci
99062306a36Sopenharmony_cistatic int nfs2_xdr_dec_readdirres(struct rpc_rqst *req,
99162306a36Sopenharmony_ci				   struct xdr_stream *xdr, void *__unused)
99262306a36Sopenharmony_ci{
99362306a36Sopenharmony_ci	enum nfs_stat status;
99462306a36Sopenharmony_ci	int error;
99562306a36Sopenharmony_ci
99662306a36Sopenharmony_ci	error = decode_stat(xdr, &status);
99762306a36Sopenharmony_ci	if (unlikely(error))
99862306a36Sopenharmony_ci		goto out;
99962306a36Sopenharmony_ci	if (status != NFS_OK)
100062306a36Sopenharmony_ci		goto out_default;
100162306a36Sopenharmony_ci	error = decode_readdirok(xdr);
100262306a36Sopenharmony_ciout:
100362306a36Sopenharmony_ci	return error;
100462306a36Sopenharmony_ciout_default:
100562306a36Sopenharmony_ci	return nfs_stat_to_errno(status);
100662306a36Sopenharmony_ci}
100762306a36Sopenharmony_ci
100862306a36Sopenharmony_ci/*
100962306a36Sopenharmony_ci * 2.2.18.  statfsres
101062306a36Sopenharmony_ci *
101162306a36Sopenharmony_ci *	union statfsres (stat status) {
101262306a36Sopenharmony_ci *	case NFS_OK:
101362306a36Sopenharmony_ci *		struct {
101462306a36Sopenharmony_ci *			unsigned tsize;
101562306a36Sopenharmony_ci *			unsigned bsize;
101662306a36Sopenharmony_ci *			unsigned blocks;
101762306a36Sopenharmony_ci *			unsigned bfree;
101862306a36Sopenharmony_ci *			unsigned bavail;
101962306a36Sopenharmony_ci *		} info;
102062306a36Sopenharmony_ci *	default:
102162306a36Sopenharmony_ci *		void;
102262306a36Sopenharmony_ci *	};
102362306a36Sopenharmony_ci */
102462306a36Sopenharmony_cistatic int decode_info(struct xdr_stream *xdr, struct nfs2_fsstat *result)
102562306a36Sopenharmony_ci{
102662306a36Sopenharmony_ci	__be32 *p;
102762306a36Sopenharmony_ci
102862306a36Sopenharmony_ci	p = xdr_inline_decode(xdr, NFS_info_sz << 2);
102962306a36Sopenharmony_ci	if (unlikely(!p))
103062306a36Sopenharmony_ci		return -EIO;
103162306a36Sopenharmony_ci	result->tsize  = be32_to_cpup(p++);
103262306a36Sopenharmony_ci	result->bsize  = be32_to_cpup(p++);
103362306a36Sopenharmony_ci	result->blocks = be32_to_cpup(p++);
103462306a36Sopenharmony_ci	result->bfree  = be32_to_cpup(p++);
103562306a36Sopenharmony_ci	result->bavail = be32_to_cpup(p);
103662306a36Sopenharmony_ci	return 0;
103762306a36Sopenharmony_ci}
103862306a36Sopenharmony_ci
103962306a36Sopenharmony_cistatic int nfs2_xdr_dec_statfsres(struct rpc_rqst *req, struct xdr_stream *xdr,
104062306a36Sopenharmony_ci				  void *result)
104162306a36Sopenharmony_ci{
104262306a36Sopenharmony_ci	enum nfs_stat status;
104362306a36Sopenharmony_ci	int error;
104462306a36Sopenharmony_ci
104562306a36Sopenharmony_ci	error = decode_stat(xdr, &status);
104662306a36Sopenharmony_ci	if (unlikely(error))
104762306a36Sopenharmony_ci		goto out;
104862306a36Sopenharmony_ci	if (status != NFS_OK)
104962306a36Sopenharmony_ci		goto out_default;
105062306a36Sopenharmony_ci	error = decode_info(xdr, result);
105162306a36Sopenharmony_ciout:
105262306a36Sopenharmony_ci	return error;
105362306a36Sopenharmony_ciout_default:
105462306a36Sopenharmony_ci	return nfs_stat_to_errno(status);
105562306a36Sopenharmony_ci}
105662306a36Sopenharmony_ci
105762306a36Sopenharmony_ci
105862306a36Sopenharmony_ci/*
105962306a36Sopenharmony_ci * We need to translate between nfs status return values and
106062306a36Sopenharmony_ci * the local errno values which may not be the same.
106162306a36Sopenharmony_ci */
106262306a36Sopenharmony_cistatic const struct {
106362306a36Sopenharmony_ci	int stat;
106462306a36Sopenharmony_ci	int errno;
106562306a36Sopenharmony_ci} nfs_errtbl[] = {
106662306a36Sopenharmony_ci	{ NFS_OK,		0		},
106762306a36Sopenharmony_ci	{ NFSERR_PERM,		-EPERM		},
106862306a36Sopenharmony_ci	{ NFSERR_NOENT,		-ENOENT		},
106962306a36Sopenharmony_ci	{ NFSERR_IO,		-errno_NFSERR_IO},
107062306a36Sopenharmony_ci	{ NFSERR_NXIO,		-ENXIO		},
107162306a36Sopenharmony_ci/*	{ NFSERR_EAGAIN,	-EAGAIN		}, */
107262306a36Sopenharmony_ci	{ NFSERR_ACCES,		-EACCES		},
107362306a36Sopenharmony_ci	{ NFSERR_EXIST,		-EEXIST		},
107462306a36Sopenharmony_ci	{ NFSERR_XDEV,		-EXDEV		},
107562306a36Sopenharmony_ci	{ NFSERR_NODEV,		-ENODEV		},
107662306a36Sopenharmony_ci	{ NFSERR_NOTDIR,	-ENOTDIR	},
107762306a36Sopenharmony_ci	{ NFSERR_ISDIR,		-EISDIR		},
107862306a36Sopenharmony_ci	{ NFSERR_INVAL,		-EINVAL		},
107962306a36Sopenharmony_ci	{ NFSERR_FBIG,		-EFBIG		},
108062306a36Sopenharmony_ci	{ NFSERR_NOSPC,		-ENOSPC		},
108162306a36Sopenharmony_ci	{ NFSERR_ROFS,		-EROFS		},
108262306a36Sopenharmony_ci	{ NFSERR_MLINK,		-EMLINK		},
108362306a36Sopenharmony_ci	{ NFSERR_NAMETOOLONG,	-ENAMETOOLONG	},
108462306a36Sopenharmony_ci	{ NFSERR_NOTEMPTY,	-ENOTEMPTY	},
108562306a36Sopenharmony_ci	{ NFSERR_DQUOT,		-EDQUOT		},
108662306a36Sopenharmony_ci	{ NFSERR_STALE,		-ESTALE		},
108762306a36Sopenharmony_ci	{ NFSERR_REMOTE,	-EREMOTE	},
108862306a36Sopenharmony_ci#ifdef EWFLUSH
108962306a36Sopenharmony_ci	{ NFSERR_WFLUSH,	-EWFLUSH	},
109062306a36Sopenharmony_ci#endif
109162306a36Sopenharmony_ci	{ NFSERR_BADHANDLE,	-EBADHANDLE	},
109262306a36Sopenharmony_ci	{ NFSERR_NOT_SYNC,	-ENOTSYNC	},
109362306a36Sopenharmony_ci	{ NFSERR_BAD_COOKIE,	-EBADCOOKIE	},
109462306a36Sopenharmony_ci	{ NFSERR_NOTSUPP,	-ENOTSUPP	},
109562306a36Sopenharmony_ci	{ NFSERR_TOOSMALL,	-ETOOSMALL	},
109662306a36Sopenharmony_ci	{ NFSERR_SERVERFAULT,	-EREMOTEIO	},
109762306a36Sopenharmony_ci	{ NFSERR_BADTYPE,	-EBADTYPE	},
109862306a36Sopenharmony_ci	{ NFSERR_JUKEBOX,	-EJUKEBOX	},
109962306a36Sopenharmony_ci	{ -1,			-EIO		}
110062306a36Sopenharmony_ci};
110162306a36Sopenharmony_ci
110262306a36Sopenharmony_ci/**
110362306a36Sopenharmony_ci * nfs_stat_to_errno - convert an NFS status code to a local errno
110462306a36Sopenharmony_ci * @status: NFS status code to convert
110562306a36Sopenharmony_ci *
110662306a36Sopenharmony_ci * Returns a local errno value, or -EIO if the NFS status code is
110762306a36Sopenharmony_ci * not recognized.  This function is used jointly by NFSv2 and NFSv3.
110862306a36Sopenharmony_ci */
110962306a36Sopenharmony_cistatic int nfs_stat_to_errno(enum nfs_stat status)
111062306a36Sopenharmony_ci{
111162306a36Sopenharmony_ci	int i;
111262306a36Sopenharmony_ci
111362306a36Sopenharmony_ci	for (i = 0; nfs_errtbl[i].stat != -1; i++) {
111462306a36Sopenharmony_ci		if (nfs_errtbl[i].stat == (int)status)
111562306a36Sopenharmony_ci			return nfs_errtbl[i].errno;
111662306a36Sopenharmony_ci	}
111762306a36Sopenharmony_ci	dprintk("NFS: Unrecognized nfs status value: %u\n", status);
111862306a36Sopenharmony_ci	return nfs_errtbl[i].errno;
111962306a36Sopenharmony_ci}
112062306a36Sopenharmony_ci
112162306a36Sopenharmony_ci#define PROC(proc, argtype, restype, timer)				\
112262306a36Sopenharmony_ci[NFSPROC_##proc] = {							\
112362306a36Sopenharmony_ci	.p_proc	    =  NFSPROC_##proc,					\
112462306a36Sopenharmony_ci	.p_encode   =  nfs2_xdr_enc_##argtype,				\
112562306a36Sopenharmony_ci	.p_decode   =  nfs2_xdr_dec_##restype,				\
112662306a36Sopenharmony_ci	.p_arglen   =  NFS_##argtype##_sz,				\
112762306a36Sopenharmony_ci	.p_replen   =  NFS_##restype##_sz,				\
112862306a36Sopenharmony_ci	.p_timer    =  timer,						\
112962306a36Sopenharmony_ci	.p_statidx  =  NFSPROC_##proc,					\
113062306a36Sopenharmony_ci	.p_name     =  #proc,						\
113162306a36Sopenharmony_ci	}
113262306a36Sopenharmony_ciconst struct rpc_procinfo nfs_procedures[] = {
113362306a36Sopenharmony_ci	PROC(GETATTR,	fhandle,	attrstat,	1),
113462306a36Sopenharmony_ci	PROC(SETATTR,	sattrargs,	attrstat,	0),
113562306a36Sopenharmony_ci	PROC(LOOKUP,	diropargs,	diropres,	2),
113662306a36Sopenharmony_ci	PROC(READLINK,	readlinkargs,	readlinkres,	3),
113762306a36Sopenharmony_ci	PROC(READ,	readargs,	readres,	3),
113862306a36Sopenharmony_ci	PROC(WRITE,	writeargs,	writeres,	4),
113962306a36Sopenharmony_ci	PROC(CREATE,	createargs,	diropres,	0),
114062306a36Sopenharmony_ci	PROC(REMOVE,	removeargs,	stat,		0),
114162306a36Sopenharmony_ci	PROC(RENAME,	renameargs,	stat,		0),
114262306a36Sopenharmony_ci	PROC(LINK,	linkargs,	stat,		0),
114362306a36Sopenharmony_ci	PROC(SYMLINK,	symlinkargs,	stat,		0),
114462306a36Sopenharmony_ci	PROC(MKDIR,	createargs,	diropres,	0),
114562306a36Sopenharmony_ci	PROC(RMDIR,	diropargs,	stat,		0),
114662306a36Sopenharmony_ci	PROC(READDIR,	readdirargs,	readdirres,	3),
114762306a36Sopenharmony_ci	PROC(STATFS,	fhandle,	statfsres,	0),
114862306a36Sopenharmony_ci};
114962306a36Sopenharmony_ci
115062306a36Sopenharmony_cistatic unsigned int nfs_version2_counts[ARRAY_SIZE(nfs_procedures)];
115162306a36Sopenharmony_ciconst struct rpc_version nfs_version2 = {
115262306a36Sopenharmony_ci	.number			= 2,
115362306a36Sopenharmony_ci	.nrprocs		= ARRAY_SIZE(nfs_procedures),
115462306a36Sopenharmony_ci	.procs			= nfs_procedures,
115562306a36Sopenharmony_ci	.counts			= nfs_version2_counts,
115662306a36Sopenharmony_ci};
1157