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