added a lot of printk output to ease writing of emulator
[linux-2.4.21-pre4.git] / 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         unsigned 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(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 svc_fh *fhp)
158 {
159         struct inode    *inode = fhp->fh_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         if (rqstp->rq_reffh->fh_version == 1
179             && rqstp->rq_reffh->fh_fsid_type == 1
180             && (fhp->fh_export->ex_flags & NFSEXP_FSID))
181                 p = xdr_encode_hyper(p, (u64) fhp->fh_export->ex_fsid);
182         else
183                 p = xdr_encode_hyper(p, (u64) inode->i_dev);
184         p = xdr_encode_hyper(p, (u64) inode->i_ino);
185         p = encode_time3(p, inode->i_atime);
186         p = encode_time3(p, lease_get_mtime(inode));
187         p = encode_time3(p, inode->i_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++ = htonl((u32) MAJOR(fhp->fh_post_rdev));
212         *p++ = htonl((u32) MINOR(fhp->fh_post_rdev));
213         if (rqstp->rq_reffh->fh_version == 1
214             && rqstp->rq_reffh->fh_fsid_type == 1
215             && (fhp->fh_export->ex_flags & NFSEXP_FSID))
216                 p = xdr_encode_hyper(p, (u64) fhp->fh_export->ex_fsid);
217         else
218                 p = xdr_encode_hyper(p, (u64) inode->i_dev);
219         p = xdr_encode_hyper(p, (u64) inode->i_ino);
220         p = encode_time3(p, fhp->fh_post_atime);
221         p = encode_time3(p, fhp->fh_post_mtime);
222         p = encode_time3(p, fhp->fh_post_ctime);
223
224         return p;
225 }
226
227 /*
228  * Encode post-operation attributes.
229  * The inode may be NULL if the call failed because of a stale file
230  * handle. In this case, no attributes are returned.
231  */
232 static u32 *
233 encode_post_op_attr(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp)
234 {
235         struct dentry *dentry = fhp->fh_dentry;
236         if (dentry && dentry->d_inode != NULL) {
237                 *p++ = xdr_one;         /* attributes follow */
238                 return encode_fattr3(rqstp, p, fhp);
239         }
240         *p++ = xdr_zero;
241         return p;
242 }
243
244 /*
245  * Enocde weak cache consistency data
246  */
247 static u32 *
248 encode_wcc_data(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp)
249 {
250         struct dentry   *dentry = fhp->fh_dentry;
251
252         if (dentry && dentry->d_inode && fhp->fh_post_saved) {
253                 if (fhp->fh_pre_saved) {
254                         *p++ = xdr_one;
255                         p = xdr_encode_hyper(p, (u64) fhp->fh_pre_size);
256                         p = encode_time3(p, fhp->fh_pre_mtime);
257                         p = encode_time3(p, fhp->fh_pre_ctime);
258                 } else {
259                         *p++ = xdr_zero;
260                 }
261                 return encode_saved_post_attr(rqstp, p, fhp);
262         }
263         /* no pre- or post-attrs */
264         *p++ = xdr_zero;
265         return encode_post_op_attr(rqstp, p, fhp);
266 }
267
268 /*
269  * Check buffer bounds after decoding arguments
270  */
271 static inline int
272 xdr_argsize_check(struct svc_rqst *rqstp, u32 *p)
273 {
274         struct svc_buf  *buf = &rqstp->rq_argbuf;
275
276         return p - buf->base <= buf->buflen;
277 }
278
279 static inline int
280 xdr_ressize_check(struct svc_rqst *rqstp, u32 *p)
281 {
282         struct svc_buf  *buf = &rqstp->rq_resbuf;
283
284         buf->len = p - buf->base;
285         dprintk("nfsd: ressize_check p %p base %p len %d\n",
286                         p, buf->base, buf->buflen);
287         return (buf->len <= buf->buflen);
288 }
289
290 /*
291  * XDR decode functions
292  */
293 int
294 nfs3svc_decode_fhandle(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp)
295 {
296         if (!(p = decode_fh(p, fhp)))
297                 return 0;
298         return xdr_argsize_check(rqstp, p);
299 }
300
301 int
302 nfs3svc_decode_sattrargs(struct svc_rqst *rqstp, u32 *p,
303                                         struct nfsd3_sattrargs *args)
304 {
305         if (!(p = decode_fh(p, &args->fh))
306          || !(p = decode_sattr3(p, &args->attrs)))
307                 return 0;
308
309         if ((args->check_guard = ntohl(*p++)) != 0)
310                 p = decode_time3(p, &args->guardtime);
311
312         return xdr_argsize_check(rqstp, p);
313 }
314
315 int
316 nfs3svc_decode_diropargs(struct svc_rqst *rqstp, u32 *p,
317                                         struct nfsd3_diropargs *args)
318 {
319         if (!(p = decode_fh(p, &args->fh))
320          || !(p = decode_filename(p, &args->name, &args->len)))
321                 return 0;
322
323         return xdr_argsize_check(rqstp, p);
324 }
325
326 int
327 nfs3svc_decode_accessargs(struct svc_rqst *rqstp, u32 *p,
328                                         struct nfsd3_accessargs *args)
329 {
330         if (!(p = decode_fh(p, &args->fh)))
331                 return 0;
332         args->access = ntohl(*p++);
333
334         return xdr_argsize_check(rqstp, p);
335 }
336
337 int
338 nfs3svc_decode_readargs(struct svc_rqst *rqstp, u32 *p,
339                                         struct nfsd3_readargs *args)
340 {
341         if (!(p = decode_fh(p, &args->fh))
342          || !(p = xdr_decode_hyper(p, &args->offset)))
343                 return 0;
344
345         args->count = ntohl(*p++);
346         return xdr_argsize_check(rqstp, p);
347 }
348
349 int
350 nfs3svc_decode_writeargs(struct svc_rqst *rqstp, u32 *p,
351                                         struct nfsd3_writeargs *args)
352 {
353         if (!(p = decode_fh(p, &args->fh))
354          || !(p = xdr_decode_hyper(p, &args->offset)))
355                 return 0;
356
357         args->count = ntohl(*p++);
358         args->stable = ntohl(*p++);
359         args->len = ntohl(*p++);
360         args->data = (char *) p;
361         p += XDR_QUADLEN(args->len);
362
363         return xdr_argsize_check(rqstp, p);
364 }
365
366 int
367 nfs3svc_decode_createargs(struct svc_rqst *rqstp, u32 *p,
368                                         struct nfsd3_createargs *args)
369 {
370         if (!(p = decode_fh(p, &args->fh))
371          || !(p = decode_filename(p, &args->name, &args->len)))
372                 return 0;
373
374         switch (args->createmode = ntohl(*p++)) {
375         case NFS3_CREATE_UNCHECKED:
376         case NFS3_CREATE_GUARDED:
377                 if (!(p = decode_sattr3(p, &args->attrs)))
378                         return 0;
379                 break;
380         case NFS3_CREATE_EXCLUSIVE:
381                 args->verf = p;
382                 p += 2;
383                 break;
384         default:
385                 return 0;
386         }
387
388         return xdr_argsize_check(rqstp, p);
389 }
390 int
391 nfs3svc_decode_mkdirargs(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          || !(p = decode_sattr3(p, &args->attrs)))
397                 return 0;
398
399         return xdr_argsize_check(rqstp, p);
400 }
401
402 int
403 nfs3svc_decode_symlinkargs(struct svc_rqst *rqstp, u32 *p,
404                                         struct nfsd3_symlinkargs *args)
405 {
406         if (!(p = decode_fh(p, &args->ffh))
407          || !(p = decode_filename(p, &args->fname, &args->flen))
408          || !(p = decode_sattr3(p, &args->attrs))
409          || !(p = decode_pathname(p, &args->tname, &args->tlen)))
410                 return 0;
411
412         return xdr_argsize_check(rqstp, p);
413 }
414
415 int
416 nfs3svc_decode_mknodargs(struct svc_rqst *rqstp, u32 *p,
417                                         struct nfsd3_mknodargs *args)
418 {
419         if (!(p = decode_fh(p, &args->fh))
420          || !(p = decode_filename(p, &args->name, &args->len)))
421                 return 0;
422
423         args->ftype = ntohl(*p++);
424
425         if (args->ftype == NF3BLK  || args->ftype == NF3CHR
426          || args->ftype == NF3SOCK || args->ftype == NF3FIFO) {
427                 if (!(p = decode_sattr3(p, &args->attrs)))
428                         return 0;
429         }
430
431         if (args->ftype == NF3BLK || args->ftype == NF3CHR) {
432                 args->major = ntohl(*p++);
433                 args->minor = ntohl(*p++);
434         }
435
436         return xdr_argsize_check(rqstp, p);
437 }
438
439 int
440 nfs3svc_decode_renameargs(struct svc_rqst *rqstp, u32 *p,
441                                         struct nfsd3_renameargs *args)
442 {
443         if (!(p = decode_fh(p, &args->ffh))
444          || !(p = decode_filename(p, &args->fname, &args->flen))
445          || !(p = decode_fh(p, &args->tfh))
446          || !(p = decode_filename(p, &args->tname, &args->tlen)))
447                 return 0;
448
449         return xdr_argsize_check(rqstp, p);
450 }
451
452 int
453 nfs3svc_decode_linkargs(struct svc_rqst *rqstp, u32 *p,
454                                         struct nfsd3_linkargs *args)
455 {
456         if (!(p = decode_fh(p, &args->ffh))
457          || !(p = decode_fh(p, &args->tfh))
458          || !(p = decode_filename(p, &args->tname, &args->tlen)))
459                 return 0;
460
461         return xdr_argsize_check(rqstp, p);
462 }
463
464 int
465 nfs3svc_decode_readdirargs(struct svc_rqst *rqstp, u32 *p,
466                                         struct nfsd3_readdirargs *args)
467 {
468         if (!(p = decode_fh(p, &args->fh)))
469                 return 0;
470         p = xdr_decode_hyper(p, &args->cookie);
471         args->verf   = p; p += 2;
472         args->dircount = ~0;
473         args->count  = ntohl(*p++);
474
475         return xdr_argsize_check(rqstp, p);
476 }
477
478 int
479 nfs3svc_decode_readdirplusargs(struct svc_rqst *rqstp, u32 *p,
480                                         struct nfsd3_readdirargs *args)
481 {
482         if (!(p = decode_fh(p, &args->fh)))
483                 return 0;
484         p = xdr_decode_hyper(p, &args->cookie);
485         args->verf     = p; p += 2;
486         args->dircount = ntohl(*p++);
487         args->count    = ntohl(*p++);
488
489         return xdr_argsize_check(rqstp, p);
490 }
491
492 int
493 nfs3svc_decode_commitargs(struct svc_rqst *rqstp, u32 *p,
494                                         struct nfsd3_commitargs *args)
495 {
496         if (!(p = decode_fh(p, &args->fh)))
497                 return 0;
498         p = xdr_decode_hyper(p, &args->offset);
499         args->count = ntohl(*p++);
500
501         return xdr_argsize_check(rqstp, p);
502 }
503
504 /*
505  * XDR encode functions
506  */
507 /*
508  * There must be an encoding function for void results so svc_process
509  * will work properly.
510  */
511 int
512 nfs3svc_encode_voidres(struct svc_rqst *rqstp, u32 *p, void *dummy)
513 {
514         return xdr_ressize_check(rqstp, p);
515 }
516
517 /* GETATTR */
518 int
519 nfs3svc_encode_attrstat(struct svc_rqst *rqstp, u32 *p,
520                                         struct nfsd3_attrstat *resp)
521 {
522         if (resp->status == 0)
523                 p = encode_fattr3(rqstp, p, &resp->fh);
524         return xdr_ressize_check(rqstp, p);
525 }
526
527 /* SETATTR, REMOVE, RMDIR */
528 int
529 nfs3svc_encode_wccstat(struct svc_rqst *rqstp, u32 *p,
530                                         struct nfsd3_attrstat *resp)
531 {
532         p = encode_wcc_data(rqstp, p, &resp->fh);
533         return xdr_ressize_check(rqstp, p);
534 }
535
536 /* LOOKUP */
537 int
538 nfs3svc_encode_diropres(struct svc_rqst *rqstp, u32 *p,
539                                         struct nfsd3_diropres *resp)
540 {
541         if (resp->status == 0) {
542                 p = encode_fh(p, &resp->fh);
543                 p = encode_post_op_attr(rqstp, p, &resp->fh);
544         }
545         p = encode_post_op_attr(rqstp, p, &resp->dirfh);
546         return xdr_ressize_check(rqstp, p);
547 }
548
549 /* ACCESS */
550 int
551 nfs3svc_encode_accessres(struct svc_rqst *rqstp, u32 *p,
552                                         struct nfsd3_accessres *resp)
553 {
554         p = encode_post_op_attr(rqstp, p, &resp->fh);
555         if (resp->status == 0)
556                 *p++ = htonl(resp->access);
557         return xdr_ressize_check(rqstp, p);
558 }
559
560 /* READLINK */
561 int
562 nfs3svc_encode_readlinkres(struct svc_rqst *rqstp, u32 *p,
563                                         struct nfsd3_readlinkres *resp)
564 {
565         p = encode_post_op_attr(rqstp, p, &resp->fh);
566         if (resp->status == 0) {
567                 *p++ = htonl(resp->len);
568                 p += XDR_QUADLEN(resp->len);
569         }
570         return xdr_ressize_check(rqstp, p);
571 }
572
573 /* READ */
574 int
575 nfs3svc_encode_readres(struct svc_rqst *rqstp, u32 *p,
576                                         struct nfsd3_readres *resp)
577 {
578         p = encode_post_op_attr(rqstp, p, &resp->fh);
579         if (resp->status == 0) {
580                 *p++ = htonl(resp->count);
581                 *p++ = htonl(resp->eof);
582                 *p++ = htonl(resp->count);      /* xdr opaque count */
583                 p += XDR_QUADLEN(resp->count);
584         }
585         return xdr_ressize_check(rqstp, p);
586 }
587
588 /* WRITE */
589 int
590 nfs3svc_encode_writeres(struct svc_rqst *rqstp, u32 *p,
591                                         struct nfsd3_writeres *resp)
592 {
593         p = encode_wcc_data(rqstp, p, &resp->fh);
594         if (resp->status == 0) {
595                 *p++ = htonl(resp->count);
596                 *p++ = htonl(resp->committed);
597                 *p++ = htonl(nfssvc_boot.tv_sec);
598                 *p++ = htonl(nfssvc_boot.tv_usec);
599         }
600         return xdr_ressize_check(rqstp, p);
601 }
602
603 /* CREATE, MKDIR, SYMLINK, MKNOD */
604 int
605 nfs3svc_encode_createres(struct svc_rqst *rqstp, u32 *p,
606                                         struct nfsd3_diropres *resp)
607 {
608         if (resp->status == 0) {
609                 *p++ = xdr_one;
610                 p = encode_fh(p, &resp->fh);
611                 p = encode_post_op_attr(rqstp, p, &resp->fh);
612         }
613         p = encode_wcc_data(rqstp, p, &resp->dirfh);
614         return xdr_ressize_check(rqstp, p);
615 }
616
617 /* RENAME */
618 int
619 nfs3svc_encode_renameres(struct svc_rqst *rqstp, u32 *p,
620                                         struct nfsd3_renameres *resp)
621 {
622         p = encode_wcc_data(rqstp, p, &resp->ffh);
623         p = encode_wcc_data(rqstp, p, &resp->tfh);
624         return xdr_ressize_check(rqstp, p);
625 }
626
627 /* LINK */
628 int
629 nfs3svc_encode_linkres(struct svc_rqst *rqstp, u32 *p,
630                                         struct nfsd3_linkres *resp)
631 {
632         p = encode_post_op_attr(rqstp, p, &resp->fh);
633         p = encode_wcc_data(rqstp, p, &resp->tfh);
634         return xdr_ressize_check(rqstp, p);
635 }
636
637 /* READDIR */
638 int
639 nfs3svc_encode_readdirres(struct svc_rqst *rqstp, u32 *p,
640                                         struct nfsd3_readdirres *resp)
641 {
642         p = encode_post_op_attr(rqstp, p, &resp->fh);
643         if (resp->status == 0) {
644                 /* stupid readdir cookie */
645                 memcpy(p, resp->verf, 8); p += 2;
646                 p += XDR_QUADLEN(resp->count);
647         }
648
649         return xdr_ressize_check(rqstp, p);
650 }
651
652 /*
653  * Encode a directory entry. This one works for both normal readdir
654  * and readdirplus.
655  * The normal readdir reply requires 2 (fileid) + 1 (stringlen)
656  * + string + 2 (cookie) + 1 (next) words, i.e. 6 + strlen.
657  * 
658  * The readdirplus baggage is 1+21 words for post_op_attr, plus the
659  * file handle.
660  */
661
662 #define NFS3_ENTRY_BAGGAGE      (2 + 1 + 2 + 1)
663 #define NFS3_ENTRYPLUS_BAGGAGE  (1 + 21 + 1 + (NFS3_FHSIZE >> 2))
664 static int
665 encode_entry(struct readdir_cd *cd, const char *name,
666              int namlen, off_t offset, ino_t ino, unsigned int d_type, int plus)
667 {
668         u32             *p = cd->buffer;
669         int             buflen, slen, elen;
670
671         if (cd->offset)
672                 xdr_encode_hyper(cd->offset, (u64) offset);
673
674         /* nfsd_readdir calls us with name == 0 when it wants us to
675          * set the last offset entry. */
676         if (name == 0)
677                 return 0;
678
679         /*
680         dprintk("encode_entry(%.*s @%ld%s)\n",
681                 namlen, name, (long) offset, plus? " plus" : "");
682          */
683
684         /* truncate filename if too long */
685         if (namlen > NFS3_MAXNAMLEN)
686                 namlen = NFS3_MAXNAMLEN;
687
688         slen = XDR_QUADLEN(namlen);
689         elen = slen + NFS3_ENTRY_BAGGAGE
690                 + (plus? NFS3_ENTRYPLUS_BAGGAGE : 0);
691         if ((buflen = cd->buflen - elen) < 0) {
692                 cd->eob = 1;
693                 return -EINVAL;
694         }
695         *p++ = xdr_one;                          /* mark entry present */
696         p    = xdr_encode_hyper(p, ino);         /* file id */
697         p    = xdr_encode_array(p, name, namlen);/* name length & name */
698
699         cd->offset = p;                 /* remember pointer */
700         p = xdr_encode_hyper(p, NFS_OFFSET_MAX);        /* offset of next entry */
701
702         /* throw in readdirplus baggage */
703         if (plus) {
704                 struct svc_fh   fh;
705                 struct svc_export       *exp;
706                 struct dentry           *dparent, *dchild;
707
708                 dparent = cd->dirfh->fh_dentry;
709                 exp  = cd->dirfh->fh_export;
710
711                 fh_init(&fh, NFS3_FHSIZE);
712                 if (isdotent(name, namlen)) {
713                         dchild = dparent;
714                         if (namlen == 2)
715                                 dchild = dchild->d_parent;
716                         dchild = dget(dchild);
717                 } else
718                         dchild = lookup_one_len(name, dparent,namlen);
719                 if (IS_ERR(dchild))
720                         goto noexec;
721                 if (fh_compose(&fh, exp, dchild, cd->dirfh) != 0 || !dchild->d_inode)
722                         goto noexec;
723                 p = encode_post_op_attr(cd->rqstp, p, &fh);
724                 *p++ = xdr_one; /* yes, a file handle follows */
725                 p = encode_fh(p, &fh);
726                 fh_put(&fh);
727         }
728
729 out:
730         cd->buflen = buflen;
731         cd->buffer = p;
732         return 0;
733
734 noexec:
735         *p++ = 0;
736         *p++ = 0;
737         goto out;
738 }
739
740 int
741 nfs3svc_encode_entry(struct readdir_cd *cd, const char *name,
742                      int namlen, loff_t offset, ino_t ino, unsigned int d_type)
743 {
744         return encode_entry(cd, name, namlen, offset, ino, d_type, 0);
745 }
746
747 int
748 nfs3svc_encode_entry_plus(struct readdir_cd *cd, const char *name,
749                           int namlen, loff_t offset, ino_t ino, unsigned int d_type)
750 {
751         return encode_entry(cd, name, namlen, offset, ino, d_type, 1);
752 }
753
754 /* FSSTAT */
755 int
756 nfs3svc_encode_fsstatres(struct svc_rqst *rqstp, u32 *p,
757                                         struct nfsd3_fsstatres *resp)
758 {
759         struct statfs   *s = &resp->stats;
760         u64             bs = s->f_bsize;
761
762         *p++ = xdr_zero;        /* no post_op_attr */
763
764         if (resp->status == 0) {
765                 p = xdr_encode_hyper(p, bs * s->f_blocks);      /* total bytes */
766                 p = xdr_encode_hyper(p, bs * s->f_bfree);       /* free bytes */
767                 p = xdr_encode_hyper(p, bs * s->f_bavail);      /* user available bytes */
768                 p = xdr_encode_hyper(p, s->f_files);    /* total inodes */
769                 p = xdr_encode_hyper(p, s->f_ffree);    /* free inodes */
770                 p = xdr_encode_hyper(p, s->f_ffree);    /* user available inodes */
771                 *p++ = htonl(resp->invarsec);   /* mean unchanged time */
772         }
773         return xdr_ressize_check(rqstp, p);
774 }
775
776 /* FSINFO */
777 int
778 nfs3svc_encode_fsinfores(struct svc_rqst *rqstp, u32 *p,
779                                         struct nfsd3_fsinfores *resp)
780 {
781         *p++ = xdr_zero;        /* no post_op_attr */
782
783         if (resp->status == 0) {
784                 *p++ = htonl(resp->f_rtmax);
785                 *p++ = htonl(resp->f_rtpref);
786                 *p++ = htonl(resp->f_rtmult);
787                 *p++ = htonl(resp->f_wtmax);
788                 *p++ = htonl(resp->f_wtpref);
789                 *p++ = htonl(resp->f_wtmult);
790                 *p++ = htonl(resp->f_dtpref);
791                 p = xdr_encode_hyper(p, resp->f_maxfilesize);
792                 *p++ = xdr_one;
793                 *p++ = xdr_zero;
794                 *p++ = htonl(resp->f_properties);
795         }
796
797         return xdr_ressize_check(rqstp, p);
798 }
799
800 /* PATHCONF */
801 int
802 nfs3svc_encode_pathconfres(struct svc_rqst *rqstp, u32 *p,
803                                         struct nfsd3_pathconfres *resp)
804 {
805         *p++ = xdr_zero;        /* no post_op_attr */
806
807         if (resp->status == 0) {
808                 *p++ = htonl(resp->p_link_max);
809                 *p++ = htonl(resp->p_name_max);
810                 *p++ = htonl(resp->p_no_trunc);
811                 *p++ = htonl(resp->p_chown_restricted);
812                 *p++ = htonl(resp->p_case_insensitive);
813                 *p++ = htonl(resp->p_case_preserving);
814         }
815
816         return xdr_ressize_check(rqstp, p);
817 }
818
819 /* COMMIT */
820 int
821 nfs3svc_encode_commitres(struct svc_rqst *rqstp, u32 *p,
822                                         struct nfsd3_commitres *resp)
823 {
824         p = encode_wcc_data(rqstp, p, &resp->fh);
825         /* Write verifier */
826         if (resp->status == 0) {
827                 *p++ = htonl(nfssvc_boot.tv_sec);
828                 *p++ = htonl(nfssvc_boot.tv_usec);
829         }
830         return xdr_ressize_check(rqstp, p);
831 }
832
833 /*
834  * XDR release functions
835  */
836 int
837 nfs3svc_release_fhandle(struct svc_rqst *rqstp, u32 *p,
838                                         struct nfsd3_attrstat *resp)
839 {
840         fh_put(&resp->fh);
841         return 1;
842 }
843
844 int
845 nfs3svc_release_fhandle2(struct svc_rqst *rqstp, u32 *p,
846                                         struct nfsd3_fhandle_pair *resp)
847 {
848         fh_put(&resp->fh1);
849         fh_put(&resp->fh2);
850         return 1;
851 }