18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * XDR support for nfsd/protocol version 3.
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (C) 1995, 1996, 1997 Olaf Kirch <okir@monad.swb.de>
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * 2003-08-09 Jamie Lokier: Use htonl() for nanoseconds, not htons()!
88c2ecf20Sopenharmony_ci */
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#include <linux/namei.h>
118c2ecf20Sopenharmony_ci#include <linux/sunrpc/svc_xprt.h>
128c2ecf20Sopenharmony_ci#include "xdr3.h"
138c2ecf20Sopenharmony_ci#include "auth.h"
148c2ecf20Sopenharmony_ci#include "netns.h"
158c2ecf20Sopenharmony_ci#include "vfs.h"
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci#define NFSDDBG_FACILITY		NFSDDBG_XDR
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_ci/*
218c2ecf20Sopenharmony_ci * Mapping of S_IF* types to NFS file types
228c2ecf20Sopenharmony_ci */
238c2ecf20Sopenharmony_cistatic u32	nfs3_ftypes[] = {
248c2ecf20Sopenharmony_ci	NF3NON,  NF3FIFO, NF3CHR, NF3BAD,
258c2ecf20Sopenharmony_ci	NF3DIR,  NF3BAD,  NF3BLK, NF3BAD,
268c2ecf20Sopenharmony_ci	NF3REG,  NF3BAD,  NF3LNK, NF3BAD,
278c2ecf20Sopenharmony_ci	NF3SOCK, NF3BAD,  NF3LNK, NF3BAD,
288c2ecf20Sopenharmony_ci};
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ci/*
328c2ecf20Sopenharmony_ci * XDR functions for basic NFS types
338c2ecf20Sopenharmony_ci */
348c2ecf20Sopenharmony_cistatic __be32 *
358c2ecf20Sopenharmony_ciencode_time3(__be32 *p, struct timespec64 *time)
368c2ecf20Sopenharmony_ci{
378c2ecf20Sopenharmony_ci	*p++ = htonl((u32) time->tv_sec); *p++ = htonl(time->tv_nsec);
388c2ecf20Sopenharmony_ci	return p;
398c2ecf20Sopenharmony_ci}
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_cistatic __be32 *
428c2ecf20Sopenharmony_cidecode_time3(__be32 *p, struct timespec64 *time)
438c2ecf20Sopenharmony_ci{
448c2ecf20Sopenharmony_ci	time->tv_sec = ntohl(*p++);
458c2ecf20Sopenharmony_ci	time->tv_nsec = ntohl(*p++);
468c2ecf20Sopenharmony_ci	return p;
478c2ecf20Sopenharmony_ci}
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_cistatic __be32 *
508c2ecf20Sopenharmony_cidecode_fh(__be32 *p, struct svc_fh *fhp)
518c2ecf20Sopenharmony_ci{
528c2ecf20Sopenharmony_ci	unsigned int size;
538c2ecf20Sopenharmony_ci	fh_init(fhp, NFS3_FHSIZE);
548c2ecf20Sopenharmony_ci	size = ntohl(*p++);
558c2ecf20Sopenharmony_ci	if (size > NFS3_FHSIZE)
568c2ecf20Sopenharmony_ci		return NULL;
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci	memcpy(&fhp->fh_handle.fh_base, p, size);
598c2ecf20Sopenharmony_ci	fhp->fh_handle.fh_size = size;
608c2ecf20Sopenharmony_ci	return p + XDR_QUADLEN(size);
618c2ecf20Sopenharmony_ci}
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci/* Helper function for NFSv3 ACL code */
648c2ecf20Sopenharmony_ci__be32 *nfs3svc_decode_fh(__be32 *p, struct svc_fh *fhp)
658c2ecf20Sopenharmony_ci{
668c2ecf20Sopenharmony_ci	return decode_fh(p, fhp);
678c2ecf20Sopenharmony_ci}
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_cistatic __be32 *
708c2ecf20Sopenharmony_ciencode_fh(__be32 *p, struct svc_fh *fhp)
718c2ecf20Sopenharmony_ci{
728c2ecf20Sopenharmony_ci	unsigned int size = fhp->fh_handle.fh_size;
738c2ecf20Sopenharmony_ci	*p++ = htonl(size);
748c2ecf20Sopenharmony_ci	if (size) p[XDR_QUADLEN(size)-1]=0;
758c2ecf20Sopenharmony_ci	memcpy(p, &fhp->fh_handle.fh_base, size);
768c2ecf20Sopenharmony_ci	return p + XDR_QUADLEN(size);
778c2ecf20Sopenharmony_ci}
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci/*
808c2ecf20Sopenharmony_ci * Decode a file name and make sure that the path contains
818c2ecf20Sopenharmony_ci * no slashes or null bytes.
828c2ecf20Sopenharmony_ci */
838c2ecf20Sopenharmony_cistatic __be32 *
848c2ecf20Sopenharmony_cidecode_filename(__be32 *p, char **namp, unsigned int *lenp)
858c2ecf20Sopenharmony_ci{
868c2ecf20Sopenharmony_ci	char		*name;
878c2ecf20Sopenharmony_ci	unsigned int	i;
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ci	if ((p = xdr_decode_string_inplace(p, namp, lenp, NFS3_MAXNAMLEN)) != NULL) {
908c2ecf20Sopenharmony_ci		for (i = 0, name = *namp; i < *lenp; i++, name++) {
918c2ecf20Sopenharmony_ci			if (*name == '\0' || *name == '/')
928c2ecf20Sopenharmony_ci				return NULL;
938c2ecf20Sopenharmony_ci		}
948c2ecf20Sopenharmony_ci	}
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_ci	return p;
978c2ecf20Sopenharmony_ci}
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_cistatic __be32 *
1008c2ecf20Sopenharmony_cidecode_sattr3(__be32 *p, struct iattr *iap, struct user_namespace *userns)
1018c2ecf20Sopenharmony_ci{
1028c2ecf20Sopenharmony_ci	u32	tmp;
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_ci	iap->ia_valid = 0;
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci	if (*p++) {
1078c2ecf20Sopenharmony_ci		iap->ia_valid |= ATTR_MODE;
1088c2ecf20Sopenharmony_ci		iap->ia_mode = ntohl(*p++);
1098c2ecf20Sopenharmony_ci	}
1108c2ecf20Sopenharmony_ci	if (*p++) {
1118c2ecf20Sopenharmony_ci		iap->ia_uid = make_kuid(userns, ntohl(*p++));
1128c2ecf20Sopenharmony_ci		if (uid_valid(iap->ia_uid))
1138c2ecf20Sopenharmony_ci			iap->ia_valid |= ATTR_UID;
1148c2ecf20Sopenharmony_ci	}
1158c2ecf20Sopenharmony_ci	if (*p++) {
1168c2ecf20Sopenharmony_ci		iap->ia_gid = make_kgid(userns, ntohl(*p++));
1178c2ecf20Sopenharmony_ci		if (gid_valid(iap->ia_gid))
1188c2ecf20Sopenharmony_ci			iap->ia_valid |= ATTR_GID;
1198c2ecf20Sopenharmony_ci	}
1208c2ecf20Sopenharmony_ci	if (*p++) {
1218c2ecf20Sopenharmony_ci		u64	newsize;
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_ci		iap->ia_valid |= ATTR_SIZE;
1248c2ecf20Sopenharmony_ci		p = xdr_decode_hyper(p, &newsize);
1258c2ecf20Sopenharmony_ci		iap->ia_size = min_t(u64, newsize, NFS_OFFSET_MAX);
1268c2ecf20Sopenharmony_ci	}
1278c2ecf20Sopenharmony_ci	if ((tmp = ntohl(*p++)) == 1) {	/* set to server time */
1288c2ecf20Sopenharmony_ci		iap->ia_valid |= ATTR_ATIME;
1298c2ecf20Sopenharmony_ci	} else if (tmp == 2) {		/* set to client time */
1308c2ecf20Sopenharmony_ci		iap->ia_valid |= ATTR_ATIME | ATTR_ATIME_SET;
1318c2ecf20Sopenharmony_ci		iap->ia_atime.tv_sec = ntohl(*p++);
1328c2ecf20Sopenharmony_ci		iap->ia_atime.tv_nsec = ntohl(*p++);
1338c2ecf20Sopenharmony_ci	}
1348c2ecf20Sopenharmony_ci	if ((tmp = ntohl(*p++)) == 1) {	/* set to server time */
1358c2ecf20Sopenharmony_ci		iap->ia_valid |= ATTR_MTIME;
1368c2ecf20Sopenharmony_ci	} else if (tmp == 2) {		/* set to client time */
1378c2ecf20Sopenharmony_ci		iap->ia_valid |= ATTR_MTIME | ATTR_MTIME_SET;
1388c2ecf20Sopenharmony_ci		iap->ia_mtime.tv_sec = ntohl(*p++);
1398c2ecf20Sopenharmony_ci		iap->ia_mtime.tv_nsec = ntohl(*p++);
1408c2ecf20Sopenharmony_ci	}
1418c2ecf20Sopenharmony_ci	return p;
1428c2ecf20Sopenharmony_ci}
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_cistatic __be32 *encode_fsid(__be32 *p, struct svc_fh *fhp)
1458c2ecf20Sopenharmony_ci{
1468c2ecf20Sopenharmony_ci	u64 f;
1478c2ecf20Sopenharmony_ci	switch(fsid_source(fhp)) {
1488c2ecf20Sopenharmony_ci	default:
1498c2ecf20Sopenharmony_ci	case FSIDSOURCE_DEV:
1508c2ecf20Sopenharmony_ci		p = xdr_encode_hyper(p, (u64)huge_encode_dev
1518c2ecf20Sopenharmony_ci				     (fhp->fh_dentry->d_sb->s_dev));
1528c2ecf20Sopenharmony_ci		break;
1538c2ecf20Sopenharmony_ci	case FSIDSOURCE_FSID:
1548c2ecf20Sopenharmony_ci		p = xdr_encode_hyper(p, (u64) fhp->fh_export->ex_fsid);
1558c2ecf20Sopenharmony_ci		break;
1568c2ecf20Sopenharmony_ci	case FSIDSOURCE_UUID:
1578c2ecf20Sopenharmony_ci		f = ((u64*)fhp->fh_export->ex_uuid)[0];
1588c2ecf20Sopenharmony_ci		f ^= ((u64*)fhp->fh_export->ex_uuid)[1];
1598c2ecf20Sopenharmony_ci		p = xdr_encode_hyper(p, f);
1608c2ecf20Sopenharmony_ci		break;
1618c2ecf20Sopenharmony_ci	}
1628c2ecf20Sopenharmony_ci	return p;
1638c2ecf20Sopenharmony_ci}
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_cistatic __be32 *
1668c2ecf20Sopenharmony_ciencode_fattr3(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp,
1678c2ecf20Sopenharmony_ci	      struct kstat *stat)
1688c2ecf20Sopenharmony_ci{
1698c2ecf20Sopenharmony_ci	struct user_namespace *userns = nfsd_user_namespace(rqstp);
1708c2ecf20Sopenharmony_ci	*p++ = htonl(nfs3_ftypes[(stat->mode & S_IFMT) >> 12]);
1718c2ecf20Sopenharmony_ci	*p++ = htonl((u32) (stat->mode & S_IALLUGO));
1728c2ecf20Sopenharmony_ci	*p++ = htonl((u32) stat->nlink);
1738c2ecf20Sopenharmony_ci	*p++ = htonl((u32) from_kuid_munged(userns, stat->uid));
1748c2ecf20Sopenharmony_ci	*p++ = htonl((u32) from_kgid_munged(userns, stat->gid));
1758c2ecf20Sopenharmony_ci	if (S_ISLNK(stat->mode) && stat->size > NFS3_MAXPATHLEN) {
1768c2ecf20Sopenharmony_ci		p = xdr_encode_hyper(p, (u64) NFS3_MAXPATHLEN);
1778c2ecf20Sopenharmony_ci	} else {
1788c2ecf20Sopenharmony_ci		p = xdr_encode_hyper(p, (u64) stat->size);
1798c2ecf20Sopenharmony_ci	}
1808c2ecf20Sopenharmony_ci	p = xdr_encode_hyper(p, ((u64)stat->blocks) << 9);
1818c2ecf20Sopenharmony_ci	*p++ = htonl((u32) MAJOR(stat->rdev));
1828c2ecf20Sopenharmony_ci	*p++ = htonl((u32) MINOR(stat->rdev));
1838c2ecf20Sopenharmony_ci	p = encode_fsid(p, fhp);
1848c2ecf20Sopenharmony_ci	p = xdr_encode_hyper(p, stat->ino);
1858c2ecf20Sopenharmony_ci	p = encode_time3(p, &stat->atime);
1868c2ecf20Sopenharmony_ci	p = encode_time3(p, &stat->mtime);
1878c2ecf20Sopenharmony_ci	p = encode_time3(p, &stat->ctime);
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_ci	return p;
1908c2ecf20Sopenharmony_ci}
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_cistatic __be32 *
1938c2ecf20Sopenharmony_ciencode_saved_post_attr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp)
1948c2ecf20Sopenharmony_ci{
1958c2ecf20Sopenharmony_ci	/* Attributes to follow */
1968c2ecf20Sopenharmony_ci	*p++ = xdr_one;
1978c2ecf20Sopenharmony_ci	return encode_fattr3(rqstp, p, fhp, &fhp->fh_post_attr);
1988c2ecf20Sopenharmony_ci}
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_ci/*
2018c2ecf20Sopenharmony_ci * Encode post-operation attributes.
2028c2ecf20Sopenharmony_ci * The inode may be NULL if the call failed because of a stale file
2038c2ecf20Sopenharmony_ci * handle. In this case, no attributes are returned.
2048c2ecf20Sopenharmony_ci */
2058c2ecf20Sopenharmony_cistatic __be32 *
2068c2ecf20Sopenharmony_ciencode_post_op_attr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp)
2078c2ecf20Sopenharmony_ci{
2088c2ecf20Sopenharmony_ci	struct dentry *dentry = fhp->fh_dentry;
2098c2ecf20Sopenharmony_ci	if (dentry && d_really_is_positive(dentry)) {
2108c2ecf20Sopenharmony_ci	        __be32 err;
2118c2ecf20Sopenharmony_ci		struct kstat stat;
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_ci		err = fh_getattr(fhp, &stat);
2148c2ecf20Sopenharmony_ci		if (!err) {
2158c2ecf20Sopenharmony_ci			*p++ = xdr_one;		/* attributes follow */
2168c2ecf20Sopenharmony_ci			lease_get_mtime(d_inode(dentry), &stat.mtime);
2178c2ecf20Sopenharmony_ci			return encode_fattr3(rqstp, p, fhp, &stat);
2188c2ecf20Sopenharmony_ci		}
2198c2ecf20Sopenharmony_ci	}
2208c2ecf20Sopenharmony_ci	*p++ = xdr_zero;
2218c2ecf20Sopenharmony_ci	return p;
2228c2ecf20Sopenharmony_ci}
2238c2ecf20Sopenharmony_ci
2248c2ecf20Sopenharmony_ci/* Helper for NFSv3 ACLs */
2258c2ecf20Sopenharmony_ci__be32 *
2268c2ecf20Sopenharmony_cinfs3svc_encode_post_op_attr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp)
2278c2ecf20Sopenharmony_ci{
2288c2ecf20Sopenharmony_ci	return encode_post_op_attr(rqstp, p, fhp);
2298c2ecf20Sopenharmony_ci}
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_ci/*
2328c2ecf20Sopenharmony_ci * Enocde weak cache consistency data
2338c2ecf20Sopenharmony_ci */
2348c2ecf20Sopenharmony_cistatic __be32 *
2358c2ecf20Sopenharmony_ciencode_wcc_data(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp)
2368c2ecf20Sopenharmony_ci{
2378c2ecf20Sopenharmony_ci	struct dentry	*dentry = fhp->fh_dentry;
2388c2ecf20Sopenharmony_ci
2398c2ecf20Sopenharmony_ci	if (dentry && d_really_is_positive(dentry) && fhp->fh_post_saved) {
2408c2ecf20Sopenharmony_ci		if (fhp->fh_pre_saved) {
2418c2ecf20Sopenharmony_ci			*p++ = xdr_one;
2428c2ecf20Sopenharmony_ci			p = xdr_encode_hyper(p, (u64) fhp->fh_pre_size);
2438c2ecf20Sopenharmony_ci			p = encode_time3(p, &fhp->fh_pre_mtime);
2448c2ecf20Sopenharmony_ci			p = encode_time3(p, &fhp->fh_pre_ctime);
2458c2ecf20Sopenharmony_ci		} else {
2468c2ecf20Sopenharmony_ci			*p++ = xdr_zero;
2478c2ecf20Sopenharmony_ci		}
2488c2ecf20Sopenharmony_ci		return encode_saved_post_attr(rqstp, p, fhp);
2498c2ecf20Sopenharmony_ci	}
2508c2ecf20Sopenharmony_ci	/* no pre- or post-attrs */
2518c2ecf20Sopenharmony_ci	*p++ = xdr_zero;
2528c2ecf20Sopenharmony_ci	return encode_post_op_attr(rqstp, p, fhp);
2538c2ecf20Sopenharmony_ci}
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_ci/*
2568c2ecf20Sopenharmony_ci * Fill in the pre_op attr for the wcc data
2578c2ecf20Sopenharmony_ci */
2588c2ecf20Sopenharmony_civoid fill_pre_wcc(struct svc_fh *fhp)
2598c2ecf20Sopenharmony_ci{
2608c2ecf20Sopenharmony_ci	struct inode    *inode;
2618c2ecf20Sopenharmony_ci	struct kstat	stat;
2628c2ecf20Sopenharmony_ci	__be32 err;
2638c2ecf20Sopenharmony_ci
2648c2ecf20Sopenharmony_ci	if (fhp->fh_pre_saved)
2658c2ecf20Sopenharmony_ci		return;
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_ci	inode = d_inode(fhp->fh_dentry);
2688c2ecf20Sopenharmony_ci	err = fh_getattr(fhp, &stat);
2698c2ecf20Sopenharmony_ci	if (err) {
2708c2ecf20Sopenharmony_ci		/* Grab the times from inode anyway */
2718c2ecf20Sopenharmony_ci		stat.mtime = inode->i_mtime;
2728c2ecf20Sopenharmony_ci		stat.ctime = inode->i_ctime;
2738c2ecf20Sopenharmony_ci		stat.size  = inode->i_size;
2748c2ecf20Sopenharmony_ci	}
2758c2ecf20Sopenharmony_ci
2768c2ecf20Sopenharmony_ci	fhp->fh_pre_mtime = stat.mtime;
2778c2ecf20Sopenharmony_ci	fhp->fh_pre_ctime = stat.ctime;
2788c2ecf20Sopenharmony_ci	fhp->fh_pre_size  = stat.size;
2798c2ecf20Sopenharmony_ci	fhp->fh_pre_change = nfsd4_change_attribute(&stat, inode);
2808c2ecf20Sopenharmony_ci	fhp->fh_pre_saved = true;
2818c2ecf20Sopenharmony_ci}
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_ci/*
2848c2ecf20Sopenharmony_ci * Fill in the post_op attr for the wcc data
2858c2ecf20Sopenharmony_ci */
2868c2ecf20Sopenharmony_civoid fill_post_wcc(struct svc_fh *fhp)
2878c2ecf20Sopenharmony_ci{
2888c2ecf20Sopenharmony_ci	__be32 err;
2898c2ecf20Sopenharmony_ci
2908c2ecf20Sopenharmony_ci	if (fhp->fh_post_saved)
2918c2ecf20Sopenharmony_ci		printk("nfsd: inode locked twice during operation.\n");
2928c2ecf20Sopenharmony_ci
2938c2ecf20Sopenharmony_ci	err = fh_getattr(fhp, &fhp->fh_post_attr);
2948c2ecf20Sopenharmony_ci	fhp->fh_post_change = nfsd4_change_attribute(&fhp->fh_post_attr,
2958c2ecf20Sopenharmony_ci						     d_inode(fhp->fh_dentry));
2968c2ecf20Sopenharmony_ci	if (err) {
2978c2ecf20Sopenharmony_ci		fhp->fh_post_saved = false;
2988c2ecf20Sopenharmony_ci		/* Grab the ctime anyway - set_change_info might use it */
2998c2ecf20Sopenharmony_ci		fhp->fh_post_attr.ctime = d_inode(fhp->fh_dentry)->i_ctime;
3008c2ecf20Sopenharmony_ci	} else
3018c2ecf20Sopenharmony_ci		fhp->fh_post_saved = true;
3028c2ecf20Sopenharmony_ci}
3038c2ecf20Sopenharmony_ci
3048c2ecf20Sopenharmony_ci/*
3058c2ecf20Sopenharmony_ci * XDR decode functions
3068c2ecf20Sopenharmony_ci */
3078c2ecf20Sopenharmony_ciint
3088c2ecf20Sopenharmony_cinfs3svc_decode_voidarg(struct svc_rqst *rqstp, __be32 *p)
3098c2ecf20Sopenharmony_ci{
3108c2ecf20Sopenharmony_ci	return 1;
3118c2ecf20Sopenharmony_ci}
3128c2ecf20Sopenharmony_ci
3138c2ecf20Sopenharmony_ciint
3148c2ecf20Sopenharmony_cinfs3svc_decode_fhandle(struct svc_rqst *rqstp, __be32 *p)
3158c2ecf20Sopenharmony_ci{
3168c2ecf20Sopenharmony_ci	struct nfsd_fhandle *args = rqstp->rq_argp;
3178c2ecf20Sopenharmony_ci
3188c2ecf20Sopenharmony_ci	p = decode_fh(p, &args->fh);
3198c2ecf20Sopenharmony_ci	if (!p)
3208c2ecf20Sopenharmony_ci		return 0;
3218c2ecf20Sopenharmony_ci	return xdr_argsize_check(rqstp, p);
3228c2ecf20Sopenharmony_ci}
3238c2ecf20Sopenharmony_ci
3248c2ecf20Sopenharmony_ciint
3258c2ecf20Sopenharmony_cinfs3svc_decode_sattrargs(struct svc_rqst *rqstp, __be32 *p)
3268c2ecf20Sopenharmony_ci{
3278c2ecf20Sopenharmony_ci	struct nfsd3_sattrargs *args = rqstp->rq_argp;
3288c2ecf20Sopenharmony_ci
3298c2ecf20Sopenharmony_ci	p = decode_fh(p, &args->fh);
3308c2ecf20Sopenharmony_ci	if (!p)
3318c2ecf20Sopenharmony_ci		return 0;
3328c2ecf20Sopenharmony_ci	p = decode_sattr3(p, &args->attrs, nfsd_user_namespace(rqstp));
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_ci	if ((args->check_guard = ntohl(*p++)) != 0) {
3358c2ecf20Sopenharmony_ci		struct timespec64 time;
3368c2ecf20Sopenharmony_ci		p = decode_time3(p, &time);
3378c2ecf20Sopenharmony_ci		args->guardtime = time.tv_sec;
3388c2ecf20Sopenharmony_ci	}
3398c2ecf20Sopenharmony_ci
3408c2ecf20Sopenharmony_ci	return xdr_argsize_check(rqstp, p);
3418c2ecf20Sopenharmony_ci}
3428c2ecf20Sopenharmony_ci
3438c2ecf20Sopenharmony_ciint
3448c2ecf20Sopenharmony_cinfs3svc_decode_diropargs(struct svc_rqst *rqstp, __be32 *p)
3458c2ecf20Sopenharmony_ci{
3468c2ecf20Sopenharmony_ci	struct nfsd3_diropargs *args = rqstp->rq_argp;
3478c2ecf20Sopenharmony_ci
3488c2ecf20Sopenharmony_ci	if (!(p = decode_fh(p, &args->fh))
3498c2ecf20Sopenharmony_ci	 || !(p = decode_filename(p, &args->name, &args->len)))
3508c2ecf20Sopenharmony_ci		return 0;
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_ci	return xdr_argsize_check(rqstp, p);
3538c2ecf20Sopenharmony_ci}
3548c2ecf20Sopenharmony_ci
3558c2ecf20Sopenharmony_ciint
3568c2ecf20Sopenharmony_cinfs3svc_decode_accessargs(struct svc_rqst *rqstp, __be32 *p)
3578c2ecf20Sopenharmony_ci{
3588c2ecf20Sopenharmony_ci	struct nfsd3_accessargs *args = rqstp->rq_argp;
3598c2ecf20Sopenharmony_ci
3608c2ecf20Sopenharmony_ci	p = decode_fh(p, &args->fh);
3618c2ecf20Sopenharmony_ci	if (!p)
3628c2ecf20Sopenharmony_ci		return 0;
3638c2ecf20Sopenharmony_ci	args->access = ntohl(*p++);
3648c2ecf20Sopenharmony_ci
3658c2ecf20Sopenharmony_ci	return xdr_argsize_check(rqstp, p);
3668c2ecf20Sopenharmony_ci}
3678c2ecf20Sopenharmony_ci
3688c2ecf20Sopenharmony_ciint
3698c2ecf20Sopenharmony_cinfs3svc_decode_readargs(struct svc_rqst *rqstp, __be32 *p)
3708c2ecf20Sopenharmony_ci{
3718c2ecf20Sopenharmony_ci	struct nfsd3_readargs *args = rqstp->rq_argp;
3728c2ecf20Sopenharmony_ci	unsigned int len;
3738c2ecf20Sopenharmony_ci	int v;
3748c2ecf20Sopenharmony_ci	u32 max_blocksize = svc_max_payload(rqstp);
3758c2ecf20Sopenharmony_ci
3768c2ecf20Sopenharmony_ci	p = decode_fh(p, &args->fh);
3778c2ecf20Sopenharmony_ci	if (!p)
3788c2ecf20Sopenharmony_ci		return 0;
3798c2ecf20Sopenharmony_ci	p = xdr_decode_hyper(p, &args->offset);
3808c2ecf20Sopenharmony_ci
3818c2ecf20Sopenharmony_ci	args->count = ntohl(*p++);
3828c2ecf20Sopenharmony_ci	len = min(args->count, max_blocksize);
3838c2ecf20Sopenharmony_ci
3848c2ecf20Sopenharmony_ci	/* set up the kvec */
3858c2ecf20Sopenharmony_ci	v=0;
3868c2ecf20Sopenharmony_ci	while (len > 0) {
3878c2ecf20Sopenharmony_ci		struct page *p = *(rqstp->rq_next_page++);
3888c2ecf20Sopenharmony_ci
3898c2ecf20Sopenharmony_ci		rqstp->rq_vec[v].iov_base = page_address(p);
3908c2ecf20Sopenharmony_ci		rqstp->rq_vec[v].iov_len = min_t(unsigned int, len, PAGE_SIZE);
3918c2ecf20Sopenharmony_ci		len -= rqstp->rq_vec[v].iov_len;
3928c2ecf20Sopenharmony_ci		v++;
3938c2ecf20Sopenharmony_ci	}
3948c2ecf20Sopenharmony_ci	args->vlen = v;
3958c2ecf20Sopenharmony_ci	return xdr_argsize_check(rqstp, p);
3968c2ecf20Sopenharmony_ci}
3978c2ecf20Sopenharmony_ci
3988c2ecf20Sopenharmony_ciint
3998c2ecf20Sopenharmony_cinfs3svc_decode_writeargs(struct svc_rqst *rqstp, __be32 *p)
4008c2ecf20Sopenharmony_ci{
4018c2ecf20Sopenharmony_ci	struct nfsd3_writeargs *args = rqstp->rq_argp;
4028c2ecf20Sopenharmony_ci	unsigned int len, hdr, dlen;
4038c2ecf20Sopenharmony_ci	u32 max_blocksize = svc_max_payload(rqstp);
4048c2ecf20Sopenharmony_ci	struct kvec *head = rqstp->rq_arg.head;
4058c2ecf20Sopenharmony_ci	struct kvec *tail = rqstp->rq_arg.tail;
4068c2ecf20Sopenharmony_ci
4078c2ecf20Sopenharmony_ci	p = decode_fh(p, &args->fh);
4088c2ecf20Sopenharmony_ci	if (!p)
4098c2ecf20Sopenharmony_ci		return 0;
4108c2ecf20Sopenharmony_ci	p = xdr_decode_hyper(p, &args->offset);
4118c2ecf20Sopenharmony_ci
4128c2ecf20Sopenharmony_ci	args->count = ntohl(*p++);
4138c2ecf20Sopenharmony_ci	args->stable = ntohl(*p++);
4148c2ecf20Sopenharmony_ci	len = args->len = ntohl(*p++);
4158c2ecf20Sopenharmony_ci	if ((void *)p > head->iov_base + head->iov_len)
4168c2ecf20Sopenharmony_ci		return 0;
4178c2ecf20Sopenharmony_ci	/*
4188c2ecf20Sopenharmony_ci	 * The count must equal the amount of data passed.
4198c2ecf20Sopenharmony_ci	 */
4208c2ecf20Sopenharmony_ci	if (args->count != args->len)
4218c2ecf20Sopenharmony_ci		return 0;
4228c2ecf20Sopenharmony_ci
4238c2ecf20Sopenharmony_ci	/*
4248c2ecf20Sopenharmony_ci	 * Check to make sure that we got the right number of
4258c2ecf20Sopenharmony_ci	 * bytes.
4268c2ecf20Sopenharmony_ci	 */
4278c2ecf20Sopenharmony_ci	hdr = (void*)p - head->iov_base;
4288c2ecf20Sopenharmony_ci	dlen = head->iov_len + rqstp->rq_arg.page_len + tail->iov_len - hdr;
4298c2ecf20Sopenharmony_ci	/*
4308c2ecf20Sopenharmony_ci	 * Round the length of the data which was specified up to
4318c2ecf20Sopenharmony_ci	 * the next multiple of XDR units and then compare that
4328c2ecf20Sopenharmony_ci	 * against the length which was actually received.
4338c2ecf20Sopenharmony_ci	 * Note that when RPCSEC/GSS (for example) is used, the
4348c2ecf20Sopenharmony_ci	 * data buffer can be padded so dlen might be larger
4358c2ecf20Sopenharmony_ci	 * than required.  It must never be smaller.
4368c2ecf20Sopenharmony_ci	 */
4378c2ecf20Sopenharmony_ci	if (dlen < XDR_QUADLEN(len)*4)
4388c2ecf20Sopenharmony_ci		return 0;
4398c2ecf20Sopenharmony_ci
4408c2ecf20Sopenharmony_ci	if (args->count > max_blocksize) {
4418c2ecf20Sopenharmony_ci		args->count = max_blocksize;
4428c2ecf20Sopenharmony_ci		len = args->len = max_blocksize;
4438c2ecf20Sopenharmony_ci	}
4448c2ecf20Sopenharmony_ci
4458c2ecf20Sopenharmony_ci	args->first.iov_base = (void *)p;
4468c2ecf20Sopenharmony_ci	args->first.iov_len = head->iov_len - hdr;
4478c2ecf20Sopenharmony_ci	return 1;
4488c2ecf20Sopenharmony_ci}
4498c2ecf20Sopenharmony_ci
4508c2ecf20Sopenharmony_ciint
4518c2ecf20Sopenharmony_cinfs3svc_decode_createargs(struct svc_rqst *rqstp, __be32 *p)
4528c2ecf20Sopenharmony_ci{
4538c2ecf20Sopenharmony_ci	struct nfsd3_createargs *args = rqstp->rq_argp;
4548c2ecf20Sopenharmony_ci
4558c2ecf20Sopenharmony_ci	if (!(p = decode_fh(p, &args->fh))
4568c2ecf20Sopenharmony_ci	 || !(p = decode_filename(p, &args->name, &args->len)))
4578c2ecf20Sopenharmony_ci		return 0;
4588c2ecf20Sopenharmony_ci
4598c2ecf20Sopenharmony_ci	switch (args->createmode = ntohl(*p++)) {
4608c2ecf20Sopenharmony_ci	case NFS3_CREATE_UNCHECKED:
4618c2ecf20Sopenharmony_ci	case NFS3_CREATE_GUARDED:
4628c2ecf20Sopenharmony_ci		p = decode_sattr3(p, &args->attrs, nfsd_user_namespace(rqstp));
4638c2ecf20Sopenharmony_ci		break;
4648c2ecf20Sopenharmony_ci	case NFS3_CREATE_EXCLUSIVE:
4658c2ecf20Sopenharmony_ci		args->verf = p;
4668c2ecf20Sopenharmony_ci		p += 2;
4678c2ecf20Sopenharmony_ci		break;
4688c2ecf20Sopenharmony_ci	default:
4698c2ecf20Sopenharmony_ci		return 0;
4708c2ecf20Sopenharmony_ci	}
4718c2ecf20Sopenharmony_ci
4728c2ecf20Sopenharmony_ci	return xdr_argsize_check(rqstp, p);
4738c2ecf20Sopenharmony_ci}
4748c2ecf20Sopenharmony_ci
4758c2ecf20Sopenharmony_ciint
4768c2ecf20Sopenharmony_cinfs3svc_decode_mkdirargs(struct svc_rqst *rqstp, __be32 *p)
4778c2ecf20Sopenharmony_ci{
4788c2ecf20Sopenharmony_ci	struct nfsd3_createargs *args = rqstp->rq_argp;
4798c2ecf20Sopenharmony_ci
4808c2ecf20Sopenharmony_ci	if (!(p = decode_fh(p, &args->fh)) ||
4818c2ecf20Sopenharmony_ci	    !(p = decode_filename(p, &args->name, &args->len)))
4828c2ecf20Sopenharmony_ci		return 0;
4838c2ecf20Sopenharmony_ci	p = decode_sattr3(p, &args->attrs, nfsd_user_namespace(rqstp));
4848c2ecf20Sopenharmony_ci
4858c2ecf20Sopenharmony_ci	return xdr_argsize_check(rqstp, p);
4868c2ecf20Sopenharmony_ci}
4878c2ecf20Sopenharmony_ci
4888c2ecf20Sopenharmony_ciint
4898c2ecf20Sopenharmony_cinfs3svc_decode_symlinkargs(struct svc_rqst *rqstp, __be32 *p)
4908c2ecf20Sopenharmony_ci{
4918c2ecf20Sopenharmony_ci	struct nfsd3_symlinkargs *args = rqstp->rq_argp;
4928c2ecf20Sopenharmony_ci	char *base = (char *)p;
4938c2ecf20Sopenharmony_ci	size_t dlen;
4948c2ecf20Sopenharmony_ci
4958c2ecf20Sopenharmony_ci	if (!(p = decode_fh(p, &args->ffh)) ||
4968c2ecf20Sopenharmony_ci	    !(p = decode_filename(p, &args->fname, &args->flen)))
4978c2ecf20Sopenharmony_ci		return 0;
4988c2ecf20Sopenharmony_ci	p = decode_sattr3(p, &args->attrs, nfsd_user_namespace(rqstp));
4998c2ecf20Sopenharmony_ci
5008c2ecf20Sopenharmony_ci	args->tlen = ntohl(*p++);
5018c2ecf20Sopenharmony_ci
5028c2ecf20Sopenharmony_ci	args->first.iov_base = p;
5038c2ecf20Sopenharmony_ci	args->first.iov_len = rqstp->rq_arg.head[0].iov_len;
5048c2ecf20Sopenharmony_ci	args->first.iov_len -= (char *)p - base;
5058c2ecf20Sopenharmony_ci
5068c2ecf20Sopenharmony_ci	dlen = args->first.iov_len + rqstp->rq_arg.page_len +
5078c2ecf20Sopenharmony_ci	       rqstp->rq_arg.tail[0].iov_len;
5088c2ecf20Sopenharmony_ci	if (dlen < XDR_QUADLEN(args->tlen) << 2)
5098c2ecf20Sopenharmony_ci		return 0;
5108c2ecf20Sopenharmony_ci	return 1;
5118c2ecf20Sopenharmony_ci}
5128c2ecf20Sopenharmony_ci
5138c2ecf20Sopenharmony_ciint
5148c2ecf20Sopenharmony_cinfs3svc_decode_mknodargs(struct svc_rqst *rqstp, __be32 *p)
5158c2ecf20Sopenharmony_ci{
5168c2ecf20Sopenharmony_ci	struct nfsd3_mknodargs *args = rqstp->rq_argp;
5178c2ecf20Sopenharmony_ci
5188c2ecf20Sopenharmony_ci	if (!(p = decode_fh(p, &args->fh))
5198c2ecf20Sopenharmony_ci	 || !(p = decode_filename(p, &args->name, &args->len)))
5208c2ecf20Sopenharmony_ci		return 0;
5218c2ecf20Sopenharmony_ci
5228c2ecf20Sopenharmony_ci	args->ftype = ntohl(*p++);
5238c2ecf20Sopenharmony_ci
5248c2ecf20Sopenharmony_ci	if (args->ftype == NF3BLK  || args->ftype == NF3CHR
5258c2ecf20Sopenharmony_ci	 || args->ftype == NF3SOCK || args->ftype == NF3FIFO)
5268c2ecf20Sopenharmony_ci		p = decode_sattr3(p, &args->attrs, nfsd_user_namespace(rqstp));
5278c2ecf20Sopenharmony_ci
5288c2ecf20Sopenharmony_ci	if (args->ftype == NF3BLK || args->ftype == NF3CHR) {
5298c2ecf20Sopenharmony_ci		args->major = ntohl(*p++);
5308c2ecf20Sopenharmony_ci		args->minor = ntohl(*p++);
5318c2ecf20Sopenharmony_ci	}
5328c2ecf20Sopenharmony_ci
5338c2ecf20Sopenharmony_ci	return xdr_argsize_check(rqstp, p);
5348c2ecf20Sopenharmony_ci}
5358c2ecf20Sopenharmony_ci
5368c2ecf20Sopenharmony_ciint
5378c2ecf20Sopenharmony_cinfs3svc_decode_renameargs(struct svc_rqst *rqstp, __be32 *p)
5388c2ecf20Sopenharmony_ci{
5398c2ecf20Sopenharmony_ci	struct nfsd3_renameargs *args = rqstp->rq_argp;
5408c2ecf20Sopenharmony_ci
5418c2ecf20Sopenharmony_ci	if (!(p = decode_fh(p, &args->ffh))
5428c2ecf20Sopenharmony_ci	 || !(p = decode_filename(p, &args->fname, &args->flen))
5438c2ecf20Sopenharmony_ci	 || !(p = decode_fh(p, &args->tfh))
5448c2ecf20Sopenharmony_ci	 || !(p = decode_filename(p, &args->tname, &args->tlen)))
5458c2ecf20Sopenharmony_ci		return 0;
5468c2ecf20Sopenharmony_ci
5478c2ecf20Sopenharmony_ci	return xdr_argsize_check(rqstp, p);
5488c2ecf20Sopenharmony_ci}
5498c2ecf20Sopenharmony_ci
5508c2ecf20Sopenharmony_ciint
5518c2ecf20Sopenharmony_cinfs3svc_decode_readlinkargs(struct svc_rqst *rqstp, __be32 *p)
5528c2ecf20Sopenharmony_ci{
5538c2ecf20Sopenharmony_ci	struct nfsd3_readlinkargs *args = rqstp->rq_argp;
5548c2ecf20Sopenharmony_ci
5558c2ecf20Sopenharmony_ci	p = decode_fh(p, &args->fh);
5568c2ecf20Sopenharmony_ci	if (!p)
5578c2ecf20Sopenharmony_ci		return 0;
5588c2ecf20Sopenharmony_ci	args->buffer = page_address(*(rqstp->rq_next_page++));
5598c2ecf20Sopenharmony_ci
5608c2ecf20Sopenharmony_ci	return xdr_argsize_check(rqstp, p);
5618c2ecf20Sopenharmony_ci}
5628c2ecf20Sopenharmony_ci
5638c2ecf20Sopenharmony_ciint
5648c2ecf20Sopenharmony_cinfs3svc_decode_linkargs(struct svc_rqst *rqstp, __be32 *p)
5658c2ecf20Sopenharmony_ci{
5668c2ecf20Sopenharmony_ci	struct nfsd3_linkargs *args = rqstp->rq_argp;
5678c2ecf20Sopenharmony_ci
5688c2ecf20Sopenharmony_ci	if (!(p = decode_fh(p, &args->ffh))
5698c2ecf20Sopenharmony_ci	 || !(p = decode_fh(p, &args->tfh))
5708c2ecf20Sopenharmony_ci	 || !(p = decode_filename(p, &args->tname, &args->tlen)))
5718c2ecf20Sopenharmony_ci		return 0;
5728c2ecf20Sopenharmony_ci
5738c2ecf20Sopenharmony_ci	return xdr_argsize_check(rqstp, p);
5748c2ecf20Sopenharmony_ci}
5758c2ecf20Sopenharmony_ci
5768c2ecf20Sopenharmony_ciint
5778c2ecf20Sopenharmony_cinfs3svc_decode_readdirargs(struct svc_rqst *rqstp, __be32 *p)
5788c2ecf20Sopenharmony_ci{
5798c2ecf20Sopenharmony_ci	struct nfsd3_readdirargs *args = rqstp->rq_argp;
5808c2ecf20Sopenharmony_ci	int len;
5818c2ecf20Sopenharmony_ci	u32 max_blocksize = svc_max_payload(rqstp);
5828c2ecf20Sopenharmony_ci
5838c2ecf20Sopenharmony_ci	p = decode_fh(p, &args->fh);
5848c2ecf20Sopenharmony_ci	if (!p)
5858c2ecf20Sopenharmony_ci		return 0;
5868c2ecf20Sopenharmony_ci	p = xdr_decode_hyper(p, &args->cookie);
5878c2ecf20Sopenharmony_ci	args->verf   = p; p += 2;
5888c2ecf20Sopenharmony_ci	args->dircount = ~0;
5898c2ecf20Sopenharmony_ci	args->count  = ntohl(*p++);
5908c2ecf20Sopenharmony_ci	len = args->count  = min_t(u32, args->count, max_blocksize);
5918c2ecf20Sopenharmony_ci
5928c2ecf20Sopenharmony_ci	while (len > 0) {
5938c2ecf20Sopenharmony_ci		struct page *p = *(rqstp->rq_next_page++);
5948c2ecf20Sopenharmony_ci		if (!args->buffer)
5958c2ecf20Sopenharmony_ci			args->buffer = page_address(p);
5968c2ecf20Sopenharmony_ci		len -= PAGE_SIZE;
5978c2ecf20Sopenharmony_ci	}
5988c2ecf20Sopenharmony_ci
5998c2ecf20Sopenharmony_ci	return xdr_argsize_check(rqstp, p);
6008c2ecf20Sopenharmony_ci}
6018c2ecf20Sopenharmony_ci
6028c2ecf20Sopenharmony_ciint
6038c2ecf20Sopenharmony_cinfs3svc_decode_readdirplusargs(struct svc_rqst *rqstp, __be32 *p)
6048c2ecf20Sopenharmony_ci{
6058c2ecf20Sopenharmony_ci	struct nfsd3_readdirargs *args = rqstp->rq_argp;
6068c2ecf20Sopenharmony_ci	int len;
6078c2ecf20Sopenharmony_ci	u32 max_blocksize = svc_max_payload(rqstp);
6088c2ecf20Sopenharmony_ci
6098c2ecf20Sopenharmony_ci	p = decode_fh(p, &args->fh);
6108c2ecf20Sopenharmony_ci	if (!p)
6118c2ecf20Sopenharmony_ci		return 0;
6128c2ecf20Sopenharmony_ci	p = xdr_decode_hyper(p, &args->cookie);
6138c2ecf20Sopenharmony_ci	args->verf     = p; p += 2;
6148c2ecf20Sopenharmony_ci	args->dircount = ntohl(*p++);
6158c2ecf20Sopenharmony_ci	args->count    = ntohl(*p++);
6168c2ecf20Sopenharmony_ci
6178c2ecf20Sopenharmony_ci	len = args->count = min(args->count, max_blocksize);
6188c2ecf20Sopenharmony_ci	while (len > 0) {
6198c2ecf20Sopenharmony_ci		struct page *p = *(rqstp->rq_next_page++);
6208c2ecf20Sopenharmony_ci		if (!args->buffer)
6218c2ecf20Sopenharmony_ci			args->buffer = page_address(p);
6228c2ecf20Sopenharmony_ci		len -= PAGE_SIZE;
6238c2ecf20Sopenharmony_ci	}
6248c2ecf20Sopenharmony_ci
6258c2ecf20Sopenharmony_ci	return xdr_argsize_check(rqstp, p);
6268c2ecf20Sopenharmony_ci}
6278c2ecf20Sopenharmony_ci
6288c2ecf20Sopenharmony_ciint
6298c2ecf20Sopenharmony_cinfs3svc_decode_commitargs(struct svc_rqst *rqstp, __be32 *p)
6308c2ecf20Sopenharmony_ci{
6318c2ecf20Sopenharmony_ci	struct nfsd3_commitargs *args = rqstp->rq_argp;
6328c2ecf20Sopenharmony_ci	p = decode_fh(p, &args->fh);
6338c2ecf20Sopenharmony_ci	if (!p)
6348c2ecf20Sopenharmony_ci		return 0;
6358c2ecf20Sopenharmony_ci	p = xdr_decode_hyper(p, &args->offset);
6368c2ecf20Sopenharmony_ci	args->count = ntohl(*p++);
6378c2ecf20Sopenharmony_ci
6388c2ecf20Sopenharmony_ci	return xdr_argsize_check(rqstp, p);
6398c2ecf20Sopenharmony_ci}
6408c2ecf20Sopenharmony_ci
6418c2ecf20Sopenharmony_ci/*
6428c2ecf20Sopenharmony_ci * XDR encode functions
6438c2ecf20Sopenharmony_ci */
6448c2ecf20Sopenharmony_ci
6458c2ecf20Sopenharmony_ciint
6468c2ecf20Sopenharmony_cinfs3svc_encode_voidres(struct svc_rqst *rqstp, __be32 *p)
6478c2ecf20Sopenharmony_ci{
6488c2ecf20Sopenharmony_ci	return xdr_ressize_check(rqstp, p);
6498c2ecf20Sopenharmony_ci}
6508c2ecf20Sopenharmony_ci
6518c2ecf20Sopenharmony_ci/* GETATTR */
6528c2ecf20Sopenharmony_ciint
6538c2ecf20Sopenharmony_cinfs3svc_encode_attrstat(struct svc_rqst *rqstp, __be32 *p)
6548c2ecf20Sopenharmony_ci{
6558c2ecf20Sopenharmony_ci	struct nfsd3_attrstat *resp = rqstp->rq_resp;
6568c2ecf20Sopenharmony_ci
6578c2ecf20Sopenharmony_ci	*p++ = resp->status;
6588c2ecf20Sopenharmony_ci	if (resp->status == 0) {
6598c2ecf20Sopenharmony_ci		lease_get_mtime(d_inode(resp->fh.fh_dentry),
6608c2ecf20Sopenharmony_ci				&resp->stat.mtime);
6618c2ecf20Sopenharmony_ci		p = encode_fattr3(rqstp, p, &resp->fh, &resp->stat);
6628c2ecf20Sopenharmony_ci	}
6638c2ecf20Sopenharmony_ci	return xdr_ressize_check(rqstp, p);
6648c2ecf20Sopenharmony_ci}
6658c2ecf20Sopenharmony_ci
6668c2ecf20Sopenharmony_ci/* SETATTR, REMOVE, RMDIR */
6678c2ecf20Sopenharmony_ciint
6688c2ecf20Sopenharmony_cinfs3svc_encode_wccstat(struct svc_rqst *rqstp, __be32 *p)
6698c2ecf20Sopenharmony_ci{
6708c2ecf20Sopenharmony_ci	struct nfsd3_attrstat *resp = rqstp->rq_resp;
6718c2ecf20Sopenharmony_ci
6728c2ecf20Sopenharmony_ci	*p++ = resp->status;
6738c2ecf20Sopenharmony_ci	p = encode_wcc_data(rqstp, p, &resp->fh);
6748c2ecf20Sopenharmony_ci	return xdr_ressize_check(rqstp, p);
6758c2ecf20Sopenharmony_ci}
6768c2ecf20Sopenharmony_ci
6778c2ecf20Sopenharmony_ci/* LOOKUP */
6788c2ecf20Sopenharmony_ciint
6798c2ecf20Sopenharmony_cinfs3svc_encode_diropres(struct svc_rqst *rqstp, __be32 *p)
6808c2ecf20Sopenharmony_ci{
6818c2ecf20Sopenharmony_ci	struct nfsd3_diropres *resp = rqstp->rq_resp;
6828c2ecf20Sopenharmony_ci
6838c2ecf20Sopenharmony_ci	*p++ = resp->status;
6848c2ecf20Sopenharmony_ci	if (resp->status == 0) {
6858c2ecf20Sopenharmony_ci		p = encode_fh(p, &resp->fh);
6868c2ecf20Sopenharmony_ci		p = encode_post_op_attr(rqstp, p, &resp->fh);
6878c2ecf20Sopenharmony_ci	}
6888c2ecf20Sopenharmony_ci	p = encode_post_op_attr(rqstp, p, &resp->dirfh);
6898c2ecf20Sopenharmony_ci	return xdr_ressize_check(rqstp, p);
6908c2ecf20Sopenharmony_ci}
6918c2ecf20Sopenharmony_ci
6928c2ecf20Sopenharmony_ci/* ACCESS */
6938c2ecf20Sopenharmony_ciint
6948c2ecf20Sopenharmony_cinfs3svc_encode_accessres(struct svc_rqst *rqstp, __be32 *p)
6958c2ecf20Sopenharmony_ci{
6968c2ecf20Sopenharmony_ci	struct nfsd3_accessres *resp = rqstp->rq_resp;
6978c2ecf20Sopenharmony_ci
6988c2ecf20Sopenharmony_ci	*p++ = resp->status;
6998c2ecf20Sopenharmony_ci	p = encode_post_op_attr(rqstp, p, &resp->fh);
7008c2ecf20Sopenharmony_ci	if (resp->status == 0)
7018c2ecf20Sopenharmony_ci		*p++ = htonl(resp->access);
7028c2ecf20Sopenharmony_ci	return xdr_ressize_check(rqstp, p);
7038c2ecf20Sopenharmony_ci}
7048c2ecf20Sopenharmony_ci
7058c2ecf20Sopenharmony_ci/* READLINK */
7068c2ecf20Sopenharmony_ciint
7078c2ecf20Sopenharmony_cinfs3svc_encode_readlinkres(struct svc_rqst *rqstp, __be32 *p)
7088c2ecf20Sopenharmony_ci{
7098c2ecf20Sopenharmony_ci	struct nfsd3_readlinkres *resp = rqstp->rq_resp;
7108c2ecf20Sopenharmony_ci
7118c2ecf20Sopenharmony_ci	*p++ = resp->status;
7128c2ecf20Sopenharmony_ci	p = encode_post_op_attr(rqstp, p, &resp->fh);
7138c2ecf20Sopenharmony_ci	if (resp->status == 0) {
7148c2ecf20Sopenharmony_ci		*p++ = htonl(resp->len);
7158c2ecf20Sopenharmony_ci		xdr_ressize_check(rqstp, p);
7168c2ecf20Sopenharmony_ci		rqstp->rq_res.page_len = resp->len;
7178c2ecf20Sopenharmony_ci		if (resp->len & 3) {
7188c2ecf20Sopenharmony_ci			/* need to pad the tail */
7198c2ecf20Sopenharmony_ci			rqstp->rq_res.tail[0].iov_base = p;
7208c2ecf20Sopenharmony_ci			*p = 0;
7218c2ecf20Sopenharmony_ci			rqstp->rq_res.tail[0].iov_len = 4 - (resp->len&3);
7228c2ecf20Sopenharmony_ci		}
7238c2ecf20Sopenharmony_ci		return 1;
7248c2ecf20Sopenharmony_ci	} else
7258c2ecf20Sopenharmony_ci		return xdr_ressize_check(rqstp, p);
7268c2ecf20Sopenharmony_ci}
7278c2ecf20Sopenharmony_ci
7288c2ecf20Sopenharmony_ci/* READ */
7298c2ecf20Sopenharmony_ciint
7308c2ecf20Sopenharmony_cinfs3svc_encode_readres(struct svc_rqst *rqstp, __be32 *p)
7318c2ecf20Sopenharmony_ci{
7328c2ecf20Sopenharmony_ci	struct nfsd3_readres *resp = rqstp->rq_resp;
7338c2ecf20Sopenharmony_ci
7348c2ecf20Sopenharmony_ci	*p++ = resp->status;
7358c2ecf20Sopenharmony_ci	p = encode_post_op_attr(rqstp, p, &resp->fh);
7368c2ecf20Sopenharmony_ci	if (resp->status == 0) {
7378c2ecf20Sopenharmony_ci		*p++ = htonl(resp->count);
7388c2ecf20Sopenharmony_ci		*p++ = htonl(resp->eof);
7398c2ecf20Sopenharmony_ci		*p++ = htonl(resp->count);	/* xdr opaque count */
7408c2ecf20Sopenharmony_ci		xdr_ressize_check(rqstp, p);
7418c2ecf20Sopenharmony_ci		/* now update rqstp->rq_res to reflect data as well */
7428c2ecf20Sopenharmony_ci		rqstp->rq_res.page_len = resp->count;
7438c2ecf20Sopenharmony_ci		if (resp->count & 3) {
7448c2ecf20Sopenharmony_ci			/* need to pad the tail */
7458c2ecf20Sopenharmony_ci			rqstp->rq_res.tail[0].iov_base = p;
7468c2ecf20Sopenharmony_ci			*p = 0;
7478c2ecf20Sopenharmony_ci			rqstp->rq_res.tail[0].iov_len = 4 - (resp->count & 3);
7488c2ecf20Sopenharmony_ci		}
7498c2ecf20Sopenharmony_ci		return 1;
7508c2ecf20Sopenharmony_ci	} else
7518c2ecf20Sopenharmony_ci		return xdr_ressize_check(rqstp, p);
7528c2ecf20Sopenharmony_ci}
7538c2ecf20Sopenharmony_ci
7548c2ecf20Sopenharmony_ci/* WRITE */
7558c2ecf20Sopenharmony_ciint
7568c2ecf20Sopenharmony_cinfs3svc_encode_writeres(struct svc_rqst *rqstp, __be32 *p)
7578c2ecf20Sopenharmony_ci{
7588c2ecf20Sopenharmony_ci	struct nfsd3_writeres *resp = rqstp->rq_resp;
7598c2ecf20Sopenharmony_ci
7608c2ecf20Sopenharmony_ci	*p++ = resp->status;
7618c2ecf20Sopenharmony_ci	p = encode_wcc_data(rqstp, p, &resp->fh);
7628c2ecf20Sopenharmony_ci	if (resp->status == 0) {
7638c2ecf20Sopenharmony_ci		*p++ = htonl(resp->count);
7648c2ecf20Sopenharmony_ci		*p++ = htonl(resp->committed);
7658c2ecf20Sopenharmony_ci		*p++ = resp->verf[0];
7668c2ecf20Sopenharmony_ci		*p++ = resp->verf[1];
7678c2ecf20Sopenharmony_ci	}
7688c2ecf20Sopenharmony_ci	return xdr_ressize_check(rqstp, p);
7698c2ecf20Sopenharmony_ci}
7708c2ecf20Sopenharmony_ci
7718c2ecf20Sopenharmony_ci/* CREATE, MKDIR, SYMLINK, MKNOD */
7728c2ecf20Sopenharmony_ciint
7738c2ecf20Sopenharmony_cinfs3svc_encode_createres(struct svc_rqst *rqstp, __be32 *p)
7748c2ecf20Sopenharmony_ci{
7758c2ecf20Sopenharmony_ci	struct nfsd3_diropres *resp = rqstp->rq_resp;
7768c2ecf20Sopenharmony_ci
7778c2ecf20Sopenharmony_ci	*p++ = resp->status;
7788c2ecf20Sopenharmony_ci	if (resp->status == 0) {
7798c2ecf20Sopenharmony_ci		*p++ = xdr_one;
7808c2ecf20Sopenharmony_ci		p = encode_fh(p, &resp->fh);
7818c2ecf20Sopenharmony_ci		p = encode_post_op_attr(rqstp, p, &resp->fh);
7828c2ecf20Sopenharmony_ci	}
7838c2ecf20Sopenharmony_ci	p = encode_wcc_data(rqstp, p, &resp->dirfh);
7848c2ecf20Sopenharmony_ci	return xdr_ressize_check(rqstp, p);
7858c2ecf20Sopenharmony_ci}
7868c2ecf20Sopenharmony_ci
7878c2ecf20Sopenharmony_ci/* RENAME */
7888c2ecf20Sopenharmony_ciint
7898c2ecf20Sopenharmony_cinfs3svc_encode_renameres(struct svc_rqst *rqstp, __be32 *p)
7908c2ecf20Sopenharmony_ci{
7918c2ecf20Sopenharmony_ci	struct nfsd3_renameres *resp = rqstp->rq_resp;
7928c2ecf20Sopenharmony_ci
7938c2ecf20Sopenharmony_ci	*p++ = resp->status;
7948c2ecf20Sopenharmony_ci	p = encode_wcc_data(rqstp, p, &resp->ffh);
7958c2ecf20Sopenharmony_ci	p = encode_wcc_data(rqstp, p, &resp->tfh);
7968c2ecf20Sopenharmony_ci	return xdr_ressize_check(rqstp, p);
7978c2ecf20Sopenharmony_ci}
7988c2ecf20Sopenharmony_ci
7998c2ecf20Sopenharmony_ci/* LINK */
8008c2ecf20Sopenharmony_ciint
8018c2ecf20Sopenharmony_cinfs3svc_encode_linkres(struct svc_rqst *rqstp, __be32 *p)
8028c2ecf20Sopenharmony_ci{
8038c2ecf20Sopenharmony_ci	struct nfsd3_linkres *resp = rqstp->rq_resp;
8048c2ecf20Sopenharmony_ci
8058c2ecf20Sopenharmony_ci	*p++ = resp->status;
8068c2ecf20Sopenharmony_ci	p = encode_post_op_attr(rqstp, p, &resp->fh);
8078c2ecf20Sopenharmony_ci	p = encode_wcc_data(rqstp, p, &resp->tfh);
8088c2ecf20Sopenharmony_ci	return xdr_ressize_check(rqstp, p);
8098c2ecf20Sopenharmony_ci}
8108c2ecf20Sopenharmony_ci
8118c2ecf20Sopenharmony_ci/* READDIR */
8128c2ecf20Sopenharmony_ciint
8138c2ecf20Sopenharmony_cinfs3svc_encode_readdirres(struct svc_rqst *rqstp, __be32 *p)
8148c2ecf20Sopenharmony_ci{
8158c2ecf20Sopenharmony_ci	struct nfsd3_readdirres *resp = rqstp->rq_resp;
8168c2ecf20Sopenharmony_ci
8178c2ecf20Sopenharmony_ci	*p++ = resp->status;
8188c2ecf20Sopenharmony_ci	p = encode_post_op_attr(rqstp, p, &resp->fh);
8198c2ecf20Sopenharmony_ci
8208c2ecf20Sopenharmony_ci	if (resp->status == 0) {
8218c2ecf20Sopenharmony_ci		/* stupid readdir cookie */
8228c2ecf20Sopenharmony_ci		memcpy(p, resp->verf, 8); p += 2;
8238c2ecf20Sopenharmony_ci		xdr_ressize_check(rqstp, p);
8248c2ecf20Sopenharmony_ci		if (rqstp->rq_res.head[0].iov_len + (2<<2) > PAGE_SIZE)
8258c2ecf20Sopenharmony_ci			return 1; /*No room for trailer */
8268c2ecf20Sopenharmony_ci		rqstp->rq_res.page_len = (resp->count) << 2;
8278c2ecf20Sopenharmony_ci
8288c2ecf20Sopenharmony_ci		/* add the 'tail' to the end of the 'head' page - page 0. */
8298c2ecf20Sopenharmony_ci		rqstp->rq_res.tail[0].iov_base = p;
8308c2ecf20Sopenharmony_ci		*p++ = 0;		/* no more entries */
8318c2ecf20Sopenharmony_ci		*p++ = htonl(resp->common.err == nfserr_eof);
8328c2ecf20Sopenharmony_ci		rqstp->rq_res.tail[0].iov_len = 2<<2;
8338c2ecf20Sopenharmony_ci		return 1;
8348c2ecf20Sopenharmony_ci	} else
8358c2ecf20Sopenharmony_ci		return xdr_ressize_check(rqstp, p);
8368c2ecf20Sopenharmony_ci}
8378c2ecf20Sopenharmony_ci
8388c2ecf20Sopenharmony_cistatic __be32 *
8398c2ecf20Sopenharmony_ciencode_entry_baggage(struct nfsd3_readdirres *cd, __be32 *p, const char *name,
8408c2ecf20Sopenharmony_ci	     int namlen, u64 ino)
8418c2ecf20Sopenharmony_ci{
8428c2ecf20Sopenharmony_ci	*p++ = xdr_one;				 /* mark entry present */
8438c2ecf20Sopenharmony_ci	p    = xdr_encode_hyper(p, ino);	 /* file id */
8448c2ecf20Sopenharmony_ci	p    = xdr_encode_array(p, name, namlen);/* name length & name */
8458c2ecf20Sopenharmony_ci
8468c2ecf20Sopenharmony_ci	cd->offset = p;				/* remember pointer */
8478c2ecf20Sopenharmony_ci	p = xdr_encode_hyper(p, NFS_OFFSET_MAX);/* offset of next entry */
8488c2ecf20Sopenharmony_ci
8498c2ecf20Sopenharmony_ci	return p;
8508c2ecf20Sopenharmony_ci}
8518c2ecf20Sopenharmony_ci
8528c2ecf20Sopenharmony_cistatic __be32
8538c2ecf20Sopenharmony_cicompose_entry_fh(struct nfsd3_readdirres *cd, struct svc_fh *fhp,
8548c2ecf20Sopenharmony_ci		 const char *name, int namlen, u64 ino)
8558c2ecf20Sopenharmony_ci{
8568c2ecf20Sopenharmony_ci	struct svc_export	*exp;
8578c2ecf20Sopenharmony_ci	struct dentry		*dparent, *dchild;
8588c2ecf20Sopenharmony_ci	__be32 rv = nfserr_noent;
8598c2ecf20Sopenharmony_ci
8608c2ecf20Sopenharmony_ci	dparent = cd->fh.fh_dentry;
8618c2ecf20Sopenharmony_ci	exp  = cd->fh.fh_export;
8628c2ecf20Sopenharmony_ci
8638c2ecf20Sopenharmony_ci	if (isdotent(name, namlen)) {
8648c2ecf20Sopenharmony_ci		if (namlen == 2) {
8658c2ecf20Sopenharmony_ci			dchild = dget_parent(dparent);
8668c2ecf20Sopenharmony_ci			/*
8678c2ecf20Sopenharmony_ci			 * Don't return filehandle for ".." if we're at
8688c2ecf20Sopenharmony_ci			 * the filesystem or export root:
8698c2ecf20Sopenharmony_ci			 */
8708c2ecf20Sopenharmony_ci			if (dchild == dparent)
8718c2ecf20Sopenharmony_ci				goto out;
8728c2ecf20Sopenharmony_ci			if (dparent == exp->ex_path.dentry)
8738c2ecf20Sopenharmony_ci				goto out;
8748c2ecf20Sopenharmony_ci		} else
8758c2ecf20Sopenharmony_ci			dchild = dget(dparent);
8768c2ecf20Sopenharmony_ci	} else
8778c2ecf20Sopenharmony_ci		dchild = lookup_positive_unlocked(name, dparent, namlen);
8788c2ecf20Sopenharmony_ci	if (IS_ERR(dchild))
8798c2ecf20Sopenharmony_ci		return rv;
8808c2ecf20Sopenharmony_ci	if (d_mountpoint(dchild))
8818c2ecf20Sopenharmony_ci		goto out;
8828c2ecf20Sopenharmony_ci	if (dchild->d_inode->i_ino != ino)
8838c2ecf20Sopenharmony_ci		goto out;
8848c2ecf20Sopenharmony_ci	rv = fh_compose(fhp, exp, dchild, &cd->fh);
8858c2ecf20Sopenharmony_ciout:
8868c2ecf20Sopenharmony_ci	dput(dchild);
8878c2ecf20Sopenharmony_ci	return rv;
8888c2ecf20Sopenharmony_ci}
8898c2ecf20Sopenharmony_ci
8908c2ecf20Sopenharmony_cistatic __be32 *encode_entryplus_baggage(struct nfsd3_readdirres *cd, __be32 *p, const char *name, int namlen, u64 ino)
8918c2ecf20Sopenharmony_ci{
8928c2ecf20Sopenharmony_ci	struct svc_fh	*fh = &cd->scratch;
8938c2ecf20Sopenharmony_ci	__be32 err;
8948c2ecf20Sopenharmony_ci
8958c2ecf20Sopenharmony_ci	fh_init(fh, NFS3_FHSIZE);
8968c2ecf20Sopenharmony_ci	err = compose_entry_fh(cd, fh, name, namlen, ino);
8978c2ecf20Sopenharmony_ci	if (err) {
8988c2ecf20Sopenharmony_ci		*p++ = 0;
8998c2ecf20Sopenharmony_ci		*p++ = 0;
9008c2ecf20Sopenharmony_ci		goto out;
9018c2ecf20Sopenharmony_ci	}
9028c2ecf20Sopenharmony_ci	p = encode_post_op_attr(cd->rqstp, p, fh);
9038c2ecf20Sopenharmony_ci	*p++ = xdr_one;			/* yes, a file handle follows */
9048c2ecf20Sopenharmony_ci	p = encode_fh(p, fh);
9058c2ecf20Sopenharmony_ciout:
9068c2ecf20Sopenharmony_ci	fh_put(fh);
9078c2ecf20Sopenharmony_ci	return p;
9088c2ecf20Sopenharmony_ci}
9098c2ecf20Sopenharmony_ci
9108c2ecf20Sopenharmony_ci/*
9118c2ecf20Sopenharmony_ci * Encode a directory entry. This one works for both normal readdir
9128c2ecf20Sopenharmony_ci * and readdirplus.
9138c2ecf20Sopenharmony_ci * The normal readdir reply requires 2 (fileid) + 1 (stringlen)
9148c2ecf20Sopenharmony_ci * + string + 2 (cookie) + 1 (next) words, i.e. 6 + strlen.
9158c2ecf20Sopenharmony_ci *
9168c2ecf20Sopenharmony_ci * The readdirplus baggage is 1+21 words for post_op_attr, plus the
9178c2ecf20Sopenharmony_ci * file handle.
9188c2ecf20Sopenharmony_ci */
9198c2ecf20Sopenharmony_ci
9208c2ecf20Sopenharmony_ci#define NFS3_ENTRY_BAGGAGE	(2 + 1 + 2 + 1)
9218c2ecf20Sopenharmony_ci#define NFS3_ENTRYPLUS_BAGGAGE	(1 + 21 + 1 + (NFS3_FHSIZE >> 2))
9228c2ecf20Sopenharmony_cistatic int
9238c2ecf20Sopenharmony_ciencode_entry(struct readdir_cd *ccd, const char *name, int namlen,
9248c2ecf20Sopenharmony_ci	     loff_t offset, u64 ino, unsigned int d_type, int plus)
9258c2ecf20Sopenharmony_ci{
9268c2ecf20Sopenharmony_ci	struct nfsd3_readdirres *cd = container_of(ccd, struct nfsd3_readdirres,
9278c2ecf20Sopenharmony_ci		       					common);
9288c2ecf20Sopenharmony_ci	__be32		*p = cd->buffer;
9298c2ecf20Sopenharmony_ci	caddr_t		curr_page_addr = NULL;
9308c2ecf20Sopenharmony_ci	struct page **	page;
9318c2ecf20Sopenharmony_ci	int		slen;		/* string (name) length */
9328c2ecf20Sopenharmony_ci	int		elen;		/* estimated entry length in words */
9338c2ecf20Sopenharmony_ci	int		num_entry_words = 0;	/* actual number of words */
9348c2ecf20Sopenharmony_ci
9358c2ecf20Sopenharmony_ci	if (cd->offset) {
9368c2ecf20Sopenharmony_ci		u64 offset64 = offset;
9378c2ecf20Sopenharmony_ci
9388c2ecf20Sopenharmony_ci		if (unlikely(cd->offset1)) {
9398c2ecf20Sopenharmony_ci			/* we ended up with offset on a page boundary */
9408c2ecf20Sopenharmony_ci			*cd->offset = htonl(offset64 >> 32);
9418c2ecf20Sopenharmony_ci			*cd->offset1 = htonl(offset64 & 0xffffffff);
9428c2ecf20Sopenharmony_ci			cd->offset1 = NULL;
9438c2ecf20Sopenharmony_ci		} else {
9448c2ecf20Sopenharmony_ci			xdr_encode_hyper(cd->offset, offset64);
9458c2ecf20Sopenharmony_ci		}
9468c2ecf20Sopenharmony_ci		cd->offset = NULL;
9478c2ecf20Sopenharmony_ci	}
9488c2ecf20Sopenharmony_ci
9498c2ecf20Sopenharmony_ci	/*
9508c2ecf20Sopenharmony_ci	dprintk("encode_entry(%.*s @%ld%s)\n",
9518c2ecf20Sopenharmony_ci		namlen, name, (long) offset, plus? " plus" : "");
9528c2ecf20Sopenharmony_ci	 */
9538c2ecf20Sopenharmony_ci
9548c2ecf20Sopenharmony_ci	/* truncate filename if too long */
9558c2ecf20Sopenharmony_ci	namlen = min(namlen, NFS3_MAXNAMLEN);
9568c2ecf20Sopenharmony_ci
9578c2ecf20Sopenharmony_ci	slen = XDR_QUADLEN(namlen);
9588c2ecf20Sopenharmony_ci	elen = slen + NFS3_ENTRY_BAGGAGE
9598c2ecf20Sopenharmony_ci		+ (plus? NFS3_ENTRYPLUS_BAGGAGE : 0);
9608c2ecf20Sopenharmony_ci
9618c2ecf20Sopenharmony_ci	if (cd->buflen < elen) {
9628c2ecf20Sopenharmony_ci		cd->common.err = nfserr_toosmall;
9638c2ecf20Sopenharmony_ci		return -EINVAL;
9648c2ecf20Sopenharmony_ci	}
9658c2ecf20Sopenharmony_ci
9668c2ecf20Sopenharmony_ci	/* determine which page in rq_respages[] we are currently filling */
9678c2ecf20Sopenharmony_ci	for (page = cd->rqstp->rq_respages + 1;
9688c2ecf20Sopenharmony_ci				page < cd->rqstp->rq_next_page; page++) {
9698c2ecf20Sopenharmony_ci		curr_page_addr = page_address(*page);
9708c2ecf20Sopenharmony_ci
9718c2ecf20Sopenharmony_ci		if (((caddr_t)cd->buffer >= curr_page_addr) &&
9728c2ecf20Sopenharmony_ci		    ((caddr_t)cd->buffer <  curr_page_addr + PAGE_SIZE))
9738c2ecf20Sopenharmony_ci			break;
9748c2ecf20Sopenharmony_ci	}
9758c2ecf20Sopenharmony_ci
9768c2ecf20Sopenharmony_ci	if ((caddr_t)(cd->buffer + elen) < (curr_page_addr + PAGE_SIZE)) {
9778c2ecf20Sopenharmony_ci		/* encode entry in current page */
9788c2ecf20Sopenharmony_ci
9798c2ecf20Sopenharmony_ci		p = encode_entry_baggage(cd, p, name, namlen, ino);
9808c2ecf20Sopenharmony_ci
9818c2ecf20Sopenharmony_ci		if (plus)
9828c2ecf20Sopenharmony_ci			p = encode_entryplus_baggage(cd, p, name, namlen, ino);
9838c2ecf20Sopenharmony_ci		num_entry_words = p - cd->buffer;
9848c2ecf20Sopenharmony_ci	} else if (*(page+1) != NULL) {
9858c2ecf20Sopenharmony_ci		/* temporarily encode entry into next page, then move back to
9868c2ecf20Sopenharmony_ci		 * current and next page in rq_respages[] */
9878c2ecf20Sopenharmony_ci		__be32 *p1, *tmp;
9888c2ecf20Sopenharmony_ci		int len1, len2;
9898c2ecf20Sopenharmony_ci
9908c2ecf20Sopenharmony_ci		/* grab next page for temporary storage of entry */
9918c2ecf20Sopenharmony_ci		p1 = tmp = page_address(*(page+1));
9928c2ecf20Sopenharmony_ci
9938c2ecf20Sopenharmony_ci		p1 = encode_entry_baggage(cd, p1, name, namlen, ino);
9948c2ecf20Sopenharmony_ci
9958c2ecf20Sopenharmony_ci		if (plus)
9968c2ecf20Sopenharmony_ci			p1 = encode_entryplus_baggage(cd, p1, name, namlen, ino);
9978c2ecf20Sopenharmony_ci
9988c2ecf20Sopenharmony_ci		/* determine entry word length and lengths to go in pages */
9998c2ecf20Sopenharmony_ci		num_entry_words = p1 - tmp;
10008c2ecf20Sopenharmony_ci		len1 = curr_page_addr + PAGE_SIZE - (caddr_t)cd->buffer;
10018c2ecf20Sopenharmony_ci		if ((num_entry_words << 2) < len1) {
10028c2ecf20Sopenharmony_ci			/* the actual number of words in the entry is less
10038c2ecf20Sopenharmony_ci			 * than elen and can still fit in the current page
10048c2ecf20Sopenharmony_ci			 */
10058c2ecf20Sopenharmony_ci			memmove(p, tmp, num_entry_words << 2);
10068c2ecf20Sopenharmony_ci			p += num_entry_words;
10078c2ecf20Sopenharmony_ci
10088c2ecf20Sopenharmony_ci			/* update offset */
10098c2ecf20Sopenharmony_ci			cd->offset = cd->buffer + (cd->offset - tmp);
10108c2ecf20Sopenharmony_ci		} else {
10118c2ecf20Sopenharmony_ci			unsigned int offset_r = (cd->offset - tmp) << 2;
10128c2ecf20Sopenharmony_ci
10138c2ecf20Sopenharmony_ci			/* update pointer to offset location.
10148c2ecf20Sopenharmony_ci			 * This is a 64bit quantity, so we need to
10158c2ecf20Sopenharmony_ci			 * deal with 3 cases:
10168c2ecf20Sopenharmony_ci			 *  -	entirely in first page
10178c2ecf20Sopenharmony_ci			 *  -	entirely in second page
10188c2ecf20Sopenharmony_ci			 *  -	4 bytes in each page
10198c2ecf20Sopenharmony_ci			 */
10208c2ecf20Sopenharmony_ci			if (offset_r + 8 <= len1) {
10218c2ecf20Sopenharmony_ci				cd->offset = p + (cd->offset - tmp);
10228c2ecf20Sopenharmony_ci			} else if (offset_r >= len1) {
10238c2ecf20Sopenharmony_ci				cd->offset -= len1 >> 2;
10248c2ecf20Sopenharmony_ci			} else {
10258c2ecf20Sopenharmony_ci				/* sitting on the fence */
10268c2ecf20Sopenharmony_ci				BUG_ON(offset_r != len1 - 4);
10278c2ecf20Sopenharmony_ci				cd->offset = p + (cd->offset - tmp);
10288c2ecf20Sopenharmony_ci				cd->offset1 = tmp;
10298c2ecf20Sopenharmony_ci			}
10308c2ecf20Sopenharmony_ci
10318c2ecf20Sopenharmony_ci			len2 = (num_entry_words << 2) - len1;
10328c2ecf20Sopenharmony_ci
10338c2ecf20Sopenharmony_ci			/* move from temp page to current and next pages */
10348c2ecf20Sopenharmony_ci			memmove(p, tmp, len1);
10358c2ecf20Sopenharmony_ci			memmove(tmp, (caddr_t)tmp+len1, len2);
10368c2ecf20Sopenharmony_ci
10378c2ecf20Sopenharmony_ci			p = tmp + (len2 >> 2);
10388c2ecf20Sopenharmony_ci		}
10398c2ecf20Sopenharmony_ci	}
10408c2ecf20Sopenharmony_ci	else {
10418c2ecf20Sopenharmony_ci		cd->common.err = nfserr_toosmall;
10428c2ecf20Sopenharmony_ci		return -EINVAL;
10438c2ecf20Sopenharmony_ci	}
10448c2ecf20Sopenharmony_ci
10458c2ecf20Sopenharmony_ci	cd->buflen -= num_entry_words;
10468c2ecf20Sopenharmony_ci	cd->buffer = p;
10478c2ecf20Sopenharmony_ci	cd->common.err = nfs_ok;
10488c2ecf20Sopenharmony_ci	return 0;
10498c2ecf20Sopenharmony_ci
10508c2ecf20Sopenharmony_ci}
10518c2ecf20Sopenharmony_ci
10528c2ecf20Sopenharmony_ciint
10538c2ecf20Sopenharmony_cinfs3svc_encode_entry(void *cd, const char *name,
10548c2ecf20Sopenharmony_ci		     int namlen, loff_t offset, u64 ino, unsigned int d_type)
10558c2ecf20Sopenharmony_ci{
10568c2ecf20Sopenharmony_ci	return encode_entry(cd, name, namlen, offset, ino, d_type, 0);
10578c2ecf20Sopenharmony_ci}
10588c2ecf20Sopenharmony_ci
10598c2ecf20Sopenharmony_ciint
10608c2ecf20Sopenharmony_cinfs3svc_encode_entry_plus(void *cd, const char *name,
10618c2ecf20Sopenharmony_ci			  int namlen, loff_t offset, u64 ino,
10628c2ecf20Sopenharmony_ci			  unsigned int d_type)
10638c2ecf20Sopenharmony_ci{
10648c2ecf20Sopenharmony_ci	return encode_entry(cd, name, namlen, offset, ino, d_type, 1);
10658c2ecf20Sopenharmony_ci}
10668c2ecf20Sopenharmony_ci
10678c2ecf20Sopenharmony_ci/* FSSTAT */
10688c2ecf20Sopenharmony_ciint
10698c2ecf20Sopenharmony_cinfs3svc_encode_fsstatres(struct svc_rqst *rqstp, __be32 *p)
10708c2ecf20Sopenharmony_ci{
10718c2ecf20Sopenharmony_ci	struct nfsd3_fsstatres *resp = rqstp->rq_resp;
10728c2ecf20Sopenharmony_ci	struct kstatfs	*s = &resp->stats;
10738c2ecf20Sopenharmony_ci	u64		bs = s->f_bsize;
10748c2ecf20Sopenharmony_ci
10758c2ecf20Sopenharmony_ci	*p++ = resp->status;
10768c2ecf20Sopenharmony_ci	*p++ = xdr_zero;	/* no post_op_attr */
10778c2ecf20Sopenharmony_ci
10788c2ecf20Sopenharmony_ci	if (resp->status == 0) {
10798c2ecf20Sopenharmony_ci		p = xdr_encode_hyper(p, bs * s->f_blocks);	/* total bytes */
10808c2ecf20Sopenharmony_ci		p = xdr_encode_hyper(p, bs * s->f_bfree);	/* free bytes */
10818c2ecf20Sopenharmony_ci		p = xdr_encode_hyper(p, bs * s->f_bavail);	/* user available bytes */
10828c2ecf20Sopenharmony_ci		p = xdr_encode_hyper(p, s->f_files);	/* total inodes */
10838c2ecf20Sopenharmony_ci		p = xdr_encode_hyper(p, s->f_ffree);	/* free inodes */
10848c2ecf20Sopenharmony_ci		p = xdr_encode_hyper(p, s->f_ffree);	/* user available inodes */
10858c2ecf20Sopenharmony_ci		*p++ = htonl(resp->invarsec);	/* mean unchanged time */
10868c2ecf20Sopenharmony_ci	}
10878c2ecf20Sopenharmony_ci	return xdr_ressize_check(rqstp, p);
10888c2ecf20Sopenharmony_ci}
10898c2ecf20Sopenharmony_ci
10908c2ecf20Sopenharmony_ci/* FSINFO */
10918c2ecf20Sopenharmony_ciint
10928c2ecf20Sopenharmony_cinfs3svc_encode_fsinfores(struct svc_rqst *rqstp, __be32 *p)
10938c2ecf20Sopenharmony_ci{
10948c2ecf20Sopenharmony_ci	struct nfsd3_fsinfores *resp = rqstp->rq_resp;
10958c2ecf20Sopenharmony_ci
10968c2ecf20Sopenharmony_ci	*p++ = resp->status;
10978c2ecf20Sopenharmony_ci	*p++ = xdr_zero;	/* no post_op_attr */
10988c2ecf20Sopenharmony_ci
10998c2ecf20Sopenharmony_ci	if (resp->status == 0) {
11008c2ecf20Sopenharmony_ci		*p++ = htonl(resp->f_rtmax);
11018c2ecf20Sopenharmony_ci		*p++ = htonl(resp->f_rtpref);
11028c2ecf20Sopenharmony_ci		*p++ = htonl(resp->f_rtmult);
11038c2ecf20Sopenharmony_ci		*p++ = htonl(resp->f_wtmax);
11048c2ecf20Sopenharmony_ci		*p++ = htonl(resp->f_wtpref);
11058c2ecf20Sopenharmony_ci		*p++ = htonl(resp->f_wtmult);
11068c2ecf20Sopenharmony_ci		*p++ = htonl(resp->f_dtpref);
11078c2ecf20Sopenharmony_ci		p = xdr_encode_hyper(p, resp->f_maxfilesize);
11088c2ecf20Sopenharmony_ci		*p++ = xdr_one;
11098c2ecf20Sopenharmony_ci		*p++ = xdr_zero;
11108c2ecf20Sopenharmony_ci		*p++ = htonl(resp->f_properties);
11118c2ecf20Sopenharmony_ci	}
11128c2ecf20Sopenharmony_ci
11138c2ecf20Sopenharmony_ci	return xdr_ressize_check(rqstp, p);
11148c2ecf20Sopenharmony_ci}
11158c2ecf20Sopenharmony_ci
11168c2ecf20Sopenharmony_ci/* PATHCONF */
11178c2ecf20Sopenharmony_ciint
11188c2ecf20Sopenharmony_cinfs3svc_encode_pathconfres(struct svc_rqst *rqstp, __be32 *p)
11198c2ecf20Sopenharmony_ci{
11208c2ecf20Sopenharmony_ci	struct nfsd3_pathconfres *resp = rqstp->rq_resp;
11218c2ecf20Sopenharmony_ci
11228c2ecf20Sopenharmony_ci	*p++ = resp->status;
11238c2ecf20Sopenharmony_ci	*p++ = xdr_zero;	/* no post_op_attr */
11248c2ecf20Sopenharmony_ci
11258c2ecf20Sopenharmony_ci	if (resp->status == 0) {
11268c2ecf20Sopenharmony_ci		*p++ = htonl(resp->p_link_max);
11278c2ecf20Sopenharmony_ci		*p++ = htonl(resp->p_name_max);
11288c2ecf20Sopenharmony_ci		*p++ = htonl(resp->p_no_trunc);
11298c2ecf20Sopenharmony_ci		*p++ = htonl(resp->p_chown_restricted);
11308c2ecf20Sopenharmony_ci		*p++ = htonl(resp->p_case_insensitive);
11318c2ecf20Sopenharmony_ci		*p++ = htonl(resp->p_case_preserving);
11328c2ecf20Sopenharmony_ci	}
11338c2ecf20Sopenharmony_ci
11348c2ecf20Sopenharmony_ci	return xdr_ressize_check(rqstp, p);
11358c2ecf20Sopenharmony_ci}
11368c2ecf20Sopenharmony_ci
11378c2ecf20Sopenharmony_ci/* COMMIT */
11388c2ecf20Sopenharmony_ciint
11398c2ecf20Sopenharmony_cinfs3svc_encode_commitres(struct svc_rqst *rqstp, __be32 *p)
11408c2ecf20Sopenharmony_ci{
11418c2ecf20Sopenharmony_ci	struct nfsd3_commitres *resp = rqstp->rq_resp;
11428c2ecf20Sopenharmony_ci
11438c2ecf20Sopenharmony_ci	*p++ = resp->status;
11448c2ecf20Sopenharmony_ci	p = encode_wcc_data(rqstp, p, &resp->fh);
11458c2ecf20Sopenharmony_ci	/* Write verifier */
11468c2ecf20Sopenharmony_ci	if (resp->status == 0) {
11478c2ecf20Sopenharmony_ci		*p++ = resp->verf[0];
11488c2ecf20Sopenharmony_ci		*p++ = resp->verf[1];
11498c2ecf20Sopenharmony_ci	}
11508c2ecf20Sopenharmony_ci	return xdr_ressize_check(rqstp, p);
11518c2ecf20Sopenharmony_ci}
11528c2ecf20Sopenharmony_ci
11538c2ecf20Sopenharmony_ci/*
11548c2ecf20Sopenharmony_ci * XDR release functions
11558c2ecf20Sopenharmony_ci */
11568c2ecf20Sopenharmony_civoid
11578c2ecf20Sopenharmony_cinfs3svc_release_fhandle(struct svc_rqst *rqstp)
11588c2ecf20Sopenharmony_ci{
11598c2ecf20Sopenharmony_ci	struct nfsd3_attrstat *resp = rqstp->rq_resp;
11608c2ecf20Sopenharmony_ci
11618c2ecf20Sopenharmony_ci	fh_put(&resp->fh);
11628c2ecf20Sopenharmony_ci}
11638c2ecf20Sopenharmony_ci
11648c2ecf20Sopenharmony_civoid
11658c2ecf20Sopenharmony_cinfs3svc_release_fhandle2(struct svc_rqst *rqstp)
11668c2ecf20Sopenharmony_ci{
11678c2ecf20Sopenharmony_ci	struct nfsd3_fhandle_pair *resp = rqstp->rq_resp;
11688c2ecf20Sopenharmony_ci
11698c2ecf20Sopenharmony_ci	fh_put(&resp->fh1);
11708c2ecf20Sopenharmony_ci	fh_put(&resp->fh2);
11718c2ecf20Sopenharmony_ci}
1172