xref: /OK3568_Linux_fs/kernel/fs/nfsd/nfsxdr.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * XDR support for nfsd
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
6*4882a593Smuzhiyun  */
7*4882a593Smuzhiyun 
8*4882a593Smuzhiyun #include "vfs.h"
9*4882a593Smuzhiyun #include "xdr.h"
10*4882a593Smuzhiyun #include "auth.h"
11*4882a593Smuzhiyun 
12*4882a593Smuzhiyun #define NFSDDBG_FACILITY		NFSDDBG_XDR
13*4882a593Smuzhiyun 
14*4882a593Smuzhiyun /*
15*4882a593Smuzhiyun  * Mapping of S_IF* types to NFS file types
16*4882a593Smuzhiyun  */
17*4882a593Smuzhiyun static u32	nfs_ftypes[] = {
18*4882a593Smuzhiyun 	NFNON,  NFCHR,  NFCHR, NFBAD,
19*4882a593Smuzhiyun 	NFDIR,  NFBAD,  NFBLK, NFBAD,
20*4882a593Smuzhiyun 	NFREG,  NFBAD,  NFLNK, NFBAD,
21*4882a593Smuzhiyun 	NFSOCK, NFBAD,  NFLNK, NFBAD,
22*4882a593Smuzhiyun };
23*4882a593Smuzhiyun 
24*4882a593Smuzhiyun 
25*4882a593Smuzhiyun /*
26*4882a593Smuzhiyun  * XDR functions for basic NFS types
27*4882a593Smuzhiyun  */
28*4882a593Smuzhiyun static __be32 *
decode_fh(__be32 * p,struct svc_fh * fhp)29*4882a593Smuzhiyun decode_fh(__be32 *p, struct svc_fh *fhp)
30*4882a593Smuzhiyun {
31*4882a593Smuzhiyun 	fh_init(fhp, NFS_FHSIZE);
32*4882a593Smuzhiyun 	memcpy(&fhp->fh_handle.fh_base, p, NFS_FHSIZE);
33*4882a593Smuzhiyun 	fhp->fh_handle.fh_size = NFS_FHSIZE;
34*4882a593Smuzhiyun 
35*4882a593Smuzhiyun 	/* FIXME: Look up export pointer here and verify
36*4882a593Smuzhiyun 	 * Sun Secure RPC if requested */
37*4882a593Smuzhiyun 	return p + (NFS_FHSIZE >> 2);
38*4882a593Smuzhiyun }
39*4882a593Smuzhiyun 
40*4882a593Smuzhiyun /* Helper function for NFSv2 ACL code */
nfs2svc_decode_fh(__be32 * p,struct svc_fh * fhp)41*4882a593Smuzhiyun __be32 *nfs2svc_decode_fh(__be32 *p, struct svc_fh *fhp)
42*4882a593Smuzhiyun {
43*4882a593Smuzhiyun 	return decode_fh(p, fhp);
44*4882a593Smuzhiyun }
45*4882a593Smuzhiyun 
46*4882a593Smuzhiyun static __be32 *
encode_fh(__be32 * p,struct svc_fh * fhp)47*4882a593Smuzhiyun encode_fh(__be32 *p, struct svc_fh *fhp)
48*4882a593Smuzhiyun {
49*4882a593Smuzhiyun 	memcpy(p, &fhp->fh_handle.fh_base, NFS_FHSIZE);
50*4882a593Smuzhiyun 	return p + (NFS_FHSIZE>> 2);
51*4882a593Smuzhiyun }
52*4882a593Smuzhiyun 
53*4882a593Smuzhiyun /*
54*4882a593Smuzhiyun  * Decode a file name and make sure that the path contains
55*4882a593Smuzhiyun  * no slashes or null bytes.
56*4882a593Smuzhiyun  */
57*4882a593Smuzhiyun static __be32 *
decode_filename(__be32 * p,char ** namp,unsigned int * lenp)58*4882a593Smuzhiyun decode_filename(__be32 *p, char **namp, unsigned int *lenp)
59*4882a593Smuzhiyun {
60*4882a593Smuzhiyun 	char		*name;
61*4882a593Smuzhiyun 	unsigned int	i;
62*4882a593Smuzhiyun 
63*4882a593Smuzhiyun 	if ((p = xdr_decode_string_inplace(p, namp, lenp, NFS_MAXNAMLEN)) != NULL) {
64*4882a593Smuzhiyun 		for (i = 0, name = *namp; i < *lenp; i++, name++) {
65*4882a593Smuzhiyun 			if (*name == '\0' || *name == '/')
66*4882a593Smuzhiyun 				return NULL;
67*4882a593Smuzhiyun 		}
68*4882a593Smuzhiyun 	}
69*4882a593Smuzhiyun 
70*4882a593Smuzhiyun 	return p;
71*4882a593Smuzhiyun }
72*4882a593Smuzhiyun 
73*4882a593Smuzhiyun static __be32 *
decode_sattr(__be32 * p,struct iattr * iap,struct user_namespace * userns)74*4882a593Smuzhiyun decode_sattr(__be32 *p, struct iattr *iap, struct user_namespace *userns)
75*4882a593Smuzhiyun {
76*4882a593Smuzhiyun 	u32	tmp, tmp1;
77*4882a593Smuzhiyun 
78*4882a593Smuzhiyun 	iap->ia_valid = 0;
79*4882a593Smuzhiyun 
80*4882a593Smuzhiyun 	/* Sun client bug compatibility check: some sun clients seem to
81*4882a593Smuzhiyun 	 * put 0xffff in the mode field when they mean 0xffffffff.
82*4882a593Smuzhiyun 	 * Quoting the 4.4BSD nfs server code: Nah nah nah nah na nah.
83*4882a593Smuzhiyun 	 */
84*4882a593Smuzhiyun 	if ((tmp = ntohl(*p++)) != (u32)-1 && tmp != 0xffff) {
85*4882a593Smuzhiyun 		iap->ia_valid |= ATTR_MODE;
86*4882a593Smuzhiyun 		iap->ia_mode = tmp;
87*4882a593Smuzhiyun 	}
88*4882a593Smuzhiyun 	if ((tmp = ntohl(*p++)) != (u32)-1) {
89*4882a593Smuzhiyun 		iap->ia_uid = make_kuid(userns, tmp);
90*4882a593Smuzhiyun 		if (uid_valid(iap->ia_uid))
91*4882a593Smuzhiyun 			iap->ia_valid |= ATTR_UID;
92*4882a593Smuzhiyun 	}
93*4882a593Smuzhiyun 	if ((tmp = ntohl(*p++)) != (u32)-1) {
94*4882a593Smuzhiyun 		iap->ia_gid = make_kgid(userns, tmp);
95*4882a593Smuzhiyun 		if (gid_valid(iap->ia_gid))
96*4882a593Smuzhiyun 			iap->ia_valid |= ATTR_GID;
97*4882a593Smuzhiyun 	}
98*4882a593Smuzhiyun 	if ((tmp = ntohl(*p++)) != (u32)-1) {
99*4882a593Smuzhiyun 		iap->ia_valid |= ATTR_SIZE;
100*4882a593Smuzhiyun 		iap->ia_size = tmp;
101*4882a593Smuzhiyun 	}
102*4882a593Smuzhiyun 	tmp  = ntohl(*p++); tmp1 = ntohl(*p++);
103*4882a593Smuzhiyun 	if (tmp != (u32)-1 && tmp1 != (u32)-1) {
104*4882a593Smuzhiyun 		iap->ia_valid |= ATTR_ATIME | ATTR_ATIME_SET;
105*4882a593Smuzhiyun 		iap->ia_atime.tv_sec = tmp;
106*4882a593Smuzhiyun 		iap->ia_atime.tv_nsec = tmp1 * 1000;
107*4882a593Smuzhiyun 	}
108*4882a593Smuzhiyun 	tmp  = ntohl(*p++); tmp1 = ntohl(*p++);
109*4882a593Smuzhiyun 	if (tmp != (u32)-1 && tmp1 != (u32)-1) {
110*4882a593Smuzhiyun 		iap->ia_valid |= ATTR_MTIME | ATTR_MTIME_SET;
111*4882a593Smuzhiyun 		iap->ia_mtime.tv_sec = tmp;
112*4882a593Smuzhiyun 		iap->ia_mtime.tv_nsec = tmp1 * 1000;
113*4882a593Smuzhiyun 		/*
114*4882a593Smuzhiyun 		 * Passing the invalid value useconds=1000000 for mtime
115*4882a593Smuzhiyun 		 * is a Sun convention for "set both mtime and atime to
116*4882a593Smuzhiyun 		 * current server time".  It's needed to make permissions
117*4882a593Smuzhiyun 		 * checks for the "touch" program across v2 mounts to
118*4882a593Smuzhiyun 		 * Solaris and Irix boxes work correctly. See description of
119*4882a593Smuzhiyun 		 * sattr in section 6.1 of "NFS Illustrated" by
120*4882a593Smuzhiyun 		 * Brent Callaghan, Addison-Wesley, ISBN 0-201-32750-5
121*4882a593Smuzhiyun 		 */
122*4882a593Smuzhiyun 		if (tmp1 == 1000000)
123*4882a593Smuzhiyun 			iap->ia_valid &= ~(ATTR_ATIME_SET|ATTR_MTIME_SET);
124*4882a593Smuzhiyun 	}
125*4882a593Smuzhiyun 	return p;
126*4882a593Smuzhiyun }
127*4882a593Smuzhiyun 
128*4882a593Smuzhiyun static __be32 *
encode_fattr(struct svc_rqst * rqstp,__be32 * p,struct svc_fh * fhp,struct kstat * stat)129*4882a593Smuzhiyun encode_fattr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp,
130*4882a593Smuzhiyun 	     struct kstat *stat)
131*4882a593Smuzhiyun {
132*4882a593Smuzhiyun 	struct user_namespace *userns = nfsd_user_namespace(rqstp);
133*4882a593Smuzhiyun 	struct dentry	*dentry = fhp->fh_dentry;
134*4882a593Smuzhiyun 	int type;
135*4882a593Smuzhiyun 	struct timespec64 time;
136*4882a593Smuzhiyun 	u32 f;
137*4882a593Smuzhiyun 
138*4882a593Smuzhiyun 	type = (stat->mode & S_IFMT);
139*4882a593Smuzhiyun 
140*4882a593Smuzhiyun 	*p++ = htonl(nfs_ftypes[type >> 12]);
141*4882a593Smuzhiyun 	*p++ = htonl((u32) stat->mode);
142*4882a593Smuzhiyun 	*p++ = htonl((u32) stat->nlink);
143*4882a593Smuzhiyun 	*p++ = htonl((u32) from_kuid_munged(userns, stat->uid));
144*4882a593Smuzhiyun 	*p++ = htonl((u32) from_kgid_munged(userns, stat->gid));
145*4882a593Smuzhiyun 
146*4882a593Smuzhiyun 	if (S_ISLNK(type) && stat->size > NFS_MAXPATHLEN) {
147*4882a593Smuzhiyun 		*p++ = htonl(NFS_MAXPATHLEN);
148*4882a593Smuzhiyun 	} else {
149*4882a593Smuzhiyun 		*p++ = htonl((u32) stat->size);
150*4882a593Smuzhiyun 	}
151*4882a593Smuzhiyun 	*p++ = htonl((u32) stat->blksize);
152*4882a593Smuzhiyun 	if (S_ISCHR(type) || S_ISBLK(type))
153*4882a593Smuzhiyun 		*p++ = htonl(new_encode_dev(stat->rdev));
154*4882a593Smuzhiyun 	else
155*4882a593Smuzhiyun 		*p++ = htonl(0xffffffff);
156*4882a593Smuzhiyun 	*p++ = htonl((u32) stat->blocks);
157*4882a593Smuzhiyun 	switch (fsid_source(fhp)) {
158*4882a593Smuzhiyun 	default:
159*4882a593Smuzhiyun 	case FSIDSOURCE_DEV:
160*4882a593Smuzhiyun 		*p++ = htonl(new_encode_dev(stat->dev));
161*4882a593Smuzhiyun 		break;
162*4882a593Smuzhiyun 	case FSIDSOURCE_FSID:
163*4882a593Smuzhiyun 		*p++ = htonl((u32) fhp->fh_export->ex_fsid);
164*4882a593Smuzhiyun 		break;
165*4882a593Smuzhiyun 	case FSIDSOURCE_UUID:
166*4882a593Smuzhiyun 		f = ((u32*)fhp->fh_export->ex_uuid)[0];
167*4882a593Smuzhiyun 		f ^= ((u32*)fhp->fh_export->ex_uuid)[1];
168*4882a593Smuzhiyun 		f ^= ((u32*)fhp->fh_export->ex_uuid)[2];
169*4882a593Smuzhiyun 		f ^= ((u32*)fhp->fh_export->ex_uuid)[3];
170*4882a593Smuzhiyun 		*p++ = htonl(f);
171*4882a593Smuzhiyun 		break;
172*4882a593Smuzhiyun 	}
173*4882a593Smuzhiyun 	*p++ = htonl((u32) stat->ino);
174*4882a593Smuzhiyun 	*p++ = htonl((u32) stat->atime.tv_sec);
175*4882a593Smuzhiyun 	*p++ = htonl(stat->atime.tv_nsec ? stat->atime.tv_nsec / 1000 : 0);
176*4882a593Smuzhiyun 	time = stat->mtime;
177*4882a593Smuzhiyun 	lease_get_mtime(d_inode(dentry), &time);
178*4882a593Smuzhiyun 	*p++ = htonl((u32) time.tv_sec);
179*4882a593Smuzhiyun 	*p++ = htonl(time.tv_nsec ? time.tv_nsec / 1000 : 0);
180*4882a593Smuzhiyun 	*p++ = htonl((u32) stat->ctime.tv_sec);
181*4882a593Smuzhiyun 	*p++ = htonl(stat->ctime.tv_nsec ? stat->ctime.tv_nsec / 1000 : 0);
182*4882a593Smuzhiyun 
183*4882a593Smuzhiyun 	return p;
184*4882a593Smuzhiyun }
185*4882a593Smuzhiyun 
186*4882a593Smuzhiyun /* Helper function for NFSv2 ACL code */
nfs2svc_encode_fattr(struct svc_rqst * rqstp,__be32 * p,struct svc_fh * fhp,struct kstat * stat)187*4882a593Smuzhiyun __be32 *nfs2svc_encode_fattr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp, struct kstat *stat)
188*4882a593Smuzhiyun {
189*4882a593Smuzhiyun 	return encode_fattr(rqstp, p, fhp, stat);
190*4882a593Smuzhiyun }
191*4882a593Smuzhiyun 
192*4882a593Smuzhiyun /*
193*4882a593Smuzhiyun  * XDR decode functions
194*4882a593Smuzhiyun  */
195*4882a593Smuzhiyun int
nfssvc_decode_void(struct svc_rqst * rqstp,__be32 * p)196*4882a593Smuzhiyun nfssvc_decode_void(struct svc_rqst *rqstp, __be32 *p)
197*4882a593Smuzhiyun {
198*4882a593Smuzhiyun 	return xdr_argsize_check(rqstp, p);
199*4882a593Smuzhiyun }
200*4882a593Smuzhiyun 
201*4882a593Smuzhiyun int
nfssvc_decode_fhandle(struct svc_rqst * rqstp,__be32 * p)202*4882a593Smuzhiyun nfssvc_decode_fhandle(struct svc_rqst *rqstp, __be32 *p)
203*4882a593Smuzhiyun {
204*4882a593Smuzhiyun 	struct nfsd_fhandle *args = rqstp->rq_argp;
205*4882a593Smuzhiyun 
206*4882a593Smuzhiyun 	p = decode_fh(p, &args->fh);
207*4882a593Smuzhiyun 	if (!p)
208*4882a593Smuzhiyun 		return 0;
209*4882a593Smuzhiyun 	return xdr_argsize_check(rqstp, p);
210*4882a593Smuzhiyun }
211*4882a593Smuzhiyun 
212*4882a593Smuzhiyun int
nfssvc_decode_sattrargs(struct svc_rqst * rqstp,__be32 * p)213*4882a593Smuzhiyun nfssvc_decode_sattrargs(struct svc_rqst *rqstp, __be32 *p)
214*4882a593Smuzhiyun {
215*4882a593Smuzhiyun 	struct nfsd_sattrargs *args = rqstp->rq_argp;
216*4882a593Smuzhiyun 
217*4882a593Smuzhiyun 	p = decode_fh(p, &args->fh);
218*4882a593Smuzhiyun 	if (!p)
219*4882a593Smuzhiyun 		return 0;
220*4882a593Smuzhiyun 	p = decode_sattr(p, &args->attrs, nfsd_user_namespace(rqstp));
221*4882a593Smuzhiyun 
222*4882a593Smuzhiyun 	return xdr_argsize_check(rqstp, p);
223*4882a593Smuzhiyun }
224*4882a593Smuzhiyun 
225*4882a593Smuzhiyun int
nfssvc_decode_diropargs(struct svc_rqst * rqstp,__be32 * p)226*4882a593Smuzhiyun nfssvc_decode_diropargs(struct svc_rqst *rqstp, __be32 *p)
227*4882a593Smuzhiyun {
228*4882a593Smuzhiyun 	struct nfsd_diropargs *args = rqstp->rq_argp;
229*4882a593Smuzhiyun 
230*4882a593Smuzhiyun 	if (!(p = decode_fh(p, &args->fh))
231*4882a593Smuzhiyun 	 || !(p = decode_filename(p, &args->name, &args->len)))
232*4882a593Smuzhiyun 		return 0;
233*4882a593Smuzhiyun 
234*4882a593Smuzhiyun 	return xdr_argsize_check(rqstp, p);
235*4882a593Smuzhiyun }
236*4882a593Smuzhiyun 
237*4882a593Smuzhiyun int
nfssvc_decode_readargs(struct svc_rqst * rqstp,__be32 * p)238*4882a593Smuzhiyun nfssvc_decode_readargs(struct svc_rqst *rqstp, __be32 *p)
239*4882a593Smuzhiyun {
240*4882a593Smuzhiyun 	struct nfsd_readargs *args = rqstp->rq_argp;
241*4882a593Smuzhiyun 	unsigned int len;
242*4882a593Smuzhiyun 	int v;
243*4882a593Smuzhiyun 	p = decode_fh(p, &args->fh);
244*4882a593Smuzhiyun 	if (!p)
245*4882a593Smuzhiyun 		return 0;
246*4882a593Smuzhiyun 
247*4882a593Smuzhiyun 	args->offset    = ntohl(*p++);
248*4882a593Smuzhiyun 	len = args->count     = ntohl(*p++);
249*4882a593Smuzhiyun 	p++; /* totalcount - unused */
250*4882a593Smuzhiyun 
251*4882a593Smuzhiyun 	len = min_t(unsigned int, len, NFSSVC_MAXBLKSIZE_V2);
252*4882a593Smuzhiyun 
253*4882a593Smuzhiyun 	/* set up somewhere to store response.
254*4882a593Smuzhiyun 	 * We take pages, put them on reslist and include in iovec
255*4882a593Smuzhiyun 	 */
256*4882a593Smuzhiyun 	v=0;
257*4882a593Smuzhiyun 	while (len > 0) {
258*4882a593Smuzhiyun 		struct page *p = *(rqstp->rq_next_page++);
259*4882a593Smuzhiyun 
260*4882a593Smuzhiyun 		rqstp->rq_vec[v].iov_base = page_address(p);
261*4882a593Smuzhiyun 		rqstp->rq_vec[v].iov_len = min_t(unsigned int, len, PAGE_SIZE);
262*4882a593Smuzhiyun 		len -= rqstp->rq_vec[v].iov_len;
263*4882a593Smuzhiyun 		v++;
264*4882a593Smuzhiyun 	}
265*4882a593Smuzhiyun 	args->vlen = v;
266*4882a593Smuzhiyun 	return xdr_argsize_check(rqstp, p);
267*4882a593Smuzhiyun }
268*4882a593Smuzhiyun 
269*4882a593Smuzhiyun int
nfssvc_decode_writeargs(struct svc_rqst * rqstp,__be32 * p)270*4882a593Smuzhiyun nfssvc_decode_writeargs(struct svc_rqst *rqstp, __be32 *p)
271*4882a593Smuzhiyun {
272*4882a593Smuzhiyun 	struct nfsd_writeargs *args = rqstp->rq_argp;
273*4882a593Smuzhiyun 	unsigned int len, hdr, dlen;
274*4882a593Smuzhiyun 	struct kvec *head = rqstp->rq_arg.head;
275*4882a593Smuzhiyun 
276*4882a593Smuzhiyun 	p = decode_fh(p, &args->fh);
277*4882a593Smuzhiyun 	if (!p)
278*4882a593Smuzhiyun 		return 0;
279*4882a593Smuzhiyun 
280*4882a593Smuzhiyun 	p++;				/* beginoffset */
281*4882a593Smuzhiyun 	args->offset = ntohl(*p++);	/* offset */
282*4882a593Smuzhiyun 	p++;				/* totalcount */
283*4882a593Smuzhiyun 	len = args->len = ntohl(*p++);
284*4882a593Smuzhiyun 	/*
285*4882a593Smuzhiyun 	 * The protocol specifies a maximum of 8192 bytes.
286*4882a593Smuzhiyun 	 */
287*4882a593Smuzhiyun 	if (len > NFSSVC_MAXBLKSIZE_V2)
288*4882a593Smuzhiyun 		return 0;
289*4882a593Smuzhiyun 
290*4882a593Smuzhiyun 	/*
291*4882a593Smuzhiyun 	 * Check to make sure that we got the right number of
292*4882a593Smuzhiyun 	 * bytes.
293*4882a593Smuzhiyun 	 */
294*4882a593Smuzhiyun 	hdr = (void*)p - head->iov_base;
295*4882a593Smuzhiyun 	if (hdr > head->iov_len)
296*4882a593Smuzhiyun 		return 0;
297*4882a593Smuzhiyun 	dlen = head->iov_len + rqstp->rq_arg.page_len - hdr;
298*4882a593Smuzhiyun 
299*4882a593Smuzhiyun 	/*
300*4882a593Smuzhiyun 	 * Round the length of the data which was specified up to
301*4882a593Smuzhiyun 	 * the next multiple of XDR units and then compare that
302*4882a593Smuzhiyun 	 * against the length which was actually received.
303*4882a593Smuzhiyun 	 * Note that when RPCSEC/GSS (for example) is used, the
304*4882a593Smuzhiyun 	 * data buffer can be padded so dlen might be larger
305*4882a593Smuzhiyun 	 * than required.  It must never be smaller.
306*4882a593Smuzhiyun 	 */
307*4882a593Smuzhiyun 	if (dlen < XDR_QUADLEN(len)*4)
308*4882a593Smuzhiyun 		return 0;
309*4882a593Smuzhiyun 
310*4882a593Smuzhiyun 	args->first.iov_base = (void *)p;
311*4882a593Smuzhiyun 	args->first.iov_len = head->iov_len - hdr;
312*4882a593Smuzhiyun 	return 1;
313*4882a593Smuzhiyun }
314*4882a593Smuzhiyun 
315*4882a593Smuzhiyun int
nfssvc_decode_createargs(struct svc_rqst * rqstp,__be32 * p)316*4882a593Smuzhiyun nfssvc_decode_createargs(struct svc_rqst *rqstp, __be32 *p)
317*4882a593Smuzhiyun {
318*4882a593Smuzhiyun 	struct nfsd_createargs *args = rqstp->rq_argp;
319*4882a593Smuzhiyun 
320*4882a593Smuzhiyun 	if (   !(p = decode_fh(p, &args->fh))
321*4882a593Smuzhiyun 	    || !(p = decode_filename(p, &args->name, &args->len)))
322*4882a593Smuzhiyun 		return 0;
323*4882a593Smuzhiyun 	p = decode_sattr(p, &args->attrs, nfsd_user_namespace(rqstp));
324*4882a593Smuzhiyun 
325*4882a593Smuzhiyun 	return xdr_argsize_check(rqstp, p);
326*4882a593Smuzhiyun }
327*4882a593Smuzhiyun 
328*4882a593Smuzhiyun int
nfssvc_decode_renameargs(struct svc_rqst * rqstp,__be32 * p)329*4882a593Smuzhiyun nfssvc_decode_renameargs(struct svc_rqst *rqstp, __be32 *p)
330*4882a593Smuzhiyun {
331*4882a593Smuzhiyun 	struct nfsd_renameargs *args = rqstp->rq_argp;
332*4882a593Smuzhiyun 
333*4882a593Smuzhiyun 	if (!(p = decode_fh(p, &args->ffh))
334*4882a593Smuzhiyun 	 || !(p = decode_filename(p, &args->fname, &args->flen))
335*4882a593Smuzhiyun 	 || !(p = decode_fh(p, &args->tfh))
336*4882a593Smuzhiyun 	 || !(p = decode_filename(p, &args->tname, &args->tlen)))
337*4882a593Smuzhiyun 		return 0;
338*4882a593Smuzhiyun 
339*4882a593Smuzhiyun 	return xdr_argsize_check(rqstp, p);
340*4882a593Smuzhiyun }
341*4882a593Smuzhiyun 
342*4882a593Smuzhiyun int
nfssvc_decode_readlinkargs(struct svc_rqst * rqstp,__be32 * p)343*4882a593Smuzhiyun nfssvc_decode_readlinkargs(struct svc_rqst *rqstp, __be32 *p)
344*4882a593Smuzhiyun {
345*4882a593Smuzhiyun 	struct nfsd_readlinkargs *args = rqstp->rq_argp;
346*4882a593Smuzhiyun 
347*4882a593Smuzhiyun 	p = decode_fh(p, &args->fh);
348*4882a593Smuzhiyun 	if (!p)
349*4882a593Smuzhiyun 		return 0;
350*4882a593Smuzhiyun 	args->buffer = page_address(*(rqstp->rq_next_page++));
351*4882a593Smuzhiyun 
352*4882a593Smuzhiyun 	return xdr_argsize_check(rqstp, p);
353*4882a593Smuzhiyun }
354*4882a593Smuzhiyun 
355*4882a593Smuzhiyun int
nfssvc_decode_linkargs(struct svc_rqst * rqstp,__be32 * p)356*4882a593Smuzhiyun nfssvc_decode_linkargs(struct svc_rqst *rqstp, __be32 *p)
357*4882a593Smuzhiyun {
358*4882a593Smuzhiyun 	struct nfsd_linkargs *args = rqstp->rq_argp;
359*4882a593Smuzhiyun 
360*4882a593Smuzhiyun 	if (!(p = decode_fh(p, &args->ffh))
361*4882a593Smuzhiyun 	 || !(p = decode_fh(p, &args->tfh))
362*4882a593Smuzhiyun 	 || !(p = decode_filename(p, &args->tname, &args->tlen)))
363*4882a593Smuzhiyun 		return 0;
364*4882a593Smuzhiyun 
365*4882a593Smuzhiyun 	return xdr_argsize_check(rqstp, p);
366*4882a593Smuzhiyun }
367*4882a593Smuzhiyun 
368*4882a593Smuzhiyun int
nfssvc_decode_symlinkargs(struct svc_rqst * rqstp,__be32 * p)369*4882a593Smuzhiyun nfssvc_decode_symlinkargs(struct svc_rqst *rqstp, __be32 *p)
370*4882a593Smuzhiyun {
371*4882a593Smuzhiyun 	struct nfsd_symlinkargs *args = rqstp->rq_argp;
372*4882a593Smuzhiyun 	char *base = (char *)p;
373*4882a593Smuzhiyun 	size_t xdrlen;
374*4882a593Smuzhiyun 
375*4882a593Smuzhiyun 	if (   !(p = decode_fh(p, &args->ffh))
376*4882a593Smuzhiyun 	    || !(p = decode_filename(p, &args->fname, &args->flen)))
377*4882a593Smuzhiyun 		return 0;
378*4882a593Smuzhiyun 
379*4882a593Smuzhiyun 	args->tlen = ntohl(*p++);
380*4882a593Smuzhiyun 	if (args->tlen == 0)
381*4882a593Smuzhiyun 		return 0;
382*4882a593Smuzhiyun 
383*4882a593Smuzhiyun 	args->first.iov_base = p;
384*4882a593Smuzhiyun 	args->first.iov_len = rqstp->rq_arg.head[0].iov_len;
385*4882a593Smuzhiyun 	args->first.iov_len -= (char *)p - base;
386*4882a593Smuzhiyun 
387*4882a593Smuzhiyun 	/* This request is never larger than a page. Therefore,
388*4882a593Smuzhiyun 	 * transport will deliver either:
389*4882a593Smuzhiyun 	 * 1. pathname in the pagelist -> sattr is in the tail.
390*4882a593Smuzhiyun 	 * 2. everything in the head buffer -> sattr is in the head.
391*4882a593Smuzhiyun 	 */
392*4882a593Smuzhiyun 	if (rqstp->rq_arg.page_len) {
393*4882a593Smuzhiyun 		if (args->tlen != rqstp->rq_arg.page_len)
394*4882a593Smuzhiyun 			return 0;
395*4882a593Smuzhiyun 		p = rqstp->rq_arg.tail[0].iov_base;
396*4882a593Smuzhiyun 	} else {
397*4882a593Smuzhiyun 		xdrlen = XDR_QUADLEN(args->tlen);
398*4882a593Smuzhiyun 		if (xdrlen > args->first.iov_len - (8 * sizeof(__be32)))
399*4882a593Smuzhiyun 			return 0;
400*4882a593Smuzhiyun 		p += xdrlen;
401*4882a593Smuzhiyun 	}
402*4882a593Smuzhiyun 	decode_sattr(p, &args->attrs, nfsd_user_namespace(rqstp));
403*4882a593Smuzhiyun 
404*4882a593Smuzhiyun 	return 1;
405*4882a593Smuzhiyun }
406*4882a593Smuzhiyun 
407*4882a593Smuzhiyun int
nfssvc_decode_readdirargs(struct svc_rqst * rqstp,__be32 * p)408*4882a593Smuzhiyun nfssvc_decode_readdirargs(struct svc_rqst *rqstp, __be32 *p)
409*4882a593Smuzhiyun {
410*4882a593Smuzhiyun 	struct nfsd_readdirargs *args = rqstp->rq_argp;
411*4882a593Smuzhiyun 
412*4882a593Smuzhiyun 	p = decode_fh(p, &args->fh);
413*4882a593Smuzhiyun 	if (!p)
414*4882a593Smuzhiyun 		return 0;
415*4882a593Smuzhiyun 	args->cookie = ntohl(*p++);
416*4882a593Smuzhiyun 	args->count  = ntohl(*p++);
417*4882a593Smuzhiyun 	args->count  = min_t(u32, args->count, PAGE_SIZE);
418*4882a593Smuzhiyun 	args->buffer = page_address(*(rqstp->rq_next_page++));
419*4882a593Smuzhiyun 
420*4882a593Smuzhiyun 	return xdr_argsize_check(rqstp, p);
421*4882a593Smuzhiyun }
422*4882a593Smuzhiyun 
423*4882a593Smuzhiyun /*
424*4882a593Smuzhiyun  * XDR encode functions
425*4882a593Smuzhiyun  */
426*4882a593Smuzhiyun int
nfssvc_encode_void(struct svc_rqst * rqstp,__be32 * p)427*4882a593Smuzhiyun nfssvc_encode_void(struct svc_rqst *rqstp, __be32 *p)
428*4882a593Smuzhiyun {
429*4882a593Smuzhiyun 	return xdr_ressize_check(rqstp, p);
430*4882a593Smuzhiyun }
431*4882a593Smuzhiyun 
432*4882a593Smuzhiyun int
nfssvc_encode_stat(struct svc_rqst * rqstp,__be32 * p)433*4882a593Smuzhiyun nfssvc_encode_stat(struct svc_rqst *rqstp, __be32 *p)
434*4882a593Smuzhiyun {
435*4882a593Smuzhiyun 	struct nfsd_stat *resp = rqstp->rq_resp;
436*4882a593Smuzhiyun 
437*4882a593Smuzhiyun 	*p++ = resp->status;
438*4882a593Smuzhiyun 	return xdr_ressize_check(rqstp, p);
439*4882a593Smuzhiyun }
440*4882a593Smuzhiyun 
441*4882a593Smuzhiyun int
nfssvc_encode_attrstat(struct svc_rqst * rqstp,__be32 * p)442*4882a593Smuzhiyun nfssvc_encode_attrstat(struct svc_rqst *rqstp, __be32 *p)
443*4882a593Smuzhiyun {
444*4882a593Smuzhiyun 	struct nfsd_attrstat *resp = rqstp->rq_resp;
445*4882a593Smuzhiyun 
446*4882a593Smuzhiyun 	*p++ = resp->status;
447*4882a593Smuzhiyun 	if (resp->status != nfs_ok)
448*4882a593Smuzhiyun 		goto out;
449*4882a593Smuzhiyun 	p = encode_fattr(rqstp, p, &resp->fh, &resp->stat);
450*4882a593Smuzhiyun out:
451*4882a593Smuzhiyun 	return xdr_ressize_check(rqstp, p);
452*4882a593Smuzhiyun }
453*4882a593Smuzhiyun 
454*4882a593Smuzhiyun int
nfssvc_encode_diropres(struct svc_rqst * rqstp,__be32 * p)455*4882a593Smuzhiyun nfssvc_encode_diropres(struct svc_rqst *rqstp, __be32 *p)
456*4882a593Smuzhiyun {
457*4882a593Smuzhiyun 	struct nfsd_diropres *resp = rqstp->rq_resp;
458*4882a593Smuzhiyun 
459*4882a593Smuzhiyun 	*p++ = resp->status;
460*4882a593Smuzhiyun 	if (resp->status != nfs_ok)
461*4882a593Smuzhiyun 		goto out;
462*4882a593Smuzhiyun 	p = encode_fh(p, &resp->fh);
463*4882a593Smuzhiyun 	p = encode_fattr(rqstp, p, &resp->fh, &resp->stat);
464*4882a593Smuzhiyun out:
465*4882a593Smuzhiyun 	return xdr_ressize_check(rqstp, p);
466*4882a593Smuzhiyun }
467*4882a593Smuzhiyun 
468*4882a593Smuzhiyun int
nfssvc_encode_readlinkres(struct svc_rqst * rqstp,__be32 * p)469*4882a593Smuzhiyun nfssvc_encode_readlinkres(struct svc_rqst *rqstp, __be32 *p)
470*4882a593Smuzhiyun {
471*4882a593Smuzhiyun 	struct nfsd_readlinkres *resp = rqstp->rq_resp;
472*4882a593Smuzhiyun 
473*4882a593Smuzhiyun 	*p++ = resp->status;
474*4882a593Smuzhiyun 	if (resp->status != nfs_ok)
475*4882a593Smuzhiyun 		return xdr_ressize_check(rqstp, p);
476*4882a593Smuzhiyun 
477*4882a593Smuzhiyun 	*p++ = htonl(resp->len);
478*4882a593Smuzhiyun 	xdr_ressize_check(rqstp, p);
479*4882a593Smuzhiyun 	rqstp->rq_res.page_len = resp->len;
480*4882a593Smuzhiyun 	if (resp->len & 3) {
481*4882a593Smuzhiyun 		/* need to pad the tail */
482*4882a593Smuzhiyun 		rqstp->rq_res.tail[0].iov_base = p;
483*4882a593Smuzhiyun 		*p = 0;
484*4882a593Smuzhiyun 		rqstp->rq_res.tail[0].iov_len = 4 - (resp->len&3);
485*4882a593Smuzhiyun 	}
486*4882a593Smuzhiyun 	return 1;
487*4882a593Smuzhiyun }
488*4882a593Smuzhiyun 
489*4882a593Smuzhiyun int
nfssvc_encode_readres(struct svc_rqst * rqstp,__be32 * p)490*4882a593Smuzhiyun nfssvc_encode_readres(struct svc_rqst *rqstp, __be32 *p)
491*4882a593Smuzhiyun {
492*4882a593Smuzhiyun 	struct nfsd_readres *resp = rqstp->rq_resp;
493*4882a593Smuzhiyun 
494*4882a593Smuzhiyun 	*p++ = resp->status;
495*4882a593Smuzhiyun 	if (resp->status != nfs_ok)
496*4882a593Smuzhiyun 		return xdr_ressize_check(rqstp, p);
497*4882a593Smuzhiyun 
498*4882a593Smuzhiyun 	p = encode_fattr(rqstp, p, &resp->fh, &resp->stat);
499*4882a593Smuzhiyun 	*p++ = htonl(resp->count);
500*4882a593Smuzhiyun 	xdr_ressize_check(rqstp, p);
501*4882a593Smuzhiyun 
502*4882a593Smuzhiyun 	/* now update rqstp->rq_res to reflect data as well */
503*4882a593Smuzhiyun 	rqstp->rq_res.page_len = resp->count;
504*4882a593Smuzhiyun 	if (resp->count & 3) {
505*4882a593Smuzhiyun 		/* need to pad the tail */
506*4882a593Smuzhiyun 		rqstp->rq_res.tail[0].iov_base = p;
507*4882a593Smuzhiyun 		*p = 0;
508*4882a593Smuzhiyun 		rqstp->rq_res.tail[0].iov_len = 4 - (resp->count&3);
509*4882a593Smuzhiyun 	}
510*4882a593Smuzhiyun 	return 1;
511*4882a593Smuzhiyun }
512*4882a593Smuzhiyun 
513*4882a593Smuzhiyun int
nfssvc_encode_readdirres(struct svc_rqst * rqstp,__be32 * p)514*4882a593Smuzhiyun nfssvc_encode_readdirres(struct svc_rqst *rqstp, __be32 *p)
515*4882a593Smuzhiyun {
516*4882a593Smuzhiyun 	struct nfsd_readdirres *resp = rqstp->rq_resp;
517*4882a593Smuzhiyun 
518*4882a593Smuzhiyun 	*p++ = resp->status;
519*4882a593Smuzhiyun 	if (resp->status != nfs_ok)
520*4882a593Smuzhiyun 		return xdr_ressize_check(rqstp, p);
521*4882a593Smuzhiyun 
522*4882a593Smuzhiyun 	xdr_ressize_check(rqstp, p);
523*4882a593Smuzhiyun 	p = resp->buffer;
524*4882a593Smuzhiyun 	*p++ = 0;			/* no more entries */
525*4882a593Smuzhiyun 	*p++ = htonl((resp->common.err == nfserr_eof));
526*4882a593Smuzhiyun 	rqstp->rq_res.page_len = (((unsigned long)p-1) & ~PAGE_MASK)+1;
527*4882a593Smuzhiyun 
528*4882a593Smuzhiyun 	return 1;
529*4882a593Smuzhiyun }
530*4882a593Smuzhiyun 
531*4882a593Smuzhiyun int
nfssvc_encode_statfsres(struct svc_rqst * rqstp,__be32 * p)532*4882a593Smuzhiyun nfssvc_encode_statfsres(struct svc_rqst *rqstp, __be32 *p)
533*4882a593Smuzhiyun {
534*4882a593Smuzhiyun 	struct nfsd_statfsres *resp = rqstp->rq_resp;
535*4882a593Smuzhiyun 	struct kstatfs	*stat = &resp->stats;
536*4882a593Smuzhiyun 
537*4882a593Smuzhiyun 	*p++ = resp->status;
538*4882a593Smuzhiyun 	if (resp->status != nfs_ok)
539*4882a593Smuzhiyun 		return xdr_ressize_check(rqstp, p);
540*4882a593Smuzhiyun 
541*4882a593Smuzhiyun 	*p++ = htonl(NFSSVC_MAXBLKSIZE_V2);	/* max transfer size */
542*4882a593Smuzhiyun 	*p++ = htonl(stat->f_bsize);
543*4882a593Smuzhiyun 	*p++ = htonl(stat->f_blocks);
544*4882a593Smuzhiyun 	*p++ = htonl(stat->f_bfree);
545*4882a593Smuzhiyun 	*p++ = htonl(stat->f_bavail);
546*4882a593Smuzhiyun 	return xdr_ressize_check(rqstp, p);
547*4882a593Smuzhiyun }
548*4882a593Smuzhiyun 
549*4882a593Smuzhiyun int
nfssvc_encode_entry(void * ccdv,const char * name,int namlen,loff_t offset,u64 ino,unsigned int d_type)550*4882a593Smuzhiyun nfssvc_encode_entry(void *ccdv, const char *name,
551*4882a593Smuzhiyun 		    int namlen, loff_t offset, u64 ino, unsigned int d_type)
552*4882a593Smuzhiyun {
553*4882a593Smuzhiyun 	struct readdir_cd *ccd = ccdv;
554*4882a593Smuzhiyun 	struct nfsd_readdirres *cd = container_of(ccd, struct nfsd_readdirres, common);
555*4882a593Smuzhiyun 	__be32	*p = cd->buffer;
556*4882a593Smuzhiyun 	int	buflen, slen;
557*4882a593Smuzhiyun 
558*4882a593Smuzhiyun 	/*
559*4882a593Smuzhiyun 	dprintk("nfsd: entry(%.*s off %ld ino %ld)\n",
560*4882a593Smuzhiyun 			namlen, name, offset, ino);
561*4882a593Smuzhiyun 	 */
562*4882a593Smuzhiyun 
563*4882a593Smuzhiyun 	if (offset > ~((u32) 0)) {
564*4882a593Smuzhiyun 		cd->common.err = nfserr_fbig;
565*4882a593Smuzhiyun 		return -EINVAL;
566*4882a593Smuzhiyun 	}
567*4882a593Smuzhiyun 	if (cd->offset)
568*4882a593Smuzhiyun 		*cd->offset = htonl(offset);
569*4882a593Smuzhiyun 
570*4882a593Smuzhiyun 	/* truncate filename */
571*4882a593Smuzhiyun 	namlen = min(namlen, NFS2_MAXNAMLEN);
572*4882a593Smuzhiyun 	slen = XDR_QUADLEN(namlen);
573*4882a593Smuzhiyun 
574*4882a593Smuzhiyun 	if ((buflen = cd->buflen - slen - 4) < 0) {
575*4882a593Smuzhiyun 		cd->common.err = nfserr_toosmall;
576*4882a593Smuzhiyun 		return -EINVAL;
577*4882a593Smuzhiyun 	}
578*4882a593Smuzhiyun 	if (ino > ~((u32) 0)) {
579*4882a593Smuzhiyun 		cd->common.err = nfserr_fbig;
580*4882a593Smuzhiyun 		return -EINVAL;
581*4882a593Smuzhiyun 	}
582*4882a593Smuzhiyun 	*p++ = xdr_one;				/* mark entry present */
583*4882a593Smuzhiyun 	*p++ = htonl((u32) ino);		/* file id */
584*4882a593Smuzhiyun 	p    = xdr_encode_array(p, name, namlen);/* name length & name */
585*4882a593Smuzhiyun 	cd->offset = p;			/* remember pointer */
586*4882a593Smuzhiyun 	*p++ = htonl(~0U);		/* offset of next entry */
587*4882a593Smuzhiyun 
588*4882a593Smuzhiyun 	cd->buflen = buflen;
589*4882a593Smuzhiyun 	cd->buffer = p;
590*4882a593Smuzhiyun 	cd->common.err = nfs_ok;
591*4882a593Smuzhiyun 	return 0;
592*4882a593Smuzhiyun }
593*4882a593Smuzhiyun 
594*4882a593Smuzhiyun /*
595*4882a593Smuzhiyun  * XDR release functions
596*4882a593Smuzhiyun  */
nfssvc_release_attrstat(struct svc_rqst * rqstp)597*4882a593Smuzhiyun void nfssvc_release_attrstat(struct svc_rqst *rqstp)
598*4882a593Smuzhiyun {
599*4882a593Smuzhiyun 	struct nfsd_attrstat *resp = rqstp->rq_resp;
600*4882a593Smuzhiyun 
601*4882a593Smuzhiyun 	fh_put(&resp->fh);
602*4882a593Smuzhiyun }
603*4882a593Smuzhiyun 
nfssvc_release_diropres(struct svc_rqst * rqstp)604*4882a593Smuzhiyun void nfssvc_release_diropres(struct svc_rqst *rqstp)
605*4882a593Smuzhiyun {
606*4882a593Smuzhiyun 	struct nfsd_diropres *resp = rqstp->rq_resp;
607*4882a593Smuzhiyun 
608*4882a593Smuzhiyun 	fh_put(&resp->fh);
609*4882a593Smuzhiyun }
610*4882a593Smuzhiyun 
nfssvc_release_readres(struct svc_rqst * rqstp)611*4882a593Smuzhiyun void nfssvc_release_readres(struct svc_rqst *rqstp)
612*4882a593Smuzhiyun {
613*4882a593Smuzhiyun 	struct nfsd_readres *resp = rqstp->rq_resp;
614*4882a593Smuzhiyun 
615*4882a593Smuzhiyun 	fh_put(&resp->fh);
616*4882a593Smuzhiyun }
617