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