File: /usr/src/linux/fs/nfsd/nfs3xdr.c

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     
9     #include <linux/types.h>
10     #include <linux/sched.h>
11     #include <linux/nfs3.h>
12     
13     #include <linux/sunrpc/xdr.h>
14     #include <linux/sunrpc/svc.h>
15     #include <linux/nfsd/nfsd.h>
16     #include <linux/nfsd/xdr3.h>
17     
18     #define NFSDDBG_FACILITY		NFSDDBG_XDR
19     
20     #ifdef NFSD_OPTIMIZE_SPACE
21     # define inline
22     #endif
23     
24     
25     /*
26      * Mapping of S_IF* types to NFS file types
27      */
28     static u32	nfs3_ftypes[] = {
29     	NF3NON,  NF3FIFO, NF3CHR, NF3BAD,
30     	NF3DIR,  NF3BAD,  NF3BLK, NF3BAD,
31     	NF3REG,  NF3BAD,  NF3LNK, NF3BAD,
32     	NF3SOCK, NF3BAD,  NF3LNK, NF3BAD,
33     };
34     
35     /*
36      * XDR functions for basic NFS types
37      */
38     static inline u32 *
39     encode_time3(u32 *p, time_t secs)
40     {
41     	*p++ = htonl((u32) secs); *p++ = 0;
42     	return p;
43     }
44     
45     static inline u32 *
46     decode_time3(u32 *p, time_t *secp)
47     {
48     	*secp = ntohl(*p++);
49     	return p + 1;
50     }
51     
52     static inline u32 *
53     decode_fh(u32 *p, struct svc_fh *fhp)
54     {
55     	int size;
56     	fh_init(fhp, NFS3_FHSIZE);
57     	size = ntohl(*p++);
58     	if (size > NFS3_FHSIZE)
59     		return NULL;
60     
61     	memcpy(&fhp->fh_handle.fh_base, p, size);
62     	fhp->fh_handle.fh_size = size;
63     	return p + XDR_QUADLEN(size);
64     }
65     
66     static inline u32 *
67     encode_fh(u32 *p, struct svc_fh *fhp)
68     {
69     	int size = fhp->fh_handle.fh_size;
70     	*p++ = htonl(size);
71     	if (size) p[XDR_QUADLEN(size)-1]=0;
72     	memcpy(p, &fhp->fh_handle.fh_base, size);
73     	return p + XDR_QUADLEN(size);
74     }
75     
76     /*
77      * Decode a file name and make sure that the path contains
78      * no slashes or null bytes.
79      */
80     static inline u32 *
81     decode_filename(u32 *p, char **namp, int *lenp)
82     {
83     	char		*name;
84     	int		i;
85     
86     	if ((p = xdr_decode_string_inplace(p, namp, lenp, NFS3_MAXNAMLEN)) != NULL) {
87     		for (i = 0, name = *namp; i < *lenp; i++, name++) {
88     			if (*name == '\0' || *name == '/')
89     				return NULL;
90     		}
91     	}
92     
93     	return p;
94     }
95     
96     static inline u32 *
97     decode_pathname(u32 *p, char **namp, int *lenp)
98     {
99     	char		*name;
100     	int		i;
101     
102     	if ((p = xdr_decode_string_inplace(p, namp, lenp, NFS3_MAXPATHLEN)) != NULL) {
103     		for (i = 0, name = *namp; i < *lenp; i++, name++) {
104     			if (*name == '\0')
105     				return NULL;
106     		}
107     	}
108     
109     	return p;
110     }
111     
112     static inline u32 *
113     decode_sattr3(u32 *p, struct iattr *iap)
114     {
115     	u32	tmp;
116     
117     	iap->ia_valid = 0;
118     
119     	if (*p++) {
120     		iap->ia_valid |= ATTR_MODE;
121     		iap->ia_mode = ntohl(*p++);
122     	}
123     	if (*p++) {
124     		iap->ia_valid |= ATTR_UID;
125     		iap->ia_uid = ntohl(*p++);
126     	}
127     	if (*p++) {
128     		iap->ia_valid |= ATTR_GID;
129     		iap->ia_gid = ntohl(*p++);
130     	}
131     	if (*p++) {
132     		u64	newsize;
133     
134     		iap->ia_valid |= ATTR_SIZE;
135     		p = xdr_decode_hyper(p, &newsize);
136     		if (newsize <= NFS_OFFSET_MAX)
137     			iap->ia_size = newsize;
138     		else
139     			iap->ia_size = NFS_OFFSET_MAX;
140     	}
141     	if ((tmp = ntohl(*p++)) == 1) {	/* set to server time */
142     		iap->ia_valid |= ATTR_ATIME;
143     	} else if (tmp == 2) {		/* set to client time */
144     		iap->ia_valid |= ATTR_ATIME | ATTR_ATIME_SET;
145     		iap->ia_atime = ntohl(*p++), p++;
146     	}
147     	if ((tmp = ntohl(*p++)) == 1) {	/* set to server time */
148     		iap->ia_valid |= ATTR_MTIME;
149     	} else if (tmp == 2) {		/* set to client time */
150     		iap->ia_valid |= ATTR_MTIME | ATTR_MTIME_SET;
151     		iap->ia_mtime = ntohl(*p++), p++;
152     	}
153     	return p;
154     }
155     
156     static inline u32 *
157     encode_fattr3(struct svc_rqst *rqstp, u32 *p, struct dentry *dentry)
158     {
159     	struct inode	*inode = dentry->d_inode;
160     
161     	*p++ = htonl(nfs3_ftypes[(inode->i_mode & S_IFMT) >> 12]);
162     	*p++ = htonl((u32) inode->i_mode);
163     	*p++ = htonl((u32) inode->i_nlink);
164     	*p++ = htonl((u32) nfsd_ruid(rqstp, inode->i_uid));
165     	*p++ = htonl((u32) nfsd_rgid(rqstp, inode->i_gid));
166     	if (S_ISLNK(inode->i_mode) && inode->i_size > NFS3_MAXPATHLEN) {
167     		p = xdr_encode_hyper(p, (u64) NFS3_MAXPATHLEN);
168     	} else {
169     		p = xdr_encode_hyper(p, (u64) inode->i_size);
170     	}
171     	if (inode->i_blksize == 0 && inode->i_blocks == 0)
172     		/* Minix file system(?) i_size is (hopefully) close enough */
173     		p = xdr_encode_hyper(p, (u64)(inode->i_size +511)& ~511);
174     	else
175     		p = xdr_encode_hyper(p, ((u64)inode->i_blocks) << 9);
176     	*p++ = htonl((u32) MAJOR(inode->i_rdev));
177     	*p++ = htonl((u32) MINOR(inode->i_rdev));
178     	p = xdr_encode_hyper(p, (u64) inode->i_dev);
179     	p = xdr_encode_hyper(p, (u64) inode->i_ino);
180     	p = encode_time3(p, inode->i_atime);
181     	p = encode_time3(p, lease_get_mtime(inode));
182     	p = encode_time3(p, inode->i_ctime);
183     
184     	return p;
185     }
186     
187     static inline u32 *
188     encode_saved_post_attr(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp)
189     {
190     	struct inode	*inode = fhp->fh_dentry->d_inode;
191     
192     	/* Attributes to follow */
193     	*p++ = xdr_one;
194     
195     	*p++ = htonl(nfs3_ftypes[(fhp->fh_post_mode & S_IFMT) >> 12]);
196     	*p++ = htonl((u32) fhp->fh_post_mode);
197     	*p++ = htonl((u32) fhp->fh_post_nlink);
198     	*p++ = htonl((u32) nfsd_ruid(rqstp, fhp->fh_post_uid));
199     	*p++ = htonl((u32) nfsd_rgid(rqstp, fhp->fh_post_gid));
200     	if (S_ISLNK(fhp->fh_post_mode) && fhp->fh_post_size > NFS3_MAXPATHLEN) {
201     		p = xdr_encode_hyper(p, (u64) NFS3_MAXPATHLEN);
202     	} else {
203     		p = xdr_encode_hyper(p, (u64) fhp->fh_post_size);
204     	}
205     	p = xdr_encode_hyper(p, ((u64)fhp->fh_post_blocks) << 9);
206     	*p++ = htonl((u32) MAJOR(fhp->fh_post_rdev));
207     	*p++ = htonl((u32) MINOR(fhp->fh_post_rdev));
208     	p = xdr_encode_hyper(p, (u64) inode->i_dev);
209     	p = xdr_encode_hyper(p, (u64) inode->i_ino);
210     	p = encode_time3(p, fhp->fh_post_atime);
211     	p = encode_time3(p, fhp->fh_post_mtime);
212     	p = encode_time3(p, fhp->fh_post_ctime);
213     
214     	return p;
215     }
216     
217     /*
218      * Encode post-operation attributes.
219      * The inode may be NULL if the call failed because of a stale file
220      * handle. In this case, no attributes are returned.
221      */
222     static u32 *
223     encode_post_op_attr(struct svc_rqst *rqstp, u32 *p, struct dentry *dentry)
224     {
225     	if (dentry && dentry->d_inode != NULL) {
226     		*p++ = xdr_one;		/* attributes follow */
227     		return encode_fattr3(rqstp, p, dentry);
228     	}
229     	*p++ = xdr_zero;
230     	return p;
231     }
232     
233     /*
234      * Enocde weak cache consistency data
235      */
236     static u32 *
237     encode_wcc_data(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp)
238     {
239     	struct dentry	*dentry = fhp->fh_dentry;
240     
241     	if (dentry && dentry->d_inode && fhp->fh_post_saved) {
242     		if (fhp->fh_pre_saved) {
243     			*p++ = xdr_one;
244     			p = xdr_encode_hyper(p, (u64) fhp->fh_pre_size);
245     			p = encode_time3(p, fhp->fh_pre_mtime);
246     			p = encode_time3(p, fhp->fh_pre_ctime);
247     		} else {
248     			*p++ = xdr_zero;
249     		}
250     		return encode_saved_post_attr(rqstp, p, fhp);
251     	}
252     	/* no pre- or post-attrs */
253     	*p++ = xdr_zero;
254     	return encode_post_op_attr(rqstp, p, dentry);
255     }
256     
257     /*
258      * Check buffer bounds after decoding arguments
259      */
260     static inline int
261     xdr_argsize_check(struct svc_rqst *rqstp, u32 *p)
262     {
263     	struct svc_buf	*buf = &rqstp->rq_argbuf;
264     
265     	return p - buf->base <= buf->buflen;
266     }
267     
268     static inline int
269     xdr_ressize_check(struct svc_rqst *rqstp, u32 *p)
270     {
271     	struct svc_buf	*buf = &rqstp->rq_resbuf;
272     
273     	buf->len = p - buf->base;
274     	dprintk("nfsd: ressize_check p %p base %p len %d\n",
275     			p, buf->base, buf->buflen);
276     	return (buf->len <= buf->buflen);
277     }
278     
279     /*
280      * XDR decode functions
281      */
282     int
283     nfs3svc_decode_fhandle(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp)
284     {
285     	if (!(p = decode_fh(p, fhp)))
286     		return 0;
287     	return xdr_argsize_check(rqstp, p);
288     }
289     
290     int
291     nfs3svc_decode_sattrargs(struct svc_rqst *rqstp, u32 *p,
292     					struct nfsd3_sattrargs *args)
293     {
294     	if (!(p = decode_fh(p, &args->fh))
295     	 || !(p = decode_sattr3(p, &args->attrs)))
296     		return 0;
297     
298     	if ((args->check_guard = ntohl(*p++)) != 0)
299     		p = decode_time3(p, &args->guardtime);
300     
301     	return xdr_argsize_check(rqstp, p);
302     }
303     
304     int
305     nfs3svc_decode_diropargs(struct svc_rqst *rqstp, u32 *p,
306     					struct nfsd3_diropargs *args)
307     {
308     	if (!(p = decode_fh(p, &args->fh))
309     	 || !(p = decode_filename(p, &args->name, &args->len)))
310     		return 0;
311     
312     	return xdr_argsize_check(rqstp, p);
313     }
314     
315     int
316     nfs3svc_decode_accessargs(struct svc_rqst *rqstp, u32 *p,
317     					struct nfsd3_accessargs *args)
318     {
319     	if (!(p = decode_fh(p, &args->fh)))
320     		return 0;
321     	args->access = ntohl(*p++);
322     
323     	return xdr_argsize_check(rqstp, p);
324     }
325     
326     int
327     nfs3svc_decode_readargs(struct svc_rqst *rqstp, u32 *p,
328     					struct nfsd3_readargs *args)
329     {
330     	if (!(p = decode_fh(p, &args->fh))
331     	 || !(p = xdr_decode_hyper(p, &args->offset)))
332     		return 0;
333     
334     	args->count = ntohl(*p++);
335     	return xdr_argsize_check(rqstp, p);
336     }
337     
338     int
339     nfs3svc_decode_writeargs(struct svc_rqst *rqstp, u32 *p,
340     					struct nfsd3_writeargs *args)
341     {
342     	if (!(p = decode_fh(p, &args->fh))
343     	 || !(p = xdr_decode_hyper(p, &args->offset)))
344     		return 0;
345     
346     	args->count = ntohl(*p++);
347     	args->stable = ntohl(*p++);
348     	args->len = ntohl(*p++);
349     	args->data = (char *) p;
350     	p += XDR_QUADLEN(args->len);
351     
352     	return xdr_argsize_check(rqstp, p);
353     }
354     
355     int
356     nfs3svc_decode_createargs(struct svc_rqst *rqstp, u32 *p,
357     					struct nfsd3_createargs *args)
358     {
359     	if (!(p = decode_fh(p, &args->fh))
360     	 || !(p = decode_filename(p, &args->name, &args->len)))
361     		return 0;
362     
363     	switch (args->createmode = ntohl(*p++)) {
364     	case NFS3_CREATE_UNCHECKED:
365     	case NFS3_CREATE_GUARDED:
366     		if (!(p = decode_sattr3(p, &args->attrs)))
367     			return 0;
368     		break;
369     	case NFS3_CREATE_EXCLUSIVE:
370     		args->verf = p;
371     		p += 2;
372     		break;
373     	default:
374     		return 0;
375     	}
376     
377     	return xdr_argsize_check(rqstp, p);
378     }
379     int
380     nfs3svc_decode_mkdirargs(struct svc_rqst *rqstp, u32 *p,
381     					struct nfsd3_createargs *args)
382     {
383     	if (!(p = decode_fh(p, &args->fh))
384     	 || !(p = decode_filename(p, &args->name, &args->len))
385     	 || !(p = decode_sattr3(p, &args->attrs)))
386     		return 0;
387     
388     	return xdr_argsize_check(rqstp, p);
389     }
390     
391     int
392     nfs3svc_decode_symlinkargs(struct svc_rqst *rqstp, u32 *p,
393     					struct nfsd3_symlinkargs *args)
394     {
395     	if (!(p = decode_fh(p, &args->ffh))
396     	 || !(p = decode_filename(p, &args->fname, &args->flen))
397     	 || !(p = decode_sattr3(p, &args->attrs))
398     	 || !(p = decode_pathname(p, &args->tname, &args->tlen)))
399     		return 0;
400     
401     	return xdr_argsize_check(rqstp, p);
402     }
403     
404     int
405     nfs3svc_decode_mknodargs(struct svc_rqst *rqstp, u32 *p,
406     					struct nfsd3_mknodargs *args)
407     {
408     	if (!(p = decode_fh(p, &args->fh))
409     	 || !(p = decode_filename(p, &args->name, &args->len)))
410     		return 0;
411     
412     	args->ftype = ntohl(*p++);
413     
414     	if (args->ftype == NF3BLK  || args->ftype == NF3CHR
415     	 || args->ftype == NF3SOCK || args->ftype == NF3FIFO) {
416     		if (!(p = decode_sattr3(p, &args->attrs)))
417     			return 0;
418     	}
419     
420     	if (args->ftype == NF3BLK || args->ftype == NF3CHR) {
421     		args->major = ntohl(*p++);
422     		args->minor = ntohl(*p++);
423     	}
424     
425     	return xdr_argsize_check(rqstp, p);
426     }
427     
428     int
429     nfs3svc_decode_renameargs(struct svc_rqst *rqstp, u32 *p,
430     					struct nfsd3_renameargs *args)
431     {
432     	if (!(p = decode_fh(p, &args->ffh))
433     	 || !(p = decode_filename(p, &args->fname, &args->flen))
434     	 || !(p = decode_fh(p, &args->tfh))
435     	 || !(p = decode_filename(p, &args->tname, &args->tlen)))
436     		return 0;
437     
438     	return xdr_argsize_check(rqstp, p);
439     }
440     
441     int
442     nfs3svc_decode_linkargs(struct svc_rqst *rqstp, u32 *p,
443     					struct nfsd3_linkargs *args)
444     {
445     	if (!(p = decode_fh(p, &args->ffh))
446     	 || !(p = decode_fh(p, &args->tfh))
447     	 || !(p = decode_filename(p, &args->tname, &args->tlen)))
448     		return 0;
449     
450     	return xdr_argsize_check(rqstp, p);
451     }
452     
453     int
454     nfs3svc_decode_readdirargs(struct svc_rqst *rqstp, u32 *p,
455     					struct nfsd3_readdirargs *args)
456     {
457     	if (!(p = decode_fh(p, &args->fh)))
458     		return 0;
459     	p = xdr_decode_hyper(p, &args->cookie);
460     	args->verf   = p; p += 2;
461     	args->dircount = ~0;
462     	args->count  = ntohl(*p++);
463     
464     	return xdr_argsize_check(rqstp, p);
465     }
466     
467     int
468     nfs3svc_decode_readdirplusargs(struct svc_rqst *rqstp, u32 *p,
469     					struct nfsd3_readdirargs *args)
470     {
471     	if (!(p = decode_fh(p, &args->fh)))
472     		return 0;
473     	p = xdr_decode_hyper(p, &args->cookie);
474     	args->verf     = p; p += 2;
475     	args->dircount = ntohl(*p++);
476     	args->count    = ntohl(*p++);
477     
478     	return xdr_argsize_check(rqstp, p);
479     }
480     
481     int
482     nfs3svc_decode_commitargs(struct svc_rqst *rqstp, u32 *p,
483     					struct nfsd3_commitargs *args)
484     {
485     	if (!(p = decode_fh(p, &args->fh)))
486     		return 0;
487     	p = xdr_decode_hyper(p, &args->offset);
488     	args->count = ntohl(*p++);
489     
490     	return xdr_argsize_check(rqstp, p);
491     }
492     
493     /*
494      * XDR encode functions
495      */
496     /*
497      * There must be an encoding function for void results so svc_process
498      * will work properly.
499      */
500     int
501     nfs3svc_encode_voidres(struct svc_rqst *rqstp, u32 *p, void *dummy)
502     {
503     	return xdr_ressize_check(rqstp, p);
504     }
505     
506     /* GETATTR */
507     int
508     nfs3svc_encode_attrstat(struct svc_rqst *rqstp, u32 *p,
509     					struct nfsd3_attrstat *resp)
510     {
511     	if (resp->status == 0)
512     		p = encode_fattr3(rqstp, p, resp->fh.fh_dentry);
513     	return xdr_ressize_check(rqstp, p);
514     }
515     
516     /* SETATTR, REMOVE, RMDIR */
517     int
518     nfs3svc_encode_wccstat(struct svc_rqst *rqstp, u32 *p,
519     					struct nfsd3_attrstat *resp)
520     {
521     	p = encode_wcc_data(rqstp, p, &resp->fh);
522     	return xdr_ressize_check(rqstp, p);
523     }
524     
525     /* LOOKUP */
526     int
527     nfs3svc_encode_diropres(struct svc_rqst *rqstp, u32 *p,
528     					struct nfsd3_diropres *resp)
529     {
530     	if (resp->status == 0) {
531     		p = encode_fh(p, &resp->fh);
532     		p = encode_post_op_attr(rqstp, p, resp->fh.fh_dentry);
533     	}
534     	p = encode_post_op_attr(rqstp, p, resp->dirfh.fh_dentry);
535     	return xdr_ressize_check(rqstp, p);
536     }
537     
538     /* ACCESS */
539     int
540     nfs3svc_encode_accessres(struct svc_rqst *rqstp, u32 *p,
541     					struct nfsd3_accessres *resp)
542     {
543     	p = encode_post_op_attr(rqstp, p, resp->fh.fh_dentry);
544     	if (resp->status == 0)
545     		*p++ = htonl(resp->access);
546     	return xdr_ressize_check(rqstp, p);
547     }
548     
549     /* READLINK */
550     int
551     nfs3svc_encode_readlinkres(struct svc_rqst *rqstp, u32 *p,
552     					struct nfsd3_readlinkres *resp)
553     {
554     	p = encode_post_op_attr(rqstp, p, resp->fh.fh_dentry);
555     	if (resp->status == 0) {
556     		*p++ = htonl(resp->len);
557     		p += XDR_QUADLEN(resp->len);
558     	}
559     	return xdr_ressize_check(rqstp, p);
560     }
561     
562     /* READ */
563     int
564     nfs3svc_encode_readres(struct svc_rqst *rqstp, u32 *p,
565     					struct nfsd3_readres *resp)
566     {
567     	p = encode_post_op_attr(rqstp, p, resp->fh.fh_dentry);
568     	if (resp->status == 0) {
569     		*p++ = htonl(resp->count);
570     		*p++ = htonl(resp->eof);
571     		*p++ = htonl(resp->count);	/* xdr opaque count */
572     		p += XDR_QUADLEN(resp->count);
573     	}
574     	return xdr_ressize_check(rqstp, p);
575     }
576     
577     /* WRITE */
578     int
579     nfs3svc_encode_writeres(struct svc_rqst *rqstp, u32 *p,
580     					struct nfsd3_writeres *resp)
581     {
582     	p = encode_wcc_data(rqstp, p, &resp->fh);
583     	if (resp->status == 0) {
584     		*p++ = htonl(resp->count);
585     		*p++ = htonl(resp->committed);
586     		*p++ = htonl(nfssvc_boot.tv_sec);
587     		*p++ = htonl(nfssvc_boot.tv_usec);
588     	}
589     	return xdr_ressize_check(rqstp, p);
590     }
591     
592     /* CREATE, MKDIR, SYMLINK, MKNOD */
593     int
594     nfs3svc_encode_createres(struct svc_rqst *rqstp, u32 *p,
595     					struct nfsd3_diropres *resp)
596     {
597     	if (resp->status == 0) {
598     		*p++ = xdr_one;
599     		p = encode_fh(p, &resp->fh);
600     		p = encode_post_op_attr(rqstp, p, resp->fh.fh_dentry);
601     	}
602     	p = encode_wcc_data(rqstp, p, &resp->dirfh);
603     	return xdr_ressize_check(rqstp, p);
604     }
605     
606     /* RENAME */
607     int
608     nfs3svc_encode_renameres(struct svc_rqst *rqstp, u32 *p,
609     					struct nfsd3_renameres *resp)
610     {
611     	p = encode_wcc_data(rqstp, p, &resp->ffh);
612     	p = encode_wcc_data(rqstp, p, &resp->tfh);
613     	return xdr_ressize_check(rqstp, p);
614     }
615     
616     /* LINK */
617     int
618     nfs3svc_encode_linkres(struct svc_rqst *rqstp, u32 *p,
619     					struct nfsd3_linkres *resp)
620     {
621     	p = encode_post_op_attr(rqstp, p, resp->fh.fh_dentry);
622     	p = encode_wcc_data(rqstp, p, &resp->tfh);
623     	return xdr_ressize_check(rqstp, p);
624     }
625     
626     /* READDIR */
627     int
628     nfs3svc_encode_readdirres(struct svc_rqst *rqstp, u32 *p,
629     					struct nfsd3_readdirres *resp)
630     {
631     	p = encode_post_op_attr(rqstp, p, resp->fh.fh_dentry);
632     	if (resp->status == 0) {
633     		/* stupid readdir cookie */
634     		memcpy(p, resp->verf, 8); p += 2;
635     		p += XDR_QUADLEN(resp->count);
636     	}
637     
638     	return xdr_ressize_check(rqstp, p);
639     }
640     
641     /*
642      * Encode a directory entry. This one works for both normal readdir
643      * and readdirplus.
644      * The normal readdir reply requires 2 (fileid) + 1 (stringlen)
645      * + string + 2 (cookie) + 1 (next) words, i.e. 6 + strlen.
646      * 
647      * The readdirplus baggage is 1+21 words for post_op_attr, plus the
648      * file handle.
649      */
650     
651     #define NFS3_ENTRY_BAGGAGE	(2 + 1 + 2 + 1)
652     #define NFS3_ENTRYPLUS_BAGGAGE	(1 + 21 + 1 + (NFS3_FHSIZE >> 2))
653     static int
654     encode_entry(struct readdir_cd *cd, const char *name,
655     	     int namlen, off_t offset, ino_t ino, unsigned int d_type, int plus)
656     {
657     	u32		*p = cd->buffer;
658     	int		buflen, slen, elen;
659     
660     	if (cd->offset)
661     		xdr_encode_hyper(cd->offset, (u64) offset);
662     
663     	/* nfsd_readdir calls us with name == 0 when it wants us to
664     	 * set the last offset entry. */
665     	if (name == 0)
666     		return 0;
667     
668     	/*
669     	dprintk("encode_entry(%.*s @%ld%s)\n",
670     		namlen, name, (long) offset, plus? " plus" : "");
671     	 */
672     
673     	/* truncate filename if too long */
674     	if (namlen > NFS3_MAXNAMLEN)
675     		namlen = NFS3_MAXNAMLEN;
676     
677     	slen = XDR_QUADLEN(namlen);
678     	elen = slen + NFS3_ENTRY_BAGGAGE
679     		+ (plus? NFS3_ENTRYPLUS_BAGGAGE : 0);
680     	if ((buflen = cd->buflen - elen) < 0) {
681     		cd->eob = 1;
682     		return -EINVAL;
683     	}
684     	*p++ = xdr_one;				 /* mark entry present */
685     	p    = xdr_encode_hyper(p, ino);	 /* file id */
686     	p    = xdr_encode_array(p, name, namlen);/* name length & name */
687     
688     	cd->offset = p;			/* remember pointer */
689     	p = xdr_encode_hyper(p, NFS_OFFSET_MAX);	/* offset of next entry */
690     
691     	/* throw in readdirplus baggage */
692     	if (plus) {
693     		struct svc_fh	fh;
694     		struct svc_export	*exp;
695     		struct dentry		*dparent, *dchild;
696     
697     		dparent = cd->dirfh->fh_dentry;
698     		exp  = cd->dirfh->fh_export;
699     
700     		fh_init(&fh, NFS3_FHSIZE);
701     		if (isdotent(name, namlen)) {
702     			dchild = dparent;
703     			if (namlen == 2)
704     				dchild = dchild->d_parent;
705     			dchild = dget(dchild);
706     		} else
707     			dchild = lookup_one_len(name, dparent,namlen);
708     		if (IS_ERR(dchild))
709     			goto noexec;
710     		if (fh_compose(&fh, exp, dchild, cd->dirfh) != 0 || !dchild->d_inode)
711     			goto noexec;
712     		p = encode_post_op_attr(cd->rqstp, p, fh.fh_dentry);
713     		*p++ = xdr_one; /* yes, a file handle follows */
714     		p = encode_fh(p, &fh);
715     		fh_put(&fh);
716     	}
717     
718     out:
719     	cd->buflen = buflen;
720     	cd->buffer = p;
721     	return 0;
722     
723     noexec:
724     	*p++ = 0;
725     	*p++ = 0;
726     	goto out;
727     }
728     
729     int
730     nfs3svc_encode_entry(struct readdir_cd *cd, const char *name,
731     		     int namlen, loff_t offset, ino_t ino, unsigned int d_type)
732     {
733     	return encode_entry(cd, name, namlen, offset, ino, d_type, 0);
734     }
735     
736     int
737     nfs3svc_encode_entry_plus(struct readdir_cd *cd, const char *name,
738     			  int namlen, loff_t offset, ino_t ino, unsigned int d_type)
739     {
740     	return encode_entry(cd, name, namlen, offset, ino, d_type, 1);
741     }
742     
743     /* FSSTAT */
744     int
745     nfs3svc_encode_fsstatres(struct svc_rqst *rqstp, u32 *p,
746     					struct nfsd3_fsstatres *resp)
747     {
748     	struct statfs	*s = &resp->stats;
749     	u64		bs = s->f_bsize;
750     
751     	*p++ = xdr_zero;	/* no post_op_attr */
752     
753     	if (resp->status == 0) {
754     		p = xdr_encode_hyper(p, bs * s->f_blocks);	/* total bytes */
755     		p = xdr_encode_hyper(p, bs * s->f_bfree);	/* free bytes */
756     		p = xdr_encode_hyper(p, bs * s->f_bavail);	/* user available bytes */
757     		p = xdr_encode_hyper(p, s->f_files);	/* total inodes */
758     		p = xdr_encode_hyper(p, s->f_ffree);	/* free inodes */
759     		p = xdr_encode_hyper(p, s->f_ffree);	/* user available inodes */
760     		*p++ = htonl(resp->invarsec);	/* mean unchanged time */
761     	}
762     	return xdr_ressize_check(rqstp, p);
763     }
764     
765     /* FSINFO */
766     int
767     nfs3svc_encode_fsinfores(struct svc_rqst *rqstp, u32 *p,
768     					struct nfsd3_fsinfores *resp)
769     {
770     	*p++ = xdr_zero;	/* no post_op_attr */
771     
772     	if (resp->status == 0) {
773     		*p++ = htonl(resp->f_rtmax);
774     		*p++ = htonl(resp->f_rtpref);
775     		*p++ = htonl(resp->f_rtmult);
776     		*p++ = htonl(resp->f_wtmax);
777     		*p++ = htonl(resp->f_wtpref);
778     		*p++ = htonl(resp->f_wtmult);
779     		*p++ = htonl(resp->f_dtpref);
780     		p = xdr_encode_hyper(p, resp->f_maxfilesize);
781     		*p++ = xdr_one;
782     		*p++ = xdr_zero;
783     		*p++ = htonl(resp->f_properties);
784     	}
785     
786     	return xdr_ressize_check(rqstp, p);
787     }
788     
789     /* PATHCONF */
790     int
791     nfs3svc_encode_pathconfres(struct svc_rqst *rqstp, u32 *p,
792     					struct nfsd3_pathconfres *resp)
793     {
794     	*p++ = xdr_zero;	/* no post_op_attr */
795     
796     	if (resp->status == 0) {
797     		*p++ = htonl(resp->p_link_max);
798     		*p++ = htonl(resp->p_name_max);
799     		*p++ = htonl(resp->p_no_trunc);
800     		*p++ = htonl(resp->p_chown_restricted);
801     		*p++ = htonl(resp->p_case_insensitive);
802     		*p++ = htonl(resp->p_case_preserving);
803     	}
804     
805     	return xdr_ressize_check(rqstp, p);
806     }
807     
808     /* COMMIT */
809     int
810     nfs3svc_encode_commitres(struct svc_rqst *rqstp, u32 *p,
811     					struct nfsd3_commitres *resp)
812     {
813     	p = encode_wcc_data(rqstp, p, &resp->fh);
814     	/* Write verifier */
815     	if (resp->status == 0) {
816     		*p++ = htonl(nfssvc_boot.tv_sec);
817     		*p++ = htonl(nfssvc_boot.tv_usec);
818     	}
819     	return xdr_ressize_check(rqstp, p);
820     }
821     
822     /*
823      * XDR release functions
824      */
825     int
826     nfs3svc_release_fhandle(struct svc_rqst *rqstp, u32 *p,
827     					struct nfsd3_attrstat *resp)
828     {
829     	fh_put(&resp->fh);
830     	return 1;
831     }
832     
833     int
834     nfs3svc_release_fhandle2(struct svc_rqst *rqstp, u32 *p,
835     					struct nfsd3_fhandle_pair *resp)
836     {
837     	fh_put(&resp->fh1);
838     	fh_put(&resp->fh2);
839     	return 1;
840     }
841