162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * linux/fs/nfs/nfs3xdr.c
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * XDR functions to encode/decode NFSv3 RPC arguments and results.
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * Copyright (C) 1996, 1997 Olaf Kirch
862306a36Sopenharmony_ci */
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include <linux/param.h>
1162306a36Sopenharmony_ci#include <linux/time.h>
1262306a36Sopenharmony_ci#include <linux/mm.h>
1362306a36Sopenharmony_ci#include <linux/errno.h>
1462306a36Sopenharmony_ci#include <linux/string.h>
1562306a36Sopenharmony_ci#include <linux/in.h>
1662306a36Sopenharmony_ci#include <linux/pagemap.h>
1762306a36Sopenharmony_ci#include <linux/proc_fs.h>
1862306a36Sopenharmony_ci#include <linux/kdev_t.h>
1962306a36Sopenharmony_ci#include <linux/sunrpc/clnt.h>
2062306a36Sopenharmony_ci#include <linux/nfs.h>
2162306a36Sopenharmony_ci#include <linux/nfs3.h>
2262306a36Sopenharmony_ci#include <linux/nfs_fs.h>
2362306a36Sopenharmony_ci#include <linux/nfsacl.h>
2462306a36Sopenharmony_ci#include "nfstrace.h"
2562306a36Sopenharmony_ci#include "internal.h"
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci#define NFSDBG_FACILITY		NFSDBG_XDR
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci/* Mapping from NFS error code to "errno" error code. */
3062306a36Sopenharmony_ci#define errno_NFSERR_IO		EIO
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci/*
3362306a36Sopenharmony_ci * Declare the space requirements for NFS arguments and replies as
3462306a36Sopenharmony_ci * number of 32bit-words
3562306a36Sopenharmony_ci */
3662306a36Sopenharmony_ci#define NFS3_pagepad_sz		(1) /* Page padding */
3762306a36Sopenharmony_ci#define NFS3_fhandle_sz		(1+16)
3862306a36Sopenharmony_ci#define NFS3_fh_sz		(NFS3_fhandle_sz)	/* shorthand */
3962306a36Sopenharmony_ci#define NFS3_post_op_fh_sz	(1+NFS3_fh_sz)
4062306a36Sopenharmony_ci#define NFS3_sattr_sz		(15)
4162306a36Sopenharmony_ci#define NFS3_filename_sz	(1+(NFS3_MAXNAMLEN>>2))
4262306a36Sopenharmony_ci#define NFS3_path_sz		(1+(NFS3_MAXPATHLEN>>2))
4362306a36Sopenharmony_ci#define NFS3_fattr_sz		(21)
4462306a36Sopenharmony_ci#define NFS3_cookieverf_sz	(NFS3_COOKIEVERFSIZE>>2)
4562306a36Sopenharmony_ci#define NFS3_wcc_attr_sz	(6)
4662306a36Sopenharmony_ci#define NFS3_pre_op_attr_sz	(1+NFS3_wcc_attr_sz)
4762306a36Sopenharmony_ci#define NFS3_post_op_attr_sz	(1+NFS3_fattr_sz)
4862306a36Sopenharmony_ci#define NFS3_wcc_data_sz	(NFS3_pre_op_attr_sz+NFS3_post_op_attr_sz)
4962306a36Sopenharmony_ci#define NFS3_diropargs_sz	(NFS3_fh_sz+NFS3_filename_sz)
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci#define NFS3_getattrargs_sz	(NFS3_fh_sz)
5262306a36Sopenharmony_ci#define NFS3_setattrargs_sz	(NFS3_fh_sz+NFS3_sattr_sz+3)
5362306a36Sopenharmony_ci#define NFS3_lookupargs_sz	(NFS3_fh_sz+NFS3_filename_sz)
5462306a36Sopenharmony_ci#define NFS3_accessargs_sz	(NFS3_fh_sz+1)
5562306a36Sopenharmony_ci#define NFS3_readlinkargs_sz	(NFS3_fh_sz)
5662306a36Sopenharmony_ci#define NFS3_readargs_sz	(NFS3_fh_sz+3)
5762306a36Sopenharmony_ci#define NFS3_writeargs_sz	(NFS3_fh_sz+5)
5862306a36Sopenharmony_ci#define NFS3_createargs_sz	(NFS3_diropargs_sz+NFS3_sattr_sz)
5962306a36Sopenharmony_ci#define NFS3_mkdirargs_sz	(NFS3_diropargs_sz+NFS3_sattr_sz)
6062306a36Sopenharmony_ci#define NFS3_symlinkargs_sz	(NFS3_diropargs_sz+1+NFS3_sattr_sz)
6162306a36Sopenharmony_ci#define NFS3_mknodargs_sz	(NFS3_diropargs_sz+2+NFS3_sattr_sz)
6262306a36Sopenharmony_ci#define NFS3_removeargs_sz	(NFS3_fh_sz+NFS3_filename_sz)
6362306a36Sopenharmony_ci#define NFS3_renameargs_sz	(NFS3_diropargs_sz+NFS3_diropargs_sz)
6462306a36Sopenharmony_ci#define NFS3_linkargs_sz		(NFS3_fh_sz+NFS3_diropargs_sz)
6562306a36Sopenharmony_ci#define NFS3_readdirargs_sz	(NFS3_fh_sz+NFS3_cookieverf_sz+3)
6662306a36Sopenharmony_ci#define NFS3_readdirplusargs_sz	(NFS3_fh_sz+NFS3_cookieverf_sz+4)
6762306a36Sopenharmony_ci#define NFS3_commitargs_sz	(NFS3_fh_sz+3)
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci#define NFS3_getattrres_sz	(1+NFS3_fattr_sz)
7062306a36Sopenharmony_ci#define NFS3_setattrres_sz	(1+NFS3_wcc_data_sz)
7162306a36Sopenharmony_ci#define NFS3_removeres_sz	(NFS3_setattrres_sz)
7262306a36Sopenharmony_ci#define NFS3_lookupres_sz	(1+NFS3_fh_sz+(2 * NFS3_post_op_attr_sz))
7362306a36Sopenharmony_ci#define NFS3_accessres_sz	(1+NFS3_post_op_attr_sz+1)
7462306a36Sopenharmony_ci#define NFS3_readlinkres_sz	(1+NFS3_post_op_attr_sz+1+NFS3_pagepad_sz)
7562306a36Sopenharmony_ci#define NFS3_readres_sz		(1+NFS3_post_op_attr_sz+3+NFS3_pagepad_sz)
7662306a36Sopenharmony_ci#define NFS3_writeres_sz	(1+NFS3_wcc_data_sz+4)
7762306a36Sopenharmony_ci#define NFS3_createres_sz	(1+NFS3_post_op_fh_sz+NFS3_post_op_attr_sz+NFS3_wcc_data_sz)
7862306a36Sopenharmony_ci#define NFS3_renameres_sz	(1+(2 * NFS3_wcc_data_sz))
7962306a36Sopenharmony_ci#define NFS3_linkres_sz		(1+NFS3_post_op_attr_sz+NFS3_wcc_data_sz)
8062306a36Sopenharmony_ci#define NFS3_readdirres_sz	(1+NFS3_post_op_attr_sz+2+NFS3_pagepad_sz)
8162306a36Sopenharmony_ci#define NFS3_fsstatres_sz	(1+NFS3_post_op_attr_sz+13)
8262306a36Sopenharmony_ci#define NFS3_fsinfores_sz	(1+NFS3_post_op_attr_sz+12)
8362306a36Sopenharmony_ci#define NFS3_pathconfres_sz	(1+NFS3_post_op_attr_sz+6)
8462306a36Sopenharmony_ci#define NFS3_commitres_sz	(1+NFS3_wcc_data_sz+2)
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci#define ACL3_getaclargs_sz	(NFS3_fh_sz+1)
8762306a36Sopenharmony_ci#define ACL3_setaclargs_sz	(NFS3_fh_sz+1+ \
8862306a36Sopenharmony_ci				XDR_QUADLEN(NFS_ACL_INLINE_BUFSIZE))
8962306a36Sopenharmony_ci#define ACL3_getaclres_sz	(1+NFS3_post_op_attr_sz+1+ \
9062306a36Sopenharmony_ci				XDR_QUADLEN(NFS_ACL_INLINE_BUFSIZE)+\
9162306a36Sopenharmony_ci				NFS3_pagepad_sz)
9262306a36Sopenharmony_ci#define ACL3_setaclres_sz	(1+NFS3_post_op_attr_sz)
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_cistatic int nfs3_stat_to_errno(enum nfs_stat);
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci/*
9762306a36Sopenharmony_ci * Map file type to S_IFMT bits
9862306a36Sopenharmony_ci */
9962306a36Sopenharmony_cistatic const umode_t nfs_type2fmt[] = {
10062306a36Sopenharmony_ci	[NF3BAD] = 0,
10162306a36Sopenharmony_ci	[NF3REG] = S_IFREG,
10262306a36Sopenharmony_ci	[NF3DIR] = S_IFDIR,
10362306a36Sopenharmony_ci	[NF3BLK] = S_IFBLK,
10462306a36Sopenharmony_ci	[NF3CHR] = S_IFCHR,
10562306a36Sopenharmony_ci	[NF3LNK] = S_IFLNK,
10662306a36Sopenharmony_ci	[NF3SOCK] = S_IFSOCK,
10762306a36Sopenharmony_ci	[NF3FIFO] = S_IFIFO,
10862306a36Sopenharmony_ci};
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_cistatic struct user_namespace *rpc_userns(const struct rpc_clnt *clnt)
11162306a36Sopenharmony_ci{
11262306a36Sopenharmony_ci	if (clnt && clnt->cl_cred)
11362306a36Sopenharmony_ci		return clnt->cl_cred->user_ns;
11462306a36Sopenharmony_ci	return &init_user_ns;
11562306a36Sopenharmony_ci}
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_cistatic struct user_namespace *rpc_rqst_userns(const struct rpc_rqst *rqstp)
11862306a36Sopenharmony_ci{
11962306a36Sopenharmony_ci	if (rqstp->rq_task)
12062306a36Sopenharmony_ci		return rpc_userns(rqstp->rq_task->tk_client);
12162306a36Sopenharmony_ci	return &init_user_ns;
12262306a36Sopenharmony_ci}
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci/*
12562306a36Sopenharmony_ci * Encode/decode NFSv3 basic data types
12662306a36Sopenharmony_ci *
12762306a36Sopenharmony_ci * Basic NFSv3 data types are defined in section 2.5 of RFC 1813:
12862306a36Sopenharmony_ci * "NFS Version 3 Protocol Specification".
12962306a36Sopenharmony_ci *
13062306a36Sopenharmony_ci * Not all basic data types have their own encoding and decoding
13162306a36Sopenharmony_ci * functions.  For run-time efficiency, some data types are encoded
13262306a36Sopenharmony_ci * or decoded inline.
13362306a36Sopenharmony_ci */
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_cistatic void encode_uint32(struct xdr_stream *xdr, u32 value)
13662306a36Sopenharmony_ci{
13762306a36Sopenharmony_ci	__be32 *p = xdr_reserve_space(xdr, 4);
13862306a36Sopenharmony_ci	*p = cpu_to_be32(value);
13962306a36Sopenharmony_ci}
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_cistatic int decode_uint32(struct xdr_stream *xdr, u32 *value)
14262306a36Sopenharmony_ci{
14362306a36Sopenharmony_ci	__be32 *p;
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci	p = xdr_inline_decode(xdr, 4);
14662306a36Sopenharmony_ci	if (unlikely(!p))
14762306a36Sopenharmony_ci		return -EIO;
14862306a36Sopenharmony_ci	*value = be32_to_cpup(p);
14962306a36Sopenharmony_ci	return 0;
15062306a36Sopenharmony_ci}
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_cistatic int decode_uint64(struct xdr_stream *xdr, u64 *value)
15362306a36Sopenharmony_ci{
15462306a36Sopenharmony_ci	__be32 *p;
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci	p = xdr_inline_decode(xdr, 8);
15762306a36Sopenharmony_ci	if (unlikely(!p))
15862306a36Sopenharmony_ci		return -EIO;
15962306a36Sopenharmony_ci	xdr_decode_hyper(p, value);
16062306a36Sopenharmony_ci	return 0;
16162306a36Sopenharmony_ci}
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_ci/*
16462306a36Sopenharmony_ci * fileid3
16562306a36Sopenharmony_ci *
16662306a36Sopenharmony_ci *	typedef uint64 fileid3;
16762306a36Sopenharmony_ci */
16862306a36Sopenharmony_cistatic __be32 *xdr_decode_fileid3(__be32 *p, u64 *fileid)
16962306a36Sopenharmony_ci{
17062306a36Sopenharmony_ci	return xdr_decode_hyper(p, fileid);
17162306a36Sopenharmony_ci}
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_cistatic int decode_fileid3(struct xdr_stream *xdr, u64 *fileid)
17462306a36Sopenharmony_ci{
17562306a36Sopenharmony_ci	return decode_uint64(xdr, fileid);
17662306a36Sopenharmony_ci}
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ci/*
17962306a36Sopenharmony_ci * filename3
18062306a36Sopenharmony_ci *
18162306a36Sopenharmony_ci *	typedef string filename3<>;
18262306a36Sopenharmony_ci */
18362306a36Sopenharmony_cistatic void encode_filename3(struct xdr_stream *xdr,
18462306a36Sopenharmony_ci			     const char *name, u32 length)
18562306a36Sopenharmony_ci{
18662306a36Sopenharmony_ci	__be32 *p;
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci	WARN_ON_ONCE(length > NFS3_MAXNAMLEN);
18962306a36Sopenharmony_ci	p = xdr_reserve_space(xdr, 4 + length);
19062306a36Sopenharmony_ci	xdr_encode_opaque(p, name, length);
19162306a36Sopenharmony_ci}
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_cistatic int decode_inline_filename3(struct xdr_stream *xdr,
19462306a36Sopenharmony_ci				   const char **name, u32 *length)
19562306a36Sopenharmony_ci{
19662306a36Sopenharmony_ci	__be32 *p;
19762306a36Sopenharmony_ci	u32 count;
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci	p = xdr_inline_decode(xdr, 4);
20062306a36Sopenharmony_ci	if (unlikely(!p))
20162306a36Sopenharmony_ci		return -EIO;
20262306a36Sopenharmony_ci	count = be32_to_cpup(p);
20362306a36Sopenharmony_ci	if (count > NFS3_MAXNAMLEN)
20462306a36Sopenharmony_ci		goto out_nametoolong;
20562306a36Sopenharmony_ci	p = xdr_inline_decode(xdr, count);
20662306a36Sopenharmony_ci	if (unlikely(!p))
20762306a36Sopenharmony_ci		return -EIO;
20862306a36Sopenharmony_ci	*name = (const char *)p;
20962306a36Sopenharmony_ci	*length = count;
21062306a36Sopenharmony_ci	return 0;
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_ciout_nametoolong:
21362306a36Sopenharmony_ci	dprintk("NFS: returned filename too long: %u\n", count);
21462306a36Sopenharmony_ci	return -ENAMETOOLONG;
21562306a36Sopenharmony_ci}
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ci/*
21862306a36Sopenharmony_ci * nfspath3
21962306a36Sopenharmony_ci *
22062306a36Sopenharmony_ci *	typedef string nfspath3<>;
22162306a36Sopenharmony_ci */
22262306a36Sopenharmony_cistatic void encode_nfspath3(struct xdr_stream *xdr, struct page **pages,
22362306a36Sopenharmony_ci			    const u32 length)
22462306a36Sopenharmony_ci{
22562306a36Sopenharmony_ci	encode_uint32(xdr, length);
22662306a36Sopenharmony_ci	xdr_write_pages(xdr, pages, 0, length);
22762306a36Sopenharmony_ci}
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_cistatic int decode_nfspath3(struct xdr_stream *xdr)
23062306a36Sopenharmony_ci{
23162306a36Sopenharmony_ci	u32 recvd, count;
23262306a36Sopenharmony_ci	__be32 *p;
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ci	p = xdr_inline_decode(xdr, 4);
23562306a36Sopenharmony_ci	if (unlikely(!p))
23662306a36Sopenharmony_ci		return -EIO;
23762306a36Sopenharmony_ci	count = be32_to_cpup(p);
23862306a36Sopenharmony_ci	if (unlikely(count >= xdr->buf->page_len || count > NFS3_MAXPATHLEN))
23962306a36Sopenharmony_ci		goto out_nametoolong;
24062306a36Sopenharmony_ci	recvd = xdr_read_pages(xdr, count);
24162306a36Sopenharmony_ci	if (unlikely(count > recvd))
24262306a36Sopenharmony_ci		goto out_cheating;
24362306a36Sopenharmony_ci	xdr_terminate_string(xdr->buf, count);
24462306a36Sopenharmony_ci	return 0;
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_ciout_nametoolong:
24762306a36Sopenharmony_ci	dprintk("NFS: returned pathname too long: %u\n", count);
24862306a36Sopenharmony_ci	return -ENAMETOOLONG;
24962306a36Sopenharmony_ciout_cheating:
25062306a36Sopenharmony_ci	dprintk("NFS: server cheating in pathname result: "
25162306a36Sopenharmony_ci		"count %u > recvd %u\n", count, recvd);
25262306a36Sopenharmony_ci	return -EIO;
25362306a36Sopenharmony_ci}
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ci/*
25662306a36Sopenharmony_ci * cookie3
25762306a36Sopenharmony_ci *
25862306a36Sopenharmony_ci *	typedef uint64 cookie3
25962306a36Sopenharmony_ci */
26062306a36Sopenharmony_cistatic __be32 *xdr_encode_cookie3(__be32 *p, u64 cookie)
26162306a36Sopenharmony_ci{
26262306a36Sopenharmony_ci	return xdr_encode_hyper(p, cookie);
26362306a36Sopenharmony_ci}
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_cistatic int decode_cookie3(struct xdr_stream *xdr, u64 *cookie)
26662306a36Sopenharmony_ci{
26762306a36Sopenharmony_ci	return decode_uint64(xdr, cookie);
26862306a36Sopenharmony_ci}
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_ci/*
27162306a36Sopenharmony_ci * cookieverf3
27262306a36Sopenharmony_ci *
27362306a36Sopenharmony_ci *	typedef opaque cookieverf3[NFS3_COOKIEVERFSIZE];
27462306a36Sopenharmony_ci */
27562306a36Sopenharmony_cistatic __be32 *xdr_encode_cookieverf3(__be32 *p, const __be32 *verifier)
27662306a36Sopenharmony_ci{
27762306a36Sopenharmony_ci	memcpy(p, verifier, NFS3_COOKIEVERFSIZE);
27862306a36Sopenharmony_ci	return p + XDR_QUADLEN(NFS3_COOKIEVERFSIZE);
27962306a36Sopenharmony_ci}
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_cistatic int decode_cookieverf3(struct xdr_stream *xdr, __be32 *verifier)
28262306a36Sopenharmony_ci{
28362306a36Sopenharmony_ci	__be32 *p;
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_ci	p = xdr_inline_decode(xdr, NFS3_COOKIEVERFSIZE);
28662306a36Sopenharmony_ci	if (unlikely(!p))
28762306a36Sopenharmony_ci		return -EIO;
28862306a36Sopenharmony_ci	memcpy(verifier, p, NFS3_COOKIEVERFSIZE);
28962306a36Sopenharmony_ci	return 0;
29062306a36Sopenharmony_ci}
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ci/*
29362306a36Sopenharmony_ci * createverf3
29462306a36Sopenharmony_ci *
29562306a36Sopenharmony_ci *	typedef opaque createverf3[NFS3_CREATEVERFSIZE];
29662306a36Sopenharmony_ci */
29762306a36Sopenharmony_cistatic void encode_createverf3(struct xdr_stream *xdr, const __be32 *verifier)
29862306a36Sopenharmony_ci{
29962306a36Sopenharmony_ci	__be32 *p;
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_ci	p = xdr_reserve_space(xdr, NFS3_CREATEVERFSIZE);
30262306a36Sopenharmony_ci	memcpy(p, verifier, NFS3_CREATEVERFSIZE);
30362306a36Sopenharmony_ci}
30462306a36Sopenharmony_ci
30562306a36Sopenharmony_cistatic int decode_writeverf3(struct xdr_stream *xdr, struct nfs_write_verifier *verifier)
30662306a36Sopenharmony_ci{
30762306a36Sopenharmony_ci	__be32 *p;
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_ci	p = xdr_inline_decode(xdr, NFS3_WRITEVERFSIZE);
31062306a36Sopenharmony_ci	if (unlikely(!p))
31162306a36Sopenharmony_ci		return -EIO;
31262306a36Sopenharmony_ci	memcpy(verifier->data, p, NFS3_WRITEVERFSIZE);
31362306a36Sopenharmony_ci	return 0;
31462306a36Sopenharmony_ci}
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_ci/*
31762306a36Sopenharmony_ci * size3
31862306a36Sopenharmony_ci *
31962306a36Sopenharmony_ci *	typedef uint64 size3;
32062306a36Sopenharmony_ci */
32162306a36Sopenharmony_cistatic __be32 *xdr_decode_size3(__be32 *p, u64 *size)
32262306a36Sopenharmony_ci{
32362306a36Sopenharmony_ci	return xdr_decode_hyper(p, size);
32462306a36Sopenharmony_ci}
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_ci/*
32762306a36Sopenharmony_ci * nfsstat3
32862306a36Sopenharmony_ci *
32962306a36Sopenharmony_ci *	enum nfsstat3 {
33062306a36Sopenharmony_ci *		NFS3_OK = 0,
33162306a36Sopenharmony_ci *		...
33262306a36Sopenharmony_ci *	}
33362306a36Sopenharmony_ci */
33462306a36Sopenharmony_ci#define NFS3_OK		NFS_OK
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_cistatic int decode_nfsstat3(struct xdr_stream *xdr, enum nfs_stat *status)
33762306a36Sopenharmony_ci{
33862306a36Sopenharmony_ci	__be32 *p;
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_ci	p = xdr_inline_decode(xdr, 4);
34162306a36Sopenharmony_ci	if (unlikely(!p))
34262306a36Sopenharmony_ci		return -EIO;
34362306a36Sopenharmony_ci	if (unlikely(*p != cpu_to_be32(NFS3_OK)))
34462306a36Sopenharmony_ci		goto out_status;
34562306a36Sopenharmony_ci	*status = 0;
34662306a36Sopenharmony_ci	return 0;
34762306a36Sopenharmony_ciout_status:
34862306a36Sopenharmony_ci	*status = be32_to_cpup(p);
34962306a36Sopenharmony_ci	trace_nfs_xdr_status(xdr, (int)*status);
35062306a36Sopenharmony_ci	return 0;
35162306a36Sopenharmony_ci}
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ci/*
35462306a36Sopenharmony_ci * ftype3
35562306a36Sopenharmony_ci *
35662306a36Sopenharmony_ci *	enum ftype3 {
35762306a36Sopenharmony_ci *		NF3REG	= 1,
35862306a36Sopenharmony_ci *		NF3DIR	= 2,
35962306a36Sopenharmony_ci *		NF3BLK	= 3,
36062306a36Sopenharmony_ci *		NF3CHR	= 4,
36162306a36Sopenharmony_ci *		NF3LNK	= 5,
36262306a36Sopenharmony_ci *		NF3SOCK	= 6,
36362306a36Sopenharmony_ci *		NF3FIFO	= 7
36462306a36Sopenharmony_ci *	};
36562306a36Sopenharmony_ci */
36662306a36Sopenharmony_cistatic void encode_ftype3(struct xdr_stream *xdr, const u32 type)
36762306a36Sopenharmony_ci{
36862306a36Sopenharmony_ci	encode_uint32(xdr, type);
36962306a36Sopenharmony_ci}
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_cistatic __be32 *xdr_decode_ftype3(__be32 *p, umode_t *mode)
37262306a36Sopenharmony_ci{
37362306a36Sopenharmony_ci	u32 type;
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_ci	type = be32_to_cpup(p++);
37662306a36Sopenharmony_ci	if (type > NF3FIFO)
37762306a36Sopenharmony_ci		type = NF3NON;
37862306a36Sopenharmony_ci	*mode = nfs_type2fmt[type];
37962306a36Sopenharmony_ci	return p;
38062306a36Sopenharmony_ci}
38162306a36Sopenharmony_ci
38262306a36Sopenharmony_ci/*
38362306a36Sopenharmony_ci * specdata3
38462306a36Sopenharmony_ci *
38562306a36Sopenharmony_ci *     struct specdata3 {
38662306a36Sopenharmony_ci *             uint32  specdata1;
38762306a36Sopenharmony_ci *             uint32  specdata2;
38862306a36Sopenharmony_ci *     };
38962306a36Sopenharmony_ci */
39062306a36Sopenharmony_cistatic void encode_specdata3(struct xdr_stream *xdr, const dev_t rdev)
39162306a36Sopenharmony_ci{
39262306a36Sopenharmony_ci	__be32 *p;
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_ci	p = xdr_reserve_space(xdr, 8);
39562306a36Sopenharmony_ci	*p++ = cpu_to_be32(MAJOR(rdev));
39662306a36Sopenharmony_ci	*p = cpu_to_be32(MINOR(rdev));
39762306a36Sopenharmony_ci}
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_cistatic __be32 *xdr_decode_specdata3(__be32 *p, dev_t *rdev)
40062306a36Sopenharmony_ci{
40162306a36Sopenharmony_ci	unsigned int major, minor;
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_ci	major = be32_to_cpup(p++);
40462306a36Sopenharmony_ci	minor = be32_to_cpup(p++);
40562306a36Sopenharmony_ci	*rdev = MKDEV(major, minor);
40662306a36Sopenharmony_ci	if (MAJOR(*rdev) != major || MINOR(*rdev) != minor)
40762306a36Sopenharmony_ci		*rdev = 0;
40862306a36Sopenharmony_ci	return p;
40962306a36Sopenharmony_ci}
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_ci/*
41262306a36Sopenharmony_ci * nfs_fh3
41362306a36Sopenharmony_ci *
41462306a36Sopenharmony_ci *	struct nfs_fh3 {
41562306a36Sopenharmony_ci *		opaque       data<NFS3_FHSIZE>;
41662306a36Sopenharmony_ci *	};
41762306a36Sopenharmony_ci */
41862306a36Sopenharmony_cistatic void encode_nfs_fh3(struct xdr_stream *xdr, const struct nfs_fh *fh)
41962306a36Sopenharmony_ci{
42062306a36Sopenharmony_ci	__be32 *p;
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_ci	WARN_ON_ONCE(fh->size > NFS3_FHSIZE);
42362306a36Sopenharmony_ci	p = xdr_reserve_space(xdr, 4 + fh->size);
42462306a36Sopenharmony_ci	xdr_encode_opaque(p, fh->data, fh->size);
42562306a36Sopenharmony_ci}
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_cistatic int decode_nfs_fh3(struct xdr_stream *xdr, struct nfs_fh *fh)
42862306a36Sopenharmony_ci{
42962306a36Sopenharmony_ci	u32 length;
43062306a36Sopenharmony_ci	__be32 *p;
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_ci	p = xdr_inline_decode(xdr, 4);
43362306a36Sopenharmony_ci	if (unlikely(!p))
43462306a36Sopenharmony_ci		return -EIO;
43562306a36Sopenharmony_ci	length = be32_to_cpup(p++);
43662306a36Sopenharmony_ci	if (unlikely(length > NFS3_FHSIZE || length == 0))
43762306a36Sopenharmony_ci		goto out_toobig;
43862306a36Sopenharmony_ci	p = xdr_inline_decode(xdr, length);
43962306a36Sopenharmony_ci	if (unlikely(!p))
44062306a36Sopenharmony_ci		return -EIO;
44162306a36Sopenharmony_ci	fh->size = length;
44262306a36Sopenharmony_ci	memcpy(fh->data, p, length);
44362306a36Sopenharmony_ci	return 0;
44462306a36Sopenharmony_ciout_toobig:
44562306a36Sopenharmony_ci	trace_nfs_xdr_bad_filehandle(xdr, NFSERR_BADHANDLE);
44662306a36Sopenharmony_ci	return -E2BIG;
44762306a36Sopenharmony_ci}
44862306a36Sopenharmony_ci
44962306a36Sopenharmony_cistatic void zero_nfs_fh3(struct nfs_fh *fh)
45062306a36Sopenharmony_ci{
45162306a36Sopenharmony_ci	memset(fh, 0, sizeof(*fh));
45262306a36Sopenharmony_ci}
45362306a36Sopenharmony_ci
45462306a36Sopenharmony_ci/*
45562306a36Sopenharmony_ci * nfstime3
45662306a36Sopenharmony_ci *
45762306a36Sopenharmony_ci *	struct nfstime3 {
45862306a36Sopenharmony_ci *		uint32	seconds;
45962306a36Sopenharmony_ci *		uint32	nseconds;
46062306a36Sopenharmony_ci *	};
46162306a36Sopenharmony_ci */
46262306a36Sopenharmony_cistatic __be32 *xdr_encode_nfstime3(__be32 *p, const struct timespec64 *timep)
46362306a36Sopenharmony_ci{
46462306a36Sopenharmony_ci	*p++ = cpu_to_be32((u32)timep->tv_sec);
46562306a36Sopenharmony_ci	*p++ = cpu_to_be32(timep->tv_nsec);
46662306a36Sopenharmony_ci	return p;
46762306a36Sopenharmony_ci}
46862306a36Sopenharmony_ci
46962306a36Sopenharmony_cistatic __be32 *xdr_decode_nfstime3(__be32 *p, struct timespec64 *timep)
47062306a36Sopenharmony_ci{
47162306a36Sopenharmony_ci	timep->tv_sec = be32_to_cpup(p++);
47262306a36Sopenharmony_ci	timep->tv_nsec = be32_to_cpup(p++);
47362306a36Sopenharmony_ci	return p;
47462306a36Sopenharmony_ci}
47562306a36Sopenharmony_ci
47662306a36Sopenharmony_ci/*
47762306a36Sopenharmony_ci * sattr3
47862306a36Sopenharmony_ci *
47962306a36Sopenharmony_ci *	enum time_how {
48062306a36Sopenharmony_ci *		DONT_CHANGE		= 0,
48162306a36Sopenharmony_ci *		SET_TO_SERVER_TIME	= 1,
48262306a36Sopenharmony_ci *		SET_TO_CLIENT_TIME	= 2
48362306a36Sopenharmony_ci *	};
48462306a36Sopenharmony_ci *
48562306a36Sopenharmony_ci *	union set_mode3 switch (bool set_it) {
48662306a36Sopenharmony_ci *	case TRUE:
48762306a36Sopenharmony_ci *		mode3	mode;
48862306a36Sopenharmony_ci *	default:
48962306a36Sopenharmony_ci *		void;
49062306a36Sopenharmony_ci *	};
49162306a36Sopenharmony_ci *
49262306a36Sopenharmony_ci *	union set_uid3 switch (bool set_it) {
49362306a36Sopenharmony_ci *	case TRUE:
49462306a36Sopenharmony_ci *		uid3	uid;
49562306a36Sopenharmony_ci *	default:
49662306a36Sopenharmony_ci *		void;
49762306a36Sopenharmony_ci *	};
49862306a36Sopenharmony_ci *
49962306a36Sopenharmony_ci *	union set_gid3 switch (bool set_it) {
50062306a36Sopenharmony_ci *	case TRUE:
50162306a36Sopenharmony_ci *		gid3	gid;
50262306a36Sopenharmony_ci *	default:
50362306a36Sopenharmony_ci *		void;
50462306a36Sopenharmony_ci *	};
50562306a36Sopenharmony_ci *
50662306a36Sopenharmony_ci *	union set_size3 switch (bool set_it) {
50762306a36Sopenharmony_ci *	case TRUE:
50862306a36Sopenharmony_ci *		size3	size;
50962306a36Sopenharmony_ci *	default:
51062306a36Sopenharmony_ci *		void;
51162306a36Sopenharmony_ci *	};
51262306a36Sopenharmony_ci *
51362306a36Sopenharmony_ci *	union set_atime switch (time_how set_it) {
51462306a36Sopenharmony_ci *	case SET_TO_CLIENT_TIME:
51562306a36Sopenharmony_ci *		nfstime3	atime;
51662306a36Sopenharmony_ci *	default:
51762306a36Sopenharmony_ci *		void;
51862306a36Sopenharmony_ci *	};
51962306a36Sopenharmony_ci *
52062306a36Sopenharmony_ci *	union set_mtime switch (time_how set_it) {
52162306a36Sopenharmony_ci *	case SET_TO_CLIENT_TIME:
52262306a36Sopenharmony_ci *		nfstime3  mtime;
52362306a36Sopenharmony_ci *	default:
52462306a36Sopenharmony_ci *		void;
52562306a36Sopenharmony_ci *	};
52662306a36Sopenharmony_ci *
52762306a36Sopenharmony_ci *	struct sattr3 {
52862306a36Sopenharmony_ci *		set_mode3	mode;
52962306a36Sopenharmony_ci *		set_uid3	uid;
53062306a36Sopenharmony_ci *		set_gid3	gid;
53162306a36Sopenharmony_ci *		set_size3	size;
53262306a36Sopenharmony_ci *		set_atime	atime;
53362306a36Sopenharmony_ci *		set_mtime	mtime;
53462306a36Sopenharmony_ci *	};
53562306a36Sopenharmony_ci */
53662306a36Sopenharmony_cistatic void encode_sattr3(struct xdr_stream *xdr, const struct iattr *attr,
53762306a36Sopenharmony_ci		struct user_namespace *userns)
53862306a36Sopenharmony_ci{
53962306a36Sopenharmony_ci	u32 nbytes;
54062306a36Sopenharmony_ci	__be32 *p;
54162306a36Sopenharmony_ci
54262306a36Sopenharmony_ci	/*
54362306a36Sopenharmony_ci	 * In order to make only a single xdr_reserve_space() call,
54462306a36Sopenharmony_ci	 * pre-compute the total number of bytes to be reserved.
54562306a36Sopenharmony_ci	 * Six boolean values, one for each set_foo field, are always
54662306a36Sopenharmony_ci	 * present in the encoded result, so start there.
54762306a36Sopenharmony_ci	 */
54862306a36Sopenharmony_ci	nbytes = 6 * 4;
54962306a36Sopenharmony_ci	if (attr->ia_valid & ATTR_MODE)
55062306a36Sopenharmony_ci		nbytes += 4;
55162306a36Sopenharmony_ci	if (attr->ia_valid & ATTR_UID)
55262306a36Sopenharmony_ci		nbytes += 4;
55362306a36Sopenharmony_ci	if (attr->ia_valid & ATTR_GID)
55462306a36Sopenharmony_ci		nbytes += 4;
55562306a36Sopenharmony_ci	if (attr->ia_valid & ATTR_SIZE)
55662306a36Sopenharmony_ci		nbytes += 8;
55762306a36Sopenharmony_ci	if (attr->ia_valid & ATTR_ATIME_SET)
55862306a36Sopenharmony_ci		nbytes += 8;
55962306a36Sopenharmony_ci	if (attr->ia_valid & ATTR_MTIME_SET)
56062306a36Sopenharmony_ci		nbytes += 8;
56162306a36Sopenharmony_ci	p = xdr_reserve_space(xdr, nbytes);
56262306a36Sopenharmony_ci
56362306a36Sopenharmony_ci	if (attr->ia_valid & ATTR_MODE) {
56462306a36Sopenharmony_ci		*p++ = xdr_one;
56562306a36Sopenharmony_ci		*p++ = cpu_to_be32(attr->ia_mode & S_IALLUGO);
56662306a36Sopenharmony_ci	} else
56762306a36Sopenharmony_ci		*p++ = xdr_zero;
56862306a36Sopenharmony_ci
56962306a36Sopenharmony_ci	if (attr->ia_valid & ATTR_UID) {
57062306a36Sopenharmony_ci		*p++ = xdr_one;
57162306a36Sopenharmony_ci		*p++ = cpu_to_be32(from_kuid_munged(userns, attr->ia_uid));
57262306a36Sopenharmony_ci	} else
57362306a36Sopenharmony_ci		*p++ = xdr_zero;
57462306a36Sopenharmony_ci
57562306a36Sopenharmony_ci	if (attr->ia_valid & ATTR_GID) {
57662306a36Sopenharmony_ci		*p++ = xdr_one;
57762306a36Sopenharmony_ci		*p++ = cpu_to_be32(from_kgid_munged(userns, attr->ia_gid));
57862306a36Sopenharmony_ci	} else
57962306a36Sopenharmony_ci		*p++ = xdr_zero;
58062306a36Sopenharmony_ci
58162306a36Sopenharmony_ci	if (attr->ia_valid & ATTR_SIZE) {
58262306a36Sopenharmony_ci		*p++ = xdr_one;
58362306a36Sopenharmony_ci		p = xdr_encode_hyper(p, (u64)attr->ia_size);
58462306a36Sopenharmony_ci	} else
58562306a36Sopenharmony_ci		*p++ = xdr_zero;
58662306a36Sopenharmony_ci
58762306a36Sopenharmony_ci	if (attr->ia_valid & ATTR_ATIME_SET) {
58862306a36Sopenharmony_ci		*p++ = xdr_two;
58962306a36Sopenharmony_ci		p = xdr_encode_nfstime3(p, &attr->ia_atime);
59062306a36Sopenharmony_ci	} else if (attr->ia_valid & ATTR_ATIME) {
59162306a36Sopenharmony_ci		*p++ = xdr_one;
59262306a36Sopenharmony_ci	} else
59362306a36Sopenharmony_ci		*p++ = xdr_zero;
59462306a36Sopenharmony_ci
59562306a36Sopenharmony_ci	if (attr->ia_valid & ATTR_MTIME_SET) {
59662306a36Sopenharmony_ci		*p++ = xdr_two;
59762306a36Sopenharmony_ci		xdr_encode_nfstime3(p, &attr->ia_mtime);
59862306a36Sopenharmony_ci	} else if (attr->ia_valid & ATTR_MTIME) {
59962306a36Sopenharmony_ci		*p = xdr_one;
60062306a36Sopenharmony_ci	} else
60162306a36Sopenharmony_ci		*p = xdr_zero;
60262306a36Sopenharmony_ci}
60362306a36Sopenharmony_ci
60462306a36Sopenharmony_ci/*
60562306a36Sopenharmony_ci * fattr3
60662306a36Sopenharmony_ci *
60762306a36Sopenharmony_ci *	struct fattr3 {
60862306a36Sopenharmony_ci *		ftype3		type;
60962306a36Sopenharmony_ci *		mode3		mode;
61062306a36Sopenharmony_ci *		uint32		nlink;
61162306a36Sopenharmony_ci *		uid3		uid;
61262306a36Sopenharmony_ci *		gid3		gid;
61362306a36Sopenharmony_ci *		size3		size;
61462306a36Sopenharmony_ci *		size3		used;
61562306a36Sopenharmony_ci *		specdata3	rdev;
61662306a36Sopenharmony_ci *		uint64		fsid;
61762306a36Sopenharmony_ci *		fileid3		fileid;
61862306a36Sopenharmony_ci *		nfstime3	atime;
61962306a36Sopenharmony_ci *		nfstime3	mtime;
62062306a36Sopenharmony_ci *		nfstime3	ctime;
62162306a36Sopenharmony_ci *	};
62262306a36Sopenharmony_ci */
62362306a36Sopenharmony_cistatic int decode_fattr3(struct xdr_stream *xdr, struct nfs_fattr *fattr,
62462306a36Sopenharmony_ci		struct user_namespace *userns)
62562306a36Sopenharmony_ci{
62662306a36Sopenharmony_ci	umode_t fmode;
62762306a36Sopenharmony_ci	__be32 *p;
62862306a36Sopenharmony_ci
62962306a36Sopenharmony_ci	p = xdr_inline_decode(xdr, NFS3_fattr_sz << 2);
63062306a36Sopenharmony_ci	if (unlikely(!p))
63162306a36Sopenharmony_ci		return -EIO;
63262306a36Sopenharmony_ci
63362306a36Sopenharmony_ci	p = xdr_decode_ftype3(p, &fmode);
63462306a36Sopenharmony_ci
63562306a36Sopenharmony_ci	fattr->mode = (be32_to_cpup(p++) & ~S_IFMT) | fmode;
63662306a36Sopenharmony_ci	fattr->nlink = be32_to_cpup(p++);
63762306a36Sopenharmony_ci	fattr->uid = make_kuid(userns, be32_to_cpup(p++));
63862306a36Sopenharmony_ci	if (!uid_valid(fattr->uid))
63962306a36Sopenharmony_ci		goto out_uid;
64062306a36Sopenharmony_ci	fattr->gid = make_kgid(userns, be32_to_cpup(p++));
64162306a36Sopenharmony_ci	if (!gid_valid(fattr->gid))
64262306a36Sopenharmony_ci		goto out_gid;
64362306a36Sopenharmony_ci
64462306a36Sopenharmony_ci	p = xdr_decode_size3(p, &fattr->size);
64562306a36Sopenharmony_ci	p = xdr_decode_size3(p, &fattr->du.nfs3.used);
64662306a36Sopenharmony_ci	p = xdr_decode_specdata3(p, &fattr->rdev);
64762306a36Sopenharmony_ci
64862306a36Sopenharmony_ci	p = xdr_decode_hyper(p, &fattr->fsid.major);
64962306a36Sopenharmony_ci	fattr->fsid.minor = 0;
65062306a36Sopenharmony_ci
65162306a36Sopenharmony_ci	p = xdr_decode_fileid3(p, &fattr->fileid);
65262306a36Sopenharmony_ci	p = xdr_decode_nfstime3(p, &fattr->atime);
65362306a36Sopenharmony_ci	p = xdr_decode_nfstime3(p, &fattr->mtime);
65462306a36Sopenharmony_ci	xdr_decode_nfstime3(p, &fattr->ctime);
65562306a36Sopenharmony_ci	fattr->change_attr = nfs_timespec_to_change_attr(&fattr->ctime);
65662306a36Sopenharmony_ci
65762306a36Sopenharmony_ci	fattr->valid |= NFS_ATTR_FATTR_V3;
65862306a36Sopenharmony_ci	return 0;
65962306a36Sopenharmony_ciout_uid:
66062306a36Sopenharmony_ci	dprintk("NFS: returned invalid uid\n");
66162306a36Sopenharmony_ci	return -EINVAL;
66262306a36Sopenharmony_ciout_gid:
66362306a36Sopenharmony_ci	dprintk("NFS: returned invalid gid\n");
66462306a36Sopenharmony_ci	return -EINVAL;
66562306a36Sopenharmony_ci}
66662306a36Sopenharmony_ci
66762306a36Sopenharmony_ci/*
66862306a36Sopenharmony_ci * post_op_attr
66962306a36Sopenharmony_ci *
67062306a36Sopenharmony_ci *	union post_op_attr switch (bool attributes_follow) {
67162306a36Sopenharmony_ci *	case TRUE:
67262306a36Sopenharmony_ci *		fattr3	attributes;
67362306a36Sopenharmony_ci *	case FALSE:
67462306a36Sopenharmony_ci *		void;
67562306a36Sopenharmony_ci *	};
67662306a36Sopenharmony_ci */
67762306a36Sopenharmony_cistatic int decode_post_op_attr(struct xdr_stream *xdr, struct nfs_fattr *fattr,
67862306a36Sopenharmony_ci		struct user_namespace *userns)
67962306a36Sopenharmony_ci{
68062306a36Sopenharmony_ci	__be32 *p;
68162306a36Sopenharmony_ci
68262306a36Sopenharmony_ci	p = xdr_inline_decode(xdr, 4);
68362306a36Sopenharmony_ci	if (unlikely(!p))
68462306a36Sopenharmony_ci		return -EIO;
68562306a36Sopenharmony_ci	if (*p != xdr_zero)
68662306a36Sopenharmony_ci		return decode_fattr3(xdr, fattr, userns);
68762306a36Sopenharmony_ci	return 0;
68862306a36Sopenharmony_ci}
68962306a36Sopenharmony_ci
69062306a36Sopenharmony_ci/*
69162306a36Sopenharmony_ci * wcc_attr
69262306a36Sopenharmony_ci *	struct wcc_attr {
69362306a36Sopenharmony_ci *		size3		size;
69462306a36Sopenharmony_ci *		nfstime3	mtime;
69562306a36Sopenharmony_ci *		nfstime3	ctime;
69662306a36Sopenharmony_ci *	};
69762306a36Sopenharmony_ci */
69862306a36Sopenharmony_cistatic int decode_wcc_attr(struct xdr_stream *xdr, struct nfs_fattr *fattr)
69962306a36Sopenharmony_ci{
70062306a36Sopenharmony_ci	__be32 *p;
70162306a36Sopenharmony_ci
70262306a36Sopenharmony_ci	p = xdr_inline_decode(xdr, NFS3_wcc_attr_sz << 2);
70362306a36Sopenharmony_ci	if (unlikely(!p))
70462306a36Sopenharmony_ci		return -EIO;
70562306a36Sopenharmony_ci
70662306a36Sopenharmony_ci	fattr->valid |= NFS_ATTR_FATTR_PRESIZE
70762306a36Sopenharmony_ci		| NFS_ATTR_FATTR_PRECHANGE
70862306a36Sopenharmony_ci		| NFS_ATTR_FATTR_PREMTIME
70962306a36Sopenharmony_ci		| NFS_ATTR_FATTR_PRECTIME;
71062306a36Sopenharmony_ci
71162306a36Sopenharmony_ci	p = xdr_decode_size3(p, &fattr->pre_size);
71262306a36Sopenharmony_ci	p = xdr_decode_nfstime3(p, &fattr->pre_mtime);
71362306a36Sopenharmony_ci	xdr_decode_nfstime3(p, &fattr->pre_ctime);
71462306a36Sopenharmony_ci	fattr->pre_change_attr = nfs_timespec_to_change_attr(&fattr->pre_ctime);
71562306a36Sopenharmony_ci
71662306a36Sopenharmony_ci	return 0;
71762306a36Sopenharmony_ci}
71862306a36Sopenharmony_ci
71962306a36Sopenharmony_ci/*
72062306a36Sopenharmony_ci * pre_op_attr
72162306a36Sopenharmony_ci *	union pre_op_attr switch (bool attributes_follow) {
72262306a36Sopenharmony_ci *	case TRUE:
72362306a36Sopenharmony_ci *		wcc_attr	attributes;
72462306a36Sopenharmony_ci *	case FALSE:
72562306a36Sopenharmony_ci *		void;
72662306a36Sopenharmony_ci *	};
72762306a36Sopenharmony_ci *
72862306a36Sopenharmony_ci * wcc_data
72962306a36Sopenharmony_ci *
73062306a36Sopenharmony_ci *	struct wcc_data {
73162306a36Sopenharmony_ci *		pre_op_attr	before;
73262306a36Sopenharmony_ci *		post_op_attr	after;
73362306a36Sopenharmony_ci *	};
73462306a36Sopenharmony_ci */
73562306a36Sopenharmony_cistatic int decode_pre_op_attr(struct xdr_stream *xdr, struct nfs_fattr *fattr)
73662306a36Sopenharmony_ci{
73762306a36Sopenharmony_ci	__be32 *p;
73862306a36Sopenharmony_ci
73962306a36Sopenharmony_ci	p = xdr_inline_decode(xdr, 4);
74062306a36Sopenharmony_ci	if (unlikely(!p))
74162306a36Sopenharmony_ci		return -EIO;
74262306a36Sopenharmony_ci	if (*p != xdr_zero)
74362306a36Sopenharmony_ci		return decode_wcc_attr(xdr, fattr);
74462306a36Sopenharmony_ci	return 0;
74562306a36Sopenharmony_ci}
74662306a36Sopenharmony_ci
74762306a36Sopenharmony_cistatic int decode_wcc_data(struct xdr_stream *xdr, struct nfs_fattr *fattr,
74862306a36Sopenharmony_ci		struct user_namespace *userns)
74962306a36Sopenharmony_ci{
75062306a36Sopenharmony_ci	int error;
75162306a36Sopenharmony_ci
75262306a36Sopenharmony_ci	error = decode_pre_op_attr(xdr, fattr);
75362306a36Sopenharmony_ci	if (unlikely(error))
75462306a36Sopenharmony_ci		goto out;
75562306a36Sopenharmony_ci	error = decode_post_op_attr(xdr, fattr, userns);
75662306a36Sopenharmony_ciout:
75762306a36Sopenharmony_ci	return error;
75862306a36Sopenharmony_ci}
75962306a36Sopenharmony_ci
76062306a36Sopenharmony_ci/*
76162306a36Sopenharmony_ci * post_op_fh3
76262306a36Sopenharmony_ci *
76362306a36Sopenharmony_ci *	union post_op_fh3 switch (bool handle_follows) {
76462306a36Sopenharmony_ci *	case TRUE:
76562306a36Sopenharmony_ci *		nfs_fh3  handle;
76662306a36Sopenharmony_ci *	case FALSE:
76762306a36Sopenharmony_ci *		void;
76862306a36Sopenharmony_ci *	};
76962306a36Sopenharmony_ci */
77062306a36Sopenharmony_cistatic int decode_post_op_fh3(struct xdr_stream *xdr, struct nfs_fh *fh)
77162306a36Sopenharmony_ci{
77262306a36Sopenharmony_ci	__be32 *p = xdr_inline_decode(xdr, 4);
77362306a36Sopenharmony_ci	if (unlikely(!p))
77462306a36Sopenharmony_ci		return -EIO;
77562306a36Sopenharmony_ci	if (*p != xdr_zero)
77662306a36Sopenharmony_ci		return decode_nfs_fh3(xdr, fh);
77762306a36Sopenharmony_ci	zero_nfs_fh3(fh);
77862306a36Sopenharmony_ci	return 0;
77962306a36Sopenharmony_ci}
78062306a36Sopenharmony_ci
78162306a36Sopenharmony_ci/*
78262306a36Sopenharmony_ci * diropargs3
78362306a36Sopenharmony_ci *
78462306a36Sopenharmony_ci *	struct diropargs3 {
78562306a36Sopenharmony_ci *		nfs_fh3		dir;
78662306a36Sopenharmony_ci *		filename3	name;
78762306a36Sopenharmony_ci *	};
78862306a36Sopenharmony_ci */
78962306a36Sopenharmony_cistatic void encode_diropargs3(struct xdr_stream *xdr, const struct nfs_fh *fh,
79062306a36Sopenharmony_ci			      const char *name, u32 length)
79162306a36Sopenharmony_ci{
79262306a36Sopenharmony_ci	encode_nfs_fh3(xdr, fh);
79362306a36Sopenharmony_ci	encode_filename3(xdr, name, length);
79462306a36Sopenharmony_ci}
79562306a36Sopenharmony_ci
79662306a36Sopenharmony_ci
79762306a36Sopenharmony_ci/*
79862306a36Sopenharmony_ci * NFSv3 XDR encode functions
79962306a36Sopenharmony_ci *
80062306a36Sopenharmony_ci * NFSv3 argument types are defined in section 3.3 of RFC 1813:
80162306a36Sopenharmony_ci * "NFS Version 3 Protocol Specification".
80262306a36Sopenharmony_ci */
80362306a36Sopenharmony_ci
80462306a36Sopenharmony_ci/*
80562306a36Sopenharmony_ci * 3.3.1  GETATTR3args
80662306a36Sopenharmony_ci *
80762306a36Sopenharmony_ci *	struct GETATTR3args {
80862306a36Sopenharmony_ci *		nfs_fh3  object;
80962306a36Sopenharmony_ci *	};
81062306a36Sopenharmony_ci */
81162306a36Sopenharmony_cistatic void nfs3_xdr_enc_getattr3args(struct rpc_rqst *req,
81262306a36Sopenharmony_ci				      struct xdr_stream *xdr,
81362306a36Sopenharmony_ci				      const void *data)
81462306a36Sopenharmony_ci{
81562306a36Sopenharmony_ci	const struct nfs_fh *fh = data;
81662306a36Sopenharmony_ci
81762306a36Sopenharmony_ci	encode_nfs_fh3(xdr, fh);
81862306a36Sopenharmony_ci}
81962306a36Sopenharmony_ci
82062306a36Sopenharmony_ci/*
82162306a36Sopenharmony_ci * 3.3.2  SETATTR3args
82262306a36Sopenharmony_ci *
82362306a36Sopenharmony_ci *	union sattrguard3 switch (bool check) {
82462306a36Sopenharmony_ci *	case TRUE:
82562306a36Sopenharmony_ci *		nfstime3  obj_ctime;
82662306a36Sopenharmony_ci *	case FALSE:
82762306a36Sopenharmony_ci *		void;
82862306a36Sopenharmony_ci *	};
82962306a36Sopenharmony_ci *
83062306a36Sopenharmony_ci *	struct SETATTR3args {
83162306a36Sopenharmony_ci *		nfs_fh3		object;
83262306a36Sopenharmony_ci *		sattr3		new_attributes;
83362306a36Sopenharmony_ci *		sattrguard3	guard;
83462306a36Sopenharmony_ci *	};
83562306a36Sopenharmony_ci */
83662306a36Sopenharmony_cistatic void encode_sattrguard3(struct xdr_stream *xdr,
83762306a36Sopenharmony_ci			       const struct nfs3_sattrargs *args)
83862306a36Sopenharmony_ci{
83962306a36Sopenharmony_ci	__be32 *p;
84062306a36Sopenharmony_ci
84162306a36Sopenharmony_ci	if (args->guard) {
84262306a36Sopenharmony_ci		p = xdr_reserve_space(xdr, 4 + 8);
84362306a36Sopenharmony_ci		*p++ = xdr_one;
84462306a36Sopenharmony_ci		xdr_encode_nfstime3(p, &args->guardtime);
84562306a36Sopenharmony_ci	} else {
84662306a36Sopenharmony_ci		p = xdr_reserve_space(xdr, 4);
84762306a36Sopenharmony_ci		*p = xdr_zero;
84862306a36Sopenharmony_ci	}
84962306a36Sopenharmony_ci}
85062306a36Sopenharmony_ci
85162306a36Sopenharmony_cistatic void nfs3_xdr_enc_setattr3args(struct rpc_rqst *req,
85262306a36Sopenharmony_ci				      struct xdr_stream *xdr,
85362306a36Sopenharmony_ci				      const void *data)
85462306a36Sopenharmony_ci{
85562306a36Sopenharmony_ci	const struct nfs3_sattrargs *args = data;
85662306a36Sopenharmony_ci	encode_nfs_fh3(xdr, args->fh);
85762306a36Sopenharmony_ci	encode_sattr3(xdr, args->sattr, rpc_rqst_userns(req));
85862306a36Sopenharmony_ci	encode_sattrguard3(xdr, args);
85962306a36Sopenharmony_ci}
86062306a36Sopenharmony_ci
86162306a36Sopenharmony_ci/*
86262306a36Sopenharmony_ci * 3.3.3  LOOKUP3args
86362306a36Sopenharmony_ci *
86462306a36Sopenharmony_ci *	struct LOOKUP3args {
86562306a36Sopenharmony_ci *		diropargs3  what;
86662306a36Sopenharmony_ci *	};
86762306a36Sopenharmony_ci */
86862306a36Sopenharmony_cistatic void nfs3_xdr_enc_lookup3args(struct rpc_rqst *req,
86962306a36Sopenharmony_ci				     struct xdr_stream *xdr,
87062306a36Sopenharmony_ci				     const void *data)
87162306a36Sopenharmony_ci{
87262306a36Sopenharmony_ci	const struct nfs3_diropargs *args = data;
87362306a36Sopenharmony_ci
87462306a36Sopenharmony_ci	encode_diropargs3(xdr, args->fh, args->name, args->len);
87562306a36Sopenharmony_ci}
87662306a36Sopenharmony_ci
87762306a36Sopenharmony_ci/*
87862306a36Sopenharmony_ci * 3.3.4  ACCESS3args
87962306a36Sopenharmony_ci *
88062306a36Sopenharmony_ci *	struct ACCESS3args {
88162306a36Sopenharmony_ci *		nfs_fh3		object;
88262306a36Sopenharmony_ci *		uint32		access;
88362306a36Sopenharmony_ci *	};
88462306a36Sopenharmony_ci */
88562306a36Sopenharmony_cistatic void encode_access3args(struct xdr_stream *xdr,
88662306a36Sopenharmony_ci			       const struct nfs3_accessargs *args)
88762306a36Sopenharmony_ci{
88862306a36Sopenharmony_ci	encode_nfs_fh3(xdr, args->fh);
88962306a36Sopenharmony_ci	encode_uint32(xdr, args->access);
89062306a36Sopenharmony_ci}
89162306a36Sopenharmony_ci
89262306a36Sopenharmony_cistatic void nfs3_xdr_enc_access3args(struct rpc_rqst *req,
89362306a36Sopenharmony_ci				     struct xdr_stream *xdr,
89462306a36Sopenharmony_ci				     const void *data)
89562306a36Sopenharmony_ci{
89662306a36Sopenharmony_ci	const struct nfs3_accessargs *args = data;
89762306a36Sopenharmony_ci
89862306a36Sopenharmony_ci	encode_access3args(xdr, args);
89962306a36Sopenharmony_ci}
90062306a36Sopenharmony_ci
90162306a36Sopenharmony_ci/*
90262306a36Sopenharmony_ci * 3.3.5  READLINK3args
90362306a36Sopenharmony_ci *
90462306a36Sopenharmony_ci *	struct READLINK3args {
90562306a36Sopenharmony_ci *		nfs_fh3	symlink;
90662306a36Sopenharmony_ci *	};
90762306a36Sopenharmony_ci */
90862306a36Sopenharmony_cistatic void nfs3_xdr_enc_readlink3args(struct rpc_rqst *req,
90962306a36Sopenharmony_ci				       struct xdr_stream *xdr,
91062306a36Sopenharmony_ci				       const void *data)
91162306a36Sopenharmony_ci{
91262306a36Sopenharmony_ci	const struct nfs3_readlinkargs *args = data;
91362306a36Sopenharmony_ci
91462306a36Sopenharmony_ci	encode_nfs_fh3(xdr, args->fh);
91562306a36Sopenharmony_ci	rpc_prepare_reply_pages(req, args->pages, args->pgbase, args->pglen,
91662306a36Sopenharmony_ci				NFS3_readlinkres_sz - NFS3_pagepad_sz);
91762306a36Sopenharmony_ci}
91862306a36Sopenharmony_ci
91962306a36Sopenharmony_ci/*
92062306a36Sopenharmony_ci * 3.3.6  READ3args
92162306a36Sopenharmony_ci *
92262306a36Sopenharmony_ci *	struct READ3args {
92362306a36Sopenharmony_ci *		nfs_fh3		file;
92462306a36Sopenharmony_ci *		offset3		offset;
92562306a36Sopenharmony_ci *		count3		count;
92662306a36Sopenharmony_ci *	};
92762306a36Sopenharmony_ci */
92862306a36Sopenharmony_cistatic void encode_read3args(struct xdr_stream *xdr,
92962306a36Sopenharmony_ci			     const struct nfs_pgio_args *args)
93062306a36Sopenharmony_ci{
93162306a36Sopenharmony_ci	__be32 *p;
93262306a36Sopenharmony_ci
93362306a36Sopenharmony_ci	encode_nfs_fh3(xdr, args->fh);
93462306a36Sopenharmony_ci
93562306a36Sopenharmony_ci	p = xdr_reserve_space(xdr, 8 + 4);
93662306a36Sopenharmony_ci	p = xdr_encode_hyper(p, args->offset);
93762306a36Sopenharmony_ci	*p = cpu_to_be32(args->count);
93862306a36Sopenharmony_ci}
93962306a36Sopenharmony_ci
94062306a36Sopenharmony_cistatic void nfs3_xdr_enc_read3args(struct rpc_rqst *req,
94162306a36Sopenharmony_ci				   struct xdr_stream *xdr,
94262306a36Sopenharmony_ci				   const void *data)
94362306a36Sopenharmony_ci{
94462306a36Sopenharmony_ci	const struct nfs_pgio_args *args = data;
94562306a36Sopenharmony_ci	unsigned int replen = args->replen ? args->replen :
94662306a36Sopenharmony_ci					     NFS3_readres_sz - NFS3_pagepad_sz;
94762306a36Sopenharmony_ci
94862306a36Sopenharmony_ci	encode_read3args(xdr, args);
94962306a36Sopenharmony_ci	rpc_prepare_reply_pages(req, args->pages, args->pgbase,
95062306a36Sopenharmony_ci				args->count, replen);
95162306a36Sopenharmony_ci	req->rq_rcv_buf.flags |= XDRBUF_READ;
95262306a36Sopenharmony_ci}
95362306a36Sopenharmony_ci
95462306a36Sopenharmony_ci/*
95562306a36Sopenharmony_ci * 3.3.7  WRITE3args
95662306a36Sopenharmony_ci *
95762306a36Sopenharmony_ci *	enum stable_how {
95862306a36Sopenharmony_ci *		UNSTABLE  = 0,
95962306a36Sopenharmony_ci *		DATA_SYNC = 1,
96062306a36Sopenharmony_ci *		FILE_SYNC = 2
96162306a36Sopenharmony_ci *	};
96262306a36Sopenharmony_ci *
96362306a36Sopenharmony_ci *	struct WRITE3args {
96462306a36Sopenharmony_ci *		nfs_fh3		file;
96562306a36Sopenharmony_ci *		offset3		offset;
96662306a36Sopenharmony_ci *		count3		count;
96762306a36Sopenharmony_ci *		stable_how	stable;
96862306a36Sopenharmony_ci *		opaque		data<>;
96962306a36Sopenharmony_ci *	};
97062306a36Sopenharmony_ci */
97162306a36Sopenharmony_cistatic void encode_write3args(struct xdr_stream *xdr,
97262306a36Sopenharmony_ci			      const struct nfs_pgio_args *args)
97362306a36Sopenharmony_ci{
97462306a36Sopenharmony_ci	__be32 *p;
97562306a36Sopenharmony_ci
97662306a36Sopenharmony_ci	encode_nfs_fh3(xdr, args->fh);
97762306a36Sopenharmony_ci
97862306a36Sopenharmony_ci	p = xdr_reserve_space(xdr, 8 + 4 + 4 + 4);
97962306a36Sopenharmony_ci	p = xdr_encode_hyper(p, args->offset);
98062306a36Sopenharmony_ci	*p++ = cpu_to_be32(args->count);
98162306a36Sopenharmony_ci	*p++ = cpu_to_be32(args->stable);
98262306a36Sopenharmony_ci	*p = cpu_to_be32(args->count);
98362306a36Sopenharmony_ci	xdr_write_pages(xdr, args->pages, args->pgbase, args->count);
98462306a36Sopenharmony_ci}
98562306a36Sopenharmony_ci
98662306a36Sopenharmony_cistatic void nfs3_xdr_enc_write3args(struct rpc_rqst *req,
98762306a36Sopenharmony_ci				    struct xdr_stream *xdr,
98862306a36Sopenharmony_ci				    const void *data)
98962306a36Sopenharmony_ci{
99062306a36Sopenharmony_ci	const struct nfs_pgio_args *args = data;
99162306a36Sopenharmony_ci
99262306a36Sopenharmony_ci	encode_write3args(xdr, args);
99362306a36Sopenharmony_ci	xdr->buf->flags |= XDRBUF_WRITE;
99462306a36Sopenharmony_ci}
99562306a36Sopenharmony_ci
99662306a36Sopenharmony_ci/*
99762306a36Sopenharmony_ci * 3.3.8  CREATE3args
99862306a36Sopenharmony_ci *
99962306a36Sopenharmony_ci *	enum createmode3 {
100062306a36Sopenharmony_ci *		UNCHECKED = 0,
100162306a36Sopenharmony_ci *		GUARDED   = 1,
100262306a36Sopenharmony_ci *		EXCLUSIVE = 2
100362306a36Sopenharmony_ci *	};
100462306a36Sopenharmony_ci *
100562306a36Sopenharmony_ci *	union createhow3 switch (createmode3 mode) {
100662306a36Sopenharmony_ci *	case UNCHECKED:
100762306a36Sopenharmony_ci *	case GUARDED:
100862306a36Sopenharmony_ci *		sattr3       obj_attributes;
100962306a36Sopenharmony_ci *	case EXCLUSIVE:
101062306a36Sopenharmony_ci *		createverf3  verf;
101162306a36Sopenharmony_ci *	};
101262306a36Sopenharmony_ci *
101362306a36Sopenharmony_ci *	struct CREATE3args {
101462306a36Sopenharmony_ci *		diropargs3	where;
101562306a36Sopenharmony_ci *		createhow3	how;
101662306a36Sopenharmony_ci *	};
101762306a36Sopenharmony_ci */
101862306a36Sopenharmony_cistatic void encode_createhow3(struct xdr_stream *xdr,
101962306a36Sopenharmony_ci			      const struct nfs3_createargs *args,
102062306a36Sopenharmony_ci			      struct user_namespace *userns)
102162306a36Sopenharmony_ci{
102262306a36Sopenharmony_ci	encode_uint32(xdr, args->createmode);
102362306a36Sopenharmony_ci	switch (args->createmode) {
102462306a36Sopenharmony_ci	case NFS3_CREATE_UNCHECKED:
102562306a36Sopenharmony_ci	case NFS3_CREATE_GUARDED:
102662306a36Sopenharmony_ci		encode_sattr3(xdr, args->sattr, userns);
102762306a36Sopenharmony_ci		break;
102862306a36Sopenharmony_ci	case NFS3_CREATE_EXCLUSIVE:
102962306a36Sopenharmony_ci		encode_createverf3(xdr, args->verifier);
103062306a36Sopenharmony_ci		break;
103162306a36Sopenharmony_ci	default:
103262306a36Sopenharmony_ci		BUG();
103362306a36Sopenharmony_ci	}
103462306a36Sopenharmony_ci}
103562306a36Sopenharmony_ci
103662306a36Sopenharmony_cistatic void nfs3_xdr_enc_create3args(struct rpc_rqst *req,
103762306a36Sopenharmony_ci				     struct xdr_stream *xdr,
103862306a36Sopenharmony_ci				     const void *data)
103962306a36Sopenharmony_ci{
104062306a36Sopenharmony_ci	const struct nfs3_createargs *args = data;
104162306a36Sopenharmony_ci
104262306a36Sopenharmony_ci	encode_diropargs3(xdr, args->fh, args->name, args->len);
104362306a36Sopenharmony_ci	encode_createhow3(xdr, args, rpc_rqst_userns(req));
104462306a36Sopenharmony_ci}
104562306a36Sopenharmony_ci
104662306a36Sopenharmony_ci/*
104762306a36Sopenharmony_ci * 3.3.9  MKDIR3args
104862306a36Sopenharmony_ci *
104962306a36Sopenharmony_ci *	struct MKDIR3args {
105062306a36Sopenharmony_ci *		diropargs3	where;
105162306a36Sopenharmony_ci *		sattr3		attributes;
105262306a36Sopenharmony_ci *	};
105362306a36Sopenharmony_ci */
105462306a36Sopenharmony_cistatic void nfs3_xdr_enc_mkdir3args(struct rpc_rqst *req,
105562306a36Sopenharmony_ci				    struct xdr_stream *xdr,
105662306a36Sopenharmony_ci				    const void *data)
105762306a36Sopenharmony_ci{
105862306a36Sopenharmony_ci	const struct nfs3_mkdirargs *args = data;
105962306a36Sopenharmony_ci
106062306a36Sopenharmony_ci	encode_diropargs3(xdr, args->fh, args->name, args->len);
106162306a36Sopenharmony_ci	encode_sattr3(xdr, args->sattr, rpc_rqst_userns(req));
106262306a36Sopenharmony_ci}
106362306a36Sopenharmony_ci
106462306a36Sopenharmony_ci/*
106562306a36Sopenharmony_ci * 3.3.10  SYMLINK3args
106662306a36Sopenharmony_ci *
106762306a36Sopenharmony_ci *	struct symlinkdata3 {
106862306a36Sopenharmony_ci *		sattr3		symlink_attributes;
106962306a36Sopenharmony_ci *		nfspath3	symlink_data;
107062306a36Sopenharmony_ci *	};
107162306a36Sopenharmony_ci *
107262306a36Sopenharmony_ci *	struct SYMLINK3args {
107362306a36Sopenharmony_ci *		diropargs3	where;
107462306a36Sopenharmony_ci *		symlinkdata3	symlink;
107562306a36Sopenharmony_ci *	};
107662306a36Sopenharmony_ci */
107762306a36Sopenharmony_cistatic void encode_symlinkdata3(struct xdr_stream *xdr,
107862306a36Sopenharmony_ci				const void *data,
107962306a36Sopenharmony_ci				struct user_namespace *userns)
108062306a36Sopenharmony_ci{
108162306a36Sopenharmony_ci	const struct nfs3_symlinkargs *args = data;
108262306a36Sopenharmony_ci
108362306a36Sopenharmony_ci	encode_sattr3(xdr, args->sattr, userns);
108462306a36Sopenharmony_ci	encode_nfspath3(xdr, args->pages, args->pathlen);
108562306a36Sopenharmony_ci}
108662306a36Sopenharmony_ci
108762306a36Sopenharmony_cistatic void nfs3_xdr_enc_symlink3args(struct rpc_rqst *req,
108862306a36Sopenharmony_ci				      struct xdr_stream *xdr,
108962306a36Sopenharmony_ci				      const void *data)
109062306a36Sopenharmony_ci{
109162306a36Sopenharmony_ci	const struct nfs3_symlinkargs *args = data;
109262306a36Sopenharmony_ci
109362306a36Sopenharmony_ci	encode_diropargs3(xdr, args->fromfh, args->fromname, args->fromlen);
109462306a36Sopenharmony_ci	encode_symlinkdata3(xdr, args, rpc_rqst_userns(req));
109562306a36Sopenharmony_ci	xdr->buf->flags |= XDRBUF_WRITE;
109662306a36Sopenharmony_ci}
109762306a36Sopenharmony_ci
109862306a36Sopenharmony_ci/*
109962306a36Sopenharmony_ci * 3.3.11  MKNOD3args
110062306a36Sopenharmony_ci *
110162306a36Sopenharmony_ci *	struct devicedata3 {
110262306a36Sopenharmony_ci *		sattr3		dev_attributes;
110362306a36Sopenharmony_ci *		specdata3	spec;
110462306a36Sopenharmony_ci *	};
110562306a36Sopenharmony_ci *
110662306a36Sopenharmony_ci *	union mknoddata3 switch (ftype3 type) {
110762306a36Sopenharmony_ci *	case NF3CHR:
110862306a36Sopenharmony_ci *	case NF3BLK:
110962306a36Sopenharmony_ci *		devicedata3	device;
111062306a36Sopenharmony_ci *	case NF3SOCK:
111162306a36Sopenharmony_ci *	case NF3FIFO:
111262306a36Sopenharmony_ci *		sattr3		pipe_attributes;
111362306a36Sopenharmony_ci *	default:
111462306a36Sopenharmony_ci *		void;
111562306a36Sopenharmony_ci *	};
111662306a36Sopenharmony_ci *
111762306a36Sopenharmony_ci *	struct MKNOD3args {
111862306a36Sopenharmony_ci *		diropargs3	where;
111962306a36Sopenharmony_ci *		mknoddata3	what;
112062306a36Sopenharmony_ci *	};
112162306a36Sopenharmony_ci */
112262306a36Sopenharmony_cistatic void encode_devicedata3(struct xdr_stream *xdr,
112362306a36Sopenharmony_ci			       const struct nfs3_mknodargs *args,
112462306a36Sopenharmony_ci			       struct user_namespace *userns)
112562306a36Sopenharmony_ci{
112662306a36Sopenharmony_ci	encode_sattr3(xdr, args->sattr, userns);
112762306a36Sopenharmony_ci	encode_specdata3(xdr, args->rdev);
112862306a36Sopenharmony_ci}
112962306a36Sopenharmony_ci
113062306a36Sopenharmony_cistatic void encode_mknoddata3(struct xdr_stream *xdr,
113162306a36Sopenharmony_ci			      const struct nfs3_mknodargs *args,
113262306a36Sopenharmony_ci			      struct user_namespace *userns)
113362306a36Sopenharmony_ci{
113462306a36Sopenharmony_ci	encode_ftype3(xdr, args->type);
113562306a36Sopenharmony_ci	switch (args->type) {
113662306a36Sopenharmony_ci	case NF3CHR:
113762306a36Sopenharmony_ci	case NF3BLK:
113862306a36Sopenharmony_ci		encode_devicedata3(xdr, args, userns);
113962306a36Sopenharmony_ci		break;
114062306a36Sopenharmony_ci	case NF3SOCK:
114162306a36Sopenharmony_ci	case NF3FIFO:
114262306a36Sopenharmony_ci		encode_sattr3(xdr, args->sattr, userns);
114362306a36Sopenharmony_ci		break;
114462306a36Sopenharmony_ci	case NF3REG:
114562306a36Sopenharmony_ci	case NF3DIR:
114662306a36Sopenharmony_ci		break;
114762306a36Sopenharmony_ci	default:
114862306a36Sopenharmony_ci		BUG();
114962306a36Sopenharmony_ci	}
115062306a36Sopenharmony_ci}
115162306a36Sopenharmony_ci
115262306a36Sopenharmony_cistatic void nfs3_xdr_enc_mknod3args(struct rpc_rqst *req,
115362306a36Sopenharmony_ci				    struct xdr_stream *xdr,
115462306a36Sopenharmony_ci				    const void *data)
115562306a36Sopenharmony_ci{
115662306a36Sopenharmony_ci	const struct nfs3_mknodargs *args = data;
115762306a36Sopenharmony_ci
115862306a36Sopenharmony_ci	encode_diropargs3(xdr, args->fh, args->name, args->len);
115962306a36Sopenharmony_ci	encode_mknoddata3(xdr, args, rpc_rqst_userns(req));
116062306a36Sopenharmony_ci}
116162306a36Sopenharmony_ci
116262306a36Sopenharmony_ci/*
116362306a36Sopenharmony_ci * 3.3.12  REMOVE3args
116462306a36Sopenharmony_ci *
116562306a36Sopenharmony_ci *	struct REMOVE3args {
116662306a36Sopenharmony_ci *		diropargs3  object;
116762306a36Sopenharmony_ci *	};
116862306a36Sopenharmony_ci */
116962306a36Sopenharmony_cistatic void nfs3_xdr_enc_remove3args(struct rpc_rqst *req,
117062306a36Sopenharmony_ci				     struct xdr_stream *xdr,
117162306a36Sopenharmony_ci				     const void *data)
117262306a36Sopenharmony_ci{
117362306a36Sopenharmony_ci	const struct nfs_removeargs *args = data;
117462306a36Sopenharmony_ci
117562306a36Sopenharmony_ci	encode_diropargs3(xdr, args->fh, args->name.name, args->name.len);
117662306a36Sopenharmony_ci}
117762306a36Sopenharmony_ci
117862306a36Sopenharmony_ci/*
117962306a36Sopenharmony_ci * 3.3.14  RENAME3args
118062306a36Sopenharmony_ci *
118162306a36Sopenharmony_ci *	struct RENAME3args {
118262306a36Sopenharmony_ci *		diropargs3	from;
118362306a36Sopenharmony_ci *		diropargs3	to;
118462306a36Sopenharmony_ci *	};
118562306a36Sopenharmony_ci */
118662306a36Sopenharmony_cistatic void nfs3_xdr_enc_rename3args(struct rpc_rqst *req,
118762306a36Sopenharmony_ci				     struct xdr_stream *xdr,
118862306a36Sopenharmony_ci				     const void *data)
118962306a36Sopenharmony_ci{
119062306a36Sopenharmony_ci	const struct nfs_renameargs *args = data;
119162306a36Sopenharmony_ci	const struct qstr *old = args->old_name;
119262306a36Sopenharmony_ci	const struct qstr *new = args->new_name;
119362306a36Sopenharmony_ci
119462306a36Sopenharmony_ci	encode_diropargs3(xdr, args->old_dir, old->name, old->len);
119562306a36Sopenharmony_ci	encode_diropargs3(xdr, args->new_dir, new->name, new->len);
119662306a36Sopenharmony_ci}
119762306a36Sopenharmony_ci
119862306a36Sopenharmony_ci/*
119962306a36Sopenharmony_ci * 3.3.15  LINK3args
120062306a36Sopenharmony_ci *
120162306a36Sopenharmony_ci *	struct LINK3args {
120262306a36Sopenharmony_ci *		nfs_fh3		file;
120362306a36Sopenharmony_ci *		diropargs3	link;
120462306a36Sopenharmony_ci *	};
120562306a36Sopenharmony_ci */
120662306a36Sopenharmony_cistatic void nfs3_xdr_enc_link3args(struct rpc_rqst *req,
120762306a36Sopenharmony_ci				   struct xdr_stream *xdr,
120862306a36Sopenharmony_ci				   const void *data)
120962306a36Sopenharmony_ci{
121062306a36Sopenharmony_ci	const struct nfs3_linkargs *args = data;
121162306a36Sopenharmony_ci
121262306a36Sopenharmony_ci	encode_nfs_fh3(xdr, args->fromfh);
121362306a36Sopenharmony_ci	encode_diropargs3(xdr, args->tofh, args->toname, args->tolen);
121462306a36Sopenharmony_ci}
121562306a36Sopenharmony_ci
121662306a36Sopenharmony_ci/*
121762306a36Sopenharmony_ci * 3.3.16  READDIR3args
121862306a36Sopenharmony_ci *
121962306a36Sopenharmony_ci *	struct READDIR3args {
122062306a36Sopenharmony_ci *		nfs_fh3		dir;
122162306a36Sopenharmony_ci *		cookie3		cookie;
122262306a36Sopenharmony_ci *		cookieverf3	cookieverf;
122362306a36Sopenharmony_ci *		count3		count;
122462306a36Sopenharmony_ci *	};
122562306a36Sopenharmony_ci */
122662306a36Sopenharmony_cistatic void encode_readdir3args(struct xdr_stream *xdr,
122762306a36Sopenharmony_ci				const struct nfs3_readdirargs *args)
122862306a36Sopenharmony_ci{
122962306a36Sopenharmony_ci	__be32 *p;
123062306a36Sopenharmony_ci
123162306a36Sopenharmony_ci	encode_nfs_fh3(xdr, args->fh);
123262306a36Sopenharmony_ci
123362306a36Sopenharmony_ci	p = xdr_reserve_space(xdr, 8 + NFS3_COOKIEVERFSIZE + 4);
123462306a36Sopenharmony_ci	p = xdr_encode_cookie3(p, args->cookie);
123562306a36Sopenharmony_ci	p = xdr_encode_cookieverf3(p, args->verf);
123662306a36Sopenharmony_ci	*p = cpu_to_be32(args->count);
123762306a36Sopenharmony_ci}
123862306a36Sopenharmony_ci
123962306a36Sopenharmony_cistatic void nfs3_xdr_enc_readdir3args(struct rpc_rqst *req,
124062306a36Sopenharmony_ci				      struct xdr_stream *xdr,
124162306a36Sopenharmony_ci				      const void *data)
124262306a36Sopenharmony_ci{
124362306a36Sopenharmony_ci	const struct nfs3_readdirargs *args = data;
124462306a36Sopenharmony_ci
124562306a36Sopenharmony_ci	encode_readdir3args(xdr, args);
124662306a36Sopenharmony_ci	rpc_prepare_reply_pages(req, args->pages, 0, args->count,
124762306a36Sopenharmony_ci				NFS3_readdirres_sz - NFS3_pagepad_sz);
124862306a36Sopenharmony_ci}
124962306a36Sopenharmony_ci
125062306a36Sopenharmony_ci/*
125162306a36Sopenharmony_ci * 3.3.17  READDIRPLUS3args
125262306a36Sopenharmony_ci *
125362306a36Sopenharmony_ci *	struct READDIRPLUS3args {
125462306a36Sopenharmony_ci *		nfs_fh3		dir;
125562306a36Sopenharmony_ci *		cookie3		cookie;
125662306a36Sopenharmony_ci *		cookieverf3	cookieverf;
125762306a36Sopenharmony_ci *		count3		dircount;
125862306a36Sopenharmony_ci *		count3		maxcount;
125962306a36Sopenharmony_ci *	};
126062306a36Sopenharmony_ci */
126162306a36Sopenharmony_cistatic void encode_readdirplus3args(struct xdr_stream *xdr,
126262306a36Sopenharmony_ci				    const struct nfs3_readdirargs *args)
126362306a36Sopenharmony_ci{
126462306a36Sopenharmony_ci	uint32_t dircount = args->count;
126562306a36Sopenharmony_ci	uint32_t maxcount = args->count;
126662306a36Sopenharmony_ci	__be32 *p;
126762306a36Sopenharmony_ci
126862306a36Sopenharmony_ci	encode_nfs_fh3(xdr, args->fh);
126962306a36Sopenharmony_ci
127062306a36Sopenharmony_ci	p = xdr_reserve_space(xdr, 8 + NFS3_COOKIEVERFSIZE + 4 + 4);
127162306a36Sopenharmony_ci	p = xdr_encode_cookie3(p, args->cookie);
127262306a36Sopenharmony_ci	p = xdr_encode_cookieverf3(p, args->verf);
127362306a36Sopenharmony_ci
127462306a36Sopenharmony_ci	/*
127562306a36Sopenharmony_ci	 * readdirplus: need dircount + buffer size.
127662306a36Sopenharmony_ci	 * We just make sure we make dircount big enough
127762306a36Sopenharmony_ci	 */
127862306a36Sopenharmony_ci	*p++ = cpu_to_be32(dircount);
127962306a36Sopenharmony_ci	*p = cpu_to_be32(maxcount);
128062306a36Sopenharmony_ci}
128162306a36Sopenharmony_ci
128262306a36Sopenharmony_cistatic void nfs3_xdr_enc_readdirplus3args(struct rpc_rqst *req,
128362306a36Sopenharmony_ci					  struct xdr_stream *xdr,
128462306a36Sopenharmony_ci					  const void *data)
128562306a36Sopenharmony_ci{
128662306a36Sopenharmony_ci	const struct nfs3_readdirargs *args = data;
128762306a36Sopenharmony_ci
128862306a36Sopenharmony_ci	encode_readdirplus3args(xdr, args);
128962306a36Sopenharmony_ci	rpc_prepare_reply_pages(req, args->pages, 0, args->count,
129062306a36Sopenharmony_ci				NFS3_readdirres_sz - NFS3_pagepad_sz);
129162306a36Sopenharmony_ci}
129262306a36Sopenharmony_ci
129362306a36Sopenharmony_ci/*
129462306a36Sopenharmony_ci * 3.3.21  COMMIT3args
129562306a36Sopenharmony_ci *
129662306a36Sopenharmony_ci *	struct COMMIT3args {
129762306a36Sopenharmony_ci *		nfs_fh3		file;
129862306a36Sopenharmony_ci *		offset3		offset;
129962306a36Sopenharmony_ci *		count3		count;
130062306a36Sopenharmony_ci *	};
130162306a36Sopenharmony_ci */
130262306a36Sopenharmony_cistatic void encode_commit3args(struct xdr_stream *xdr,
130362306a36Sopenharmony_ci			       const struct nfs_commitargs *args)
130462306a36Sopenharmony_ci{
130562306a36Sopenharmony_ci	__be32 *p;
130662306a36Sopenharmony_ci
130762306a36Sopenharmony_ci	encode_nfs_fh3(xdr, args->fh);
130862306a36Sopenharmony_ci
130962306a36Sopenharmony_ci	p = xdr_reserve_space(xdr, 8 + 4);
131062306a36Sopenharmony_ci	p = xdr_encode_hyper(p, args->offset);
131162306a36Sopenharmony_ci	*p = cpu_to_be32(args->count);
131262306a36Sopenharmony_ci}
131362306a36Sopenharmony_ci
131462306a36Sopenharmony_cistatic void nfs3_xdr_enc_commit3args(struct rpc_rqst *req,
131562306a36Sopenharmony_ci				     struct xdr_stream *xdr,
131662306a36Sopenharmony_ci				     const void *data)
131762306a36Sopenharmony_ci{
131862306a36Sopenharmony_ci	const struct nfs_commitargs *args = data;
131962306a36Sopenharmony_ci
132062306a36Sopenharmony_ci	encode_commit3args(xdr, args);
132162306a36Sopenharmony_ci}
132262306a36Sopenharmony_ci
132362306a36Sopenharmony_ci#ifdef CONFIG_NFS_V3_ACL
132462306a36Sopenharmony_ci
132562306a36Sopenharmony_cistatic void nfs3_xdr_enc_getacl3args(struct rpc_rqst *req,
132662306a36Sopenharmony_ci				     struct xdr_stream *xdr,
132762306a36Sopenharmony_ci				     const void *data)
132862306a36Sopenharmony_ci{
132962306a36Sopenharmony_ci	const struct nfs3_getaclargs *args = data;
133062306a36Sopenharmony_ci
133162306a36Sopenharmony_ci	encode_nfs_fh3(xdr, args->fh);
133262306a36Sopenharmony_ci	encode_uint32(xdr, args->mask);
133362306a36Sopenharmony_ci	if (args->mask & (NFS_ACL | NFS_DFACL)) {
133462306a36Sopenharmony_ci		rpc_prepare_reply_pages(req, args->pages, 0,
133562306a36Sopenharmony_ci					NFSACL_MAXPAGES << PAGE_SHIFT,
133662306a36Sopenharmony_ci					ACL3_getaclres_sz - NFS3_pagepad_sz);
133762306a36Sopenharmony_ci		req->rq_rcv_buf.flags |= XDRBUF_SPARSE_PAGES;
133862306a36Sopenharmony_ci	}
133962306a36Sopenharmony_ci}
134062306a36Sopenharmony_ci
134162306a36Sopenharmony_cistatic void nfs3_xdr_enc_setacl3args(struct rpc_rqst *req,
134262306a36Sopenharmony_ci				     struct xdr_stream *xdr,
134362306a36Sopenharmony_ci				     const void *data)
134462306a36Sopenharmony_ci{
134562306a36Sopenharmony_ci	const struct nfs3_setaclargs *args = data;
134662306a36Sopenharmony_ci	unsigned int base;
134762306a36Sopenharmony_ci	int error;
134862306a36Sopenharmony_ci
134962306a36Sopenharmony_ci	encode_nfs_fh3(xdr, NFS_FH(args->inode));
135062306a36Sopenharmony_ci	encode_uint32(xdr, args->mask);
135162306a36Sopenharmony_ci
135262306a36Sopenharmony_ci	base = req->rq_slen;
135362306a36Sopenharmony_ci	if (args->npages != 0)
135462306a36Sopenharmony_ci		xdr_write_pages(xdr, args->pages, 0, args->len);
135562306a36Sopenharmony_ci	else
135662306a36Sopenharmony_ci		xdr_reserve_space(xdr, args->len);
135762306a36Sopenharmony_ci
135862306a36Sopenharmony_ci	error = nfsacl_encode(xdr->buf, base, args->inode,
135962306a36Sopenharmony_ci			    (args->mask & NFS_ACL) ?
136062306a36Sopenharmony_ci			    args->acl_access : NULL, 1, 0);
136162306a36Sopenharmony_ci	/* FIXME: this is just broken */
136262306a36Sopenharmony_ci	BUG_ON(error < 0);
136362306a36Sopenharmony_ci	error = nfsacl_encode(xdr->buf, base + error, args->inode,
136462306a36Sopenharmony_ci			    (args->mask & NFS_DFACL) ?
136562306a36Sopenharmony_ci			    args->acl_default : NULL, 1,
136662306a36Sopenharmony_ci			    NFS_ACL_DEFAULT);
136762306a36Sopenharmony_ci	BUG_ON(error < 0);
136862306a36Sopenharmony_ci}
136962306a36Sopenharmony_ci
137062306a36Sopenharmony_ci#endif  /* CONFIG_NFS_V3_ACL */
137162306a36Sopenharmony_ci
137262306a36Sopenharmony_ci/*
137362306a36Sopenharmony_ci * NFSv3 XDR decode functions
137462306a36Sopenharmony_ci *
137562306a36Sopenharmony_ci * NFSv3 result types are defined in section 3.3 of RFC 1813:
137662306a36Sopenharmony_ci * "NFS Version 3 Protocol Specification".
137762306a36Sopenharmony_ci */
137862306a36Sopenharmony_ci
137962306a36Sopenharmony_ci/*
138062306a36Sopenharmony_ci * 3.3.1  GETATTR3res
138162306a36Sopenharmony_ci *
138262306a36Sopenharmony_ci *	struct GETATTR3resok {
138362306a36Sopenharmony_ci *		fattr3		obj_attributes;
138462306a36Sopenharmony_ci *	};
138562306a36Sopenharmony_ci *
138662306a36Sopenharmony_ci *	union GETATTR3res switch (nfsstat3 status) {
138762306a36Sopenharmony_ci *	case NFS3_OK:
138862306a36Sopenharmony_ci *		GETATTR3resok  resok;
138962306a36Sopenharmony_ci *	default:
139062306a36Sopenharmony_ci *		void;
139162306a36Sopenharmony_ci *	};
139262306a36Sopenharmony_ci */
139362306a36Sopenharmony_cistatic int nfs3_xdr_dec_getattr3res(struct rpc_rqst *req,
139462306a36Sopenharmony_ci				    struct xdr_stream *xdr,
139562306a36Sopenharmony_ci				    void *result)
139662306a36Sopenharmony_ci{
139762306a36Sopenharmony_ci	enum nfs_stat status;
139862306a36Sopenharmony_ci	int error;
139962306a36Sopenharmony_ci
140062306a36Sopenharmony_ci	error = decode_nfsstat3(xdr, &status);
140162306a36Sopenharmony_ci	if (unlikely(error))
140262306a36Sopenharmony_ci		goto out;
140362306a36Sopenharmony_ci	if (status != NFS3_OK)
140462306a36Sopenharmony_ci		goto out_default;
140562306a36Sopenharmony_ci	error = decode_fattr3(xdr, result, rpc_rqst_userns(req));
140662306a36Sopenharmony_ciout:
140762306a36Sopenharmony_ci	return error;
140862306a36Sopenharmony_ciout_default:
140962306a36Sopenharmony_ci	return nfs3_stat_to_errno(status);
141062306a36Sopenharmony_ci}
141162306a36Sopenharmony_ci
141262306a36Sopenharmony_ci/*
141362306a36Sopenharmony_ci * 3.3.2  SETATTR3res
141462306a36Sopenharmony_ci *
141562306a36Sopenharmony_ci *	struct SETATTR3resok {
141662306a36Sopenharmony_ci *		wcc_data  obj_wcc;
141762306a36Sopenharmony_ci *	};
141862306a36Sopenharmony_ci *
141962306a36Sopenharmony_ci *	struct SETATTR3resfail {
142062306a36Sopenharmony_ci *		wcc_data  obj_wcc;
142162306a36Sopenharmony_ci *	};
142262306a36Sopenharmony_ci *
142362306a36Sopenharmony_ci *	union SETATTR3res switch (nfsstat3 status) {
142462306a36Sopenharmony_ci *	case NFS3_OK:
142562306a36Sopenharmony_ci *		SETATTR3resok   resok;
142662306a36Sopenharmony_ci *	default:
142762306a36Sopenharmony_ci *		SETATTR3resfail resfail;
142862306a36Sopenharmony_ci *	};
142962306a36Sopenharmony_ci */
143062306a36Sopenharmony_cistatic int nfs3_xdr_dec_setattr3res(struct rpc_rqst *req,
143162306a36Sopenharmony_ci				    struct xdr_stream *xdr,
143262306a36Sopenharmony_ci				    void *result)
143362306a36Sopenharmony_ci{
143462306a36Sopenharmony_ci	enum nfs_stat status;
143562306a36Sopenharmony_ci	int error;
143662306a36Sopenharmony_ci
143762306a36Sopenharmony_ci	error = decode_nfsstat3(xdr, &status);
143862306a36Sopenharmony_ci	if (unlikely(error))
143962306a36Sopenharmony_ci		goto out;
144062306a36Sopenharmony_ci	error = decode_wcc_data(xdr, result, rpc_rqst_userns(req));
144162306a36Sopenharmony_ci	if (unlikely(error))
144262306a36Sopenharmony_ci		goto out;
144362306a36Sopenharmony_ci	if (status != NFS3_OK)
144462306a36Sopenharmony_ci		goto out_status;
144562306a36Sopenharmony_ciout:
144662306a36Sopenharmony_ci	return error;
144762306a36Sopenharmony_ciout_status:
144862306a36Sopenharmony_ci	return nfs3_stat_to_errno(status);
144962306a36Sopenharmony_ci}
145062306a36Sopenharmony_ci
145162306a36Sopenharmony_ci/*
145262306a36Sopenharmony_ci * 3.3.3  LOOKUP3res
145362306a36Sopenharmony_ci *
145462306a36Sopenharmony_ci *	struct LOOKUP3resok {
145562306a36Sopenharmony_ci *		nfs_fh3		object;
145662306a36Sopenharmony_ci *		post_op_attr	obj_attributes;
145762306a36Sopenharmony_ci *		post_op_attr	dir_attributes;
145862306a36Sopenharmony_ci *	};
145962306a36Sopenharmony_ci *
146062306a36Sopenharmony_ci *	struct LOOKUP3resfail {
146162306a36Sopenharmony_ci *		post_op_attr	dir_attributes;
146262306a36Sopenharmony_ci *	};
146362306a36Sopenharmony_ci *
146462306a36Sopenharmony_ci *	union LOOKUP3res switch (nfsstat3 status) {
146562306a36Sopenharmony_ci *	case NFS3_OK:
146662306a36Sopenharmony_ci *		LOOKUP3resok	resok;
146762306a36Sopenharmony_ci *	default:
146862306a36Sopenharmony_ci *		LOOKUP3resfail	resfail;
146962306a36Sopenharmony_ci *	};
147062306a36Sopenharmony_ci */
147162306a36Sopenharmony_cistatic int nfs3_xdr_dec_lookup3res(struct rpc_rqst *req,
147262306a36Sopenharmony_ci				   struct xdr_stream *xdr,
147362306a36Sopenharmony_ci				   void *data)
147462306a36Sopenharmony_ci{
147562306a36Sopenharmony_ci	struct user_namespace *userns = rpc_rqst_userns(req);
147662306a36Sopenharmony_ci	struct nfs3_diropres *result = data;
147762306a36Sopenharmony_ci	enum nfs_stat status;
147862306a36Sopenharmony_ci	int error;
147962306a36Sopenharmony_ci
148062306a36Sopenharmony_ci	error = decode_nfsstat3(xdr, &status);
148162306a36Sopenharmony_ci	if (unlikely(error))
148262306a36Sopenharmony_ci		goto out;
148362306a36Sopenharmony_ci	if (status != NFS3_OK)
148462306a36Sopenharmony_ci		goto out_default;
148562306a36Sopenharmony_ci	error = decode_nfs_fh3(xdr, result->fh);
148662306a36Sopenharmony_ci	if (unlikely(error))
148762306a36Sopenharmony_ci		goto out;
148862306a36Sopenharmony_ci	error = decode_post_op_attr(xdr, result->fattr, userns);
148962306a36Sopenharmony_ci	if (unlikely(error))
149062306a36Sopenharmony_ci		goto out;
149162306a36Sopenharmony_ci	error = decode_post_op_attr(xdr, result->dir_attr, userns);
149262306a36Sopenharmony_ciout:
149362306a36Sopenharmony_ci	return error;
149462306a36Sopenharmony_ciout_default:
149562306a36Sopenharmony_ci	error = decode_post_op_attr(xdr, result->dir_attr, userns);
149662306a36Sopenharmony_ci	if (unlikely(error))
149762306a36Sopenharmony_ci		goto out;
149862306a36Sopenharmony_ci	return nfs3_stat_to_errno(status);
149962306a36Sopenharmony_ci}
150062306a36Sopenharmony_ci
150162306a36Sopenharmony_ci/*
150262306a36Sopenharmony_ci * 3.3.4  ACCESS3res
150362306a36Sopenharmony_ci *
150462306a36Sopenharmony_ci *	struct ACCESS3resok {
150562306a36Sopenharmony_ci *		post_op_attr	obj_attributes;
150662306a36Sopenharmony_ci *		uint32		access;
150762306a36Sopenharmony_ci *	};
150862306a36Sopenharmony_ci *
150962306a36Sopenharmony_ci *	struct ACCESS3resfail {
151062306a36Sopenharmony_ci *		post_op_attr	obj_attributes;
151162306a36Sopenharmony_ci *	};
151262306a36Sopenharmony_ci *
151362306a36Sopenharmony_ci *	union ACCESS3res switch (nfsstat3 status) {
151462306a36Sopenharmony_ci *	case NFS3_OK:
151562306a36Sopenharmony_ci *		ACCESS3resok	resok;
151662306a36Sopenharmony_ci *	default:
151762306a36Sopenharmony_ci *		ACCESS3resfail	resfail;
151862306a36Sopenharmony_ci *	};
151962306a36Sopenharmony_ci */
152062306a36Sopenharmony_cistatic int nfs3_xdr_dec_access3res(struct rpc_rqst *req,
152162306a36Sopenharmony_ci				   struct xdr_stream *xdr,
152262306a36Sopenharmony_ci				   void *data)
152362306a36Sopenharmony_ci{
152462306a36Sopenharmony_ci	struct nfs3_accessres *result = data;
152562306a36Sopenharmony_ci	enum nfs_stat status;
152662306a36Sopenharmony_ci	int error;
152762306a36Sopenharmony_ci
152862306a36Sopenharmony_ci	error = decode_nfsstat3(xdr, &status);
152962306a36Sopenharmony_ci	if (unlikely(error))
153062306a36Sopenharmony_ci		goto out;
153162306a36Sopenharmony_ci	error = decode_post_op_attr(xdr, result->fattr, rpc_rqst_userns(req));
153262306a36Sopenharmony_ci	if (unlikely(error))
153362306a36Sopenharmony_ci		goto out;
153462306a36Sopenharmony_ci	if (status != NFS3_OK)
153562306a36Sopenharmony_ci		goto out_default;
153662306a36Sopenharmony_ci	error = decode_uint32(xdr, &result->access);
153762306a36Sopenharmony_ciout:
153862306a36Sopenharmony_ci	return error;
153962306a36Sopenharmony_ciout_default:
154062306a36Sopenharmony_ci	return nfs3_stat_to_errno(status);
154162306a36Sopenharmony_ci}
154262306a36Sopenharmony_ci
154362306a36Sopenharmony_ci/*
154462306a36Sopenharmony_ci * 3.3.5  READLINK3res
154562306a36Sopenharmony_ci *
154662306a36Sopenharmony_ci *	struct READLINK3resok {
154762306a36Sopenharmony_ci *		post_op_attr	symlink_attributes;
154862306a36Sopenharmony_ci *		nfspath3	data;
154962306a36Sopenharmony_ci *	};
155062306a36Sopenharmony_ci *
155162306a36Sopenharmony_ci *	struct READLINK3resfail {
155262306a36Sopenharmony_ci *		post_op_attr	symlink_attributes;
155362306a36Sopenharmony_ci *	};
155462306a36Sopenharmony_ci *
155562306a36Sopenharmony_ci *	union READLINK3res switch (nfsstat3 status) {
155662306a36Sopenharmony_ci *	case NFS3_OK:
155762306a36Sopenharmony_ci *		READLINK3resok	resok;
155862306a36Sopenharmony_ci *	default:
155962306a36Sopenharmony_ci *		READLINK3resfail resfail;
156062306a36Sopenharmony_ci *	};
156162306a36Sopenharmony_ci */
156262306a36Sopenharmony_cistatic int nfs3_xdr_dec_readlink3res(struct rpc_rqst *req,
156362306a36Sopenharmony_ci				     struct xdr_stream *xdr,
156462306a36Sopenharmony_ci				     void *result)
156562306a36Sopenharmony_ci{
156662306a36Sopenharmony_ci	enum nfs_stat status;
156762306a36Sopenharmony_ci	int error;
156862306a36Sopenharmony_ci
156962306a36Sopenharmony_ci	error = decode_nfsstat3(xdr, &status);
157062306a36Sopenharmony_ci	if (unlikely(error))
157162306a36Sopenharmony_ci		goto out;
157262306a36Sopenharmony_ci	error = decode_post_op_attr(xdr, result, rpc_rqst_userns(req));
157362306a36Sopenharmony_ci	if (unlikely(error))
157462306a36Sopenharmony_ci		goto out;
157562306a36Sopenharmony_ci	if (status != NFS3_OK)
157662306a36Sopenharmony_ci		goto out_default;
157762306a36Sopenharmony_ci	error = decode_nfspath3(xdr);
157862306a36Sopenharmony_ciout:
157962306a36Sopenharmony_ci	return error;
158062306a36Sopenharmony_ciout_default:
158162306a36Sopenharmony_ci	return nfs3_stat_to_errno(status);
158262306a36Sopenharmony_ci}
158362306a36Sopenharmony_ci
158462306a36Sopenharmony_ci/*
158562306a36Sopenharmony_ci * 3.3.6  READ3res
158662306a36Sopenharmony_ci *
158762306a36Sopenharmony_ci *	struct READ3resok {
158862306a36Sopenharmony_ci *		post_op_attr	file_attributes;
158962306a36Sopenharmony_ci *		count3		count;
159062306a36Sopenharmony_ci *		bool		eof;
159162306a36Sopenharmony_ci *		opaque		data<>;
159262306a36Sopenharmony_ci *	};
159362306a36Sopenharmony_ci *
159462306a36Sopenharmony_ci *	struct READ3resfail {
159562306a36Sopenharmony_ci *		post_op_attr	file_attributes;
159662306a36Sopenharmony_ci *	};
159762306a36Sopenharmony_ci *
159862306a36Sopenharmony_ci *	union READ3res switch (nfsstat3 status) {
159962306a36Sopenharmony_ci *	case NFS3_OK:
160062306a36Sopenharmony_ci *		READ3resok	resok;
160162306a36Sopenharmony_ci *	default:
160262306a36Sopenharmony_ci *		READ3resfail	resfail;
160362306a36Sopenharmony_ci *	};
160462306a36Sopenharmony_ci */
160562306a36Sopenharmony_cistatic int decode_read3resok(struct xdr_stream *xdr,
160662306a36Sopenharmony_ci			     struct nfs_pgio_res *result)
160762306a36Sopenharmony_ci{
160862306a36Sopenharmony_ci	u32 eof, count, ocount, recvd;
160962306a36Sopenharmony_ci	__be32 *p;
161062306a36Sopenharmony_ci
161162306a36Sopenharmony_ci	p = xdr_inline_decode(xdr, 4 + 4 + 4);
161262306a36Sopenharmony_ci	if (unlikely(!p))
161362306a36Sopenharmony_ci		return -EIO;
161462306a36Sopenharmony_ci	count = be32_to_cpup(p++);
161562306a36Sopenharmony_ci	eof = be32_to_cpup(p++);
161662306a36Sopenharmony_ci	ocount = be32_to_cpup(p++);
161762306a36Sopenharmony_ci	if (unlikely(ocount != count))
161862306a36Sopenharmony_ci		goto out_mismatch;
161962306a36Sopenharmony_ci	recvd = xdr_read_pages(xdr, count);
162062306a36Sopenharmony_ci	if (unlikely(count > recvd))
162162306a36Sopenharmony_ci		goto out_cheating;
162262306a36Sopenharmony_ciout:
162362306a36Sopenharmony_ci	result->eof = eof;
162462306a36Sopenharmony_ci	result->count = count;
162562306a36Sopenharmony_ci	return count;
162662306a36Sopenharmony_ciout_mismatch:
162762306a36Sopenharmony_ci	dprintk("NFS: READ count doesn't match length of opaque: "
162862306a36Sopenharmony_ci		"count %u != ocount %u\n", count, ocount);
162962306a36Sopenharmony_ci	return -EIO;
163062306a36Sopenharmony_ciout_cheating:
163162306a36Sopenharmony_ci	dprintk("NFS: server cheating in read result: "
163262306a36Sopenharmony_ci		"count %u > recvd %u\n", count, recvd);
163362306a36Sopenharmony_ci	count = recvd;
163462306a36Sopenharmony_ci	eof = 0;
163562306a36Sopenharmony_ci	goto out;
163662306a36Sopenharmony_ci}
163762306a36Sopenharmony_ci
163862306a36Sopenharmony_cistatic int nfs3_xdr_dec_read3res(struct rpc_rqst *req, struct xdr_stream *xdr,
163962306a36Sopenharmony_ci				 void *data)
164062306a36Sopenharmony_ci{
164162306a36Sopenharmony_ci	struct nfs_pgio_res *result = data;
164262306a36Sopenharmony_ci	unsigned int pos;
164362306a36Sopenharmony_ci	enum nfs_stat status;
164462306a36Sopenharmony_ci	int error;
164562306a36Sopenharmony_ci
164662306a36Sopenharmony_ci	pos = xdr_stream_pos(xdr);
164762306a36Sopenharmony_ci	error = decode_nfsstat3(xdr, &status);
164862306a36Sopenharmony_ci	if (unlikely(error))
164962306a36Sopenharmony_ci		goto out;
165062306a36Sopenharmony_ci	error = decode_post_op_attr(xdr, result->fattr, rpc_rqst_userns(req));
165162306a36Sopenharmony_ci	if (unlikely(error))
165262306a36Sopenharmony_ci		goto out;
165362306a36Sopenharmony_ci	result->op_status = status;
165462306a36Sopenharmony_ci	if (status != NFS3_OK)
165562306a36Sopenharmony_ci		goto out_status;
165662306a36Sopenharmony_ci	result->replen = 3 + ((xdr_stream_pos(xdr) - pos) >> 2);
165762306a36Sopenharmony_ci	error = decode_read3resok(xdr, result);
165862306a36Sopenharmony_ciout:
165962306a36Sopenharmony_ci	return error;
166062306a36Sopenharmony_ciout_status:
166162306a36Sopenharmony_ci	return nfs3_stat_to_errno(status);
166262306a36Sopenharmony_ci}
166362306a36Sopenharmony_ci
166462306a36Sopenharmony_ci/*
166562306a36Sopenharmony_ci * 3.3.7  WRITE3res
166662306a36Sopenharmony_ci *
166762306a36Sopenharmony_ci *	enum stable_how {
166862306a36Sopenharmony_ci *		UNSTABLE  = 0,
166962306a36Sopenharmony_ci *		DATA_SYNC = 1,
167062306a36Sopenharmony_ci *		FILE_SYNC = 2
167162306a36Sopenharmony_ci *	};
167262306a36Sopenharmony_ci *
167362306a36Sopenharmony_ci *	struct WRITE3resok {
167462306a36Sopenharmony_ci *		wcc_data	file_wcc;
167562306a36Sopenharmony_ci *		count3		count;
167662306a36Sopenharmony_ci *		stable_how	committed;
167762306a36Sopenharmony_ci *		writeverf3	verf;
167862306a36Sopenharmony_ci *	};
167962306a36Sopenharmony_ci *
168062306a36Sopenharmony_ci *	struct WRITE3resfail {
168162306a36Sopenharmony_ci *		wcc_data	file_wcc;
168262306a36Sopenharmony_ci *	};
168362306a36Sopenharmony_ci *
168462306a36Sopenharmony_ci *	union WRITE3res switch (nfsstat3 status) {
168562306a36Sopenharmony_ci *	case NFS3_OK:
168662306a36Sopenharmony_ci *		WRITE3resok	resok;
168762306a36Sopenharmony_ci *	default:
168862306a36Sopenharmony_ci *		WRITE3resfail	resfail;
168962306a36Sopenharmony_ci *	};
169062306a36Sopenharmony_ci */
169162306a36Sopenharmony_cistatic int decode_write3resok(struct xdr_stream *xdr,
169262306a36Sopenharmony_ci			      struct nfs_pgio_res *result)
169362306a36Sopenharmony_ci{
169462306a36Sopenharmony_ci	__be32 *p;
169562306a36Sopenharmony_ci
169662306a36Sopenharmony_ci	p = xdr_inline_decode(xdr, 4 + 4);
169762306a36Sopenharmony_ci	if (unlikely(!p))
169862306a36Sopenharmony_ci		return -EIO;
169962306a36Sopenharmony_ci	result->count = be32_to_cpup(p++);
170062306a36Sopenharmony_ci	result->verf->committed = be32_to_cpup(p++);
170162306a36Sopenharmony_ci	if (unlikely(result->verf->committed > NFS_FILE_SYNC))
170262306a36Sopenharmony_ci		goto out_badvalue;
170362306a36Sopenharmony_ci	if (decode_writeverf3(xdr, &result->verf->verifier))
170462306a36Sopenharmony_ci		return -EIO;
170562306a36Sopenharmony_ci	return result->count;
170662306a36Sopenharmony_ciout_badvalue:
170762306a36Sopenharmony_ci	dprintk("NFS: bad stable_how value: %u\n", result->verf->committed);
170862306a36Sopenharmony_ci	return -EIO;
170962306a36Sopenharmony_ci}
171062306a36Sopenharmony_ci
171162306a36Sopenharmony_cistatic int nfs3_xdr_dec_write3res(struct rpc_rqst *req, struct xdr_stream *xdr,
171262306a36Sopenharmony_ci				  void *data)
171362306a36Sopenharmony_ci{
171462306a36Sopenharmony_ci	struct nfs_pgio_res *result = data;
171562306a36Sopenharmony_ci	enum nfs_stat status;
171662306a36Sopenharmony_ci	int error;
171762306a36Sopenharmony_ci
171862306a36Sopenharmony_ci	error = decode_nfsstat3(xdr, &status);
171962306a36Sopenharmony_ci	if (unlikely(error))
172062306a36Sopenharmony_ci		goto out;
172162306a36Sopenharmony_ci	error = decode_wcc_data(xdr, result->fattr, rpc_rqst_userns(req));
172262306a36Sopenharmony_ci	if (unlikely(error))
172362306a36Sopenharmony_ci		goto out;
172462306a36Sopenharmony_ci	result->op_status = status;
172562306a36Sopenharmony_ci	if (status != NFS3_OK)
172662306a36Sopenharmony_ci		goto out_status;
172762306a36Sopenharmony_ci	error = decode_write3resok(xdr, result);
172862306a36Sopenharmony_ciout:
172962306a36Sopenharmony_ci	return error;
173062306a36Sopenharmony_ciout_status:
173162306a36Sopenharmony_ci	return nfs3_stat_to_errno(status);
173262306a36Sopenharmony_ci}
173362306a36Sopenharmony_ci
173462306a36Sopenharmony_ci/*
173562306a36Sopenharmony_ci * 3.3.8  CREATE3res
173662306a36Sopenharmony_ci *
173762306a36Sopenharmony_ci *	struct CREATE3resok {
173862306a36Sopenharmony_ci *		post_op_fh3	obj;
173962306a36Sopenharmony_ci *		post_op_attr	obj_attributes;
174062306a36Sopenharmony_ci *		wcc_data	dir_wcc;
174162306a36Sopenharmony_ci *	};
174262306a36Sopenharmony_ci *
174362306a36Sopenharmony_ci *	struct CREATE3resfail {
174462306a36Sopenharmony_ci *		wcc_data	dir_wcc;
174562306a36Sopenharmony_ci *	};
174662306a36Sopenharmony_ci *
174762306a36Sopenharmony_ci *	union CREATE3res switch (nfsstat3 status) {
174862306a36Sopenharmony_ci *	case NFS3_OK:
174962306a36Sopenharmony_ci *		CREATE3resok	resok;
175062306a36Sopenharmony_ci *	default:
175162306a36Sopenharmony_ci *		CREATE3resfail	resfail;
175262306a36Sopenharmony_ci *	};
175362306a36Sopenharmony_ci */
175462306a36Sopenharmony_cistatic int decode_create3resok(struct xdr_stream *xdr,
175562306a36Sopenharmony_ci			       struct nfs3_diropres *result,
175662306a36Sopenharmony_ci			       struct user_namespace *userns)
175762306a36Sopenharmony_ci{
175862306a36Sopenharmony_ci	int error;
175962306a36Sopenharmony_ci
176062306a36Sopenharmony_ci	error = decode_post_op_fh3(xdr, result->fh);
176162306a36Sopenharmony_ci	if (unlikely(error))
176262306a36Sopenharmony_ci		goto out;
176362306a36Sopenharmony_ci	error = decode_post_op_attr(xdr, result->fattr, userns);
176462306a36Sopenharmony_ci	if (unlikely(error))
176562306a36Sopenharmony_ci		goto out;
176662306a36Sopenharmony_ci	/* The server isn't required to return a file handle.
176762306a36Sopenharmony_ci	 * If it didn't, force the client to perform a LOOKUP
176862306a36Sopenharmony_ci	 * to determine the correct file handle and attribute
176962306a36Sopenharmony_ci	 * values for the new object. */
177062306a36Sopenharmony_ci	if (result->fh->size == 0)
177162306a36Sopenharmony_ci		result->fattr->valid = 0;
177262306a36Sopenharmony_ci	error = decode_wcc_data(xdr, result->dir_attr, userns);
177362306a36Sopenharmony_ciout:
177462306a36Sopenharmony_ci	return error;
177562306a36Sopenharmony_ci}
177662306a36Sopenharmony_ci
177762306a36Sopenharmony_cistatic int nfs3_xdr_dec_create3res(struct rpc_rqst *req,
177862306a36Sopenharmony_ci				   struct xdr_stream *xdr,
177962306a36Sopenharmony_ci				   void *data)
178062306a36Sopenharmony_ci{
178162306a36Sopenharmony_ci	struct user_namespace *userns = rpc_rqst_userns(req);
178262306a36Sopenharmony_ci	struct nfs3_diropres *result = data;
178362306a36Sopenharmony_ci	enum nfs_stat status;
178462306a36Sopenharmony_ci	int error;
178562306a36Sopenharmony_ci
178662306a36Sopenharmony_ci	error = decode_nfsstat3(xdr, &status);
178762306a36Sopenharmony_ci	if (unlikely(error))
178862306a36Sopenharmony_ci		goto out;
178962306a36Sopenharmony_ci	if (status != NFS3_OK)
179062306a36Sopenharmony_ci		goto out_default;
179162306a36Sopenharmony_ci	error = decode_create3resok(xdr, result, userns);
179262306a36Sopenharmony_ciout:
179362306a36Sopenharmony_ci	return error;
179462306a36Sopenharmony_ciout_default:
179562306a36Sopenharmony_ci	error = decode_wcc_data(xdr, result->dir_attr, userns);
179662306a36Sopenharmony_ci	if (unlikely(error))
179762306a36Sopenharmony_ci		goto out;
179862306a36Sopenharmony_ci	return nfs3_stat_to_errno(status);
179962306a36Sopenharmony_ci}
180062306a36Sopenharmony_ci
180162306a36Sopenharmony_ci/*
180262306a36Sopenharmony_ci * 3.3.12  REMOVE3res
180362306a36Sopenharmony_ci *
180462306a36Sopenharmony_ci *	struct REMOVE3resok {
180562306a36Sopenharmony_ci *		wcc_data    dir_wcc;
180662306a36Sopenharmony_ci *	};
180762306a36Sopenharmony_ci *
180862306a36Sopenharmony_ci *	struct REMOVE3resfail {
180962306a36Sopenharmony_ci *		wcc_data    dir_wcc;
181062306a36Sopenharmony_ci *	};
181162306a36Sopenharmony_ci *
181262306a36Sopenharmony_ci *	union REMOVE3res switch (nfsstat3 status) {
181362306a36Sopenharmony_ci *	case NFS3_OK:
181462306a36Sopenharmony_ci *		REMOVE3resok   resok;
181562306a36Sopenharmony_ci *	default:
181662306a36Sopenharmony_ci *		REMOVE3resfail resfail;
181762306a36Sopenharmony_ci *	};
181862306a36Sopenharmony_ci */
181962306a36Sopenharmony_cistatic int nfs3_xdr_dec_remove3res(struct rpc_rqst *req,
182062306a36Sopenharmony_ci				   struct xdr_stream *xdr,
182162306a36Sopenharmony_ci				   void *data)
182262306a36Sopenharmony_ci{
182362306a36Sopenharmony_ci	struct nfs_removeres *result = data;
182462306a36Sopenharmony_ci	enum nfs_stat status;
182562306a36Sopenharmony_ci	int error;
182662306a36Sopenharmony_ci
182762306a36Sopenharmony_ci	error = decode_nfsstat3(xdr, &status);
182862306a36Sopenharmony_ci	if (unlikely(error))
182962306a36Sopenharmony_ci		goto out;
183062306a36Sopenharmony_ci	error = decode_wcc_data(xdr, result->dir_attr, rpc_rqst_userns(req));
183162306a36Sopenharmony_ci	if (unlikely(error))
183262306a36Sopenharmony_ci		goto out;
183362306a36Sopenharmony_ci	if (status != NFS3_OK)
183462306a36Sopenharmony_ci		goto out_status;
183562306a36Sopenharmony_ciout:
183662306a36Sopenharmony_ci	return error;
183762306a36Sopenharmony_ciout_status:
183862306a36Sopenharmony_ci	return nfs3_stat_to_errno(status);
183962306a36Sopenharmony_ci}
184062306a36Sopenharmony_ci
184162306a36Sopenharmony_ci/*
184262306a36Sopenharmony_ci * 3.3.14  RENAME3res
184362306a36Sopenharmony_ci *
184462306a36Sopenharmony_ci *	struct RENAME3resok {
184562306a36Sopenharmony_ci *		wcc_data	fromdir_wcc;
184662306a36Sopenharmony_ci *		wcc_data	todir_wcc;
184762306a36Sopenharmony_ci *	};
184862306a36Sopenharmony_ci *
184962306a36Sopenharmony_ci *	struct RENAME3resfail {
185062306a36Sopenharmony_ci *		wcc_data	fromdir_wcc;
185162306a36Sopenharmony_ci *		wcc_data	todir_wcc;
185262306a36Sopenharmony_ci *	};
185362306a36Sopenharmony_ci *
185462306a36Sopenharmony_ci *	union RENAME3res switch (nfsstat3 status) {
185562306a36Sopenharmony_ci *	case NFS3_OK:
185662306a36Sopenharmony_ci *		RENAME3resok   resok;
185762306a36Sopenharmony_ci *	default:
185862306a36Sopenharmony_ci *		RENAME3resfail resfail;
185962306a36Sopenharmony_ci *	};
186062306a36Sopenharmony_ci */
186162306a36Sopenharmony_cistatic int nfs3_xdr_dec_rename3res(struct rpc_rqst *req,
186262306a36Sopenharmony_ci				   struct xdr_stream *xdr,
186362306a36Sopenharmony_ci				   void *data)
186462306a36Sopenharmony_ci{
186562306a36Sopenharmony_ci	struct user_namespace *userns = rpc_rqst_userns(req);
186662306a36Sopenharmony_ci	struct nfs_renameres *result = data;
186762306a36Sopenharmony_ci	enum nfs_stat status;
186862306a36Sopenharmony_ci	int error;
186962306a36Sopenharmony_ci
187062306a36Sopenharmony_ci	error = decode_nfsstat3(xdr, &status);
187162306a36Sopenharmony_ci	if (unlikely(error))
187262306a36Sopenharmony_ci		goto out;
187362306a36Sopenharmony_ci	error = decode_wcc_data(xdr, result->old_fattr, userns);
187462306a36Sopenharmony_ci	if (unlikely(error))
187562306a36Sopenharmony_ci		goto out;
187662306a36Sopenharmony_ci	error = decode_wcc_data(xdr, result->new_fattr, userns);
187762306a36Sopenharmony_ci	if (unlikely(error))
187862306a36Sopenharmony_ci		goto out;
187962306a36Sopenharmony_ci	if (status != NFS3_OK)
188062306a36Sopenharmony_ci		goto out_status;
188162306a36Sopenharmony_ciout:
188262306a36Sopenharmony_ci	return error;
188362306a36Sopenharmony_ciout_status:
188462306a36Sopenharmony_ci	return nfs3_stat_to_errno(status);
188562306a36Sopenharmony_ci}
188662306a36Sopenharmony_ci
188762306a36Sopenharmony_ci/*
188862306a36Sopenharmony_ci * 3.3.15  LINK3res
188962306a36Sopenharmony_ci *
189062306a36Sopenharmony_ci *	struct LINK3resok {
189162306a36Sopenharmony_ci *		post_op_attr	file_attributes;
189262306a36Sopenharmony_ci *		wcc_data	linkdir_wcc;
189362306a36Sopenharmony_ci *	};
189462306a36Sopenharmony_ci *
189562306a36Sopenharmony_ci *	struct LINK3resfail {
189662306a36Sopenharmony_ci *		post_op_attr	file_attributes;
189762306a36Sopenharmony_ci *		wcc_data	linkdir_wcc;
189862306a36Sopenharmony_ci *	};
189962306a36Sopenharmony_ci *
190062306a36Sopenharmony_ci *	union LINK3res switch (nfsstat3 status) {
190162306a36Sopenharmony_ci *	case NFS3_OK:
190262306a36Sopenharmony_ci *		LINK3resok	resok;
190362306a36Sopenharmony_ci *	default:
190462306a36Sopenharmony_ci *		LINK3resfail	resfail;
190562306a36Sopenharmony_ci *	};
190662306a36Sopenharmony_ci */
190762306a36Sopenharmony_cistatic int nfs3_xdr_dec_link3res(struct rpc_rqst *req, struct xdr_stream *xdr,
190862306a36Sopenharmony_ci				 void *data)
190962306a36Sopenharmony_ci{
191062306a36Sopenharmony_ci	struct user_namespace *userns = rpc_rqst_userns(req);
191162306a36Sopenharmony_ci	struct nfs3_linkres *result = data;
191262306a36Sopenharmony_ci	enum nfs_stat status;
191362306a36Sopenharmony_ci	int error;
191462306a36Sopenharmony_ci
191562306a36Sopenharmony_ci	error = decode_nfsstat3(xdr, &status);
191662306a36Sopenharmony_ci	if (unlikely(error))
191762306a36Sopenharmony_ci		goto out;
191862306a36Sopenharmony_ci	error = decode_post_op_attr(xdr, result->fattr, userns);
191962306a36Sopenharmony_ci	if (unlikely(error))
192062306a36Sopenharmony_ci		goto out;
192162306a36Sopenharmony_ci	error = decode_wcc_data(xdr, result->dir_attr, userns);
192262306a36Sopenharmony_ci	if (unlikely(error))
192362306a36Sopenharmony_ci		goto out;
192462306a36Sopenharmony_ci	if (status != NFS3_OK)
192562306a36Sopenharmony_ci		goto out_status;
192662306a36Sopenharmony_ciout:
192762306a36Sopenharmony_ci	return error;
192862306a36Sopenharmony_ciout_status:
192962306a36Sopenharmony_ci	return nfs3_stat_to_errno(status);
193062306a36Sopenharmony_ci}
193162306a36Sopenharmony_ci
193262306a36Sopenharmony_ci/**
193362306a36Sopenharmony_ci * nfs3_decode_dirent - Decode a single NFSv3 directory entry stored in
193462306a36Sopenharmony_ci *			the local page cache
193562306a36Sopenharmony_ci * @xdr: XDR stream where entry resides
193662306a36Sopenharmony_ci * @entry: buffer to fill in with entry data
193762306a36Sopenharmony_ci * @plus: boolean indicating whether this should be a readdirplus entry
193862306a36Sopenharmony_ci *
193962306a36Sopenharmony_ci * Returns zero if successful, otherwise a negative errno value is
194062306a36Sopenharmony_ci * returned.
194162306a36Sopenharmony_ci *
194262306a36Sopenharmony_ci * This function is not invoked during READDIR reply decoding, but
194362306a36Sopenharmony_ci * rather whenever an application invokes the getdents(2) system call
194462306a36Sopenharmony_ci * on a directory already in our cache.
194562306a36Sopenharmony_ci *
194662306a36Sopenharmony_ci * 3.3.16  entry3
194762306a36Sopenharmony_ci *
194862306a36Sopenharmony_ci *	struct entry3 {
194962306a36Sopenharmony_ci *		fileid3		fileid;
195062306a36Sopenharmony_ci *		filename3	name;
195162306a36Sopenharmony_ci *		cookie3		cookie;
195262306a36Sopenharmony_ci *		fhandle3	filehandle;
195362306a36Sopenharmony_ci *		post_op_attr3	attributes;
195462306a36Sopenharmony_ci *		entry3		*nextentry;
195562306a36Sopenharmony_ci *	};
195662306a36Sopenharmony_ci *
195762306a36Sopenharmony_ci * 3.3.17  entryplus3
195862306a36Sopenharmony_ci *	struct entryplus3 {
195962306a36Sopenharmony_ci *		fileid3		fileid;
196062306a36Sopenharmony_ci *		filename3	name;
196162306a36Sopenharmony_ci *		cookie3		cookie;
196262306a36Sopenharmony_ci *		post_op_attr	name_attributes;
196362306a36Sopenharmony_ci *		post_op_fh3	name_handle;
196462306a36Sopenharmony_ci *		entryplus3	*nextentry;
196562306a36Sopenharmony_ci *	};
196662306a36Sopenharmony_ci */
196762306a36Sopenharmony_ciint nfs3_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry,
196862306a36Sopenharmony_ci		       bool plus)
196962306a36Sopenharmony_ci{
197062306a36Sopenharmony_ci	struct user_namespace *userns = rpc_userns(entry->server->client);
197162306a36Sopenharmony_ci	__be32 *p;
197262306a36Sopenharmony_ci	int error;
197362306a36Sopenharmony_ci	u64 new_cookie;
197462306a36Sopenharmony_ci
197562306a36Sopenharmony_ci	p = xdr_inline_decode(xdr, 4);
197662306a36Sopenharmony_ci	if (unlikely(!p))
197762306a36Sopenharmony_ci		return -EAGAIN;
197862306a36Sopenharmony_ci	if (*p == xdr_zero) {
197962306a36Sopenharmony_ci		p = xdr_inline_decode(xdr, 4);
198062306a36Sopenharmony_ci		if (unlikely(!p))
198162306a36Sopenharmony_ci			return -EAGAIN;
198262306a36Sopenharmony_ci		if (*p == xdr_zero)
198362306a36Sopenharmony_ci			return -EAGAIN;
198462306a36Sopenharmony_ci		entry->eof = 1;
198562306a36Sopenharmony_ci		return -EBADCOOKIE;
198662306a36Sopenharmony_ci	}
198762306a36Sopenharmony_ci
198862306a36Sopenharmony_ci	error = decode_fileid3(xdr, &entry->ino);
198962306a36Sopenharmony_ci	if (unlikely(error))
199062306a36Sopenharmony_ci		return -EAGAIN;
199162306a36Sopenharmony_ci
199262306a36Sopenharmony_ci	error = decode_inline_filename3(xdr, &entry->name, &entry->len);
199362306a36Sopenharmony_ci	if (unlikely(error))
199462306a36Sopenharmony_ci		return error == -ENAMETOOLONG ? -ENAMETOOLONG : -EAGAIN;
199562306a36Sopenharmony_ci
199662306a36Sopenharmony_ci	error = decode_cookie3(xdr, &new_cookie);
199762306a36Sopenharmony_ci	if (unlikely(error))
199862306a36Sopenharmony_ci		return -EAGAIN;
199962306a36Sopenharmony_ci
200062306a36Sopenharmony_ci	entry->d_type = DT_UNKNOWN;
200162306a36Sopenharmony_ci
200262306a36Sopenharmony_ci	if (plus) {
200362306a36Sopenharmony_ci		entry->fattr->valid = 0;
200462306a36Sopenharmony_ci		error = decode_post_op_attr(xdr, entry->fattr, userns);
200562306a36Sopenharmony_ci		if (unlikely(error))
200662306a36Sopenharmony_ci			return -EAGAIN;
200762306a36Sopenharmony_ci		if (entry->fattr->valid & NFS_ATTR_FATTR_V3)
200862306a36Sopenharmony_ci			entry->d_type = nfs_umode_to_dtype(entry->fattr->mode);
200962306a36Sopenharmony_ci
201062306a36Sopenharmony_ci		if (entry->fattr->fileid != entry->ino) {
201162306a36Sopenharmony_ci			entry->fattr->mounted_on_fileid = entry->ino;
201262306a36Sopenharmony_ci			entry->fattr->valid |= NFS_ATTR_FATTR_MOUNTED_ON_FILEID;
201362306a36Sopenharmony_ci		}
201462306a36Sopenharmony_ci
201562306a36Sopenharmony_ci		/* In fact, a post_op_fh3: */
201662306a36Sopenharmony_ci		p = xdr_inline_decode(xdr, 4);
201762306a36Sopenharmony_ci		if (unlikely(!p))
201862306a36Sopenharmony_ci			return -EAGAIN;
201962306a36Sopenharmony_ci		if (*p != xdr_zero) {
202062306a36Sopenharmony_ci			error = decode_nfs_fh3(xdr, entry->fh);
202162306a36Sopenharmony_ci			if (unlikely(error))
202262306a36Sopenharmony_ci				return -EAGAIN;
202362306a36Sopenharmony_ci		} else
202462306a36Sopenharmony_ci			zero_nfs_fh3(entry->fh);
202562306a36Sopenharmony_ci	}
202662306a36Sopenharmony_ci
202762306a36Sopenharmony_ci	entry->cookie = new_cookie;
202862306a36Sopenharmony_ci
202962306a36Sopenharmony_ci	return 0;
203062306a36Sopenharmony_ci}
203162306a36Sopenharmony_ci
203262306a36Sopenharmony_ci/*
203362306a36Sopenharmony_ci * 3.3.16  READDIR3res
203462306a36Sopenharmony_ci *
203562306a36Sopenharmony_ci *	struct dirlist3 {
203662306a36Sopenharmony_ci *		entry3		*entries;
203762306a36Sopenharmony_ci *		bool		eof;
203862306a36Sopenharmony_ci *	};
203962306a36Sopenharmony_ci *
204062306a36Sopenharmony_ci *	struct READDIR3resok {
204162306a36Sopenharmony_ci *		post_op_attr	dir_attributes;
204262306a36Sopenharmony_ci *		cookieverf3	cookieverf;
204362306a36Sopenharmony_ci *		dirlist3	reply;
204462306a36Sopenharmony_ci *	};
204562306a36Sopenharmony_ci *
204662306a36Sopenharmony_ci *	struct READDIR3resfail {
204762306a36Sopenharmony_ci *		post_op_attr	dir_attributes;
204862306a36Sopenharmony_ci *	};
204962306a36Sopenharmony_ci *
205062306a36Sopenharmony_ci *	union READDIR3res switch (nfsstat3 status) {
205162306a36Sopenharmony_ci *	case NFS3_OK:
205262306a36Sopenharmony_ci *		READDIR3resok	resok;
205362306a36Sopenharmony_ci *	default:
205462306a36Sopenharmony_ci *		READDIR3resfail	resfail;
205562306a36Sopenharmony_ci *	};
205662306a36Sopenharmony_ci *
205762306a36Sopenharmony_ci * Read the directory contents into the page cache, but otherwise
205862306a36Sopenharmony_ci * don't touch them.  The actual decoding is done by nfs3_decode_entry()
205962306a36Sopenharmony_ci * during subsequent nfs_readdir() calls.
206062306a36Sopenharmony_ci */
206162306a36Sopenharmony_cistatic int decode_dirlist3(struct xdr_stream *xdr)
206262306a36Sopenharmony_ci{
206362306a36Sopenharmony_ci	return xdr_read_pages(xdr, xdr->buf->page_len);
206462306a36Sopenharmony_ci}
206562306a36Sopenharmony_ci
206662306a36Sopenharmony_cistatic int decode_readdir3resok(struct xdr_stream *xdr,
206762306a36Sopenharmony_ci				struct nfs3_readdirres *result,
206862306a36Sopenharmony_ci				struct user_namespace *userns)
206962306a36Sopenharmony_ci{
207062306a36Sopenharmony_ci	int error;
207162306a36Sopenharmony_ci
207262306a36Sopenharmony_ci	error = decode_post_op_attr(xdr, result->dir_attr, userns);
207362306a36Sopenharmony_ci	if (unlikely(error))
207462306a36Sopenharmony_ci		goto out;
207562306a36Sopenharmony_ci	/* XXX: do we need to check if result->verf != NULL ? */
207662306a36Sopenharmony_ci	error = decode_cookieverf3(xdr, result->verf);
207762306a36Sopenharmony_ci	if (unlikely(error))
207862306a36Sopenharmony_ci		goto out;
207962306a36Sopenharmony_ci	error = decode_dirlist3(xdr);
208062306a36Sopenharmony_ciout:
208162306a36Sopenharmony_ci	return error;
208262306a36Sopenharmony_ci}
208362306a36Sopenharmony_ci
208462306a36Sopenharmony_cistatic int nfs3_xdr_dec_readdir3res(struct rpc_rqst *req,
208562306a36Sopenharmony_ci				    struct xdr_stream *xdr,
208662306a36Sopenharmony_ci				    void *data)
208762306a36Sopenharmony_ci{
208862306a36Sopenharmony_ci	struct nfs3_readdirres *result = data;
208962306a36Sopenharmony_ci	enum nfs_stat status;
209062306a36Sopenharmony_ci	int error;
209162306a36Sopenharmony_ci
209262306a36Sopenharmony_ci	error = decode_nfsstat3(xdr, &status);
209362306a36Sopenharmony_ci	if (unlikely(error))
209462306a36Sopenharmony_ci		goto out;
209562306a36Sopenharmony_ci	if (status != NFS3_OK)
209662306a36Sopenharmony_ci		goto out_default;
209762306a36Sopenharmony_ci	error = decode_readdir3resok(xdr, result, rpc_rqst_userns(req));
209862306a36Sopenharmony_ciout:
209962306a36Sopenharmony_ci	return error;
210062306a36Sopenharmony_ciout_default:
210162306a36Sopenharmony_ci	error = decode_post_op_attr(xdr, result->dir_attr, rpc_rqst_userns(req));
210262306a36Sopenharmony_ci	if (unlikely(error))
210362306a36Sopenharmony_ci		goto out;
210462306a36Sopenharmony_ci	return nfs3_stat_to_errno(status);
210562306a36Sopenharmony_ci}
210662306a36Sopenharmony_ci
210762306a36Sopenharmony_ci/*
210862306a36Sopenharmony_ci * 3.3.18  FSSTAT3res
210962306a36Sopenharmony_ci *
211062306a36Sopenharmony_ci *	struct FSSTAT3resok {
211162306a36Sopenharmony_ci *		post_op_attr	obj_attributes;
211262306a36Sopenharmony_ci *		size3		tbytes;
211362306a36Sopenharmony_ci *		size3		fbytes;
211462306a36Sopenharmony_ci *		size3		abytes;
211562306a36Sopenharmony_ci *		size3		tfiles;
211662306a36Sopenharmony_ci *		size3		ffiles;
211762306a36Sopenharmony_ci *		size3		afiles;
211862306a36Sopenharmony_ci *		uint32		invarsec;
211962306a36Sopenharmony_ci *	};
212062306a36Sopenharmony_ci *
212162306a36Sopenharmony_ci *	struct FSSTAT3resfail {
212262306a36Sopenharmony_ci *		post_op_attr	obj_attributes;
212362306a36Sopenharmony_ci *	};
212462306a36Sopenharmony_ci *
212562306a36Sopenharmony_ci *	union FSSTAT3res switch (nfsstat3 status) {
212662306a36Sopenharmony_ci *	case NFS3_OK:
212762306a36Sopenharmony_ci *		FSSTAT3resok	resok;
212862306a36Sopenharmony_ci *	default:
212962306a36Sopenharmony_ci *		FSSTAT3resfail	resfail;
213062306a36Sopenharmony_ci *	};
213162306a36Sopenharmony_ci */
213262306a36Sopenharmony_cistatic int decode_fsstat3resok(struct xdr_stream *xdr,
213362306a36Sopenharmony_ci			       struct nfs_fsstat *result)
213462306a36Sopenharmony_ci{
213562306a36Sopenharmony_ci	__be32 *p;
213662306a36Sopenharmony_ci
213762306a36Sopenharmony_ci	p = xdr_inline_decode(xdr, 8 * 6 + 4);
213862306a36Sopenharmony_ci	if (unlikely(!p))
213962306a36Sopenharmony_ci		return -EIO;
214062306a36Sopenharmony_ci	p = xdr_decode_size3(p, &result->tbytes);
214162306a36Sopenharmony_ci	p = xdr_decode_size3(p, &result->fbytes);
214262306a36Sopenharmony_ci	p = xdr_decode_size3(p, &result->abytes);
214362306a36Sopenharmony_ci	p = xdr_decode_size3(p, &result->tfiles);
214462306a36Sopenharmony_ci	p = xdr_decode_size3(p, &result->ffiles);
214562306a36Sopenharmony_ci	xdr_decode_size3(p, &result->afiles);
214662306a36Sopenharmony_ci	/* ignore invarsec */
214762306a36Sopenharmony_ci	return 0;
214862306a36Sopenharmony_ci}
214962306a36Sopenharmony_ci
215062306a36Sopenharmony_cistatic int nfs3_xdr_dec_fsstat3res(struct rpc_rqst *req,
215162306a36Sopenharmony_ci				   struct xdr_stream *xdr,
215262306a36Sopenharmony_ci				   void *data)
215362306a36Sopenharmony_ci{
215462306a36Sopenharmony_ci	struct nfs_fsstat *result = data;
215562306a36Sopenharmony_ci	enum nfs_stat status;
215662306a36Sopenharmony_ci	int error;
215762306a36Sopenharmony_ci
215862306a36Sopenharmony_ci	error = decode_nfsstat3(xdr, &status);
215962306a36Sopenharmony_ci	if (unlikely(error))
216062306a36Sopenharmony_ci		goto out;
216162306a36Sopenharmony_ci	error = decode_post_op_attr(xdr, result->fattr, rpc_rqst_userns(req));
216262306a36Sopenharmony_ci	if (unlikely(error))
216362306a36Sopenharmony_ci		goto out;
216462306a36Sopenharmony_ci	if (status != NFS3_OK)
216562306a36Sopenharmony_ci		goto out_status;
216662306a36Sopenharmony_ci	error = decode_fsstat3resok(xdr, result);
216762306a36Sopenharmony_ciout:
216862306a36Sopenharmony_ci	return error;
216962306a36Sopenharmony_ciout_status:
217062306a36Sopenharmony_ci	return nfs3_stat_to_errno(status);
217162306a36Sopenharmony_ci}
217262306a36Sopenharmony_ci
217362306a36Sopenharmony_ci/*
217462306a36Sopenharmony_ci * 3.3.19  FSINFO3res
217562306a36Sopenharmony_ci *
217662306a36Sopenharmony_ci *	struct FSINFO3resok {
217762306a36Sopenharmony_ci *		post_op_attr	obj_attributes;
217862306a36Sopenharmony_ci *		uint32		rtmax;
217962306a36Sopenharmony_ci *		uint32		rtpref;
218062306a36Sopenharmony_ci *		uint32		rtmult;
218162306a36Sopenharmony_ci *		uint32		wtmax;
218262306a36Sopenharmony_ci *		uint32		wtpref;
218362306a36Sopenharmony_ci *		uint32		wtmult;
218462306a36Sopenharmony_ci *		uint32		dtpref;
218562306a36Sopenharmony_ci *		size3		maxfilesize;
218662306a36Sopenharmony_ci *		nfstime3	time_delta;
218762306a36Sopenharmony_ci *		uint32		properties;
218862306a36Sopenharmony_ci *	};
218962306a36Sopenharmony_ci *
219062306a36Sopenharmony_ci *	struct FSINFO3resfail {
219162306a36Sopenharmony_ci *		post_op_attr	obj_attributes;
219262306a36Sopenharmony_ci *	};
219362306a36Sopenharmony_ci *
219462306a36Sopenharmony_ci *	union FSINFO3res switch (nfsstat3 status) {
219562306a36Sopenharmony_ci *	case NFS3_OK:
219662306a36Sopenharmony_ci *		FSINFO3resok	resok;
219762306a36Sopenharmony_ci *	default:
219862306a36Sopenharmony_ci *		FSINFO3resfail	resfail;
219962306a36Sopenharmony_ci *	};
220062306a36Sopenharmony_ci */
220162306a36Sopenharmony_cistatic int decode_fsinfo3resok(struct xdr_stream *xdr,
220262306a36Sopenharmony_ci			       struct nfs_fsinfo *result)
220362306a36Sopenharmony_ci{
220462306a36Sopenharmony_ci	__be32 *p;
220562306a36Sopenharmony_ci
220662306a36Sopenharmony_ci	p = xdr_inline_decode(xdr, 4 * 7 + 8 + 8 + 4);
220762306a36Sopenharmony_ci	if (unlikely(!p))
220862306a36Sopenharmony_ci		return -EIO;
220962306a36Sopenharmony_ci	result->rtmax  = be32_to_cpup(p++);
221062306a36Sopenharmony_ci	result->rtpref = be32_to_cpup(p++);
221162306a36Sopenharmony_ci	result->rtmult = be32_to_cpup(p++);
221262306a36Sopenharmony_ci	result->wtmax  = be32_to_cpup(p++);
221362306a36Sopenharmony_ci	result->wtpref = be32_to_cpup(p++);
221462306a36Sopenharmony_ci	result->wtmult = be32_to_cpup(p++);
221562306a36Sopenharmony_ci	result->dtpref = be32_to_cpup(p++);
221662306a36Sopenharmony_ci	p = xdr_decode_size3(p, &result->maxfilesize);
221762306a36Sopenharmony_ci	xdr_decode_nfstime3(p, &result->time_delta);
221862306a36Sopenharmony_ci
221962306a36Sopenharmony_ci	/* ignore properties */
222062306a36Sopenharmony_ci	result->lease_time = 0;
222162306a36Sopenharmony_ci	result->change_attr_type = NFS4_CHANGE_TYPE_IS_UNDEFINED;
222262306a36Sopenharmony_ci	result->xattr_support = 0;
222362306a36Sopenharmony_ci	return 0;
222462306a36Sopenharmony_ci}
222562306a36Sopenharmony_ci
222662306a36Sopenharmony_cistatic int nfs3_xdr_dec_fsinfo3res(struct rpc_rqst *req,
222762306a36Sopenharmony_ci				   struct xdr_stream *xdr,
222862306a36Sopenharmony_ci				   void *data)
222962306a36Sopenharmony_ci{
223062306a36Sopenharmony_ci	struct nfs_fsinfo *result = data;
223162306a36Sopenharmony_ci	enum nfs_stat status;
223262306a36Sopenharmony_ci	int error;
223362306a36Sopenharmony_ci
223462306a36Sopenharmony_ci	error = decode_nfsstat3(xdr, &status);
223562306a36Sopenharmony_ci	if (unlikely(error))
223662306a36Sopenharmony_ci		goto out;
223762306a36Sopenharmony_ci	error = decode_post_op_attr(xdr, result->fattr, rpc_rqst_userns(req));
223862306a36Sopenharmony_ci	if (unlikely(error))
223962306a36Sopenharmony_ci		goto out;
224062306a36Sopenharmony_ci	if (status != NFS3_OK)
224162306a36Sopenharmony_ci		goto out_status;
224262306a36Sopenharmony_ci	error = decode_fsinfo3resok(xdr, result);
224362306a36Sopenharmony_ciout:
224462306a36Sopenharmony_ci	return error;
224562306a36Sopenharmony_ciout_status:
224662306a36Sopenharmony_ci	return nfs3_stat_to_errno(status);
224762306a36Sopenharmony_ci}
224862306a36Sopenharmony_ci
224962306a36Sopenharmony_ci/*
225062306a36Sopenharmony_ci * 3.3.20  PATHCONF3res
225162306a36Sopenharmony_ci *
225262306a36Sopenharmony_ci *	struct PATHCONF3resok {
225362306a36Sopenharmony_ci *		post_op_attr	obj_attributes;
225462306a36Sopenharmony_ci *		uint32		linkmax;
225562306a36Sopenharmony_ci *		uint32		name_max;
225662306a36Sopenharmony_ci *		bool		no_trunc;
225762306a36Sopenharmony_ci *		bool		chown_restricted;
225862306a36Sopenharmony_ci *		bool		case_insensitive;
225962306a36Sopenharmony_ci *		bool		case_preserving;
226062306a36Sopenharmony_ci *	};
226162306a36Sopenharmony_ci *
226262306a36Sopenharmony_ci *	struct PATHCONF3resfail {
226362306a36Sopenharmony_ci *		post_op_attr	obj_attributes;
226462306a36Sopenharmony_ci *	};
226562306a36Sopenharmony_ci *
226662306a36Sopenharmony_ci *	union PATHCONF3res switch (nfsstat3 status) {
226762306a36Sopenharmony_ci *	case NFS3_OK:
226862306a36Sopenharmony_ci *		PATHCONF3resok	resok;
226962306a36Sopenharmony_ci *	default:
227062306a36Sopenharmony_ci *		PATHCONF3resfail resfail;
227162306a36Sopenharmony_ci *	};
227262306a36Sopenharmony_ci */
227362306a36Sopenharmony_cistatic int decode_pathconf3resok(struct xdr_stream *xdr,
227462306a36Sopenharmony_ci				 struct nfs_pathconf *result)
227562306a36Sopenharmony_ci{
227662306a36Sopenharmony_ci	__be32 *p;
227762306a36Sopenharmony_ci
227862306a36Sopenharmony_ci	p = xdr_inline_decode(xdr, 4 * 6);
227962306a36Sopenharmony_ci	if (unlikely(!p))
228062306a36Sopenharmony_ci		return -EIO;
228162306a36Sopenharmony_ci	result->max_link = be32_to_cpup(p++);
228262306a36Sopenharmony_ci	result->max_namelen = be32_to_cpup(p);
228362306a36Sopenharmony_ci	/* ignore remaining fields */
228462306a36Sopenharmony_ci	return 0;
228562306a36Sopenharmony_ci}
228662306a36Sopenharmony_ci
228762306a36Sopenharmony_cistatic int nfs3_xdr_dec_pathconf3res(struct rpc_rqst *req,
228862306a36Sopenharmony_ci				     struct xdr_stream *xdr,
228962306a36Sopenharmony_ci				     void *data)
229062306a36Sopenharmony_ci{
229162306a36Sopenharmony_ci	struct nfs_pathconf *result = data;
229262306a36Sopenharmony_ci	enum nfs_stat status;
229362306a36Sopenharmony_ci	int error;
229462306a36Sopenharmony_ci
229562306a36Sopenharmony_ci	error = decode_nfsstat3(xdr, &status);
229662306a36Sopenharmony_ci	if (unlikely(error))
229762306a36Sopenharmony_ci		goto out;
229862306a36Sopenharmony_ci	error = decode_post_op_attr(xdr, result->fattr, rpc_rqst_userns(req));
229962306a36Sopenharmony_ci	if (unlikely(error))
230062306a36Sopenharmony_ci		goto out;
230162306a36Sopenharmony_ci	if (status != NFS3_OK)
230262306a36Sopenharmony_ci		goto out_status;
230362306a36Sopenharmony_ci	error = decode_pathconf3resok(xdr, result);
230462306a36Sopenharmony_ciout:
230562306a36Sopenharmony_ci	return error;
230662306a36Sopenharmony_ciout_status:
230762306a36Sopenharmony_ci	return nfs3_stat_to_errno(status);
230862306a36Sopenharmony_ci}
230962306a36Sopenharmony_ci
231062306a36Sopenharmony_ci/*
231162306a36Sopenharmony_ci * 3.3.21  COMMIT3res
231262306a36Sopenharmony_ci *
231362306a36Sopenharmony_ci *	struct COMMIT3resok {
231462306a36Sopenharmony_ci *		wcc_data	file_wcc;
231562306a36Sopenharmony_ci *		writeverf3	verf;
231662306a36Sopenharmony_ci *	};
231762306a36Sopenharmony_ci *
231862306a36Sopenharmony_ci *	struct COMMIT3resfail {
231962306a36Sopenharmony_ci *		wcc_data	file_wcc;
232062306a36Sopenharmony_ci *	};
232162306a36Sopenharmony_ci *
232262306a36Sopenharmony_ci *	union COMMIT3res switch (nfsstat3 status) {
232362306a36Sopenharmony_ci *	case NFS3_OK:
232462306a36Sopenharmony_ci *		COMMIT3resok	resok;
232562306a36Sopenharmony_ci *	default:
232662306a36Sopenharmony_ci *		COMMIT3resfail	resfail;
232762306a36Sopenharmony_ci *	};
232862306a36Sopenharmony_ci */
232962306a36Sopenharmony_cistatic int nfs3_xdr_dec_commit3res(struct rpc_rqst *req,
233062306a36Sopenharmony_ci				   struct xdr_stream *xdr,
233162306a36Sopenharmony_ci				   void *data)
233262306a36Sopenharmony_ci{
233362306a36Sopenharmony_ci	struct nfs_commitres *result = data;
233462306a36Sopenharmony_ci	struct nfs_writeverf *verf = result->verf;
233562306a36Sopenharmony_ci	enum nfs_stat status;
233662306a36Sopenharmony_ci	int error;
233762306a36Sopenharmony_ci
233862306a36Sopenharmony_ci	error = decode_nfsstat3(xdr, &status);
233962306a36Sopenharmony_ci	if (unlikely(error))
234062306a36Sopenharmony_ci		goto out;
234162306a36Sopenharmony_ci	error = decode_wcc_data(xdr, result->fattr, rpc_rqst_userns(req));
234262306a36Sopenharmony_ci	if (unlikely(error))
234362306a36Sopenharmony_ci		goto out;
234462306a36Sopenharmony_ci	result->op_status = status;
234562306a36Sopenharmony_ci	if (status != NFS3_OK)
234662306a36Sopenharmony_ci		goto out_status;
234762306a36Sopenharmony_ci	error = decode_writeverf3(xdr, &verf->verifier);
234862306a36Sopenharmony_ci	if (!error)
234962306a36Sopenharmony_ci		verf->committed = NFS_FILE_SYNC;
235062306a36Sopenharmony_ciout:
235162306a36Sopenharmony_ci	return error;
235262306a36Sopenharmony_ciout_status:
235362306a36Sopenharmony_ci	return nfs3_stat_to_errno(status);
235462306a36Sopenharmony_ci}
235562306a36Sopenharmony_ci
235662306a36Sopenharmony_ci#ifdef CONFIG_NFS_V3_ACL
235762306a36Sopenharmony_ci
235862306a36Sopenharmony_cistatic inline int decode_getacl3resok(struct xdr_stream *xdr,
235962306a36Sopenharmony_ci				      struct nfs3_getaclres *result,
236062306a36Sopenharmony_ci				      struct user_namespace *userns)
236162306a36Sopenharmony_ci{
236262306a36Sopenharmony_ci	struct posix_acl **acl;
236362306a36Sopenharmony_ci	unsigned int *aclcnt;
236462306a36Sopenharmony_ci	size_t hdrlen;
236562306a36Sopenharmony_ci	int error;
236662306a36Sopenharmony_ci
236762306a36Sopenharmony_ci	error = decode_post_op_attr(xdr, result->fattr, userns);
236862306a36Sopenharmony_ci	if (unlikely(error))
236962306a36Sopenharmony_ci		goto out;
237062306a36Sopenharmony_ci	error = decode_uint32(xdr, &result->mask);
237162306a36Sopenharmony_ci	if (unlikely(error))
237262306a36Sopenharmony_ci		goto out;
237362306a36Sopenharmony_ci	error = -EINVAL;
237462306a36Sopenharmony_ci	if (result->mask & ~(NFS_ACL|NFS_ACLCNT|NFS_DFACL|NFS_DFACLCNT))
237562306a36Sopenharmony_ci		goto out;
237662306a36Sopenharmony_ci
237762306a36Sopenharmony_ci	hdrlen = xdr_stream_pos(xdr);
237862306a36Sopenharmony_ci
237962306a36Sopenharmony_ci	acl = NULL;
238062306a36Sopenharmony_ci	if (result->mask & NFS_ACL)
238162306a36Sopenharmony_ci		acl = &result->acl_access;
238262306a36Sopenharmony_ci	aclcnt = NULL;
238362306a36Sopenharmony_ci	if (result->mask & NFS_ACLCNT)
238462306a36Sopenharmony_ci		aclcnt = &result->acl_access_count;
238562306a36Sopenharmony_ci	error = nfsacl_decode(xdr->buf, hdrlen, aclcnt, acl);
238662306a36Sopenharmony_ci	if (unlikely(error <= 0))
238762306a36Sopenharmony_ci		goto out;
238862306a36Sopenharmony_ci
238962306a36Sopenharmony_ci	acl = NULL;
239062306a36Sopenharmony_ci	if (result->mask & NFS_DFACL)
239162306a36Sopenharmony_ci		acl = &result->acl_default;
239262306a36Sopenharmony_ci	aclcnt = NULL;
239362306a36Sopenharmony_ci	if (result->mask & NFS_DFACLCNT)
239462306a36Sopenharmony_ci		aclcnt = &result->acl_default_count;
239562306a36Sopenharmony_ci	error = nfsacl_decode(xdr->buf, hdrlen + error, aclcnt, acl);
239662306a36Sopenharmony_ci	if (unlikely(error <= 0))
239762306a36Sopenharmony_ci		return error;
239862306a36Sopenharmony_ci	error = 0;
239962306a36Sopenharmony_ciout:
240062306a36Sopenharmony_ci	return error;
240162306a36Sopenharmony_ci}
240262306a36Sopenharmony_ci
240362306a36Sopenharmony_cistatic int nfs3_xdr_dec_getacl3res(struct rpc_rqst *req,
240462306a36Sopenharmony_ci				   struct xdr_stream *xdr,
240562306a36Sopenharmony_ci				   void *result)
240662306a36Sopenharmony_ci{
240762306a36Sopenharmony_ci	enum nfs_stat status;
240862306a36Sopenharmony_ci	int error;
240962306a36Sopenharmony_ci
241062306a36Sopenharmony_ci	error = decode_nfsstat3(xdr, &status);
241162306a36Sopenharmony_ci	if (unlikely(error))
241262306a36Sopenharmony_ci		goto out;
241362306a36Sopenharmony_ci	if (status != NFS3_OK)
241462306a36Sopenharmony_ci		goto out_default;
241562306a36Sopenharmony_ci	error = decode_getacl3resok(xdr, result, rpc_rqst_userns(req));
241662306a36Sopenharmony_ciout:
241762306a36Sopenharmony_ci	return error;
241862306a36Sopenharmony_ciout_default:
241962306a36Sopenharmony_ci	return nfs3_stat_to_errno(status);
242062306a36Sopenharmony_ci}
242162306a36Sopenharmony_ci
242262306a36Sopenharmony_cistatic int nfs3_xdr_dec_setacl3res(struct rpc_rqst *req,
242362306a36Sopenharmony_ci				   struct xdr_stream *xdr,
242462306a36Sopenharmony_ci				   void *result)
242562306a36Sopenharmony_ci{
242662306a36Sopenharmony_ci	enum nfs_stat status;
242762306a36Sopenharmony_ci	int error;
242862306a36Sopenharmony_ci
242962306a36Sopenharmony_ci	error = decode_nfsstat3(xdr, &status);
243062306a36Sopenharmony_ci	if (unlikely(error))
243162306a36Sopenharmony_ci		goto out;
243262306a36Sopenharmony_ci	if (status != NFS3_OK)
243362306a36Sopenharmony_ci		goto out_default;
243462306a36Sopenharmony_ci	error = decode_post_op_attr(xdr, result, rpc_rqst_userns(req));
243562306a36Sopenharmony_ciout:
243662306a36Sopenharmony_ci	return error;
243762306a36Sopenharmony_ciout_default:
243862306a36Sopenharmony_ci	return nfs3_stat_to_errno(status);
243962306a36Sopenharmony_ci}
244062306a36Sopenharmony_ci
244162306a36Sopenharmony_ci#endif  /* CONFIG_NFS_V3_ACL */
244262306a36Sopenharmony_ci
244362306a36Sopenharmony_ci
244462306a36Sopenharmony_ci/*
244562306a36Sopenharmony_ci * We need to translate between nfs status return values and
244662306a36Sopenharmony_ci * the local errno values which may not be the same.
244762306a36Sopenharmony_ci */
244862306a36Sopenharmony_cistatic const struct {
244962306a36Sopenharmony_ci	int stat;
245062306a36Sopenharmony_ci	int errno;
245162306a36Sopenharmony_ci} nfs_errtbl[] = {
245262306a36Sopenharmony_ci	{ NFS_OK,		0		},
245362306a36Sopenharmony_ci	{ NFSERR_PERM,		-EPERM		},
245462306a36Sopenharmony_ci	{ NFSERR_NOENT,		-ENOENT		},
245562306a36Sopenharmony_ci	{ NFSERR_IO,		-errno_NFSERR_IO},
245662306a36Sopenharmony_ci	{ NFSERR_NXIO,		-ENXIO		},
245762306a36Sopenharmony_ci/*	{ NFSERR_EAGAIN,	-EAGAIN		}, */
245862306a36Sopenharmony_ci	{ NFSERR_ACCES,		-EACCES		},
245962306a36Sopenharmony_ci	{ NFSERR_EXIST,		-EEXIST		},
246062306a36Sopenharmony_ci	{ NFSERR_XDEV,		-EXDEV		},
246162306a36Sopenharmony_ci	{ NFSERR_NODEV,		-ENODEV		},
246262306a36Sopenharmony_ci	{ NFSERR_NOTDIR,	-ENOTDIR	},
246362306a36Sopenharmony_ci	{ NFSERR_ISDIR,		-EISDIR		},
246462306a36Sopenharmony_ci	{ NFSERR_INVAL,		-EINVAL		},
246562306a36Sopenharmony_ci	{ NFSERR_FBIG,		-EFBIG		},
246662306a36Sopenharmony_ci	{ NFSERR_NOSPC,		-ENOSPC		},
246762306a36Sopenharmony_ci	{ NFSERR_ROFS,		-EROFS		},
246862306a36Sopenharmony_ci	{ NFSERR_MLINK,		-EMLINK		},
246962306a36Sopenharmony_ci	{ NFSERR_NAMETOOLONG,	-ENAMETOOLONG	},
247062306a36Sopenharmony_ci	{ NFSERR_NOTEMPTY,	-ENOTEMPTY	},
247162306a36Sopenharmony_ci	{ NFSERR_DQUOT,		-EDQUOT		},
247262306a36Sopenharmony_ci	{ NFSERR_STALE,		-ESTALE		},
247362306a36Sopenharmony_ci	{ NFSERR_REMOTE,	-EREMOTE	},
247462306a36Sopenharmony_ci#ifdef EWFLUSH
247562306a36Sopenharmony_ci	{ NFSERR_WFLUSH,	-EWFLUSH	},
247662306a36Sopenharmony_ci#endif
247762306a36Sopenharmony_ci	{ NFSERR_BADHANDLE,	-EBADHANDLE	},
247862306a36Sopenharmony_ci	{ NFSERR_NOT_SYNC,	-ENOTSYNC	},
247962306a36Sopenharmony_ci	{ NFSERR_BAD_COOKIE,	-EBADCOOKIE	},
248062306a36Sopenharmony_ci	{ NFSERR_NOTSUPP,	-ENOTSUPP	},
248162306a36Sopenharmony_ci	{ NFSERR_TOOSMALL,	-ETOOSMALL	},
248262306a36Sopenharmony_ci	{ NFSERR_SERVERFAULT,	-EREMOTEIO	},
248362306a36Sopenharmony_ci	{ NFSERR_BADTYPE,	-EBADTYPE	},
248462306a36Sopenharmony_ci	{ NFSERR_JUKEBOX,	-EJUKEBOX	},
248562306a36Sopenharmony_ci	{ -1,			-EIO		}
248662306a36Sopenharmony_ci};
248762306a36Sopenharmony_ci
248862306a36Sopenharmony_ci/**
248962306a36Sopenharmony_ci * nfs3_stat_to_errno - convert an NFS status code to a local errno
249062306a36Sopenharmony_ci * @status: NFS status code to convert
249162306a36Sopenharmony_ci *
249262306a36Sopenharmony_ci * Returns a local errno value, or -EIO if the NFS status code is
249362306a36Sopenharmony_ci * not recognized.  This function is used jointly by NFSv2 and NFSv3.
249462306a36Sopenharmony_ci */
249562306a36Sopenharmony_cistatic int nfs3_stat_to_errno(enum nfs_stat status)
249662306a36Sopenharmony_ci{
249762306a36Sopenharmony_ci	int i;
249862306a36Sopenharmony_ci
249962306a36Sopenharmony_ci	for (i = 0; nfs_errtbl[i].stat != -1; i++) {
250062306a36Sopenharmony_ci		if (nfs_errtbl[i].stat == (int)status)
250162306a36Sopenharmony_ci			return nfs_errtbl[i].errno;
250262306a36Sopenharmony_ci	}
250362306a36Sopenharmony_ci	dprintk("NFS: Unrecognized nfs status value: %u\n", status);
250462306a36Sopenharmony_ci	return nfs_errtbl[i].errno;
250562306a36Sopenharmony_ci}
250662306a36Sopenharmony_ci
250762306a36Sopenharmony_ci
250862306a36Sopenharmony_ci#define PROC(proc, argtype, restype, timer)				\
250962306a36Sopenharmony_ci[NFS3PROC_##proc] = {							\
251062306a36Sopenharmony_ci	.p_proc      = NFS3PROC_##proc,					\
251162306a36Sopenharmony_ci	.p_encode    = nfs3_xdr_enc_##argtype##3args,			\
251262306a36Sopenharmony_ci	.p_decode    = nfs3_xdr_dec_##restype##3res,			\
251362306a36Sopenharmony_ci	.p_arglen    = NFS3_##argtype##args_sz,				\
251462306a36Sopenharmony_ci	.p_replen    = NFS3_##restype##res_sz,				\
251562306a36Sopenharmony_ci	.p_timer     = timer,						\
251662306a36Sopenharmony_ci	.p_statidx   = NFS3PROC_##proc,					\
251762306a36Sopenharmony_ci	.p_name      = #proc,						\
251862306a36Sopenharmony_ci	}
251962306a36Sopenharmony_ci
252062306a36Sopenharmony_ciconst struct rpc_procinfo nfs3_procedures[] = {
252162306a36Sopenharmony_ci	PROC(GETATTR,		getattr,	getattr,	1),
252262306a36Sopenharmony_ci	PROC(SETATTR,		setattr,	setattr,	0),
252362306a36Sopenharmony_ci	PROC(LOOKUP,		lookup,		lookup,		2),
252462306a36Sopenharmony_ci	PROC(ACCESS,		access,		access,		1),
252562306a36Sopenharmony_ci	PROC(READLINK,		readlink,	readlink,	3),
252662306a36Sopenharmony_ci	PROC(READ,		read,		read,		3),
252762306a36Sopenharmony_ci	PROC(WRITE,		write,		write,		4),
252862306a36Sopenharmony_ci	PROC(CREATE,		create,		create,		0),
252962306a36Sopenharmony_ci	PROC(MKDIR,		mkdir,		create,		0),
253062306a36Sopenharmony_ci	PROC(SYMLINK,		symlink,	create,		0),
253162306a36Sopenharmony_ci	PROC(MKNOD,		mknod,		create,		0),
253262306a36Sopenharmony_ci	PROC(REMOVE,		remove,		remove,		0),
253362306a36Sopenharmony_ci	PROC(RMDIR,		lookup,		setattr,	0),
253462306a36Sopenharmony_ci	PROC(RENAME,		rename,		rename,		0),
253562306a36Sopenharmony_ci	PROC(LINK,		link,		link,		0),
253662306a36Sopenharmony_ci	PROC(READDIR,		readdir,	readdir,	3),
253762306a36Sopenharmony_ci	PROC(READDIRPLUS,	readdirplus,	readdir,	3),
253862306a36Sopenharmony_ci	PROC(FSSTAT,		getattr,	fsstat,		0),
253962306a36Sopenharmony_ci	PROC(FSINFO,		getattr,	fsinfo,		0),
254062306a36Sopenharmony_ci	PROC(PATHCONF,		getattr,	pathconf,	0),
254162306a36Sopenharmony_ci	PROC(COMMIT,		commit,		commit,		5),
254262306a36Sopenharmony_ci};
254362306a36Sopenharmony_ci
254462306a36Sopenharmony_cistatic unsigned int nfs_version3_counts[ARRAY_SIZE(nfs3_procedures)];
254562306a36Sopenharmony_ciconst struct rpc_version nfs_version3 = {
254662306a36Sopenharmony_ci	.number			= 3,
254762306a36Sopenharmony_ci	.nrprocs		= ARRAY_SIZE(nfs3_procedures),
254862306a36Sopenharmony_ci	.procs			= nfs3_procedures,
254962306a36Sopenharmony_ci	.counts			= nfs_version3_counts,
255062306a36Sopenharmony_ci};
255162306a36Sopenharmony_ci
255262306a36Sopenharmony_ci#ifdef CONFIG_NFS_V3_ACL
255362306a36Sopenharmony_cistatic const struct rpc_procinfo nfs3_acl_procedures[] = {
255462306a36Sopenharmony_ci	[ACLPROC3_GETACL] = {
255562306a36Sopenharmony_ci		.p_proc = ACLPROC3_GETACL,
255662306a36Sopenharmony_ci		.p_encode = nfs3_xdr_enc_getacl3args,
255762306a36Sopenharmony_ci		.p_decode = nfs3_xdr_dec_getacl3res,
255862306a36Sopenharmony_ci		.p_arglen = ACL3_getaclargs_sz,
255962306a36Sopenharmony_ci		.p_replen = ACL3_getaclres_sz,
256062306a36Sopenharmony_ci		.p_timer = 1,
256162306a36Sopenharmony_ci		.p_name = "GETACL",
256262306a36Sopenharmony_ci	},
256362306a36Sopenharmony_ci	[ACLPROC3_SETACL] = {
256462306a36Sopenharmony_ci		.p_proc = ACLPROC3_SETACL,
256562306a36Sopenharmony_ci		.p_encode = nfs3_xdr_enc_setacl3args,
256662306a36Sopenharmony_ci		.p_decode = nfs3_xdr_dec_setacl3res,
256762306a36Sopenharmony_ci		.p_arglen = ACL3_setaclargs_sz,
256862306a36Sopenharmony_ci		.p_replen = ACL3_setaclres_sz,
256962306a36Sopenharmony_ci		.p_timer = 0,
257062306a36Sopenharmony_ci		.p_name = "SETACL",
257162306a36Sopenharmony_ci	},
257262306a36Sopenharmony_ci};
257362306a36Sopenharmony_ci
257462306a36Sopenharmony_cistatic unsigned int nfs3_acl_counts[ARRAY_SIZE(nfs3_acl_procedures)];
257562306a36Sopenharmony_ciconst struct rpc_version nfsacl_version3 = {
257662306a36Sopenharmony_ci	.number			= 3,
257762306a36Sopenharmony_ci	.nrprocs		= ARRAY_SIZE(nfs3_acl_procedures),
257862306a36Sopenharmony_ci	.procs			= nfs3_acl_procedures,
257962306a36Sopenharmony_ci	.counts			= nfs3_acl_counts,
258062306a36Sopenharmony_ci};
258162306a36Sopenharmony_ci#endif  /* CONFIG_NFS_V3_ACL */
2582