162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci *  Server-side XDR for NFSv4
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci *  Copyright (c) 2002 The Regents of the University of Michigan.
562306a36Sopenharmony_ci *  All rights reserved.
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci *  Kendrick Smith <kmsmith@umich.edu>
862306a36Sopenharmony_ci *  Andy Adamson   <andros@umich.edu>
962306a36Sopenharmony_ci *
1062306a36Sopenharmony_ci *  Redistribution and use in source and binary forms, with or without
1162306a36Sopenharmony_ci *  modification, are permitted provided that the following conditions
1262306a36Sopenharmony_ci *  are met:
1362306a36Sopenharmony_ci *
1462306a36Sopenharmony_ci *  1. Redistributions of source code must retain the above copyright
1562306a36Sopenharmony_ci *     notice, this list of conditions and the following disclaimer.
1662306a36Sopenharmony_ci *  2. Redistributions in binary form must reproduce the above copyright
1762306a36Sopenharmony_ci *     notice, this list of conditions and the following disclaimer in the
1862306a36Sopenharmony_ci *     documentation and/or other materials provided with the distribution.
1962306a36Sopenharmony_ci *  3. Neither the name of the University nor the names of its
2062306a36Sopenharmony_ci *     contributors may be used to endorse or promote products derived
2162306a36Sopenharmony_ci *     from this software without specific prior written permission.
2262306a36Sopenharmony_ci *
2362306a36Sopenharmony_ci *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
2462306a36Sopenharmony_ci *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
2562306a36Sopenharmony_ci *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
2662306a36Sopenharmony_ci *  DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2762306a36Sopenharmony_ci *  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2862306a36Sopenharmony_ci *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2962306a36Sopenharmony_ci *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
3062306a36Sopenharmony_ci *  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
3162306a36Sopenharmony_ci *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
3262306a36Sopenharmony_ci *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
3362306a36Sopenharmony_ci *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3462306a36Sopenharmony_ci */
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci#include <linux/file.h>
3762306a36Sopenharmony_ci#include <linux/slab.h>
3862306a36Sopenharmony_ci#include <linux/namei.h>
3962306a36Sopenharmony_ci#include <linux/statfs.h>
4062306a36Sopenharmony_ci#include <linux/utsname.h>
4162306a36Sopenharmony_ci#include <linux/pagemap.h>
4262306a36Sopenharmony_ci#include <linux/sunrpc/svcauth_gss.h>
4362306a36Sopenharmony_ci#include <linux/sunrpc/addr.h>
4462306a36Sopenharmony_ci#include <linux/xattr.h>
4562306a36Sopenharmony_ci#include <linux/vmalloc.h>
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci#include <uapi/linux/xattr.h>
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci#include "idmap.h"
5062306a36Sopenharmony_ci#include "acl.h"
5162306a36Sopenharmony_ci#include "xdr4.h"
5262306a36Sopenharmony_ci#include "vfs.h"
5362306a36Sopenharmony_ci#include "state.h"
5462306a36Sopenharmony_ci#include "cache.h"
5562306a36Sopenharmony_ci#include "netns.h"
5662306a36Sopenharmony_ci#include "pnfs.h"
5762306a36Sopenharmony_ci#include "filecache.h"
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci#include "trace.h"
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
6262306a36Sopenharmony_ci#include <linux/security.h>
6362306a36Sopenharmony_ci#endif
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci#define NFSDDBG_FACILITY		NFSDDBG_XDR
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ciconst u32 nfsd_suppattrs[3][3] = {
6962306a36Sopenharmony_ci	{NFSD4_SUPPORTED_ATTRS_WORD0,
7062306a36Sopenharmony_ci	 NFSD4_SUPPORTED_ATTRS_WORD1,
7162306a36Sopenharmony_ci	 NFSD4_SUPPORTED_ATTRS_WORD2},
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci	{NFSD4_1_SUPPORTED_ATTRS_WORD0,
7462306a36Sopenharmony_ci	 NFSD4_1_SUPPORTED_ATTRS_WORD1,
7562306a36Sopenharmony_ci	 NFSD4_1_SUPPORTED_ATTRS_WORD2},
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci	{NFSD4_1_SUPPORTED_ATTRS_WORD0,
7862306a36Sopenharmony_ci	 NFSD4_1_SUPPORTED_ATTRS_WORD1,
7962306a36Sopenharmony_ci	 NFSD4_2_SUPPORTED_ATTRS_WORD2},
8062306a36Sopenharmony_ci};
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci/*
8362306a36Sopenharmony_ci * As per referral draft, the fsid for a referral MUST be different from the fsid of the containing
8462306a36Sopenharmony_ci * directory in order to indicate to the client that a filesystem boundary is present
8562306a36Sopenharmony_ci * We use a fixed fsid for a referral
8662306a36Sopenharmony_ci */
8762306a36Sopenharmony_ci#define NFS4_REFERRAL_FSID_MAJOR	0x8000000ULL
8862306a36Sopenharmony_ci#define NFS4_REFERRAL_FSID_MINOR	0x8000000ULL
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_cistatic __be32
9162306a36Sopenharmony_cicheck_filename(char *str, int len)
9262306a36Sopenharmony_ci{
9362306a36Sopenharmony_ci	int i;
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci	if (len == 0)
9662306a36Sopenharmony_ci		return nfserr_inval;
9762306a36Sopenharmony_ci	if (len > NFS4_MAXNAMLEN)
9862306a36Sopenharmony_ci		return nfserr_nametoolong;
9962306a36Sopenharmony_ci	if (isdotent(str, len))
10062306a36Sopenharmony_ci		return nfserr_badname;
10162306a36Sopenharmony_ci	for (i = 0; i < len; i++)
10262306a36Sopenharmony_ci		if (str[i] == '/')
10362306a36Sopenharmony_ci			return nfserr_badname;
10462306a36Sopenharmony_ci	return 0;
10562306a36Sopenharmony_ci}
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_cistatic int zero_clientid(clientid_t *clid)
10862306a36Sopenharmony_ci{
10962306a36Sopenharmony_ci	return (clid->cl_boot == 0) && (clid->cl_id == 0);
11062306a36Sopenharmony_ci}
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci/**
11362306a36Sopenharmony_ci * svcxdr_tmpalloc - allocate memory to be freed after compound processing
11462306a36Sopenharmony_ci * @argp: NFSv4 compound argument structure
11562306a36Sopenharmony_ci * @len: length of buffer to allocate
11662306a36Sopenharmony_ci *
11762306a36Sopenharmony_ci * Allocates a buffer of size @len to be freed when processing the compound
11862306a36Sopenharmony_ci * operation described in @argp finishes.
11962306a36Sopenharmony_ci */
12062306a36Sopenharmony_cistatic void *
12162306a36Sopenharmony_cisvcxdr_tmpalloc(struct nfsd4_compoundargs *argp, u32 len)
12262306a36Sopenharmony_ci{
12362306a36Sopenharmony_ci	struct svcxdr_tmpbuf *tb;
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci	tb = kmalloc(sizeof(*tb) + len, GFP_KERNEL);
12662306a36Sopenharmony_ci	if (!tb)
12762306a36Sopenharmony_ci		return NULL;
12862306a36Sopenharmony_ci	tb->next = argp->to_free;
12962306a36Sopenharmony_ci	argp->to_free = tb;
13062306a36Sopenharmony_ci	return tb->buf;
13162306a36Sopenharmony_ci}
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci/*
13462306a36Sopenharmony_ci * For xdr strings that need to be passed to other kernel api's
13562306a36Sopenharmony_ci * as null-terminated strings.
13662306a36Sopenharmony_ci *
13762306a36Sopenharmony_ci * Note null-terminating in place usually isn't safe since the
13862306a36Sopenharmony_ci * buffer might end on a page boundary.
13962306a36Sopenharmony_ci */
14062306a36Sopenharmony_cistatic char *
14162306a36Sopenharmony_cisvcxdr_dupstr(struct nfsd4_compoundargs *argp, void *buf, u32 len)
14262306a36Sopenharmony_ci{
14362306a36Sopenharmony_ci	char *p = svcxdr_tmpalloc(argp, len + 1);
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci	if (!p)
14662306a36Sopenharmony_ci		return NULL;
14762306a36Sopenharmony_ci	memcpy(p, buf, len);
14862306a36Sopenharmony_ci	p[len] = '\0';
14962306a36Sopenharmony_ci	return p;
15062306a36Sopenharmony_ci}
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_cistatic void *
15362306a36Sopenharmony_cisvcxdr_savemem(struct nfsd4_compoundargs *argp, __be32 *p, u32 len)
15462306a36Sopenharmony_ci{
15562306a36Sopenharmony_ci	__be32 *tmp;
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ci	/*
15862306a36Sopenharmony_ci	 * The location of the decoded data item is stable,
15962306a36Sopenharmony_ci	 * so @p is OK to use. This is the common case.
16062306a36Sopenharmony_ci	 */
16162306a36Sopenharmony_ci	if (p != argp->xdr->scratch.iov_base)
16262306a36Sopenharmony_ci		return p;
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ci	tmp = svcxdr_tmpalloc(argp, len);
16562306a36Sopenharmony_ci	if (!tmp)
16662306a36Sopenharmony_ci		return NULL;
16762306a36Sopenharmony_ci	memcpy(tmp, p, len);
16862306a36Sopenharmony_ci	return tmp;
16962306a36Sopenharmony_ci}
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ci/*
17262306a36Sopenharmony_ci * NFSv4 basic data type decoders
17362306a36Sopenharmony_ci */
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci/*
17662306a36Sopenharmony_ci * This helper handles variable-length opaques which belong to protocol
17762306a36Sopenharmony_ci * elements that this implementation does not support.
17862306a36Sopenharmony_ci */
17962306a36Sopenharmony_cistatic __be32
18062306a36Sopenharmony_cinfsd4_decode_ignored_string(struct nfsd4_compoundargs *argp, u32 maxlen)
18162306a36Sopenharmony_ci{
18262306a36Sopenharmony_ci	u32 len;
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci	if (xdr_stream_decode_u32(argp->xdr, &len) < 0)
18562306a36Sopenharmony_ci		return nfserr_bad_xdr;
18662306a36Sopenharmony_ci	if (maxlen && len > maxlen)
18762306a36Sopenharmony_ci		return nfserr_bad_xdr;
18862306a36Sopenharmony_ci	if (!xdr_inline_decode(argp->xdr, len))
18962306a36Sopenharmony_ci		return nfserr_bad_xdr;
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ci	return nfs_ok;
19262306a36Sopenharmony_ci}
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_cistatic __be32
19562306a36Sopenharmony_cinfsd4_decode_opaque(struct nfsd4_compoundargs *argp, struct xdr_netobj *o)
19662306a36Sopenharmony_ci{
19762306a36Sopenharmony_ci	__be32 *p;
19862306a36Sopenharmony_ci	u32 len;
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_ci	if (xdr_stream_decode_u32(argp->xdr, &len) < 0)
20162306a36Sopenharmony_ci		return nfserr_bad_xdr;
20262306a36Sopenharmony_ci	if (len == 0 || len > NFS4_OPAQUE_LIMIT)
20362306a36Sopenharmony_ci		return nfserr_bad_xdr;
20462306a36Sopenharmony_ci	p = xdr_inline_decode(argp->xdr, len);
20562306a36Sopenharmony_ci	if (!p)
20662306a36Sopenharmony_ci		return nfserr_bad_xdr;
20762306a36Sopenharmony_ci	o->data = svcxdr_savemem(argp, p, len);
20862306a36Sopenharmony_ci	if (!o->data)
20962306a36Sopenharmony_ci		return nfserr_jukebox;
21062306a36Sopenharmony_ci	o->len = len;
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_ci	return nfs_ok;
21362306a36Sopenharmony_ci}
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_cistatic __be32
21662306a36Sopenharmony_cinfsd4_decode_component4(struct nfsd4_compoundargs *argp, char **namp, u32 *lenp)
21762306a36Sopenharmony_ci{
21862306a36Sopenharmony_ci	__be32 *p, status;
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci	if (xdr_stream_decode_u32(argp->xdr, lenp) < 0)
22162306a36Sopenharmony_ci		return nfserr_bad_xdr;
22262306a36Sopenharmony_ci	p = xdr_inline_decode(argp->xdr, *lenp);
22362306a36Sopenharmony_ci	if (!p)
22462306a36Sopenharmony_ci		return nfserr_bad_xdr;
22562306a36Sopenharmony_ci	status = check_filename((char *)p, *lenp);
22662306a36Sopenharmony_ci	if (status)
22762306a36Sopenharmony_ci		return status;
22862306a36Sopenharmony_ci	*namp = svcxdr_savemem(argp, p, *lenp);
22962306a36Sopenharmony_ci	if (!*namp)
23062306a36Sopenharmony_ci		return nfserr_jukebox;
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ci	return nfs_ok;
23362306a36Sopenharmony_ci}
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_cistatic __be32
23662306a36Sopenharmony_cinfsd4_decode_nfstime4(struct nfsd4_compoundargs *argp, struct timespec64 *tv)
23762306a36Sopenharmony_ci{
23862306a36Sopenharmony_ci	__be32 *p;
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_ci	p = xdr_inline_decode(argp->xdr, XDR_UNIT * 3);
24162306a36Sopenharmony_ci	if (!p)
24262306a36Sopenharmony_ci		return nfserr_bad_xdr;
24362306a36Sopenharmony_ci	p = xdr_decode_hyper(p, &tv->tv_sec);
24462306a36Sopenharmony_ci	tv->tv_nsec = be32_to_cpup(p++);
24562306a36Sopenharmony_ci	if (tv->tv_nsec >= (u32)1000000000)
24662306a36Sopenharmony_ci		return nfserr_inval;
24762306a36Sopenharmony_ci	return nfs_ok;
24862306a36Sopenharmony_ci}
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_cistatic __be32
25162306a36Sopenharmony_cinfsd4_decode_verifier4(struct nfsd4_compoundargs *argp, nfs4_verifier *verf)
25262306a36Sopenharmony_ci{
25362306a36Sopenharmony_ci	__be32 *p;
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ci	p = xdr_inline_decode(argp->xdr, NFS4_VERIFIER_SIZE);
25662306a36Sopenharmony_ci	if (!p)
25762306a36Sopenharmony_ci		return nfserr_bad_xdr;
25862306a36Sopenharmony_ci	memcpy(verf->data, p, sizeof(verf->data));
25962306a36Sopenharmony_ci	return nfs_ok;
26062306a36Sopenharmony_ci}
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci/**
26362306a36Sopenharmony_ci * nfsd4_decode_bitmap4 - Decode an NFSv4 bitmap4
26462306a36Sopenharmony_ci * @argp: NFSv4 compound argument structure
26562306a36Sopenharmony_ci * @bmval: pointer to an array of u32's to decode into
26662306a36Sopenharmony_ci * @bmlen: size of the @bmval array
26762306a36Sopenharmony_ci *
26862306a36Sopenharmony_ci * The server needs to return nfs_ok rather than nfserr_bad_xdr when
26962306a36Sopenharmony_ci * encountering bitmaps containing bits it does not recognize. This
27062306a36Sopenharmony_ci * includes bits in bitmap words past WORDn, where WORDn is the last
27162306a36Sopenharmony_ci * bitmap WORD the implementation currently supports. Thus we are
27262306a36Sopenharmony_ci * careful here to simply ignore bits in bitmap words that this
27362306a36Sopenharmony_ci * implementation has yet to support explicitly.
27462306a36Sopenharmony_ci *
27562306a36Sopenharmony_ci * Return values:
27662306a36Sopenharmony_ci *   %nfs_ok: @bmval populated successfully
27762306a36Sopenharmony_ci *   %nfserr_bad_xdr: the encoded bitmap was invalid
27862306a36Sopenharmony_ci */
27962306a36Sopenharmony_cistatic __be32
28062306a36Sopenharmony_cinfsd4_decode_bitmap4(struct nfsd4_compoundargs *argp, u32 *bmval, u32 bmlen)
28162306a36Sopenharmony_ci{
28262306a36Sopenharmony_ci	ssize_t status;
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_ci	status = xdr_stream_decode_uint32_array(argp->xdr, bmval, bmlen);
28562306a36Sopenharmony_ci	return status == -EBADMSG ? nfserr_bad_xdr : nfs_ok;
28662306a36Sopenharmony_ci}
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_cistatic __be32
28962306a36Sopenharmony_cinfsd4_decode_nfsace4(struct nfsd4_compoundargs *argp, struct nfs4_ace *ace)
29062306a36Sopenharmony_ci{
29162306a36Sopenharmony_ci	__be32 *p, status;
29262306a36Sopenharmony_ci	u32 length;
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_ci	if (xdr_stream_decode_u32(argp->xdr, &ace->type) < 0)
29562306a36Sopenharmony_ci		return nfserr_bad_xdr;
29662306a36Sopenharmony_ci	if (xdr_stream_decode_u32(argp->xdr, &ace->flag) < 0)
29762306a36Sopenharmony_ci		return nfserr_bad_xdr;
29862306a36Sopenharmony_ci	if (xdr_stream_decode_u32(argp->xdr, &ace->access_mask) < 0)
29962306a36Sopenharmony_ci		return nfserr_bad_xdr;
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_ci	if (xdr_stream_decode_u32(argp->xdr, &length) < 0)
30262306a36Sopenharmony_ci		return nfserr_bad_xdr;
30362306a36Sopenharmony_ci	p = xdr_inline_decode(argp->xdr, length);
30462306a36Sopenharmony_ci	if (!p)
30562306a36Sopenharmony_ci		return nfserr_bad_xdr;
30662306a36Sopenharmony_ci	ace->whotype = nfs4_acl_get_whotype((char *)p, length);
30762306a36Sopenharmony_ci	if (ace->whotype != NFS4_ACL_WHO_NAMED)
30862306a36Sopenharmony_ci		status = nfs_ok;
30962306a36Sopenharmony_ci	else if (ace->flag & NFS4_ACE_IDENTIFIER_GROUP)
31062306a36Sopenharmony_ci		status = nfsd_map_name_to_gid(argp->rqstp,
31162306a36Sopenharmony_ci				(char *)p, length, &ace->who_gid);
31262306a36Sopenharmony_ci	else
31362306a36Sopenharmony_ci		status = nfsd_map_name_to_uid(argp->rqstp,
31462306a36Sopenharmony_ci				(char *)p, length, &ace->who_uid);
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_ci	return status;
31762306a36Sopenharmony_ci}
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_ci/* A counted array of nfsace4's */
32062306a36Sopenharmony_cistatic noinline __be32
32162306a36Sopenharmony_cinfsd4_decode_acl(struct nfsd4_compoundargs *argp, struct nfs4_acl **acl)
32262306a36Sopenharmony_ci{
32362306a36Sopenharmony_ci	struct nfs4_ace *ace;
32462306a36Sopenharmony_ci	__be32 status;
32562306a36Sopenharmony_ci	u32 count;
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_ci	if (xdr_stream_decode_u32(argp->xdr, &count) < 0)
32862306a36Sopenharmony_ci		return nfserr_bad_xdr;
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ci	if (count > xdr_stream_remaining(argp->xdr) / 20)
33162306a36Sopenharmony_ci		/*
33262306a36Sopenharmony_ci		 * Even with 4-byte names there wouldn't be
33362306a36Sopenharmony_ci		 * space for that many aces; something fishy is
33462306a36Sopenharmony_ci		 * going on:
33562306a36Sopenharmony_ci		 */
33662306a36Sopenharmony_ci		return nfserr_fbig;
33762306a36Sopenharmony_ci
33862306a36Sopenharmony_ci	*acl = svcxdr_tmpalloc(argp, nfs4_acl_bytes(count));
33962306a36Sopenharmony_ci	if (*acl == NULL)
34062306a36Sopenharmony_ci		return nfserr_jukebox;
34162306a36Sopenharmony_ci
34262306a36Sopenharmony_ci	(*acl)->naces = count;
34362306a36Sopenharmony_ci	for (ace = (*acl)->aces; ace < (*acl)->aces + count; ace++) {
34462306a36Sopenharmony_ci		status = nfsd4_decode_nfsace4(argp, ace);
34562306a36Sopenharmony_ci		if (status)
34662306a36Sopenharmony_ci			return status;
34762306a36Sopenharmony_ci	}
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_ci	return nfs_ok;
35062306a36Sopenharmony_ci}
35162306a36Sopenharmony_ci
35262306a36Sopenharmony_cistatic noinline __be32
35362306a36Sopenharmony_cinfsd4_decode_security_label(struct nfsd4_compoundargs *argp,
35462306a36Sopenharmony_ci			    struct xdr_netobj *label)
35562306a36Sopenharmony_ci{
35662306a36Sopenharmony_ci	u32 lfs, pi, length;
35762306a36Sopenharmony_ci	__be32 *p;
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci	if (xdr_stream_decode_u32(argp->xdr, &lfs) < 0)
36062306a36Sopenharmony_ci		return nfserr_bad_xdr;
36162306a36Sopenharmony_ci	if (xdr_stream_decode_u32(argp->xdr, &pi) < 0)
36262306a36Sopenharmony_ci		return nfserr_bad_xdr;
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_ci	if (xdr_stream_decode_u32(argp->xdr, &length) < 0)
36562306a36Sopenharmony_ci		return nfserr_bad_xdr;
36662306a36Sopenharmony_ci	if (length > NFS4_MAXLABELLEN)
36762306a36Sopenharmony_ci		return nfserr_badlabel;
36862306a36Sopenharmony_ci	p = xdr_inline_decode(argp->xdr, length);
36962306a36Sopenharmony_ci	if (!p)
37062306a36Sopenharmony_ci		return nfserr_bad_xdr;
37162306a36Sopenharmony_ci	label->len = length;
37262306a36Sopenharmony_ci	label->data = svcxdr_dupstr(argp, p, length);
37362306a36Sopenharmony_ci	if (!label->data)
37462306a36Sopenharmony_ci		return nfserr_jukebox;
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_ci	return nfs_ok;
37762306a36Sopenharmony_ci}
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_cistatic __be32
38062306a36Sopenharmony_cinfsd4_decode_fattr4(struct nfsd4_compoundargs *argp, u32 *bmval, u32 bmlen,
38162306a36Sopenharmony_ci		    struct iattr *iattr, struct nfs4_acl **acl,
38262306a36Sopenharmony_ci		    struct xdr_netobj *label, int *umask)
38362306a36Sopenharmony_ci{
38462306a36Sopenharmony_ci	unsigned int starting_pos;
38562306a36Sopenharmony_ci	u32 attrlist4_count;
38662306a36Sopenharmony_ci	__be32 *p, status;
38762306a36Sopenharmony_ci
38862306a36Sopenharmony_ci	iattr->ia_valid = 0;
38962306a36Sopenharmony_ci	status = nfsd4_decode_bitmap4(argp, bmval, bmlen);
39062306a36Sopenharmony_ci	if (status)
39162306a36Sopenharmony_ci		return nfserr_bad_xdr;
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_ci	if (bmval[0] & ~NFSD_WRITEABLE_ATTRS_WORD0
39462306a36Sopenharmony_ci	    || bmval[1] & ~NFSD_WRITEABLE_ATTRS_WORD1
39562306a36Sopenharmony_ci	    || bmval[2] & ~NFSD_WRITEABLE_ATTRS_WORD2) {
39662306a36Sopenharmony_ci		if (nfsd_attrs_supported(argp->minorversion, bmval))
39762306a36Sopenharmony_ci			return nfserr_inval;
39862306a36Sopenharmony_ci		return nfserr_attrnotsupp;
39962306a36Sopenharmony_ci	}
40062306a36Sopenharmony_ci
40162306a36Sopenharmony_ci	if (xdr_stream_decode_u32(argp->xdr, &attrlist4_count) < 0)
40262306a36Sopenharmony_ci		return nfserr_bad_xdr;
40362306a36Sopenharmony_ci	starting_pos = xdr_stream_pos(argp->xdr);
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_ci	if (bmval[0] & FATTR4_WORD0_SIZE) {
40662306a36Sopenharmony_ci		u64 size;
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_ci		if (xdr_stream_decode_u64(argp->xdr, &size) < 0)
40962306a36Sopenharmony_ci			return nfserr_bad_xdr;
41062306a36Sopenharmony_ci		iattr->ia_size = size;
41162306a36Sopenharmony_ci		iattr->ia_valid |= ATTR_SIZE;
41262306a36Sopenharmony_ci	}
41362306a36Sopenharmony_ci	if (bmval[0] & FATTR4_WORD0_ACL) {
41462306a36Sopenharmony_ci		status = nfsd4_decode_acl(argp, acl);
41562306a36Sopenharmony_ci		if (status)
41662306a36Sopenharmony_ci			return status;
41762306a36Sopenharmony_ci	} else
41862306a36Sopenharmony_ci		*acl = NULL;
41962306a36Sopenharmony_ci	if (bmval[1] & FATTR4_WORD1_MODE) {
42062306a36Sopenharmony_ci		u32 mode;
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_ci		if (xdr_stream_decode_u32(argp->xdr, &mode) < 0)
42362306a36Sopenharmony_ci			return nfserr_bad_xdr;
42462306a36Sopenharmony_ci		iattr->ia_mode = mode;
42562306a36Sopenharmony_ci		iattr->ia_mode &= (S_IFMT | S_IALLUGO);
42662306a36Sopenharmony_ci		iattr->ia_valid |= ATTR_MODE;
42762306a36Sopenharmony_ci	}
42862306a36Sopenharmony_ci	if (bmval[1] & FATTR4_WORD1_OWNER) {
42962306a36Sopenharmony_ci		u32 length;
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_ci		if (xdr_stream_decode_u32(argp->xdr, &length) < 0)
43262306a36Sopenharmony_ci			return nfserr_bad_xdr;
43362306a36Sopenharmony_ci		p = xdr_inline_decode(argp->xdr, length);
43462306a36Sopenharmony_ci		if (!p)
43562306a36Sopenharmony_ci			return nfserr_bad_xdr;
43662306a36Sopenharmony_ci		status = nfsd_map_name_to_uid(argp->rqstp, (char *)p, length,
43762306a36Sopenharmony_ci					      &iattr->ia_uid);
43862306a36Sopenharmony_ci		if (status)
43962306a36Sopenharmony_ci			return status;
44062306a36Sopenharmony_ci		iattr->ia_valid |= ATTR_UID;
44162306a36Sopenharmony_ci	}
44262306a36Sopenharmony_ci	if (bmval[1] & FATTR4_WORD1_OWNER_GROUP) {
44362306a36Sopenharmony_ci		u32 length;
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_ci		if (xdr_stream_decode_u32(argp->xdr, &length) < 0)
44662306a36Sopenharmony_ci			return nfserr_bad_xdr;
44762306a36Sopenharmony_ci		p = xdr_inline_decode(argp->xdr, length);
44862306a36Sopenharmony_ci		if (!p)
44962306a36Sopenharmony_ci			return nfserr_bad_xdr;
45062306a36Sopenharmony_ci		status = nfsd_map_name_to_gid(argp->rqstp, (char *)p, length,
45162306a36Sopenharmony_ci					      &iattr->ia_gid);
45262306a36Sopenharmony_ci		if (status)
45362306a36Sopenharmony_ci			return status;
45462306a36Sopenharmony_ci		iattr->ia_valid |= ATTR_GID;
45562306a36Sopenharmony_ci	}
45662306a36Sopenharmony_ci	if (bmval[1] & FATTR4_WORD1_TIME_ACCESS_SET) {
45762306a36Sopenharmony_ci		u32 set_it;
45862306a36Sopenharmony_ci
45962306a36Sopenharmony_ci		if (xdr_stream_decode_u32(argp->xdr, &set_it) < 0)
46062306a36Sopenharmony_ci			return nfserr_bad_xdr;
46162306a36Sopenharmony_ci		switch (set_it) {
46262306a36Sopenharmony_ci		case NFS4_SET_TO_CLIENT_TIME:
46362306a36Sopenharmony_ci			status = nfsd4_decode_nfstime4(argp, &iattr->ia_atime);
46462306a36Sopenharmony_ci			if (status)
46562306a36Sopenharmony_ci				return status;
46662306a36Sopenharmony_ci			iattr->ia_valid |= (ATTR_ATIME | ATTR_ATIME_SET);
46762306a36Sopenharmony_ci			break;
46862306a36Sopenharmony_ci		case NFS4_SET_TO_SERVER_TIME:
46962306a36Sopenharmony_ci			iattr->ia_valid |= ATTR_ATIME;
47062306a36Sopenharmony_ci			break;
47162306a36Sopenharmony_ci		default:
47262306a36Sopenharmony_ci			return nfserr_bad_xdr;
47362306a36Sopenharmony_ci		}
47462306a36Sopenharmony_ci	}
47562306a36Sopenharmony_ci	if (bmval[1] & FATTR4_WORD1_TIME_CREATE) {
47662306a36Sopenharmony_ci		struct timespec64 ts;
47762306a36Sopenharmony_ci
47862306a36Sopenharmony_ci		/* No Linux filesystem supports setting this attribute. */
47962306a36Sopenharmony_ci		bmval[1] &= ~FATTR4_WORD1_TIME_CREATE;
48062306a36Sopenharmony_ci		status = nfsd4_decode_nfstime4(argp, &ts);
48162306a36Sopenharmony_ci		if (status)
48262306a36Sopenharmony_ci			return status;
48362306a36Sopenharmony_ci	}
48462306a36Sopenharmony_ci	if (bmval[1] & FATTR4_WORD1_TIME_MODIFY_SET) {
48562306a36Sopenharmony_ci		u32 set_it;
48662306a36Sopenharmony_ci
48762306a36Sopenharmony_ci		if (xdr_stream_decode_u32(argp->xdr, &set_it) < 0)
48862306a36Sopenharmony_ci			return nfserr_bad_xdr;
48962306a36Sopenharmony_ci		switch (set_it) {
49062306a36Sopenharmony_ci		case NFS4_SET_TO_CLIENT_TIME:
49162306a36Sopenharmony_ci			status = nfsd4_decode_nfstime4(argp, &iattr->ia_mtime);
49262306a36Sopenharmony_ci			if (status)
49362306a36Sopenharmony_ci				return status;
49462306a36Sopenharmony_ci			iattr->ia_valid |= (ATTR_MTIME | ATTR_MTIME_SET);
49562306a36Sopenharmony_ci			break;
49662306a36Sopenharmony_ci		case NFS4_SET_TO_SERVER_TIME:
49762306a36Sopenharmony_ci			iattr->ia_valid |= ATTR_MTIME;
49862306a36Sopenharmony_ci			break;
49962306a36Sopenharmony_ci		default:
50062306a36Sopenharmony_ci			return nfserr_bad_xdr;
50162306a36Sopenharmony_ci		}
50262306a36Sopenharmony_ci	}
50362306a36Sopenharmony_ci	label->len = 0;
50462306a36Sopenharmony_ci	if (IS_ENABLED(CONFIG_NFSD_V4_SECURITY_LABEL) &&
50562306a36Sopenharmony_ci	    bmval[2] & FATTR4_WORD2_SECURITY_LABEL) {
50662306a36Sopenharmony_ci		status = nfsd4_decode_security_label(argp, label);
50762306a36Sopenharmony_ci		if (status)
50862306a36Sopenharmony_ci			return status;
50962306a36Sopenharmony_ci	}
51062306a36Sopenharmony_ci	if (bmval[2] & FATTR4_WORD2_MODE_UMASK) {
51162306a36Sopenharmony_ci		u32 mode, mask;
51262306a36Sopenharmony_ci
51362306a36Sopenharmony_ci		if (!umask)
51462306a36Sopenharmony_ci			return nfserr_bad_xdr;
51562306a36Sopenharmony_ci		if (xdr_stream_decode_u32(argp->xdr, &mode) < 0)
51662306a36Sopenharmony_ci			return nfserr_bad_xdr;
51762306a36Sopenharmony_ci		iattr->ia_mode = mode & (S_IFMT | S_IALLUGO);
51862306a36Sopenharmony_ci		if (xdr_stream_decode_u32(argp->xdr, &mask) < 0)
51962306a36Sopenharmony_ci			return nfserr_bad_xdr;
52062306a36Sopenharmony_ci		*umask = mask & S_IRWXUGO;
52162306a36Sopenharmony_ci		iattr->ia_valid |= ATTR_MODE;
52262306a36Sopenharmony_ci	}
52362306a36Sopenharmony_ci
52462306a36Sopenharmony_ci	/* request sanity: did attrlist4 contain the expected number of words? */
52562306a36Sopenharmony_ci	if (attrlist4_count != xdr_stream_pos(argp->xdr) - starting_pos)
52662306a36Sopenharmony_ci		return nfserr_bad_xdr;
52762306a36Sopenharmony_ci
52862306a36Sopenharmony_ci	return nfs_ok;
52962306a36Sopenharmony_ci}
53062306a36Sopenharmony_ci
53162306a36Sopenharmony_cistatic __be32
53262306a36Sopenharmony_cinfsd4_decode_stateid4(struct nfsd4_compoundargs *argp, stateid_t *sid)
53362306a36Sopenharmony_ci{
53462306a36Sopenharmony_ci	__be32 *p;
53562306a36Sopenharmony_ci
53662306a36Sopenharmony_ci	p = xdr_inline_decode(argp->xdr, NFS4_STATEID_SIZE);
53762306a36Sopenharmony_ci	if (!p)
53862306a36Sopenharmony_ci		return nfserr_bad_xdr;
53962306a36Sopenharmony_ci	sid->si_generation = be32_to_cpup(p++);
54062306a36Sopenharmony_ci	memcpy(&sid->si_opaque, p, sizeof(sid->si_opaque));
54162306a36Sopenharmony_ci	return nfs_ok;
54262306a36Sopenharmony_ci}
54362306a36Sopenharmony_ci
54462306a36Sopenharmony_cistatic __be32
54562306a36Sopenharmony_cinfsd4_decode_clientid4(struct nfsd4_compoundargs *argp, clientid_t *clientid)
54662306a36Sopenharmony_ci{
54762306a36Sopenharmony_ci	__be32 *p;
54862306a36Sopenharmony_ci
54962306a36Sopenharmony_ci	p = xdr_inline_decode(argp->xdr, sizeof(__be64));
55062306a36Sopenharmony_ci	if (!p)
55162306a36Sopenharmony_ci		return nfserr_bad_xdr;
55262306a36Sopenharmony_ci	memcpy(clientid, p, sizeof(*clientid));
55362306a36Sopenharmony_ci	return nfs_ok;
55462306a36Sopenharmony_ci}
55562306a36Sopenharmony_ci
55662306a36Sopenharmony_cistatic __be32
55762306a36Sopenharmony_cinfsd4_decode_state_owner4(struct nfsd4_compoundargs *argp,
55862306a36Sopenharmony_ci			  clientid_t *clientid, struct xdr_netobj *owner)
55962306a36Sopenharmony_ci{
56062306a36Sopenharmony_ci	__be32 status;
56162306a36Sopenharmony_ci
56262306a36Sopenharmony_ci	status = nfsd4_decode_clientid4(argp, clientid);
56362306a36Sopenharmony_ci	if (status)
56462306a36Sopenharmony_ci		return status;
56562306a36Sopenharmony_ci	return nfsd4_decode_opaque(argp, owner);
56662306a36Sopenharmony_ci}
56762306a36Sopenharmony_ci
56862306a36Sopenharmony_ci#ifdef CONFIG_NFSD_PNFS
56962306a36Sopenharmony_cistatic __be32
57062306a36Sopenharmony_cinfsd4_decode_deviceid4(struct nfsd4_compoundargs *argp,
57162306a36Sopenharmony_ci		       struct nfsd4_deviceid *devid)
57262306a36Sopenharmony_ci{
57362306a36Sopenharmony_ci	__be32 *p;
57462306a36Sopenharmony_ci
57562306a36Sopenharmony_ci	p = xdr_inline_decode(argp->xdr, NFS4_DEVICEID4_SIZE);
57662306a36Sopenharmony_ci	if (!p)
57762306a36Sopenharmony_ci		return nfserr_bad_xdr;
57862306a36Sopenharmony_ci	memcpy(devid, p, sizeof(*devid));
57962306a36Sopenharmony_ci	return nfs_ok;
58062306a36Sopenharmony_ci}
58162306a36Sopenharmony_ci
58262306a36Sopenharmony_cistatic __be32
58362306a36Sopenharmony_cinfsd4_decode_layoutupdate4(struct nfsd4_compoundargs *argp,
58462306a36Sopenharmony_ci			   struct nfsd4_layoutcommit *lcp)
58562306a36Sopenharmony_ci{
58662306a36Sopenharmony_ci	if (xdr_stream_decode_u32(argp->xdr, &lcp->lc_layout_type) < 0)
58762306a36Sopenharmony_ci		return nfserr_bad_xdr;
58862306a36Sopenharmony_ci	if (lcp->lc_layout_type < LAYOUT_NFSV4_1_FILES)
58962306a36Sopenharmony_ci		return nfserr_bad_xdr;
59062306a36Sopenharmony_ci	if (lcp->lc_layout_type >= LAYOUT_TYPE_MAX)
59162306a36Sopenharmony_ci		return nfserr_bad_xdr;
59262306a36Sopenharmony_ci
59362306a36Sopenharmony_ci	if (xdr_stream_decode_u32(argp->xdr, &lcp->lc_up_len) < 0)
59462306a36Sopenharmony_ci		return nfserr_bad_xdr;
59562306a36Sopenharmony_ci	if (lcp->lc_up_len > 0) {
59662306a36Sopenharmony_ci		lcp->lc_up_layout = xdr_inline_decode(argp->xdr, lcp->lc_up_len);
59762306a36Sopenharmony_ci		if (!lcp->lc_up_layout)
59862306a36Sopenharmony_ci			return nfserr_bad_xdr;
59962306a36Sopenharmony_ci	}
60062306a36Sopenharmony_ci
60162306a36Sopenharmony_ci	return nfs_ok;
60262306a36Sopenharmony_ci}
60362306a36Sopenharmony_ci
60462306a36Sopenharmony_cistatic __be32
60562306a36Sopenharmony_cinfsd4_decode_layoutreturn4(struct nfsd4_compoundargs *argp,
60662306a36Sopenharmony_ci			   struct nfsd4_layoutreturn *lrp)
60762306a36Sopenharmony_ci{
60862306a36Sopenharmony_ci	__be32 status;
60962306a36Sopenharmony_ci
61062306a36Sopenharmony_ci	if (xdr_stream_decode_u32(argp->xdr, &lrp->lr_return_type) < 0)
61162306a36Sopenharmony_ci		return nfserr_bad_xdr;
61262306a36Sopenharmony_ci	switch (lrp->lr_return_type) {
61362306a36Sopenharmony_ci	case RETURN_FILE:
61462306a36Sopenharmony_ci		if (xdr_stream_decode_u64(argp->xdr, &lrp->lr_seg.offset) < 0)
61562306a36Sopenharmony_ci			return nfserr_bad_xdr;
61662306a36Sopenharmony_ci		if (xdr_stream_decode_u64(argp->xdr, &lrp->lr_seg.length) < 0)
61762306a36Sopenharmony_ci			return nfserr_bad_xdr;
61862306a36Sopenharmony_ci		status = nfsd4_decode_stateid4(argp, &lrp->lr_sid);
61962306a36Sopenharmony_ci		if (status)
62062306a36Sopenharmony_ci			return status;
62162306a36Sopenharmony_ci		if (xdr_stream_decode_u32(argp->xdr, &lrp->lrf_body_len) < 0)
62262306a36Sopenharmony_ci			return nfserr_bad_xdr;
62362306a36Sopenharmony_ci		if (lrp->lrf_body_len > 0) {
62462306a36Sopenharmony_ci			lrp->lrf_body = xdr_inline_decode(argp->xdr, lrp->lrf_body_len);
62562306a36Sopenharmony_ci			if (!lrp->lrf_body)
62662306a36Sopenharmony_ci				return nfserr_bad_xdr;
62762306a36Sopenharmony_ci		}
62862306a36Sopenharmony_ci		break;
62962306a36Sopenharmony_ci	case RETURN_FSID:
63062306a36Sopenharmony_ci	case RETURN_ALL:
63162306a36Sopenharmony_ci		lrp->lr_seg.offset = 0;
63262306a36Sopenharmony_ci		lrp->lr_seg.length = NFS4_MAX_UINT64;
63362306a36Sopenharmony_ci		break;
63462306a36Sopenharmony_ci	default:
63562306a36Sopenharmony_ci		return nfserr_bad_xdr;
63662306a36Sopenharmony_ci	}
63762306a36Sopenharmony_ci
63862306a36Sopenharmony_ci	return nfs_ok;
63962306a36Sopenharmony_ci}
64062306a36Sopenharmony_ci
64162306a36Sopenharmony_ci#endif /* CONFIG_NFSD_PNFS */
64262306a36Sopenharmony_ci
64362306a36Sopenharmony_cistatic __be32
64462306a36Sopenharmony_cinfsd4_decode_sessionid4(struct nfsd4_compoundargs *argp,
64562306a36Sopenharmony_ci			struct nfs4_sessionid *sessionid)
64662306a36Sopenharmony_ci{
64762306a36Sopenharmony_ci	__be32 *p;
64862306a36Sopenharmony_ci
64962306a36Sopenharmony_ci	p = xdr_inline_decode(argp->xdr, NFS4_MAX_SESSIONID_LEN);
65062306a36Sopenharmony_ci	if (!p)
65162306a36Sopenharmony_ci		return nfserr_bad_xdr;
65262306a36Sopenharmony_ci	memcpy(sessionid->data, p, sizeof(sessionid->data));
65362306a36Sopenharmony_ci	return nfs_ok;
65462306a36Sopenharmony_ci}
65562306a36Sopenharmony_ci
65662306a36Sopenharmony_ci/* Defined in Appendix A of RFC 5531 */
65762306a36Sopenharmony_cistatic __be32
65862306a36Sopenharmony_cinfsd4_decode_authsys_parms(struct nfsd4_compoundargs *argp,
65962306a36Sopenharmony_ci			   struct nfsd4_cb_sec *cbs)
66062306a36Sopenharmony_ci{
66162306a36Sopenharmony_ci	u32 stamp, gidcount, uid, gid;
66262306a36Sopenharmony_ci	__be32 *p, status;
66362306a36Sopenharmony_ci
66462306a36Sopenharmony_ci	if (xdr_stream_decode_u32(argp->xdr, &stamp) < 0)
66562306a36Sopenharmony_ci		return nfserr_bad_xdr;
66662306a36Sopenharmony_ci	/* machine name */
66762306a36Sopenharmony_ci	status = nfsd4_decode_ignored_string(argp, 255);
66862306a36Sopenharmony_ci	if (status)
66962306a36Sopenharmony_ci		return status;
67062306a36Sopenharmony_ci	if (xdr_stream_decode_u32(argp->xdr, &uid) < 0)
67162306a36Sopenharmony_ci		return nfserr_bad_xdr;
67262306a36Sopenharmony_ci	if (xdr_stream_decode_u32(argp->xdr, &gid) < 0)
67362306a36Sopenharmony_ci		return nfserr_bad_xdr;
67462306a36Sopenharmony_ci	if (xdr_stream_decode_u32(argp->xdr, &gidcount) < 0)
67562306a36Sopenharmony_ci		return nfserr_bad_xdr;
67662306a36Sopenharmony_ci	if (gidcount > 16)
67762306a36Sopenharmony_ci		return nfserr_bad_xdr;
67862306a36Sopenharmony_ci	p = xdr_inline_decode(argp->xdr, gidcount << 2);
67962306a36Sopenharmony_ci	if (!p)
68062306a36Sopenharmony_ci		return nfserr_bad_xdr;
68162306a36Sopenharmony_ci	if (cbs->flavor == (u32)(-1)) {
68262306a36Sopenharmony_ci		struct user_namespace *userns = nfsd_user_namespace(argp->rqstp);
68362306a36Sopenharmony_ci
68462306a36Sopenharmony_ci		kuid_t kuid = make_kuid(userns, uid);
68562306a36Sopenharmony_ci		kgid_t kgid = make_kgid(userns, gid);
68662306a36Sopenharmony_ci		if (uid_valid(kuid) && gid_valid(kgid)) {
68762306a36Sopenharmony_ci			cbs->uid = kuid;
68862306a36Sopenharmony_ci			cbs->gid = kgid;
68962306a36Sopenharmony_ci			cbs->flavor = RPC_AUTH_UNIX;
69062306a36Sopenharmony_ci		} else {
69162306a36Sopenharmony_ci			dprintk("RPC_AUTH_UNIX with invalid uid or gid, ignoring!\n");
69262306a36Sopenharmony_ci		}
69362306a36Sopenharmony_ci	}
69462306a36Sopenharmony_ci
69562306a36Sopenharmony_ci	return nfs_ok;
69662306a36Sopenharmony_ci}
69762306a36Sopenharmony_ci
69862306a36Sopenharmony_cistatic __be32
69962306a36Sopenharmony_cinfsd4_decode_gss_cb_handles4(struct nfsd4_compoundargs *argp,
70062306a36Sopenharmony_ci			     struct nfsd4_cb_sec *cbs)
70162306a36Sopenharmony_ci{
70262306a36Sopenharmony_ci	__be32 status;
70362306a36Sopenharmony_ci	u32 service;
70462306a36Sopenharmony_ci
70562306a36Sopenharmony_ci	dprintk("RPC_AUTH_GSS callback secflavor not supported!\n");
70662306a36Sopenharmony_ci
70762306a36Sopenharmony_ci	if (xdr_stream_decode_u32(argp->xdr, &service) < 0)
70862306a36Sopenharmony_ci		return nfserr_bad_xdr;
70962306a36Sopenharmony_ci	if (service < RPC_GSS_SVC_NONE || service > RPC_GSS_SVC_PRIVACY)
71062306a36Sopenharmony_ci		return nfserr_bad_xdr;
71162306a36Sopenharmony_ci	/* gcbp_handle_from_server */
71262306a36Sopenharmony_ci	status = nfsd4_decode_ignored_string(argp, 0);
71362306a36Sopenharmony_ci	if (status)
71462306a36Sopenharmony_ci		return status;
71562306a36Sopenharmony_ci	/* gcbp_handle_from_client */
71662306a36Sopenharmony_ci	status = nfsd4_decode_ignored_string(argp, 0);
71762306a36Sopenharmony_ci	if (status)
71862306a36Sopenharmony_ci		return status;
71962306a36Sopenharmony_ci
72062306a36Sopenharmony_ci	return nfs_ok;
72162306a36Sopenharmony_ci}
72262306a36Sopenharmony_ci
72362306a36Sopenharmony_ci/* a counted array of callback_sec_parms4 items */
72462306a36Sopenharmony_cistatic __be32
72562306a36Sopenharmony_cinfsd4_decode_cb_sec(struct nfsd4_compoundargs *argp, struct nfsd4_cb_sec *cbs)
72662306a36Sopenharmony_ci{
72762306a36Sopenharmony_ci	u32 i, secflavor, nr_secflavs;
72862306a36Sopenharmony_ci	__be32 status;
72962306a36Sopenharmony_ci
73062306a36Sopenharmony_ci	/* callback_sec_params4 */
73162306a36Sopenharmony_ci	if (xdr_stream_decode_u32(argp->xdr, &nr_secflavs) < 0)
73262306a36Sopenharmony_ci		return nfserr_bad_xdr;
73362306a36Sopenharmony_ci	if (nr_secflavs)
73462306a36Sopenharmony_ci		cbs->flavor = (u32)(-1);
73562306a36Sopenharmony_ci	else
73662306a36Sopenharmony_ci		/* Is this legal? Be generous, take it to mean AUTH_NONE: */
73762306a36Sopenharmony_ci		cbs->flavor = 0;
73862306a36Sopenharmony_ci
73962306a36Sopenharmony_ci	for (i = 0; i < nr_secflavs; ++i) {
74062306a36Sopenharmony_ci		if (xdr_stream_decode_u32(argp->xdr, &secflavor) < 0)
74162306a36Sopenharmony_ci			return nfserr_bad_xdr;
74262306a36Sopenharmony_ci		switch (secflavor) {
74362306a36Sopenharmony_ci		case RPC_AUTH_NULL:
74462306a36Sopenharmony_ci			/* void */
74562306a36Sopenharmony_ci			if (cbs->flavor == (u32)(-1))
74662306a36Sopenharmony_ci				cbs->flavor = RPC_AUTH_NULL;
74762306a36Sopenharmony_ci			break;
74862306a36Sopenharmony_ci		case RPC_AUTH_UNIX:
74962306a36Sopenharmony_ci			status = nfsd4_decode_authsys_parms(argp, cbs);
75062306a36Sopenharmony_ci			if (status)
75162306a36Sopenharmony_ci				return status;
75262306a36Sopenharmony_ci			break;
75362306a36Sopenharmony_ci		case RPC_AUTH_GSS:
75462306a36Sopenharmony_ci			status = nfsd4_decode_gss_cb_handles4(argp, cbs);
75562306a36Sopenharmony_ci			if (status)
75662306a36Sopenharmony_ci				return status;
75762306a36Sopenharmony_ci			break;
75862306a36Sopenharmony_ci		default:
75962306a36Sopenharmony_ci			return nfserr_inval;
76062306a36Sopenharmony_ci		}
76162306a36Sopenharmony_ci	}
76262306a36Sopenharmony_ci
76362306a36Sopenharmony_ci	return nfs_ok;
76462306a36Sopenharmony_ci}
76562306a36Sopenharmony_ci
76662306a36Sopenharmony_ci
76762306a36Sopenharmony_ci/*
76862306a36Sopenharmony_ci * NFSv4 operation argument decoders
76962306a36Sopenharmony_ci */
77062306a36Sopenharmony_ci
77162306a36Sopenharmony_cistatic __be32
77262306a36Sopenharmony_cinfsd4_decode_access(struct nfsd4_compoundargs *argp,
77362306a36Sopenharmony_ci		    union nfsd4_op_u *u)
77462306a36Sopenharmony_ci{
77562306a36Sopenharmony_ci	struct nfsd4_access *access = &u->access;
77662306a36Sopenharmony_ci	if (xdr_stream_decode_u32(argp->xdr, &access->ac_req_access) < 0)
77762306a36Sopenharmony_ci		return nfserr_bad_xdr;
77862306a36Sopenharmony_ci	return nfs_ok;
77962306a36Sopenharmony_ci}
78062306a36Sopenharmony_ci
78162306a36Sopenharmony_cistatic __be32
78262306a36Sopenharmony_cinfsd4_decode_close(struct nfsd4_compoundargs *argp, union nfsd4_op_u *u)
78362306a36Sopenharmony_ci{
78462306a36Sopenharmony_ci	struct nfsd4_close *close = &u->close;
78562306a36Sopenharmony_ci	if (xdr_stream_decode_u32(argp->xdr, &close->cl_seqid) < 0)
78662306a36Sopenharmony_ci		return nfserr_bad_xdr;
78762306a36Sopenharmony_ci	return nfsd4_decode_stateid4(argp, &close->cl_stateid);
78862306a36Sopenharmony_ci}
78962306a36Sopenharmony_ci
79062306a36Sopenharmony_ci
79162306a36Sopenharmony_cistatic __be32
79262306a36Sopenharmony_cinfsd4_decode_commit(struct nfsd4_compoundargs *argp, union nfsd4_op_u *u)
79362306a36Sopenharmony_ci{
79462306a36Sopenharmony_ci	struct nfsd4_commit *commit = &u->commit;
79562306a36Sopenharmony_ci	if (xdr_stream_decode_u64(argp->xdr, &commit->co_offset) < 0)
79662306a36Sopenharmony_ci		return nfserr_bad_xdr;
79762306a36Sopenharmony_ci	if (xdr_stream_decode_u32(argp->xdr, &commit->co_count) < 0)
79862306a36Sopenharmony_ci		return nfserr_bad_xdr;
79962306a36Sopenharmony_ci	memset(&commit->co_verf, 0, sizeof(commit->co_verf));
80062306a36Sopenharmony_ci	return nfs_ok;
80162306a36Sopenharmony_ci}
80262306a36Sopenharmony_ci
80362306a36Sopenharmony_cistatic __be32
80462306a36Sopenharmony_cinfsd4_decode_create(struct nfsd4_compoundargs *argp, union nfsd4_op_u *u)
80562306a36Sopenharmony_ci{
80662306a36Sopenharmony_ci	struct nfsd4_create *create = &u->create;
80762306a36Sopenharmony_ci	__be32 *p, status;
80862306a36Sopenharmony_ci
80962306a36Sopenharmony_ci	memset(create, 0, sizeof(*create));
81062306a36Sopenharmony_ci	if (xdr_stream_decode_u32(argp->xdr, &create->cr_type) < 0)
81162306a36Sopenharmony_ci		return nfserr_bad_xdr;
81262306a36Sopenharmony_ci	switch (create->cr_type) {
81362306a36Sopenharmony_ci	case NF4LNK:
81462306a36Sopenharmony_ci		if (xdr_stream_decode_u32(argp->xdr, &create->cr_datalen) < 0)
81562306a36Sopenharmony_ci			return nfserr_bad_xdr;
81662306a36Sopenharmony_ci		p = xdr_inline_decode(argp->xdr, create->cr_datalen);
81762306a36Sopenharmony_ci		if (!p)
81862306a36Sopenharmony_ci			return nfserr_bad_xdr;
81962306a36Sopenharmony_ci		create->cr_data = svcxdr_dupstr(argp, p, create->cr_datalen);
82062306a36Sopenharmony_ci		if (!create->cr_data)
82162306a36Sopenharmony_ci			return nfserr_jukebox;
82262306a36Sopenharmony_ci		break;
82362306a36Sopenharmony_ci	case NF4BLK:
82462306a36Sopenharmony_ci	case NF4CHR:
82562306a36Sopenharmony_ci		if (xdr_stream_decode_u32(argp->xdr, &create->cr_specdata1) < 0)
82662306a36Sopenharmony_ci			return nfserr_bad_xdr;
82762306a36Sopenharmony_ci		if (xdr_stream_decode_u32(argp->xdr, &create->cr_specdata2) < 0)
82862306a36Sopenharmony_ci			return nfserr_bad_xdr;
82962306a36Sopenharmony_ci		break;
83062306a36Sopenharmony_ci	case NF4SOCK:
83162306a36Sopenharmony_ci	case NF4FIFO:
83262306a36Sopenharmony_ci	case NF4DIR:
83362306a36Sopenharmony_ci	default:
83462306a36Sopenharmony_ci		break;
83562306a36Sopenharmony_ci	}
83662306a36Sopenharmony_ci	status = nfsd4_decode_component4(argp, &create->cr_name,
83762306a36Sopenharmony_ci					 &create->cr_namelen);
83862306a36Sopenharmony_ci	if (status)
83962306a36Sopenharmony_ci		return status;
84062306a36Sopenharmony_ci	status = nfsd4_decode_fattr4(argp, create->cr_bmval,
84162306a36Sopenharmony_ci				    ARRAY_SIZE(create->cr_bmval),
84262306a36Sopenharmony_ci				    &create->cr_iattr, &create->cr_acl,
84362306a36Sopenharmony_ci				    &create->cr_label, &create->cr_umask);
84462306a36Sopenharmony_ci	if (status)
84562306a36Sopenharmony_ci		return status;
84662306a36Sopenharmony_ci
84762306a36Sopenharmony_ci	return nfs_ok;
84862306a36Sopenharmony_ci}
84962306a36Sopenharmony_ci
85062306a36Sopenharmony_cistatic inline __be32
85162306a36Sopenharmony_cinfsd4_decode_delegreturn(struct nfsd4_compoundargs *argp, union nfsd4_op_u *u)
85262306a36Sopenharmony_ci{
85362306a36Sopenharmony_ci	struct nfsd4_delegreturn *dr = &u->delegreturn;
85462306a36Sopenharmony_ci	return nfsd4_decode_stateid4(argp, &dr->dr_stateid);
85562306a36Sopenharmony_ci}
85662306a36Sopenharmony_ci
85762306a36Sopenharmony_cistatic inline __be32
85862306a36Sopenharmony_cinfsd4_decode_getattr(struct nfsd4_compoundargs *argp, union nfsd4_op_u *u)
85962306a36Sopenharmony_ci{
86062306a36Sopenharmony_ci	struct nfsd4_getattr *getattr = &u->getattr;
86162306a36Sopenharmony_ci	memset(getattr, 0, sizeof(*getattr));
86262306a36Sopenharmony_ci	return nfsd4_decode_bitmap4(argp, getattr->ga_bmval,
86362306a36Sopenharmony_ci				    ARRAY_SIZE(getattr->ga_bmval));
86462306a36Sopenharmony_ci}
86562306a36Sopenharmony_ci
86662306a36Sopenharmony_cistatic __be32
86762306a36Sopenharmony_cinfsd4_decode_link(struct nfsd4_compoundargs *argp, union nfsd4_op_u *u)
86862306a36Sopenharmony_ci{
86962306a36Sopenharmony_ci	struct nfsd4_link *link = &u->link;
87062306a36Sopenharmony_ci	memset(link, 0, sizeof(*link));
87162306a36Sopenharmony_ci	return nfsd4_decode_component4(argp, &link->li_name, &link->li_namelen);
87262306a36Sopenharmony_ci}
87362306a36Sopenharmony_ci
87462306a36Sopenharmony_cistatic __be32
87562306a36Sopenharmony_cinfsd4_decode_open_to_lock_owner4(struct nfsd4_compoundargs *argp,
87662306a36Sopenharmony_ci				 struct nfsd4_lock *lock)
87762306a36Sopenharmony_ci{
87862306a36Sopenharmony_ci	__be32 status;
87962306a36Sopenharmony_ci
88062306a36Sopenharmony_ci	if (xdr_stream_decode_u32(argp->xdr, &lock->lk_new_open_seqid) < 0)
88162306a36Sopenharmony_ci		return nfserr_bad_xdr;
88262306a36Sopenharmony_ci	status = nfsd4_decode_stateid4(argp, &lock->lk_new_open_stateid);
88362306a36Sopenharmony_ci	if (status)
88462306a36Sopenharmony_ci		return status;
88562306a36Sopenharmony_ci	if (xdr_stream_decode_u32(argp->xdr, &lock->lk_new_lock_seqid) < 0)
88662306a36Sopenharmony_ci		return nfserr_bad_xdr;
88762306a36Sopenharmony_ci	return nfsd4_decode_state_owner4(argp, &lock->lk_new_clientid,
88862306a36Sopenharmony_ci					 &lock->lk_new_owner);
88962306a36Sopenharmony_ci}
89062306a36Sopenharmony_ci
89162306a36Sopenharmony_cistatic __be32
89262306a36Sopenharmony_cinfsd4_decode_exist_lock_owner4(struct nfsd4_compoundargs *argp,
89362306a36Sopenharmony_ci			       struct nfsd4_lock *lock)
89462306a36Sopenharmony_ci{
89562306a36Sopenharmony_ci	__be32 status;
89662306a36Sopenharmony_ci
89762306a36Sopenharmony_ci	status = nfsd4_decode_stateid4(argp, &lock->lk_old_lock_stateid);
89862306a36Sopenharmony_ci	if (status)
89962306a36Sopenharmony_ci		return status;
90062306a36Sopenharmony_ci	if (xdr_stream_decode_u32(argp->xdr, &lock->lk_old_lock_seqid) < 0)
90162306a36Sopenharmony_ci		return nfserr_bad_xdr;
90262306a36Sopenharmony_ci
90362306a36Sopenharmony_ci	return nfs_ok;
90462306a36Sopenharmony_ci}
90562306a36Sopenharmony_ci
90662306a36Sopenharmony_cistatic __be32
90762306a36Sopenharmony_cinfsd4_decode_locker4(struct nfsd4_compoundargs *argp, struct nfsd4_lock *lock)
90862306a36Sopenharmony_ci{
90962306a36Sopenharmony_ci	if (xdr_stream_decode_bool(argp->xdr, &lock->lk_is_new) < 0)
91062306a36Sopenharmony_ci		return nfserr_bad_xdr;
91162306a36Sopenharmony_ci	if (lock->lk_is_new)
91262306a36Sopenharmony_ci		return nfsd4_decode_open_to_lock_owner4(argp, lock);
91362306a36Sopenharmony_ci	return nfsd4_decode_exist_lock_owner4(argp, lock);
91462306a36Sopenharmony_ci}
91562306a36Sopenharmony_ci
91662306a36Sopenharmony_cistatic __be32
91762306a36Sopenharmony_cinfsd4_decode_lock(struct nfsd4_compoundargs *argp, union nfsd4_op_u *u)
91862306a36Sopenharmony_ci{
91962306a36Sopenharmony_ci	struct nfsd4_lock *lock = &u->lock;
92062306a36Sopenharmony_ci	memset(lock, 0, sizeof(*lock));
92162306a36Sopenharmony_ci	if (xdr_stream_decode_u32(argp->xdr, &lock->lk_type) < 0)
92262306a36Sopenharmony_ci		return nfserr_bad_xdr;
92362306a36Sopenharmony_ci	if ((lock->lk_type < NFS4_READ_LT) || (lock->lk_type > NFS4_WRITEW_LT))
92462306a36Sopenharmony_ci		return nfserr_bad_xdr;
92562306a36Sopenharmony_ci	if (xdr_stream_decode_bool(argp->xdr, &lock->lk_reclaim) < 0)
92662306a36Sopenharmony_ci		return nfserr_bad_xdr;
92762306a36Sopenharmony_ci	if (xdr_stream_decode_u64(argp->xdr, &lock->lk_offset) < 0)
92862306a36Sopenharmony_ci		return nfserr_bad_xdr;
92962306a36Sopenharmony_ci	if (xdr_stream_decode_u64(argp->xdr, &lock->lk_length) < 0)
93062306a36Sopenharmony_ci		return nfserr_bad_xdr;
93162306a36Sopenharmony_ci	return nfsd4_decode_locker4(argp, lock);
93262306a36Sopenharmony_ci}
93362306a36Sopenharmony_ci
93462306a36Sopenharmony_cistatic __be32
93562306a36Sopenharmony_cinfsd4_decode_lockt(struct nfsd4_compoundargs *argp, union nfsd4_op_u *u)
93662306a36Sopenharmony_ci{
93762306a36Sopenharmony_ci	struct nfsd4_lockt *lockt = &u->lockt;
93862306a36Sopenharmony_ci	memset(lockt, 0, sizeof(*lockt));
93962306a36Sopenharmony_ci	if (xdr_stream_decode_u32(argp->xdr, &lockt->lt_type) < 0)
94062306a36Sopenharmony_ci		return nfserr_bad_xdr;
94162306a36Sopenharmony_ci	if ((lockt->lt_type < NFS4_READ_LT) || (lockt->lt_type > NFS4_WRITEW_LT))
94262306a36Sopenharmony_ci		return nfserr_bad_xdr;
94362306a36Sopenharmony_ci	if (xdr_stream_decode_u64(argp->xdr, &lockt->lt_offset) < 0)
94462306a36Sopenharmony_ci		return nfserr_bad_xdr;
94562306a36Sopenharmony_ci	if (xdr_stream_decode_u64(argp->xdr, &lockt->lt_length) < 0)
94662306a36Sopenharmony_ci		return nfserr_bad_xdr;
94762306a36Sopenharmony_ci	return nfsd4_decode_state_owner4(argp, &lockt->lt_clientid,
94862306a36Sopenharmony_ci					 &lockt->lt_owner);
94962306a36Sopenharmony_ci}
95062306a36Sopenharmony_ci
95162306a36Sopenharmony_cistatic __be32
95262306a36Sopenharmony_cinfsd4_decode_locku(struct nfsd4_compoundargs *argp, union nfsd4_op_u *u)
95362306a36Sopenharmony_ci{
95462306a36Sopenharmony_ci	struct nfsd4_locku *locku = &u->locku;
95562306a36Sopenharmony_ci	__be32 status;
95662306a36Sopenharmony_ci
95762306a36Sopenharmony_ci	if (xdr_stream_decode_u32(argp->xdr, &locku->lu_type) < 0)
95862306a36Sopenharmony_ci		return nfserr_bad_xdr;
95962306a36Sopenharmony_ci	if ((locku->lu_type < NFS4_READ_LT) || (locku->lu_type > NFS4_WRITEW_LT))
96062306a36Sopenharmony_ci		return nfserr_bad_xdr;
96162306a36Sopenharmony_ci	if (xdr_stream_decode_u32(argp->xdr, &locku->lu_seqid) < 0)
96262306a36Sopenharmony_ci		return nfserr_bad_xdr;
96362306a36Sopenharmony_ci	status = nfsd4_decode_stateid4(argp, &locku->lu_stateid);
96462306a36Sopenharmony_ci	if (status)
96562306a36Sopenharmony_ci		return status;
96662306a36Sopenharmony_ci	if (xdr_stream_decode_u64(argp->xdr, &locku->lu_offset) < 0)
96762306a36Sopenharmony_ci		return nfserr_bad_xdr;
96862306a36Sopenharmony_ci	if (xdr_stream_decode_u64(argp->xdr, &locku->lu_length) < 0)
96962306a36Sopenharmony_ci		return nfserr_bad_xdr;
97062306a36Sopenharmony_ci
97162306a36Sopenharmony_ci	return nfs_ok;
97262306a36Sopenharmony_ci}
97362306a36Sopenharmony_ci
97462306a36Sopenharmony_cistatic __be32
97562306a36Sopenharmony_cinfsd4_decode_lookup(struct nfsd4_compoundargs *argp, union nfsd4_op_u *u)
97662306a36Sopenharmony_ci{
97762306a36Sopenharmony_ci	struct nfsd4_lookup *lookup = &u->lookup;
97862306a36Sopenharmony_ci	return nfsd4_decode_component4(argp, &lookup->lo_name, &lookup->lo_len);
97962306a36Sopenharmony_ci}
98062306a36Sopenharmony_ci
98162306a36Sopenharmony_cistatic __be32
98262306a36Sopenharmony_cinfsd4_decode_createhow4(struct nfsd4_compoundargs *argp, struct nfsd4_open *open)
98362306a36Sopenharmony_ci{
98462306a36Sopenharmony_ci	__be32 status;
98562306a36Sopenharmony_ci
98662306a36Sopenharmony_ci	if (xdr_stream_decode_u32(argp->xdr, &open->op_createmode) < 0)
98762306a36Sopenharmony_ci		return nfserr_bad_xdr;
98862306a36Sopenharmony_ci	switch (open->op_createmode) {
98962306a36Sopenharmony_ci	case NFS4_CREATE_UNCHECKED:
99062306a36Sopenharmony_ci	case NFS4_CREATE_GUARDED:
99162306a36Sopenharmony_ci		status = nfsd4_decode_fattr4(argp, open->op_bmval,
99262306a36Sopenharmony_ci					     ARRAY_SIZE(open->op_bmval),
99362306a36Sopenharmony_ci					     &open->op_iattr, &open->op_acl,
99462306a36Sopenharmony_ci					     &open->op_label, &open->op_umask);
99562306a36Sopenharmony_ci		if (status)
99662306a36Sopenharmony_ci			return status;
99762306a36Sopenharmony_ci		break;
99862306a36Sopenharmony_ci	case NFS4_CREATE_EXCLUSIVE:
99962306a36Sopenharmony_ci		status = nfsd4_decode_verifier4(argp, &open->op_verf);
100062306a36Sopenharmony_ci		if (status)
100162306a36Sopenharmony_ci			return status;
100262306a36Sopenharmony_ci		break;
100362306a36Sopenharmony_ci	case NFS4_CREATE_EXCLUSIVE4_1:
100462306a36Sopenharmony_ci		if (argp->minorversion < 1)
100562306a36Sopenharmony_ci			return nfserr_bad_xdr;
100662306a36Sopenharmony_ci		status = nfsd4_decode_verifier4(argp, &open->op_verf);
100762306a36Sopenharmony_ci		if (status)
100862306a36Sopenharmony_ci			return status;
100962306a36Sopenharmony_ci		status = nfsd4_decode_fattr4(argp, open->op_bmval,
101062306a36Sopenharmony_ci					     ARRAY_SIZE(open->op_bmval),
101162306a36Sopenharmony_ci					     &open->op_iattr, &open->op_acl,
101262306a36Sopenharmony_ci					     &open->op_label, &open->op_umask);
101362306a36Sopenharmony_ci		if (status)
101462306a36Sopenharmony_ci			return status;
101562306a36Sopenharmony_ci		break;
101662306a36Sopenharmony_ci	default:
101762306a36Sopenharmony_ci		return nfserr_bad_xdr;
101862306a36Sopenharmony_ci	}
101962306a36Sopenharmony_ci
102062306a36Sopenharmony_ci	return nfs_ok;
102162306a36Sopenharmony_ci}
102262306a36Sopenharmony_ci
102362306a36Sopenharmony_cistatic __be32
102462306a36Sopenharmony_cinfsd4_decode_openflag4(struct nfsd4_compoundargs *argp, struct nfsd4_open *open)
102562306a36Sopenharmony_ci{
102662306a36Sopenharmony_ci	__be32 status;
102762306a36Sopenharmony_ci
102862306a36Sopenharmony_ci	if (xdr_stream_decode_u32(argp->xdr, &open->op_create) < 0)
102962306a36Sopenharmony_ci		return nfserr_bad_xdr;
103062306a36Sopenharmony_ci	switch (open->op_create) {
103162306a36Sopenharmony_ci	case NFS4_OPEN_NOCREATE:
103262306a36Sopenharmony_ci		break;
103362306a36Sopenharmony_ci	case NFS4_OPEN_CREATE:
103462306a36Sopenharmony_ci		status = nfsd4_decode_createhow4(argp, open);
103562306a36Sopenharmony_ci		if (status)
103662306a36Sopenharmony_ci			return status;
103762306a36Sopenharmony_ci		break;
103862306a36Sopenharmony_ci	default:
103962306a36Sopenharmony_ci		return nfserr_bad_xdr;
104062306a36Sopenharmony_ci	}
104162306a36Sopenharmony_ci
104262306a36Sopenharmony_ci	return nfs_ok;
104362306a36Sopenharmony_ci}
104462306a36Sopenharmony_ci
104562306a36Sopenharmony_cistatic __be32 nfsd4_decode_share_access(struct nfsd4_compoundargs *argp, u32 *share_access, u32 *deleg_want, u32 *deleg_when)
104662306a36Sopenharmony_ci{
104762306a36Sopenharmony_ci	u32 w;
104862306a36Sopenharmony_ci
104962306a36Sopenharmony_ci	if (xdr_stream_decode_u32(argp->xdr, &w) < 0)
105062306a36Sopenharmony_ci		return nfserr_bad_xdr;
105162306a36Sopenharmony_ci	*share_access = w & NFS4_SHARE_ACCESS_MASK;
105262306a36Sopenharmony_ci	*deleg_want = w & NFS4_SHARE_WANT_MASK;
105362306a36Sopenharmony_ci	if (deleg_when)
105462306a36Sopenharmony_ci		*deleg_when = w & NFS4_SHARE_WHEN_MASK;
105562306a36Sopenharmony_ci
105662306a36Sopenharmony_ci	switch (w & NFS4_SHARE_ACCESS_MASK) {
105762306a36Sopenharmony_ci	case NFS4_SHARE_ACCESS_READ:
105862306a36Sopenharmony_ci	case NFS4_SHARE_ACCESS_WRITE:
105962306a36Sopenharmony_ci	case NFS4_SHARE_ACCESS_BOTH:
106062306a36Sopenharmony_ci		break;
106162306a36Sopenharmony_ci	default:
106262306a36Sopenharmony_ci		return nfserr_bad_xdr;
106362306a36Sopenharmony_ci	}
106462306a36Sopenharmony_ci	w &= ~NFS4_SHARE_ACCESS_MASK;
106562306a36Sopenharmony_ci	if (!w)
106662306a36Sopenharmony_ci		return nfs_ok;
106762306a36Sopenharmony_ci	if (!argp->minorversion)
106862306a36Sopenharmony_ci		return nfserr_bad_xdr;
106962306a36Sopenharmony_ci	switch (w & NFS4_SHARE_WANT_MASK) {
107062306a36Sopenharmony_ci	case NFS4_SHARE_WANT_NO_PREFERENCE:
107162306a36Sopenharmony_ci	case NFS4_SHARE_WANT_READ_DELEG:
107262306a36Sopenharmony_ci	case NFS4_SHARE_WANT_WRITE_DELEG:
107362306a36Sopenharmony_ci	case NFS4_SHARE_WANT_ANY_DELEG:
107462306a36Sopenharmony_ci	case NFS4_SHARE_WANT_NO_DELEG:
107562306a36Sopenharmony_ci	case NFS4_SHARE_WANT_CANCEL:
107662306a36Sopenharmony_ci		break;
107762306a36Sopenharmony_ci	default:
107862306a36Sopenharmony_ci		return nfserr_bad_xdr;
107962306a36Sopenharmony_ci	}
108062306a36Sopenharmony_ci	w &= ~NFS4_SHARE_WANT_MASK;
108162306a36Sopenharmony_ci	if (!w)
108262306a36Sopenharmony_ci		return nfs_ok;
108362306a36Sopenharmony_ci
108462306a36Sopenharmony_ci	if (!deleg_when)	/* open_downgrade */
108562306a36Sopenharmony_ci		return nfserr_inval;
108662306a36Sopenharmony_ci	switch (w) {
108762306a36Sopenharmony_ci	case NFS4_SHARE_SIGNAL_DELEG_WHEN_RESRC_AVAIL:
108862306a36Sopenharmony_ci	case NFS4_SHARE_PUSH_DELEG_WHEN_UNCONTENDED:
108962306a36Sopenharmony_ci	case (NFS4_SHARE_SIGNAL_DELEG_WHEN_RESRC_AVAIL |
109062306a36Sopenharmony_ci	      NFS4_SHARE_PUSH_DELEG_WHEN_UNCONTENDED):
109162306a36Sopenharmony_ci		return nfs_ok;
109262306a36Sopenharmony_ci	}
109362306a36Sopenharmony_ci	return nfserr_bad_xdr;
109462306a36Sopenharmony_ci}
109562306a36Sopenharmony_ci
109662306a36Sopenharmony_cistatic __be32 nfsd4_decode_share_deny(struct nfsd4_compoundargs *argp, u32 *x)
109762306a36Sopenharmony_ci{
109862306a36Sopenharmony_ci	if (xdr_stream_decode_u32(argp->xdr, x) < 0)
109962306a36Sopenharmony_ci		return nfserr_bad_xdr;
110062306a36Sopenharmony_ci	/* Note: unlike access bits, deny bits may be zero. */
110162306a36Sopenharmony_ci	if (*x & ~NFS4_SHARE_DENY_BOTH)
110262306a36Sopenharmony_ci		return nfserr_bad_xdr;
110362306a36Sopenharmony_ci
110462306a36Sopenharmony_ci	return nfs_ok;
110562306a36Sopenharmony_ci}
110662306a36Sopenharmony_ci
110762306a36Sopenharmony_cistatic __be32
110862306a36Sopenharmony_cinfsd4_decode_open_claim4(struct nfsd4_compoundargs *argp,
110962306a36Sopenharmony_ci			 struct nfsd4_open *open)
111062306a36Sopenharmony_ci{
111162306a36Sopenharmony_ci	__be32 status;
111262306a36Sopenharmony_ci
111362306a36Sopenharmony_ci	if (xdr_stream_decode_u32(argp->xdr, &open->op_claim_type) < 0)
111462306a36Sopenharmony_ci		return nfserr_bad_xdr;
111562306a36Sopenharmony_ci	switch (open->op_claim_type) {
111662306a36Sopenharmony_ci	case NFS4_OPEN_CLAIM_NULL:
111762306a36Sopenharmony_ci	case NFS4_OPEN_CLAIM_DELEGATE_PREV:
111862306a36Sopenharmony_ci		status = nfsd4_decode_component4(argp, &open->op_fname,
111962306a36Sopenharmony_ci						 &open->op_fnamelen);
112062306a36Sopenharmony_ci		if (status)
112162306a36Sopenharmony_ci			return status;
112262306a36Sopenharmony_ci		break;
112362306a36Sopenharmony_ci	case NFS4_OPEN_CLAIM_PREVIOUS:
112462306a36Sopenharmony_ci		if (xdr_stream_decode_u32(argp->xdr, &open->op_delegate_type) < 0)
112562306a36Sopenharmony_ci			return nfserr_bad_xdr;
112662306a36Sopenharmony_ci		break;
112762306a36Sopenharmony_ci	case NFS4_OPEN_CLAIM_DELEGATE_CUR:
112862306a36Sopenharmony_ci		status = nfsd4_decode_stateid4(argp, &open->op_delegate_stateid);
112962306a36Sopenharmony_ci		if (status)
113062306a36Sopenharmony_ci			return status;
113162306a36Sopenharmony_ci		status = nfsd4_decode_component4(argp, &open->op_fname,
113262306a36Sopenharmony_ci						 &open->op_fnamelen);
113362306a36Sopenharmony_ci		if (status)
113462306a36Sopenharmony_ci			return status;
113562306a36Sopenharmony_ci		break;
113662306a36Sopenharmony_ci	case NFS4_OPEN_CLAIM_FH:
113762306a36Sopenharmony_ci	case NFS4_OPEN_CLAIM_DELEG_PREV_FH:
113862306a36Sopenharmony_ci		if (argp->minorversion < 1)
113962306a36Sopenharmony_ci			return nfserr_bad_xdr;
114062306a36Sopenharmony_ci		/* void */
114162306a36Sopenharmony_ci		break;
114262306a36Sopenharmony_ci	case NFS4_OPEN_CLAIM_DELEG_CUR_FH:
114362306a36Sopenharmony_ci		if (argp->minorversion < 1)
114462306a36Sopenharmony_ci			return nfserr_bad_xdr;
114562306a36Sopenharmony_ci		status = nfsd4_decode_stateid4(argp, &open->op_delegate_stateid);
114662306a36Sopenharmony_ci		if (status)
114762306a36Sopenharmony_ci			return status;
114862306a36Sopenharmony_ci		break;
114962306a36Sopenharmony_ci	default:
115062306a36Sopenharmony_ci		return nfserr_bad_xdr;
115162306a36Sopenharmony_ci	}
115262306a36Sopenharmony_ci
115362306a36Sopenharmony_ci	return nfs_ok;
115462306a36Sopenharmony_ci}
115562306a36Sopenharmony_ci
115662306a36Sopenharmony_cistatic __be32
115762306a36Sopenharmony_cinfsd4_decode_open(struct nfsd4_compoundargs *argp, union nfsd4_op_u *u)
115862306a36Sopenharmony_ci{
115962306a36Sopenharmony_ci	struct nfsd4_open *open = &u->open;
116062306a36Sopenharmony_ci	__be32 status;
116162306a36Sopenharmony_ci	u32 dummy;
116262306a36Sopenharmony_ci
116362306a36Sopenharmony_ci	memset(open, 0, sizeof(*open));
116462306a36Sopenharmony_ci
116562306a36Sopenharmony_ci	if (xdr_stream_decode_u32(argp->xdr, &open->op_seqid) < 0)
116662306a36Sopenharmony_ci		return nfserr_bad_xdr;
116762306a36Sopenharmony_ci	/* deleg_want is ignored */
116862306a36Sopenharmony_ci	status = nfsd4_decode_share_access(argp, &open->op_share_access,
116962306a36Sopenharmony_ci					   &open->op_deleg_want, &dummy);
117062306a36Sopenharmony_ci	if (status)
117162306a36Sopenharmony_ci		return status;
117262306a36Sopenharmony_ci	status = nfsd4_decode_share_deny(argp, &open->op_share_deny);
117362306a36Sopenharmony_ci	if (status)
117462306a36Sopenharmony_ci		return status;
117562306a36Sopenharmony_ci	status = nfsd4_decode_state_owner4(argp, &open->op_clientid,
117662306a36Sopenharmony_ci					   &open->op_owner);
117762306a36Sopenharmony_ci	if (status)
117862306a36Sopenharmony_ci		return status;
117962306a36Sopenharmony_ci	status = nfsd4_decode_openflag4(argp, open);
118062306a36Sopenharmony_ci	if (status)
118162306a36Sopenharmony_ci		return status;
118262306a36Sopenharmony_ci	return nfsd4_decode_open_claim4(argp, open);
118362306a36Sopenharmony_ci}
118462306a36Sopenharmony_ci
118562306a36Sopenharmony_cistatic __be32
118662306a36Sopenharmony_cinfsd4_decode_open_confirm(struct nfsd4_compoundargs *argp,
118762306a36Sopenharmony_ci			  union nfsd4_op_u *u)
118862306a36Sopenharmony_ci{
118962306a36Sopenharmony_ci	struct nfsd4_open_confirm *open_conf = &u->open_confirm;
119062306a36Sopenharmony_ci	__be32 status;
119162306a36Sopenharmony_ci
119262306a36Sopenharmony_ci	if (argp->minorversion >= 1)
119362306a36Sopenharmony_ci		return nfserr_notsupp;
119462306a36Sopenharmony_ci
119562306a36Sopenharmony_ci	status = nfsd4_decode_stateid4(argp, &open_conf->oc_req_stateid);
119662306a36Sopenharmony_ci	if (status)
119762306a36Sopenharmony_ci		return status;
119862306a36Sopenharmony_ci	if (xdr_stream_decode_u32(argp->xdr, &open_conf->oc_seqid) < 0)
119962306a36Sopenharmony_ci		return nfserr_bad_xdr;
120062306a36Sopenharmony_ci
120162306a36Sopenharmony_ci	memset(&open_conf->oc_resp_stateid, 0,
120262306a36Sopenharmony_ci	       sizeof(open_conf->oc_resp_stateid));
120362306a36Sopenharmony_ci	return nfs_ok;
120462306a36Sopenharmony_ci}
120562306a36Sopenharmony_ci
120662306a36Sopenharmony_cistatic __be32
120762306a36Sopenharmony_cinfsd4_decode_open_downgrade(struct nfsd4_compoundargs *argp,
120862306a36Sopenharmony_ci			    union nfsd4_op_u *u)
120962306a36Sopenharmony_ci{
121062306a36Sopenharmony_ci	struct nfsd4_open_downgrade *open_down = &u->open_downgrade;
121162306a36Sopenharmony_ci	__be32 status;
121262306a36Sopenharmony_ci
121362306a36Sopenharmony_ci	memset(open_down, 0, sizeof(*open_down));
121462306a36Sopenharmony_ci	status = nfsd4_decode_stateid4(argp, &open_down->od_stateid);
121562306a36Sopenharmony_ci	if (status)
121662306a36Sopenharmony_ci		return status;
121762306a36Sopenharmony_ci	if (xdr_stream_decode_u32(argp->xdr, &open_down->od_seqid) < 0)
121862306a36Sopenharmony_ci		return nfserr_bad_xdr;
121962306a36Sopenharmony_ci	/* deleg_want is ignored */
122062306a36Sopenharmony_ci	status = nfsd4_decode_share_access(argp, &open_down->od_share_access,
122162306a36Sopenharmony_ci					   &open_down->od_deleg_want, NULL);
122262306a36Sopenharmony_ci	if (status)
122362306a36Sopenharmony_ci		return status;
122462306a36Sopenharmony_ci	return nfsd4_decode_share_deny(argp, &open_down->od_share_deny);
122562306a36Sopenharmony_ci}
122662306a36Sopenharmony_ci
122762306a36Sopenharmony_cistatic __be32
122862306a36Sopenharmony_cinfsd4_decode_putfh(struct nfsd4_compoundargs *argp, union nfsd4_op_u *u)
122962306a36Sopenharmony_ci{
123062306a36Sopenharmony_ci	struct nfsd4_putfh *putfh = &u->putfh;
123162306a36Sopenharmony_ci	__be32 *p;
123262306a36Sopenharmony_ci
123362306a36Sopenharmony_ci	if (xdr_stream_decode_u32(argp->xdr, &putfh->pf_fhlen) < 0)
123462306a36Sopenharmony_ci		return nfserr_bad_xdr;
123562306a36Sopenharmony_ci	if (putfh->pf_fhlen > NFS4_FHSIZE)
123662306a36Sopenharmony_ci		return nfserr_bad_xdr;
123762306a36Sopenharmony_ci	p = xdr_inline_decode(argp->xdr, putfh->pf_fhlen);
123862306a36Sopenharmony_ci	if (!p)
123962306a36Sopenharmony_ci		return nfserr_bad_xdr;
124062306a36Sopenharmony_ci	putfh->pf_fhval = svcxdr_savemem(argp, p, putfh->pf_fhlen);
124162306a36Sopenharmony_ci	if (!putfh->pf_fhval)
124262306a36Sopenharmony_ci		return nfserr_jukebox;
124362306a36Sopenharmony_ci
124462306a36Sopenharmony_ci	putfh->no_verify = false;
124562306a36Sopenharmony_ci	return nfs_ok;
124662306a36Sopenharmony_ci}
124762306a36Sopenharmony_ci
124862306a36Sopenharmony_cistatic __be32
124962306a36Sopenharmony_cinfsd4_decode_putpubfh(struct nfsd4_compoundargs *argp, union nfsd4_op_u *p)
125062306a36Sopenharmony_ci{
125162306a36Sopenharmony_ci	if (argp->minorversion == 0)
125262306a36Sopenharmony_ci		return nfs_ok;
125362306a36Sopenharmony_ci	return nfserr_notsupp;
125462306a36Sopenharmony_ci}
125562306a36Sopenharmony_ci
125662306a36Sopenharmony_cistatic __be32
125762306a36Sopenharmony_cinfsd4_decode_read(struct nfsd4_compoundargs *argp, union nfsd4_op_u *u)
125862306a36Sopenharmony_ci{
125962306a36Sopenharmony_ci	struct nfsd4_read *read = &u->read;
126062306a36Sopenharmony_ci	__be32 status;
126162306a36Sopenharmony_ci
126262306a36Sopenharmony_ci	memset(read, 0, sizeof(*read));
126362306a36Sopenharmony_ci	status = nfsd4_decode_stateid4(argp, &read->rd_stateid);
126462306a36Sopenharmony_ci	if (status)
126562306a36Sopenharmony_ci		return status;
126662306a36Sopenharmony_ci	if (xdr_stream_decode_u64(argp->xdr, &read->rd_offset) < 0)
126762306a36Sopenharmony_ci		return nfserr_bad_xdr;
126862306a36Sopenharmony_ci	if (xdr_stream_decode_u32(argp->xdr, &read->rd_length) < 0)
126962306a36Sopenharmony_ci		return nfserr_bad_xdr;
127062306a36Sopenharmony_ci
127162306a36Sopenharmony_ci	return nfs_ok;
127262306a36Sopenharmony_ci}
127362306a36Sopenharmony_ci
127462306a36Sopenharmony_cistatic __be32
127562306a36Sopenharmony_cinfsd4_decode_readdir(struct nfsd4_compoundargs *argp, union nfsd4_op_u *u)
127662306a36Sopenharmony_ci{
127762306a36Sopenharmony_ci	struct nfsd4_readdir *readdir = &u->readdir;
127862306a36Sopenharmony_ci	__be32 status;
127962306a36Sopenharmony_ci
128062306a36Sopenharmony_ci	memset(readdir, 0, sizeof(*readdir));
128162306a36Sopenharmony_ci	if (xdr_stream_decode_u64(argp->xdr, &readdir->rd_cookie) < 0)
128262306a36Sopenharmony_ci		return nfserr_bad_xdr;
128362306a36Sopenharmony_ci	status = nfsd4_decode_verifier4(argp, &readdir->rd_verf);
128462306a36Sopenharmony_ci	if (status)
128562306a36Sopenharmony_ci		return status;
128662306a36Sopenharmony_ci	if (xdr_stream_decode_u32(argp->xdr, &readdir->rd_dircount) < 0)
128762306a36Sopenharmony_ci		return nfserr_bad_xdr;
128862306a36Sopenharmony_ci	if (xdr_stream_decode_u32(argp->xdr, &readdir->rd_maxcount) < 0)
128962306a36Sopenharmony_ci		return nfserr_bad_xdr;
129062306a36Sopenharmony_ci	if (xdr_stream_decode_uint32_array(argp->xdr, readdir->rd_bmval,
129162306a36Sopenharmony_ci					   ARRAY_SIZE(readdir->rd_bmval)) < 0)
129262306a36Sopenharmony_ci		return nfserr_bad_xdr;
129362306a36Sopenharmony_ci
129462306a36Sopenharmony_ci	return nfs_ok;
129562306a36Sopenharmony_ci}
129662306a36Sopenharmony_ci
129762306a36Sopenharmony_cistatic __be32
129862306a36Sopenharmony_cinfsd4_decode_remove(struct nfsd4_compoundargs *argp, union nfsd4_op_u *u)
129962306a36Sopenharmony_ci{
130062306a36Sopenharmony_ci	struct nfsd4_remove *remove = &u->remove;
130162306a36Sopenharmony_ci	memset(&remove->rm_cinfo, 0, sizeof(remove->rm_cinfo));
130262306a36Sopenharmony_ci	return nfsd4_decode_component4(argp, &remove->rm_name, &remove->rm_namelen);
130362306a36Sopenharmony_ci}
130462306a36Sopenharmony_ci
130562306a36Sopenharmony_cistatic __be32
130662306a36Sopenharmony_cinfsd4_decode_rename(struct nfsd4_compoundargs *argp, union nfsd4_op_u *u)
130762306a36Sopenharmony_ci{
130862306a36Sopenharmony_ci	struct nfsd4_rename *rename = &u->rename;
130962306a36Sopenharmony_ci	__be32 status;
131062306a36Sopenharmony_ci
131162306a36Sopenharmony_ci	memset(rename, 0, sizeof(*rename));
131262306a36Sopenharmony_ci	status = nfsd4_decode_component4(argp, &rename->rn_sname, &rename->rn_snamelen);
131362306a36Sopenharmony_ci	if (status)
131462306a36Sopenharmony_ci		return status;
131562306a36Sopenharmony_ci	return nfsd4_decode_component4(argp, &rename->rn_tname, &rename->rn_tnamelen);
131662306a36Sopenharmony_ci}
131762306a36Sopenharmony_ci
131862306a36Sopenharmony_cistatic __be32
131962306a36Sopenharmony_cinfsd4_decode_renew(struct nfsd4_compoundargs *argp, union nfsd4_op_u *u)
132062306a36Sopenharmony_ci{
132162306a36Sopenharmony_ci	clientid_t *clientid = &u->renew;
132262306a36Sopenharmony_ci	return nfsd4_decode_clientid4(argp, clientid);
132362306a36Sopenharmony_ci}
132462306a36Sopenharmony_ci
132562306a36Sopenharmony_cistatic __be32
132662306a36Sopenharmony_cinfsd4_decode_secinfo(struct nfsd4_compoundargs *argp,
132762306a36Sopenharmony_ci		     union nfsd4_op_u *u)
132862306a36Sopenharmony_ci{
132962306a36Sopenharmony_ci	struct nfsd4_secinfo *secinfo = &u->secinfo;
133062306a36Sopenharmony_ci	secinfo->si_exp = NULL;
133162306a36Sopenharmony_ci	return nfsd4_decode_component4(argp, &secinfo->si_name, &secinfo->si_namelen);
133262306a36Sopenharmony_ci}
133362306a36Sopenharmony_ci
133462306a36Sopenharmony_cistatic __be32
133562306a36Sopenharmony_cinfsd4_decode_setattr(struct nfsd4_compoundargs *argp, union nfsd4_op_u *u)
133662306a36Sopenharmony_ci{
133762306a36Sopenharmony_ci	struct nfsd4_setattr *setattr = &u->setattr;
133862306a36Sopenharmony_ci	__be32 status;
133962306a36Sopenharmony_ci
134062306a36Sopenharmony_ci	memset(setattr, 0, sizeof(*setattr));
134162306a36Sopenharmony_ci	status = nfsd4_decode_stateid4(argp, &setattr->sa_stateid);
134262306a36Sopenharmony_ci	if (status)
134362306a36Sopenharmony_ci		return status;
134462306a36Sopenharmony_ci	return nfsd4_decode_fattr4(argp, setattr->sa_bmval,
134562306a36Sopenharmony_ci				   ARRAY_SIZE(setattr->sa_bmval),
134662306a36Sopenharmony_ci				   &setattr->sa_iattr, &setattr->sa_acl,
134762306a36Sopenharmony_ci				   &setattr->sa_label, NULL);
134862306a36Sopenharmony_ci}
134962306a36Sopenharmony_ci
135062306a36Sopenharmony_cistatic __be32
135162306a36Sopenharmony_cinfsd4_decode_setclientid(struct nfsd4_compoundargs *argp, union nfsd4_op_u *u)
135262306a36Sopenharmony_ci{
135362306a36Sopenharmony_ci	struct nfsd4_setclientid *setclientid = &u->setclientid;
135462306a36Sopenharmony_ci	__be32 *p, status;
135562306a36Sopenharmony_ci
135662306a36Sopenharmony_ci	memset(setclientid, 0, sizeof(*setclientid));
135762306a36Sopenharmony_ci
135862306a36Sopenharmony_ci	if (argp->minorversion >= 1)
135962306a36Sopenharmony_ci		return nfserr_notsupp;
136062306a36Sopenharmony_ci
136162306a36Sopenharmony_ci	status = nfsd4_decode_verifier4(argp, &setclientid->se_verf);
136262306a36Sopenharmony_ci	if (status)
136362306a36Sopenharmony_ci		return status;
136462306a36Sopenharmony_ci	status = nfsd4_decode_opaque(argp, &setclientid->se_name);
136562306a36Sopenharmony_ci	if (status)
136662306a36Sopenharmony_ci		return status;
136762306a36Sopenharmony_ci	if (xdr_stream_decode_u32(argp->xdr, &setclientid->se_callback_prog) < 0)
136862306a36Sopenharmony_ci		return nfserr_bad_xdr;
136962306a36Sopenharmony_ci	if (xdr_stream_decode_u32(argp->xdr, &setclientid->se_callback_netid_len) < 0)
137062306a36Sopenharmony_ci		return nfserr_bad_xdr;
137162306a36Sopenharmony_ci	p = xdr_inline_decode(argp->xdr, setclientid->se_callback_netid_len);
137262306a36Sopenharmony_ci	if (!p)
137362306a36Sopenharmony_ci		return nfserr_bad_xdr;
137462306a36Sopenharmony_ci	setclientid->se_callback_netid_val = svcxdr_savemem(argp, p,
137562306a36Sopenharmony_ci						setclientid->se_callback_netid_len);
137662306a36Sopenharmony_ci	if (!setclientid->se_callback_netid_val)
137762306a36Sopenharmony_ci		return nfserr_jukebox;
137862306a36Sopenharmony_ci
137962306a36Sopenharmony_ci	if (xdr_stream_decode_u32(argp->xdr, &setclientid->se_callback_addr_len) < 0)
138062306a36Sopenharmony_ci		return nfserr_bad_xdr;
138162306a36Sopenharmony_ci	p = xdr_inline_decode(argp->xdr, setclientid->se_callback_addr_len);
138262306a36Sopenharmony_ci	if (!p)
138362306a36Sopenharmony_ci		return nfserr_bad_xdr;
138462306a36Sopenharmony_ci	setclientid->se_callback_addr_val = svcxdr_savemem(argp, p,
138562306a36Sopenharmony_ci						setclientid->se_callback_addr_len);
138662306a36Sopenharmony_ci	if (!setclientid->se_callback_addr_val)
138762306a36Sopenharmony_ci		return nfserr_jukebox;
138862306a36Sopenharmony_ci	if (xdr_stream_decode_u32(argp->xdr, &setclientid->se_callback_ident) < 0)
138962306a36Sopenharmony_ci		return nfserr_bad_xdr;
139062306a36Sopenharmony_ci
139162306a36Sopenharmony_ci	return nfs_ok;
139262306a36Sopenharmony_ci}
139362306a36Sopenharmony_ci
139462306a36Sopenharmony_cistatic __be32
139562306a36Sopenharmony_cinfsd4_decode_setclientid_confirm(struct nfsd4_compoundargs *argp,
139662306a36Sopenharmony_ci				 union nfsd4_op_u *u)
139762306a36Sopenharmony_ci{
139862306a36Sopenharmony_ci	struct nfsd4_setclientid_confirm *scd_c = &u->setclientid_confirm;
139962306a36Sopenharmony_ci	__be32 status;
140062306a36Sopenharmony_ci
140162306a36Sopenharmony_ci	if (argp->minorversion >= 1)
140262306a36Sopenharmony_ci		return nfserr_notsupp;
140362306a36Sopenharmony_ci
140462306a36Sopenharmony_ci	status = nfsd4_decode_clientid4(argp, &scd_c->sc_clientid);
140562306a36Sopenharmony_ci	if (status)
140662306a36Sopenharmony_ci		return status;
140762306a36Sopenharmony_ci	return nfsd4_decode_verifier4(argp, &scd_c->sc_confirm);
140862306a36Sopenharmony_ci}
140962306a36Sopenharmony_ci
141062306a36Sopenharmony_ci/* Also used for NVERIFY */
141162306a36Sopenharmony_cistatic __be32
141262306a36Sopenharmony_cinfsd4_decode_verify(struct nfsd4_compoundargs *argp, union nfsd4_op_u *u)
141362306a36Sopenharmony_ci{
141462306a36Sopenharmony_ci	struct nfsd4_verify *verify = &u->verify;
141562306a36Sopenharmony_ci	__be32 *p, status;
141662306a36Sopenharmony_ci
141762306a36Sopenharmony_ci	memset(verify, 0, sizeof(*verify));
141862306a36Sopenharmony_ci
141962306a36Sopenharmony_ci	status = nfsd4_decode_bitmap4(argp, verify->ve_bmval,
142062306a36Sopenharmony_ci				      ARRAY_SIZE(verify->ve_bmval));
142162306a36Sopenharmony_ci	if (status)
142262306a36Sopenharmony_ci		return status;
142362306a36Sopenharmony_ci
142462306a36Sopenharmony_ci	/* For convenience's sake, we compare raw xdr'd attributes in
142562306a36Sopenharmony_ci	 * nfsd4_proc_verify */
142662306a36Sopenharmony_ci
142762306a36Sopenharmony_ci	if (xdr_stream_decode_u32(argp->xdr, &verify->ve_attrlen) < 0)
142862306a36Sopenharmony_ci		return nfserr_bad_xdr;
142962306a36Sopenharmony_ci	p = xdr_inline_decode(argp->xdr, verify->ve_attrlen);
143062306a36Sopenharmony_ci	if (!p)
143162306a36Sopenharmony_ci		return nfserr_bad_xdr;
143262306a36Sopenharmony_ci	verify->ve_attrval = svcxdr_savemem(argp, p, verify->ve_attrlen);
143362306a36Sopenharmony_ci	if (!verify->ve_attrval)
143462306a36Sopenharmony_ci		return nfserr_jukebox;
143562306a36Sopenharmony_ci
143662306a36Sopenharmony_ci	return nfs_ok;
143762306a36Sopenharmony_ci}
143862306a36Sopenharmony_ci
143962306a36Sopenharmony_cistatic __be32
144062306a36Sopenharmony_cinfsd4_decode_write(struct nfsd4_compoundargs *argp, union nfsd4_op_u *u)
144162306a36Sopenharmony_ci{
144262306a36Sopenharmony_ci	struct nfsd4_write *write = &u->write;
144362306a36Sopenharmony_ci	__be32 status;
144462306a36Sopenharmony_ci
144562306a36Sopenharmony_ci	status = nfsd4_decode_stateid4(argp, &write->wr_stateid);
144662306a36Sopenharmony_ci	if (status)
144762306a36Sopenharmony_ci		return status;
144862306a36Sopenharmony_ci	if (xdr_stream_decode_u64(argp->xdr, &write->wr_offset) < 0)
144962306a36Sopenharmony_ci		return nfserr_bad_xdr;
145062306a36Sopenharmony_ci	if (xdr_stream_decode_u32(argp->xdr, &write->wr_stable_how) < 0)
145162306a36Sopenharmony_ci		return nfserr_bad_xdr;
145262306a36Sopenharmony_ci	if (write->wr_stable_how > NFS_FILE_SYNC)
145362306a36Sopenharmony_ci		return nfserr_bad_xdr;
145462306a36Sopenharmony_ci	if (xdr_stream_decode_u32(argp->xdr, &write->wr_buflen) < 0)
145562306a36Sopenharmony_ci		return nfserr_bad_xdr;
145662306a36Sopenharmony_ci	if (!xdr_stream_subsegment(argp->xdr, &write->wr_payload, write->wr_buflen))
145762306a36Sopenharmony_ci		return nfserr_bad_xdr;
145862306a36Sopenharmony_ci
145962306a36Sopenharmony_ci	write->wr_bytes_written = 0;
146062306a36Sopenharmony_ci	write->wr_how_written = 0;
146162306a36Sopenharmony_ci	memset(&write->wr_verifier, 0, sizeof(write->wr_verifier));
146262306a36Sopenharmony_ci	return nfs_ok;
146362306a36Sopenharmony_ci}
146462306a36Sopenharmony_ci
146562306a36Sopenharmony_cistatic __be32
146662306a36Sopenharmony_cinfsd4_decode_release_lockowner(struct nfsd4_compoundargs *argp,
146762306a36Sopenharmony_ci			       union nfsd4_op_u *u)
146862306a36Sopenharmony_ci{
146962306a36Sopenharmony_ci	struct nfsd4_release_lockowner *rlockowner = &u->release_lockowner;
147062306a36Sopenharmony_ci	__be32 status;
147162306a36Sopenharmony_ci
147262306a36Sopenharmony_ci	if (argp->minorversion >= 1)
147362306a36Sopenharmony_ci		return nfserr_notsupp;
147462306a36Sopenharmony_ci
147562306a36Sopenharmony_ci	status = nfsd4_decode_state_owner4(argp, &rlockowner->rl_clientid,
147662306a36Sopenharmony_ci					   &rlockowner->rl_owner);
147762306a36Sopenharmony_ci	if (status)
147862306a36Sopenharmony_ci		return status;
147962306a36Sopenharmony_ci
148062306a36Sopenharmony_ci	if (argp->minorversion && !zero_clientid(&rlockowner->rl_clientid))
148162306a36Sopenharmony_ci		return nfserr_inval;
148262306a36Sopenharmony_ci
148362306a36Sopenharmony_ci	return nfs_ok;
148462306a36Sopenharmony_ci}
148562306a36Sopenharmony_ci
148662306a36Sopenharmony_cistatic __be32 nfsd4_decode_backchannel_ctl(struct nfsd4_compoundargs *argp,
148762306a36Sopenharmony_ci					   union nfsd4_op_u *u)
148862306a36Sopenharmony_ci{
148962306a36Sopenharmony_ci	struct nfsd4_backchannel_ctl *bc = &u->backchannel_ctl;
149062306a36Sopenharmony_ci	memset(bc, 0, sizeof(*bc));
149162306a36Sopenharmony_ci	if (xdr_stream_decode_u32(argp->xdr, &bc->bc_cb_program) < 0)
149262306a36Sopenharmony_ci		return nfserr_bad_xdr;
149362306a36Sopenharmony_ci	return nfsd4_decode_cb_sec(argp, &bc->bc_cb_sec);
149462306a36Sopenharmony_ci}
149562306a36Sopenharmony_ci
149662306a36Sopenharmony_cistatic __be32 nfsd4_decode_bind_conn_to_session(struct nfsd4_compoundargs *argp,
149762306a36Sopenharmony_ci						union nfsd4_op_u *u)
149862306a36Sopenharmony_ci{
149962306a36Sopenharmony_ci	struct nfsd4_bind_conn_to_session *bcts = &u->bind_conn_to_session;
150062306a36Sopenharmony_ci	u32 use_conn_in_rdma_mode;
150162306a36Sopenharmony_ci	__be32 status;
150262306a36Sopenharmony_ci
150362306a36Sopenharmony_ci	memset(bcts, 0, sizeof(*bcts));
150462306a36Sopenharmony_ci	status = nfsd4_decode_sessionid4(argp, &bcts->sessionid);
150562306a36Sopenharmony_ci	if (status)
150662306a36Sopenharmony_ci		return status;
150762306a36Sopenharmony_ci	if (xdr_stream_decode_u32(argp->xdr, &bcts->dir) < 0)
150862306a36Sopenharmony_ci		return nfserr_bad_xdr;
150962306a36Sopenharmony_ci	if (xdr_stream_decode_u32(argp->xdr, &use_conn_in_rdma_mode) < 0)
151062306a36Sopenharmony_ci		return nfserr_bad_xdr;
151162306a36Sopenharmony_ci
151262306a36Sopenharmony_ci	return nfs_ok;
151362306a36Sopenharmony_ci}
151462306a36Sopenharmony_ci
151562306a36Sopenharmony_cistatic __be32
151662306a36Sopenharmony_cinfsd4_decode_state_protect_ops(struct nfsd4_compoundargs *argp,
151762306a36Sopenharmony_ci			       struct nfsd4_exchange_id *exid)
151862306a36Sopenharmony_ci{
151962306a36Sopenharmony_ci	__be32 status;
152062306a36Sopenharmony_ci
152162306a36Sopenharmony_ci	status = nfsd4_decode_bitmap4(argp, exid->spo_must_enforce,
152262306a36Sopenharmony_ci				      ARRAY_SIZE(exid->spo_must_enforce));
152362306a36Sopenharmony_ci	if (status)
152462306a36Sopenharmony_ci		return nfserr_bad_xdr;
152562306a36Sopenharmony_ci	status = nfsd4_decode_bitmap4(argp, exid->spo_must_allow,
152662306a36Sopenharmony_ci				      ARRAY_SIZE(exid->spo_must_allow));
152762306a36Sopenharmony_ci	if (status)
152862306a36Sopenharmony_ci		return nfserr_bad_xdr;
152962306a36Sopenharmony_ci
153062306a36Sopenharmony_ci	return nfs_ok;
153162306a36Sopenharmony_ci}
153262306a36Sopenharmony_ci
153362306a36Sopenharmony_ci/*
153462306a36Sopenharmony_ci * This implementation currently does not support SP4_SSV.
153562306a36Sopenharmony_ci * This decoder simply skips over these arguments.
153662306a36Sopenharmony_ci */
153762306a36Sopenharmony_cistatic noinline __be32
153862306a36Sopenharmony_cinfsd4_decode_ssv_sp_parms(struct nfsd4_compoundargs *argp,
153962306a36Sopenharmony_ci			  struct nfsd4_exchange_id *exid)
154062306a36Sopenharmony_ci{
154162306a36Sopenharmony_ci	u32 count, window, num_gss_handles;
154262306a36Sopenharmony_ci	__be32 status;
154362306a36Sopenharmony_ci
154462306a36Sopenharmony_ci	/* ssp_ops */
154562306a36Sopenharmony_ci	status = nfsd4_decode_state_protect_ops(argp, exid);
154662306a36Sopenharmony_ci	if (status)
154762306a36Sopenharmony_ci		return status;
154862306a36Sopenharmony_ci
154962306a36Sopenharmony_ci	/* ssp_hash_algs<> */
155062306a36Sopenharmony_ci	if (xdr_stream_decode_u32(argp->xdr, &count) < 0)
155162306a36Sopenharmony_ci		return nfserr_bad_xdr;
155262306a36Sopenharmony_ci	while (count--) {
155362306a36Sopenharmony_ci		status = nfsd4_decode_ignored_string(argp, 0);
155462306a36Sopenharmony_ci		if (status)
155562306a36Sopenharmony_ci			return status;
155662306a36Sopenharmony_ci	}
155762306a36Sopenharmony_ci
155862306a36Sopenharmony_ci	/* ssp_encr_algs<> */
155962306a36Sopenharmony_ci	if (xdr_stream_decode_u32(argp->xdr, &count) < 0)
156062306a36Sopenharmony_ci		return nfserr_bad_xdr;
156162306a36Sopenharmony_ci	while (count--) {
156262306a36Sopenharmony_ci		status = nfsd4_decode_ignored_string(argp, 0);
156362306a36Sopenharmony_ci		if (status)
156462306a36Sopenharmony_ci			return status;
156562306a36Sopenharmony_ci	}
156662306a36Sopenharmony_ci
156762306a36Sopenharmony_ci	if (xdr_stream_decode_u32(argp->xdr, &window) < 0)
156862306a36Sopenharmony_ci		return nfserr_bad_xdr;
156962306a36Sopenharmony_ci	if (xdr_stream_decode_u32(argp->xdr, &num_gss_handles) < 0)
157062306a36Sopenharmony_ci		return nfserr_bad_xdr;
157162306a36Sopenharmony_ci
157262306a36Sopenharmony_ci	return nfs_ok;
157362306a36Sopenharmony_ci}
157462306a36Sopenharmony_ci
157562306a36Sopenharmony_cistatic __be32
157662306a36Sopenharmony_cinfsd4_decode_state_protect4_a(struct nfsd4_compoundargs *argp,
157762306a36Sopenharmony_ci			      struct nfsd4_exchange_id *exid)
157862306a36Sopenharmony_ci{
157962306a36Sopenharmony_ci	__be32 status;
158062306a36Sopenharmony_ci
158162306a36Sopenharmony_ci	if (xdr_stream_decode_u32(argp->xdr, &exid->spa_how) < 0)
158262306a36Sopenharmony_ci		return nfserr_bad_xdr;
158362306a36Sopenharmony_ci	switch (exid->spa_how) {
158462306a36Sopenharmony_ci	case SP4_NONE:
158562306a36Sopenharmony_ci		break;
158662306a36Sopenharmony_ci	case SP4_MACH_CRED:
158762306a36Sopenharmony_ci		status = nfsd4_decode_state_protect_ops(argp, exid);
158862306a36Sopenharmony_ci		if (status)
158962306a36Sopenharmony_ci			return status;
159062306a36Sopenharmony_ci		break;
159162306a36Sopenharmony_ci	case SP4_SSV:
159262306a36Sopenharmony_ci		status = nfsd4_decode_ssv_sp_parms(argp, exid);
159362306a36Sopenharmony_ci		if (status)
159462306a36Sopenharmony_ci			return status;
159562306a36Sopenharmony_ci		break;
159662306a36Sopenharmony_ci	default:
159762306a36Sopenharmony_ci		return nfserr_bad_xdr;
159862306a36Sopenharmony_ci	}
159962306a36Sopenharmony_ci
160062306a36Sopenharmony_ci	return nfs_ok;
160162306a36Sopenharmony_ci}
160262306a36Sopenharmony_ci
160362306a36Sopenharmony_cistatic __be32
160462306a36Sopenharmony_cinfsd4_decode_nfs_impl_id4(struct nfsd4_compoundargs *argp,
160562306a36Sopenharmony_ci			  struct nfsd4_exchange_id *exid)
160662306a36Sopenharmony_ci{
160762306a36Sopenharmony_ci	__be32 status;
160862306a36Sopenharmony_ci	u32 count;
160962306a36Sopenharmony_ci
161062306a36Sopenharmony_ci	if (xdr_stream_decode_u32(argp->xdr, &count) < 0)
161162306a36Sopenharmony_ci		return nfserr_bad_xdr;
161262306a36Sopenharmony_ci	switch (count) {
161362306a36Sopenharmony_ci	case 0:
161462306a36Sopenharmony_ci		break;
161562306a36Sopenharmony_ci	case 1:
161662306a36Sopenharmony_ci		/* Note that RFC 8881 places no length limit on
161762306a36Sopenharmony_ci		 * nii_domain, but this implementation permits no
161862306a36Sopenharmony_ci		 * more than NFS4_OPAQUE_LIMIT bytes */
161962306a36Sopenharmony_ci		status = nfsd4_decode_opaque(argp, &exid->nii_domain);
162062306a36Sopenharmony_ci		if (status)
162162306a36Sopenharmony_ci			return status;
162262306a36Sopenharmony_ci		/* Note that RFC 8881 places no length limit on
162362306a36Sopenharmony_ci		 * nii_name, but this implementation permits no
162462306a36Sopenharmony_ci		 * more than NFS4_OPAQUE_LIMIT bytes */
162562306a36Sopenharmony_ci		status = nfsd4_decode_opaque(argp, &exid->nii_name);
162662306a36Sopenharmony_ci		if (status)
162762306a36Sopenharmony_ci			return status;
162862306a36Sopenharmony_ci		status = nfsd4_decode_nfstime4(argp, &exid->nii_time);
162962306a36Sopenharmony_ci		if (status)
163062306a36Sopenharmony_ci			return status;
163162306a36Sopenharmony_ci		break;
163262306a36Sopenharmony_ci	default:
163362306a36Sopenharmony_ci		return nfserr_bad_xdr;
163462306a36Sopenharmony_ci	}
163562306a36Sopenharmony_ci
163662306a36Sopenharmony_ci	return nfs_ok;
163762306a36Sopenharmony_ci}
163862306a36Sopenharmony_ci
163962306a36Sopenharmony_cistatic __be32
164062306a36Sopenharmony_cinfsd4_decode_exchange_id(struct nfsd4_compoundargs *argp,
164162306a36Sopenharmony_ci			 union nfsd4_op_u *u)
164262306a36Sopenharmony_ci{
164362306a36Sopenharmony_ci	struct nfsd4_exchange_id *exid = &u->exchange_id;
164462306a36Sopenharmony_ci	__be32 status;
164562306a36Sopenharmony_ci
164662306a36Sopenharmony_ci	memset(exid, 0, sizeof(*exid));
164762306a36Sopenharmony_ci	status = nfsd4_decode_verifier4(argp, &exid->verifier);
164862306a36Sopenharmony_ci	if (status)
164962306a36Sopenharmony_ci		return status;
165062306a36Sopenharmony_ci	status = nfsd4_decode_opaque(argp, &exid->clname);
165162306a36Sopenharmony_ci	if (status)
165262306a36Sopenharmony_ci		return status;
165362306a36Sopenharmony_ci	if (xdr_stream_decode_u32(argp->xdr, &exid->flags) < 0)
165462306a36Sopenharmony_ci		return nfserr_bad_xdr;
165562306a36Sopenharmony_ci	status = nfsd4_decode_state_protect4_a(argp, exid);
165662306a36Sopenharmony_ci	if (status)
165762306a36Sopenharmony_ci		return status;
165862306a36Sopenharmony_ci	return nfsd4_decode_nfs_impl_id4(argp, exid);
165962306a36Sopenharmony_ci}
166062306a36Sopenharmony_ci
166162306a36Sopenharmony_cistatic __be32
166262306a36Sopenharmony_cinfsd4_decode_channel_attrs4(struct nfsd4_compoundargs *argp,
166362306a36Sopenharmony_ci			    struct nfsd4_channel_attrs *ca)
166462306a36Sopenharmony_ci{
166562306a36Sopenharmony_ci	__be32 *p;
166662306a36Sopenharmony_ci
166762306a36Sopenharmony_ci	p = xdr_inline_decode(argp->xdr, XDR_UNIT * 7);
166862306a36Sopenharmony_ci	if (!p)
166962306a36Sopenharmony_ci		return nfserr_bad_xdr;
167062306a36Sopenharmony_ci
167162306a36Sopenharmony_ci	/* headerpadsz is ignored */
167262306a36Sopenharmony_ci	p++;
167362306a36Sopenharmony_ci	ca->maxreq_sz = be32_to_cpup(p++);
167462306a36Sopenharmony_ci	ca->maxresp_sz = be32_to_cpup(p++);
167562306a36Sopenharmony_ci	ca->maxresp_cached = be32_to_cpup(p++);
167662306a36Sopenharmony_ci	ca->maxops = be32_to_cpup(p++);
167762306a36Sopenharmony_ci	ca->maxreqs = be32_to_cpup(p++);
167862306a36Sopenharmony_ci	ca->nr_rdma_attrs = be32_to_cpup(p);
167962306a36Sopenharmony_ci	switch (ca->nr_rdma_attrs) {
168062306a36Sopenharmony_ci	case 0:
168162306a36Sopenharmony_ci		break;
168262306a36Sopenharmony_ci	case 1:
168362306a36Sopenharmony_ci		if (xdr_stream_decode_u32(argp->xdr, &ca->rdma_attrs) < 0)
168462306a36Sopenharmony_ci			return nfserr_bad_xdr;
168562306a36Sopenharmony_ci		break;
168662306a36Sopenharmony_ci	default:
168762306a36Sopenharmony_ci		return nfserr_bad_xdr;
168862306a36Sopenharmony_ci	}
168962306a36Sopenharmony_ci
169062306a36Sopenharmony_ci	return nfs_ok;
169162306a36Sopenharmony_ci}
169262306a36Sopenharmony_ci
169362306a36Sopenharmony_cistatic __be32
169462306a36Sopenharmony_cinfsd4_decode_create_session(struct nfsd4_compoundargs *argp,
169562306a36Sopenharmony_ci			    union nfsd4_op_u *u)
169662306a36Sopenharmony_ci{
169762306a36Sopenharmony_ci	struct nfsd4_create_session *sess = &u->create_session;
169862306a36Sopenharmony_ci	__be32 status;
169962306a36Sopenharmony_ci
170062306a36Sopenharmony_ci	memset(sess, 0, sizeof(*sess));
170162306a36Sopenharmony_ci	status = nfsd4_decode_clientid4(argp, &sess->clientid);
170262306a36Sopenharmony_ci	if (status)
170362306a36Sopenharmony_ci		return status;
170462306a36Sopenharmony_ci	if (xdr_stream_decode_u32(argp->xdr, &sess->seqid) < 0)
170562306a36Sopenharmony_ci		return nfserr_bad_xdr;
170662306a36Sopenharmony_ci	if (xdr_stream_decode_u32(argp->xdr, &sess->flags) < 0)
170762306a36Sopenharmony_ci		return nfserr_bad_xdr;
170862306a36Sopenharmony_ci	status = nfsd4_decode_channel_attrs4(argp, &sess->fore_channel);
170962306a36Sopenharmony_ci	if (status)
171062306a36Sopenharmony_ci		return status;
171162306a36Sopenharmony_ci	status = nfsd4_decode_channel_attrs4(argp, &sess->back_channel);
171262306a36Sopenharmony_ci	if (status)
171362306a36Sopenharmony_ci		return status;
171462306a36Sopenharmony_ci	if (xdr_stream_decode_u32(argp->xdr, &sess->callback_prog) < 0)
171562306a36Sopenharmony_ci		return nfserr_bad_xdr;
171662306a36Sopenharmony_ci	return nfsd4_decode_cb_sec(argp, &sess->cb_sec);
171762306a36Sopenharmony_ci}
171862306a36Sopenharmony_ci
171962306a36Sopenharmony_cistatic __be32
172062306a36Sopenharmony_cinfsd4_decode_destroy_session(struct nfsd4_compoundargs *argp,
172162306a36Sopenharmony_ci			     union nfsd4_op_u *u)
172262306a36Sopenharmony_ci{
172362306a36Sopenharmony_ci	struct nfsd4_destroy_session *destroy_session = &u->destroy_session;
172462306a36Sopenharmony_ci	return nfsd4_decode_sessionid4(argp, &destroy_session->sessionid);
172562306a36Sopenharmony_ci}
172662306a36Sopenharmony_ci
172762306a36Sopenharmony_cistatic __be32
172862306a36Sopenharmony_cinfsd4_decode_free_stateid(struct nfsd4_compoundargs *argp,
172962306a36Sopenharmony_ci			  union nfsd4_op_u *u)
173062306a36Sopenharmony_ci{
173162306a36Sopenharmony_ci	struct nfsd4_free_stateid *free_stateid = &u->free_stateid;
173262306a36Sopenharmony_ci	return nfsd4_decode_stateid4(argp, &free_stateid->fr_stateid);
173362306a36Sopenharmony_ci}
173462306a36Sopenharmony_ci
173562306a36Sopenharmony_ci#ifdef CONFIG_NFSD_PNFS
173662306a36Sopenharmony_cistatic __be32
173762306a36Sopenharmony_cinfsd4_decode_getdeviceinfo(struct nfsd4_compoundargs *argp,
173862306a36Sopenharmony_ci		union nfsd4_op_u *u)
173962306a36Sopenharmony_ci{
174062306a36Sopenharmony_ci	struct nfsd4_getdeviceinfo *gdev = &u->getdeviceinfo;
174162306a36Sopenharmony_ci	__be32 status;
174262306a36Sopenharmony_ci
174362306a36Sopenharmony_ci	memset(gdev, 0, sizeof(*gdev));
174462306a36Sopenharmony_ci	status = nfsd4_decode_deviceid4(argp, &gdev->gd_devid);
174562306a36Sopenharmony_ci	if (status)
174662306a36Sopenharmony_ci		return status;
174762306a36Sopenharmony_ci	if (xdr_stream_decode_u32(argp->xdr, &gdev->gd_layout_type) < 0)
174862306a36Sopenharmony_ci		return nfserr_bad_xdr;
174962306a36Sopenharmony_ci	if (xdr_stream_decode_u32(argp->xdr, &gdev->gd_maxcount) < 0)
175062306a36Sopenharmony_ci		return nfserr_bad_xdr;
175162306a36Sopenharmony_ci	if (xdr_stream_decode_uint32_array(argp->xdr,
175262306a36Sopenharmony_ci					   &gdev->gd_notify_types, 1) < 0)
175362306a36Sopenharmony_ci		return nfserr_bad_xdr;
175462306a36Sopenharmony_ci
175562306a36Sopenharmony_ci	return nfs_ok;
175662306a36Sopenharmony_ci}
175762306a36Sopenharmony_ci
175862306a36Sopenharmony_cistatic __be32
175962306a36Sopenharmony_cinfsd4_decode_layoutcommit(struct nfsd4_compoundargs *argp,
176062306a36Sopenharmony_ci			  union nfsd4_op_u *u)
176162306a36Sopenharmony_ci{
176262306a36Sopenharmony_ci	struct nfsd4_layoutcommit *lcp = &u->layoutcommit;
176362306a36Sopenharmony_ci	__be32 *p, status;
176462306a36Sopenharmony_ci
176562306a36Sopenharmony_ci	memset(lcp, 0, sizeof(*lcp));
176662306a36Sopenharmony_ci	if (xdr_stream_decode_u64(argp->xdr, &lcp->lc_seg.offset) < 0)
176762306a36Sopenharmony_ci		return nfserr_bad_xdr;
176862306a36Sopenharmony_ci	if (xdr_stream_decode_u64(argp->xdr, &lcp->lc_seg.length) < 0)
176962306a36Sopenharmony_ci		return nfserr_bad_xdr;
177062306a36Sopenharmony_ci	if (xdr_stream_decode_bool(argp->xdr, &lcp->lc_reclaim) < 0)
177162306a36Sopenharmony_ci		return nfserr_bad_xdr;
177262306a36Sopenharmony_ci	status = nfsd4_decode_stateid4(argp, &lcp->lc_sid);
177362306a36Sopenharmony_ci	if (status)
177462306a36Sopenharmony_ci		return status;
177562306a36Sopenharmony_ci	if (xdr_stream_decode_u32(argp->xdr, &lcp->lc_newoffset) < 0)
177662306a36Sopenharmony_ci		return nfserr_bad_xdr;
177762306a36Sopenharmony_ci	if (lcp->lc_newoffset) {
177862306a36Sopenharmony_ci		if (xdr_stream_decode_u64(argp->xdr, &lcp->lc_last_wr) < 0)
177962306a36Sopenharmony_ci			return nfserr_bad_xdr;
178062306a36Sopenharmony_ci	} else
178162306a36Sopenharmony_ci		lcp->lc_last_wr = 0;
178262306a36Sopenharmony_ci	p = xdr_inline_decode(argp->xdr, XDR_UNIT);
178362306a36Sopenharmony_ci	if (!p)
178462306a36Sopenharmony_ci		return nfserr_bad_xdr;
178562306a36Sopenharmony_ci	if (xdr_item_is_present(p)) {
178662306a36Sopenharmony_ci		status = nfsd4_decode_nfstime4(argp, &lcp->lc_mtime);
178762306a36Sopenharmony_ci		if (status)
178862306a36Sopenharmony_ci			return status;
178962306a36Sopenharmony_ci	} else {
179062306a36Sopenharmony_ci		lcp->lc_mtime.tv_nsec = UTIME_NOW;
179162306a36Sopenharmony_ci	}
179262306a36Sopenharmony_ci	return nfsd4_decode_layoutupdate4(argp, lcp);
179362306a36Sopenharmony_ci}
179462306a36Sopenharmony_ci
179562306a36Sopenharmony_cistatic __be32
179662306a36Sopenharmony_cinfsd4_decode_layoutget(struct nfsd4_compoundargs *argp,
179762306a36Sopenharmony_ci		union nfsd4_op_u *u)
179862306a36Sopenharmony_ci{
179962306a36Sopenharmony_ci	struct nfsd4_layoutget *lgp = &u->layoutget;
180062306a36Sopenharmony_ci	__be32 status;
180162306a36Sopenharmony_ci
180262306a36Sopenharmony_ci	memset(lgp, 0, sizeof(*lgp));
180362306a36Sopenharmony_ci	if (xdr_stream_decode_u32(argp->xdr, &lgp->lg_signal) < 0)
180462306a36Sopenharmony_ci		return nfserr_bad_xdr;
180562306a36Sopenharmony_ci	if (xdr_stream_decode_u32(argp->xdr, &lgp->lg_layout_type) < 0)
180662306a36Sopenharmony_ci		return nfserr_bad_xdr;
180762306a36Sopenharmony_ci	if (xdr_stream_decode_u32(argp->xdr, &lgp->lg_seg.iomode) < 0)
180862306a36Sopenharmony_ci		return nfserr_bad_xdr;
180962306a36Sopenharmony_ci	if (xdr_stream_decode_u64(argp->xdr, &lgp->lg_seg.offset) < 0)
181062306a36Sopenharmony_ci		return nfserr_bad_xdr;
181162306a36Sopenharmony_ci	if (xdr_stream_decode_u64(argp->xdr, &lgp->lg_seg.length) < 0)
181262306a36Sopenharmony_ci		return nfserr_bad_xdr;
181362306a36Sopenharmony_ci	if (xdr_stream_decode_u64(argp->xdr, &lgp->lg_minlength) < 0)
181462306a36Sopenharmony_ci		return nfserr_bad_xdr;
181562306a36Sopenharmony_ci	status = nfsd4_decode_stateid4(argp, &lgp->lg_sid);
181662306a36Sopenharmony_ci	if (status)
181762306a36Sopenharmony_ci		return status;
181862306a36Sopenharmony_ci	if (xdr_stream_decode_u32(argp->xdr, &lgp->lg_maxcount) < 0)
181962306a36Sopenharmony_ci		return nfserr_bad_xdr;
182062306a36Sopenharmony_ci
182162306a36Sopenharmony_ci	return nfs_ok;
182262306a36Sopenharmony_ci}
182362306a36Sopenharmony_ci
182462306a36Sopenharmony_cistatic __be32
182562306a36Sopenharmony_cinfsd4_decode_layoutreturn(struct nfsd4_compoundargs *argp,
182662306a36Sopenharmony_ci		union nfsd4_op_u *u)
182762306a36Sopenharmony_ci{
182862306a36Sopenharmony_ci	struct nfsd4_layoutreturn *lrp = &u->layoutreturn;
182962306a36Sopenharmony_ci	memset(lrp, 0, sizeof(*lrp));
183062306a36Sopenharmony_ci	if (xdr_stream_decode_bool(argp->xdr, &lrp->lr_reclaim) < 0)
183162306a36Sopenharmony_ci		return nfserr_bad_xdr;
183262306a36Sopenharmony_ci	if (xdr_stream_decode_u32(argp->xdr, &lrp->lr_layout_type) < 0)
183362306a36Sopenharmony_ci		return nfserr_bad_xdr;
183462306a36Sopenharmony_ci	if (xdr_stream_decode_u32(argp->xdr, &lrp->lr_seg.iomode) < 0)
183562306a36Sopenharmony_ci		return nfserr_bad_xdr;
183662306a36Sopenharmony_ci	return nfsd4_decode_layoutreturn4(argp, lrp);
183762306a36Sopenharmony_ci}
183862306a36Sopenharmony_ci#endif /* CONFIG_NFSD_PNFS */
183962306a36Sopenharmony_ci
184062306a36Sopenharmony_cistatic __be32 nfsd4_decode_secinfo_no_name(struct nfsd4_compoundargs *argp,
184162306a36Sopenharmony_ci					   union nfsd4_op_u *u)
184262306a36Sopenharmony_ci{
184362306a36Sopenharmony_ci	struct nfsd4_secinfo_no_name *sin = &u->secinfo_no_name;
184462306a36Sopenharmony_ci	if (xdr_stream_decode_u32(argp->xdr, &sin->sin_style) < 0)
184562306a36Sopenharmony_ci		return nfserr_bad_xdr;
184662306a36Sopenharmony_ci
184762306a36Sopenharmony_ci	sin->sin_exp = NULL;
184862306a36Sopenharmony_ci	return nfs_ok;
184962306a36Sopenharmony_ci}
185062306a36Sopenharmony_ci
185162306a36Sopenharmony_cistatic __be32
185262306a36Sopenharmony_cinfsd4_decode_sequence(struct nfsd4_compoundargs *argp,
185362306a36Sopenharmony_ci		      union nfsd4_op_u *u)
185462306a36Sopenharmony_ci{
185562306a36Sopenharmony_ci	struct nfsd4_sequence *seq = &u->sequence;
185662306a36Sopenharmony_ci	__be32 *p, status;
185762306a36Sopenharmony_ci
185862306a36Sopenharmony_ci	status = nfsd4_decode_sessionid4(argp, &seq->sessionid);
185962306a36Sopenharmony_ci	if (status)
186062306a36Sopenharmony_ci		return status;
186162306a36Sopenharmony_ci	p = xdr_inline_decode(argp->xdr, XDR_UNIT * 4);
186262306a36Sopenharmony_ci	if (!p)
186362306a36Sopenharmony_ci		return nfserr_bad_xdr;
186462306a36Sopenharmony_ci	seq->seqid = be32_to_cpup(p++);
186562306a36Sopenharmony_ci	seq->slotid = be32_to_cpup(p++);
186662306a36Sopenharmony_ci	seq->maxslots = be32_to_cpup(p++);
186762306a36Sopenharmony_ci	seq->cachethis = be32_to_cpup(p);
186862306a36Sopenharmony_ci
186962306a36Sopenharmony_ci	seq->status_flags = 0;
187062306a36Sopenharmony_ci	return nfs_ok;
187162306a36Sopenharmony_ci}
187262306a36Sopenharmony_ci
187362306a36Sopenharmony_cistatic __be32
187462306a36Sopenharmony_cinfsd4_decode_test_stateid(struct nfsd4_compoundargs *argp,
187562306a36Sopenharmony_ci			  union nfsd4_op_u *u)
187662306a36Sopenharmony_ci{
187762306a36Sopenharmony_ci	struct nfsd4_test_stateid *test_stateid = &u->test_stateid;
187862306a36Sopenharmony_ci	struct nfsd4_test_stateid_id *stateid;
187962306a36Sopenharmony_ci	__be32 status;
188062306a36Sopenharmony_ci	u32 i;
188162306a36Sopenharmony_ci
188262306a36Sopenharmony_ci	memset(test_stateid, 0, sizeof(*test_stateid));
188362306a36Sopenharmony_ci	if (xdr_stream_decode_u32(argp->xdr, &test_stateid->ts_num_ids) < 0)
188462306a36Sopenharmony_ci		return nfserr_bad_xdr;
188562306a36Sopenharmony_ci
188662306a36Sopenharmony_ci	INIT_LIST_HEAD(&test_stateid->ts_stateid_list);
188762306a36Sopenharmony_ci	for (i = 0; i < test_stateid->ts_num_ids; i++) {
188862306a36Sopenharmony_ci		stateid = svcxdr_tmpalloc(argp, sizeof(*stateid));
188962306a36Sopenharmony_ci		if (!stateid)
189062306a36Sopenharmony_ci			return nfserr_jukebox;
189162306a36Sopenharmony_ci		INIT_LIST_HEAD(&stateid->ts_id_list);
189262306a36Sopenharmony_ci		list_add_tail(&stateid->ts_id_list, &test_stateid->ts_stateid_list);
189362306a36Sopenharmony_ci		status = nfsd4_decode_stateid4(argp, &stateid->ts_id_stateid);
189462306a36Sopenharmony_ci		if (status)
189562306a36Sopenharmony_ci			return status;
189662306a36Sopenharmony_ci	}
189762306a36Sopenharmony_ci
189862306a36Sopenharmony_ci	return nfs_ok;
189962306a36Sopenharmony_ci}
190062306a36Sopenharmony_ci
190162306a36Sopenharmony_cistatic __be32 nfsd4_decode_destroy_clientid(struct nfsd4_compoundargs *argp,
190262306a36Sopenharmony_ci					    union nfsd4_op_u *u)
190362306a36Sopenharmony_ci{
190462306a36Sopenharmony_ci	struct nfsd4_destroy_clientid *dc = &u->destroy_clientid;
190562306a36Sopenharmony_ci	return nfsd4_decode_clientid4(argp, &dc->clientid);
190662306a36Sopenharmony_ci}
190762306a36Sopenharmony_ci
190862306a36Sopenharmony_cistatic __be32 nfsd4_decode_reclaim_complete(struct nfsd4_compoundargs *argp,
190962306a36Sopenharmony_ci					    union nfsd4_op_u *u)
191062306a36Sopenharmony_ci{
191162306a36Sopenharmony_ci	struct nfsd4_reclaim_complete *rc = &u->reclaim_complete;
191262306a36Sopenharmony_ci	if (xdr_stream_decode_bool(argp->xdr, &rc->rca_one_fs) < 0)
191362306a36Sopenharmony_ci		return nfserr_bad_xdr;
191462306a36Sopenharmony_ci	return nfs_ok;
191562306a36Sopenharmony_ci}
191662306a36Sopenharmony_ci
191762306a36Sopenharmony_cistatic __be32
191862306a36Sopenharmony_cinfsd4_decode_fallocate(struct nfsd4_compoundargs *argp,
191962306a36Sopenharmony_ci		       union nfsd4_op_u *u)
192062306a36Sopenharmony_ci{
192162306a36Sopenharmony_ci	struct nfsd4_fallocate *fallocate = &u->allocate;
192262306a36Sopenharmony_ci	__be32 status;
192362306a36Sopenharmony_ci
192462306a36Sopenharmony_ci	status = nfsd4_decode_stateid4(argp, &fallocate->falloc_stateid);
192562306a36Sopenharmony_ci	if (status)
192662306a36Sopenharmony_ci		return status;
192762306a36Sopenharmony_ci	if (xdr_stream_decode_u64(argp->xdr, &fallocate->falloc_offset) < 0)
192862306a36Sopenharmony_ci		return nfserr_bad_xdr;
192962306a36Sopenharmony_ci	if (xdr_stream_decode_u64(argp->xdr, &fallocate->falloc_length) < 0)
193062306a36Sopenharmony_ci		return nfserr_bad_xdr;
193162306a36Sopenharmony_ci
193262306a36Sopenharmony_ci	return nfs_ok;
193362306a36Sopenharmony_ci}
193462306a36Sopenharmony_ci
193562306a36Sopenharmony_cistatic __be32 nfsd4_decode_nl4_server(struct nfsd4_compoundargs *argp,
193662306a36Sopenharmony_ci				      struct nl4_server *ns)
193762306a36Sopenharmony_ci{
193862306a36Sopenharmony_ci	struct nfs42_netaddr *naddr;
193962306a36Sopenharmony_ci	__be32 *p;
194062306a36Sopenharmony_ci
194162306a36Sopenharmony_ci	if (xdr_stream_decode_u32(argp->xdr, &ns->nl4_type) < 0)
194262306a36Sopenharmony_ci		return nfserr_bad_xdr;
194362306a36Sopenharmony_ci
194462306a36Sopenharmony_ci	/* currently support for 1 inter-server source server */
194562306a36Sopenharmony_ci	switch (ns->nl4_type) {
194662306a36Sopenharmony_ci	case NL4_NETADDR:
194762306a36Sopenharmony_ci		naddr = &ns->u.nl4_addr;
194862306a36Sopenharmony_ci
194962306a36Sopenharmony_ci		if (xdr_stream_decode_u32(argp->xdr, &naddr->netid_len) < 0)
195062306a36Sopenharmony_ci			return nfserr_bad_xdr;
195162306a36Sopenharmony_ci		if (naddr->netid_len > RPCBIND_MAXNETIDLEN)
195262306a36Sopenharmony_ci			return nfserr_bad_xdr;
195362306a36Sopenharmony_ci
195462306a36Sopenharmony_ci		p = xdr_inline_decode(argp->xdr, naddr->netid_len);
195562306a36Sopenharmony_ci		if (!p)
195662306a36Sopenharmony_ci			return nfserr_bad_xdr;
195762306a36Sopenharmony_ci		memcpy(naddr->netid, p, naddr->netid_len);
195862306a36Sopenharmony_ci
195962306a36Sopenharmony_ci		if (xdr_stream_decode_u32(argp->xdr, &naddr->addr_len) < 0)
196062306a36Sopenharmony_ci			return nfserr_bad_xdr;
196162306a36Sopenharmony_ci		if (naddr->addr_len > RPCBIND_MAXUADDRLEN)
196262306a36Sopenharmony_ci			return nfserr_bad_xdr;
196362306a36Sopenharmony_ci
196462306a36Sopenharmony_ci		p = xdr_inline_decode(argp->xdr, naddr->addr_len);
196562306a36Sopenharmony_ci		if (!p)
196662306a36Sopenharmony_ci			return nfserr_bad_xdr;
196762306a36Sopenharmony_ci		memcpy(naddr->addr, p, naddr->addr_len);
196862306a36Sopenharmony_ci		break;
196962306a36Sopenharmony_ci	default:
197062306a36Sopenharmony_ci		return nfserr_bad_xdr;
197162306a36Sopenharmony_ci	}
197262306a36Sopenharmony_ci
197362306a36Sopenharmony_ci	return nfs_ok;
197462306a36Sopenharmony_ci}
197562306a36Sopenharmony_ci
197662306a36Sopenharmony_cistatic __be32
197762306a36Sopenharmony_cinfsd4_decode_copy(struct nfsd4_compoundargs *argp, union nfsd4_op_u *u)
197862306a36Sopenharmony_ci{
197962306a36Sopenharmony_ci	struct nfsd4_copy *copy = &u->copy;
198062306a36Sopenharmony_ci	u32 consecutive, i, count, sync;
198162306a36Sopenharmony_ci	struct nl4_server *ns_dummy;
198262306a36Sopenharmony_ci	__be32 status;
198362306a36Sopenharmony_ci
198462306a36Sopenharmony_ci	memset(copy, 0, sizeof(*copy));
198562306a36Sopenharmony_ci	status = nfsd4_decode_stateid4(argp, &copy->cp_src_stateid);
198662306a36Sopenharmony_ci	if (status)
198762306a36Sopenharmony_ci		return status;
198862306a36Sopenharmony_ci	status = nfsd4_decode_stateid4(argp, &copy->cp_dst_stateid);
198962306a36Sopenharmony_ci	if (status)
199062306a36Sopenharmony_ci		return status;
199162306a36Sopenharmony_ci	if (xdr_stream_decode_u64(argp->xdr, &copy->cp_src_pos) < 0)
199262306a36Sopenharmony_ci		return nfserr_bad_xdr;
199362306a36Sopenharmony_ci	if (xdr_stream_decode_u64(argp->xdr, &copy->cp_dst_pos) < 0)
199462306a36Sopenharmony_ci		return nfserr_bad_xdr;
199562306a36Sopenharmony_ci	if (xdr_stream_decode_u64(argp->xdr, &copy->cp_count) < 0)
199662306a36Sopenharmony_ci		return nfserr_bad_xdr;
199762306a36Sopenharmony_ci	/* ca_consecutive: we always do consecutive copies */
199862306a36Sopenharmony_ci	if (xdr_stream_decode_u32(argp->xdr, &consecutive) < 0)
199962306a36Sopenharmony_ci		return nfserr_bad_xdr;
200062306a36Sopenharmony_ci	if (xdr_stream_decode_bool(argp->xdr, &sync) < 0)
200162306a36Sopenharmony_ci		return nfserr_bad_xdr;
200262306a36Sopenharmony_ci	nfsd4_copy_set_sync(copy, sync);
200362306a36Sopenharmony_ci
200462306a36Sopenharmony_ci	if (xdr_stream_decode_u32(argp->xdr, &count) < 0)
200562306a36Sopenharmony_ci		return nfserr_bad_xdr;
200662306a36Sopenharmony_ci	copy->cp_src = svcxdr_tmpalloc(argp, sizeof(*copy->cp_src));
200762306a36Sopenharmony_ci	if (copy->cp_src == NULL)
200862306a36Sopenharmony_ci		return nfserr_jukebox;
200962306a36Sopenharmony_ci	if (count == 0) { /* intra-server copy */
201062306a36Sopenharmony_ci		__set_bit(NFSD4_COPY_F_INTRA, &copy->cp_flags);
201162306a36Sopenharmony_ci		return nfs_ok;
201262306a36Sopenharmony_ci	}
201362306a36Sopenharmony_ci
201462306a36Sopenharmony_ci	/* decode all the supplied server addresses but use only the first */
201562306a36Sopenharmony_ci	status = nfsd4_decode_nl4_server(argp, copy->cp_src);
201662306a36Sopenharmony_ci	if (status)
201762306a36Sopenharmony_ci		return status;
201862306a36Sopenharmony_ci
201962306a36Sopenharmony_ci	ns_dummy = kmalloc(sizeof(struct nl4_server), GFP_KERNEL);
202062306a36Sopenharmony_ci	if (ns_dummy == NULL)
202162306a36Sopenharmony_ci		return nfserr_jukebox;
202262306a36Sopenharmony_ci	for (i = 0; i < count - 1; i++) {
202362306a36Sopenharmony_ci		status = nfsd4_decode_nl4_server(argp, ns_dummy);
202462306a36Sopenharmony_ci		if (status) {
202562306a36Sopenharmony_ci			kfree(ns_dummy);
202662306a36Sopenharmony_ci			return status;
202762306a36Sopenharmony_ci		}
202862306a36Sopenharmony_ci	}
202962306a36Sopenharmony_ci	kfree(ns_dummy);
203062306a36Sopenharmony_ci
203162306a36Sopenharmony_ci	return nfs_ok;
203262306a36Sopenharmony_ci}
203362306a36Sopenharmony_ci
203462306a36Sopenharmony_cistatic __be32
203562306a36Sopenharmony_cinfsd4_decode_copy_notify(struct nfsd4_compoundargs *argp,
203662306a36Sopenharmony_ci			 union nfsd4_op_u *u)
203762306a36Sopenharmony_ci{
203862306a36Sopenharmony_ci	struct nfsd4_copy_notify *cn = &u->copy_notify;
203962306a36Sopenharmony_ci	__be32 status;
204062306a36Sopenharmony_ci
204162306a36Sopenharmony_ci	memset(cn, 0, sizeof(*cn));
204262306a36Sopenharmony_ci	cn->cpn_src = svcxdr_tmpalloc(argp, sizeof(*cn->cpn_src));
204362306a36Sopenharmony_ci	if (cn->cpn_src == NULL)
204462306a36Sopenharmony_ci		return nfserr_jukebox;
204562306a36Sopenharmony_ci	cn->cpn_dst = svcxdr_tmpalloc(argp, sizeof(*cn->cpn_dst));
204662306a36Sopenharmony_ci	if (cn->cpn_dst == NULL)
204762306a36Sopenharmony_ci		return nfserr_jukebox;
204862306a36Sopenharmony_ci
204962306a36Sopenharmony_ci	status = nfsd4_decode_stateid4(argp, &cn->cpn_src_stateid);
205062306a36Sopenharmony_ci	if (status)
205162306a36Sopenharmony_ci		return status;
205262306a36Sopenharmony_ci	return nfsd4_decode_nl4_server(argp, cn->cpn_dst);
205362306a36Sopenharmony_ci}
205462306a36Sopenharmony_ci
205562306a36Sopenharmony_cistatic __be32
205662306a36Sopenharmony_cinfsd4_decode_offload_status(struct nfsd4_compoundargs *argp,
205762306a36Sopenharmony_ci			    union nfsd4_op_u *u)
205862306a36Sopenharmony_ci{
205962306a36Sopenharmony_ci	struct nfsd4_offload_status *os = &u->offload_status;
206062306a36Sopenharmony_ci	os->count = 0;
206162306a36Sopenharmony_ci	os->status = 0;
206262306a36Sopenharmony_ci	return nfsd4_decode_stateid4(argp, &os->stateid);
206362306a36Sopenharmony_ci}
206462306a36Sopenharmony_ci
206562306a36Sopenharmony_cistatic __be32
206662306a36Sopenharmony_cinfsd4_decode_seek(struct nfsd4_compoundargs *argp, union nfsd4_op_u *u)
206762306a36Sopenharmony_ci{
206862306a36Sopenharmony_ci	struct nfsd4_seek *seek = &u->seek;
206962306a36Sopenharmony_ci	__be32 status;
207062306a36Sopenharmony_ci
207162306a36Sopenharmony_ci	status = nfsd4_decode_stateid4(argp, &seek->seek_stateid);
207262306a36Sopenharmony_ci	if (status)
207362306a36Sopenharmony_ci		return status;
207462306a36Sopenharmony_ci	if (xdr_stream_decode_u64(argp->xdr, &seek->seek_offset) < 0)
207562306a36Sopenharmony_ci		return nfserr_bad_xdr;
207662306a36Sopenharmony_ci	if (xdr_stream_decode_u32(argp->xdr, &seek->seek_whence) < 0)
207762306a36Sopenharmony_ci		return nfserr_bad_xdr;
207862306a36Sopenharmony_ci
207962306a36Sopenharmony_ci	seek->seek_eof = 0;
208062306a36Sopenharmony_ci	seek->seek_pos = 0;
208162306a36Sopenharmony_ci	return nfs_ok;
208262306a36Sopenharmony_ci}
208362306a36Sopenharmony_ci
208462306a36Sopenharmony_cistatic __be32
208562306a36Sopenharmony_cinfsd4_decode_clone(struct nfsd4_compoundargs *argp, union nfsd4_op_u *u)
208662306a36Sopenharmony_ci{
208762306a36Sopenharmony_ci	struct nfsd4_clone *clone = &u->clone;
208862306a36Sopenharmony_ci	__be32 status;
208962306a36Sopenharmony_ci
209062306a36Sopenharmony_ci	status = nfsd4_decode_stateid4(argp, &clone->cl_src_stateid);
209162306a36Sopenharmony_ci	if (status)
209262306a36Sopenharmony_ci		return status;
209362306a36Sopenharmony_ci	status = nfsd4_decode_stateid4(argp, &clone->cl_dst_stateid);
209462306a36Sopenharmony_ci	if (status)
209562306a36Sopenharmony_ci		return status;
209662306a36Sopenharmony_ci	if (xdr_stream_decode_u64(argp->xdr, &clone->cl_src_pos) < 0)
209762306a36Sopenharmony_ci		return nfserr_bad_xdr;
209862306a36Sopenharmony_ci	if (xdr_stream_decode_u64(argp->xdr, &clone->cl_dst_pos) < 0)
209962306a36Sopenharmony_ci		return nfserr_bad_xdr;
210062306a36Sopenharmony_ci	if (xdr_stream_decode_u64(argp->xdr, &clone->cl_count) < 0)
210162306a36Sopenharmony_ci		return nfserr_bad_xdr;
210262306a36Sopenharmony_ci
210362306a36Sopenharmony_ci	return nfs_ok;
210462306a36Sopenharmony_ci}
210562306a36Sopenharmony_ci
210662306a36Sopenharmony_ci/*
210762306a36Sopenharmony_ci * XDR data that is more than PAGE_SIZE in size is normally part of a
210862306a36Sopenharmony_ci * read or write. However, the size of extended attributes is limited
210962306a36Sopenharmony_ci * by the maximum request size, and then further limited by the underlying
211062306a36Sopenharmony_ci * filesystem limits. This can exceed PAGE_SIZE (currently, XATTR_SIZE_MAX
211162306a36Sopenharmony_ci * is 64k). Since there is no kvec- or page-based interface to xattrs,
211262306a36Sopenharmony_ci * and we're not dealing with contiguous pages, we need to do some copying.
211362306a36Sopenharmony_ci */
211462306a36Sopenharmony_ci
211562306a36Sopenharmony_ci/*
211662306a36Sopenharmony_ci * Decode data into buffer.
211762306a36Sopenharmony_ci */
211862306a36Sopenharmony_cistatic __be32
211962306a36Sopenharmony_cinfsd4_vbuf_from_vector(struct nfsd4_compoundargs *argp, struct xdr_buf *xdr,
212062306a36Sopenharmony_ci		       char **bufp, u32 buflen)
212162306a36Sopenharmony_ci{
212262306a36Sopenharmony_ci	struct page **pages = xdr->pages;
212362306a36Sopenharmony_ci	struct kvec *head = xdr->head;
212462306a36Sopenharmony_ci	char *tmp, *dp;
212562306a36Sopenharmony_ci	u32 len;
212662306a36Sopenharmony_ci
212762306a36Sopenharmony_ci	if (buflen <= head->iov_len) {
212862306a36Sopenharmony_ci		/*
212962306a36Sopenharmony_ci		 * We're in luck, the head has enough space. Just return
213062306a36Sopenharmony_ci		 * the head, no need for copying.
213162306a36Sopenharmony_ci		 */
213262306a36Sopenharmony_ci		*bufp = head->iov_base;
213362306a36Sopenharmony_ci		return 0;
213462306a36Sopenharmony_ci	}
213562306a36Sopenharmony_ci
213662306a36Sopenharmony_ci	tmp = svcxdr_tmpalloc(argp, buflen);
213762306a36Sopenharmony_ci	if (tmp == NULL)
213862306a36Sopenharmony_ci		return nfserr_jukebox;
213962306a36Sopenharmony_ci
214062306a36Sopenharmony_ci	dp = tmp;
214162306a36Sopenharmony_ci	memcpy(dp, head->iov_base, head->iov_len);
214262306a36Sopenharmony_ci	buflen -= head->iov_len;
214362306a36Sopenharmony_ci	dp += head->iov_len;
214462306a36Sopenharmony_ci
214562306a36Sopenharmony_ci	while (buflen > 0) {
214662306a36Sopenharmony_ci		len = min_t(u32, buflen, PAGE_SIZE);
214762306a36Sopenharmony_ci		memcpy(dp, page_address(*pages), len);
214862306a36Sopenharmony_ci
214962306a36Sopenharmony_ci		buflen -= len;
215062306a36Sopenharmony_ci		dp += len;
215162306a36Sopenharmony_ci		pages++;
215262306a36Sopenharmony_ci	}
215362306a36Sopenharmony_ci
215462306a36Sopenharmony_ci	*bufp = tmp;
215562306a36Sopenharmony_ci	return 0;
215662306a36Sopenharmony_ci}
215762306a36Sopenharmony_ci
215862306a36Sopenharmony_ci/*
215962306a36Sopenharmony_ci * Get a user extended attribute name from the XDR buffer.
216062306a36Sopenharmony_ci * It will not have the "user." prefix, so prepend it.
216162306a36Sopenharmony_ci * Lastly, check for nul characters in the name.
216262306a36Sopenharmony_ci */
216362306a36Sopenharmony_cistatic __be32
216462306a36Sopenharmony_cinfsd4_decode_xattr_name(struct nfsd4_compoundargs *argp, char **namep)
216562306a36Sopenharmony_ci{
216662306a36Sopenharmony_ci	char *name, *sp, *dp;
216762306a36Sopenharmony_ci	u32 namelen, cnt;
216862306a36Sopenharmony_ci	__be32 *p;
216962306a36Sopenharmony_ci
217062306a36Sopenharmony_ci	if (xdr_stream_decode_u32(argp->xdr, &namelen) < 0)
217162306a36Sopenharmony_ci		return nfserr_bad_xdr;
217262306a36Sopenharmony_ci	if (namelen > (XATTR_NAME_MAX - XATTR_USER_PREFIX_LEN))
217362306a36Sopenharmony_ci		return nfserr_nametoolong;
217462306a36Sopenharmony_ci	if (namelen == 0)
217562306a36Sopenharmony_ci		return nfserr_bad_xdr;
217662306a36Sopenharmony_ci	p = xdr_inline_decode(argp->xdr, namelen);
217762306a36Sopenharmony_ci	if (!p)
217862306a36Sopenharmony_ci		return nfserr_bad_xdr;
217962306a36Sopenharmony_ci	name = svcxdr_tmpalloc(argp, namelen + XATTR_USER_PREFIX_LEN + 1);
218062306a36Sopenharmony_ci	if (!name)
218162306a36Sopenharmony_ci		return nfserr_jukebox;
218262306a36Sopenharmony_ci	memcpy(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN);
218362306a36Sopenharmony_ci
218462306a36Sopenharmony_ci	/*
218562306a36Sopenharmony_ci	 * Copy the extended attribute name over while checking for 0
218662306a36Sopenharmony_ci	 * characters.
218762306a36Sopenharmony_ci	 */
218862306a36Sopenharmony_ci	sp = (char *)p;
218962306a36Sopenharmony_ci	dp = name + XATTR_USER_PREFIX_LEN;
219062306a36Sopenharmony_ci	cnt = namelen;
219162306a36Sopenharmony_ci
219262306a36Sopenharmony_ci	while (cnt-- > 0) {
219362306a36Sopenharmony_ci		if (*sp == '\0')
219462306a36Sopenharmony_ci			return nfserr_bad_xdr;
219562306a36Sopenharmony_ci		*dp++ = *sp++;
219662306a36Sopenharmony_ci	}
219762306a36Sopenharmony_ci	*dp = '\0';
219862306a36Sopenharmony_ci
219962306a36Sopenharmony_ci	*namep = name;
220062306a36Sopenharmony_ci
220162306a36Sopenharmony_ci	return nfs_ok;
220262306a36Sopenharmony_ci}
220362306a36Sopenharmony_ci
220462306a36Sopenharmony_ci/*
220562306a36Sopenharmony_ci * A GETXATTR op request comes without a length specifier. We just set the
220662306a36Sopenharmony_ci * maximum length for the reply based on XATTR_SIZE_MAX and the maximum
220762306a36Sopenharmony_ci * channel reply size. nfsd_getxattr will probe the length of the xattr,
220862306a36Sopenharmony_ci * check it against getxa_len, and allocate + return the value.
220962306a36Sopenharmony_ci */
221062306a36Sopenharmony_cistatic __be32
221162306a36Sopenharmony_cinfsd4_decode_getxattr(struct nfsd4_compoundargs *argp,
221262306a36Sopenharmony_ci		      union nfsd4_op_u *u)
221362306a36Sopenharmony_ci{
221462306a36Sopenharmony_ci	struct nfsd4_getxattr *getxattr = &u->getxattr;
221562306a36Sopenharmony_ci	__be32 status;
221662306a36Sopenharmony_ci	u32 maxcount;
221762306a36Sopenharmony_ci
221862306a36Sopenharmony_ci	memset(getxattr, 0, sizeof(*getxattr));
221962306a36Sopenharmony_ci	status = nfsd4_decode_xattr_name(argp, &getxattr->getxa_name);
222062306a36Sopenharmony_ci	if (status)
222162306a36Sopenharmony_ci		return status;
222262306a36Sopenharmony_ci
222362306a36Sopenharmony_ci	maxcount = svc_max_payload(argp->rqstp);
222462306a36Sopenharmony_ci	maxcount = min_t(u32, XATTR_SIZE_MAX, maxcount);
222562306a36Sopenharmony_ci
222662306a36Sopenharmony_ci	getxattr->getxa_len = maxcount;
222762306a36Sopenharmony_ci	return nfs_ok;
222862306a36Sopenharmony_ci}
222962306a36Sopenharmony_ci
223062306a36Sopenharmony_cistatic __be32
223162306a36Sopenharmony_cinfsd4_decode_setxattr(struct nfsd4_compoundargs *argp,
223262306a36Sopenharmony_ci		      union nfsd4_op_u *u)
223362306a36Sopenharmony_ci{
223462306a36Sopenharmony_ci	struct nfsd4_setxattr *setxattr = &u->setxattr;
223562306a36Sopenharmony_ci	u32 flags, maxcount, size;
223662306a36Sopenharmony_ci	__be32 status;
223762306a36Sopenharmony_ci
223862306a36Sopenharmony_ci	memset(setxattr, 0, sizeof(*setxattr));
223962306a36Sopenharmony_ci
224062306a36Sopenharmony_ci	if (xdr_stream_decode_u32(argp->xdr, &flags) < 0)
224162306a36Sopenharmony_ci		return nfserr_bad_xdr;
224262306a36Sopenharmony_ci
224362306a36Sopenharmony_ci	if (flags > SETXATTR4_REPLACE)
224462306a36Sopenharmony_ci		return nfserr_inval;
224562306a36Sopenharmony_ci	setxattr->setxa_flags = flags;
224662306a36Sopenharmony_ci
224762306a36Sopenharmony_ci	status = nfsd4_decode_xattr_name(argp, &setxattr->setxa_name);
224862306a36Sopenharmony_ci	if (status)
224962306a36Sopenharmony_ci		return status;
225062306a36Sopenharmony_ci
225162306a36Sopenharmony_ci	maxcount = svc_max_payload(argp->rqstp);
225262306a36Sopenharmony_ci	maxcount = min_t(u32, XATTR_SIZE_MAX, maxcount);
225362306a36Sopenharmony_ci
225462306a36Sopenharmony_ci	if (xdr_stream_decode_u32(argp->xdr, &size) < 0)
225562306a36Sopenharmony_ci		return nfserr_bad_xdr;
225662306a36Sopenharmony_ci	if (size > maxcount)
225762306a36Sopenharmony_ci		return nfserr_xattr2big;
225862306a36Sopenharmony_ci
225962306a36Sopenharmony_ci	setxattr->setxa_len = size;
226062306a36Sopenharmony_ci	if (size > 0) {
226162306a36Sopenharmony_ci		struct xdr_buf payload;
226262306a36Sopenharmony_ci
226362306a36Sopenharmony_ci		if (!xdr_stream_subsegment(argp->xdr, &payload, size))
226462306a36Sopenharmony_ci			return nfserr_bad_xdr;
226562306a36Sopenharmony_ci		status = nfsd4_vbuf_from_vector(argp, &payload,
226662306a36Sopenharmony_ci						&setxattr->setxa_buf, size);
226762306a36Sopenharmony_ci	}
226862306a36Sopenharmony_ci
226962306a36Sopenharmony_ci	return nfs_ok;
227062306a36Sopenharmony_ci}
227162306a36Sopenharmony_ci
227262306a36Sopenharmony_cistatic __be32
227362306a36Sopenharmony_cinfsd4_decode_listxattrs(struct nfsd4_compoundargs *argp,
227462306a36Sopenharmony_ci			union nfsd4_op_u *u)
227562306a36Sopenharmony_ci{
227662306a36Sopenharmony_ci	struct nfsd4_listxattrs *listxattrs = &u->listxattrs;
227762306a36Sopenharmony_ci	u32 maxcount;
227862306a36Sopenharmony_ci
227962306a36Sopenharmony_ci	memset(listxattrs, 0, sizeof(*listxattrs));
228062306a36Sopenharmony_ci
228162306a36Sopenharmony_ci	if (xdr_stream_decode_u64(argp->xdr, &listxattrs->lsxa_cookie) < 0)
228262306a36Sopenharmony_ci		return nfserr_bad_xdr;
228362306a36Sopenharmony_ci
228462306a36Sopenharmony_ci	/*
228562306a36Sopenharmony_ci	 * If the cookie  is too large to have even one user.x attribute
228662306a36Sopenharmony_ci	 * plus trailing '\0' left in a maximum size buffer, it's invalid.
228762306a36Sopenharmony_ci	 */
228862306a36Sopenharmony_ci	if (listxattrs->lsxa_cookie >=
228962306a36Sopenharmony_ci	    (XATTR_LIST_MAX / (XATTR_USER_PREFIX_LEN + 2)))
229062306a36Sopenharmony_ci		return nfserr_badcookie;
229162306a36Sopenharmony_ci
229262306a36Sopenharmony_ci	if (xdr_stream_decode_u32(argp->xdr, &maxcount) < 0)
229362306a36Sopenharmony_ci		return nfserr_bad_xdr;
229462306a36Sopenharmony_ci	if (maxcount < 8)
229562306a36Sopenharmony_ci		/* Always need at least 2 words (length and one character) */
229662306a36Sopenharmony_ci		return nfserr_inval;
229762306a36Sopenharmony_ci
229862306a36Sopenharmony_ci	maxcount = min(maxcount, svc_max_payload(argp->rqstp));
229962306a36Sopenharmony_ci	listxattrs->lsxa_maxcount = maxcount;
230062306a36Sopenharmony_ci
230162306a36Sopenharmony_ci	return nfs_ok;
230262306a36Sopenharmony_ci}
230362306a36Sopenharmony_ci
230462306a36Sopenharmony_cistatic __be32
230562306a36Sopenharmony_cinfsd4_decode_removexattr(struct nfsd4_compoundargs *argp,
230662306a36Sopenharmony_ci			 union nfsd4_op_u *u)
230762306a36Sopenharmony_ci{
230862306a36Sopenharmony_ci	struct nfsd4_removexattr *removexattr = &u->removexattr;
230962306a36Sopenharmony_ci	memset(removexattr, 0, sizeof(*removexattr));
231062306a36Sopenharmony_ci	return nfsd4_decode_xattr_name(argp, &removexattr->rmxa_name);
231162306a36Sopenharmony_ci}
231262306a36Sopenharmony_ci
231362306a36Sopenharmony_cistatic __be32
231462306a36Sopenharmony_cinfsd4_decode_noop(struct nfsd4_compoundargs *argp, union nfsd4_op_u *p)
231562306a36Sopenharmony_ci{
231662306a36Sopenharmony_ci	return nfs_ok;
231762306a36Sopenharmony_ci}
231862306a36Sopenharmony_ci
231962306a36Sopenharmony_cistatic __be32
232062306a36Sopenharmony_cinfsd4_decode_notsupp(struct nfsd4_compoundargs *argp, union nfsd4_op_u *p)
232162306a36Sopenharmony_ci{
232262306a36Sopenharmony_ci	return nfserr_notsupp;
232362306a36Sopenharmony_ci}
232462306a36Sopenharmony_ci
232562306a36Sopenharmony_citypedef __be32(*nfsd4_dec)(struct nfsd4_compoundargs *argp, union nfsd4_op_u *u);
232662306a36Sopenharmony_ci
232762306a36Sopenharmony_cistatic const nfsd4_dec nfsd4_dec_ops[] = {
232862306a36Sopenharmony_ci	[OP_ACCESS]		= nfsd4_decode_access,
232962306a36Sopenharmony_ci	[OP_CLOSE]		= nfsd4_decode_close,
233062306a36Sopenharmony_ci	[OP_COMMIT]		= nfsd4_decode_commit,
233162306a36Sopenharmony_ci	[OP_CREATE]		= nfsd4_decode_create,
233262306a36Sopenharmony_ci	[OP_DELEGPURGE]		= nfsd4_decode_notsupp,
233362306a36Sopenharmony_ci	[OP_DELEGRETURN]	= nfsd4_decode_delegreturn,
233462306a36Sopenharmony_ci	[OP_GETATTR]		= nfsd4_decode_getattr,
233562306a36Sopenharmony_ci	[OP_GETFH]		= nfsd4_decode_noop,
233662306a36Sopenharmony_ci	[OP_LINK]		= nfsd4_decode_link,
233762306a36Sopenharmony_ci	[OP_LOCK]		= nfsd4_decode_lock,
233862306a36Sopenharmony_ci	[OP_LOCKT]		= nfsd4_decode_lockt,
233962306a36Sopenharmony_ci	[OP_LOCKU]		= nfsd4_decode_locku,
234062306a36Sopenharmony_ci	[OP_LOOKUP]		= nfsd4_decode_lookup,
234162306a36Sopenharmony_ci	[OP_LOOKUPP]		= nfsd4_decode_noop,
234262306a36Sopenharmony_ci	[OP_NVERIFY]		= nfsd4_decode_verify,
234362306a36Sopenharmony_ci	[OP_OPEN]		= nfsd4_decode_open,
234462306a36Sopenharmony_ci	[OP_OPENATTR]		= nfsd4_decode_notsupp,
234562306a36Sopenharmony_ci	[OP_OPEN_CONFIRM]	= nfsd4_decode_open_confirm,
234662306a36Sopenharmony_ci	[OP_OPEN_DOWNGRADE]	= nfsd4_decode_open_downgrade,
234762306a36Sopenharmony_ci	[OP_PUTFH]		= nfsd4_decode_putfh,
234862306a36Sopenharmony_ci	[OP_PUTPUBFH]		= nfsd4_decode_putpubfh,
234962306a36Sopenharmony_ci	[OP_PUTROOTFH]		= nfsd4_decode_noop,
235062306a36Sopenharmony_ci	[OP_READ]		= nfsd4_decode_read,
235162306a36Sopenharmony_ci	[OP_READDIR]		= nfsd4_decode_readdir,
235262306a36Sopenharmony_ci	[OP_READLINK]		= nfsd4_decode_noop,
235362306a36Sopenharmony_ci	[OP_REMOVE]		= nfsd4_decode_remove,
235462306a36Sopenharmony_ci	[OP_RENAME]		= nfsd4_decode_rename,
235562306a36Sopenharmony_ci	[OP_RENEW]		= nfsd4_decode_renew,
235662306a36Sopenharmony_ci	[OP_RESTOREFH]		= nfsd4_decode_noop,
235762306a36Sopenharmony_ci	[OP_SAVEFH]		= nfsd4_decode_noop,
235862306a36Sopenharmony_ci	[OP_SECINFO]		= nfsd4_decode_secinfo,
235962306a36Sopenharmony_ci	[OP_SETATTR]		= nfsd4_decode_setattr,
236062306a36Sopenharmony_ci	[OP_SETCLIENTID]	= nfsd4_decode_setclientid,
236162306a36Sopenharmony_ci	[OP_SETCLIENTID_CONFIRM] = nfsd4_decode_setclientid_confirm,
236262306a36Sopenharmony_ci	[OP_VERIFY]		= nfsd4_decode_verify,
236362306a36Sopenharmony_ci	[OP_WRITE]		= nfsd4_decode_write,
236462306a36Sopenharmony_ci	[OP_RELEASE_LOCKOWNER]	= nfsd4_decode_release_lockowner,
236562306a36Sopenharmony_ci
236662306a36Sopenharmony_ci	/* new operations for NFSv4.1 */
236762306a36Sopenharmony_ci	[OP_BACKCHANNEL_CTL]	= nfsd4_decode_backchannel_ctl,
236862306a36Sopenharmony_ci	[OP_BIND_CONN_TO_SESSION] = nfsd4_decode_bind_conn_to_session,
236962306a36Sopenharmony_ci	[OP_EXCHANGE_ID]	= nfsd4_decode_exchange_id,
237062306a36Sopenharmony_ci	[OP_CREATE_SESSION]	= nfsd4_decode_create_session,
237162306a36Sopenharmony_ci	[OP_DESTROY_SESSION]	= nfsd4_decode_destroy_session,
237262306a36Sopenharmony_ci	[OP_FREE_STATEID]	= nfsd4_decode_free_stateid,
237362306a36Sopenharmony_ci	[OP_GET_DIR_DELEGATION]	= nfsd4_decode_notsupp,
237462306a36Sopenharmony_ci#ifdef CONFIG_NFSD_PNFS
237562306a36Sopenharmony_ci	[OP_GETDEVICEINFO]	= nfsd4_decode_getdeviceinfo,
237662306a36Sopenharmony_ci	[OP_GETDEVICELIST]	= nfsd4_decode_notsupp,
237762306a36Sopenharmony_ci	[OP_LAYOUTCOMMIT]	= nfsd4_decode_layoutcommit,
237862306a36Sopenharmony_ci	[OP_LAYOUTGET]		= nfsd4_decode_layoutget,
237962306a36Sopenharmony_ci	[OP_LAYOUTRETURN]	= nfsd4_decode_layoutreturn,
238062306a36Sopenharmony_ci#else
238162306a36Sopenharmony_ci	[OP_GETDEVICEINFO]	= nfsd4_decode_notsupp,
238262306a36Sopenharmony_ci	[OP_GETDEVICELIST]	= nfsd4_decode_notsupp,
238362306a36Sopenharmony_ci	[OP_LAYOUTCOMMIT]	= nfsd4_decode_notsupp,
238462306a36Sopenharmony_ci	[OP_LAYOUTGET]		= nfsd4_decode_notsupp,
238562306a36Sopenharmony_ci	[OP_LAYOUTRETURN]	= nfsd4_decode_notsupp,
238662306a36Sopenharmony_ci#endif
238762306a36Sopenharmony_ci	[OP_SECINFO_NO_NAME]	= nfsd4_decode_secinfo_no_name,
238862306a36Sopenharmony_ci	[OP_SEQUENCE]		= nfsd4_decode_sequence,
238962306a36Sopenharmony_ci	[OP_SET_SSV]		= nfsd4_decode_notsupp,
239062306a36Sopenharmony_ci	[OP_TEST_STATEID]	= nfsd4_decode_test_stateid,
239162306a36Sopenharmony_ci	[OP_WANT_DELEGATION]	= nfsd4_decode_notsupp,
239262306a36Sopenharmony_ci	[OP_DESTROY_CLIENTID]	= nfsd4_decode_destroy_clientid,
239362306a36Sopenharmony_ci	[OP_RECLAIM_COMPLETE]	= nfsd4_decode_reclaim_complete,
239462306a36Sopenharmony_ci
239562306a36Sopenharmony_ci	/* new operations for NFSv4.2 */
239662306a36Sopenharmony_ci	[OP_ALLOCATE]		= nfsd4_decode_fallocate,
239762306a36Sopenharmony_ci	[OP_COPY]		= nfsd4_decode_copy,
239862306a36Sopenharmony_ci	[OP_COPY_NOTIFY]	= nfsd4_decode_copy_notify,
239962306a36Sopenharmony_ci	[OP_DEALLOCATE]		= nfsd4_decode_fallocate,
240062306a36Sopenharmony_ci	[OP_IO_ADVISE]		= nfsd4_decode_notsupp,
240162306a36Sopenharmony_ci	[OP_LAYOUTERROR]	= nfsd4_decode_notsupp,
240262306a36Sopenharmony_ci	[OP_LAYOUTSTATS]	= nfsd4_decode_notsupp,
240362306a36Sopenharmony_ci	[OP_OFFLOAD_CANCEL]	= nfsd4_decode_offload_status,
240462306a36Sopenharmony_ci	[OP_OFFLOAD_STATUS]	= nfsd4_decode_offload_status,
240562306a36Sopenharmony_ci	[OP_READ_PLUS]		= nfsd4_decode_read,
240662306a36Sopenharmony_ci	[OP_SEEK]		= nfsd4_decode_seek,
240762306a36Sopenharmony_ci	[OP_WRITE_SAME]		= nfsd4_decode_notsupp,
240862306a36Sopenharmony_ci	[OP_CLONE]		= nfsd4_decode_clone,
240962306a36Sopenharmony_ci	/* RFC 8276 extended atributes operations */
241062306a36Sopenharmony_ci	[OP_GETXATTR]		= nfsd4_decode_getxattr,
241162306a36Sopenharmony_ci	[OP_SETXATTR]		= nfsd4_decode_setxattr,
241262306a36Sopenharmony_ci	[OP_LISTXATTRS]		= nfsd4_decode_listxattrs,
241362306a36Sopenharmony_ci	[OP_REMOVEXATTR]	= nfsd4_decode_removexattr,
241462306a36Sopenharmony_ci};
241562306a36Sopenharmony_ci
241662306a36Sopenharmony_cistatic inline bool
241762306a36Sopenharmony_cinfsd4_opnum_in_range(struct nfsd4_compoundargs *argp, struct nfsd4_op *op)
241862306a36Sopenharmony_ci{
241962306a36Sopenharmony_ci	if (op->opnum < FIRST_NFS4_OP)
242062306a36Sopenharmony_ci		return false;
242162306a36Sopenharmony_ci	else if (argp->minorversion == 0 && op->opnum > LAST_NFS40_OP)
242262306a36Sopenharmony_ci		return false;
242362306a36Sopenharmony_ci	else if (argp->minorversion == 1 && op->opnum > LAST_NFS41_OP)
242462306a36Sopenharmony_ci		return false;
242562306a36Sopenharmony_ci	else if (argp->minorversion == 2 && op->opnum > LAST_NFS42_OP)
242662306a36Sopenharmony_ci		return false;
242762306a36Sopenharmony_ci	return true;
242862306a36Sopenharmony_ci}
242962306a36Sopenharmony_ci
243062306a36Sopenharmony_cistatic bool
243162306a36Sopenharmony_cinfsd4_decode_compound(struct nfsd4_compoundargs *argp)
243262306a36Sopenharmony_ci{
243362306a36Sopenharmony_ci	struct nfsd4_op *op;
243462306a36Sopenharmony_ci	bool cachethis = false;
243562306a36Sopenharmony_ci	int auth_slack= argp->rqstp->rq_auth_slack;
243662306a36Sopenharmony_ci	int max_reply = auth_slack + 8; /* opcnt, status */
243762306a36Sopenharmony_ci	int readcount = 0;
243862306a36Sopenharmony_ci	int readbytes = 0;
243962306a36Sopenharmony_ci	__be32 *p;
244062306a36Sopenharmony_ci	int i;
244162306a36Sopenharmony_ci
244262306a36Sopenharmony_ci	if (xdr_stream_decode_u32(argp->xdr, &argp->taglen) < 0)
244362306a36Sopenharmony_ci		return false;
244462306a36Sopenharmony_ci	max_reply += XDR_UNIT;
244562306a36Sopenharmony_ci	argp->tag = NULL;
244662306a36Sopenharmony_ci	if (unlikely(argp->taglen)) {
244762306a36Sopenharmony_ci		if (argp->taglen > NFSD4_MAX_TAGLEN)
244862306a36Sopenharmony_ci			return false;
244962306a36Sopenharmony_ci		p = xdr_inline_decode(argp->xdr, argp->taglen);
245062306a36Sopenharmony_ci		if (!p)
245162306a36Sopenharmony_ci			return false;
245262306a36Sopenharmony_ci		argp->tag = svcxdr_savemem(argp, p, argp->taglen);
245362306a36Sopenharmony_ci		if (!argp->tag)
245462306a36Sopenharmony_ci			return false;
245562306a36Sopenharmony_ci		max_reply += xdr_align_size(argp->taglen);
245662306a36Sopenharmony_ci	}
245762306a36Sopenharmony_ci
245862306a36Sopenharmony_ci	if (xdr_stream_decode_u32(argp->xdr, &argp->minorversion) < 0)
245962306a36Sopenharmony_ci		return false;
246062306a36Sopenharmony_ci	if (xdr_stream_decode_u32(argp->xdr, &argp->client_opcnt) < 0)
246162306a36Sopenharmony_ci		return false;
246262306a36Sopenharmony_ci	argp->opcnt = min_t(u32, argp->client_opcnt,
246362306a36Sopenharmony_ci			    NFSD_MAX_OPS_PER_COMPOUND);
246462306a36Sopenharmony_ci
246562306a36Sopenharmony_ci	if (argp->opcnt > ARRAY_SIZE(argp->iops)) {
246662306a36Sopenharmony_ci		argp->ops = vcalloc(argp->opcnt, sizeof(*argp->ops));
246762306a36Sopenharmony_ci		if (!argp->ops) {
246862306a36Sopenharmony_ci			argp->ops = argp->iops;
246962306a36Sopenharmony_ci			return false;
247062306a36Sopenharmony_ci		}
247162306a36Sopenharmony_ci	}
247262306a36Sopenharmony_ci
247362306a36Sopenharmony_ci	if (argp->minorversion > NFSD_SUPPORTED_MINOR_VERSION)
247462306a36Sopenharmony_ci		argp->opcnt = 0;
247562306a36Sopenharmony_ci
247662306a36Sopenharmony_ci	for (i = 0; i < argp->opcnt; i++) {
247762306a36Sopenharmony_ci		op = &argp->ops[i];
247862306a36Sopenharmony_ci		op->replay = NULL;
247962306a36Sopenharmony_ci		op->opdesc = NULL;
248062306a36Sopenharmony_ci
248162306a36Sopenharmony_ci		if (xdr_stream_decode_u32(argp->xdr, &op->opnum) < 0)
248262306a36Sopenharmony_ci			return false;
248362306a36Sopenharmony_ci		if (nfsd4_opnum_in_range(argp, op)) {
248462306a36Sopenharmony_ci			op->opdesc = OPDESC(op);
248562306a36Sopenharmony_ci			op->status = nfsd4_dec_ops[op->opnum](argp, &op->u);
248662306a36Sopenharmony_ci			if (op->status != nfs_ok)
248762306a36Sopenharmony_ci				trace_nfsd_compound_decode_err(argp->rqstp,
248862306a36Sopenharmony_ci							       argp->opcnt, i,
248962306a36Sopenharmony_ci							       op->opnum,
249062306a36Sopenharmony_ci							       op->status);
249162306a36Sopenharmony_ci		} else {
249262306a36Sopenharmony_ci			op->opnum = OP_ILLEGAL;
249362306a36Sopenharmony_ci			op->status = nfserr_op_illegal;
249462306a36Sopenharmony_ci		}
249562306a36Sopenharmony_ci
249662306a36Sopenharmony_ci		/*
249762306a36Sopenharmony_ci		 * We'll try to cache the result in the DRC if any one
249862306a36Sopenharmony_ci		 * op in the compound wants to be cached:
249962306a36Sopenharmony_ci		 */
250062306a36Sopenharmony_ci		cachethis |= nfsd4_cache_this_op(op);
250162306a36Sopenharmony_ci
250262306a36Sopenharmony_ci		if (op->opnum == OP_READ || op->opnum == OP_READ_PLUS) {
250362306a36Sopenharmony_ci			readcount++;
250462306a36Sopenharmony_ci			readbytes += nfsd4_max_reply(argp->rqstp, op);
250562306a36Sopenharmony_ci		} else
250662306a36Sopenharmony_ci			max_reply += nfsd4_max_reply(argp->rqstp, op);
250762306a36Sopenharmony_ci		/*
250862306a36Sopenharmony_ci		 * OP_LOCK and OP_LOCKT may return a conflicting lock.
250962306a36Sopenharmony_ci		 * (Special case because it will just skip encoding this
251062306a36Sopenharmony_ci		 * if it runs out of xdr buffer space, and it is the only
251162306a36Sopenharmony_ci		 * operation that behaves this way.)
251262306a36Sopenharmony_ci		 */
251362306a36Sopenharmony_ci		if (op->opnum == OP_LOCK || op->opnum == OP_LOCKT)
251462306a36Sopenharmony_ci			max_reply += NFS4_OPAQUE_LIMIT;
251562306a36Sopenharmony_ci
251662306a36Sopenharmony_ci		if (op->status) {
251762306a36Sopenharmony_ci			argp->opcnt = i+1;
251862306a36Sopenharmony_ci			break;
251962306a36Sopenharmony_ci		}
252062306a36Sopenharmony_ci	}
252162306a36Sopenharmony_ci	/* Sessions make the DRC unnecessary: */
252262306a36Sopenharmony_ci	if (argp->minorversion)
252362306a36Sopenharmony_ci		cachethis = false;
252462306a36Sopenharmony_ci	svc_reserve(argp->rqstp, max_reply + readbytes);
252562306a36Sopenharmony_ci	argp->rqstp->rq_cachetype = cachethis ? RC_REPLBUFF : RC_NOCACHE;
252662306a36Sopenharmony_ci
252762306a36Sopenharmony_ci	if (readcount > 1 || max_reply > PAGE_SIZE - auth_slack)
252862306a36Sopenharmony_ci		clear_bit(RQ_SPLICE_OK, &argp->rqstp->rq_flags);
252962306a36Sopenharmony_ci
253062306a36Sopenharmony_ci	return true;
253162306a36Sopenharmony_ci}
253262306a36Sopenharmony_ci
253362306a36Sopenharmony_cistatic __be32 *encode_change(__be32 *p, struct kstat *stat, struct inode *inode,
253462306a36Sopenharmony_ci			     struct svc_export *exp)
253562306a36Sopenharmony_ci{
253662306a36Sopenharmony_ci	if (exp->ex_flags & NFSEXP_V4ROOT) {
253762306a36Sopenharmony_ci		*p++ = cpu_to_be32(convert_to_wallclock(exp->cd->flush_time));
253862306a36Sopenharmony_ci		*p++ = 0;
253962306a36Sopenharmony_ci	} else
254062306a36Sopenharmony_ci		p = xdr_encode_hyper(p, nfsd4_change_attribute(stat, inode));
254162306a36Sopenharmony_ci	return p;
254262306a36Sopenharmony_ci}
254362306a36Sopenharmony_ci
254462306a36Sopenharmony_cistatic __be32 nfsd4_encode_nfstime4(struct xdr_stream *xdr,
254562306a36Sopenharmony_ci				    struct timespec64 *tv)
254662306a36Sopenharmony_ci{
254762306a36Sopenharmony_ci	__be32 *p;
254862306a36Sopenharmony_ci
254962306a36Sopenharmony_ci	p = xdr_reserve_space(xdr, XDR_UNIT * 3);
255062306a36Sopenharmony_ci	if (!p)
255162306a36Sopenharmony_ci		return nfserr_resource;
255262306a36Sopenharmony_ci
255362306a36Sopenharmony_ci	p = xdr_encode_hyper(p, (s64)tv->tv_sec);
255462306a36Sopenharmony_ci	*p = cpu_to_be32(tv->tv_nsec);
255562306a36Sopenharmony_ci	return nfs_ok;
255662306a36Sopenharmony_ci}
255762306a36Sopenharmony_ci
255862306a36Sopenharmony_ci/*
255962306a36Sopenharmony_ci * ctime (in NFSv4, time_metadata) is not writeable, and the client
256062306a36Sopenharmony_ci * doesn't really care what resolution could theoretically be stored by
256162306a36Sopenharmony_ci * the filesystem.
256262306a36Sopenharmony_ci *
256362306a36Sopenharmony_ci * The client cares how close together changes can be while still
256462306a36Sopenharmony_ci * guaranteeing ctime changes.  For most filesystems (which have
256562306a36Sopenharmony_ci * timestamps with nanosecond fields) that is limited by the resolution
256662306a36Sopenharmony_ci * of the time returned from current_time() (which I'm assuming to be
256762306a36Sopenharmony_ci * 1/HZ).
256862306a36Sopenharmony_ci */
256962306a36Sopenharmony_cistatic __be32 *encode_time_delta(__be32 *p, struct inode *inode)
257062306a36Sopenharmony_ci{
257162306a36Sopenharmony_ci	struct timespec64 ts;
257262306a36Sopenharmony_ci	u32 ns;
257362306a36Sopenharmony_ci
257462306a36Sopenharmony_ci	ns = max_t(u32, NSEC_PER_SEC/HZ, inode->i_sb->s_time_gran);
257562306a36Sopenharmony_ci	ts = ns_to_timespec64(ns);
257662306a36Sopenharmony_ci
257762306a36Sopenharmony_ci	p = xdr_encode_hyper(p, ts.tv_sec);
257862306a36Sopenharmony_ci	*p++ = cpu_to_be32(ts.tv_nsec);
257962306a36Sopenharmony_ci
258062306a36Sopenharmony_ci	return p;
258162306a36Sopenharmony_ci}
258262306a36Sopenharmony_ci
258362306a36Sopenharmony_cistatic __be32
258462306a36Sopenharmony_cinfsd4_encode_change_info4(struct xdr_stream *xdr, struct nfsd4_change_info *c)
258562306a36Sopenharmony_ci{
258662306a36Sopenharmony_ci	if (xdr_stream_encode_bool(xdr, c->atomic) < 0)
258762306a36Sopenharmony_ci		return nfserr_resource;
258862306a36Sopenharmony_ci	if (xdr_stream_encode_u64(xdr, c->before_change) < 0)
258962306a36Sopenharmony_ci		return nfserr_resource;
259062306a36Sopenharmony_ci	if (xdr_stream_encode_u64(xdr, c->after_change) < 0)
259162306a36Sopenharmony_ci		return nfserr_resource;
259262306a36Sopenharmony_ci	return nfs_ok;
259362306a36Sopenharmony_ci}
259462306a36Sopenharmony_ci
259562306a36Sopenharmony_ci/* Encode as an array of strings the string given with components
259662306a36Sopenharmony_ci * separated @sep, escaped with esc_enter and esc_exit.
259762306a36Sopenharmony_ci */
259862306a36Sopenharmony_cistatic __be32 nfsd4_encode_components_esc(struct xdr_stream *xdr, char sep,
259962306a36Sopenharmony_ci					  char *components, char esc_enter,
260062306a36Sopenharmony_ci					  char esc_exit)
260162306a36Sopenharmony_ci{
260262306a36Sopenharmony_ci	__be32 *p;
260362306a36Sopenharmony_ci	__be32 pathlen;
260462306a36Sopenharmony_ci	int pathlen_offset;
260562306a36Sopenharmony_ci	int strlen, count=0;
260662306a36Sopenharmony_ci	char *str, *end, *next;
260762306a36Sopenharmony_ci
260862306a36Sopenharmony_ci	dprintk("nfsd4_encode_components(%s)\n", components);
260962306a36Sopenharmony_ci
261062306a36Sopenharmony_ci	pathlen_offset = xdr->buf->len;
261162306a36Sopenharmony_ci	p = xdr_reserve_space(xdr, 4);
261262306a36Sopenharmony_ci	if (!p)
261362306a36Sopenharmony_ci		return nfserr_resource;
261462306a36Sopenharmony_ci	p++; /* We will fill this in with @count later */
261562306a36Sopenharmony_ci
261662306a36Sopenharmony_ci	end = str = components;
261762306a36Sopenharmony_ci	while (*end) {
261862306a36Sopenharmony_ci		bool found_esc = false;
261962306a36Sopenharmony_ci
262062306a36Sopenharmony_ci		/* try to parse as esc_start, ..., esc_end, sep */
262162306a36Sopenharmony_ci		if (*str == esc_enter) {
262262306a36Sopenharmony_ci			for (; *end && (*end != esc_exit); end++)
262362306a36Sopenharmony_ci				/* find esc_exit or end of string */;
262462306a36Sopenharmony_ci			next = end + 1;
262562306a36Sopenharmony_ci			if (*end && (!*next || *next == sep)) {
262662306a36Sopenharmony_ci				str++;
262762306a36Sopenharmony_ci				found_esc = true;
262862306a36Sopenharmony_ci			}
262962306a36Sopenharmony_ci		}
263062306a36Sopenharmony_ci
263162306a36Sopenharmony_ci		if (!found_esc)
263262306a36Sopenharmony_ci			for (; *end && (*end != sep); end++)
263362306a36Sopenharmony_ci				/* find sep or end of string */;
263462306a36Sopenharmony_ci
263562306a36Sopenharmony_ci		strlen = end - str;
263662306a36Sopenharmony_ci		if (strlen) {
263762306a36Sopenharmony_ci			p = xdr_reserve_space(xdr, strlen + 4);
263862306a36Sopenharmony_ci			if (!p)
263962306a36Sopenharmony_ci				return nfserr_resource;
264062306a36Sopenharmony_ci			p = xdr_encode_opaque(p, str, strlen);
264162306a36Sopenharmony_ci			count++;
264262306a36Sopenharmony_ci		}
264362306a36Sopenharmony_ci		else
264462306a36Sopenharmony_ci			end++;
264562306a36Sopenharmony_ci		if (found_esc)
264662306a36Sopenharmony_ci			end = next;
264762306a36Sopenharmony_ci
264862306a36Sopenharmony_ci		str = end;
264962306a36Sopenharmony_ci	}
265062306a36Sopenharmony_ci	pathlen = htonl(count);
265162306a36Sopenharmony_ci	write_bytes_to_xdr_buf(xdr->buf, pathlen_offset, &pathlen, 4);
265262306a36Sopenharmony_ci	return 0;
265362306a36Sopenharmony_ci}
265462306a36Sopenharmony_ci
265562306a36Sopenharmony_ci/* Encode as an array of strings the string given with components
265662306a36Sopenharmony_ci * separated @sep.
265762306a36Sopenharmony_ci */
265862306a36Sopenharmony_cistatic __be32 nfsd4_encode_components(struct xdr_stream *xdr, char sep,
265962306a36Sopenharmony_ci				      char *components)
266062306a36Sopenharmony_ci{
266162306a36Sopenharmony_ci	return nfsd4_encode_components_esc(xdr, sep, components, 0, 0);
266262306a36Sopenharmony_ci}
266362306a36Sopenharmony_ci
266462306a36Sopenharmony_ci/*
266562306a36Sopenharmony_ci * encode a location element of a fs_locations structure
266662306a36Sopenharmony_ci */
266762306a36Sopenharmony_cistatic __be32 nfsd4_encode_fs_location4(struct xdr_stream *xdr,
266862306a36Sopenharmony_ci					struct nfsd4_fs_location *location)
266962306a36Sopenharmony_ci{
267062306a36Sopenharmony_ci	__be32 status;
267162306a36Sopenharmony_ci
267262306a36Sopenharmony_ci	status = nfsd4_encode_components_esc(xdr, ':', location->hosts,
267362306a36Sopenharmony_ci						'[', ']');
267462306a36Sopenharmony_ci	if (status)
267562306a36Sopenharmony_ci		return status;
267662306a36Sopenharmony_ci	status = nfsd4_encode_components(xdr, '/', location->path);
267762306a36Sopenharmony_ci	if (status)
267862306a36Sopenharmony_ci		return status;
267962306a36Sopenharmony_ci	return 0;
268062306a36Sopenharmony_ci}
268162306a36Sopenharmony_ci
268262306a36Sopenharmony_ci/*
268362306a36Sopenharmony_ci * Encode a path in RFC3530 'pathname4' format
268462306a36Sopenharmony_ci */
268562306a36Sopenharmony_cistatic __be32 nfsd4_encode_path(struct xdr_stream *xdr,
268662306a36Sopenharmony_ci				const struct path *root,
268762306a36Sopenharmony_ci				const struct path *path)
268862306a36Sopenharmony_ci{
268962306a36Sopenharmony_ci	struct path cur = *path;
269062306a36Sopenharmony_ci	__be32 *p;
269162306a36Sopenharmony_ci	struct dentry **components = NULL;
269262306a36Sopenharmony_ci	unsigned int ncomponents = 0;
269362306a36Sopenharmony_ci	__be32 err = nfserr_jukebox;
269462306a36Sopenharmony_ci
269562306a36Sopenharmony_ci	dprintk("nfsd4_encode_components(");
269662306a36Sopenharmony_ci
269762306a36Sopenharmony_ci	path_get(&cur);
269862306a36Sopenharmony_ci	/* First walk the path up to the nfsd root, and store the
269962306a36Sopenharmony_ci	 * dentries/path components in an array.
270062306a36Sopenharmony_ci	 */
270162306a36Sopenharmony_ci	for (;;) {
270262306a36Sopenharmony_ci		if (path_equal(&cur, root))
270362306a36Sopenharmony_ci			break;
270462306a36Sopenharmony_ci		if (cur.dentry == cur.mnt->mnt_root) {
270562306a36Sopenharmony_ci			if (follow_up(&cur))
270662306a36Sopenharmony_ci				continue;
270762306a36Sopenharmony_ci			goto out_free;
270862306a36Sopenharmony_ci		}
270962306a36Sopenharmony_ci		if ((ncomponents & 15) == 0) {
271062306a36Sopenharmony_ci			struct dentry **new;
271162306a36Sopenharmony_ci			new = krealloc(components,
271262306a36Sopenharmony_ci					sizeof(*new) * (ncomponents + 16),
271362306a36Sopenharmony_ci					GFP_KERNEL);
271462306a36Sopenharmony_ci			if (!new)
271562306a36Sopenharmony_ci				goto out_free;
271662306a36Sopenharmony_ci			components = new;
271762306a36Sopenharmony_ci		}
271862306a36Sopenharmony_ci		components[ncomponents++] = cur.dentry;
271962306a36Sopenharmony_ci		cur.dentry = dget_parent(cur.dentry);
272062306a36Sopenharmony_ci	}
272162306a36Sopenharmony_ci	err = nfserr_resource;
272262306a36Sopenharmony_ci	p = xdr_reserve_space(xdr, 4);
272362306a36Sopenharmony_ci	if (!p)
272462306a36Sopenharmony_ci		goto out_free;
272562306a36Sopenharmony_ci	*p++ = cpu_to_be32(ncomponents);
272662306a36Sopenharmony_ci
272762306a36Sopenharmony_ci	while (ncomponents) {
272862306a36Sopenharmony_ci		struct dentry *dentry = components[ncomponents - 1];
272962306a36Sopenharmony_ci		unsigned int len;
273062306a36Sopenharmony_ci
273162306a36Sopenharmony_ci		spin_lock(&dentry->d_lock);
273262306a36Sopenharmony_ci		len = dentry->d_name.len;
273362306a36Sopenharmony_ci		p = xdr_reserve_space(xdr, len + 4);
273462306a36Sopenharmony_ci		if (!p) {
273562306a36Sopenharmony_ci			spin_unlock(&dentry->d_lock);
273662306a36Sopenharmony_ci			goto out_free;
273762306a36Sopenharmony_ci		}
273862306a36Sopenharmony_ci		p = xdr_encode_opaque(p, dentry->d_name.name, len);
273962306a36Sopenharmony_ci		dprintk("/%pd", dentry);
274062306a36Sopenharmony_ci		spin_unlock(&dentry->d_lock);
274162306a36Sopenharmony_ci		dput(dentry);
274262306a36Sopenharmony_ci		ncomponents--;
274362306a36Sopenharmony_ci	}
274462306a36Sopenharmony_ci
274562306a36Sopenharmony_ci	err = 0;
274662306a36Sopenharmony_ciout_free:
274762306a36Sopenharmony_ci	dprintk(")\n");
274862306a36Sopenharmony_ci	while (ncomponents)
274962306a36Sopenharmony_ci		dput(components[--ncomponents]);
275062306a36Sopenharmony_ci	kfree(components);
275162306a36Sopenharmony_ci	path_put(&cur);
275262306a36Sopenharmony_ci	return err;
275362306a36Sopenharmony_ci}
275462306a36Sopenharmony_ci
275562306a36Sopenharmony_cistatic __be32 nfsd4_encode_fsloc_fsroot(struct xdr_stream *xdr,
275662306a36Sopenharmony_ci			struct svc_rqst *rqstp, const struct path *path)
275762306a36Sopenharmony_ci{
275862306a36Sopenharmony_ci	struct svc_export *exp_ps;
275962306a36Sopenharmony_ci	__be32 res;
276062306a36Sopenharmony_ci
276162306a36Sopenharmony_ci	exp_ps = rqst_find_fsidzero_export(rqstp);
276262306a36Sopenharmony_ci	if (IS_ERR(exp_ps))
276362306a36Sopenharmony_ci		return nfserrno(PTR_ERR(exp_ps));
276462306a36Sopenharmony_ci	res = nfsd4_encode_path(xdr, &exp_ps->ex_path, path);
276562306a36Sopenharmony_ci	exp_put(exp_ps);
276662306a36Sopenharmony_ci	return res;
276762306a36Sopenharmony_ci}
276862306a36Sopenharmony_ci
276962306a36Sopenharmony_ci/*
277062306a36Sopenharmony_ci *  encode a fs_locations structure
277162306a36Sopenharmony_ci */
277262306a36Sopenharmony_cistatic __be32 nfsd4_encode_fs_locations(struct xdr_stream *xdr,
277362306a36Sopenharmony_ci			struct svc_rqst *rqstp, struct svc_export *exp)
277462306a36Sopenharmony_ci{
277562306a36Sopenharmony_ci	__be32 status;
277662306a36Sopenharmony_ci	int i;
277762306a36Sopenharmony_ci	__be32 *p;
277862306a36Sopenharmony_ci	struct nfsd4_fs_locations *fslocs = &exp->ex_fslocs;
277962306a36Sopenharmony_ci
278062306a36Sopenharmony_ci	status = nfsd4_encode_fsloc_fsroot(xdr, rqstp, &exp->ex_path);
278162306a36Sopenharmony_ci	if (status)
278262306a36Sopenharmony_ci		return status;
278362306a36Sopenharmony_ci	p = xdr_reserve_space(xdr, 4);
278462306a36Sopenharmony_ci	if (!p)
278562306a36Sopenharmony_ci		return nfserr_resource;
278662306a36Sopenharmony_ci	*p++ = cpu_to_be32(fslocs->locations_count);
278762306a36Sopenharmony_ci	for (i=0; i<fslocs->locations_count; i++) {
278862306a36Sopenharmony_ci		status = nfsd4_encode_fs_location4(xdr, &fslocs->locations[i]);
278962306a36Sopenharmony_ci		if (status)
279062306a36Sopenharmony_ci			return status;
279162306a36Sopenharmony_ci	}
279262306a36Sopenharmony_ci	return 0;
279362306a36Sopenharmony_ci}
279462306a36Sopenharmony_ci
279562306a36Sopenharmony_cistatic u32 nfs4_file_type(umode_t mode)
279662306a36Sopenharmony_ci{
279762306a36Sopenharmony_ci	switch (mode & S_IFMT) {
279862306a36Sopenharmony_ci	case S_IFIFO:	return NF4FIFO;
279962306a36Sopenharmony_ci	case S_IFCHR:	return NF4CHR;
280062306a36Sopenharmony_ci	case S_IFDIR:	return NF4DIR;
280162306a36Sopenharmony_ci	case S_IFBLK:	return NF4BLK;
280262306a36Sopenharmony_ci	case S_IFLNK:	return NF4LNK;
280362306a36Sopenharmony_ci	case S_IFREG:	return NF4REG;
280462306a36Sopenharmony_ci	case S_IFSOCK:	return NF4SOCK;
280562306a36Sopenharmony_ci	default:	return NF4BAD;
280662306a36Sopenharmony_ci	}
280762306a36Sopenharmony_ci}
280862306a36Sopenharmony_ci
280962306a36Sopenharmony_cistatic inline __be32
281062306a36Sopenharmony_cinfsd4_encode_aclname(struct xdr_stream *xdr, struct svc_rqst *rqstp,
281162306a36Sopenharmony_ci		     struct nfs4_ace *ace)
281262306a36Sopenharmony_ci{
281362306a36Sopenharmony_ci	if (ace->whotype != NFS4_ACL_WHO_NAMED)
281462306a36Sopenharmony_ci		return nfs4_acl_write_who(xdr, ace->whotype);
281562306a36Sopenharmony_ci	else if (ace->flag & NFS4_ACE_IDENTIFIER_GROUP)
281662306a36Sopenharmony_ci		return nfsd4_encode_group(xdr, rqstp, ace->who_gid);
281762306a36Sopenharmony_ci	else
281862306a36Sopenharmony_ci		return nfsd4_encode_user(xdr, rqstp, ace->who_uid);
281962306a36Sopenharmony_ci}
282062306a36Sopenharmony_ci
282162306a36Sopenharmony_cistatic inline __be32
282262306a36Sopenharmony_cinfsd4_encode_layout_types(struct xdr_stream *xdr, u32 layout_types)
282362306a36Sopenharmony_ci{
282462306a36Sopenharmony_ci	__be32		*p;
282562306a36Sopenharmony_ci	unsigned long	i = hweight_long(layout_types);
282662306a36Sopenharmony_ci
282762306a36Sopenharmony_ci	p = xdr_reserve_space(xdr, 4 + 4 * i);
282862306a36Sopenharmony_ci	if (!p)
282962306a36Sopenharmony_ci		return nfserr_resource;
283062306a36Sopenharmony_ci
283162306a36Sopenharmony_ci	*p++ = cpu_to_be32(i);
283262306a36Sopenharmony_ci
283362306a36Sopenharmony_ci	for (i = LAYOUT_NFSV4_1_FILES; i < LAYOUT_TYPE_MAX; ++i)
283462306a36Sopenharmony_ci		if (layout_types & (1 << i))
283562306a36Sopenharmony_ci			*p++ = cpu_to_be32(i);
283662306a36Sopenharmony_ci
283762306a36Sopenharmony_ci	return 0;
283862306a36Sopenharmony_ci}
283962306a36Sopenharmony_ci
284062306a36Sopenharmony_ci#define WORD0_ABSENT_FS_ATTRS (FATTR4_WORD0_FS_LOCATIONS | FATTR4_WORD0_FSID | \
284162306a36Sopenharmony_ci			      FATTR4_WORD0_RDATTR_ERROR)
284262306a36Sopenharmony_ci#define WORD1_ABSENT_FS_ATTRS FATTR4_WORD1_MOUNTED_ON_FILEID
284362306a36Sopenharmony_ci#define WORD2_ABSENT_FS_ATTRS 0
284462306a36Sopenharmony_ci
284562306a36Sopenharmony_ci#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
284662306a36Sopenharmony_cistatic inline __be32
284762306a36Sopenharmony_cinfsd4_encode_security_label(struct xdr_stream *xdr, struct svc_rqst *rqstp,
284862306a36Sopenharmony_ci			    void *context, int len)
284962306a36Sopenharmony_ci{
285062306a36Sopenharmony_ci	__be32 *p;
285162306a36Sopenharmony_ci
285262306a36Sopenharmony_ci	p = xdr_reserve_space(xdr, len + 4 + 4 + 4);
285362306a36Sopenharmony_ci	if (!p)
285462306a36Sopenharmony_ci		return nfserr_resource;
285562306a36Sopenharmony_ci
285662306a36Sopenharmony_ci	/*
285762306a36Sopenharmony_ci	 * For now we use a 0 here to indicate the null translation; in
285862306a36Sopenharmony_ci	 * the future we may place a call to translation code here.
285962306a36Sopenharmony_ci	 */
286062306a36Sopenharmony_ci	*p++ = cpu_to_be32(0); /* lfs */
286162306a36Sopenharmony_ci	*p++ = cpu_to_be32(0); /* pi */
286262306a36Sopenharmony_ci	p = xdr_encode_opaque(p, context, len);
286362306a36Sopenharmony_ci	return 0;
286462306a36Sopenharmony_ci}
286562306a36Sopenharmony_ci#else
286662306a36Sopenharmony_cistatic inline __be32
286762306a36Sopenharmony_cinfsd4_encode_security_label(struct xdr_stream *xdr, struct svc_rqst *rqstp,
286862306a36Sopenharmony_ci			    void *context, int len)
286962306a36Sopenharmony_ci{ return 0; }
287062306a36Sopenharmony_ci#endif
287162306a36Sopenharmony_ci
287262306a36Sopenharmony_cistatic __be32 fattr_handle_absent_fs(u32 *bmval0, u32 *bmval1, u32 *bmval2, u32 *rdattr_err)
287362306a36Sopenharmony_ci{
287462306a36Sopenharmony_ci	/* As per referral draft:  */
287562306a36Sopenharmony_ci	if (*bmval0 & ~WORD0_ABSENT_FS_ATTRS ||
287662306a36Sopenharmony_ci	    *bmval1 & ~WORD1_ABSENT_FS_ATTRS) {
287762306a36Sopenharmony_ci		if (*bmval0 & FATTR4_WORD0_RDATTR_ERROR ||
287862306a36Sopenharmony_ci	            *bmval0 & FATTR4_WORD0_FS_LOCATIONS)
287962306a36Sopenharmony_ci			*rdattr_err = NFSERR_MOVED;
288062306a36Sopenharmony_ci		else
288162306a36Sopenharmony_ci			return nfserr_moved;
288262306a36Sopenharmony_ci	}
288362306a36Sopenharmony_ci	*bmval0 &= WORD0_ABSENT_FS_ATTRS;
288462306a36Sopenharmony_ci	*bmval1 &= WORD1_ABSENT_FS_ATTRS;
288562306a36Sopenharmony_ci	*bmval2 &= WORD2_ABSENT_FS_ATTRS;
288662306a36Sopenharmony_ci	return 0;
288762306a36Sopenharmony_ci}
288862306a36Sopenharmony_ci
288962306a36Sopenharmony_ci
289062306a36Sopenharmony_cistatic int nfsd4_get_mounted_on_ino(struct svc_export *exp, u64 *pino)
289162306a36Sopenharmony_ci{
289262306a36Sopenharmony_ci	struct path path = exp->ex_path;
289362306a36Sopenharmony_ci	struct kstat stat;
289462306a36Sopenharmony_ci	int err;
289562306a36Sopenharmony_ci
289662306a36Sopenharmony_ci	path_get(&path);
289762306a36Sopenharmony_ci	while (follow_up(&path)) {
289862306a36Sopenharmony_ci		if (path.dentry != path.mnt->mnt_root)
289962306a36Sopenharmony_ci			break;
290062306a36Sopenharmony_ci	}
290162306a36Sopenharmony_ci	err = vfs_getattr(&path, &stat, STATX_INO, AT_STATX_SYNC_AS_STAT);
290262306a36Sopenharmony_ci	path_put(&path);
290362306a36Sopenharmony_ci	if (!err)
290462306a36Sopenharmony_ci		*pino = stat.ino;
290562306a36Sopenharmony_ci	return err;
290662306a36Sopenharmony_ci}
290762306a36Sopenharmony_ci
290862306a36Sopenharmony_cistatic __be32
290962306a36Sopenharmony_cinfsd4_encode_bitmap(struct xdr_stream *xdr, u32 bmval0, u32 bmval1, u32 bmval2)
291062306a36Sopenharmony_ci{
291162306a36Sopenharmony_ci	__be32 *p;
291262306a36Sopenharmony_ci
291362306a36Sopenharmony_ci	if (bmval2) {
291462306a36Sopenharmony_ci		p = xdr_reserve_space(xdr, 16);
291562306a36Sopenharmony_ci		if (!p)
291662306a36Sopenharmony_ci			goto out_resource;
291762306a36Sopenharmony_ci		*p++ = cpu_to_be32(3);
291862306a36Sopenharmony_ci		*p++ = cpu_to_be32(bmval0);
291962306a36Sopenharmony_ci		*p++ = cpu_to_be32(bmval1);
292062306a36Sopenharmony_ci		*p++ = cpu_to_be32(bmval2);
292162306a36Sopenharmony_ci	} else if (bmval1) {
292262306a36Sopenharmony_ci		p = xdr_reserve_space(xdr, 12);
292362306a36Sopenharmony_ci		if (!p)
292462306a36Sopenharmony_ci			goto out_resource;
292562306a36Sopenharmony_ci		*p++ = cpu_to_be32(2);
292662306a36Sopenharmony_ci		*p++ = cpu_to_be32(bmval0);
292762306a36Sopenharmony_ci		*p++ = cpu_to_be32(bmval1);
292862306a36Sopenharmony_ci	} else {
292962306a36Sopenharmony_ci		p = xdr_reserve_space(xdr, 8);
293062306a36Sopenharmony_ci		if (!p)
293162306a36Sopenharmony_ci			goto out_resource;
293262306a36Sopenharmony_ci		*p++ = cpu_to_be32(1);
293362306a36Sopenharmony_ci		*p++ = cpu_to_be32(bmval0);
293462306a36Sopenharmony_ci	}
293562306a36Sopenharmony_ci
293662306a36Sopenharmony_ci	return 0;
293762306a36Sopenharmony_ciout_resource:
293862306a36Sopenharmony_ci	return nfserr_resource;
293962306a36Sopenharmony_ci}
294062306a36Sopenharmony_ci
294162306a36Sopenharmony_ci/*
294262306a36Sopenharmony_ci * Note: @fhp can be NULL; in this case, we might have to compose the filehandle
294362306a36Sopenharmony_ci * ourselves.
294462306a36Sopenharmony_ci */
294562306a36Sopenharmony_cistatic __be32
294662306a36Sopenharmony_cinfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp,
294762306a36Sopenharmony_ci		struct svc_export *exp,
294862306a36Sopenharmony_ci		struct dentry *dentry, u32 *bmval,
294962306a36Sopenharmony_ci		struct svc_rqst *rqstp, int ignore_crossmnt)
295062306a36Sopenharmony_ci{
295162306a36Sopenharmony_ci	u32 bmval0 = bmval[0];
295262306a36Sopenharmony_ci	u32 bmval1 = bmval[1];
295362306a36Sopenharmony_ci	u32 bmval2 = bmval[2];
295462306a36Sopenharmony_ci	struct kstat stat;
295562306a36Sopenharmony_ci	struct svc_fh *tempfh = NULL;
295662306a36Sopenharmony_ci	struct kstatfs statfs;
295762306a36Sopenharmony_ci	__be32 *p, *attrlen_p;
295862306a36Sopenharmony_ci	int starting_len = xdr->buf->len;
295962306a36Sopenharmony_ci	int attrlen_offset;
296062306a36Sopenharmony_ci	u32 dummy;
296162306a36Sopenharmony_ci	u64 dummy64;
296262306a36Sopenharmony_ci	u32 rdattr_err = 0;
296362306a36Sopenharmony_ci	__be32 status;
296462306a36Sopenharmony_ci	int err;
296562306a36Sopenharmony_ci	struct nfs4_acl *acl = NULL;
296662306a36Sopenharmony_ci#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
296762306a36Sopenharmony_ci	void *context = NULL;
296862306a36Sopenharmony_ci	int contextlen;
296962306a36Sopenharmony_ci#endif
297062306a36Sopenharmony_ci	bool contextsupport = false;
297162306a36Sopenharmony_ci	struct nfsd4_compoundres *resp = rqstp->rq_resp;
297262306a36Sopenharmony_ci	u32 minorversion = resp->cstate.minorversion;
297362306a36Sopenharmony_ci	struct path path = {
297462306a36Sopenharmony_ci		.mnt	= exp->ex_path.mnt,
297562306a36Sopenharmony_ci		.dentry	= dentry,
297662306a36Sopenharmony_ci	};
297762306a36Sopenharmony_ci	struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
297862306a36Sopenharmony_ci
297962306a36Sopenharmony_ci	BUG_ON(bmval1 & NFSD_WRITEONLY_ATTRS_WORD1);
298062306a36Sopenharmony_ci	BUG_ON(!nfsd_attrs_supported(minorversion, bmval));
298162306a36Sopenharmony_ci
298262306a36Sopenharmony_ci	if (exp->ex_fslocs.migrated) {
298362306a36Sopenharmony_ci		status = fattr_handle_absent_fs(&bmval0, &bmval1, &bmval2, &rdattr_err);
298462306a36Sopenharmony_ci		if (status)
298562306a36Sopenharmony_ci			goto out;
298662306a36Sopenharmony_ci	}
298762306a36Sopenharmony_ci	if (bmval0 & (FATTR4_WORD0_CHANGE | FATTR4_WORD0_SIZE)) {
298862306a36Sopenharmony_ci		status = nfsd4_deleg_getattr_conflict(rqstp, d_inode(dentry));
298962306a36Sopenharmony_ci		if (status)
299062306a36Sopenharmony_ci			goto out;
299162306a36Sopenharmony_ci	}
299262306a36Sopenharmony_ci
299362306a36Sopenharmony_ci	err = vfs_getattr(&path, &stat,
299462306a36Sopenharmony_ci			  STATX_BASIC_STATS | STATX_BTIME | STATX_CHANGE_COOKIE,
299562306a36Sopenharmony_ci			  AT_STATX_SYNC_AS_STAT);
299662306a36Sopenharmony_ci	if (err)
299762306a36Sopenharmony_ci		goto out_nfserr;
299862306a36Sopenharmony_ci	if (!(stat.result_mask & STATX_BTIME))
299962306a36Sopenharmony_ci		/* underlying FS does not offer btime so we can't share it */
300062306a36Sopenharmony_ci		bmval1 &= ~FATTR4_WORD1_TIME_CREATE;
300162306a36Sopenharmony_ci	if ((bmval0 & (FATTR4_WORD0_FILES_AVAIL | FATTR4_WORD0_FILES_FREE |
300262306a36Sopenharmony_ci			FATTR4_WORD0_FILES_TOTAL | FATTR4_WORD0_MAXNAME)) ||
300362306a36Sopenharmony_ci	    (bmval1 & (FATTR4_WORD1_SPACE_AVAIL | FATTR4_WORD1_SPACE_FREE |
300462306a36Sopenharmony_ci		       FATTR4_WORD1_SPACE_TOTAL))) {
300562306a36Sopenharmony_ci		err = vfs_statfs(&path, &statfs);
300662306a36Sopenharmony_ci		if (err)
300762306a36Sopenharmony_ci			goto out_nfserr;
300862306a36Sopenharmony_ci	}
300962306a36Sopenharmony_ci	if ((bmval0 & (FATTR4_WORD0_FILEHANDLE | FATTR4_WORD0_FSID)) && !fhp) {
301062306a36Sopenharmony_ci		tempfh = kmalloc(sizeof(struct svc_fh), GFP_KERNEL);
301162306a36Sopenharmony_ci		status = nfserr_jukebox;
301262306a36Sopenharmony_ci		if (!tempfh)
301362306a36Sopenharmony_ci			goto out;
301462306a36Sopenharmony_ci		fh_init(tempfh, NFS4_FHSIZE);
301562306a36Sopenharmony_ci		status = fh_compose(tempfh, exp, dentry, NULL);
301662306a36Sopenharmony_ci		if (status)
301762306a36Sopenharmony_ci			goto out;
301862306a36Sopenharmony_ci		fhp = tempfh;
301962306a36Sopenharmony_ci	}
302062306a36Sopenharmony_ci	if (bmval0 & FATTR4_WORD0_ACL) {
302162306a36Sopenharmony_ci		err = nfsd4_get_nfs4_acl(rqstp, dentry, &acl);
302262306a36Sopenharmony_ci		if (err == -EOPNOTSUPP)
302362306a36Sopenharmony_ci			bmval0 &= ~FATTR4_WORD0_ACL;
302462306a36Sopenharmony_ci		else if (err == -EINVAL) {
302562306a36Sopenharmony_ci			status = nfserr_attrnotsupp;
302662306a36Sopenharmony_ci			goto out;
302762306a36Sopenharmony_ci		} else if (err != 0)
302862306a36Sopenharmony_ci			goto out_nfserr;
302962306a36Sopenharmony_ci	}
303062306a36Sopenharmony_ci
303162306a36Sopenharmony_ci#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
303262306a36Sopenharmony_ci	if ((bmval2 & FATTR4_WORD2_SECURITY_LABEL) ||
303362306a36Sopenharmony_ci	     bmval0 & FATTR4_WORD0_SUPPORTED_ATTRS) {
303462306a36Sopenharmony_ci		if (exp->ex_flags & NFSEXP_SECURITY_LABEL)
303562306a36Sopenharmony_ci			err = security_inode_getsecctx(d_inode(dentry),
303662306a36Sopenharmony_ci						&context, &contextlen);
303762306a36Sopenharmony_ci		else
303862306a36Sopenharmony_ci			err = -EOPNOTSUPP;
303962306a36Sopenharmony_ci		contextsupport = (err == 0);
304062306a36Sopenharmony_ci		if (bmval2 & FATTR4_WORD2_SECURITY_LABEL) {
304162306a36Sopenharmony_ci			if (err == -EOPNOTSUPP)
304262306a36Sopenharmony_ci				bmval2 &= ~FATTR4_WORD2_SECURITY_LABEL;
304362306a36Sopenharmony_ci			else if (err)
304462306a36Sopenharmony_ci				goto out_nfserr;
304562306a36Sopenharmony_ci		}
304662306a36Sopenharmony_ci	}
304762306a36Sopenharmony_ci#endif /* CONFIG_NFSD_V4_SECURITY_LABEL */
304862306a36Sopenharmony_ci
304962306a36Sopenharmony_ci	status = nfsd4_encode_bitmap(xdr, bmval0, bmval1, bmval2);
305062306a36Sopenharmony_ci	if (status)
305162306a36Sopenharmony_ci		goto out;
305262306a36Sopenharmony_ci
305362306a36Sopenharmony_ci	attrlen_offset = xdr->buf->len;
305462306a36Sopenharmony_ci	attrlen_p = xdr_reserve_space(xdr, XDR_UNIT);
305562306a36Sopenharmony_ci	if (!attrlen_p)
305662306a36Sopenharmony_ci		goto out_resource;
305762306a36Sopenharmony_ci
305862306a36Sopenharmony_ci	if (bmval0 & FATTR4_WORD0_SUPPORTED_ATTRS) {
305962306a36Sopenharmony_ci		u32 supp[3];
306062306a36Sopenharmony_ci
306162306a36Sopenharmony_ci		memcpy(supp, nfsd_suppattrs[minorversion], sizeof(supp));
306262306a36Sopenharmony_ci
306362306a36Sopenharmony_ci		if (!IS_POSIXACL(dentry->d_inode))
306462306a36Sopenharmony_ci			supp[0] &= ~FATTR4_WORD0_ACL;
306562306a36Sopenharmony_ci		if (!contextsupport)
306662306a36Sopenharmony_ci			supp[2] &= ~FATTR4_WORD2_SECURITY_LABEL;
306762306a36Sopenharmony_ci		if (!supp[2]) {
306862306a36Sopenharmony_ci			p = xdr_reserve_space(xdr, 12);
306962306a36Sopenharmony_ci			if (!p)
307062306a36Sopenharmony_ci				goto out_resource;
307162306a36Sopenharmony_ci			*p++ = cpu_to_be32(2);
307262306a36Sopenharmony_ci			*p++ = cpu_to_be32(supp[0]);
307362306a36Sopenharmony_ci			*p++ = cpu_to_be32(supp[1]);
307462306a36Sopenharmony_ci		} else {
307562306a36Sopenharmony_ci			p = xdr_reserve_space(xdr, 16);
307662306a36Sopenharmony_ci			if (!p)
307762306a36Sopenharmony_ci				goto out_resource;
307862306a36Sopenharmony_ci			*p++ = cpu_to_be32(3);
307962306a36Sopenharmony_ci			*p++ = cpu_to_be32(supp[0]);
308062306a36Sopenharmony_ci			*p++ = cpu_to_be32(supp[1]);
308162306a36Sopenharmony_ci			*p++ = cpu_to_be32(supp[2]);
308262306a36Sopenharmony_ci		}
308362306a36Sopenharmony_ci	}
308462306a36Sopenharmony_ci	if (bmval0 & FATTR4_WORD0_TYPE) {
308562306a36Sopenharmony_ci		p = xdr_reserve_space(xdr, 4);
308662306a36Sopenharmony_ci		if (!p)
308762306a36Sopenharmony_ci			goto out_resource;
308862306a36Sopenharmony_ci		dummy = nfs4_file_type(stat.mode);
308962306a36Sopenharmony_ci		if (dummy == NF4BAD) {
309062306a36Sopenharmony_ci			status = nfserr_serverfault;
309162306a36Sopenharmony_ci			goto out;
309262306a36Sopenharmony_ci		}
309362306a36Sopenharmony_ci		*p++ = cpu_to_be32(dummy);
309462306a36Sopenharmony_ci	}
309562306a36Sopenharmony_ci	if (bmval0 & FATTR4_WORD0_FH_EXPIRE_TYPE) {
309662306a36Sopenharmony_ci		p = xdr_reserve_space(xdr, 4);
309762306a36Sopenharmony_ci		if (!p)
309862306a36Sopenharmony_ci			goto out_resource;
309962306a36Sopenharmony_ci		if (exp->ex_flags & NFSEXP_NOSUBTREECHECK)
310062306a36Sopenharmony_ci			*p++ = cpu_to_be32(NFS4_FH_PERSISTENT);
310162306a36Sopenharmony_ci		else
310262306a36Sopenharmony_ci			*p++ = cpu_to_be32(NFS4_FH_PERSISTENT|
310362306a36Sopenharmony_ci						NFS4_FH_VOL_RENAME);
310462306a36Sopenharmony_ci	}
310562306a36Sopenharmony_ci	if (bmval0 & FATTR4_WORD0_CHANGE) {
310662306a36Sopenharmony_ci		p = xdr_reserve_space(xdr, 8);
310762306a36Sopenharmony_ci		if (!p)
310862306a36Sopenharmony_ci			goto out_resource;
310962306a36Sopenharmony_ci		p = encode_change(p, &stat, d_inode(dentry), exp);
311062306a36Sopenharmony_ci	}
311162306a36Sopenharmony_ci	if (bmval0 & FATTR4_WORD0_SIZE) {
311262306a36Sopenharmony_ci		p = xdr_reserve_space(xdr, 8);
311362306a36Sopenharmony_ci		if (!p)
311462306a36Sopenharmony_ci			goto out_resource;
311562306a36Sopenharmony_ci		p = xdr_encode_hyper(p, stat.size);
311662306a36Sopenharmony_ci	}
311762306a36Sopenharmony_ci	if (bmval0 & FATTR4_WORD0_LINK_SUPPORT) {
311862306a36Sopenharmony_ci		p = xdr_reserve_space(xdr, 4);
311962306a36Sopenharmony_ci		if (!p)
312062306a36Sopenharmony_ci			goto out_resource;
312162306a36Sopenharmony_ci		*p++ = cpu_to_be32(1);
312262306a36Sopenharmony_ci	}
312362306a36Sopenharmony_ci	if (bmval0 & FATTR4_WORD0_SYMLINK_SUPPORT) {
312462306a36Sopenharmony_ci		p = xdr_reserve_space(xdr, 4);
312562306a36Sopenharmony_ci		if (!p)
312662306a36Sopenharmony_ci			goto out_resource;
312762306a36Sopenharmony_ci		*p++ = cpu_to_be32(1);
312862306a36Sopenharmony_ci	}
312962306a36Sopenharmony_ci	if (bmval0 & FATTR4_WORD0_NAMED_ATTR) {
313062306a36Sopenharmony_ci		p = xdr_reserve_space(xdr, 4);
313162306a36Sopenharmony_ci		if (!p)
313262306a36Sopenharmony_ci			goto out_resource;
313362306a36Sopenharmony_ci		*p++ = cpu_to_be32(0);
313462306a36Sopenharmony_ci	}
313562306a36Sopenharmony_ci	if (bmval0 & FATTR4_WORD0_FSID) {
313662306a36Sopenharmony_ci		p = xdr_reserve_space(xdr, 16);
313762306a36Sopenharmony_ci		if (!p)
313862306a36Sopenharmony_ci			goto out_resource;
313962306a36Sopenharmony_ci		if (exp->ex_fslocs.migrated) {
314062306a36Sopenharmony_ci			p = xdr_encode_hyper(p, NFS4_REFERRAL_FSID_MAJOR);
314162306a36Sopenharmony_ci			p = xdr_encode_hyper(p, NFS4_REFERRAL_FSID_MINOR);
314262306a36Sopenharmony_ci		} else switch(fsid_source(fhp)) {
314362306a36Sopenharmony_ci		case FSIDSOURCE_FSID:
314462306a36Sopenharmony_ci			p = xdr_encode_hyper(p, (u64)exp->ex_fsid);
314562306a36Sopenharmony_ci			p = xdr_encode_hyper(p, (u64)0);
314662306a36Sopenharmony_ci			break;
314762306a36Sopenharmony_ci		case FSIDSOURCE_DEV:
314862306a36Sopenharmony_ci			*p++ = cpu_to_be32(0);
314962306a36Sopenharmony_ci			*p++ = cpu_to_be32(MAJOR(stat.dev));
315062306a36Sopenharmony_ci			*p++ = cpu_to_be32(0);
315162306a36Sopenharmony_ci			*p++ = cpu_to_be32(MINOR(stat.dev));
315262306a36Sopenharmony_ci			break;
315362306a36Sopenharmony_ci		case FSIDSOURCE_UUID:
315462306a36Sopenharmony_ci			p = xdr_encode_opaque_fixed(p, exp->ex_uuid,
315562306a36Sopenharmony_ci								EX_UUID_LEN);
315662306a36Sopenharmony_ci			break;
315762306a36Sopenharmony_ci		}
315862306a36Sopenharmony_ci	}
315962306a36Sopenharmony_ci	if (bmval0 & FATTR4_WORD0_UNIQUE_HANDLES) {
316062306a36Sopenharmony_ci		p = xdr_reserve_space(xdr, 4);
316162306a36Sopenharmony_ci		if (!p)
316262306a36Sopenharmony_ci			goto out_resource;
316362306a36Sopenharmony_ci		*p++ = cpu_to_be32(0);
316462306a36Sopenharmony_ci	}
316562306a36Sopenharmony_ci	if (bmval0 & FATTR4_WORD0_LEASE_TIME) {
316662306a36Sopenharmony_ci		p = xdr_reserve_space(xdr, 4);
316762306a36Sopenharmony_ci		if (!p)
316862306a36Sopenharmony_ci			goto out_resource;
316962306a36Sopenharmony_ci		*p++ = cpu_to_be32(nn->nfsd4_lease);
317062306a36Sopenharmony_ci	}
317162306a36Sopenharmony_ci	if (bmval0 & FATTR4_WORD0_RDATTR_ERROR) {
317262306a36Sopenharmony_ci		p = xdr_reserve_space(xdr, 4);
317362306a36Sopenharmony_ci		if (!p)
317462306a36Sopenharmony_ci			goto out_resource;
317562306a36Sopenharmony_ci		*p++ = cpu_to_be32(rdattr_err);
317662306a36Sopenharmony_ci	}
317762306a36Sopenharmony_ci	if (bmval0 & FATTR4_WORD0_ACL) {
317862306a36Sopenharmony_ci		struct nfs4_ace *ace;
317962306a36Sopenharmony_ci
318062306a36Sopenharmony_ci		if (acl == NULL) {
318162306a36Sopenharmony_ci			p = xdr_reserve_space(xdr, 4);
318262306a36Sopenharmony_ci			if (!p)
318362306a36Sopenharmony_ci				goto out_resource;
318462306a36Sopenharmony_ci
318562306a36Sopenharmony_ci			*p++ = cpu_to_be32(0);
318662306a36Sopenharmony_ci			goto out_acl;
318762306a36Sopenharmony_ci		}
318862306a36Sopenharmony_ci		p = xdr_reserve_space(xdr, 4);
318962306a36Sopenharmony_ci		if (!p)
319062306a36Sopenharmony_ci			goto out_resource;
319162306a36Sopenharmony_ci		*p++ = cpu_to_be32(acl->naces);
319262306a36Sopenharmony_ci
319362306a36Sopenharmony_ci		for (ace = acl->aces; ace < acl->aces + acl->naces; ace++) {
319462306a36Sopenharmony_ci			p = xdr_reserve_space(xdr, 4*3);
319562306a36Sopenharmony_ci			if (!p)
319662306a36Sopenharmony_ci				goto out_resource;
319762306a36Sopenharmony_ci			*p++ = cpu_to_be32(ace->type);
319862306a36Sopenharmony_ci			*p++ = cpu_to_be32(ace->flag);
319962306a36Sopenharmony_ci			*p++ = cpu_to_be32(ace->access_mask &
320062306a36Sopenharmony_ci							NFS4_ACE_MASK_ALL);
320162306a36Sopenharmony_ci			status = nfsd4_encode_aclname(xdr, rqstp, ace);
320262306a36Sopenharmony_ci			if (status)
320362306a36Sopenharmony_ci				goto out;
320462306a36Sopenharmony_ci		}
320562306a36Sopenharmony_ci	}
320662306a36Sopenharmony_ciout_acl:
320762306a36Sopenharmony_ci	if (bmval0 & FATTR4_WORD0_ACLSUPPORT) {
320862306a36Sopenharmony_ci		p = xdr_reserve_space(xdr, 4);
320962306a36Sopenharmony_ci		if (!p)
321062306a36Sopenharmony_ci			goto out_resource;
321162306a36Sopenharmony_ci		*p++ = cpu_to_be32(IS_POSIXACL(dentry->d_inode) ?
321262306a36Sopenharmony_ci			ACL4_SUPPORT_ALLOW_ACL|ACL4_SUPPORT_DENY_ACL : 0);
321362306a36Sopenharmony_ci	}
321462306a36Sopenharmony_ci	if (bmval0 & FATTR4_WORD0_CANSETTIME) {
321562306a36Sopenharmony_ci		p = xdr_reserve_space(xdr, 4);
321662306a36Sopenharmony_ci		if (!p)
321762306a36Sopenharmony_ci			goto out_resource;
321862306a36Sopenharmony_ci		*p++ = cpu_to_be32(1);
321962306a36Sopenharmony_ci	}
322062306a36Sopenharmony_ci	if (bmval0 & FATTR4_WORD0_CASE_INSENSITIVE) {
322162306a36Sopenharmony_ci		p = xdr_reserve_space(xdr, 4);
322262306a36Sopenharmony_ci		if (!p)
322362306a36Sopenharmony_ci			goto out_resource;
322462306a36Sopenharmony_ci		*p++ = cpu_to_be32(0);
322562306a36Sopenharmony_ci	}
322662306a36Sopenharmony_ci	if (bmval0 & FATTR4_WORD0_CASE_PRESERVING) {
322762306a36Sopenharmony_ci		p = xdr_reserve_space(xdr, 4);
322862306a36Sopenharmony_ci		if (!p)
322962306a36Sopenharmony_ci			goto out_resource;
323062306a36Sopenharmony_ci		*p++ = cpu_to_be32(1);
323162306a36Sopenharmony_ci	}
323262306a36Sopenharmony_ci	if (bmval0 & FATTR4_WORD0_CHOWN_RESTRICTED) {
323362306a36Sopenharmony_ci		p = xdr_reserve_space(xdr, 4);
323462306a36Sopenharmony_ci		if (!p)
323562306a36Sopenharmony_ci			goto out_resource;
323662306a36Sopenharmony_ci		*p++ = cpu_to_be32(1);
323762306a36Sopenharmony_ci	}
323862306a36Sopenharmony_ci	if (bmval0 & FATTR4_WORD0_FILEHANDLE) {
323962306a36Sopenharmony_ci		p = xdr_reserve_space(xdr, fhp->fh_handle.fh_size + 4);
324062306a36Sopenharmony_ci		if (!p)
324162306a36Sopenharmony_ci			goto out_resource;
324262306a36Sopenharmony_ci		p = xdr_encode_opaque(p, &fhp->fh_handle.fh_raw,
324362306a36Sopenharmony_ci					fhp->fh_handle.fh_size);
324462306a36Sopenharmony_ci	}
324562306a36Sopenharmony_ci	if (bmval0 & FATTR4_WORD0_FILEID) {
324662306a36Sopenharmony_ci		p = xdr_reserve_space(xdr, 8);
324762306a36Sopenharmony_ci		if (!p)
324862306a36Sopenharmony_ci			goto out_resource;
324962306a36Sopenharmony_ci		p = xdr_encode_hyper(p, stat.ino);
325062306a36Sopenharmony_ci	}
325162306a36Sopenharmony_ci	if (bmval0 & FATTR4_WORD0_FILES_AVAIL) {
325262306a36Sopenharmony_ci		p = xdr_reserve_space(xdr, 8);
325362306a36Sopenharmony_ci		if (!p)
325462306a36Sopenharmony_ci			goto out_resource;
325562306a36Sopenharmony_ci		p = xdr_encode_hyper(p, (u64) statfs.f_ffree);
325662306a36Sopenharmony_ci	}
325762306a36Sopenharmony_ci	if (bmval0 & FATTR4_WORD0_FILES_FREE) {
325862306a36Sopenharmony_ci		p = xdr_reserve_space(xdr, 8);
325962306a36Sopenharmony_ci		if (!p)
326062306a36Sopenharmony_ci			goto out_resource;
326162306a36Sopenharmony_ci		p = xdr_encode_hyper(p, (u64) statfs.f_ffree);
326262306a36Sopenharmony_ci	}
326362306a36Sopenharmony_ci	if (bmval0 & FATTR4_WORD0_FILES_TOTAL) {
326462306a36Sopenharmony_ci		p = xdr_reserve_space(xdr, 8);
326562306a36Sopenharmony_ci		if (!p)
326662306a36Sopenharmony_ci			goto out_resource;
326762306a36Sopenharmony_ci		p = xdr_encode_hyper(p, (u64) statfs.f_files);
326862306a36Sopenharmony_ci	}
326962306a36Sopenharmony_ci	if (bmval0 & FATTR4_WORD0_FS_LOCATIONS) {
327062306a36Sopenharmony_ci		status = nfsd4_encode_fs_locations(xdr, rqstp, exp);
327162306a36Sopenharmony_ci		if (status)
327262306a36Sopenharmony_ci			goto out;
327362306a36Sopenharmony_ci	}
327462306a36Sopenharmony_ci	if (bmval0 & FATTR4_WORD0_HOMOGENEOUS) {
327562306a36Sopenharmony_ci		p = xdr_reserve_space(xdr, 4);
327662306a36Sopenharmony_ci		if (!p)
327762306a36Sopenharmony_ci			goto out_resource;
327862306a36Sopenharmony_ci		*p++ = cpu_to_be32(1);
327962306a36Sopenharmony_ci	}
328062306a36Sopenharmony_ci	if (bmval0 & FATTR4_WORD0_MAXFILESIZE) {
328162306a36Sopenharmony_ci		p = xdr_reserve_space(xdr, 8);
328262306a36Sopenharmony_ci		if (!p)
328362306a36Sopenharmony_ci			goto out_resource;
328462306a36Sopenharmony_ci		p = xdr_encode_hyper(p, exp->ex_path.mnt->mnt_sb->s_maxbytes);
328562306a36Sopenharmony_ci	}
328662306a36Sopenharmony_ci	if (bmval0 & FATTR4_WORD0_MAXLINK) {
328762306a36Sopenharmony_ci		p = xdr_reserve_space(xdr, 4);
328862306a36Sopenharmony_ci		if (!p)
328962306a36Sopenharmony_ci			goto out_resource;
329062306a36Sopenharmony_ci		*p++ = cpu_to_be32(255);
329162306a36Sopenharmony_ci	}
329262306a36Sopenharmony_ci	if (bmval0 & FATTR4_WORD0_MAXNAME) {
329362306a36Sopenharmony_ci		p = xdr_reserve_space(xdr, 4);
329462306a36Sopenharmony_ci		if (!p)
329562306a36Sopenharmony_ci			goto out_resource;
329662306a36Sopenharmony_ci		*p++ = cpu_to_be32(statfs.f_namelen);
329762306a36Sopenharmony_ci	}
329862306a36Sopenharmony_ci	if (bmval0 & FATTR4_WORD0_MAXREAD) {
329962306a36Sopenharmony_ci		p = xdr_reserve_space(xdr, 8);
330062306a36Sopenharmony_ci		if (!p)
330162306a36Sopenharmony_ci			goto out_resource;
330262306a36Sopenharmony_ci		p = xdr_encode_hyper(p, (u64) svc_max_payload(rqstp));
330362306a36Sopenharmony_ci	}
330462306a36Sopenharmony_ci	if (bmval0 & FATTR4_WORD0_MAXWRITE) {
330562306a36Sopenharmony_ci		p = xdr_reserve_space(xdr, 8);
330662306a36Sopenharmony_ci		if (!p)
330762306a36Sopenharmony_ci			goto out_resource;
330862306a36Sopenharmony_ci		p = xdr_encode_hyper(p, (u64) svc_max_payload(rqstp));
330962306a36Sopenharmony_ci	}
331062306a36Sopenharmony_ci	if (bmval1 & FATTR4_WORD1_MODE) {
331162306a36Sopenharmony_ci		p = xdr_reserve_space(xdr, 4);
331262306a36Sopenharmony_ci		if (!p)
331362306a36Sopenharmony_ci			goto out_resource;
331462306a36Sopenharmony_ci		*p++ = cpu_to_be32(stat.mode & S_IALLUGO);
331562306a36Sopenharmony_ci	}
331662306a36Sopenharmony_ci	if (bmval1 & FATTR4_WORD1_NO_TRUNC) {
331762306a36Sopenharmony_ci		p = xdr_reserve_space(xdr, 4);
331862306a36Sopenharmony_ci		if (!p)
331962306a36Sopenharmony_ci			goto out_resource;
332062306a36Sopenharmony_ci		*p++ = cpu_to_be32(1);
332162306a36Sopenharmony_ci	}
332262306a36Sopenharmony_ci	if (bmval1 & FATTR4_WORD1_NUMLINKS) {
332362306a36Sopenharmony_ci		p = xdr_reserve_space(xdr, 4);
332462306a36Sopenharmony_ci		if (!p)
332562306a36Sopenharmony_ci			goto out_resource;
332662306a36Sopenharmony_ci		*p++ = cpu_to_be32(stat.nlink);
332762306a36Sopenharmony_ci	}
332862306a36Sopenharmony_ci	if (bmval1 & FATTR4_WORD1_OWNER) {
332962306a36Sopenharmony_ci		status = nfsd4_encode_user(xdr, rqstp, stat.uid);
333062306a36Sopenharmony_ci		if (status)
333162306a36Sopenharmony_ci			goto out;
333262306a36Sopenharmony_ci	}
333362306a36Sopenharmony_ci	if (bmval1 & FATTR4_WORD1_OWNER_GROUP) {
333462306a36Sopenharmony_ci		status = nfsd4_encode_group(xdr, rqstp, stat.gid);
333562306a36Sopenharmony_ci		if (status)
333662306a36Sopenharmony_ci			goto out;
333762306a36Sopenharmony_ci	}
333862306a36Sopenharmony_ci	if (bmval1 & FATTR4_WORD1_RAWDEV) {
333962306a36Sopenharmony_ci		p = xdr_reserve_space(xdr, 8);
334062306a36Sopenharmony_ci		if (!p)
334162306a36Sopenharmony_ci			goto out_resource;
334262306a36Sopenharmony_ci		*p++ = cpu_to_be32((u32) MAJOR(stat.rdev));
334362306a36Sopenharmony_ci		*p++ = cpu_to_be32((u32) MINOR(stat.rdev));
334462306a36Sopenharmony_ci	}
334562306a36Sopenharmony_ci	if (bmval1 & FATTR4_WORD1_SPACE_AVAIL) {
334662306a36Sopenharmony_ci		p = xdr_reserve_space(xdr, 8);
334762306a36Sopenharmony_ci		if (!p)
334862306a36Sopenharmony_ci			goto out_resource;
334962306a36Sopenharmony_ci		dummy64 = (u64)statfs.f_bavail * (u64)statfs.f_bsize;
335062306a36Sopenharmony_ci		p = xdr_encode_hyper(p, dummy64);
335162306a36Sopenharmony_ci	}
335262306a36Sopenharmony_ci	if (bmval1 & FATTR4_WORD1_SPACE_FREE) {
335362306a36Sopenharmony_ci		p = xdr_reserve_space(xdr, 8);
335462306a36Sopenharmony_ci		if (!p)
335562306a36Sopenharmony_ci			goto out_resource;
335662306a36Sopenharmony_ci		dummy64 = (u64)statfs.f_bfree * (u64)statfs.f_bsize;
335762306a36Sopenharmony_ci		p = xdr_encode_hyper(p, dummy64);
335862306a36Sopenharmony_ci	}
335962306a36Sopenharmony_ci	if (bmval1 & FATTR4_WORD1_SPACE_TOTAL) {
336062306a36Sopenharmony_ci		p = xdr_reserve_space(xdr, 8);
336162306a36Sopenharmony_ci		if (!p)
336262306a36Sopenharmony_ci			goto out_resource;
336362306a36Sopenharmony_ci		dummy64 = (u64)statfs.f_blocks * (u64)statfs.f_bsize;
336462306a36Sopenharmony_ci		p = xdr_encode_hyper(p, dummy64);
336562306a36Sopenharmony_ci	}
336662306a36Sopenharmony_ci	if (bmval1 & FATTR4_WORD1_SPACE_USED) {
336762306a36Sopenharmony_ci		p = xdr_reserve_space(xdr, 8);
336862306a36Sopenharmony_ci		if (!p)
336962306a36Sopenharmony_ci			goto out_resource;
337062306a36Sopenharmony_ci		dummy64 = (u64)stat.blocks << 9;
337162306a36Sopenharmony_ci		p = xdr_encode_hyper(p, dummy64);
337262306a36Sopenharmony_ci	}
337362306a36Sopenharmony_ci	if (bmval1 & FATTR4_WORD1_TIME_ACCESS) {
337462306a36Sopenharmony_ci		status = nfsd4_encode_nfstime4(xdr, &stat.atime);
337562306a36Sopenharmony_ci		if (status)
337662306a36Sopenharmony_ci			goto out;
337762306a36Sopenharmony_ci	}
337862306a36Sopenharmony_ci	if (bmval1 & FATTR4_WORD1_TIME_CREATE) {
337962306a36Sopenharmony_ci		status = nfsd4_encode_nfstime4(xdr, &stat.btime);
338062306a36Sopenharmony_ci		if (status)
338162306a36Sopenharmony_ci			goto out;
338262306a36Sopenharmony_ci	}
338362306a36Sopenharmony_ci	if (bmval1 & FATTR4_WORD1_TIME_DELTA) {
338462306a36Sopenharmony_ci		p = xdr_reserve_space(xdr, 12);
338562306a36Sopenharmony_ci		if (!p)
338662306a36Sopenharmony_ci			goto out_resource;
338762306a36Sopenharmony_ci		p = encode_time_delta(p, d_inode(dentry));
338862306a36Sopenharmony_ci	}
338962306a36Sopenharmony_ci	if (bmval1 & FATTR4_WORD1_TIME_METADATA) {
339062306a36Sopenharmony_ci		status = nfsd4_encode_nfstime4(xdr, &stat.ctime);
339162306a36Sopenharmony_ci		if (status)
339262306a36Sopenharmony_ci			goto out;
339362306a36Sopenharmony_ci	}
339462306a36Sopenharmony_ci	if (bmval1 & FATTR4_WORD1_TIME_MODIFY) {
339562306a36Sopenharmony_ci		status = nfsd4_encode_nfstime4(xdr, &stat.mtime);
339662306a36Sopenharmony_ci		if (status)
339762306a36Sopenharmony_ci			goto out;
339862306a36Sopenharmony_ci	}
339962306a36Sopenharmony_ci	if (bmval1 & FATTR4_WORD1_MOUNTED_ON_FILEID) {
340062306a36Sopenharmony_ci		u64 ino = stat.ino;
340162306a36Sopenharmony_ci
340262306a36Sopenharmony_ci		p = xdr_reserve_space(xdr, 8);
340362306a36Sopenharmony_ci		if (!p)
340462306a36Sopenharmony_ci                	goto out_resource;
340562306a36Sopenharmony_ci		/*
340662306a36Sopenharmony_ci		 * Get ino of mountpoint in parent filesystem, if not ignoring
340762306a36Sopenharmony_ci		 * crossmount and this is the root of a cross-mounted
340862306a36Sopenharmony_ci		 * filesystem.
340962306a36Sopenharmony_ci		 */
341062306a36Sopenharmony_ci		if (ignore_crossmnt == 0 &&
341162306a36Sopenharmony_ci		    dentry == exp->ex_path.mnt->mnt_root) {
341262306a36Sopenharmony_ci			err = nfsd4_get_mounted_on_ino(exp, &ino);
341362306a36Sopenharmony_ci			if (err)
341462306a36Sopenharmony_ci				goto out_nfserr;
341562306a36Sopenharmony_ci		}
341662306a36Sopenharmony_ci		p = xdr_encode_hyper(p, ino);
341762306a36Sopenharmony_ci	}
341862306a36Sopenharmony_ci#ifdef CONFIG_NFSD_PNFS
341962306a36Sopenharmony_ci	if (bmval1 & FATTR4_WORD1_FS_LAYOUT_TYPES) {
342062306a36Sopenharmony_ci		status = nfsd4_encode_layout_types(xdr, exp->ex_layout_types);
342162306a36Sopenharmony_ci		if (status)
342262306a36Sopenharmony_ci			goto out;
342362306a36Sopenharmony_ci	}
342462306a36Sopenharmony_ci
342562306a36Sopenharmony_ci	if (bmval2 & FATTR4_WORD2_LAYOUT_TYPES) {
342662306a36Sopenharmony_ci		status = nfsd4_encode_layout_types(xdr, exp->ex_layout_types);
342762306a36Sopenharmony_ci		if (status)
342862306a36Sopenharmony_ci			goto out;
342962306a36Sopenharmony_ci	}
343062306a36Sopenharmony_ci
343162306a36Sopenharmony_ci	if (bmval2 & FATTR4_WORD2_LAYOUT_BLKSIZE) {
343262306a36Sopenharmony_ci		p = xdr_reserve_space(xdr, 4);
343362306a36Sopenharmony_ci		if (!p)
343462306a36Sopenharmony_ci			goto out_resource;
343562306a36Sopenharmony_ci		*p++ = cpu_to_be32(stat.blksize);
343662306a36Sopenharmony_ci	}
343762306a36Sopenharmony_ci#endif /* CONFIG_NFSD_PNFS */
343862306a36Sopenharmony_ci	if (bmval2 & FATTR4_WORD2_SUPPATTR_EXCLCREAT) {
343962306a36Sopenharmony_ci		u32 supp[3];
344062306a36Sopenharmony_ci
344162306a36Sopenharmony_ci		memcpy(supp, nfsd_suppattrs[minorversion], sizeof(supp));
344262306a36Sopenharmony_ci		supp[0] &= NFSD_SUPPATTR_EXCLCREAT_WORD0;
344362306a36Sopenharmony_ci		supp[1] &= NFSD_SUPPATTR_EXCLCREAT_WORD1;
344462306a36Sopenharmony_ci		supp[2] &= NFSD_SUPPATTR_EXCLCREAT_WORD2;
344562306a36Sopenharmony_ci
344662306a36Sopenharmony_ci		status = nfsd4_encode_bitmap(xdr, supp[0], supp[1], supp[2]);
344762306a36Sopenharmony_ci		if (status)
344862306a36Sopenharmony_ci			goto out;
344962306a36Sopenharmony_ci	}
345062306a36Sopenharmony_ci
345162306a36Sopenharmony_ci#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
345262306a36Sopenharmony_ci	if (bmval2 & FATTR4_WORD2_SECURITY_LABEL) {
345362306a36Sopenharmony_ci		status = nfsd4_encode_security_label(xdr, rqstp, context,
345462306a36Sopenharmony_ci								contextlen);
345562306a36Sopenharmony_ci		if (status)
345662306a36Sopenharmony_ci			goto out;
345762306a36Sopenharmony_ci	}
345862306a36Sopenharmony_ci#endif
345962306a36Sopenharmony_ci
346062306a36Sopenharmony_ci	if (bmval2 & FATTR4_WORD2_XATTR_SUPPORT) {
346162306a36Sopenharmony_ci		p = xdr_reserve_space(xdr, 4);
346262306a36Sopenharmony_ci		if (!p)
346362306a36Sopenharmony_ci			goto out_resource;
346462306a36Sopenharmony_ci		err = xattr_supports_user_prefix(d_inode(dentry));
346562306a36Sopenharmony_ci		*p++ = cpu_to_be32(err == 0);
346662306a36Sopenharmony_ci	}
346762306a36Sopenharmony_ci
346862306a36Sopenharmony_ci	*attrlen_p = cpu_to_be32(xdr->buf->len - attrlen_offset - XDR_UNIT);
346962306a36Sopenharmony_ci	status = nfs_ok;
347062306a36Sopenharmony_ci
347162306a36Sopenharmony_ciout:
347262306a36Sopenharmony_ci#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
347362306a36Sopenharmony_ci	if (context)
347462306a36Sopenharmony_ci		security_release_secctx(context, contextlen);
347562306a36Sopenharmony_ci#endif /* CONFIG_NFSD_V4_SECURITY_LABEL */
347662306a36Sopenharmony_ci	kfree(acl);
347762306a36Sopenharmony_ci	if (tempfh) {
347862306a36Sopenharmony_ci		fh_put(tempfh);
347962306a36Sopenharmony_ci		kfree(tempfh);
348062306a36Sopenharmony_ci	}
348162306a36Sopenharmony_ci	if (status)
348262306a36Sopenharmony_ci		xdr_truncate_encode(xdr, starting_len);
348362306a36Sopenharmony_ci	return status;
348462306a36Sopenharmony_ciout_nfserr:
348562306a36Sopenharmony_ci	status = nfserrno(err);
348662306a36Sopenharmony_ci	goto out;
348762306a36Sopenharmony_ciout_resource:
348862306a36Sopenharmony_ci	status = nfserr_resource;
348962306a36Sopenharmony_ci	goto out;
349062306a36Sopenharmony_ci}
349162306a36Sopenharmony_ci
349262306a36Sopenharmony_cistatic void svcxdr_init_encode_from_buffer(struct xdr_stream *xdr,
349362306a36Sopenharmony_ci				struct xdr_buf *buf, __be32 *p, int bytes)
349462306a36Sopenharmony_ci{
349562306a36Sopenharmony_ci	xdr->scratch.iov_len = 0;
349662306a36Sopenharmony_ci	memset(buf, 0, sizeof(struct xdr_buf));
349762306a36Sopenharmony_ci	buf->head[0].iov_base = p;
349862306a36Sopenharmony_ci	buf->head[0].iov_len = 0;
349962306a36Sopenharmony_ci	buf->len = 0;
350062306a36Sopenharmony_ci	xdr->buf = buf;
350162306a36Sopenharmony_ci	xdr->iov = buf->head;
350262306a36Sopenharmony_ci	xdr->p = p;
350362306a36Sopenharmony_ci	xdr->end = (void *)p + bytes;
350462306a36Sopenharmony_ci	buf->buflen = bytes;
350562306a36Sopenharmony_ci}
350662306a36Sopenharmony_ci
350762306a36Sopenharmony_ci__be32 nfsd4_encode_fattr_to_buf(__be32 **p, int words,
350862306a36Sopenharmony_ci			struct svc_fh *fhp, struct svc_export *exp,
350962306a36Sopenharmony_ci			struct dentry *dentry, u32 *bmval,
351062306a36Sopenharmony_ci			struct svc_rqst *rqstp, int ignore_crossmnt)
351162306a36Sopenharmony_ci{
351262306a36Sopenharmony_ci	struct xdr_buf dummy;
351362306a36Sopenharmony_ci	struct xdr_stream xdr;
351462306a36Sopenharmony_ci	__be32 ret;
351562306a36Sopenharmony_ci
351662306a36Sopenharmony_ci	svcxdr_init_encode_from_buffer(&xdr, &dummy, *p, words << 2);
351762306a36Sopenharmony_ci	ret = nfsd4_encode_fattr(&xdr, fhp, exp, dentry, bmval, rqstp,
351862306a36Sopenharmony_ci							ignore_crossmnt);
351962306a36Sopenharmony_ci	*p = xdr.p;
352062306a36Sopenharmony_ci	return ret;
352162306a36Sopenharmony_ci}
352262306a36Sopenharmony_ci
352362306a36Sopenharmony_cistatic inline int attributes_need_mount(u32 *bmval)
352462306a36Sopenharmony_ci{
352562306a36Sopenharmony_ci	if (bmval[0] & ~(FATTR4_WORD0_RDATTR_ERROR | FATTR4_WORD0_LEASE_TIME))
352662306a36Sopenharmony_ci		return 1;
352762306a36Sopenharmony_ci	if (bmval[1] & ~FATTR4_WORD1_MOUNTED_ON_FILEID)
352862306a36Sopenharmony_ci		return 1;
352962306a36Sopenharmony_ci	return 0;
353062306a36Sopenharmony_ci}
353162306a36Sopenharmony_ci
353262306a36Sopenharmony_cistatic __be32
353362306a36Sopenharmony_cinfsd4_encode_dirent_fattr(struct xdr_stream *xdr, struct nfsd4_readdir *cd,
353462306a36Sopenharmony_ci			const char *name, int namlen)
353562306a36Sopenharmony_ci{
353662306a36Sopenharmony_ci	struct svc_export *exp = cd->rd_fhp->fh_export;
353762306a36Sopenharmony_ci	struct dentry *dentry;
353862306a36Sopenharmony_ci	__be32 nfserr;
353962306a36Sopenharmony_ci	int ignore_crossmnt = 0;
354062306a36Sopenharmony_ci
354162306a36Sopenharmony_ci	dentry = lookup_positive_unlocked(name, cd->rd_fhp->fh_dentry, namlen);
354262306a36Sopenharmony_ci	if (IS_ERR(dentry))
354362306a36Sopenharmony_ci		return nfserrno(PTR_ERR(dentry));
354462306a36Sopenharmony_ci
354562306a36Sopenharmony_ci	exp_get(exp);
354662306a36Sopenharmony_ci	/*
354762306a36Sopenharmony_ci	 * In the case of a mountpoint, the client may be asking for
354862306a36Sopenharmony_ci	 * attributes that are only properties of the underlying filesystem
354962306a36Sopenharmony_ci	 * as opposed to the cross-mounted file system. In such a case,
355062306a36Sopenharmony_ci	 * we will not follow the cross mount and will fill the attribtutes
355162306a36Sopenharmony_ci	 * directly from the mountpoint dentry.
355262306a36Sopenharmony_ci	 */
355362306a36Sopenharmony_ci	if (nfsd_mountpoint(dentry, exp)) {
355462306a36Sopenharmony_ci		int err;
355562306a36Sopenharmony_ci
355662306a36Sopenharmony_ci		if (!(exp->ex_flags & NFSEXP_V4ROOT)
355762306a36Sopenharmony_ci				&& !attributes_need_mount(cd->rd_bmval)) {
355862306a36Sopenharmony_ci			ignore_crossmnt = 1;
355962306a36Sopenharmony_ci			goto out_encode;
356062306a36Sopenharmony_ci		}
356162306a36Sopenharmony_ci		/*
356262306a36Sopenharmony_ci		 * Why the heck aren't we just using nfsd_lookup??
356362306a36Sopenharmony_ci		 * Different "."/".." handling?  Something else?
356462306a36Sopenharmony_ci		 * At least, add a comment here to explain....
356562306a36Sopenharmony_ci		 */
356662306a36Sopenharmony_ci		err = nfsd_cross_mnt(cd->rd_rqstp, &dentry, &exp);
356762306a36Sopenharmony_ci		if (err) {
356862306a36Sopenharmony_ci			nfserr = nfserrno(err);
356962306a36Sopenharmony_ci			goto out_put;
357062306a36Sopenharmony_ci		}
357162306a36Sopenharmony_ci		nfserr = check_nfsd_access(exp, cd->rd_rqstp);
357262306a36Sopenharmony_ci		if (nfserr)
357362306a36Sopenharmony_ci			goto out_put;
357462306a36Sopenharmony_ci
357562306a36Sopenharmony_ci	}
357662306a36Sopenharmony_ciout_encode:
357762306a36Sopenharmony_ci	nfserr = nfsd4_encode_fattr(xdr, NULL, exp, dentry, cd->rd_bmval,
357862306a36Sopenharmony_ci					cd->rd_rqstp, ignore_crossmnt);
357962306a36Sopenharmony_ciout_put:
358062306a36Sopenharmony_ci	dput(dentry);
358162306a36Sopenharmony_ci	exp_put(exp);
358262306a36Sopenharmony_ci	return nfserr;
358362306a36Sopenharmony_ci}
358462306a36Sopenharmony_ci
358562306a36Sopenharmony_cistatic __be32 *
358662306a36Sopenharmony_cinfsd4_encode_rdattr_error(struct xdr_stream *xdr, __be32 nfserr)
358762306a36Sopenharmony_ci{
358862306a36Sopenharmony_ci	__be32 *p;
358962306a36Sopenharmony_ci
359062306a36Sopenharmony_ci	p = xdr_reserve_space(xdr, 20);
359162306a36Sopenharmony_ci	if (!p)
359262306a36Sopenharmony_ci		return NULL;
359362306a36Sopenharmony_ci	*p++ = htonl(2);
359462306a36Sopenharmony_ci	*p++ = htonl(FATTR4_WORD0_RDATTR_ERROR); /* bmval0 */
359562306a36Sopenharmony_ci	*p++ = htonl(0);			 /* bmval1 */
359662306a36Sopenharmony_ci
359762306a36Sopenharmony_ci	*p++ = htonl(4);     /* attribute length */
359862306a36Sopenharmony_ci	*p++ = nfserr;       /* no htonl */
359962306a36Sopenharmony_ci	return p;
360062306a36Sopenharmony_ci}
360162306a36Sopenharmony_ci
360262306a36Sopenharmony_cistatic int
360362306a36Sopenharmony_cinfsd4_encode_dirent(void *ccdv, const char *name, int namlen,
360462306a36Sopenharmony_ci		    loff_t offset, u64 ino, unsigned int d_type)
360562306a36Sopenharmony_ci{
360662306a36Sopenharmony_ci	struct readdir_cd *ccd = ccdv;
360762306a36Sopenharmony_ci	struct nfsd4_readdir *cd = container_of(ccd, struct nfsd4_readdir, common);
360862306a36Sopenharmony_ci	struct xdr_stream *xdr = cd->xdr;
360962306a36Sopenharmony_ci	int start_offset = xdr->buf->len;
361062306a36Sopenharmony_ci	int cookie_offset;
361162306a36Sopenharmony_ci	u32 name_and_cookie;
361262306a36Sopenharmony_ci	int entry_bytes;
361362306a36Sopenharmony_ci	__be32 nfserr = nfserr_toosmall;
361462306a36Sopenharmony_ci	__be64 wire_offset;
361562306a36Sopenharmony_ci	__be32 *p;
361662306a36Sopenharmony_ci
361762306a36Sopenharmony_ci	/* In nfsv4, "." and ".." never make it onto the wire.. */
361862306a36Sopenharmony_ci	if (name && isdotent(name, namlen)) {
361962306a36Sopenharmony_ci		cd->common.err = nfs_ok;
362062306a36Sopenharmony_ci		return 0;
362162306a36Sopenharmony_ci	}
362262306a36Sopenharmony_ci
362362306a36Sopenharmony_ci	if (cd->cookie_offset) {
362462306a36Sopenharmony_ci		wire_offset = cpu_to_be64(offset);
362562306a36Sopenharmony_ci		write_bytes_to_xdr_buf(xdr->buf, cd->cookie_offset,
362662306a36Sopenharmony_ci							&wire_offset, 8);
362762306a36Sopenharmony_ci	}
362862306a36Sopenharmony_ci
362962306a36Sopenharmony_ci	p = xdr_reserve_space(xdr, 4);
363062306a36Sopenharmony_ci	if (!p)
363162306a36Sopenharmony_ci		goto fail;
363262306a36Sopenharmony_ci	*p++ = xdr_one;                             /* mark entry present */
363362306a36Sopenharmony_ci	cookie_offset = xdr->buf->len;
363462306a36Sopenharmony_ci	p = xdr_reserve_space(xdr, 3*4 + namlen);
363562306a36Sopenharmony_ci	if (!p)
363662306a36Sopenharmony_ci		goto fail;
363762306a36Sopenharmony_ci	p = xdr_encode_hyper(p, OFFSET_MAX);        /* offset of next entry */
363862306a36Sopenharmony_ci	p = xdr_encode_array(p, name, namlen);      /* name length & name */
363962306a36Sopenharmony_ci
364062306a36Sopenharmony_ci	nfserr = nfsd4_encode_dirent_fattr(xdr, cd, name, namlen);
364162306a36Sopenharmony_ci	switch (nfserr) {
364262306a36Sopenharmony_ci	case nfs_ok:
364362306a36Sopenharmony_ci		break;
364462306a36Sopenharmony_ci	case nfserr_resource:
364562306a36Sopenharmony_ci		nfserr = nfserr_toosmall;
364662306a36Sopenharmony_ci		goto fail;
364762306a36Sopenharmony_ci	case nfserr_noent:
364862306a36Sopenharmony_ci		xdr_truncate_encode(xdr, start_offset);
364962306a36Sopenharmony_ci		goto skip_entry;
365062306a36Sopenharmony_ci	case nfserr_jukebox:
365162306a36Sopenharmony_ci		/*
365262306a36Sopenharmony_ci		 * The pseudoroot should only display dentries that lead to
365362306a36Sopenharmony_ci		 * exports. If we get EJUKEBOX here, then we can't tell whether
365462306a36Sopenharmony_ci		 * this entry should be included. Just fail the whole READDIR
365562306a36Sopenharmony_ci		 * with NFS4ERR_DELAY in that case, and hope that the situation
365662306a36Sopenharmony_ci		 * will resolve itself by the client's next attempt.
365762306a36Sopenharmony_ci		 */
365862306a36Sopenharmony_ci		if (cd->rd_fhp->fh_export->ex_flags & NFSEXP_V4ROOT)
365962306a36Sopenharmony_ci			goto fail;
366062306a36Sopenharmony_ci		fallthrough;
366162306a36Sopenharmony_ci	default:
366262306a36Sopenharmony_ci		/*
366362306a36Sopenharmony_ci		 * If the client requested the RDATTR_ERROR attribute,
366462306a36Sopenharmony_ci		 * we stuff the error code into this attribute
366562306a36Sopenharmony_ci		 * and continue.  If this attribute was not requested,
366662306a36Sopenharmony_ci		 * then in accordance with the spec, we fail the
366762306a36Sopenharmony_ci		 * entire READDIR operation(!)
366862306a36Sopenharmony_ci		 */
366962306a36Sopenharmony_ci		if (!(cd->rd_bmval[0] & FATTR4_WORD0_RDATTR_ERROR))
367062306a36Sopenharmony_ci			goto fail;
367162306a36Sopenharmony_ci		p = nfsd4_encode_rdattr_error(xdr, nfserr);
367262306a36Sopenharmony_ci		if (p == NULL) {
367362306a36Sopenharmony_ci			nfserr = nfserr_toosmall;
367462306a36Sopenharmony_ci			goto fail;
367562306a36Sopenharmony_ci		}
367662306a36Sopenharmony_ci	}
367762306a36Sopenharmony_ci	nfserr = nfserr_toosmall;
367862306a36Sopenharmony_ci	entry_bytes = xdr->buf->len - start_offset;
367962306a36Sopenharmony_ci	if (entry_bytes > cd->rd_maxcount)
368062306a36Sopenharmony_ci		goto fail;
368162306a36Sopenharmony_ci	cd->rd_maxcount -= entry_bytes;
368262306a36Sopenharmony_ci	/*
368362306a36Sopenharmony_ci	 * RFC 3530 14.2.24 describes rd_dircount as only a "hint", and
368462306a36Sopenharmony_ci	 * notes that it could be zero. If it is zero, then the server
368562306a36Sopenharmony_ci	 * should enforce only the rd_maxcount value.
368662306a36Sopenharmony_ci	 */
368762306a36Sopenharmony_ci	if (cd->rd_dircount) {
368862306a36Sopenharmony_ci		name_and_cookie = 4 + 4 * XDR_QUADLEN(namlen) + 8;
368962306a36Sopenharmony_ci		if (name_and_cookie > cd->rd_dircount && cd->cookie_offset)
369062306a36Sopenharmony_ci			goto fail;
369162306a36Sopenharmony_ci		cd->rd_dircount -= min(cd->rd_dircount, name_and_cookie);
369262306a36Sopenharmony_ci		if (!cd->rd_dircount)
369362306a36Sopenharmony_ci			cd->rd_maxcount = 0;
369462306a36Sopenharmony_ci	}
369562306a36Sopenharmony_ci
369662306a36Sopenharmony_ci	cd->cookie_offset = cookie_offset;
369762306a36Sopenharmony_ciskip_entry:
369862306a36Sopenharmony_ci	cd->common.err = nfs_ok;
369962306a36Sopenharmony_ci	return 0;
370062306a36Sopenharmony_cifail:
370162306a36Sopenharmony_ci	xdr_truncate_encode(xdr, start_offset);
370262306a36Sopenharmony_ci	cd->common.err = nfserr;
370362306a36Sopenharmony_ci	return -EINVAL;
370462306a36Sopenharmony_ci}
370562306a36Sopenharmony_ci
370662306a36Sopenharmony_cistatic __be32
370762306a36Sopenharmony_cinfsd4_encode_verifier4(struct xdr_stream *xdr, const nfs4_verifier *verf)
370862306a36Sopenharmony_ci{
370962306a36Sopenharmony_ci	__be32 *p;
371062306a36Sopenharmony_ci
371162306a36Sopenharmony_ci	p = xdr_reserve_space(xdr, NFS4_VERIFIER_SIZE);
371262306a36Sopenharmony_ci	if (!p)
371362306a36Sopenharmony_ci		return nfserr_resource;
371462306a36Sopenharmony_ci	memcpy(p, verf->data, sizeof(verf->data));
371562306a36Sopenharmony_ci	return nfs_ok;
371662306a36Sopenharmony_ci}
371762306a36Sopenharmony_ci
371862306a36Sopenharmony_cistatic __be32
371962306a36Sopenharmony_cinfsd4_encode_clientid4(struct xdr_stream *xdr, const clientid_t *clientid)
372062306a36Sopenharmony_ci{
372162306a36Sopenharmony_ci	__be32 *p;
372262306a36Sopenharmony_ci
372362306a36Sopenharmony_ci	p = xdr_reserve_space(xdr, sizeof(__be64));
372462306a36Sopenharmony_ci	if (!p)
372562306a36Sopenharmony_ci		return nfserr_resource;
372662306a36Sopenharmony_ci	memcpy(p, clientid, sizeof(*clientid));
372762306a36Sopenharmony_ci	return nfs_ok;
372862306a36Sopenharmony_ci}
372962306a36Sopenharmony_ci
373062306a36Sopenharmony_cistatic __be32
373162306a36Sopenharmony_cinfsd4_encode_stateid(struct xdr_stream *xdr, stateid_t *sid)
373262306a36Sopenharmony_ci{
373362306a36Sopenharmony_ci	__be32 *p;
373462306a36Sopenharmony_ci
373562306a36Sopenharmony_ci	p = xdr_reserve_space(xdr, sizeof(stateid_t));
373662306a36Sopenharmony_ci	if (!p)
373762306a36Sopenharmony_ci		return nfserr_resource;
373862306a36Sopenharmony_ci	*p++ = cpu_to_be32(sid->si_generation);
373962306a36Sopenharmony_ci	p = xdr_encode_opaque_fixed(p, &sid->si_opaque,
374062306a36Sopenharmony_ci					sizeof(stateid_opaque_t));
374162306a36Sopenharmony_ci	return 0;
374262306a36Sopenharmony_ci}
374362306a36Sopenharmony_ci
374462306a36Sopenharmony_cistatic __be32
374562306a36Sopenharmony_cinfsd4_encode_access(struct nfsd4_compoundres *resp, __be32 nfserr,
374662306a36Sopenharmony_ci		    union nfsd4_op_u *u)
374762306a36Sopenharmony_ci{
374862306a36Sopenharmony_ci	struct nfsd4_access *access = &u->access;
374962306a36Sopenharmony_ci	struct xdr_stream *xdr = resp->xdr;
375062306a36Sopenharmony_ci	__be32 *p;
375162306a36Sopenharmony_ci
375262306a36Sopenharmony_ci	p = xdr_reserve_space(xdr, 8);
375362306a36Sopenharmony_ci	if (!p)
375462306a36Sopenharmony_ci		return nfserr_resource;
375562306a36Sopenharmony_ci	*p++ = cpu_to_be32(access->ac_supported);
375662306a36Sopenharmony_ci	*p++ = cpu_to_be32(access->ac_resp_access);
375762306a36Sopenharmony_ci	return 0;
375862306a36Sopenharmony_ci}
375962306a36Sopenharmony_ci
376062306a36Sopenharmony_cistatic __be32 nfsd4_encode_bind_conn_to_session(struct nfsd4_compoundres *resp, __be32 nfserr,
376162306a36Sopenharmony_ci						union nfsd4_op_u *u)
376262306a36Sopenharmony_ci{
376362306a36Sopenharmony_ci	struct nfsd4_bind_conn_to_session *bcts = &u->bind_conn_to_session;
376462306a36Sopenharmony_ci	struct xdr_stream *xdr = resp->xdr;
376562306a36Sopenharmony_ci	__be32 *p;
376662306a36Sopenharmony_ci
376762306a36Sopenharmony_ci	p = xdr_reserve_space(xdr, NFS4_MAX_SESSIONID_LEN + 8);
376862306a36Sopenharmony_ci	if (!p)
376962306a36Sopenharmony_ci		return nfserr_resource;
377062306a36Sopenharmony_ci	p = xdr_encode_opaque_fixed(p, bcts->sessionid.data,
377162306a36Sopenharmony_ci					NFS4_MAX_SESSIONID_LEN);
377262306a36Sopenharmony_ci	*p++ = cpu_to_be32(bcts->dir);
377362306a36Sopenharmony_ci	/* Upshifting from TCP to RDMA is not supported */
377462306a36Sopenharmony_ci	*p++ = cpu_to_be32(0);
377562306a36Sopenharmony_ci	return 0;
377662306a36Sopenharmony_ci}
377762306a36Sopenharmony_ci
377862306a36Sopenharmony_cistatic __be32
377962306a36Sopenharmony_cinfsd4_encode_close(struct nfsd4_compoundres *resp, __be32 nfserr,
378062306a36Sopenharmony_ci		   union nfsd4_op_u *u)
378162306a36Sopenharmony_ci{
378262306a36Sopenharmony_ci	struct nfsd4_close *close = &u->close;
378362306a36Sopenharmony_ci	struct xdr_stream *xdr = resp->xdr;
378462306a36Sopenharmony_ci
378562306a36Sopenharmony_ci	return nfsd4_encode_stateid(xdr, &close->cl_stateid);
378662306a36Sopenharmony_ci}
378762306a36Sopenharmony_ci
378862306a36Sopenharmony_ci
378962306a36Sopenharmony_cistatic __be32
379062306a36Sopenharmony_cinfsd4_encode_commit(struct nfsd4_compoundres *resp, __be32 nfserr,
379162306a36Sopenharmony_ci		    union nfsd4_op_u *u)
379262306a36Sopenharmony_ci{
379362306a36Sopenharmony_ci	struct nfsd4_commit *commit = &u->commit;
379462306a36Sopenharmony_ci
379562306a36Sopenharmony_ci	return nfsd4_encode_verifier4(resp->xdr, &commit->co_verf);
379662306a36Sopenharmony_ci}
379762306a36Sopenharmony_ci
379862306a36Sopenharmony_cistatic __be32
379962306a36Sopenharmony_cinfsd4_encode_create(struct nfsd4_compoundres *resp, __be32 nfserr,
380062306a36Sopenharmony_ci		    union nfsd4_op_u *u)
380162306a36Sopenharmony_ci{
380262306a36Sopenharmony_ci	struct nfsd4_create *create = &u->create;
380362306a36Sopenharmony_ci	struct xdr_stream *xdr = resp->xdr;
380462306a36Sopenharmony_ci
380562306a36Sopenharmony_ci	nfserr = nfsd4_encode_change_info4(xdr, &create->cr_cinfo);
380662306a36Sopenharmony_ci	if (nfserr)
380762306a36Sopenharmony_ci		return nfserr;
380862306a36Sopenharmony_ci	return nfsd4_encode_bitmap(xdr, create->cr_bmval[0],
380962306a36Sopenharmony_ci			create->cr_bmval[1], create->cr_bmval[2]);
381062306a36Sopenharmony_ci}
381162306a36Sopenharmony_ci
381262306a36Sopenharmony_cistatic __be32
381362306a36Sopenharmony_cinfsd4_encode_getattr(struct nfsd4_compoundres *resp, __be32 nfserr,
381462306a36Sopenharmony_ci		     union nfsd4_op_u *u)
381562306a36Sopenharmony_ci{
381662306a36Sopenharmony_ci	struct nfsd4_getattr *getattr = &u->getattr;
381762306a36Sopenharmony_ci	struct svc_fh *fhp = getattr->ga_fhp;
381862306a36Sopenharmony_ci	struct xdr_stream *xdr = resp->xdr;
381962306a36Sopenharmony_ci
382062306a36Sopenharmony_ci	return nfsd4_encode_fattr(xdr, fhp, fhp->fh_export, fhp->fh_dentry,
382162306a36Sopenharmony_ci				    getattr->ga_bmval, resp->rqstp, 0);
382262306a36Sopenharmony_ci}
382362306a36Sopenharmony_ci
382462306a36Sopenharmony_cistatic __be32
382562306a36Sopenharmony_cinfsd4_encode_getfh(struct nfsd4_compoundres *resp, __be32 nfserr,
382662306a36Sopenharmony_ci		   union nfsd4_op_u *u)
382762306a36Sopenharmony_ci{
382862306a36Sopenharmony_ci	struct svc_fh **fhpp = &u->getfh;
382962306a36Sopenharmony_ci	struct xdr_stream *xdr = resp->xdr;
383062306a36Sopenharmony_ci	struct svc_fh *fhp = *fhpp;
383162306a36Sopenharmony_ci	unsigned int len;
383262306a36Sopenharmony_ci	__be32 *p;
383362306a36Sopenharmony_ci
383462306a36Sopenharmony_ci	len = fhp->fh_handle.fh_size;
383562306a36Sopenharmony_ci	p = xdr_reserve_space(xdr, len + 4);
383662306a36Sopenharmony_ci	if (!p)
383762306a36Sopenharmony_ci		return nfserr_resource;
383862306a36Sopenharmony_ci	p = xdr_encode_opaque(p, &fhp->fh_handle.fh_raw, len);
383962306a36Sopenharmony_ci	return 0;
384062306a36Sopenharmony_ci}
384162306a36Sopenharmony_ci
384262306a36Sopenharmony_ci/*
384362306a36Sopenharmony_ci* Including all fields other than the name, a LOCK4denied structure requires
384462306a36Sopenharmony_ci*   8(clientid) + 4(namelen) + 8(offset) + 8(length) + 4(type) = 32 bytes.
384562306a36Sopenharmony_ci*/
384662306a36Sopenharmony_cistatic __be32
384762306a36Sopenharmony_cinfsd4_encode_lock_denied(struct xdr_stream *xdr, struct nfsd4_lock_denied *ld)
384862306a36Sopenharmony_ci{
384962306a36Sopenharmony_ci	struct xdr_netobj *conf = &ld->ld_owner;
385062306a36Sopenharmony_ci	__be32 *p;
385162306a36Sopenharmony_ci
385262306a36Sopenharmony_ciagain:
385362306a36Sopenharmony_ci	p = xdr_reserve_space(xdr, 32 + XDR_LEN(conf->len));
385462306a36Sopenharmony_ci	if (!p) {
385562306a36Sopenharmony_ci		/*
385662306a36Sopenharmony_ci		 * Don't fail to return the result just because we can't
385762306a36Sopenharmony_ci		 * return the conflicting open:
385862306a36Sopenharmony_ci		 */
385962306a36Sopenharmony_ci		if (conf->len) {
386062306a36Sopenharmony_ci			kfree(conf->data);
386162306a36Sopenharmony_ci			conf->len = 0;
386262306a36Sopenharmony_ci			conf->data = NULL;
386362306a36Sopenharmony_ci			goto again;
386462306a36Sopenharmony_ci		}
386562306a36Sopenharmony_ci		return nfserr_resource;
386662306a36Sopenharmony_ci	}
386762306a36Sopenharmony_ci	p = xdr_encode_hyper(p, ld->ld_start);
386862306a36Sopenharmony_ci	p = xdr_encode_hyper(p, ld->ld_length);
386962306a36Sopenharmony_ci	*p++ = cpu_to_be32(ld->ld_type);
387062306a36Sopenharmony_ci	if (conf->len) {
387162306a36Sopenharmony_ci		p = xdr_encode_opaque_fixed(p, &ld->ld_clientid, 8);
387262306a36Sopenharmony_ci		p = xdr_encode_opaque(p, conf->data, conf->len);
387362306a36Sopenharmony_ci		kfree(conf->data);
387462306a36Sopenharmony_ci	}  else {  /* non - nfsv4 lock in conflict, no clientid nor owner */
387562306a36Sopenharmony_ci		p = xdr_encode_hyper(p, (u64)0); /* clientid */
387662306a36Sopenharmony_ci		*p++ = cpu_to_be32(0); /* length of owner name */
387762306a36Sopenharmony_ci	}
387862306a36Sopenharmony_ci	return nfserr_denied;
387962306a36Sopenharmony_ci}
388062306a36Sopenharmony_ci
388162306a36Sopenharmony_cistatic __be32
388262306a36Sopenharmony_cinfsd4_encode_lock(struct nfsd4_compoundres *resp, __be32 nfserr,
388362306a36Sopenharmony_ci		  union nfsd4_op_u *u)
388462306a36Sopenharmony_ci{
388562306a36Sopenharmony_ci	struct nfsd4_lock *lock = &u->lock;
388662306a36Sopenharmony_ci	struct xdr_stream *xdr = resp->xdr;
388762306a36Sopenharmony_ci
388862306a36Sopenharmony_ci	if (!nfserr)
388962306a36Sopenharmony_ci		nfserr = nfsd4_encode_stateid(xdr, &lock->lk_resp_stateid);
389062306a36Sopenharmony_ci	else if (nfserr == nfserr_denied)
389162306a36Sopenharmony_ci		nfserr = nfsd4_encode_lock_denied(xdr, &lock->lk_denied);
389262306a36Sopenharmony_ci
389362306a36Sopenharmony_ci	return nfserr;
389462306a36Sopenharmony_ci}
389562306a36Sopenharmony_ci
389662306a36Sopenharmony_cistatic __be32
389762306a36Sopenharmony_cinfsd4_encode_lockt(struct nfsd4_compoundres *resp, __be32 nfserr,
389862306a36Sopenharmony_ci		   union nfsd4_op_u *u)
389962306a36Sopenharmony_ci{
390062306a36Sopenharmony_ci	struct nfsd4_lockt *lockt = &u->lockt;
390162306a36Sopenharmony_ci	struct xdr_stream *xdr = resp->xdr;
390262306a36Sopenharmony_ci
390362306a36Sopenharmony_ci	if (nfserr == nfserr_denied)
390462306a36Sopenharmony_ci		nfsd4_encode_lock_denied(xdr, &lockt->lt_denied);
390562306a36Sopenharmony_ci	return nfserr;
390662306a36Sopenharmony_ci}
390762306a36Sopenharmony_ci
390862306a36Sopenharmony_cistatic __be32
390962306a36Sopenharmony_cinfsd4_encode_locku(struct nfsd4_compoundres *resp, __be32 nfserr,
391062306a36Sopenharmony_ci		   union nfsd4_op_u *u)
391162306a36Sopenharmony_ci{
391262306a36Sopenharmony_ci	struct nfsd4_locku *locku = &u->locku;
391362306a36Sopenharmony_ci	struct xdr_stream *xdr = resp->xdr;
391462306a36Sopenharmony_ci
391562306a36Sopenharmony_ci	return nfsd4_encode_stateid(xdr, &locku->lu_stateid);
391662306a36Sopenharmony_ci}
391762306a36Sopenharmony_ci
391862306a36Sopenharmony_ci
391962306a36Sopenharmony_cistatic __be32
392062306a36Sopenharmony_cinfsd4_encode_link(struct nfsd4_compoundres *resp, __be32 nfserr,
392162306a36Sopenharmony_ci		  union nfsd4_op_u *u)
392262306a36Sopenharmony_ci{
392362306a36Sopenharmony_ci	struct nfsd4_link *link = &u->link;
392462306a36Sopenharmony_ci	struct xdr_stream *xdr = resp->xdr;
392562306a36Sopenharmony_ci
392662306a36Sopenharmony_ci	return nfsd4_encode_change_info4(xdr, &link->li_cinfo);
392762306a36Sopenharmony_ci}
392862306a36Sopenharmony_ci
392962306a36Sopenharmony_ci
393062306a36Sopenharmony_cistatic __be32
393162306a36Sopenharmony_cinfsd4_encode_open(struct nfsd4_compoundres *resp, __be32 nfserr,
393262306a36Sopenharmony_ci		  union nfsd4_op_u *u)
393362306a36Sopenharmony_ci{
393462306a36Sopenharmony_ci	struct nfsd4_open *open = &u->open;
393562306a36Sopenharmony_ci	struct xdr_stream *xdr = resp->xdr;
393662306a36Sopenharmony_ci	__be32 *p;
393762306a36Sopenharmony_ci
393862306a36Sopenharmony_ci	nfserr = nfsd4_encode_stateid(xdr, &open->op_stateid);
393962306a36Sopenharmony_ci	if (nfserr)
394062306a36Sopenharmony_ci		return nfserr;
394162306a36Sopenharmony_ci	nfserr = nfsd4_encode_change_info4(xdr, &open->op_cinfo);
394262306a36Sopenharmony_ci	if (nfserr)
394362306a36Sopenharmony_ci		return nfserr;
394462306a36Sopenharmony_ci	if (xdr_stream_encode_u32(xdr, open->op_rflags) < 0)
394562306a36Sopenharmony_ci		return nfserr_resource;
394662306a36Sopenharmony_ci
394762306a36Sopenharmony_ci	nfserr = nfsd4_encode_bitmap(xdr, open->op_bmval[0], open->op_bmval[1],
394862306a36Sopenharmony_ci					open->op_bmval[2]);
394962306a36Sopenharmony_ci	if (nfserr)
395062306a36Sopenharmony_ci		return nfserr;
395162306a36Sopenharmony_ci
395262306a36Sopenharmony_ci	p = xdr_reserve_space(xdr, 4);
395362306a36Sopenharmony_ci	if (!p)
395462306a36Sopenharmony_ci		return nfserr_resource;
395562306a36Sopenharmony_ci
395662306a36Sopenharmony_ci	*p++ = cpu_to_be32(open->op_delegate_type);
395762306a36Sopenharmony_ci	switch (open->op_delegate_type) {
395862306a36Sopenharmony_ci	case NFS4_OPEN_DELEGATE_NONE:
395962306a36Sopenharmony_ci		break;
396062306a36Sopenharmony_ci	case NFS4_OPEN_DELEGATE_READ:
396162306a36Sopenharmony_ci		nfserr = nfsd4_encode_stateid(xdr, &open->op_delegate_stateid);
396262306a36Sopenharmony_ci		if (nfserr)
396362306a36Sopenharmony_ci			return nfserr;
396462306a36Sopenharmony_ci		p = xdr_reserve_space(xdr, 20);
396562306a36Sopenharmony_ci		if (!p)
396662306a36Sopenharmony_ci			return nfserr_resource;
396762306a36Sopenharmony_ci		*p++ = cpu_to_be32(open->op_recall);
396862306a36Sopenharmony_ci
396962306a36Sopenharmony_ci		/*
397062306a36Sopenharmony_ci		 * TODO: ACE's in delegations
397162306a36Sopenharmony_ci		 */
397262306a36Sopenharmony_ci		*p++ = cpu_to_be32(NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE);
397362306a36Sopenharmony_ci		*p++ = cpu_to_be32(0);
397462306a36Sopenharmony_ci		*p++ = cpu_to_be32(0);
397562306a36Sopenharmony_ci		*p++ = cpu_to_be32(0);   /* XXX: is NULL principal ok? */
397662306a36Sopenharmony_ci		break;
397762306a36Sopenharmony_ci	case NFS4_OPEN_DELEGATE_WRITE:
397862306a36Sopenharmony_ci		nfserr = nfsd4_encode_stateid(xdr, &open->op_delegate_stateid);
397962306a36Sopenharmony_ci		if (nfserr)
398062306a36Sopenharmony_ci			return nfserr;
398162306a36Sopenharmony_ci
398262306a36Sopenharmony_ci		p = xdr_reserve_space(xdr, XDR_UNIT * 8);
398362306a36Sopenharmony_ci		if (!p)
398462306a36Sopenharmony_ci			return nfserr_resource;
398562306a36Sopenharmony_ci		*p++ = cpu_to_be32(open->op_recall);
398662306a36Sopenharmony_ci
398762306a36Sopenharmony_ci		/*
398862306a36Sopenharmony_ci		 * Always flush on close
398962306a36Sopenharmony_ci		 *
399062306a36Sopenharmony_ci		 * TODO: space_limit's in delegations
399162306a36Sopenharmony_ci		 */
399262306a36Sopenharmony_ci		*p++ = cpu_to_be32(NFS4_LIMIT_SIZE);
399362306a36Sopenharmony_ci		*p++ = xdr_zero;
399462306a36Sopenharmony_ci		*p++ = xdr_zero;
399562306a36Sopenharmony_ci
399662306a36Sopenharmony_ci		/*
399762306a36Sopenharmony_ci		 * TODO: ACE's in delegations
399862306a36Sopenharmony_ci		 */
399962306a36Sopenharmony_ci		*p++ = cpu_to_be32(NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE);
400062306a36Sopenharmony_ci		*p++ = cpu_to_be32(0);
400162306a36Sopenharmony_ci		*p++ = cpu_to_be32(0);
400262306a36Sopenharmony_ci		*p++ = cpu_to_be32(0);   /* XXX: is NULL principal ok? */
400362306a36Sopenharmony_ci		break;
400462306a36Sopenharmony_ci	case NFS4_OPEN_DELEGATE_NONE_EXT: /* 4.1 */
400562306a36Sopenharmony_ci		switch (open->op_why_no_deleg) {
400662306a36Sopenharmony_ci		case WND4_CONTENTION:
400762306a36Sopenharmony_ci		case WND4_RESOURCE:
400862306a36Sopenharmony_ci			p = xdr_reserve_space(xdr, 8);
400962306a36Sopenharmony_ci			if (!p)
401062306a36Sopenharmony_ci				return nfserr_resource;
401162306a36Sopenharmony_ci			*p++ = cpu_to_be32(open->op_why_no_deleg);
401262306a36Sopenharmony_ci			/* deleg signaling not supported yet: */
401362306a36Sopenharmony_ci			*p++ = cpu_to_be32(0);
401462306a36Sopenharmony_ci			break;
401562306a36Sopenharmony_ci		default:
401662306a36Sopenharmony_ci			p = xdr_reserve_space(xdr, 4);
401762306a36Sopenharmony_ci			if (!p)
401862306a36Sopenharmony_ci				return nfserr_resource;
401962306a36Sopenharmony_ci			*p++ = cpu_to_be32(open->op_why_no_deleg);
402062306a36Sopenharmony_ci		}
402162306a36Sopenharmony_ci		break;
402262306a36Sopenharmony_ci	default:
402362306a36Sopenharmony_ci		BUG();
402462306a36Sopenharmony_ci	}
402562306a36Sopenharmony_ci	/* XXX save filehandle here */
402662306a36Sopenharmony_ci	return 0;
402762306a36Sopenharmony_ci}
402862306a36Sopenharmony_ci
402962306a36Sopenharmony_cistatic __be32
403062306a36Sopenharmony_cinfsd4_encode_open_confirm(struct nfsd4_compoundres *resp, __be32 nfserr,
403162306a36Sopenharmony_ci			  union nfsd4_op_u *u)
403262306a36Sopenharmony_ci{
403362306a36Sopenharmony_ci	struct nfsd4_open_confirm *oc = &u->open_confirm;
403462306a36Sopenharmony_ci	struct xdr_stream *xdr = resp->xdr;
403562306a36Sopenharmony_ci
403662306a36Sopenharmony_ci	return nfsd4_encode_stateid(xdr, &oc->oc_resp_stateid);
403762306a36Sopenharmony_ci}
403862306a36Sopenharmony_ci
403962306a36Sopenharmony_cistatic __be32
404062306a36Sopenharmony_cinfsd4_encode_open_downgrade(struct nfsd4_compoundres *resp, __be32 nfserr,
404162306a36Sopenharmony_ci			    union nfsd4_op_u *u)
404262306a36Sopenharmony_ci{
404362306a36Sopenharmony_ci	struct nfsd4_open_downgrade *od = &u->open_downgrade;
404462306a36Sopenharmony_ci	struct xdr_stream *xdr = resp->xdr;
404562306a36Sopenharmony_ci
404662306a36Sopenharmony_ci	return nfsd4_encode_stateid(xdr, &od->od_stateid);
404762306a36Sopenharmony_ci}
404862306a36Sopenharmony_ci
404962306a36Sopenharmony_ci/*
405062306a36Sopenharmony_ci * The operation of this function assumes that this is the only
405162306a36Sopenharmony_ci * READ operation in the COMPOUND. If there are multiple READs,
405262306a36Sopenharmony_ci * we use nfsd4_encode_readv().
405362306a36Sopenharmony_ci */
405462306a36Sopenharmony_cistatic __be32 nfsd4_encode_splice_read(
405562306a36Sopenharmony_ci				struct nfsd4_compoundres *resp,
405662306a36Sopenharmony_ci				struct nfsd4_read *read,
405762306a36Sopenharmony_ci				struct file *file, unsigned long maxcount)
405862306a36Sopenharmony_ci{
405962306a36Sopenharmony_ci	struct xdr_stream *xdr = resp->xdr;
406062306a36Sopenharmony_ci	struct xdr_buf *buf = xdr->buf;
406162306a36Sopenharmony_ci	int status, space_left;
406262306a36Sopenharmony_ci	__be32 nfserr;
406362306a36Sopenharmony_ci
406462306a36Sopenharmony_ci	/*
406562306a36Sopenharmony_ci	 * Make sure there is room at the end of buf->head for
406662306a36Sopenharmony_ci	 * svcxdr_encode_opaque_pages() to create a tail buffer
406762306a36Sopenharmony_ci	 * to XDR-pad the payload.
406862306a36Sopenharmony_ci	 */
406962306a36Sopenharmony_ci	if (xdr->iov != xdr->buf->head || xdr->end - xdr->p < 1)
407062306a36Sopenharmony_ci		return nfserr_resource;
407162306a36Sopenharmony_ci
407262306a36Sopenharmony_ci	nfserr = nfsd_splice_read(read->rd_rqstp, read->rd_fhp,
407362306a36Sopenharmony_ci				  file, read->rd_offset, &maxcount,
407462306a36Sopenharmony_ci				  &read->rd_eof);
407562306a36Sopenharmony_ci	read->rd_length = maxcount;
407662306a36Sopenharmony_ci	if (nfserr)
407762306a36Sopenharmony_ci		goto out_err;
407862306a36Sopenharmony_ci	svcxdr_encode_opaque_pages(read->rd_rqstp, xdr, buf->pages,
407962306a36Sopenharmony_ci				   buf->page_base, maxcount);
408062306a36Sopenharmony_ci	status = svc_encode_result_payload(read->rd_rqstp,
408162306a36Sopenharmony_ci					   buf->head[0].iov_len, maxcount);
408262306a36Sopenharmony_ci	if (status) {
408362306a36Sopenharmony_ci		nfserr = nfserrno(status);
408462306a36Sopenharmony_ci		goto out_err;
408562306a36Sopenharmony_ci	}
408662306a36Sopenharmony_ci
408762306a36Sopenharmony_ci	/*
408862306a36Sopenharmony_ci	 * Prepare to encode subsequent operations.
408962306a36Sopenharmony_ci	 *
409062306a36Sopenharmony_ci	 * xdr_truncate_encode() is not safe to use after a successful
409162306a36Sopenharmony_ci	 * splice read has been done, so the following stream
409262306a36Sopenharmony_ci	 * manipulations are open-coded.
409362306a36Sopenharmony_ci	 */
409462306a36Sopenharmony_ci	space_left = min_t(int, (void *)xdr->end - (void *)xdr->p,
409562306a36Sopenharmony_ci				buf->buflen - buf->len);
409662306a36Sopenharmony_ci	buf->buflen = buf->len + space_left;
409762306a36Sopenharmony_ci	xdr->end = (__be32 *)((void *)xdr->end + space_left);
409862306a36Sopenharmony_ci
409962306a36Sopenharmony_ci	return nfs_ok;
410062306a36Sopenharmony_ci
410162306a36Sopenharmony_ciout_err:
410262306a36Sopenharmony_ci	/*
410362306a36Sopenharmony_ci	 * nfsd_splice_actor may have already messed with the
410462306a36Sopenharmony_ci	 * page length; reset it so as not to confuse
410562306a36Sopenharmony_ci	 * xdr_truncate_encode in our caller.
410662306a36Sopenharmony_ci	 */
410762306a36Sopenharmony_ci	buf->page_len = 0;
410862306a36Sopenharmony_ci	return nfserr;
410962306a36Sopenharmony_ci}
411062306a36Sopenharmony_ci
411162306a36Sopenharmony_cistatic __be32 nfsd4_encode_readv(struct nfsd4_compoundres *resp,
411262306a36Sopenharmony_ci				 struct nfsd4_read *read,
411362306a36Sopenharmony_ci				 struct file *file, unsigned long maxcount)
411462306a36Sopenharmony_ci{
411562306a36Sopenharmony_ci	struct xdr_stream *xdr = resp->xdr;
411662306a36Sopenharmony_ci	unsigned int base = xdr->buf->page_len & ~PAGE_MASK;
411762306a36Sopenharmony_ci	unsigned int starting_len = xdr->buf->len;
411862306a36Sopenharmony_ci	__be32 zero = xdr_zero;
411962306a36Sopenharmony_ci	__be32 nfserr;
412062306a36Sopenharmony_ci
412162306a36Sopenharmony_ci	if (xdr_reserve_space_vec(xdr, maxcount) < 0)
412262306a36Sopenharmony_ci		return nfserr_resource;
412362306a36Sopenharmony_ci
412462306a36Sopenharmony_ci	nfserr = nfsd_iter_read(resp->rqstp, read->rd_fhp, file,
412562306a36Sopenharmony_ci				read->rd_offset, &maxcount, base,
412662306a36Sopenharmony_ci				&read->rd_eof);
412762306a36Sopenharmony_ci	read->rd_length = maxcount;
412862306a36Sopenharmony_ci	if (nfserr)
412962306a36Sopenharmony_ci		return nfserr;
413062306a36Sopenharmony_ci	if (svc_encode_result_payload(resp->rqstp, starting_len, maxcount))
413162306a36Sopenharmony_ci		return nfserr_io;
413262306a36Sopenharmony_ci	xdr_truncate_encode(xdr, starting_len + xdr_align_size(maxcount));
413362306a36Sopenharmony_ci
413462306a36Sopenharmony_ci	write_bytes_to_xdr_buf(xdr->buf, starting_len + maxcount, &zero,
413562306a36Sopenharmony_ci			       xdr_pad_size(maxcount));
413662306a36Sopenharmony_ci	return nfs_ok;
413762306a36Sopenharmony_ci}
413862306a36Sopenharmony_ci
413962306a36Sopenharmony_cistatic __be32
414062306a36Sopenharmony_cinfsd4_encode_read(struct nfsd4_compoundres *resp, __be32 nfserr,
414162306a36Sopenharmony_ci		  union nfsd4_op_u *u)
414262306a36Sopenharmony_ci{
414362306a36Sopenharmony_ci	struct nfsd4_read *read = &u->read;
414462306a36Sopenharmony_ci	bool splice_ok = test_bit(RQ_SPLICE_OK, &resp->rqstp->rq_flags);
414562306a36Sopenharmony_ci	unsigned long maxcount;
414662306a36Sopenharmony_ci	struct xdr_stream *xdr = resp->xdr;
414762306a36Sopenharmony_ci	struct file *file;
414862306a36Sopenharmony_ci	int starting_len = xdr->buf->len;
414962306a36Sopenharmony_ci	__be32 *p;
415062306a36Sopenharmony_ci
415162306a36Sopenharmony_ci	if (nfserr)
415262306a36Sopenharmony_ci		return nfserr;
415362306a36Sopenharmony_ci	file = read->rd_nf->nf_file;
415462306a36Sopenharmony_ci
415562306a36Sopenharmony_ci	p = xdr_reserve_space(xdr, 8); /* eof flag and byte count */
415662306a36Sopenharmony_ci	if (!p) {
415762306a36Sopenharmony_ci		WARN_ON_ONCE(splice_ok);
415862306a36Sopenharmony_ci		return nfserr_resource;
415962306a36Sopenharmony_ci	}
416062306a36Sopenharmony_ci	if (resp->xdr->buf->page_len && splice_ok) {
416162306a36Sopenharmony_ci		WARN_ON_ONCE(1);
416262306a36Sopenharmony_ci		return nfserr_serverfault;
416362306a36Sopenharmony_ci	}
416462306a36Sopenharmony_ci	xdr_commit_encode(xdr);
416562306a36Sopenharmony_ci
416662306a36Sopenharmony_ci	maxcount = min_t(unsigned long, read->rd_length,
416762306a36Sopenharmony_ci			 (xdr->buf->buflen - xdr->buf->len));
416862306a36Sopenharmony_ci
416962306a36Sopenharmony_ci	if (file->f_op->splice_read && splice_ok)
417062306a36Sopenharmony_ci		nfserr = nfsd4_encode_splice_read(resp, read, file, maxcount);
417162306a36Sopenharmony_ci	else
417262306a36Sopenharmony_ci		nfserr = nfsd4_encode_readv(resp, read, file, maxcount);
417362306a36Sopenharmony_ci	if (nfserr) {
417462306a36Sopenharmony_ci		xdr_truncate_encode(xdr, starting_len);
417562306a36Sopenharmony_ci		return nfserr;
417662306a36Sopenharmony_ci	}
417762306a36Sopenharmony_ci
417862306a36Sopenharmony_ci	p = xdr_encode_bool(p, read->rd_eof);
417962306a36Sopenharmony_ci	*p = cpu_to_be32(read->rd_length);
418062306a36Sopenharmony_ci	return nfs_ok;
418162306a36Sopenharmony_ci}
418262306a36Sopenharmony_ci
418362306a36Sopenharmony_cistatic __be32
418462306a36Sopenharmony_cinfsd4_encode_readlink(struct nfsd4_compoundres *resp, __be32 nfserr,
418562306a36Sopenharmony_ci		      union nfsd4_op_u *u)
418662306a36Sopenharmony_ci{
418762306a36Sopenharmony_ci	struct nfsd4_readlink *readlink = &u->readlink;
418862306a36Sopenharmony_ci	__be32 *p, *maxcount_p, zero = xdr_zero;
418962306a36Sopenharmony_ci	struct xdr_stream *xdr = resp->xdr;
419062306a36Sopenharmony_ci	int length_offset = xdr->buf->len;
419162306a36Sopenharmony_ci	int maxcount, status;
419262306a36Sopenharmony_ci
419362306a36Sopenharmony_ci	maxcount_p = xdr_reserve_space(xdr, XDR_UNIT);
419462306a36Sopenharmony_ci	if (!maxcount_p)
419562306a36Sopenharmony_ci		return nfserr_resource;
419662306a36Sopenharmony_ci	maxcount = PAGE_SIZE;
419762306a36Sopenharmony_ci
419862306a36Sopenharmony_ci	p = xdr_reserve_space(xdr, maxcount);
419962306a36Sopenharmony_ci	if (!p)
420062306a36Sopenharmony_ci		return nfserr_resource;
420162306a36Sopenharmony_ci	/*
420262306a36Sopenharmony_ci	 * XXX: By default, vfs_readlink() will truncate symlinks if they
420362306a36Sopenharmony_ci	 * would overflow the buffer.  Is this kosher in NFSv4?  If not, one
420462306a36Sopenharmony_ci	 * easy fix is: if vfs_readlink() precisely fills the buffer, assume
420562306a36Sopenharmony_ci	 * that truncation occurred, and return NFS4ERR_RESOURCE.
420662306a36Sopenharmony_ci	 */
420762306a36Sopenharmony_ci	nfserr = nfsd_readlink(readlink->rl_rqstp, readlink->rl_fhp,
420862306a36Sopenharmony_ci						(char *)p, &maxcount);
420962306a36Sopenharmony_ci	if (nfserr == nfserr_isdir)
421062306a36Sopenharmony_ci		nfserr = nfserr_inval;
421162306a36Sopenharmony_ci	if (nfserr)
421262306a36Sopenharmony_ci		goto out_err;
421362306a36Sopenharmony_ci	status = svc_encode_result_payload(readlink->rl_rqstp, length_offset,
421462306a36Sopenharmony_ci					   maxcount);
421562306a36Sopenharmony_ci	if (status) {
421662306a36Sopenharmony_ci		nfserr = nfserrno(status);
421762306a36Sopenharmony_ci		goto out_err;
421862306a36Sopenharmony_ci	}
421962306a36Sopenharmony_ci	*maxcount_p = cpu_to_be32(maxcount);
422062306a36Sopenharmony_ci	xdr_truncate_encode(xdr, length_offset + 4 + xdr_align_size(maxcount));
422162306a36Sopenharmony_ci	write_bytes_to_xdr_buf(xdr->buf, length_offset + 4 + maxcount, &zero,
422262306a36Sopenharmony_ci			       xdr_pad_size(maxcount));
422362306a36Sopenharmony_ci	return nfs_ok;
422462306a36Sopenharmony_ci
422562306a36Sopenharmony_ciout_err:
422662306a36Sopenharmony_ci	xdr_truncate_encode(xdr, length_offset);
422762306a36Sopenharmony_ci	return nfserr;
422862306a36Sopenharmony_ci}
422962306a36Sopenharmony_ci
423062306a36Sopenharmony_cistatic __be32
423162306a36Sopenharmony_cinfsd4_encode_readdir(struct nfsd4_compoundres *resp, __be32 nfserr,
423262306a36Sopenharmony_ci		     union nfsd4_op_u *u)
423362306a36Sopenharmony_ci{
423462306a36Sopenharmony_ci	struct nfsd4_readdir *readdir = &u->readdir;
423562306a36Sopenharmony_ci	int maxcount;
423662306a36Sopenharmony_ci	int bytes_left;
423762306a36Sopenharmony_ci	loff_t offset;
423862306a36Sopenharmony_ci	__be64 wire_offset;
423962306a36Sopenharmony_ci	struct xdr_stream *xdr = resp->xdr;
424062306a36Sopenharmony_ci	int starting_len = xdr->buf->len;
424162306a36Sopenharmony_ci	__be32 *p;
424262306a36Sopenharmony_ci
424362306a36Sopenharmony_ci	nfserr = nfsd4_encode_verifier4(xdr, &readdir->rd_verf);
424462306a36Sopenharmony_ci	if (nfserr != nfs_ok)
424562306a36Sopenharmony_ci		return nfserr;
424662306a36Sopenharmony_ci
424762306a36Sopenharmony_ci	/*
424862306a36Sopenharmony_ci	 * Number of bytes left for directory entries allowing for the
424962306a36Sopenharmony_ci	 * final 8 bytes of the readdir and a following failed op:
425062306a36Sopenharmony_ci	 */
425162306a36Sopenharmony_ci	bytes_left = xdr->buf->buflen - xdr->buf->len
425262306a36Sopenharmony_ci			- COMPOUND_ERR_SLACK_SPACE - 8;
425362306a36Sopenharmony_ci	if (bytes_left < 0) {
425462306a36Sopenharmony_ci		nfserr = nfserr_resource;
425562306a36Sopenharmony_ci		goto err_no_verf;
425662306a36Sopenharmony_ci	}
425762306a36Sopenharmony_ci	maxcount = svc_max_payload(resp->rqstp);
425862306a36Sopenharmony_ci	maxcount = min_t(u32, readdir->rd_maxcount, maxcount);
425962306a36Sopenharmony_ci	/*
426062306a36Sopenharmony_ci	 * Note the rfc defines rd_maxcount as the size of the
426162306a36Sopenharmony_ci	 * READDIR4resok structure, which includes the verifier above
426262306a36Sopenharmony_ci	 * and the 8 bytes encoded at the end of this function:
426362306a36Sopenharmony_ci	 */
426462306a36Sopenharmony_ci	if (maxcount < 16) {
426562306a36Sopenharmony_ci		nfserr = nfserr_toosmall;
426662306a36Sopenharmony_ci		goto err_no_verf;
426762306a36Sopenharmony_ci	}
426862306a36Sopenharmony_ci	maxcount = min_t(int, maxcount-16, bytes_left);
426962306a36Sopenharmony_ci
427062306a36Sopenharmony_ci	/* RFC 3530 14.2.24 allows us to ignore dircount when it's 0: */
427162306a36Sopenharmony_ci	if (!readdir->rd_dircount)
427262306a36Sopenharmony_ci		readdir->rd_dircount = svc_max_payload(resp->rqstp);
427362306a36Sopenharmony_ci
427462306a36Sopenharmony_ci	readdir->xdr = xdr;
427562306a36Sopenharmony_ci	readdir->rd_maxcount = maxcount;
427662306a36Sopenharmony_ci	readdir->common.err = 0;
427762306a36Sopenharmony_ci	readdir->cookie_offset = 0;
427862306a36Sopenharmony_ci
427962306a36Sopenharmony_ci	offset = readdir->rd_cookie;
428062306a36Sopenharmony_ci	nfserr = nfsd_readdir(readdir->rd_rqstp, readdir->rd_fhp,
428162306a36Sopenharmony_ci			      &offset,
428262306a36Sopenharmony_ci			      &readdir->common, nfsd4_encode_dirent);
428362306a36Sopenharmony_ci	if (nfserr == nfs_ok &&
428462306a36Sopenharmony_ci	    readdir->common.err == nfserr_toosmall &&
428562306a36Sopenharmony_ci	    xdr->buf->len == starting_len + 8) {
428662306a36Sopenharmony_ci		/* nothing encoded; which limit did we hit?: */
428762306a36Sopenharmony_ci		if (maxcount - 16 < bytes_left)
428862306a36Sopenharmony_ci			/* It was the fault of rd_maxcount: */
428962306a36Sopenharmony_ci			nfserr = nfserr_toosmall;
429062306a36Sopenharmony_ci		else
429162306a36Sopenharmony_ci			/* We ran out of buffer space: */
429262306a36Sopenharmony_ci			nfserr = nfserr_resource;
429362306a36Sopenharmony_ci	}
429462306a36Sopenharmony_ci	if (nfserr)
429562306a36Sopenharmony_ci		goto err_no_verf;
429662306a36Sopenharmony_ci
429762306a36Sopenharmony_ci	if (readdir->cookie_offset) {
429862306a36Sopenharmony_ci		wire_offset = cpu_to_be64(offset);
429962306a36Sopenharmony_ci		write_bytes_to_xdr_buf(xdr->buf, readdir->cookie_offset,
430062306a36Sopenharmony_ci							&wire_offset, 8);
430162306a36Sopenharmony_ci	}
430262306a36Sopenharmony_ci
430362306a36Sopenharmony_ci	p = xdr_reserve_space(xdr, 8);
430462306a36Sopenharmony_ci	if (!p) {
430562306a36Sopenharmony_ci		WARN_ON_ONCE(1);
430662306a36Sopenharmony_ci		goto err_no_verf;
430762306a36Sopenharmony_ci	}
430862306a36Sopenharmony_ci	*p++ = 0;	/* no more entries */
430962306a36Sopenharmony_ci	*p++ = htonl(readdir->common.err == nfserr_eof);
431062306a36Sopenharmony_ci
431162306a36Sopenharmony_ci	return 0;
431262306a36Sopenharmony_cierr_no_verf:
431362306a36Sopenharmony_ci	xdr_truncate_encode(xdr, starting_len);
431462306a36Sopenharmony_ci	return nfserr;
431562306a36Sopenharmony_ci}
431662306a36Sopenharmony_ci
431762306a36Sopenharmony_cistatic __be32
431862306a36Sopenharmony_cinfsd4_encode_remove(struct nfsd4_compoundres *resp, __be32 nfserr,
431962306a36Sopenharmony_ci		    union nfsd4_op_u *u)
432062306a36Sopenharmony_ci{
432162306a36Sopenharmony_ci	struct nfsd4_remove *remove = &u->remove;
432262306a36Sopenharmony_ci	struct xdr_stream *xdr = resp->xdr;
432362306a36Sopenharmony_ci
432462306a36Sopenharmony_ci	return nfsd4_encode_change_info4(xdr, &remove->rm_cinfo);
432562306a36Sopenharmony_ci}
432662306a36Sopenharmony_ci
432762306a36Sopenharmony_cistatic __be32
432862306a36Sopenharmony_cinfsd4_encode_rename(struct nfsd4_compoundres *resp, __be32 nfserr,
432962306a36Sopenharmony_ci		    union nfsd4_op_u *u)
433062306a36Sopenharmony_ci{
433162306a36Sopenharmony_ci	struct nfsd4_rename *rename = &u->rename;
433262306a36Sopenharmony_ci	struct xdr_stream *xdr = resp->xdr;
433362306a36Sopenharmony_ci
433462306a36Sopenharmony_ci	nfserr = nfsd4_encode_change_info4(xdr, &rename->rn_sinfo);
433562306a36Sopenharmony_ci	if (nfserr)
433662306a36Sopenharmony_ci		return nfserr;
433762306a36Sopenharmony_ci	return nfsd4_encode_change_info4(xdr, &rename->rn_tinfo);
433862306a36Sopenharmony_ci}
433962306a36Sopenharmony_ci
434062306a36Sopenharmony_cistatic __be32
434162306a36Sopenharmony_cinfsd4_do_encode_secinfo(struct xdr_stream *xdr, struct svc_export *exp)
434262306a36Sopenharmony_ci{
434362306a36Sopenharmony_ci	u32 i, nflavs, supported;
434462306a36Sopenharmony_ci	struct exp_flavor_info *flavs;
434562306a36Sopenharmony_ci	struct exp_flavor_info def_flavs[2];
434662306a36Sopenharmony_ci	__be32 *p, *flavorsp;
434762306a36Sopenharmony_ci	static bool report = true;
434862306a36Sopenharmony_ci
434962306a36Sopenharmony_ci	if (exp->ex_nflavors) {
435062306a36Sopenharmony_ci		flavs = exp->ex_flavors;
435162306a36Sopenharmony_ci		nflavs = exp->ex_nflavors;
435262306a36Sopenharmony_ci	} else { /* Handling of some defaults in absence of real secinfo: */
435362306a36Sopenharmony_ci		flavs = def_flavs;
435462306a36Sopenharmony_ci		if (exp->ex_client->flavour->flavour == RPC_AUTH_UNIX) {
435562306a36Sopenharmony_ci			nflavs = 2;
435662306a36Sopenharmony_ci			flavs[0].pseudoflavor = RPC_AUTH_UNIX;
435762306a36Sopenharmony_ci			flavs[1].pseudoflavor = RPC_AUTH_NULL;
435862306a36Sopenharmony_ci		} else if (exp->ex_client->flavour->flavour == RPC_AUTH_GSS) {
435962306a36Sopenharmony_ci			nflavs = 1;
436062306a36Sopenharmony_ci			flavs[0].pseudoflavor
436162306a36Sopenharmony_ci					= svcauth_gss_flavor(exp->ex_client);
436262306a36Sopenharmony_ci		} else {
436362306a36Sopenharmony_ci			nflavs = 1;
436462306a36Sopenharmony_ci			flavs[0].pseudoflavor
436562306a36Sopenharmony_ci					= exp->ex_client->flavour->flavour;
436662306a36Sopenharmony_ci		}
436762306a36Sopenharmony_ci	}
436862306a36Sopenharmony_ci
436962306a36Sopenharmony_ci	supported = 0;
437062306a36Sopenharmony_ci	p = xdr_reserve_space(xdr, 4);
437162306a36Sopenharmony_ci	if (!p)
437262306a36Sopenharmony_ci		return nfserr_resource;
437362306a36Sopenharmony_ci	flavorsp = p++;		/* to be backfilled later */
437462306a36Sopenharmony_ci
437562306a36Sopenharmony_ci	for (i = 0; i < nflavs; i++) {
437662306a36Sopenharmony_ci		rpc_authflavor_t pf = flavs[i].pseudoflavor;
437762306a36Sopenharmony_ci		struct rpcsec_gss_info info;
437862306a36Sopenharmony_ci
437962306a36Sopenharmony_ci		if (rpcauth_get_gssinfo(pf, &info) == 0) {
438062306a36Sopenharmony_ci			supported++;
438162306a36Sopenharmony_ci			p = xdr_reserve_space(xdr, 4 + 4 +
438262306a36Sopenharmony_ci					      XDR_LEN(info.oid.len) + 4 + 4);
438362306a36Sopenharmony_ci			if (!p)
438462306a36Sopenharmony_ci				return nfserr_resource;
438562306a36Sopenharmony_ci			*p++ = cpu_to_be32(RPC_AUTH_GSS);
438662306a36Sopenharmony_ci			p = xdr_encode_opaque(p,  info.oid.data, info.oid.len);
438762306a36Sopenharmony_ci			*p++ = cpu_to_be32(info.qop);
438862306a36Sopenharmony_ci			*p++ = cpu_to_be32(info.service);
438962306a36Sopenharmony_ci		} else if (pf < RPC_AUTH_MAXFLAVOR) {
439062306a36Sopenharmony_ci			supported++;
439162306a36Sopenharmony_ci			p = xdr_reserve_space(xdr, 4);
439262306a36Sopenharmony_ci			if (!p)
439362306a36Sopenharmony_ci				return nfserr_resource;
439462306a36Sopenharmony_ci			*p++ = cpu_to_be32(pf);
439562306a36Sopenharmony_ci		} else {
439662306a36Sopenharmony_ci			if (report)
439762306a36Sopenharmony_ci				pr_warn("NFS: SECINFO: security flavor %u "
439862306a36Sopenharmony_ci					"is not supported\n", pf);
439962306a36Sopenharmony_ci		}
440062306a36Sopenharmony_ci	}
440162306a36Sopenharmony_ci
440262306a36Sopenharmony_ci	if (nflavs != supported)
440362306a36Sopenharmony_ci		report = false;
440462306a36Sopenharmony_ci	*flavorsp = htonl(supported);
440562306a36Sopenharmony_ci	return 0;
440662306a36Sopenharmony_ci}
440762306a36Sopenharmony_ci
440862306a36Sopenharmony_cistatic __be32
440962306a36Sopenharmony_cinfsd4_encode_secinfo(struct nfsd4_compoundres *resp, __be32 nfserr,
441062306a36Sopenharmony_ci		     union nfsd4_op_u *u)
441162306a36Sopenharmony_ci{
441262306a36Sopenharmony_ci	struct nfsd4_secinfo *secinfo = &u->secinfo;
441362306a36Sopenharmony_ci	struct xdr_stream *xdr = resp->xdr;
441462306a36Sopenharmony_ci
441562306a36Sopenharmony_ci	return nfsd4_do_encode_secinfo(xdr, secinfo->si_exp);
441662306a36Sopenharmony_ci}
441762306a36Sopenharmony_ci
441862306a36Sopenharmony_cistatic __be32
441962306a36Sopenharmony_cinfsd4_encode_secinfo_no_name(struct nfsd4_compoundres *resp, __be32 nfserr,
442062306a36Sopenharmony_ci		     union nfsd4_op_u *u)
442162306a36Sopenharmony_ci{
442262306a36Sopenharmony_ci	struct nfsd4_secinfo_no_name *secinfo = &u->secinfo_no_name;
442362306a36Sopenharmony_ci	struct xdr_stream *xdr = resp->xdr;
442462306a36Sopenharmony_ci
442562306a36Sopenharmony_ci	return nfsd4_do_encode_secinfo(xdr, secinfo->sin_exp);
442662306a36Sopenharmony_ci}
442762306a36Sopenharmony_ci
442862306a36Sopenharmony_ci/*
442962306a36Sopenharmony_ci * The SETATTR encode routine is special -- it always encodes a bitmap,
443062306a36Sopenharmony_ci * regardless of the error status.
443162306a36Sopenharmony_ci */
443262306a36Sopenharmony_cistatic __be32
443362306a36Sopenharmony_cinfsd4_encode_setattr(struct nfsd4_compoundres *resp, __be32 nfserr,
443462306a36Sopenharmony_ci		     union nfsd4_op_u *u)
443562306a36Sopenharmony_ci{
443662306a36Sopenharmony_ci	struct nfsd4_setattr *setattr = &u->setattr;
443762306a36Sopenharmony_ci	struct xdr_stream *xdr = resp->xdr;
443862306a36Sopenharmony_ci	__be32 *p;
443962306a36Sopenharmony_ci
444062306a36Sopenharmony_ci	p = xdr_reserve_space(xdr, 16);
444162306a36Sopenharmony_ci	if (!p)
444262306a36Sopenharmony_ci		return nfserr_resource;
444362306a36Sopenharmony_ci	if (nfserr) {
444462306a36Sopenharmony_ci		*p++ = cpu_to_be32(3);
444562306a36Sopenharmony_ci		*p++ = cpu_to_be32(0);
444662306a36Sopenharmony_ci		*p++ = cpu_to_be32(0);
444762306a36Sopenharmony_ci		*p++ = cpu_to_be32(0);
444862306a36Sopenharmony_ci	}
444962306a36Sopenharmony_ci	else {
445062306a36Sopenharmony_ci		*p++ = cpu_to_be32(3);
445162306a36Sopenharmony_ci		*p++ = cpu_to_be32(setattr->sa_bmval[0]);
445262306a36Sopenharmony_ci		*p++ = cpu_to_be32(setattr->sa_bmval[1]);
445362306a36Sopenharmony_ci		*p++ = cpu_to_be32(setattr->sa_bmval[2]);
445462306a36Sopenharmony_ci	}
445562306a36Sopenharmony_ci	return nfserr;
445662306a36Sopenharmony_ci}
445762306a36Sopenharmony_ci
445862306a36Sopenharmony_cistatic __be32
445962306a36Sopenharmony_cinfsd4_encode_setclientid(struct nfsd4_compoundres *resp, __be32 nfserr,
446062306a36Sopenharmony_ci			 union nfsd4_op_u *u)
446162306a36Sopenharmony_ci{
446262306a36Sopenharmony_ci	struct nfsd4_setclientid *scd = &u->setclientid;
446362306a36Sopenharmony_ci	struct xdr_stream *xdr = resp->xdr;
446462306a36Sopenharmony_ci
446562306a36Sopenharmony_ci	if (!nfserr) {
446662306a36Sopenharmony_ci		nfserr = nfsd4_encode_clientid4(xdr, &scd->se_clientid);
446762306a36Sopenharmony_ci		if (nfserr != nfs_ok)
446862306a36Sopenharmony_ci			goto out;
446962306a36Sopenharmony_ci		nfserr = nfsd4_encode_verifier4(xdr, &scd->se_confirm);
447062306a36Sopenharmony_ci	} else if (nfserr == nfserr_clid_inuse) {
447162306a36Sopenharmony_ci		/* empty network id */
447262306a36Sopenharmony_ci		if (xdr_stream_encode_u32(xdr, 0) < 0) {
447362306a36Sopenharmony_ci			nfserr = nfserr_resource;
447462306a36Sopenharmony_ci			goto out;
447562306a36Sopenharmony_ci		}
447662306a36Sopenharmony_ci		/* empty universal address */
447762306a36Sopenharmony_ci		if (xdr_stream_encode_u32(xdr, 0) < 0) {
447862306a36Sopenharmony_ci			nfserr = nfserr_resource;
447962306a36Sopenharmony_ci			goto out;
448062306a36Sopenharmony_ci		}
448162306a36Sopenharmony_ci	}
448262306a36Sopenharmony_ciout:
448362306a36Sopenharmony_ci	return nfserr;
448462306a36Sopenharmony_ci}
448562306a36Sopenharmony_ci
448662306a36Sopenharmony_cistatic __be32
448762306a36Sopenharmony_cinfsd4_encode_write(struct nfsd4_compoundres *resp, __be32 nfserr,
448862306a36Sopenharmony_ci		   union nfsd4_op_u *u)
448962306a36Sopenharmony_ci{
449062306a36Sopenharmony_ci	struct nfsd4_write *write = &u->write;
449162306a36Sopenharmony_ci
449262306a36Sopenharmony_ci	if (xdr_stream_encode_u32(resp->xdr, write->wr_bytes_written) < 0)
449362306a36Sopenharmony_ci		return nfserr_resource;
449462306a36Sopenharmony_ci	if (xdr_stream_encode_u32(resp->xdr, write->wr_how_written) < 0)
449562306a36Sopenharmony_ci		return nfserr_resource;
449662306a36Sopenharmony_ci	return nfsd4_encode_verifier4(resp->xdr, &write->wr_verifier);
449762306a36Sopenharmony_ci}
449862306a36Sopenharmony_ci
449962306a36Sopenharmony_cistatic __be32
450062306a36Sopenharmony_cinfsd4_encode_exchange_id(struct nfsd4_compoundres *resp, __be32 nfserr,
450162306a36Sopenharmony_ci			 union nfsd4_op_u *u)
450262306a36Sopenharmony_ci{
450362306a36Sopenharmony_ci	struct nfsd4_exchange_id *exid = &u->exchange_id;
450462306a36Sopenharmony_ci	struct xdr_stream *xdr = resp->xdr;
450562306a36Sopenharmony_ci	__be32 *p;
450662306a36Sopenharmony_ci	char *major_id;
450762306a36Sopenharmony_ci	char *server_scope;
450862306a36Sopenharmony_ci	int major_id_sz;
450962306a36Sopenharmony_ci	int server_scope_sz;
451062306a36Sopenharmony_ci	uint64_t minor_id = 0;
451162306a36Sopenharmony_ci	struct nfsd_net *nn = net_generic(SVC_NET(resp->rqstp), nfsd_net_id);
451262306a36Sopenharmony_ci
451362306a36Sopenharmony_ci	major_id = nn->nfsd_name;
451462306a36Sopenharmony_ci	major_id_sz = strlen(nn->nfsd_name);
451562306a36Sopenharmony_ci	server_scope = nn->nfsd_name;
451662306a36Sopenharmony_ci	server_scope_sz = strlen(nn->nfsd_name);
451762306a36Sopenharmony_ci
451862306a36Sopenharmony_ci	if (nfsd4_encode_clientid4(xdr, &exid->clientid) != nfs_ok)
451962306a36Sopenharmony_ci		return nfserr_resource;
452062306a36Sopenharmony_ci	if (xdr_stream_encode_u32(xdr, exid->seqid) < 0)
452162306a36Sopenharmony_ci		return nfserr_resource;
452262306a36Sopenharmony_ci	if (xdr_stream_encode_u32(xdr, exid->flags) < 0)
452362306a36Sopenharmony_ci		return nfserr_resource;
452462306a36Sopenharmony_ci
452562306a36Sopenharmony_ci	if (xdr_stream_encode_u32(xdr, exid->spa_how) < 0)
452662306a36Sopenharmony_ci		return nfserr_resource;
452762306a36Sopenharmony_ci	switch (exid->spa_how) {
452862306a36Sopenharmony_ci	case SP4_NONE:
452962306a36Sopenharmony_ci		break;
453062306a36Sopenharmony_ci	case SP4_MACH_CRED:
453162306a36Sopenharmony_ci		/* spo_must_enforce bitmap: */
453262306a36Sopenharmony_ci		nfserr = nfsd4_encode_bitmap(xdr,
453362306a36Sopenharmony_ci					exid->spo_must_enforce[0],
453462306a36Sopenharmony_ci					exid->spo_must_enforce[1],
453562306a36Sopenharmony_ci					exid->spo_must_enforce[2]);
453662306a36Sopenharmony_ci		if (nfserr)
453762306a36Sopenharmony_ci			return nfserr;
453862306a36Sopenharmony_ci		/* spo_must_allow bitmap: */
453962306a36Sopenharmony_ci		nfserr = nfsd4_encode_bitmap(xdr,
454062306a36Sopenharmony_ci					exid->spo_must_allow[0],
454162306a36Sopenharmony_ci					exid->spo_must_allow[1],
454262306a36Sopenharmony_ci					exid->spo_must_allow[2]);
454362306a36Sopenharmony_ci		if (nfserr)
454462306a36Sopenharmony_ci			return nfserr;
454562306a36Sopenharmony_ci		break;
454662306a36Sopenharmony_ci	default:
454762306a36Sopenharmony_ci		WARN_ON_ONCE(1);
454862306a36Sopenharmony_ci	}
454962306a36Sopenharmony_ci
455062306a36Sopenharmony_ci	p = xdr_reserve_space(xdr,
455162306a36Sopenharmony_ci		8 /* so_minor_id */ +
455262306a36Sopenharmony_ci		4 /* so_major_id.len */ +
455362306a36Sopenharmony_ci		(XDR_QUADLEN(major_id_sz) * 4) +
455462306a36Sopenharmony_ci		4 /* eir_server_scope.len */ +
455562306a36Sopenharmony_ci		(XDR_QUADLEN(server_scope_sz) * 4) +
455662306a36Sopenharmony_ci		4 /* eir_server_impl_id.count (0) */);
455762306a36Sopenharmony_ci	if (!p)
455862306a36Sopenharmony_ci		return nfserr_resource;
455962306a36Sopenharmony_ci
456062306a36Sopenharmony_ci	/* The server_owner struct */
456162306a36Sopenharmony_ci	p = xdr_encode_hyper(p, minor_id);      /* Minor id */
456262306a36Sopenharmony_ci	/* major id */
456362306a36Sopenharmony_ci	p = xdr_encode_opaque(p, major_id, major_id_sz);
456462306a36Sopenharmony_ci
456562306a36Sopenharmony_ci	/* Server scope */
456662306a36Sopenharmony_ci	p = xdr_encode_opaque(p, server_scope, server_scope_sz);
456762306a36Sopenharmony_ci
456862306a36Sopenharmony_ci	/* Implementation id */
456962306a36Sopenharmony_ci	*p++ = cpu_to_be32(0);	/* zero length nfs_impl_id4 array */
457062306a36Sopenharmony_ci	return 0;
457162306a36Sopenharmony_ci}
457262306a36Sopenharmony_ci
457362306a36Sopenharmony_cistatic __be32
457462306a36Sopenharmony_cinfsd4_encode_create_session(struct nfsd4_compoundres *resp, __be32 nfserr,
457562306a36Sopenharmony_ci			    union nfsd4_op_u *u)
457662306a36Sopenharmony_ci{
457762306a36Sopenharmony_ci	struct nfsd4_create_session *sess = &u->create_session;
457862306a36Sopenharmony_ci	struct xdr_stream *xdr = resp->xdr;
457962306a36Sopenharmony_ci	__be32 *p;
458062306a36Sopenharmony_ci
458162306a36Sopenharmony_ci	p = xdr_reserve_space(xdr, 24);
458262306a36Sopenharmony_ci	if (!p)
458362306a36Sopenharmony_ci		return nfserr_resource;
458462306a36Sopenharmony_ci	p = xdr_encode_opaque_fixed(p, sess->sessionid.data,
458562306a36Sopenharmony_ci					NFS4_MAX_SESSIONID_LEN);
458662306a36Sopenharmony_ci	*p++ = cpu_to_be32(sess->seqid);
458762306a36Sopenharmony_ci	*p++ = cpu_to_be32(sess->flags);
458862306a36Sopenharmony_ci
458962306a36Sopenharmony_ci	p = xdr_reserve_space(xdr, 28);
459062306a36Sopenharmony_ci	if (!p)
459162306a36Sopenharmony_ci		return nfserr_resource;
459262306a36Sopenharmony_ci	*p++ = cpu_to_be32(0); /* headerpadsz */
459362306a36Sopenharmony_ci	*p++ = cpu_to_be32(sess->fore_channel.maxreq_sz);
459462306a36Sopenharmony_ci	*p++ = cpu_to_be32(sess->fore_channel.maxresp_sz);
459562306a36Sopenharmony_ci	*p++ = cpu_to_be32(sess->fore_channel.maxresp_cached);
459662306a36Sopenharmony_ci	*p++ = cpu_to_be32(sess->fore_channel.maxops);
459762306a36Sopenharmony_ci	*p++ = cpu_to_be32(sess->fore_channel.maxreqs);
459862306a36Sopenharmony_ci	*p++ = cpu_to_be32(sess->fore_channel.nr_rdma_attrs);
459962306a36Sopenharmony_ci
460062306a36Sopenharmony_ci	if (sess->fore_channel.nr_rdma_attrs) {
460162306a36Sopenharmony_ci		p = xdr_reserve_space(xdr, 4);
460262306a36Sopenharmony_ci		if (!p)
460362306a36Sopenharmony_ci			return nfserr_resource;
460462306a36Sopenharmony_ci		*p++ = cpu_to_be32(sess->fore_channel.rdma_attrs);
460562306a36Sopenharmony_ci	}
460662306a36Sopenharmony_ci
460762306a36Sopenharmony_ci	p = xdr_reserve_space(xdr, 28);
460862306a36Sopenharmony_ci	if (!p)
460962306a36Sopenharmony_ci		return nfserr_resource;
461062306a36Sopenharmony_ci	*p++ = cpu_to_be32(0); /* headerpadsz */
461162306a36Sopenharmony_ci	*p++ = cpu_to_be32(sess->back_channel.maxreq_sz);
461262306a36Sopenharmony_ci	*p++ = cpu_to_be32(sess->back_channel.maxresp_sz);
461362306a36Sopenharmony_ci	*p++ = cpu_to_be32(sess->back_channel.maxresp_cached);
461462306a36Sopenharmony_ci	*p++ = cpu_to_be32(sess->back_channel.maxops);
461562306a36Sopenharmony_ci	*p++ = cpu_to_be32(sess->back_channel.maxreqs);
461662306a36Sopenharmony_ci	*p++ = cpu_to_be32(sess->back_channel.nr_rdma_attrs);
461762306a36Sopenharmony_ci
461862306a36Sopenharmony_ci	if (sess->back_channel.nr_rdma_attrs) {
461962306a36Sopenharmony_ci		p = xdr_reserve_space(xdr, 4);
462062306a36Sopenharmony_ci		if (!p)
462162306a36Sopenharmony_ci			return nfserr_resource;
462262306a36Sopenharmony_ci		*p++ = cpu_to_be32(sess->back_channel.rdma_attrs);
462362306a36Sopenharmony_ci	}
462462306a36Sopenharmony_ci	return 0;
462562306a36Sopenharmony_ci}
462662306a36Sopenharmony_ci
462762306a36Sopenharmony_cistatic __be32
462862306a36Sopenharmony_cinfsd4_encode_sequence(struct nfsd4_compoundres *resp, __be32 nfserr,
462962306a36Sopenharmony_ci		      union nfsd4_op_u *u)
463062306a36Sopenharmony_ci{
463162306a36Sopenharmony_ci	struct nfsd4_sequence *seq = &u->sequence;
463262306a36Sopenharmony_ci	struct xdr_stream *xdr = resp->xdr;
463362306a36Sopenharmony_ci	__be32 *p;
463462306a36Sopenharmony_ci
463562306a36Sopenharmony_ci	p = xdr_reserve_space(xdr, NFS4_MAX_SESSIONID_LEN + 20);
463662306a36Sopenharmony_ci	if (!p)
463762306a36Sopenharmony_ci		return nfserr_resource;
463862306a36Sopenharmony_ci	p = xdr_encode_opaque_fixed(p, seq->sessionid.data,
463962306a36Sopenharmony_ci					NFS4_MAX_SESSIONID_LEN);
464062306a36Sopenharmony_ci	*p++ = cpu_to_be32(seq->seqid);
464162306a36Sopenharmony_ci	*p++ = cpu_to_be32(seq->slotid);
464262306a36Sopenharmony_ci	/* Note slotid's are numbered from zero: */
464362306a36Sopenharmony_ci	*p++ = cpu_to_be32(seq->maxslots - 1); /* sr_highest_slotid */
464462306a36Sopenharmony_ci	*p++ = cpu_to_be32(seq->maxslots - 1); /* sr_target_highest_slotid */
464562306a36Sopenharmony_ci	*p++ = cpu_to_be32(seq->status_flags);
464662306a36Sopenharmony_ci
464762306a36Sopenharmony_ci	resp->cstate.data_offset = xdr->buf->len; /* DRC cache data pointer */
464862306a36Sopenharmony_ci	return 0;
464962306a36Sopenharmony_ci}
465062306a36Sopenharmony_ci
465162306a36Sopenharmony_cistatic __be32
465262306a36Sopenharmony_cinfsd4_encode_test_stateid(struct nfsd4_compoundres *resp, __be32 nfserr,
465362306a36Sopenharmony_ci			  union nfsd4_op_u *u)
465462306a36Sopenharmony_ci{
465562306a36Sopenharmony_ci	struct nfsd4_test_stateid *test_stateid = &u->test_stateid;
465662306a36Sopenharmony_ci	struct xdr_stream *xdr = resp->xdr;
465762306a36Sopenharmony_ci	struct nfsd4_test_stateid_id *stateid, *next;
465862306a36Sopenharmony_ci	__be32 *p;
465962306a36Sopenharmony_ci
466062306a36Sopenharmony_ci	p = xdr_reserve_space(xdr, 4 + (4 * test_stateid->ts_num_ids));
466162306a36Sopenharmony_ci	if (!p)
466262306a36Sopenharmony_ci		return nfserr_resource;
466362306a36Sopenharmony_ci	*p++ = htonl(test_stateid->ts_num_ids);
466462306a36Sopenharmony_ci
466562306a36Sopenharmony_ci	list_for_each_entry_safe(stateid, next, &test_stateid->ts_stateid_list, ts_id_list) {
466662306a36Sopenharmony_ci		*p++ = stateid->ts_id_status;
466762306a36Sopenharmony_ci	}
466862306a36Sopenharmony_ci
466962306a36Sopenharmony_ci	return 0;
467062306a36Sopenharmony_ci}
467162306a36Sopenharmony_ci
467262306a36Sopenharmony_ci#ifdef CONFIG_NFSD_PNFS
467362306a36Sopenharmony_cistatic __be32
467462306a36Sopenharmony_cinfsd4_encode_getdeviceinfo(struct nfsd4_compoundres *resp, __be32 nfserr,
467562306a36Sopenharmony_ci		union nfsd4_op_u *u)
467662306a36Sopenharmony_ci{
467762306a36Sopenharmony_ci	struct nfsd4_getdeviceinfo *gdev = &u->getdeviceinfo;
467862306a36Sopenharmony_ci	struct xdr_stream *xdr = resp->xdr;
467962306a36Sopenharmony_ci	const struct nfsd4_layout_ops *ops;
468062306a36Sopenharmony_ci	u32 starting_len = xdr->buf->len, needed_len;
468162306a36Sopenharmony_ci	__be32 *p;
468262306a36Sopenharmony_ci
468362306a36Sopenharmony_ci	p = xdr_reserve_space(xdr, 4);
468462306a36Sopenharmony_ci	if (!p)
468562306a36Sopenharmony_ci		return nfserr_resource;
468662306a36Sopenharmony_ci
468762306a36Sopenharmony_ci	*p++ = cpu_to_be32(gdev->gd_layout_type);
468862306a36Sopenharmony_ci
468962306a36Sopenharmony_ci	ops = nfsd4_layout_ops[gdev->gd_layout_type];
469062306a36Sopenharmony_ci	nfserr = ops->encode_getdeviceinfo(xdr, gdev);
469162306a36Sopenharmony_ci	if (nfserr) {
469262306a36Sopenharmony_ci		/*
469362306a36Sopenharmony_ci		 * We don't bother to burden the layout drivers with
469462306a36Sopenharmony_ci		 * enforcing gd_maxcount, just tell the client to
469562306a36Sopenharmony_ci		 * come back with a bigger buffer if it's not enough.
469662306a36Sopenharmony_ci		 */
469762306a36Sopenharmony_ci		if (xdr->buf->len + 4 > gdev->gd_maxcount)
469862306a36Sopenharmony_ci			goto toosmall;
469962306a36Sopenharmony_ci		return nfserr;
470062306a36Sopenharmony_ci	}
470162306a36Sopenharmony_ci
470262306a36Sopenharmony_ci	if (gdev->gd_notify_types) {
470362306a36Sopenharmony_ci		p = xdr_reserve_space(xdr, 4 + 4);
470462306a36Sopenharmony_ci		if (!p)
470562306a36Sopenharmony_ci			return nfserr_resource;
470662306a36Sopenharmony_ci		*p++ = cpu_to_be32(1);			/* bitmap length */
470762306a36Sopenharmony_ci		*p++ = cpu_to_be32(gdev->gd_notify_types);
470862306a36Sopenharmony_ci	} else {
470962306a36Sopenharmony_ci		p = xdr_reserve_space(xdr, 4);
471062306a36Sopenharmony_ci		if (!p)
471162306a36Sopenharmony_ci			return nfserr_resource;
471262306a36Sopenharmony_ci		*p++ = 0;
471362306a36Sopenharmony_ci	}
471462306a36Sopenharmony_ci
471562306a36Sopenharmony_ci	return 0;
471662306a36Sopenharmony_citoosmall:
471762306a36Sopenharmony_ci	dprintk("%s: maxcount too small\n", __func__);
471862306a36Sopenharmony_ci	needed_len = xdr->buf->len + 4 /* notifications */;
471962306a36Sopenharmony_ci	xdr_truncate_encode(xdr, starting_len);
472062306a36Sopenharmony_ci	p = xdr_reserve_space(xdr, 4);
472162306a36Sopenharmony_ci	if (!p)
472262306a36Sopenharmony_ci		return nfserr_resource;
472362306a36Sopenharmony_ci	*p++ = cpu_to_be32(needed_len);
472462306a36Sopenharmony_ci	return nfserr_toosmall;
472562306a36Sopenharmony_ci}
472662306a36Sopenharmony_ci
472762306a36Sopenharmony_cistatic __be32
472862306a36Sopenharmony_cinfsd4_encode_layoutget(struct nfsd4_compoundres *resp, __be32 nfserr,
472962306a36Sopenharmony_ci		union nfsd4_op_u *u)
473062306a36Sopenharmony_ci{
473162306a36Sopenharmony_ci	struct nfsd4_layoutget *lgp = &u->layoutget;
473262306a36Sopenharmony_ci	struct xdr_stream *xdr = resp->xdr;
473362306a36Sopenharmony_ci	const struct nfsd4_layout_ops *ops;
473462306a36Sopenharmony_ci	__be32 *p;
473562306a36Sopenharmony_ci
473662306a36Sopenharmony_ci	p = xdr_reserve_space(xdr, 36 + sizeof(stateid_opaque_t));
473762306a36Sopenharmony_ci	if (!p)
473862306a36Sopenharmony_ci		return nfserr_resource;
473962306a36Sopenharmony_ci
474062306a36Sopenharmony_ci	*p++ = cpu_to_be32(1);	/* we always set return-on-close */
474162306a36Sopenharmony_ci	*p++ = cpu_to_be32(lgp->lg_sid.si_generation);
474262306a36Sopenharmony_ci	p = xdr_encode_opaque_fixed(p, &lgp->lg_sid.si_opaque,
474362306a36Sopenharmony_ci				    sizeof(stateid_opaque_t));
474462306a36Sopenharmony_ci
474562306a36Sopenharmony_ci	*p++ = cpu_to_be32(1);	/* we always return a single layout */
474662306a36Sopenharmony_ci	p = xdr_encode_hyper(p, lgp->lg_seg.offset);
474762306a36Sopenharmony_ci	p = xdr_encode_hyper(p, lgp->lg_seg.length);
474862306a36Sopenharmony_ci	*p++ = cpu_to_be32(lgp->lg_seg.iomode);
474962306a36Sopenharmony_ci	*p++ = cpu_to_be32(lgp->lg_layout_type);
475062306a36Sopenharmony_ci
475162306a36Sopenharmony_ci	ops = nfsd4_layout_ops[lgp->lg_layout_type];
475262306a36Sopenharmony_ci	return ops->encode_layoutget(xdr, lgp);
475362306a36Sopenharmony_ci}
475462306a36Sopenharmony_ci
475562306a36Sopenharmony_cistatic __be32
475662306a36Sopenharmony_cinfsd4_encode_layoutcommit(struct nfsd4_compoundres *resp, __be32 nfserr,
475762306a36Sopenharmony_ci			  union nfsd4_op_u *u)
475862306a36Sopenharmony_ci{
475962306a36Sopenharmony_ci	struct nfsd4_layoutcommit *lcp = &u->layoutcommit;
476062306a36Sopenharmony_ci	struct xdr_stream *xdr = resp->xdr;
476162306a36Sopenharmony_ci	__be32 *p;
476262306a36Sopenharmony_ci
476362306a36Sopenharmony_ci	p = xdr_reserve_space(xdr, 4);
476462306a36Sopenharmony_ci	if (!p)
476562306a36Sopenharmony_ci		return nfserr_resource;
476662306a36Sopenharmony_ci	*p++ = cpu_to_be32(lcp->lc_size_chg);
476762306a36Sopenharmony_ci	if (lcp->lc_size_chg) {
476862306a36Sopenharmony_ci		p = xdr_reserve_space(xdr, 8);
476962306a36Sopenharmony_ci		if (!p)
477062306a36Sopenharmony_ci			return nfserr_resource;
477162306a36Sopenharmony_ci		p = xdr_encode_hyper(p, lcp->lc_newsize);
477262306a36Sopenharmony_ci	}
477362306a36Sopenharmony_ci
477462306a36Sopenharmony_ci	return 0;
477562306a36Sopenharmony_ci}
477662306a36Sopenharmony_ci
477762306a36Sopenharmony_cistatic __be32
477862306a36Sopenharmony_cinfsd4_encode_layoutreturn(struct nfsd4_compoundres *resp, __be32 nfserr,
477962306a36Sopenharmony_ci		union nfsd4_op_u *u)
478062306a36Sopenharmony_ci{
478162306a36Sopenharmony_ci	struct nfsd4_layoutreturn *lrp = &u->layoutreturn;
478262306a36Sopenharmony_ci	struct xdr_stream *xdr = resp->xdr;
478362306a36Sopenharmony_ci	__be32 *p;
478462306a36Sopenharmony_ci
478562306a36Sopenharmony_ci	p = xdr_reserve_space(xdr, 4);
478662306a36Sopenharmony_ci	if (!p)
478762306a36Sopenharmony_ci		return nfserr_resource;
478862306a36Sopenharmony_ci	*p++ = cpu_to_be32(lrp->lrs_present);
478962306a36Sopenharmony_ci	if (lrp->lrs_present)
479062306a36Sopenharmony_ci		return nfsd4_encode_stateid(xdr, &lrp->lr_sid);
479162306a36Sopenharmony_ci	return 0;
479262306a36Sopenharmony_ci}
479362306a36Sopenharmony_ci#endif /* CONFIG_NFSD_PNFS */
479462306a36Sopenharmony_ci
479562306a36Sopenharmony_cistatic __be32
479662306a36Sopenharmony_cinfsd42_encode_write_res(struct nfsd4_compoundres *resp,
479762306a36Sopenharmony_ci		struct nfsd42_write_res *write, bool sync)
479862306a36Sopenharmony_ci{
479962306a36Sopenharmony_ci	__be32 *p;
480062306a36Sopenharmony_ci	p = xdr_reserve_space(resp->xdr, 4);
480162306a36Sopenharmony_ci	if (!p)
480262306a36Sopenharmony_ci		return nfserr_resource;
480362306a36Sopenharmony_ci
480462306a36Sopenharmony_ci	if (sync)
480562306a36Sopenharmony_ci		*p++ = cpu_to_be32(0);
480662306a36Sopenharmony_ci	else {
480762306a36Sopenharmony_ci		__be32 nfserr;
480862306a36Sopenharmony_ci		*p++ = cpu_to_be32(1);
480962306a36Sopenharmony_ci		nfserr = nfsd4_encode_stateid(resp->xdr, &write->cb_stateid);
481062306a36Sopenharmony_ci		if (nfserr)
481162306a36Sopenharmony_ci			return nfserr;
481262306a36Sopenharmony_ci	}
481362306a36Sopenharmony_ci	p = xdr_reserve_space(resp->xdr, 8 + 4 + NFS4_VERIFIER_SIZE);
481462306a36Sopenharmony_ci	if (!p)
481562306a36Sopenharmony_ci		return nfserr_resource;
481662306a36Sopenharmony_ci
481762306a36Sopenharmony_ci	p = xdr_encode_hyper(p, write->wr_bytes_written);
481862306a36Sopenharmony_ci	*p++ = cpu_to_be32(write->wr_stable_how);
481962306a36Sopenharmony_ci	p = xdr_encode_opaque_fixed(p, write->wr_verifier.data,
482062306a36Sopenharmony_ci				    NFS4_VERIFIER_SIZE);
482162306a36Sopenharmony_ci	return nfs_ok;
482262306a36Sopenharmony_ci}
482362306a36Sopenharmony_ci
482462306a36Sopenharmony_cistatic __be32
482562306a36Sopenharmony_cinfsd42_encode_nl4_server(struct nfsd4_compoundres *resp, struct nl4_server *ns)
482662306a36Sopenharmony_ci{
482762306a36Sopenharmony_ci	struct xdr_stream *xdr = resp->xdr;
482862306a36Sopenharmony_ci	struct nfs42_netaddr *addr;
482962306a36Sopenharmony_ci	__be32 *p;
483062306a36Sopenharmony_ci
483162306a36Sopenharmony_ci	p = xdr_reserve_space(xdr, 4);
483262306a36Sopenharmony_ci	*p++ = cpu_to_be32(ns->nl4_type);
483362306a36Sopenharmony_ci
483462306a36Sopenharmony_ci	switch (ns->nl4_type) {
483562306a36Sopenharmony_ci	case NL4_NETADDR:
483662306a36Sopenharmony_ci		addr = &ns->u.nl4_addr;
483762306a36Sopenharmony_ci
483862306a36Sopenharmony_ci		/* netid_len, netid, uaddr_len, uaddr (port included
483962306a36Sopenharmony_ci		 * in RPCBIND_MAXUADDRLEN)
484062306a36Sopenharmony_ci		 */
484162306a36Sopenharmony_ci		p = xdr_reserve_space(xdr,
484262306a36Sopenharmony_ci			4 /* netid len */ +
484362306a36Sopenharmony_ci			(XDR_QUADLEN(addr->netid_len) * 4) +
484462306a36Sopenharmony_ci			4 /* uaddr len */ +
484562306a36Sopenharmony_ci			(XDR_QUADLEN(addr->addr_len) * 4));
484662306a36Sopenharmony_ci		if (!p)
484762306a36Sopenharmony_ci			return nfserr_resource;
484862306a36Sopenharmony_ci
484962306a36Sopenharmony_ci		*p++ = cpu_to_be32(addr->netid_len);
485062306a36Sopenharmony_ci		p = xdr_encode_opaque_fixed(p, addr->netid,
485162306a36Sopenharmony_ci					    addr->netid_len);
485262306a36Sopenharmony_ci		*p++ = cpu_to_be32(addr->addr_len);
485362306a36Sopenharmony_ci		p = xdr_encode_opaque_fixed(p, addr->addr,
485462306a36Sopenharmony_ci					addr->addr_len);
485562306a36Sopenharmony_ci		break;
485662306a36Sopenharmony_ci	default:
485762306a36Sopenharmony_ci		WARN_ON_ONCE(ns->nl4_type != NL4_NETADDR);
485862306a36Sopenharmony_ci		return nfserr_inval;
485962306a36Sopenharmony_ci	}
486062306a36Sopenharmony_ci
486162306a36Sopenharmony_ci	return 0;
486262306a36Sopenharmony_ci}
486362306a36Sopenharmony_ci
486462306a36Sopenharmony_cistatic __be32
486562306a36Sopenharmony_cinfsd4_encode_copy(struct nfsd4_compoundres *resp, __be32 nfserr,
486662306a36Sopenharmony_ci		  union nfsd4_op_u *u)
486762306a36Sopenharmony_ci{
486862306a36Sopenharmony_ci	struct nfsd4_copy *copy = &u->copy;
486962306a36Sopenharmony_ci	__be32 *p;
487062306a36Sopenharmony_ci
487162306a36Sopenharmony_ci	nfserr = nfsd42_encode_write_res(resp, &copy->cp_res,
487262306a36Sopenharmony_ci					 nfsd4_copy_is_sync(copy));
487362306a36Sopenharmony_ci	if (nfserr)
487462306a36Sopenharmony_ci		return nfserr;
487562306a36Sopenharmony_ci
487662306a36Sopenharmony_ci	p = xdr_reserve_space(resp->xdr, 4 + 4);
487762306a36Sopenharmony_ci	*p++ = xdr_one; /* cr_consecutive */
487862306a36Sopenharmony_ci	*p = nfsd4_copy_is_sync(copy) ? xdr_one : xdr_zero;
487962306a36Sopenharmony_ci	return 0;
488062306a36Sopenharmony_ci}
488162306a36Sopenharmony_ci
488262306a36Sopenharmony_cistatic __be32
488362306a36Sopenharmony_cinfsd4_encode_offload_status(struct nfsd4_compoundres *resp, __be32 nfserr,
488462306a36Sopenharmony_ci			    union nfsd4_op_u *u)
488562306a36Sopenharmony_ci{
488662306a36Sopenharmony_ci	struct nfsd4_offload_status *os = &u->offload_status;
488762306a36Sopenharmony_ci	struct xdr_stream *xdr = resp->xdr;
488862306a36Sopenharmony_ci	__be32 *p;
488962306a36Sopenharmony_ci
489062306a36Sopenharmony_ci	p = xdr_reserve_space(xdr, 8 + 4);
489162306a36Sopenharmony_ci	if (!p)
489262306a36Sopenharmony_ci		return nfserr_resource;
489362306a36Sopenharmony_ci	p = xdr_encode_hyper(p, os->count);
489462306a36Sopenharmony_ci	*p++ = cpu_to_be32(0);
489562306a36Sopenharmony_ci	return nfserr;
489662306a36Sopenharmony_ci}
489762306a36Sopenharmony_ci
489862306a36Sopenharmony_cistatic __be32
489962306a36Sopenharmony_cinfsd4_encode_read_plus_data(struct nfsd4_compoundres *resp,
490062306a36Sopenharmony_ci			    struct nfsd4_read *read)
490162306a36Sopenharmony_ci{
490262306a36Sopenharmony_ci	bool splice_ok = test_bit(RQ_SPLICE_OK, &resp->rqstp->rq_flags);
490362306a36Sopenharmony_ci	struct file *file = read->rd_nf->nf_file;
490462306a36Sopenharmony_ci	struct xdr_stream *xdr = resp->xdr;
490562306a36Sopenharmony_ci	unsigned long maxcount;
490662306a36Sopenharmony_ci	__be32 nfserr, *p;
490762306a36Sopenharmony_ci
490862306a36Sopenharmony_ci	/* Content type, offset, byte count */
490962306a36Sopenharmony_ci	p = xdr_reserve_space(xdr, 4 + 8 + 4);
491062306a36Sopenharmony_ci	if (!p)
491162306a36Sopenharmony_ci		return nfserr_io;
491262306a36Sopenharmony_ci	if (resp->xdr->buf->page_len && splice_ok) {
491362306a36Sopenharmony_ci		WARN_ON_ONCE(splice_ok);
491462306a36Sopenharmony_ci		return nfserr_serverfault;
491562306a36Sopenharmony_ci	}
491662306a36Sopenharmony_ci
491762306a36Sopenharmony_ci	maxcount = min_t(unsigned long, read->rd_length,
491862306a36Sopenharmony_ci			 (xdr->buf->buflen - xdr->buf->len));
491962306a36Sopenharmony_ci
492062306a36Sopenharmony_ci	if (file->f_op->splice_read && splice_ok)
492162306a36Sopenharmony_ci		nfserr = nfsd4_encode_splice_read(resp, read, file, maxcount);
492262306a36Sopenharmony_ci	else
492362306a36Sopenharmony_ci		nfserr = nfsd4_encode_readv(resp, read, file, maxcount);
492462306a36Sopenharmony_ci	if (nfserr)
492562306a36Sopenharmony_ci		return nfserr;
492662306a36Sopenharmony_ci
492762306a36Sopenharmony_ci	*p++ = cpu_to_be32(NFS4_CONTENT_DATA);
492862306a36Sopenharmony_ci	p = xdr_encode_hyper(p, read->rd_offset);
492962306a36Sopenharmony_ci	*p = cpu_to_be32(read->rd_length);
493062306a36Sopenharmony_ci
493162306a36Sopenharmony_ci	return nfs_ok;
493262306a36Sopenharmony_ci}
493362306a36Sopenharmony_ci
493462306a36Sopenharmony_cistatic __be32
493562306a36Sopenharmony_cinfsd4_encode_read_plus(struct nfsd4_compoundres *resp, __be32 nfserr,
493662306a36Sopenharmony_ci		       union nfsd4_op_u *u)
493762306a36Sopenharmony_ci{
493862306a36Sopenharmony_ci	struct nfsd4_read *read = &u->read;
493962306a36Sopenharmony_ci	struct file *file = read->rd_nf->nf_file;
494062306a36Sopenharmony_ci	struct xdr_stream *xdr = resp->xdr;
494162306a36Sopenharmony_ci	int starting_len = xdr->buf->len;
494262306a36Sopenharmony_ci	u32 segments = 0;
494362306a36Sopenharmony_ci	__be32 *p;
494462306a36Sopenharmony_ci
494562306a36Sopenharmony_ci	if (nfserr)
494662306a36Sopenharmony_ci		return nfserr;
494762306a36Sopenharmony_ci
494862306a36Sopenharmony_ci	/* eof flag, segment count */
494962306a36Sopenharmony_ci	p = xdr_reserve_space(xdr, 4 + 4);
495062306a36Sopenharmony_ci	if (!p)
495162306a36Sopenharmony_ci		return nfserr_io;
495262306a36Sopenharmony_ci	xdr_commit_encode(xdr);
495362306a36Sopenharmony_ci
495462306a36Sopenharmony_ci	read->rd_eof = read->rd_offset >= i_size_read(file_inode(file));
495562306a36Sopenharmony_ci	if (read->rd_eof)
495662306a36Sopenharmony_ci		goto out;
495762306a36Sopenharmony_ci
495862306a36Sopenharmony_ci	nfserr = nfsd4_encode_read_plus_data(resp, read);
495962306a36Sopenharmony_ci	if (nfserr) {
496062306a36Sopenharmony_ci		xdr_truncate_encode(xdr, starting_len);
496162306a36Sopenharmony_ci		return nfserr;
496262306a36Sopenharmony_ci	}
496362306a36Sopenharmony_ci
496462306a36Sopenharmony_ci	segments++;
496562306a36Sopenharmony_ci
496662306a36Sopenharmony_ciout:
496762306a36Sopenharmony_ci	p = xdr_encode_bool(p, read->rd_eof);
496862306a36Sopenharmony_ci	*p = cpu_to_be32(segments);
496962306a36Sopenharmony_ci	return nfserr;
497062306a36Sopenharmony_ci}
497162306a36Sopenharmony_ci
497262306a36Sopenharmony_cistatic __be32
497362306a36Sopenharmony_cinfsd4_encode_copy_notify(struct nfsd4_compoundres *resp, __be32 nfserr,
497462306a36Sopenharmony_ci			 union nfsd4_op_u *u)
497562306a36Sopenharmony_ci{
497662306a36Sopenharmony_ci	struct nfsd4_copy_notify *cn = &u->copy_notify;
497762306a36Sopenharmony_ci	struct xdr_stream *xdr = resp->xdr;
497862306a36Sopenharmony_ci	__be32 *p;
497962306a36Sopenharmony_ci
498062306a36Sopenharmony_ci	if (nfserr)
498162306a36Sopenharmony_ci		return nfserr;
498262306a36Sopenharmony_ci
498362306a36Sopenharmony_ci	/* 8 sec, 4 nsec */
498462306a36Sopenharmony_ci	p = xdr_reserve_space(xdr, 12);
498562306a36Sopenharmony_ci	if (!p)
498662306a36Sopenharmony_ci		return nfserr_resource;
498762306a36Sopenharmony_ci
498862306a36Sopenharmony_ci	/* cnr_lease_time */
498962306a36Sopenharmony_ci	p = xdr_encode_hyper(p, cn->cpn_sec);
499062306a36Sopenharmony_ci	*p++ = cpu_to_be32(cn->cpn_nsec);
499162306a36Sopenharmony_ci
499262306a36Sopenharmony_ci	/* cnr_stateid */
499362306a36Sopenharmony_ci	nfserr = nfsd4_encode_stateid(xdr, &cn->cpn_cnr_stateid);
499462306a36Sopenharmony_ci	if (nfserr)
499562306a36Sopenharmony_ci		return nfserr;
499662306a36Sopenharmony_ci
499762306a36Sopenharmony_ci	/* cnr_src.nl_nsvr */
499862306a36Sopenharmony_ci	p = xdr_reserve_space(xdr, 4);
499962306a36Sopenharmony_ci	if (!p)
500062306a36Sopenharmony_ci		return nfserr_resource;
500162306a36Sopenharmony_ci
500262306a36Sopenharmony_ci	*p++ = cpu_to_be32(1);
500362306a36Sopenharmony_ci
500462306a36Sopenharmony_ci	nfserr = nfsd42_encode_nl4_server(resp, cn->cpn_src);
500562306a36Sopenharmony_ci	return nfserr;
500662306a36Sopenharmony_ci}
500762306a36Sopenharmony_ci
500862306a36Sopenharmony_cistatic __be32
500962306a36Sopenharmony_cinfsd4_encode_seek(struct nfsd4_compoundres *resp, __be32 nfserr,
501062306a36Sopenharmony_ci		  union nfsd4_op_u *u)
501162306a36Sopenharmony_ci{
501262306a36Sopenharmony_ci	struct nfsd4_seek *seek = &u->seek;
501362306a36Sopenharmony_ci	__be32 *p;
501462306a36Sopenharmony_ci
501562306a36Sopenharmony_ci	p = xdr_reserve_space(resp->xdr, 4 + 8);
501662306a36Sopenharmony_ci	*p++ = cpu_to_be32(seek->seek_eof);
501762306a36Sopenharmony_ci	p = xdr_encode_hyper(p, seek->seek_pos);
501862306a36Sopenharmony_ci
501962306a36Sopenharmony_ci	return 0;
502062306a36Sopenharmony_ci}
502162306a36Sopenharmony_ci
502262306a36Sopenharmony_cistatic __be32
502362306a36Sopenharmony_cinfsd4_encode_noop(struct nfsd4_compoundres *resp, __be32 nfserr,
502462306a36Sopenharmony_ci		  union nfsd4_op_u *p)
502562306a36Sopenharmony_ci{
502662306a36Sopenharmony_ci	return nfserr;
502762306a36Sopenharmony_ci}
502862306a36Sopenharmony_ci
502962306a36Sopenharmony_ci/*
503062306a36Sopenharmony_ci * Encode kmalloc-ed buffer in to XDR stream.
503162306a36Sopenharmony_ci */
503262306a36Sopenharmony_cistatic __be32
503362306a36Sopenharmony_cinfsd4_vbuf_to_stream(struct xdr_stream *xdr, char *buf, u32 buflen)
503462306a36Sopenharmony_ci{
503562306a36Sopenharmony_ci	u32 cplen;
503662306a36Sopenharmony_ci	__be32 *p;
503762306a36Sopenharmony_ci
503862306a36Sopenharmony_ci	cplen = min_t(unsigned long, buflen,
503962306a36Sopenharmony_ci		      ((void *)xdr->end - (void *)xdr->p));
504062306a36Sopenharmony_ci	p = xdr_reserve_space(xdr, cplen);
504162306a36Sopenharmony_ci	if (!p)
504262306a36Sopenharmony_ci		return nfserr_resource;
504362306a36Sopenharmony_ci
504462306a36Sopenharmony_ci	memcpy(p, buf, cplen);
504562306a36Sopenharmony_ci	buf += cplen;
504662306a36Sopenharmony_ci	buflen -= cplen;
504762306a36Sopenharmony_ci
504862306a36Sopenharmony_ci	while (buflen) {
504962306a36Sopenharmony_ci		cplen = min_t(u32, buflen, PAGE_SIZE);
505062306a36Sopenharmony_ci		p = xdr_reserve_space(xdr, cplen);
505162306a36Sopenharmony_ci		if (!p)
505262306a36Sopenharmony_ci			return nfserr_resource;
505362306a36Sopenharmony_ci
505462306a36Sopenharmony_ci		memcpy(p, buf, cplen);
505562306a36Sopenharmony_ci
505662306a36Sopenharmony_ci		if (cplen < PAGE_SIZE) {
505762306a36Sopenharmony_ci			/*
505862306a36Sopenharmony_ci			 * We're done, with a length that wasn't page
505962306a36Sopenharmony_ci			 * aligned, so possibly not word aligned. Pad
506062306a36Sopenharmony_ci			 * any trailing bytes with 0.
506162306a36Sopenharmony_ci			 */
506262306a36Sopenharmony_ci			xdr_encode_opaque_fixed(p, NULL, cplen);
506362306a36Sopenharmony_ci			break;
506462306a36Sopenharmony_ci		}
506562306a36Sopenharmony_ci
506662306a36Sopenharmony_ci		buflen -= PAGE_SIZE;
506762306a36Sopenharmony_ci		buf += PAGE_SIZE;
506862306a36Sopenharmony_ci	}
506962306a36Sopenharmony_ci
507062306a36Sopenharmony_ci	return 0;
507162306a36Sopenharmony_ci}
507262306a36Sopenharmony_ci
507362306a36Sopenharmony_cistatic __be32
507462306a36Sopenharmony_cinfsd4_encode_getxattr(struct nfsd4_compoundres *resp, __be32 nfserr,
507562306a36Sopenharmony_ci		      union nfsd4_op_u *u)
507662306a36Sopenharmony_ci{
507762306a36Sopenharmony_ci	struct nfsd4_getxattr *getxattr = &u->getxattr;
507862306a36Sopenharmony_ci	struct xdr_stream *xdr = resp->xdr;
507962306a36Sopenharmony_ci	__be32 *p, err;
508062306a36Sopenharmony_ci
508162306a36Sopenharmony_ci	p = xdr_reserve_space(xdr, 4);
508262306a36Sopenharmony_ci	if (!p)
508362306a36Sopenharmony_ci		return nfserr_resource;
508462306a36Sopenharmony_ci
508562306a36Sopenharmony_ci	*p = cpu_to_be32(getxattr->getxa_len);
508662306a36Sopenharmony_ci
508762306a36Sopenharmony_ci	if (getxattr->getxa_len == 0)
508862306a36Sopenharmony_ci		return 0;
508962306a36Sopenharmony_ci
509062306a36Sopenharmony_ci	err = nfsd4_vbuf_to_stream(xdr, getxattr->getxa_buf,
509162306a36Sopenharmony_ci				    getxattr->getxa_len);
509262306a36Sopenharmony_ci
509362306a36Sopenharmony_ci	kvfree(getxattr->getxa_buf);
509462306a36Sopenharmony_ci
509562306a36Sopenharmony_ci	return err;
509662306a36Sopenharmony_ci}
509762306a36Sopenharmony_ci
509862306a36Sopenharmony_cistatic __be32
509962306a36Sopenharmony_cinfsd4_encode_setxattr(struct nfsd4_compoundres *resp, __be32 nfserr,
510062306a36Sopenharmony_ci		      union nfsd4_op_u *u)
510162306a36Sopenharmony_ci{
510262306a36Sopenharmony_ci	struct nfsd4_setxattr *setxattr = &u->setxattr;
510362306a36Sopenharmony_ci	struct xdr_stream *xdr = resp->xdr;
510462306a36Sopenharmony_ci
510562306a36Sopenharmony_ci	return nfsd4_encode_change_info4(xdr, &setxattr->setxa_cinfo);
510662306a36Sopenharmony_ci}
510762306a36Sopenharmony_ci
510862306a36Sopenharmony_ci/*
510962306a36Sopenharmony_ci * See if there are cookie values that can be rejected outright.
511062306a36Sopenharmony_ci */
511162306a36Sopenharmony_cistatic __be32
511262306a36Sopenharmony_cinfsd4_listxattr_validate_cookie(struct nfsd4_listxattrs *listxattrs,
511362306a36Sopenharmony_ci				u32 *offsetp)
511462306a36Sopenharmony_ci{
511562306a36Sopenharmony_ci	u64 cookie = listxattrs->lsxa_cookie;
511662306a36Sopenharmony_ci
511762306a36Sopenharmony_ci	/*
511862306a36Sopenharmony_ci	 * If the cookie is larger than the maximum number we can fit
511962306a36Sopenharmony_ci	 * in either the buffer we just got back from vfs_listxattr, or,
512062306a36Sopenharmony_ci	 * XDR-encoded, in the return buffer, it's invalid.
512162306a36Sopenharmony_ci	 */
512262306a36Sopenharmony_ci	if (cookie > (listxattrs->lsxa_len) / (XATTR_USER_PREFIX_LEN + 2))
512362306a36Sopenharmony_ci		return nfserr_badcookie;
512462306a36Sopenharmony_ci
512562306a36Sopenharmony_ci	if (cookie > (listxattrs->lsxa_maxcount /
512662306a36Sopenharmony_ci		      (XDR_QUADLEN(XATTR_USER_PREFIX_LEN + 2) + 4)))
512762306a36Sopenharmony_ci		return nfserr_badcookie;
512862306a36Sopenharmony_ci
512962306a36Sopenharmony_ci	*offsetp = (u32)cookie;
513062306a36Sopenharmony_ci	return 0;
513162306a36Sopenharmony_ci}
513262306a36Sopenharmony_ci
513362306a36Sopenharmony_cistatic __be32
513462306a36Sopenharmony_cinfsd4_encode_listxattrs(struct nfsd4_compoundres *resp, __be32 nfserr,
513562306a36Sopenharmony_ci			union nfsd4_op_u *u)
513662306a36Sopenharmony_ci{
513762306a36Sopenharmony_ci	struct nfsd4_listxattrs *listxattrs = &u->listxattrs;
513862306a36Sopenharmony_ci	struct xdr_stream *xdr = resp->xdr;
513962306a36Sopenharmony_ci	u32 cookie_offset, count_offset, eof;
514062306a36Sopenharmony_ci	u32 left, xdrleft, slen, count;
514162306a36Sopenharmony_ci	u32 xdrlen, offset;
514262306a36Sopenharmony_ci	u64 cookie;
514362306a36Sopenharmony_ci	char *sp;
514462306a36Sopenharmony_ci	__be32 status, tmp;
514562306a36Sopenharmony_ci	__be32 *p;
514662306a36Sopenharmony_ci	u32 nuser;
514762306a36Sopenharmony_ci
514862306a36Sopenharmony_ci	eof = 1;
514962306a36Sopenharmony_ci
515062306a36Sopenharmony_ci	status = nfsd4_listxattr_validate_cookie(listxattrs, &offset);
515162306a36Sopenharmony_ci	if (status)
515262306a36Sopenharmony_ci		goto out;
515362306a36Sopenharmony_ci
515462306a36Sopenharmony_ci	/*
515562306a36Sopenharmony_ci	 * Reserve space for the cookie and the name array count. Record
515662306a36Sopenharmony_ci	 * the offsets to save them later.
515762306a36Sopenharmony_ci	 */
515862306a36Sopenharmony_ci	cookie_offset = xdr->buf->len;
515962306a36Sopenharmony_ci	count_offset = cookie_offset + 8;
516062306a36Sopenharmony_ci	p = xdr_reserve_space(xdr, 12);
516162306a36Sopenharmony_ci	if (!p) {
516262306a36Sopenharmony_ci		status = nfserr_resource;
516362306a36Sopenharmony_ci		goto out;
516462306a36Sopenharmony_ci	}
516562306a36Sopenharmony_ci
516662306a36Sopenharmony_ci	count = 0;
516762306a36Sopenharmony_ci	left = listxattrs->lsxa_len;
516862306a36Sopenharmony_ci	sp = listxattrs->lsxa_buf;
516962306a36Sopenharmony_ci	nuser = 0;
517062306a36Sopenharmony_ci
517162306a36Sopenharmony_ci	xdrleft = listxattrs->lsxa_maxcount;
517262306a36Sopenharmony_ci
517362306a36Sopenharmony_ci	while (left > 0 && xdrleft > 0) {
517462306a36Sopenharmony_ci		slen = strlen(sp);
517562306a36Sopenharmony_ci
517662306a36Sopenharmony_ci		/*
517762306a36Sopenharmony_ci		 * Check if this is a "user." attribute, skip it if not.
517862306a36Sopenharmony_ci		 */
517962306a36Sopenharmony_ci		if (strncmp(sp, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN))
518062306a36Sopenharmony_ci			goto contloop;
518162306a36Sopenharmony_ci
518262306a36Sopenharmony_ci		slen -= XATTR_USER_PREFIX_LEN;
518362306a36Sopenharmony_ci		xdrlen = 4 + ((slen + 3) & ~3);
518462306a36Sopenharmony_ci		if (xdrlen > xdrleft) {
518562306a36Sopenharmony_ci			if (count == 0) {
518662306a36Sopenharmony_ci				/*
518762306a36Sopenharmony_ci				 * Can't even fit the first attribute name.
518862306a36Sopenharmony_ci				 */
518962306a36Sopenharmony_ci				status = nfserr_toosmall;
519062306a36Sopenharmony_ci				goto out;
519162306a36Sopenharmony_ci			}
519262306a36Sopenharmony_ci			eof = 0;
519362306a36Sopenharmony_ci			goto wreof;
519462306a36Sopenharmony_ci		}
519562306a36Sopenharmony_ci
519662306a36Sopenharmony_ci		left -= XATTR_USER_PREFIX_LEN;
519762306a36Sopenharmony_ci		sp += XATTR_USER_PREFIX_LEN;
519862306a36Sopenharmony_ci		if (nuser++ < offset)
519962306a36Sopenharmony_ci			goto contloop;
520062306a36Sopenharmony_ci
520162306a36Sopenharmony_ci
520262306a36Sopenharmony_ci		p = xdr_reserve_space(xdr, xdrlen);
520362306a36Sopenharmony_ci		if (!p) {
520462306a36Sopenharmony_ci			status = nfserr_resource;
520562306a36Sopenharmony_ci			goto out;
520662306a36Sopenharmony_ci		}
520762306a36Sopenharmony_ci
520862306a36Sopenharmony_ci		xdr_encode_opaque(p, sp, slen);
520962306a36Sopenharmony_ci
521062306a36Sopenharmony_ci		xdrleft -= xdrlen;
521162306a36Sopenharmony_ci		count++;
521262306a36Sopenharmony_cicontloop:
521362306a36Sopenharmony_ci		sp += slen + 1;
521462306a36Sopenharmony_ci		left -= slen + 1;
521562306a36Sopenharmony_ci	}
521662306a36Sopenharmony_ci
521762306a36Sopenharmony_ci	/*
521862306a36Sopenharmony_ci	 * If there were user attributes to copy, but we didn't copy
521962306a36Sopenharmony_ci	 * any, the offset was too large (e.g. the cookie was invalid).
522062306a36Sopenharmony_ci	 */
522162306a36Sopenharmony_ci	if (nuser > 0 && count == 0) {
522262306a36Sopenharmony_ci		status = nfserr_badcookie;
522362306a36Sopenharmony_ci		goto out;
522462306a36Sopenharmony_ci	}
522562306a36Sopenharmony_ci
522662306a36Sopenharmony_ciwreof:
522762306a36Sopenharmony_ci	p = xdr_reserve_space(xdr, 4);
522862306a36Sopenharmony_ci	if (!p) {
522962306a36Sopenharmony_ci		status = nfserr_resource;
523062306a36Sopenharmony_ci		goto out;
523162306a36Sopenharmony_ci	}
523262306a36Sopenharmony_ci	*p = cpu_to_be32(eof);
523362306a36Sopenharmony_ci
523462306a36Sopenharmony_ci	cookie = offset + count;
523562306a36Sopenharmony_ci
523662306a36Sopenharmony_ci	write_bytes_to_xdr_buf(xdr->buf, cookie_offset, &cookie, 8);
523762306a36Sopenharmony_ci	tmp = cpu_to_be32(count);
523862306a36Sopenharmony_ci	write_bytes_to_xdr_buf(xdr->buf, count_offset, &tmp, 4);
523962306a36Sopenharmony_ciout:
524062306a36Sopenharmony_ci	if (listxattrs->lsxa_len)
524162306a36Sopenharmony_ci		kvfree(listxattrs->lsxa_buf);
524262306a36Sopenharmony_ci	return status;
524362306a36Sopenharmony_ci}
524462306a36Sopenharmony_ci
524562306a36Sopenharmony_cistatic __be32
524662306a36Sopenharmony_cinfsd4_encode_removexattr(struct nfsd4_compoundres *resp, __be32 nfserr,
524762306a36Sopenharmony_ci			 union nfsd4_op_u *u)
524862306a36Sopenharmony_ci{
524962306a36Sopenharmony_ci	struct nfsd4_removexattr *removexattr = &u->removexattr;
525062306a36Sopenharmony_ci	struct xdr_stream *xdr = resp->xdr;
525162306a36Sopenharmony_ci
525262306a36Sopenharmony_ci	return nfsd4_encode_change_info4(xdr, &removexattr->rmxa_cinfo);
525362306a36Sopenharmony_ci}
525462306a36Sopenharmony_ci
525562306a36Sopenharmony_citypedef __be32(*nfsd4_enc)(struct nfsd4_compoundres *, __be32, union nfsd4_op_u *u);
525662306a36Sopenharmony_ci
525762306a36Sopenharmony_ci/*
525862306a36Sopenharmony_ci * Note: nfsd4_enc_ops vector is shared for v4.0 and v4.1
525962306a36Sopenharmony_ci * since we don't need to filter out obsolete ops as this is
526062306a36Sopenharmony_ci * done in the decoding phase.
526162306a36Sopenharmony_ci */
526262306a36Sopenharmony_cistatic const nfsd4_enc nfsd4_enc_ops[] = {
526362306a36Sopenharmony_ci	[OP_ACCESS]		= nfsd4_encode_access,
526462306a36Sopenharmony_ci	[OP_CLOSE]		= nfsd4_encode_close,
526562306a36Sopenharmony_ci	[OP_COMMIT]		= nfsd4_encode_commit,
526662306a36Sopenharmony_ci	[OP_CREATE]		= nfsd4_encode_create,
526762306a36Sopenharmony_ci	[OP_DELEGPURGE]		= nfsd4_encode_noop,
526862306a36Sopenharmony_ci	[OP_DELEGRETURN]	= nfsd4_encode_noop,
526962306a36Sopenharmony_ci	[OP_GETATTR]		= nfsd4_encode_getattr,
527062306a36Sopenharmony_ci	[OP_GETFH]		= nfsd4_encode_getfh,
527162306a36Sopenharmony_ci	[OP_LINK]		= nfsd4_encode_link,
527262306a36Sopenharmony_ci	[OP_LOCK]		= nfsd4_encode_lock,
527362306a36Sopenharmony_ci	[OP_LOCKT]		= nfsd4_encode_lockt,
527462306a36Sopenharmony_ci	[OP_LOCKU]		= nfsd4_encode_locku,
527562306a36Sopenharmony_ci	[OP_LOOKUP]		= nfsd4_encode_noop,
527662306a36Sopenharmony_ci	[OP_LOOKUPP]		= nfsd4_encode_noop,
527762306a36Sopenharmony_ci	[OP_NVERIFY]		= nfsd4_encode_noop,
527862306a36Sopenharmony_ci	[OP_OPEN]		= nfsd4_encode_open,
527962306a36Sopenharmony_ci	[OP_OPENATTR]		= nfsd4_encode_noop,
528062306a36Sopenharmony_ci	[OP_OPEN_CONFIRM]	= nfsd4_encode_open_confirm,
528162306a36Sopenharmony_ci	[OP_OPEN_DOWNGRADE]	= nfsd4_encode_open_downgrade,
528262306a36Sopenharmony_ci	[OP_PUTFH]		= nfsd4_encode_noop,
528362306a36Sopenharmony_ci	[OP_PUTPUBFH]		= nfsd4_encode_noop,
528462306a36Sopenharmony_ci	[OP_PUTROOTFH]		= nfsd4_encode_noop,
528562306a36Sopenharmony_ci	[OP_READ]		= nfsd4_encode_read,
528662306a36Sopenharmony_ci	[OP_READDIR]		= nfsd4_encode_readdir,
528762306a36Sopenharmony_ci	[OP_READLINK]		= nfsd4_encode_readlink,
528862306a36Sopenharmony_ci	[OP_REMOVE]		= nfsd4_encode_remove,
528962306a36Sopenharmony_ci	[OP_RENAME]		= nfsd4_encode_rename,
529062306a36Sopenharmony_ci	[OP_RENEW]		= nfsd4_encode_noop,
529162306a36Sopenharmony_ci	[OP_RESTOREFH]		= nfsd4_encode_noop,
529262306a36Sopenharmony_ci	[OP_SAVEFH]		= nfsd4_encode_noop,
529362306a36Sopenharmony_ci	[OP_SECINFO]		= nfsd4_encode_secinfo,
529462306a36Sopenharmony_ci	[OP_SETATTR]		= nfsd4_encode_setattr,
529562306a36Sopenharmony_ci	[OP_SETCLIENTID]	= nfsd4_encode_setclientid,
529662306a36Sopenharmony_ci	[OP_SETCLIENTID_CONFIRM] = nfsd4_encode_noop,
529762306a36Sopenharmony_ci	[OP_VERIFY]		= nfsd4_encode_noop,
529862306a36Sopenharmony_ci	[OP_WRITE]		= nfsd4_encode_write,
529962306a36Sopenharmony_ci	[OP_RELEASE_LOCKOWNER]	= nfsd4_encode_noop,
530062306a36Sopenharmony_ci
530162306a36Sopenharmony_ci	/* NFSv4.1 operations */
530262306a36Sopenharmony_ci	[OP_BACKCHANNEL_CTL]	= nfsd4_encode_noop,
530362306a36Sopenharmony_ci	[OP_BIND_CONN_TO_SESSION] = nfsd4_encode_bind_conn_to_session,
530462306a36Sopenharmony_ci	[OP_EXCHANGE_ID]	= nfsd4_encode_exchange_id,
530562306a36Sopenharmony_ci	[OP_CREATE_SESSION]	= nfsd4_encode_create_session,
530662306a36Sopenharmony_ci	[OP_DESTROY_SESSION]	= nfsd4_encode_noop,
530762306a36Sopenharmony_ci	[OP_FREE_STATEID]	= nfsd4_encode_noop,
530862306a36Sopenharmony_ci	[OP_GET_DIR_DELEGATION]	= nfsd4_encode_noop,
530962306a36Sopenharmony_ci#ifdef CONFIG_NFSD_PNFS
531062306a36Sopenharmony_ci	[OP_GETDEVICEINFO]	= nfsd4_encode_getdeviceinfo,
531162306a36Sopenharmony_ci	[OP_GETDEVICELIST]	= nfsd4_encode_noop,
531262306a36Sopenharmony_ci	[OP_LAYOUTCOMMIT]	= nfsd4_encode_layoutcommit,
531362306a36Sopenharmony_ci	[OP_LAYOUTGET]		= nfsd4_encode_layoutget,
531462306a36Sopenharmony_ci	[OP_LAYOUTRETURN]	= nfsd4_encode_layoutreturn,
531562306a36Sopenharmony_ci#else
531662306a36Sopenharmony_ci	[OP_GETDEVICEINFO]	= nfsd4_encode_noop,
531762306a36Sopenharmony_ci	[OP_GETDEVICELIST]	= nfsd4_encode_noop,
531862306a36Sopenharmony_ci	[OP_LAYOUTCOMMIT]	= nfsd4_encode_noop,
531962306a36Sopenharmony_ci	[OP_LAYOUTGET]		= nfsd4_encode_noop,
532062306a36Sopenharmony_ci	[OP_LAYOUTRETURN]	= nfsd4_encode_noop,
532162306a36Sopenharmony_ci#endif
532262306a36Sopenharmony_ci	[OP_SECINFO_NO_NAME]	= nfsd4_encode_secinfo_no_name,
532362306a36Sopenharmony_ci	[OP_SEQUENCE]		= nfsd4_encode_sequence,
532462306a36Sopenharmony_ci	[OP_SET_SSV]		= nfsd4_encode_noop,
532562306a36Sopenharmony_ci	[OP_TEST_STATEID]	= nfsd4_encode_test_stateid,
532662306a36Sopenharmony_ci	[OP_WANT_DELEGATION]	= nfsd4_encode_noop,
532762306a36Sopenharmony_ci	[OP_DESTROY_CLIENTID]	= nfsd4_encode_noop,
532862306a36Sopenharmony_ci	[OP_RECLAIM_COMPLETE]	= nfsd4_encode_noop,
532962306a36Sopenharmony_ci
533062306a36Sopenharmony_ci	/* NFSv4.2 operations */
533162306a36Sopenharmony_ci	[OP_ALLOCATE]		= nfsd4_encode_noop,
533262306a36Sopenharmony_ci	[OP_COPY]		= nfsd4_encode_copy,
533362306a36Sopenharmony_ci	[OP_COPY_NOTIFY]	= nfsd4_encode_copy_notify,
533462306a36Sopenharmony_ci	[OP_DEALLOCATE]		= nfsd4_encode_noop,
533562306a36Sopenharmony_ci	[OP_IO_ADVISE]		= nfsd4_encode_noop,
533662306a36Sopenharmony_ci	[OP_LAYOUTERROR]	= nfsd4_encode_noop,
533762306a36Sopenharmony_ci	[OP_LAYOUTSTATS]	= nfsd4_encode_noop,
533862306a36Sopenharmony_ci	[OP_OFFLOAD_CANCEL]	= nfsd4_encode_noop,
533962306a36Sopenharmony_ci	[OP_OFFLOAD_STATUS]	= nfsd4_encode_offload_status,
534062306a36Sopenharmony_ci	[OP_READ_PLUS]		= nfsd4_encode_read_plus,
534162306a36Sopenharmony_ci	[OP_SEEK]		= nfsd4_encode_seek,
534262306a36Sopenharmony_ci	[OP_WRITE_SAME]		= nfsd4_encode_noop,
534362306a36Sopenharmony_ci	[OP_CLONE]		= nfsd4_encode_noop,
534462306a36Sopenharmony_ci
534562306a36Sopenharmony_ci	/* RFC 8276 extended atributes operations */
534662306a36Sopenharmony_ci	[OP_GETXATTR]		= nfsd4_encode_getxattr,
534762306a36Sopenharmony_ci	[OP_SETXATTR]		= nfsd4_encode_setxattr,
534862306a36Sopenharmony_ci	[OP_LISTXATTRS]		= nfsd4_encode_listxattrs,
534962306a36Sopenharmony_ci	[OP_REMOVEXATTR]	= nfsd4_encode_removexattr,
535062306a36Sopenharmony_ci};
535162306a36Sopenharmony_ci
535262306a36Sopenharmony_ci/*
535362306a36Sopenharmony_ci * Calculate whether we still have space to encode repsize bytes.
535462306a36Sopenharmony_ci * There are two considerations:
535562306a36Sopenharmony_ci *     - For NFS versions >=4.1, the size of the reply must stay within
535662306a36Sopenharmony_ci *       session limits
535762306a36Sopenharmony_ci *     - For all NFS versions, we must stay within limited preallocated
535862306a36Sopenharmony_ci *       buffer space.
535962306a36Sopenharmony_ci *
536062306a36Sopenharmony_ci * This is called before the operation is processed, so can only provide
536162306a36Sopenharmony_ci * an upper estimate.  For some nonidempotent operations (such as
536262306a36Sopenharmony_ci * getattr), it's not necessarily a problem if that estimate is wrong,
536362306a36Sopenharmony_ci * as we can fail it after processing without significant side effects.
536462306a36Sopenharmony_ci */
536562306a36Sopenharmony_ci__be32 nfsd4_check_resp_size(struct nfsd4_compoundres *resp, u32 respsize)
536662306a36Sopenharmony_ci{
536762306a36Sopenharmony_ci	struct xdr_buf *buf = &resp->rqstp->rq_res;
536862306a36Sopenharmony_ci	struct nfsd4_slot *slot = resp->cstate.slot;
536962306a36Sopenharmony_ci
537062306a36Sopenharmony_ci	if (buf->len + respsize <= buf->buflen)
537162306a36Sopenharmony_ci		return nfs_ok;
537262306a36Sopenharmony_ci	if (!nfsd4_has_session(&resp->cstate))
537362306a36Sopenharmony_ci		return nfserr_resource;
537462306a36Sopenharmony_ci	if (slot->sl_flags & NFSD4_SLOT_CACHETHIS) {
537562306a36Sopenharmony_ci		WARN_ON_ONCE(1);
537662306a36Sopenharmony_ci		return nfserr_rep_too_big_to_cache;
537762306a36Sopenharmony_ci	}
537862306a36Sopenharmony_ci	return nfserr_rep_too_big;
537962306a36Sopenharmony_ci}
538062306a36Sopenharmony_ci
538162306a36Sopenharmony_civoid
538262306a36Sopenharmony_cinfsd4_encode_operation(struct nfsd4_compoundres *resp, struct nfsd4_op *op)
538362306a36Sopenharmony_ci{
538462306a36Sopenharmony_ci	struct xdr_stream *xdr = resp->xdr;
538562306a36Sopenharmony_ci	struct nfs4_stateowner *so = resp->cstate.replay_owner;
538662306a36Sopenharmony_ci	struct svc_rqst *rqstp = resp->rqstp;
538762306a36Sopenharmony_ci	const struct nfsd4_operation *opdesc = op->opdesc;
538862306a36Sopenharmony_ci	int post_err_offset;
538962306a36Sopenharmony_ci	nfsd4_enc encoder;
539062306a36Sopenharmony_ci	__be32 *p;
539162306a36Sopenharmony_ci
539262306a36Sopenharmony_ci	p = xdr_reserve_space(xdr, 8);
539362306a36Sopenharmony_ci	if (!p)
539462306a36Sopenharmony_ci		goto release;
539562306a36Sopenharmony_ci	*p++ = cpu_to_be32(op->opnum);
539662306a36Sopenharmony_ci	post_err_offset = xdr->buf->len;
539762306a36Sopenharmony_ci
539862306a36Sopenharmony_ci	if (op->opnum == OP_ILLEGAL)
539962306a36Sopenharmony_ci		goto status;
540062306a36Sopenharmony_ci	if (op->status && opdesc &&
540162306a36Sopenharmony_ci			!(opdesc->op_flags & OP_NONTRIVIAL_ERROR_ENCODE))
540262306a36Sopenharmony_ci		goto status;
540362306a36Sopenharmony_ci	BUG_ON(op->opnum >= ARRAY_SIZE(nfsd4_enc_ops) ||
540462306a36Sopenharmony_ci	       !nfsd4_enc_ops[op->opnum]);
540562306a36Sopenharmony_ci	encoder = nfsd4_enc_ops[op->opnum];
540662306a36Sopenharmony_ci	op->status = encoder(resp, op->status, &op->u);
540762306a36Sopenharmony_ci	if (op->status)
540862306a36Sopenharmony_ci		trace_nfsd_compound_encode_err(rqstp, op->opnum, op->status);
540962306a36Sopenharmony_ci	xdr_commit_encode(xdr);
541062306a36Sopenharmony_ci
541162306a36Sopenharmony_ci	/* nfsd4_check_resp_size guarantees enough room for error status */
541262306a36Sopenharmony_ci	if (!op->status) {
541362306a36Sopenharmony_ci		int space_needed = 0;
541462306a36Sopenharmony_ci		if (!nfsd4_last_compound_op(rqstp))
541562306a36Sopenharmony_ci			space_needed = COMPOUND_ERR_SLACK_SPACE;
541662306a36Sopenharmony_ci		op->status = nfsd4_check_resp_size(resp, space_needed);
541762306a36Sopenharmony_ci	}
541862306a36Sopenharmony_ci	if (op->status == nfserr_resource && nfsd4_has_session(&resp->cstate)) {
541962306a36Sopenharmony_ci		struct nfsd4_slot *slot = resp->cstate.slot;
542062306a36Sopenharmony_ci
542162306a36Sopenharmony_ci		if (slot->sl_flags & NFSD4_SLOT_CACHETHIS)
542262306a36Sopenharmony_ci			op->status = nfserr_rep_too_big_to_cache;
542362306a36Sopenharmony_ci		else
542462306a36Sopenharmony_ci			op->status = nfserr_rep_too_big;
542562306a36Sopenharmony_ci	}
542662306a36Sopenharmony_ci	if (op->status == nfserr_resource ||
542762306a36Sopenharmony_ci	    op->status == nfserr_rep_too_big ||
542862306a36Sopenharmony_ci	    op->status == nfserr_rep_too_big_to_cache) {
542962306a36Sopenharmony_ci		/*
543062306a36Sopenharmony_ci		 * The operation may have already been encoded or
543162306a36Sopenharmony_ci		 * partially encoded.  No op returns anything additional
543262306a36Sopenharmony_ci		 * in the case of one of these three errors, so we can
543362306a36Sopenharmony_ci		 * just truncate back to after the status.  But it's a
543462306a36Sopenharmony_ci		 * bug if we had to do this on a non-idempotent op:
543562306a36Sopenharmony_ci		 */
543662306a36Sopenharmony_ci		warn_on_nonidempotent_op(op);
543762306a36Sopenharmony_ci		xdr_truncate_encode(xdr, post_err_offset);
543862306a36Sopenharmony_ci	}
543962306a36Sopenharmony_ci	if (so) {
544062306a36Sopenharmony_ci		int len = xdr->buf->len - post_err_offset;
544162306a36Sopenharmony_ci
544262306a36Sopenharmony_ci		so->so_replay.rp_status = op->status;
544362306a36Sopenharmony_ci		so->so_replay.rp_buflen = len;
544462306a36Sopenharmony_ci		read_bytes_from_xdr_buf(xdr->buf, post_err_offset,
544562306a36Sopenharmony_ci						so->so_replay.rp_buf, len);
544662306a36Sopenharmony_ci	}
544762306a36Sopenharmony_cistatus:
544862306a36Sopenharmony_ci	*p = op->status;
544962306a36Sopenharmony_cirelease:
545062306a36Sopenharmony_ci	if (opdesc && opdesc->op_release)
545162306a36Sopenharmony_ci		opdesc->op_release(&op->u);
545262306a36Sopenharmony_ci
545362306a36Sopenharmony_ci	/*
545462306a36Sopenharmony_ci	 * Account for pages consumed while encoding this operation.
545562306a36Sopenharmony_ci	 * The xdr_stream primitives don't manage rq_next_page.
545662306a36Sopenharmony_ci	 */
545762306a36Sopenharmony_ci	rqstp->rq_next_page = xdr->page_ptr + 1;
545862306a36Sopenharmony_ci}
545962306a36Sopenharmony_ci
546062306a36Sopenharmony_ci/*
546162306a36Sopenharmony_ci * Encode the reply stored in the stateowner reply cache
546262306a36Sopenharmony_ci *
546362306a36Sopenharmony_ci * XDR note: do not encode rp->rp_buflen: the buffer contains the
546462306a36Sopenharmony_ci * previously sent already encoded operation.
546562306a36Sopenharmony_ci */
546662306a36Sopenharmony_civoid
546762306a36Sopenharmony_cinfsd4_encode_replay(struct xdr_stream *xdr, struct nfsd4_op *op)
546862306a36Sopenharmony_ci{
546962306a36Sopenharmony_ci	__be32 *p;
547062306a36Sopenharmony_ci	struct nfs4_replay *rp = op->replay;
547162306a36Sopenharmony_ci
547262306a36Sopenharmony_ci	p = xdr_reserve_space(xdr, 8 + rp->rp_buflen);
547362306a36Sopenharmony_ci	if (!p) {
547462306a36Sopenharmony_ci		WARN_ON_ONCE(1);
547562306a36Sopenharmony_ci		return;
547662306a36Sopenharmony_ci	}
547762306a36Sopenharmony_ci	*p++ = cpu_to_be32(op->opnum);
547862306a36Sopenharmony_ci	*p++ = rp->rp_status;  /* already xdr'ed */
547962306a36Sopenharmony_ci
548062306a36Sopenharmony_ci	p = xdr_encode_opaque_fixed(p, rp->rp_buf, rp->rp_buflen);
548162306a36Sopenharmony_ci}
548262306a36Sopenharmony_ci
548362306a36Sopenharmony_civoid nfsd4_release_compoundargs(struct svc_rqst *rqstp)
548462306a36Sopenharmony_ci{
548562306a36Sopenharmony_ci	struct nfsd4_compoundargs *args = rqstp->rq_argp;
548662306a36Sopenharmony_ci
548762306a36Sopenharmony_ci	if (args->ops != args->iops) {
548862306a36Sopenharmony_ci		vfree(args->ops);
548962306a36Sopenharmony_ci		args->ops = args->iops;
549062306a36Sopenharmony_ci	}
549162306a36Sopenharmony_ci	while (args->to_free) {
549262306a36Sopenharmony_ci		struct svcxdr_tmpbuf *tb = args->to_free;
549362306a36Sopenharmony_ci		args->to_free = tb->next;
549462306a36Sopenharmony_ci		kfree(tb);
549562306a36Sopenharmony_ci	}
549662306a36Sopenharmony_ci}
549762306a36Sopenharmony_ci
549862306a36Sopenharmony_cibool
549962306a36Sopenharmony_cinfs4svc_decode_compoundargs(struct svc_rqst *rqstp, struct xdr_stream *xdr)
550062306a36Sopenharmony_ci{
550162306a36Sopenharmony_ci	struct nfsd4_compoundargs *args = rqstp->rq_argp;
550262306a36Sopenharmony_ci
550362306a36Sopenharmony_ci	/* svcxdr_tmp_alloc */
550462306a36Sopenharmony_ci	args->to_free = NULL;
550562306a36Sopenharmony_ci
550662306a36Sopenharmony_ci	args->xdr = xdr;
550762306a36Sopenharmony_ci	args->ops = args->iops;
550862306a36Sopenharmony_ci	args->rqstp = rqstp;
550962306a36Sopenharmony_ci
551062306a36Sopenharmony_ci	return nfsd4_decode_compound(args);
551162306a36Sopenharmony_ci}
551262306a36Sopenharmony_ci
551362306a36Sopenharmony_cibool
551462306a36Sopenharmony_cinfs4svc_encode_compoundres(struct svc_rqst *rqstp, struct xdr_stream *xdr)
551562306a36Sopenharmony_ci{
551662306a36Sopenharmony_ci	struct nfsd4_compoundres *resp = rqstp->rq_resp;
551762306a36Sopenharmony_ci	__be32 *p;
551862306a36Sopenharmony_ci
551962306a36Sopenharmony_ci	/*
552062306a36Sopenharmony_ci	 * Send buffer space for the following items is reserved
552162306a36Sopenharmony_ci	 * at the top of nfsd4_proc_compound().
552262306a36Sopenharmony_ci	 */
552362306a36Sopenharmony_ci	p = resp->statusp;
552462306a36Sopenharmony_ci
552562306a36Sopenharmony_ci	*p++ = resp->cstate.status;
552662306a36Sopenharmony_ci	*p++ = htonl(resp->taglen);
552762306a36Sopenharmony_ci	memcpy(p, resp->tag, resp->taglen);
552862306a36Sopenharmony_ci	p += XDR_QUADLEN(resp->taglen);
552962306a36Sopenharmony_ci	*p++ = htonl(resp->opcnt);
553062306a36Sopenharmony_ci
553162306a36Sopenharmony_ci	nfsd4_sequence_done(resp);
553262306a36Sopenharmony_ci	return true;
553362306a36Sopenharmony_ci}
5534