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