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