xref: /openbmc/linux/fs/nfsd/nfs3xdr.c (revision d5cb9783536a41df9f9cba5b0a1d78047ed787f7)
1 /*
2  * linux/fs/nfsd/nfs3xdr.c
3  *
4  * XDR support for nfsd/protocol version 3.
5  *
6  * Copyright (C) 1995, 1996, 1997 Olaf Kirch <okir@monad.swb.de>
7  *
8  * 2003-08-09 Jamie Lokier: Use htonl() for nanoseconds, not htons()!
9  */
10 
11 #include <linux/types.h>
12 #include <linux/time.h>
13 #include <linux/nfs3.h>
14 #include <linux/list.h>
15 #include <linux/spinlock.h>
16 #include <linux/dcache.h>
17 #include <linux/namei.h>
18 #include <linux/mm.h>
19 #include <linux/vfs.h>
20 #include <linux/sunrpc/xdr.h>
21 #include <linux/sunrpc/svc.h>
22 #include <linux/nfsd/nfsd.h>
23 #include <linux/nfsd/xdr3.h>
24 
25 #define NFSDDBG_FACILITY		NFSDDBG_XDR
26 
27 #ifdef NFSD_OPTIMIZE_SPACE
28 # define inline
29 #endif
30 
31 
32 /*
33  * Mapping of S_IF* types to NFS file types
34  */
35 static u32	nfs3_ftypes[] = {
36 	NF3NON,  NF3FIFO, NF3CHR, NF3BAD,
37 	NF3DIR,  NF3BAD,  NF3BLK, NF3BAD,
38 	NF3REG,  NF3BAD,  NF3LNK, NF3BAD,
39 	NF3SOCK, NF3BAD,  NF3LNK, NF3BAD,
40 };
41 
42 /*
43  * XDR functions for basic NFS types
44  */
45 static inline u32 *
46 encode_time3(u32 *p, struct timespec *time)
47 {
48 	*p++ = htonl((u32) time->tv_sec); *p++ = htonl(time->tv_nsec);
49 	return p;
50 }
51 
52 static inline u32 *
53 decode_time3(u32 *p, struct timespec *time)
54 {
55 	time->tv_sec = ntohl(*p++);
56 	time->tv_nsec = ntohl(*p++);
57 	return p;
58 }
59 
60 static inline u32 *
61 decode_fh(u32 *p, struct svc_fh *fhp)
62 {
63 	unsigned int size;
64 	fh_init(fhp, NFS3_FHSIZE);
65 	size = ntohl(*p++);
66 	if (size > NFS3_FHSIZE)
67 		return NULL;
68 
69 	memcpy(&fhp->fh_handle.fh_base, p, size);
70 	fhp->fh_handle.fh_size = size;
71 	return p + XDR_QUADLEN(size);
72 }
73 
74 /* Helper function for NFSv3 ACL code */
75 u32 *nfs3svc_decode_fh(u32 *p, struct svc_fh *fhp)
76 {
77 	return decode_fh(p, fhp);
78 }
79 
80 static inline u32 *
81 encode_fh(u32 *p, struct svc_fh *fhp)
82 {
83 	unsigned int size = fhp->fh_handle.fh_size;
84 	*p++ = htonl(size);
85 	if (size) p[XDR_QUADLEN(size)-1]=0;
86 	memcpy(p, &fhp->fh_handle.fh_base, size);
87 	return p + XDR_QUADLEN(size);
88 }
89 
90 /*
91  * Decode a file name and make sure that the path contains
92  * no slashes or null bytes.
93  */
94 static inline u32 *
95 decode_filename(u32 *p, char **namp, int *lenp)
96 {
97 	char		*name;
98 	int		i;
99 
100 	if ((p = xdr_decode_string_inplace(p, namp, lenp, NFS3_MAXNAMLEN)) != NULL) {
101 		for (i = 0, name = *namp; i < *lenp; i++, name++) {
102 			if (*name == '\0' || *name == '/')
103 				return NULL;
104 		}
105 	}
106 
107 	return p;
108 }
109 
110 static inline u32 *
111 decode_sattr3(u32 *p, struct iattr *iap)
112 {
113 	u32	tmp;
114 
115 	iap->ia_valid = 0;
116 
117 	if (*p++) {
118 		iap->ia_valid |= ATTR_MODE;
119 		iap->ia_mode = ntohl(*p++);
120 	}
121 	if (*p++) {
122 		iap->ia_valid |= ATTR_UID;
123 		iap->ia_uid = ntohl(*p++);
124 	}
125 	if (*p++) {
126 		iap->ia_valid |= ATTR_GID;
127 		iap->ia_gid = ntohl(*p++);
128 	}
129 	if (*p++) {
130 		u64	newsize;
131 
132 		iap->ia_valid |= ATTR_SIZE;
133 		p = xdr_decode_hyper(p, &newsize);
134 		if (newsize <= NFS_OFFSET_MAX)
135 			iap->ia_size = newsize;
136 		else
137 			iap->ia_size = NFS_OFFSET_MAX;
138 	}
139 	if ((tmp = ntohl(*p++)) == 1) {	/* set to server time */
140 		iap->ia_valid |= ATTR_ATIME;
141 	} else if (tmp == 2) {		/* set to client time */
142 		iap->ia_valid |= ATTR_ATIME | ATTR_ATIME_SET;
143 		iap->ia_atime.tv_sec = ntohl(*p++);
144 		iap->ia_atime.tv_nsec = ntohl(*p++);
145 	}
146 	if ((tmp = ntohl(*p++)) == 1) {	/* set to server time */
147 		iap->ia_valid |= ATTR_MTIME;
148 	} else if (tmp == 2) {		/* set to client time */
149 		iap->ia_valid |= ATTR_MTIME | ATTR_MTIME_SET;
150 		iap->ia_mtime.tv_sec = ntohl(*p++);
151 		iap->ia_mtime.tv_nsec = ntohl(*p++);
152 	}
153 	return p;
154 }
155 
156 static inline u32 *
157 encode_fattr3(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp)
158 {
159 	struct vfsmount *mnt = fhp->fh_export->ex_mnt;
160 	struct dentry	*dentry = fhp->fh_dentry;
161 	struct kstat stat;
162 	struct timespec time;
163 
164 	vfs_getattr(mnt, dentry, &stat);
165 
166 	*p++ = htonl(nfs3_ftypes[(stat.mode & S_IFMT) >> 12]);
167 	*p++ = htonl((u32) stat.mode);
168 	*p++ = htonl((u32) stat.nlink);
169 	*p++ = htonl((u32) nfsd_ruid(rqstp, stat.uid));
170 	*p++ = htonl((u32) nfsd_rgid(rqstp, stat.gid));
171 	if (S_ISLNK(stat.mode) && stat.size > NFS3_MAXPATHLEN) {
172 		p = xdr_encode_hyper(p, (u64) NFS3_MAXPATHLEN);
173 	} else {
174 		p = xdr_encode_hyper(p, (u64) stat.size);
175 	}
176 	p = xdr_encode_hyper(p, ((u64)stat.blocks) << 9);
177 	*p++ = htonl((u32) MAJOR(stat.rdev));
178 	*p++ = htonl((u32) MINOR(stat.rdev));
179 	if (is_fsid(fhp, rqstp->rq_reffh))
180 		p = xdr_encode_hyper(p, (u64) fhp->fh_export->ex_fsid);
181 	else
182 		p = xdr_encode_hyper(p, (u64) huge_encode_dev(stat.dev));
183 	p = xdr_encode_hyper(p, (u64) stat.ino);
184 	p = encode_time3(p, &stat.atime);
185 	lease_get_mtime(dentry->d_inode, &time);
186 	p = encode_time3(p, &time);
187 	p = encode_time3(p, &stat.ctime);
188 
189 	return p;
190 }
191 
192 static inline u32 *
193 encode_saved_post_attr(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp)
194 {
195 	struct inode	*inode = fhp->fh_dentry->d_inode;
196 
197 	/* Attributes to follow */
198 	*p++ = xdr_one;
199 
200 	*p++ = htonl(nfs3_ftypes[(fhp->fh_post_mode & S_IFMT) >> 12]);
201 	*p++ = htonl((u32) fhp->fh_post_mode);
202 	*p++ = htonl((u32) fhp->fh_post_nlink);
203 	*p++ = htonl((u32) nfsd_ruid(rqstp, fhp->fh_post_uid));
204 	*p++ = htonl((u32) nfsd_rgid(rqstp, fhp->fh_post_gid));
205 	if (S_ISLNK(fhp->fh_post_mode) && fhp->fh_post_size > NFS3_MAXPATHLEN) {
206 		p = xdr_encode_hyper(p, (u64) NFS3_MAXPATHLEN);
207 	} else {
208 		p = xdr_encode_hyper(p, (u64) fhp->fh_post_size);
209 	}
210 	p = xdr_encode_hyper(p, ((u64)fhp->fh_post_blocks) << 9);
211 	*p++ = fhp->fh_post_rdev[0];
212 	*p++ = fhp->fh_post_rdev[1];
213 	if (is_fsid(fhp, rqstp->rq_reffh))
214 		p = xdr_encode_hyper(p, (u64) fhp->fh_export->ex_fsid);
215 	else
216 		p = xdr_encode_hyper(p, (u64)huge_encode_dev(inode->i_sb->s_dev));
217 	p = xdr_encode_hyper(p, (u64) inode->i_ino);
218 	p = encode_time3(p, &fhp->fh_post_atime);
219 	p = encode_time3(p, &fhp->fh_post_mtime);
220 	p = encode_time3(p, &fhp->fh_post_ctime);
221 
222 	return p;
223 }
224 
225 /*
226  * Encode post-operation attributes.
227  * The inode may be NULL if the call failed because of a stale file
228  * handle. In this case, no attributes are returned.
229  */
230 static u32 *
231 encode_post_op_attr(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp)
232 {
233 	struct dentry *dentry = fhp->fh_dentry;
234 	if (dentry && dentry->d_inode != NULL) {
235 		*p++ = xdr_one;		/* attributes follow */
236 		return encode_fattr3(rqstp, p, fhp);
237 	}
238 	*p++ = xdr_zero;
239 	return p;
240 }
241 
242 /* Helper for NFSv3 ACLs */
243 u32 *
244 nfs3svc_encode_post_op_attr(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp)
245 {
246 	return encode_post_op_attr(rqstp, p, fhp);
247 }
248 
249 /*
250  * Enocde weak cache consistency data
251  */
252 static u32 *
253 encode_wcc_data(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp)
254 {
255 	struct dentry	*dentry = fhp->fh_dentry;
256 
257 	if (dentry && dentry->d_inode && fhp->fh_post_saved) {
258 		if (fhp->fh_pre_saved) {
259 			*p++ = xdr_one;
260 			p = xdr_encode_hyper(p, (u64) fhp->fh_pre_size);
261 			p = encode_time3(p, &fhp->fh_pre_mtime);
262 			p = encode_time3(p, &fhp->fh_pre_ctime);
263 		} else {
264 			*p++ = xdr_zero;
265 		}
266 		return encode_saved_post_attr(rqstp, p, fhp);
267 	}
268 	/* no pre- or post-attrs */
269 	*p++ = xdr_zero;
270 	return encode_post_op_attr(rqstp, p, fhp);
271 }
272 
273 
274 /*
275  * XDR decode functions
276  */
277 int
278 nfs3svc_decode_fhandle(struct svc_rqst *rqstp, u32 *p, struct nfsd_fhandle *args)
279 {
280 	if (!(p = decode_fh(p, &args->fh)))
281 		return 0;
282 	return xdr_argsize_check(rqstp, p);
283 }
284 
285 int
286 nfs3svc_decode_sattrargs(struct svc_rqst *rqstp, u32 *p,
287 					struct nfsd3_sattrargs *args)
288 {
289 	if (!(p = decode_fh(p, &args->fh))
290 	 || !(p = decode_sattr3(p, &args->attrs)))
291 		return 0;
292 
293 	if ((args->check_guard = ntohl(*p++)) != 0) {
294 		struct timespec time;
295 		p = decode_time3(p, &time);
296 		args->guardtime = time.tv_sec;
297 	}
298 
299 	return xdr_argsize_check(rqstp, p);
300 }
301 
302 int
303 nfs3svc_decode_diropargs(struct svc_rqst *rqstp, u32 *p,
304 					struct nfsd3_diropargs *args)
305 {
306 	if (!(p = decode_fh(p, &args->fh))
307 	 || !(p = decode_filename(p, &args->name, &args->len)))
308 		return 0;
309 
310 	return xdr_argsize_check(rqstp, p);
311 }
312 
313 int
314 nfs3svc_decode_accessargs(struct svc_rqst *rqstp, u32 *p,
315 					struct nfsd3_accessargs *args)
316 {
317 	if (!(p = decode_fh(p, &args->fh)))
318 		return 0;
319 	args->access = ntohl(*p++);
320 
321 	return xdr_argsize_check(rqstp, p);
322 }
323 
324 int
325 nfs3svc_decode_readargs(struct svc_rqst *rqstp, u32 *p,
326 					struct nfsd3_readargs *args)
327 {
328 	unsigned int len;
329 	int v,pn;
330 
331 	if (!(p = decode_fh(p, &args->fh))
332 	 || !(p = xdr_decode_hyper(p, &args->offset)))
333 		return 0;
334 
335 	len = args->count = ntohl(*p++);
336 
337 	if (len > NFSSVC_MAXBLKSIZE)
338 		len = NFSSVC_MAXBLKSIZE;
339 
340 	/* set up the kvec */
341 	v=0;
342 	while (len > 0) {
343 		pn = rqstp->rq_resused;
344 		svc_take_page(rqstp);
345 		args->vec[v].iov_base = page_address(rqstp->rq_respages[pn]);
346 		args->vec[v].iov_len = len < PAGE_SIZE? len : PAGE_SIZE;
347 		len -= args->vec[v].iov_len;
348 		v++;
349 	}
350 	args->vlen = v;
351 	return xdr_argsize_check(rqstp, p);
352 }
353 
354 int
355 nfs3svc_decode_writeargs(struct svc_rqst *rqstp, u32 *p,
356 					struct nfsd3_writeargs *args)
357 {
358 	unsigned int len, v, hdr;
359 
360 	if (!(p = decode_fh(p, &args->fh))
361 	 || !(p = xdr_decode_hyper(p, &args->offset)))
362 		return 0;
363 
364 	args->count = ntohl(*p++);
365 	args->stable = ntohl(*p++);
366 	len = args->len = ntohl(*p++);
367 
368 	hdr = (void*)p - rqstp->rq_arg.head[0].iov_base;
369 	if (rqstp->rq_arg.len < len + hdr)
370 		return 0;
371 
372 	args->vec[0].iov_base = (void*)p;
373 	args->vec[0].iov_len = rqstp->rq_arg.head[0].iov_len - hdr;
374 
375 	if (len > NFSSVC_MAXBLKSIZE)
376 		len = NFSSVC_MAXBLKSIZE;
377 	v=  0;
378 	while (len > args->vec[v].iov_len) {
379 		len -= args->vec[v].iov_len;
380 		v++;
381 		args->vec[v].iov_base = page_address(rqstp->rq_argpages[v]);
382 		args->vec[v].iov_len = PAGE_SIZE;
383 	}
384 	args->vec[v].iov_len = len;
385 	args->vlen = v+1;
386 
387 	return args->count == args->len && args->vec[0].iov_len > 0;
388 }
389 
390 int
391 nfs3svc_decode_createargs(struct svc_rqst *rqstp, u32 *p,
392 					struct nfsd3_createargs *args)
393 {
394 	if (!(p = decode_fh(p, &args->fh))
395 	 || !(p = decode_filename(p, &args->name, &args->len)))
396 		return 0;
397 
398 	switch (args->createmode = ntohl(*p++)) {
399 	case NFS3_CREATE_UNCHECKED:
400 	case NFS3_CREATE_GUARDED:
401 		if (!(p = decode_sattr3(p, &args->attrs)))
402 			return 0;
403 		break;
404 	case NFS3_CREATE_EXCLUSIVE:
405 		args->verf = p;
406 		p += 2;
407 		break;
408 	default:
409 		return 0;
410 	}
411 
412 	return xdr_argsize_check(rqstp, p);
413 }
414 int
415 nfs3svc_decode_mkdirargs(struct svc_rqst *rqstp, u32 *p,
416 					struct nfsd3_createargs *args)
417 {
418 	if (!(p = decode_fh(p, &args->fh))
419 	 || !(p = decode_filename(p, &args->name, &args->len))
420 	 || !(p = decode_sattr3(p, &args->attrs)))
421 		return 0;
422 
423 	return xdr_argsize_check(rqstp, p);
424 }
425 
426 int
427 nfs3svc_decode_symlinkargs(struct svc_rqst *rqstp, u32 *p,
428 					struct nfsd3_symlinkargs *args)
429 {
430 	unsigned int len;
431 	int avail;
432 	char *old, *new;
433 	struct kvec *vec;
434 
435 	if (!(p = decode_fh(p, &args->ffh))
436 	 || !(p = decode_filename(p, &args->fname, &args->flen))
437 	 || !(p = decode_sattr3(p, &args->attrs))
438 		)
439 		return 0;
440 	/* now decode the pathname, which might be larger than the first page.
441 	 * As we have to check for nul's anyway, we copy it into a new page
442 	 * This page appears in the rq_res.pages list, but as pages_len is always
443 	 * 0, it won't get in the way
444 	 */
445 	svc_take_page(rqstp);
446 	len = ntohl(*p++);
447 	if (len == 0 || len > NFS3_MAXPATHLEN || len >= PAGE_SIZE)
448 		return 0;
449 	args->tname = new = page_address(rqstp->rq_respages[rqstp->rq_resused-1]);
450 	args->tlen = len;
451 	/* first copy and check from the first page */
452 	old = (char*)p;
453 	vec = &rqstp->rq_arg.head[0];
454 	avail = vec->iov_len - (old - (char*)vec->iov_base);
455 	while (len && avail && *old) {
456 		*new++ = *old++;
457 		len--;
458 		avail--;
459 	}
460 	/* now copy next page if there is one */
461 	if (len && !avail && rqstp->rq_arg.page_len) {
462 		avail = rqstp->rq_arg.page_len;
463 		if (avail > PAGE_SIZE) avail = PAGE_SIZE;
464 		old = page_address(rqstp->rq_arg.pages[0]);
465 	}
466 	while (len && avail && *old) {
467 		*new++ = *old++;
468 		len--;
469 		avail--;
470 	}
471 	*new = '\0';
472 	if (len)
473 		return 0;
474 
475 	return 1;
476 }
477 
478 int
479 nfs3svc_decode_mknodargs(struct svc_rqst *rqstp, u32 *p,
480 					struct nfsd3_mknodargs *args)
481 {
482 	if (!(p = decode_fh(p, &args->fh))
483 	 || !(p = decode_filename(p, &args->name, &args->len)))
484 		return 0;
485 
486 	args->ftype = ntohl(*p++);
487 
488 	if (args->ftype == NF3BLK  || args->ftype == NF3CHR
489 	 || args->ftype == NF3SOCK || args->ftype == NF3FIFO) {
490 		if (!(p = decode_sattr3(p, &args->attrs)))
491 			return 0;
492 	}
493 
494 	if (args->ftype == NF3BLK || args->ftype == NF3CHR) {
495 		args->major = ntohl(*p++);
496 		args->minor = ntohl(*p++);
497 	}
498 
499 	return xdr_argsize_check(rqstp, p);
500 }
501 
502 int
503 nfs3svc_decode_renameargs(struct svc_rqst *rqstp, u32 *p,
504 					struct nfsd3_renameargs *args)
505 {
506 	if (!(p = decode_fh(p, &args->ffh))
507 	 || !(p = decode_filename(p, &args->fname, &args->flen))
508 	 || !(p = decode_fh(p, &args->tfh))
509 	 || !(p = decode_filename(p, &args->tname, &args->tlen)))
510 		return 0;
511 
512 	return xdr_argsize_check(rqstp, p);
513 }
514 
515 int
516 nfs3svc_decode_readlinkargs(struct svc_rqst *rqstp, u32 *p,
517 					struct nfsd3_readlinkargs *args)
518 {
519 	if (!(p = decode_fh(p, &args->fh)))
520 		return 0;
521 	svc_take_page(rqstp);
522 	args->buffer = page_address(rqstp->rq_respages[rqstp->rq_resused-1]);
523 
524 	return xdr_argsize_check(rqstp, p);
525 }
526 
527 int
528 nfs3svc_decode_linkargs(struct svc_rqst *rqstp, u32 *p,
529 					struct nfsd3_linkargs *args)
530 {
531 	if (!(p = decode_fh(p, &args->ffh))
532 	 || !(p = decode_fh(p, &args->tfh))
533 	 || !(p = decode_filename(p, &args->tname, &args->tlen)))
534 		return 0;
535 
536 	return xdr_argsize_check(rqstp, p);
537 }
538 
539 int
540 nfs3svc_decode_readdirargs(struct svc_rqst *rqstp, u32 *p,
541 					struct nfsd3_readdirargs *args)
542 {
543 	if (!(p = decode_fh(p, &args->fh)))
544 		return 0;
545 	p = xdr_decode_hyper(p, &args->cookie);
546 	args->verf   = p; p += 2;
547 	args->dircount = ~0;
548 	args->count  = ntohl(*p++);
549 
550 	if (args->count > PAGE_SIZE)
551 		args->count = PAGE_SIZE;
552 
553 	svc_take_page(rqstp);
554 	args->buffer = page_address(rqstp->rq_respages[rqstp->rq_resused-1]);
555 
556 	return xdr_argsize_check(rqstp, p);
557 }
558 
559 int
560 nfs3svc_decode_readdirplusargs(struct svc_rqst *rqstp, u32 *p,
561 					struct nfsd3_readdirargs *args)
562 {
563 	int len, pn;
564 
565 	if (!(p = decode_fh(p, &args->fh)))
566 		return 0;
567 	p = xdr_decode_hyper(p, &args->cookie);
568 	args->verf     = p; p += 2;
569 	args->dircount = ntohl(*p++);
570 	args->count    = ntohl(*p++);
571 
572 	len = (args->count > NFSSVC_MAXBLKSIZE) ? NFSSVC_MAXBLKSIZE :
573 						  args->count;
574 	args->count = len;
575 
576 	while (len > 0) {
577 		pn = rqstp->rq_resused;
578 		svc_take_page(rqstp);
579 		if (!args->buffer)
580 			args->buffer = page_address(rqstp->rq_respages[pn]);
581 		len -= PAGE_SIZE;
582 	}
583 
584 	return xdr_argsize_check(rqstp, p);
585 }
586 
587 int
588 nfs3svc_decode_commitargs(struct svc_rqst *rqstp, u32 *p,
589 					struct nfsd3_commitargs *args)
590 {
591 	if (!(p = decode_fh(p, &args->fh)))
592 		return 0;
593 	p = xdr_decode_hyper(p, &args->offset);
594 	args->count = ntohl(*p++);
595 
596 	return xdr_argsize_check(rqstp, p);
597 }
598 
599 /*
600  * XDR encode functions
601  */
602 /*
603  * There must be an encoding function for void results so svc_process
604  * will work properly.
605  */
606 int
607 nfs3svc_encode_voidres(struct svc_rqst *rqstp, u32 *p, void *dummy)
608 {
609 	return xdr_ressize_check(rqstp, p);
610 }
611 
612 /* GETATTR */
613 int
614 nfs3svc_encode_attrstat(struct svc_rqst *rqstp, u32 *p,
615 					struct nfsd3_attrstat *resp)
616 {
617 	if (resp->status == 0)
618 		p = encode_fattr3(rqstp, p, &resp->fh);
619 	return xdr_ressize_check(rqstp, p);
620 }
621 
622 /* SETATTR, REMOVE, RMDIR */
623 int
624 nfs3svc_encode_wccstat(struct svc_rqst *rqstp, u32 *p,
625 					struct nfsd3_attrstat *resp)
626 {
627 	p = encode_wcc_data(rqstp, p, &resp->fh);
628 	return xdr_ressize_check(rqstp, p);
629 }
630 
631 /* LOOKUP */
632 int
633 nfs3svc_encode_diropres(struct svc_rqst *rqstp, u32 *p,
634 					struct nfsd3_diropres *resp)
635 {
636 	if (resp->status == 0) {
637 		p = encode_fh(p, &resp->fh);
638 		p = encode_post_op_attr(rqstp, p, &resp->fh);
639 	}
640 	p = encode_post_op_attr(rqstp, p, &resp->dirfh);
641 	return xdr_ressize_check(rqstp, p);
642 }
643 
644 /* ACCESS */
645 int
646 nfs3svc_encode_accessres(struct svc_rqst *rqstp, u32 *p,
647 					struct nfsd3_accessres *resp)
648 {
649 	p = encode_post_op_attr(rqstp, p, &resp->fh);
650 	if (resp->status == 0)
651 		*p++ = htonl(resp->access);
652 	return xdr_ressize_check(rqstp, p);
653 }
654 
655 /* READLINK */
656 int
657 nfs3svc_encode_readlinkres(struct svc_rqst *rqstp, u32 *p,
658 					struct nfsd3_readlinkres *resp)
659 {
660 	p = encode_post_op_attr(rqstp, p, &resp->fh);
661 	if (resp->status == 0) {
662 		*p++ = htonl(resp->len);
663 		xdr_ressize_check(rqstp, p);
664 		rqstp->rq_res.page_len = resp->len;
665 		if (resp->len & 3) {
666 			/* need to pad the tail */
667 			rqstp->rq_restailpage = 0;
668 			rqstp->rq_res.tail[0].iov_base = p;
669 			*p = 0;
670 			rqstp->rq_res.tail[0].iov_len = 4 - (resp->len&3);
671 		}
672 		return 1;
673 	} else
674 		return xdr_ressize_check(rqstp, p);
675 }
676 
677 /* READ */
678 int
679 nfs3svc_encode_readres(struct svc_rqst *rqstp, u32 *p,
680 					struct nfsd3_readres *resp)
681 {
682 	p = encode_post_op_attr(rqstp, p, &resp->fh);
683 	if (resp->status == 0) {
684 		*p++ = htonl(resp->count);
685 		*p++ = htonl(resp->eof);
686 		*p++ = htonl(resp->count);	/* xdr opaque count */
687 		xdr_ressize_check(rqstp, p);
688 		/* now update rqstp->rq_res to reflect data aswell */
689 		rqstp->rq_res.page_len = resp->count;
690 		if (resp->count & 3) {
691 			/* need to pad the tail */
692 			rqstp->rq_restailpage = 0;
693 			rqstp->rq_res.tail[0].iov_base = p;
694 			*p = 0;
695 			rqstp->rq_res.tail[0].iov_len = 4 - (resp->count & 3);
696 		}
697 		return 1;
698 	} else
699 		return xdr_ressize_check(rqstp, p);
700 }
701 
702 /* WRITE */
703 int
704 nfs3svc_encode_writeres(struct svc_rqst *rqstp, u32 *p,
705 					struct nfsd3_writeres *resp)
706 {
707 	p = encode_wcc_data(rqstp, p, &resp->fh);
708 	if (resp->status == 0) {
709 		*p++ = htonl(resp->count);
710 		*p++ = htonl(resp->committed);
711 		*p++ = htonl(nfssvc_boot.tv_sec);
712 		*p++ = htonl(nfssvc_boot.tv_usec);
713 	}
714 	return xdr_ressize_check(rqstp, p);
715 }
716 
717 /* CREATE, MKDIR, SYMLINK, MKNOD */
718 int
719 nfs3svc_encode_createres(struct svc_rqst *rqstp, u32 *p,
720 					struct nfsd3_diropres *resp)
721 {
722 	if (resp->status == 0) {
723 		*p++ = xdr_one;
724 		p = encode_fh(p, &resp->fh);
725 		p = encode_post_op_attr(rqstp, p, &resp->fh);
726 	}
727 	p = encode_wcc_data(rqstp, p, &resp->dirfh);
728 	return xdr_ressize_check(rqstp, p);
729 }
730 
731 /* RENAME */
732 int
733 nfs3svc_encode_renameres(struct svc_rqst *rqstp, u32 *p,
734 					struct nfsd3_renameres *resp)
735 {
736 	p = encode_wcc_data(rqstp, p, &resp->ffh);
737 	p = encode_wcc_data(rqstp, p, &resp->tfh);
738 	return xdr_ressize_check(rqstp, p);
739 }
740 
741 /* LINK */
742 int
743 nfs3svc_encode_linkres(struct svc_rqst *rqstp, u32 *p,
744 					struct nfsd3_linkres *resp)
745 {
746 	p = encode_post_op_attr(rqstp, p, &resp->fh);
747 	p = encode_wcc_data(rqstp, p, &resp->tfh);
748 	return xdr_ressize_check(rqstp, p);
749 }
750 
751 /* READDIR */
752 int
753 nfs3svc_encode_readdirres(struct svc_rqst *rqstp, u32 *p,
754 					struct nfsd3_readdirres *resp)
755 {
756 	p = encode_post_op_attr(rqstp, p, &resp->fh);
757 
758 	if (resp->status == 0) {
759 		/* stupid readdir cookie */
760 		memcpy(p, resp->verf, 8); p += 2;
761 		xdr_ressize_check(rqstp, p);
762 		if (rqstp->rq_res.head[0].iov_len + (2<<2) > PAGE_SIZE)
763 			return 1; /*No room for trailer */
764 		rqstp->rq_res.page_len = (resp->count) << 2;
765 
766 		/* add the 'tail' to the end of the 'head' page - page 0. */
767 		rqstp->rq_restailpage = 0;
768 		rqstp->rq_res.tail[0].iov_base = p;
769 		*p++ = 0;		/* no more entries */
770 		*p++ = htonl(resp->common.err == nfserr_eof);
771 		rqstp->rq_res.tail[0].iov_len = 2<<2;
772 		return 1;
773 	} else
774 		return xdr_ressize_check(rqstp, p);
775 }
776 
777 static inline u32 *
778 encode_entry_baggage(struct nfsd3_readdirres *cd, u32 *p, const char *name,
779 	     int namlen, ino_t ino)
780 {
781 	*p++ = xdr_one;				 /* mark entry present */
782 	p    = xdr_encode_hyper(p, ino);	 /* file id */
783 	p    = xdr_encode_array(p, name, namlen);/* name length & name */
784 
785 	cd->offset = p;				/* remember pointer */
786 	p = xdr_encode_hyper(p, NFS_OFFSET_MAX);/* offset of next entry */
787 
788 	return p;
789 }
790 
791 static inline u32 *
792 encode_entryplus_baggage(struct nfsd3_readdirres *cd, u32 *p,
793 		struct svc_fh *fhp)
794 {
795 		p = encode_post_op_attr(cd->rqstp, p, fhp);
796 		*p++ = xdr_one;			/* yes, a file handle follows */
797 		p = encode_fh(p, fhp);
798 		fh_put(fhp);
799 		return p;
800 }
801 
802 static int
803 compose_entry_fh(struct nfsd3_readdirres *cd, struct svc_fh *fhp,
804 		const char *name, int namlen)
805 {
806 	struct svc_export	*exp;
807 	struct dentry		*dparent, *dchild;
808 	int rv = 0;
809 
810 	dparent = cd->fh.fh_dentry;
811 	exp  = cd->fh.fh_export;
812 
813 	fh_init(fhp, NFS3_FHSIZE);
814 	if (isdotent(name, namlen)) {
815 		if (namlen == 2) {
816 			dchild = dget_parent(dparent);
817 			if (dchild == dparent) {
818 				/* filesystem root - cannot return filehandle for ".." */
819 				dput(dchild);
820 				return 1;
821 			}
822 		} else
823 			dchild = dget(dparent);
824 	} else
825 		dchild = lookup_one_len(name, dparent, namlen);
826 	if (IS_ERR(dchild))
827 		return 1;
828 	if (d_mountpoint(dchild) ||
829 	    fh_compose(fhp, exp, dchild, &cd->fh) != 0 ||
830 	    !dchild->d_inode)
831 		rv = 1;
832 	dput(dchild);
833 	return rv;
834 }
835 
836 /*
837  * Encode a directory entry. This one works for both normal readdir
838  * and readdirplus.
839  * The normal readdir reply requires 2 (fileid) + 1 (stringlen)
840  * + string + 2 (cookie) + 1 (next) words, i.e. 6 + strlen.
841  *
842  * The readdirplus baggage is 1+21 words for post_op_attr, plus the
843  * file handle.
844  */
845 
846 #define NFS3_ENTRY_BAGGAGE	(2 + 1 + 2 + 1)
847 #define NFS3_ENTRYPLUS_BAGGAGE	(1 + 21 + 1 + (NFS3_FHSIZE >> 2))
848 static int
849 encode_entry(struct readdir_cd *ccd, const char *name,
850 	     int namlen, off_t offset, ino_t ino, unsigned int d_type, int plus)
851 {
852 	struct nfsd3_readdirres *cd = container_of(ccd, struct nfsd3_readdirres,
853 		       					common);
854 	u32		*p = cd->buffer;
855 	caddr_t		curr_page_addr = NULL;
856 	int		pn;		/* current page number */
857 	int		slen;		/* string (name) length */
858 	int		elen;		/* estimated entry length in words */
859 	int		num_entry_words = 0;	/* actual number of words */
860 
861 	if (cd->offset) {
862 		u64 offset64 = offset;
863 
864 		if (unlikely(cd->offset1)) {
865 			/* we ended up with offset on a page boundary */
866 			*cd->offset = htonl(offset64 >> 32);
867 			*cd->offset1 = htonl(offset64 & 0xffffffff);
868 			cd->offset1 = NULL;
869 		} else {
870 			xdr_encode_hyper(cd->offset, (u64) offset);
871 		}
872 	}
873 
874 	/*
875 	dprintk("encode_entry(%.*s @%ld%s)\n",
876 		namlen, name, (long) offset, plus? " plus" : "");
877 	 */
878 
879 	/* truncate filename if too long */
880 	if (namlen > NFS3_MAXNAMLEN)
881 		namlen = NFS3_MAXNAMLEN;
882 
883 	slen = XDR_QUADLEN(namlen);
884 	elen = slen + NFS3_ENTRY_BAGGAGE
885 		+ (plus? NFS3_ENTRYPLUS_BAGGAGE : 0);
886 
887 	if (cd->buflen < elen) {
888 		cd->common.err = nfserr_toosmall;
889 		return -EINVAL;
890 	}
891 
892 	/* determine which page in rq_respages[] we are currently filling */
893 	for (pn=1; pn < cd->rqstp->rq_resused; pn++) {
894 		curr_page_addr = page_address(cd->rqstp->rq_respages[pn]);
895 
896 		if (((caddr_t)cd->buffer >= curr_page_addr) &&
897 		    ((caddr_t)cd->buffer <  curr_page_addr + PAGE_SIZE))
898 			break;
899 	}
900 
901 	if ((caddr_t)(cd->buffer + elen) < (curr_page_addr + PAGE_SIZE)) {
902 		/* encode entry in current page */
903 
904 		p = encode_entry_baggage(cd, p, name, namlen, ino);
905 
906 		/* throw in readdirplus baggage */
907 		if (plus) {
908 			struct svc_fh	fh;
909 
910 			if (compose_entry_fh(cd, &fh, name, namlen) > 0) {
911 				*p++ = 0;
912 				*p++ = 0;
913 			} else
914 				p = encode_entryplus_baggage(cd, p, &fh);
915 		}
916 		num_entry_words = p - cd->buffer;
917 	} else if (cd->rqstp->rq_respages[pn+1] != NULL) {
918 		/* temporarily encode entry into next page, then move back to
919 		 * current and next page in rq_respages[] */
920 		u32 *p1, *tmp;
921 		int len1, len2;
922 
923 		/* grab next page for temporary storage of entry */
924 		p1 = tmp = page_address(cd->rqstp->rq_respages[pn+1]);
925 
926 		p1 = encode_entry_baggage(cd, p1, name, namlen, ino);
927 
928 		/* throw in readdirplus baggage */
929 		if (plus) {
930 			struct svc_fh	fh;
931 
932 			if (compose_entry_fh(cd, &fh, name, namlen) > 0) {
933 				/* zero out the filehandle */
934 				*p1++ = 0;
935 				*p1++ = 0;
936 			} else
937 				p1 = encode_entryplus_baggage(cd, p1, &fh);
938 		}
939 
940 		/* determine entry word length and lengths to go in pages */
941 		num_entry_words = p1 - tmp;
942 		len1 = curr_page_addr + PAGE_SIZE - (caddr_t)cd->buffer;
943 		if ((num_entry_words << 2) < len1) {
944 			/* the actual number of words in the entry is less
945 			 * than elen and can still fit in the current page
946 			 */
947 			memmove(p, tmp, num_entry_words << 2);
948 			p += num_entry_words;
949 
950 			/* update offset */
951 			cd->offset = cd->buffer + (cd->offset - tmp);
952 		} else {
953 			unsigned int offset_r = (cd->offset - tmp) << 2;
954 
955 			/* update pointer to offset location.
956 			 * This is a 64bit quantity, so we need to
957 			 * deal with 3 cases:
958 			 *  -	entirely in first page
959 			 *  -	entirely in second page
960 			 *  -	4 bytes in each page
961 			 */
962 			if (offset_r + 8 <= len1) {
963 				cd->offset = p + (cd->offset - tmp);
964 			} else if (offset_r >= len1) {
965 				cd->offset -= len1 >> 2;
966 			} else {
967 				/* sitting on the fence */
968 				BUG_ON(offset_r != len1 - 4);
969 				cd->offset = p + (cd->offset - tmp);
970 				cd->offset1 = tmp;
971 			}
972 
973 			len2 = (num_entry_words << 2) - len1;
974 
975 			/* move from temp page to current and next pages */
976 			memmove(p, tmp, len1);
977 			memmove(tmp, (caddr_t)tmp+len1, len2);
978 
979 			p = tmp + (len2 >> 2);
980 		}
981 	}
982 	else {
983 		cd->common.err = nfserr_toosmall;
984 		return -EINVAL;
985 	}
986 
987 	cd->buflen -= num_entry_words;
988 	cd->buffer = p;
989 	cd->common.err = nfs_ok;
990 	return 0;
991 
992 }
993 
994 int
995 nfs3svc_encode_entry(struct readdir_cd *cd, const char *name,
996 		     int namlen, loff_t offset, ino_t ino, unsigned int d_type)
997 {
998 	return encode_entry(cd, name, namlen, offset, ino, d_type, 0);
999 }
1000 
1001 int
1002 nfs3svc_encode_entry_plus(struct readdir_cd *cd, const char *name,
1003 			  int namlen, loff_t offset, ino_t ino, unsigned int d_type)
1004 {
1005 	return encode_entry(cd, name, namlen, offset, ino, d_type, 1);
1006 }
1007 
1008 /* FSSTAT */
1009 int
1010 nfs3svc_encode_fsstatres(struct svc_rqst *rqstp, u32 *p,
1011 					struct nfsd3_fsstatres *resp)
1012 {
1013 	struct kstatfs	*s = &resp->stats;
1014 	u64		bs = s->f_bsize;
1015 
1016 	*p++ = xdr_zero;	/* no post_op_attr */
1017 
1018 	if (resp->status == 0) {
1019 		p = xdr_encode_hyper(p, bs * s->f_blocks);	/* total bytes */
1020 		p = xdr_encode_hyper(p, bs * s->f_bfree);	/* free bytes */
1021 		p = xdr_encode_hyper(p, bs * s->f_bavail);	/* user available bytes */
1022 		p = xdr_encode_hyper(p, s->f_files);	/* total inodes */
1023 		p = xdr_encode_hyper(p, s->f_ffree);	/* free inodes */
1024 		p = xdr_encode_hyper(p, s->f_ffree);	/* user available inodes */
1025 		*p++ = htonl(resp->invarsec);	/* mean unchanged time */
1026 	}
1027 	return xdr_ressize_check(rqstp, p);
1028 }
1029 
1030 /* FSINFO */
1031 int
1032 nfs3svc_encode_fsinfores(struct svc_rqst *rqstp, u32 *p,
1033 					struct nfsd3_fsinfores *resp)
1034 {
1035 	*p++ = xdr_zero;	/* no post_op_attr */
1036 
1037 	if (resp->status == 0) {
1038 		*p++ = htonl(resp->f_rtmax);
1039 		*p++ = htonl(resp->f_rtpref);
1040 		*p++ = htonl(resp->f_rtmult);
1041 		*p++ = htonl(resp->f_wtmax);
1042 		*p++ = htonl(resp->f_wtpref);
1043 		*p++ = htonl(resp->f_wtmult);
1044 		*p++ = htonl(resp->f_dtpref);
1045 		p = xdr_encode_hyper(p, resp->f_maxfilesize);
1046 		*p++ = xdr_one;
1047 		*p++ = xdr_zero;
1048 		*p++ = htonl(resp->f_properties);
1049 	}
1050 
1051 	return xdr_ressize_check(rqstp, p);
1052 }
1053 
1054 /* PATHCONF */
1055 int
1056 nfs3svc_encode_pathconfres(struct svc_rqst *rqstp, u32 *p,
1057 					struct nfsd3_pathconfres *resp)
1058 {
1059 	*p++ = xdr_zero;	/* no post_op_attr */
1060 
1061 	if (resp->status == 0) {
1062 		*p++ = htonl(resp->p_link_max);
1063 		*p++ = htonl(resp->p_name_max);
1064 		*p++ = htonl(resp->p_no_trunc);
1065 		*p++ = htonl(resp->p_chown_restricted);
1066 		*p++ = htonl(resp->p_case_insensitive);
1067 		*p++ = htonl(resp->p_case_preserving);
1068 	}
1069 
1070 	return xdr_ressize_check(rqstp, p);
1071 }
1072 
1073 /* COMMIT */
1074 int
1075 nfs3svc_encode_commitres(struct svc_rqst *rqstp, u32 *p,
1076 					struct nfsd3_commitres *resp)
1077 {
1078 	p = encode_wcc_data(rqstp, p, &resp->fh);
1079 	/* Write verifier */
1080 	if (resp->status == 0) {
1081 		*p++ = htonl(nfssvc_boot.tv_sec);
1082 		*p++ = htonl(nfssvc_boot.tv_usec);
1083 	}
1084 	return xdr_ressize_check(rqstp, p);
1085 }
1086 
1087 /*
1088  * XDR release functions
1089  */
1090 int
1091 nfs3svc_release_fhandle(struct svc_rqst *rqstp, u32 *p,
1092 					struct nfsd3_attrstat *resp)
1093 {
1094 	fh_put(&resp->fh);
1095 	return 1;
1096 }
1097 
1098 int
1099 nfs3svc_release_fhandle2(struct svc_rqst *rqstp, u32 *p,
1100 					struct nfsd3_fhandle_pair *resp)
1101 {
1102 	fh_put(&resp->fh1);
1103 	fh_put(&resp->fh2);
1104 	return 1;
1105 }
1106