[JFFS2] Namespace clean up
[linux-2.6] / fs / nfs / nfs3xdr.c
1 /*
2  * linux/fs/nfs/nfs3xdr.c
3  *
4  * XDR functions to encode/decode NFSv3 RPC arguments and results.
5  *
6  * Copyright (C) 1996, 1997 Olaf Kirch
7  */
8
9 #include <linux/param.h>
10 #include <linux/time.h>
11 #include <linux/mm.h>
12 #include <linux/slab.h>
13 #include <linux/utsname.h>
14 #include <linux/errno.h>
15 #include <linux/string.h>
16 #include <linux/in.h>
17 #include <linux/pagemap.h>
18 #include <linux/proc_fs.h>
19 #include <linux/kdev_t.h>
20 #include <linux/sunrpc/clnt.h>
21 #include <linux/nfs.h>
22 #include <linux/nfs3.h>
23 #include <linux/nfs_fs.h>
24 #include <linux/nfsacl.h>
25
26 #define NFSDBG_FACILITY         NFSDBG_XDR
27
28 /* Mapping from NFS error code to "errno" error code. */
29 #define errno_NFSERR_IO         EIO
30
31 extern int                      nfs_stat_to_errno(int);
32
33 /*
34  * Declare the space requirements for NFS arguments and replies as
35  * number of 32bit-words
36  */
37 #define NFS3_fhandle_sz         (1+16)
38 #define NFS3_fh_sz              (NFS3_fhandle_sz)       /* shorthand */
39 #define NFS3_sattr_sz           (15)
40 #define NFS3_filename_sz        (1+(NFS3_MAXNAMLEN>>2))
41 #define NFS3_path_sz            (1+(NFS3_MAXPATHLEN>>2))
42 #define NFS3_fattr_sz           (21)
43 #define NFS3_wcc_attr_sz                (6)
44 #define NFS3_pre_op_attr_sz     (1+NFS3_wcc_attr_sz)
45 #define NFS3_post_op_attr_sz    (1+NFS3_fattr_sz)
46 #define NFS3_wcc_data_sz                (NFS3_pre_op_attr_sz+NFS3_post_op_attr_sz)
47 #define NFS3_fsstat_sz          
48 #define NFS3_fsinfo_sz          
49 #define NFS3_pathconf_sz                
50 #define NFS3_entry_sz           (NFS3_filename_sz+3)
51
52 #define NFS3_sattrargs_sz       (NFS3_fh_sz+NFS3_sattr_sz+3)
53 #define NFS3_diropargs_sz       (NFS3_fh_sz+NFS3_filename_sz)
54 #define NFS3_accessargs_sz      (NFS3_fh_sz+1)
55 #define NFS3_readlinkargs_sz    (NFS3_fh_sz)
56 #define NFS3_readargs_sz        (NFS3_fh_sz+3)
57 #define NFS3_writeargs_sz       (NFS3_fh_sz+5)
58 #define NFS3_createargs_sz      (NFS3_diropargs_sz+NFS3_sattr_sz)
59 #define NFS3_mkdirargs_sz       (NFS3_diropargs_sz+NFS3_sattr_sz)
60 #define NFS3_symlinkargs_sz     (NFS3_diropargs_sz+NFS3_path_sz+NFS3_sattr_sz)
61 #define NFS3_mknodargs_sz       (NFS3_diropargs_sz+2+NFS3_sattr_sz)
62 #define NFS3_renameargs_sz      (NFS3_diropargs_sz+NFS3_diropargs_sz)
63 #define NFS3_linkargs_sz                (NFS3_fh_sz+NFS3_diropargs_sz)
64 #define NFS3_readdirargs_sz     (NFS3_fh_sz+2)
65 #define NFS3_commitargs_sz      (NFS3_fh_sz+3)
66
67 #define NFS3_attrstat_sz        (1+NFS3_fattr_sz)
68 #define NFS3_wccstat_sz         (1+NFS3_wcc_data_sz)
69 #define NFS3_lookupres_sz       (1+NFS3_fh_sz+(2 * NFS3_post_op_attr_sz))
70 #define NFS3_accessres_sz       (1+NFS3_post_op_attr_sz+1)
71 #define NFS3_readlinkres_sz     (1+NFS3_post_op_attr_sz+1)
72 #define NFS3_readres_sz         (1+NFS3_post_op_attr_sz+3)
73 #define NFS3_writeres_sz        (1+NFS3_wcc_data_sz+4)
74 #define NFS3_createres_sz       (1+NFS3_fh_sz+NFS3_post_op_attr_sz+NFS3_wcc_data_sz)
75 #define NFS3_renameres_sz       (1+(2 * NFS3_wcc_data_sz))
76 #define NFS3_linkres_sz         (1+NFS3_post_op_attr_sz+NFS3_wcc_data_sz)
77 #define NFS3_readdirres_sz      (1+NFS3_post_op_attr_sz+2)
78 #define NFS3_fsstatres_sz       (1+NFS3_post_op_attr_sz+13)
79 #define NFS3_fsinfores_sz       (1+NFS3_post_op_attr_sz+12)
80 #define NFS3_pathconfres_sz     (1+NFS3_post_op_attr_sz+6)
81 #define NFS3_commitres_sz       (1+NFS3_wcc_data_sz+2)
82
83 #define ACL3_getaclargs_sz      (NFS3_fh_sz+1)
84 #define ACL3_setaclargs_sz      (NFS3_fh_sz+1+2*(2+5*3))
85 #define ACL3_getaclres_sz       (1+NFS3_post_op_attr_sz+1+2*(2+5*3))
86 #define ACL3_setaclres_sz       (1+NFS3_post_op_attr_sz)
87
88 /*
89  * Map file type to S_IFMT bits
90  */
91 static struct {
92         unsigned int    mode;
93         unsigned int    nfs2type;
94 } nfs_type2fmt[] = {
95       { 0,              NFNON   },
96       { S_IFREG,        NFREG   },
97       { S_IFDIR,        NFDIR   },
98       { S_IFBLK,        NFBLK   },
99       { S_IFCHR,        NFCHR   },
100       { S_IFLNK,        NFLNK   },
101       { S_IFSOCK,       NFSOCK  },
102       { S_IFIFO,        NFFIFO  },
103       { 0,              NFBAD   }
104 };
105
106 /*
107  * Common NFS XDR functions as inlines
108  */
109 static inline u32 *
110 xdr_encode_fhandle(u32 *p, struct nfs_fh *fh)
111 {
112         return xdr_encode_array(p, fh->data, fh->size);
113 }
114
115 static inline u32 *
116 xdr_decode_fhandle(u32 *p, struct nfs_fh *fh)
117 {
118         if ((fh->size = ntohl(*p++)) <= NFS3_FHSIZE) {
119                 memcpy(fh->data, p, fh->size);
120                 return p + XDR_QUADLEN(fh->size);
121         }
122         return NULL;
123 }
124
125 /*
126  * Encode/decode time.
127  */
128 static inline u32 *
129 xdr_encode_time3(u32 *p, struct timespec *timep)
130 {
131         *p++ = htonl(timep->tv_sec);
132         *p++ = htonl(timep->tv_nsec);
133         return p;
134 }
135
136 static inline u32 *
137 xdr_decode_time3(u32 *p, struct timespec *timep)
138 {
139         timep->tv_sec = ntohl(*p++);
140         timep->tv_nsec = ntohl(*p++);
141         return p;
142 }
143
144 static u32 *
145 xdr_decode_fattr(u32 *p, struct nfs_fattr *fattr)
146 {
147         unsigned int    type, major, minor;
148         int             fmode;
149
150         type = ntohl(*p++);
151         if (type >= NF3BAD)
152                 type = NF3BAD;
153         fmode = nfs_type2fmt[type].mode;
154         fattr->type = nfs_type2fmt[type].nfs2type;
155         fattr->mode = (ntohl(*p++) & ~S_IFMT) | fmode;
156         fattr->nlink = ntohl(*p++);
157         fattr->uid = ntohl(*p++);
158         fattr->gid = ntohl(*p++);
159         p = xdr_decode_hyper(p, &fattr->size);
160         p = xdr_decode_hyper(p, &fattr->du.nfs3.used);
161
162         /* Turn remote device info into Linux-specific dev_t */
163         major = ntohl(*p++);
164         minor = ntohl(*p++);
165         fattr->rdev = MKDEV(major, minor);
166         if (MAJOR(fattr->rdev) != major || MINOR(fattr->rdev) != minor)
167                 fattr->rdev = 0;
168
169         p = xdr_decode_hyper(p, &fattr->fsid_u.nfs3);
170         p = xdr_decode_hyper(p, &fattr->fileid);
171         p = xdr_decode_time3(p, &fattr->atime);
172         p = xdr_decode_time3(p, &fattr->mtime);
173         p = xdr_decode_time3(p, &fattr->ctime);
174
175         /* Update the mode bits */
176         fattr->valid |= (NFS_ATTR_FATTR | NFS_ATTR_FATTR_V3);
177         return p;
178 }
179
180 static inline u32 *
181 xdr_encode_sattr(u32 *p, struct iattr *attr)
182 {
183         if (attr->ia_valid & ATTR_MODE) {
184                 *p++ = xdr_one;
185                 *p++ = htonl(attr->ia_mode);
186         } else {
187                 *p++ = xdr_zero;
188         }
189         if (attr->ia_valid & ATTR_UID) {
190                 *p++ = xdr_one;
191                 *p++ = htonl(attr->ia_uid);
192         } else {
193                 *p++ = xdr_zero;
194         }
195         if (attr->ia_valid & ATTR_GID) {
196                 *p++ = xdr_one;
197                 *p++ = htonl(attr->ia_gid);
198         } else {
199                 *p++ = xdr_zero;
200         }
201         if (attr->ia_valid & ATTR_SIZE) {
202                 *p++ = xdr_one;
203                 p = xdr_encode_hyper(p, (__u64) attr->ia_size);
204         } else {
205                 *p++ = xdr_zero;
206         }
207         if (attr->ia_valid & ATTR_ATIME_SET) {
208                 *p++ = xdr_two;
209                 p = xdr_encode_time3(p, &attr->ia_atime);
210         } else if (attr->ia_valid & ATTR_ATIME) {
211                 *p++ = xdr_one;
212         } else {
213                 *p++ = xdr_zero;
214         }
215         if (attr->ia_valid & ATTR_MTIME_SET) {
216                 *p++ = xdr_two;
217                 p = xdr_encode_time3(p, &attr->ia_mtime);
218         } else if (attr->ia_valid & ATTR_MTIME) {
219                 *p++ = xdr_one;
220         } else {
221                 *p++ = xdr_zero;
222         }
223         return p;
224 }
225
226 static inline u32 *
227 xdr_decode_wcc_attr(u32 *p, struct nfs_fattr *fattr)
228 {
229         p = xdr_decode_hyper(p, &fattr->pre_size);
230         p = xdr_decode_time3(p, &fattr->pre_mtime);
231         p = xdr_decode_time3(p, &fattr->pre_ctime);
232         fattr->valid |= NFS_ATTR_WCC;
233         return p;
234 }
235
236 static inline u32 *
237 xdr_decode_post_op_attr(u32 *p, struct nfs_fattr *fattr)
238 {
239         if (*p++)
240                 p = xdr_decode_fattr(p, fattr);
241         return p;
242 }
243
244 static inline u32 *
245 xdr_decode_pre_op_attr(u32 *p, struct nfs_fattr *fattr)
246 {
247         if (*p++)
248                 return xdr_decode_wcc_attr(p, fattr);
249         return p;
250 }
251
252
253 static inline u32 *
254 xdr_decode_wcc_data(u32 *p, struct nfs_fattr *fattr)
255 {
256         p = xdr_decode_pre_op_attr(p, fattr);
257         return xdr_decode_post_op_attr(p, fattr);
258 }
259
260 /*
261  * NFS encode functions
262  */
263
264 /*
265  * Encode file handle argument
266  */
267 static int
268 nfs3_xdr_fhandle(struct rpc_rqst *req, u32 *p, struct nfs_fh *fh)
269 {
270         p = xdr_encode_fhandle(p, fh);
271         req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
272         return 0;
273 }
274
275 /*
276  * Encode SETATTR arguments
277  */
278 static int
279 nfs3_xdr_sattrargs(struct rpc_rqst *req, u32 *p, struct nfs3_sattrargs *args)
280 {
281         p = xdr_encode_fhandle(p, args->fh);
282         p = xdr_encode_sattr(p, args->sattr);
283         *p++ = htonl(args->guard);
284         if (args->guard)
285                 p = xdr_encode_time3(p, &args->guardtime);
286         req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
287         return 0;
288 }
289
290 /*
291  * Encode directory ops argument
292  */
293 static int
294 nfs3_xdr_diropargs(struct rpc_rqst *req, u32 *p, struct nfs3_diropargs *args)
295 {
296         p = xdr_encode_fhandle(p, args->fh);
297         p = xdr_encode_array(p, args->name, args->len);
298         req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
299         return 0;
300 }
301
302 /*
303  * Encode access() argument
304  */
305 static int
306 nfs3_xdr_accessargs(struct rpc_rqst *req, u32 *p, struct nfs3_accessargs *args)
307 {
308         p = xdr_encode_fhandle(p, args->fh);
309         *p++ = htonl(args->access);
310         req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
311         return 0;
312 }
313
314 /*
315  * Arguments to a READ call. Since we read data directly into the page
316  * cache, we also set up the reply iovec here so that iov[1] points
317  * exactly to the page we want to fetch.
318  */
319 static int
320 nfs3_xdr_readargs(struct rpc_rqst *req, u32 *p, struct nfs_readargs *args)
321 {
322         struct rpc_auth *auth = req->rq_task->tk_auth;
323         unsigned int replen;
324         u32 count = args->count;
325
326         p = xdr_encode_fhandle(p, args->fh);
327         p = xdr_encode_hyper(p, args->offset);
328         *p++ = htonl(count);
329         req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
330
331         /* Inline the page array */
332         replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS3_readres_sz) << 2;
333         xdr_inline_pages(&req->rq_rcv_buf, replen,
334                          args->pages, args->pgbase, count);
335         return 0;
336 }
337
338 /*
339  * Write arguments. Splice the buffer to be written into the iovec.
340  */
341 static int
342 nfs3_xdr_writeargs(struct rpc_rqst *req, u32 *p, struct nfs_writeargs *args)
343 {
344         struct xdr_buf *sndbuf = &req->rq_snd_buf;
345         u32 count = args->count;
346
347         p = xdr_encode_fhandle(p, args->fh);
348         p = xdr_encode_hyper(p, args->offset);
349         *p++ = htonl(count);
350         *p++ = htonl(args->stable);
351         *p++ = htonl(count);
352         sndbuf->len = xdr_adjust_iovec(sndbuf->head, p);
353
354         /* Copy the page array */
355         xdr_encode_pages(sndbuf, args->pages, args->pgbase, count);
356         return 0;
357 }
358
359 /*
360  * Encode CREATE arguments
361  */
362 static int
363 nfs3_xdr_createargs(struct rpc_rqst *req, u32 *p, struct nfs3_createargs *args)
364 {
365         p = xdr_encode_fhandle(p, args->fh);
366         p = xdr_encode_array(p, args->name, args->len);
367
368         *p++ = htonl(args->createmode);
369         if (args->createmode == NFS3_CREATE_EXCLUSIVE) {
370                 *p++ = args->verifier[0];
371                 *p++ = args->verifier[1];
372         } else
373                 p = xdr_encode_sattr(p, args->sattr);
374
375         req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
376         return 0;
377 }
378
379 /*
380  * Encode MKDIR arguments
381  */
382 static int
383 nfs3_xdr_mkdirargs(struct rpc_rqst *req, u32 *p, struct nfs3_mkdirargs *args)
384 {
385         p = xdr_encode_fhandle(p, args->fh);
386         p = xdr_encode_array(p, args->name, args->len);
387         p = xdr_encode_sattr(p, args->sattr);
388         req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
389         return 0;
390 }
391
392 /*
393  * Encode SYMLINK arguments
394  */
395 static int
396 nfs3_xdr_symlinkargs(struct rpc_rqst *req, u32 *p, struct nfs3_symlinkargs *args)
397 {
398         p = xdr_encode_fhandle(p, args->fromfh);
399         p = xdr_encode_array(p, args->fromname, args->fromlen);
400         p = xdr_encode_sattr(p, args->sattr);
401         p = xdr_encode_array(p, args->topath, args->tolen);
402         req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
403         return 0;
404 }
405
406 /*
407  * Encode MKNOD arguments
408  */
409 static int
410 nfs3_xdr_mknodargs(struct rpc_rqst *req, u32 *p, struct nfs3_mknodargs *args)
411 {
412         p = xdr_encode_fhandle(p, args->fh);
413         p = xdr_encode_array(p, args->name, args->len);
414         *p++ = htonl(args->type);
415         p = xdr_encode_sattr(p, args->sattr);
416         if (args->type == NF3CHR || args->type == NF3BLK) {
417                 *p++ = htonl(MAJOR(args->rdev));
418                 *p++ = htonl(MINOR(args->rdev));
419         }
420
421         req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
422         return 0;
423 }
424
425 /*
426  * Encode RENAME arguments
427  */
428 static int
429 nfs3_xdr_renameargs(struct rpc_rqst *req, u32 *p, struct nfs3_renameargs *args)
430 {
431         p = xdr_encode_fhandle(p, args->fromfh);
432         p = xdr_encode_array(p, args->fromname, args->fromlen);
433         p = xdr_encode_fhandle(p, args->tofh);
434         p = xdr_encode_array(p, args->toname, args->tolen);
435         req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
436         return 0;
437 }
438
439 /*
440  * Encode LINK arguments
441  */
442 static int
443 nfs3_xdr_linkargs(struct rpc_rqst *req, u32 *p, struct nfs3_linkargs *args)
444 {
445         p = xdr_encode_fhandle(p, args->fromfh);
446         p = xdr_encode_fhandle(p, args->tofh);
447         p = xdr_encode_array(p, args->toname, args->tolen);
448         req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
449         return 0;
450 }
451
452 /*
453  * Encode arguments to readdir call
454  */
455 static int
456 nfs3_xdr_readdirargs(struct rpc_rqst *req, u32 *p, struct nfs3_readdirargs *args)
457 {
458         struct rpc_auth *auth = req->rq_task->tk_auth;
459         unsigned int replen;
460         u32 count = args->count;
461
462         p = xdr_encode_fhandle(p, args->fh);
463         p = xdr_encode_hyper(p, args->cookie);
464         *p++ = args->verf[0];
465         *p++ = args->verf[1];
466         if (args->plus) {
467                 /* readdirplus: need dircount + buffer size.
468                  * We just make sure we make dircount big enough */
469                 *p++ = htonl(count >> 3);
470         }
471         *p++ = htonl(count);
472         req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
473
474         /* Inline the page array */
475         replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS3_readdirres_sz) << 2;
476         xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, 0, count);
477         return 0;
478 }
479
480 /*
481  * Decode the result of a readdir call.
482  * We just check for syntactical correctness.
483  */
484 static int
485 nfs3_xdr_readdirres(struct rpc_rqst *req, u32 *p, struct nfs3_readdirres *res)
486 {
487         struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
488         struct kvec *iov = rcvbuf->head;
489         struct page **page;
490         int hdrlen, recvd;
491         int status, nr;
492         unsigned int len, pglen;
493         u32 *entry, *end, *kaddr;
494
495         status = ntohl(*p++);
496         /* Decode post_op_attrs */
497         p = xdr_decode_post_op_attr(p, res->dir_attr);
498         if (status)
499                 return -nfs_stat_to_errno(status);
500         /* Decode verifier cookie */
501         if (res->verf) {
502                 res->verf[0] = *p++;
503                 res->verf[1] = *p++;
504         } else {
505                 p += 2;
506         }
507
508         hdrlen = (u8 *) p - (u8 *) iov->iov_base;
509         if (iov->iov_len < hdrlen) {
510                 printk(KERN_WARNING "NFS: READDIR reply header overflowed:"
511                                 "length %d > %Zu\n", hdrlen, iov->iov_len);
512                 return -errno_NFSERR_IO;
513         } else if (iov->iov_len != hdrlen) {
514                 dprintk("NFS: READDIR header is short. iovec will be shifted.\n");
515                 xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen);
516         }
517
518         pglen = rcvbuf->page_len;
519         recvd = rcvbuf->len - hdrlen;
520         if (pglen > recvd)
521                 pglen = recvd;
522         page = rcvbuf->pages;
523         kaddr = p = (u32 *)kmap_atomic(*page, KM_USER0);
524         end = (u32 *)((char *)p + pglen);
525         entry = p;
526         for (nr = 0; *p++; nr++) {
527                 if (p + 3 > end)
528                         goto short_pkt;
529                 p += 2;                         /* inode # */
530                 len = ntohl(*p++);              /* string length */
531                 p += XDR_QUADLEN(len) + 2;      /* name + cookie */
532                 if (len > NFS3_MAXNAMLEN) {
533                         printk(KERN_WARNING "NFS: giant filename in readdir (len %x)!\n",
534                                                 len);
535                         goto err_unmap;
536                 }
537
538                 if (res->plus) {
539                         /* post_op_attr */
540                         if (p + 2 > end)
541                                 goto short_pkt;
542                         if (*p++) {
543                                 p += 21;
544                                 if (p + 1 > end)
545                                         goto short_pkt;
546                         }
547                         /* post_op_fh3 */
548                         if (*p++) {
549                                 if (p + 1 > end)
550                                         goto short_pkt;
551                                 len = ntohl(*p++);
552                                 if (len > NFS3_FHSIZE) {
553                                         printk(KERN_WARNING "NFS: giant filehandle in "
554                                                 "readdir (len %x)!\n", len);
555                                         goto err_unmap;
556                                 }
557                                 p += XDR_QUADLEN(len);
558                         }
559                 }
560
561                 if (p + 2 > end)
562                         goto short_pkt;
563                 entry = p;
564         }
565         if (!nr && (entry[0] != 0 || entry[1] == 0))
566                 goto short_pkt;
567  out:
568         kunmap_atomic(kaddr, KM_USER0);
569         return nr;
570  short_pkt:
571         entry[0] = entry[1] = 0;
572         /* truncate listing ? */
573         if (!nr) {
574                 printk(KERN_NOTICE "NFS: readdir reply truncated!\n");
575                 entry[1] = 1;
576         }
577         goto out;
578 err_unmap:
579         nr = -errno_NFSERR_IO;
580         goto out;
581 }
582
583 u32 *
584 nfs3_decode_dirent(u32 *p, struct nfs_entry *entry, int plus)
585 {
586         struct nfs_entry old = *entry;
587
588         if (!*p++) {
589                 if (!*p)
590                         return ERR_PTR(-EAGAIN);
591                 entry->eof = 1;
592                 return ERR_PTR(-EBADCOOKIE);
593         }
594
595         p = xdr_decode_hyper(p, &entry->ino);
596         entry->len  = ntohl(*p++);
597         entry->name = (const char *) p;
598         p += XDR_QUADLEN(entry->len);
599         entry->prev_cookie = entry->cookie;
600         p = xdr_decode_hyper(p, &entry->cookie);
601
602         if (plus) {
603                 entry->fattr->valid = 0;
604                 p = xdr_decode_post_op_attr(p, entry->fattr);
605                 /* In fact, a post_op_fh3: */
606                 if (*p++) {
607                         p = xdr_decode_fhandle(p, entry->fh);
608                         /* Ugh -- server reply was truncated */
609                         if (p == NULL) {
610                                 dprintk("NFS: FH truncated\n");
611                                 *entry = old;
612                                 return ERR_PTR(-EAGAIN);
613                         }
614                 } else
615                         memset((u8*)(entry->fh), 0, sizeof(*entry->fh));
616         }
617
618         entry->eof = !p[0] && p[1];
619         return p;
620 }
621
622 /*
623  * Encode COMMIT arguments
624  */
625 static int
626 nfs3_xdr_commitargs(struct rpc_rqst *req, u32 *p, struct nfs_writeargs *args)
627 {
628         p = xdr_encode_fhandle(p, args->fh);
629         p = xdr_encode_hyper(p, args->offset);
630         *p++ = htonl(args->count);
631         req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
632         return 0;
633 }
634
635 #ifdef CONFIG_NFS_V3_ACL
636 /*
637  * Encode GETACL arguments
638  */
639 static int
640 nfs3_xdr_getaclargs(struct rpc_rqst *req, u32 *p,
641                     struct nfs3_getaclargs *args)
642 {
643         struct rpc_auth *auth = req->rq_task->tk_auth;
644         unsigned int replen;
645
646         p = xdr_encode_fhandle(p, args->fh);
647         *p++ = htonl(args->mask);
648         req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
649
650         if (args->mask & (NFS_ACL | NFS_DFACL)) {
651                 /* Inline the page array */
652                 replen = (RPC_REPHDRSIZE + auth->au_rslack +
653                           ACL3_getaclres_sz) << 2;
654                 xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, 0,
655                                  NFSACL_MAXPAGES << PAGE_SHIFT);
656         }
657         return 0;
658 }
659
660 /*
661  * Encode SETACL arguments
662  */
663 static int
664 nfs3_xdr_setaclargs(struct rpc_rqst *req, u32 *p,
665                    struct nfs3_setaclargs *args)
666 {
667         struct xdr_buf *buf = &req->rq_snd_buf;
668         unsigned int base, len_in_head, len = nfsacl_size(
669                 (args->mask & NFS_ACL)   ? args->acl_access  : NULL,
670                 (args->mask & NFS_DFACL) ? args->acl_default : NULL);
671         int count, err;
672
673         p = xdr_encode_fhandle(p, NFS_FH(args->inode));
674         *p++ = htonl(args->mask);
675         base = (char *)p - (char *)buf->head->iov_base;
676         /* put as much of the acls into head as possible. */
677         len_in_head = min_t(unsigned int, buf->head->iov_len - base, len);
678         len -= len_in_head;
679         req->rq_slen = xdr_adjust_iovec(req->rq_svec, p + (len_in_head >> 2));
680
681         for (count = 0; (count << PAGE_SHIFT) < len; count++) {
682                 args->pages[count] = alloc_page(GFP_KERNEL);
683                 if (!args->pages[count]) {
684                         while (count)
685                                 __free_page(args->pages[--count]);
686                         return -ENOMEM;
687                 }
688         }
689         xdr_encode_pages(buf, args->pages, 0, len);
690
691         err = nfsacl_encode(buf, base, args->inode,
692                             (args->mask & NFS_ACL) ?
693                             args->acl_access : NULL, 1, 0);
694         if (err > 0)
695                 err = nfsacl_encode(buf, base + err, args->inode,
696                                     (args->mask & NFS_DFACL) ?
697                                     args->acl_default : NULL, 1,
698                                     NFS_ACL_DEFAULT);
699         return (err > 0) ? 0 : err;
700 }
701 #endif  /* CONFIG_NFS_V3_ACL */
702
703 /*
704  * NFS XDR decode functions
705  */
706
707 /*
708  * Decode attrstat reply.
709  */
710 static int
711 nfs3_xdr_attrstat(struct rpc_rqst *req, u32 *p, struct nfs_fattr *fattr)
712 {
713         int     status;
714
715         if ((status = ntohl(*p++)))
716                 return -nfs_stat_to_errno(status);
717         xdr_decode_fattr(p, fattr);
718         return 0;
719 }
720
721 /*
722  * Decode status+wcc_data reply
723  * SATTR, REMOVE, RMDIR
724  */
725 static int
726 nfs3_xdr_wccstat(struct rpc_rqst *req, u32 *p, struct nfs_fattr *fattr)
727 {
728         int     status;
729
730         if ((status = ntohl(*p++)))
731                 status = -nfs_stat_to_errno(status);
732         xdr_decode_wcc_data(p, fattr);
733         return status;
734 }
735
736 /*
737  * Decode LOOKUP reply
738  */
739 static int
740 nfs3_xdr_lookupres(struct rpc_rqst *req, u32 *p, struct nfs3_diropres *res)
741 {
742         int     status;
743
744         if ((status = ntohl(*p++))) {
745                 status = -nfs_stat_to_errno(status);
746         } else {
747                 if (!(p = xdr_decode_fhandle(p, res->fh)))
748                         return -errno_NFSERR_IO;
749                 p = xdr_decode_post_op_attr(p, res->fattr);
750         }
751         xdr_decode_post_op_attr(p, res->dir_attr);
752         return status;
753 }
754
755 /*
756  * Decode ACCESS reply
757  */
758 static int
759 nfs3_xdr_accessres(struct rpc_rqst *req, u32 *p, struct nfs3_accessres *res)
760 {
761         int     status = ntohl(*p++);
762
763         p = xdr_decode_post_op_attr(p, res->fattr);
764         if (status)
765                 return -nfs_stat_to_errno(status);
766         res->access = ntohl(*p++);
767         return 0;
768 }
769
770 static int
771 nfs3_xdr_readlinkargs(struct rpc_rqst *req, u32 *p, struct nfs3_readlinkargs *args)
772 {
773         struct rpc_auth *auth = req->rq_task->tk_auth;
774         unsigned int replen;
775
776         p = xdr_encode_fhandle(p, args->fh);
777         req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
778
779         /* Inline the page array */
780         replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS3_readlinkres_sz) << 2;
781         xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, args->pgbase, args->pglen);
782         return 0;
783 }
784
785 /*
786  * Decode READLINK reply
787  */
788 static int
789 nfs3_xdr_readlinkres(struct rpc_rqst *req, u32 *p, struct nfs_fattr *fattr)
790 {
791         struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
792         struct kvec *iov = rcvbuf->head;
793         int hdrlen, len, recvd;
794         char    *kaddr;
795         int     status;
796
797         status = ntohl(*p++);
798         p = xdr_decode_post_op_attr(p, fattr);
799
800         if (status != 0)
801                 return -nfs_stat_to_errno(status);
802
803         /* Convert length of symlink */
804         len = ntohl(*p++);
805         if (len >= rcvbuf->page_len || len <= 0) {
806                 dprintk(KERN_WARNING "nfs: server returned giant symlink!\n");
807                 return -ENAMETOOLONG;
808         }
809
810         hdrlen = (u8 *) p - (u8 *) iov->iov_base;
811         if (iov->iov_len < hdrlen) {
812                 printk(KERN_WARNING "NFS: READLINK reply header overflowed:"
813                                 "length %d > %Zu\n", hdrlen, iov->iov_len);
814                 return -errno_NFSERR_IO;
815         } else if (iov->iov_len != hdrlen) {
816                 dprintk("NFS: READLINK header is short. iovec will be shifted.\n");
817                 xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen);
818         }
819         recvd = req->rq_rcv_buf.len - hdrlen;
820         if (recvd < len) {
821                 printk(KERN_WARNING "NFS: server cheating in readlink reply: "
822                                 "count %u > recvd %u\n", len, recvd);
823                 return -EIO;
824         }
825
826         /* NULL terminate the string we got */
827         kaddr = (char*)kmap_atomic(rcvbuf->pages[0], KM_USER0);
828         kaddr[len+rcvbuf->page_base] = '\0';
829         kunmap_atomic(kaddr, KM_USER0);
830         return 0;
831 }
832
833 /*
834  * Decode READ reply
835  */
836 static int
837 nfs3_xdr_readres(struct rpc_rqst *req, u32 *p, struct nfs_readres *res)
838 {
839         struct kvec *iov = req->rq_rcv_buf.head;
840         int     status, count, ocount, recvd, hdrlen;
841
842         status = ntohl(*p++);
843         p = xdr_decode_post_op_attr(p, res->fattr);
844
845         if (status != 0)
846                 return -nfs_stat_to_errno(status);
847
848         /* Decode reply could and EOF flag. NFSv3 is somewhat redundant
849          * in that it puts the count both in the res struct and in the
850          * opaque data count. */
851         count    = ntohl(*p++);
852         res->eof = ntohl(*p++);
853         ocount   = ntohl(*p++);
854
855         if (ocount != count) {
856                 printk(KERN_WARNING "NFS: READ count doesn't match RPC opaque count.\n");
857                 return -errno_NFSERR_IO;
858         }
859
860         hdrlen = (u8 *) p - (u8 *) iov->iov_base;
861         if (iov->iov_len < hdrlen) {
862                 printk(KERN_WARNING "NFS: READ reply header overflowed:"
863                                 "length %d > %Zu\n", hdrlen, iov->iov_len);
864                 return -errno_NFSERR_IO;
865         } else if (iov->iov_len != hdrlen) {
866                 dprintk("NFS: READ header is short. iovec will be shifted.\n");
867                 xdr_shift_buf(&req->rq_rcv_buf, iov->iov_len - hdrlen);
868         }
869
870         recvd = req->rq_rcv_buf.len - hdrlen;
871         if (count > recvd) {
872                 printk(KERN_WARNING "NFS: server cheating in read reply: "
873                         "count %d > recvd %d\n", count, recvd);
874                 count = recvd;
875                 res->eof = 0;
876         }
877
878         if (count < res->count)
879                 res->count = count;
880
881         return count;
882 }
883
884 /*
885  * Decode WRITE response
886  */
887 static int
888 nfs3_xdr_writeres(struct rpc_rqst *req, u32 *p, struct nfs_writeres *res)
889 {
890         int     status;
891
892         status = ntohl(*p++);
893         p = xdr_decode_wcc_data(p, res->fattr);
894
895         if (status != 0)
896                 return -nfs_stat_to_errno(status);
897
898         res->count = ntohl(*p++);
899         res->verf->committed = (enum nfs3_stable_how)ntohl(*p++);
900         res->verf->verifier[0] = *p++;
901         res->verf->verifier[1] = *p++;
902
903         return res->count;
904 }
905
906 /*
907  * Decode a CREATE response
908  */
909 static int
910 nfs3_xdr_createres(struct rpc_rqst *req, u32 *p, struct nfs3_diropres *res)
911 {
912         int     status;
913
914         status = ntohl(*p++);
915         if (status == 0) {
916                 if (*p++) {
917                         if (!(p = xdr_decode_fhandle(p, res->fh)))
918                                 return -errno_NFSERR_IO;
919                         p = xdr_decode_post_op_attr(p, res->fattr);
920                 } else {
921                         memset(res->fh, 0, sizeof(*res->fh));
922                         /* Do decode post_op_attr but set it to NULL */
923                         p = xdr_decode_post_op_attr(p, res->fattr);
924                         res->fattr->valid = 0;
925                 }
926         } else {
927                 status = -nfs_stat_to_errno(status);
928         }
929         p = xdr_decode_wcc_data(p, res->dir_attr);
930         return status;
931 }
932
933 /*
934  * Decode RENAME reply
935  */
936 static int
937 nfs3_xdr_renameres(struct rpc_rqst *req, u32 *p, struct nfs3_renameres *res)
938 {
939         int     status;
940
941         if ((status = ntohl(*p++)) != 0)
942                 status = -nfs_stat_to_errno(status);
943         p = xdr_decode_wcc_data(p, res->fromattr);
944         p = xdr_decode_wcc_data(p, res->toattr);
945         return status;
946 }
947
948 /*
949  * Decode LINK reply
950  */
951 static int
952 nfs3_xdr_linkres(struct rpc_rqst *req, u32 *p, struct nfs3_linkres *res)
953 {
954         int     status;
955
956         if ((status = ntohl(*p++)) != 0)
957                 status = -nfs_stat_to_errno(status);
958         p = xdr_decode_post_op_attr(p, res->fattr);
959         p = xdr_decode_wcc_data(p, res->dir_attr);
960         return status;
961 }
962
963 /*
964  * Decode FSSTAT reply
965  */
966 static int
967 nfs3_xdr_fsstatres(struct rpc_rqst *req, u32 *p, struct nfs_fsstat *res)
968 {
969         int             status;
970
971         status = ntohl(*p++);
972
973         p = xdr_decode_post_op_attr(p, res->fattr);
974         if (status != 0)
975                 return -nfs_stat_to_errno(status);
976
977         p = xdr_decode_hyper(p, &res->tbytes);
978         p = xdr_decode_hyper(p, &res->fbytes);
979         p = xdr_decode_hyper(p, &res->abytes);
980         p = xdr_decode_hyper(p, &res->tfiles);
981         p = xdr_decode_hyper(p, &res->ffiles);
982         p = xdr_decode_hyper(p, &res->afiles);
983
984         /* ignore invarsec */
985         return 0;
986 }
987
988 /*
989  * Decode FSINFO reply
990  */
991 static int
992 nfs3_xdr_fsinfores(struct rpc_rqst *req, u32 *p, struct nfs_fsinfo *res)
993 {
994         int             status;
995
996         status = ntohl(*p++);
997
998         p = xdr_decode_post_op_attr(p, res->fattr);
999         if (status != 0)
1000                 return -nfs_stat_to_errno(status);
1001
1002         res->rtmax  = ntohl(*p++);
1003         res->rtpref = ntohl(*p++);
1004         res->rtmult = ntohl(*p++);
1005         res->wtmax  = ntohl(*p++);
1006         res->wtpref = ntohl(*p++);
1007         res->wtmult = ntohl(*p++);
1008         res->dtpref = ntohl(*p++);
1009         p = xdr_decode_hyper(p, &res->maxfilesize);
1010
1011         /* ignore time_delta and properties */
1012         res->lease_time = 0;
1013         return 0;
1014 }
1015
1016 /*
1017  * Decode PATHCONF reply
1018  */
1019 static int
1020 nfs3_xdr_pathconfres(struct rpc_rqst *req, u32 *p, struct nfs_pathconf *res)
1021 {
1022         int             status;
1023
1024         status = ntohl(*p++);
1025
1026         p = xdr_decode_post_op_attr(p, res->fattr);
1027         if (status != 0)
1028                 return -nfs_stat_to_errno(status);
1029         res->max_link = ntohl(*p++);
1030         res->max_namelen = ntohl(*p++);
1031
1032         /* ignore remaining fields */
1033         return 0;
1034 }
1035
1036 /*
1037  * Decode COMMIT reply
1038  */
1039 static int
1040 nfs3_xdr_commitres(struct rpc_rqst *req, u32 *p, struct nfs_writeres *res)
1041 {
1042         int             status;
1043
1044         status = ntohl(*p++);
1045         p = xdr_decode_wcc_data(p, res->fattr);
1046         if (status != 0)
1047                 return -nfs_stat_to_errno(status);
1048
1049         res->verf->verifier[0] = *p++;
1050         res->verf->verifier[1] = *p++;
1051         return 0;
1052 }
1053
1054 #ifdef CONFIG_NFS_V3_ACL
1055 /*
1056  * Decode GETACL reply
1057  */
1058 static int
1059 nfs3_xdr_getaclres(struct rpc_rqst *req, u32 *p,
1060                    struct nfs3_getaclres *res)
1061 {
1062         struct xdr_buf *buf = &req->rq_rcv_buf;
1063         int status = ntohl(*p++);
1064         struct posix_acl **acl;
1065         unsigned int *aclcnt;
1066         int err, base;
1067
1068         if (status != 0)
1069                 return -nfs_stat_to_errno(status);
1070         p = xdr_decode_post_op_attr(p, res->fattr);
1071         res->mask = ntohl(*p++);
1072         if (res->mask & ~(NFS_ACL|NFS_ACLCNT|NFS_DFACL|NFS_DFACLCNT))
1073                 return -EINVAL;
1074         base = (char *)p - (char *)req->rq_rcv_buf.head->iov_base;
1075
1076         acl = (res->mask & NFS_ACL) ? &res->acl_access : NULL;
1077         aclcnt = (res->mask & NFS_ACLCNT) ? &res->acl_access_count : NULL;
1078         err = nfsacl_decode(buf, base, aclcnt, acl);
1079
1080         acl = (res->mask & NFS_DFACL) ? &res->acl_default : NULL;
1081         aclcnt = (res->mask & NFS_DFACLCNT) ? &res->acl_default_count : NULL;
1082         if (err > 0)
1083                 err = nfsacl_decode(buf, base + err, aclcnt, acl);
1084         return (err > 0) ? 0 : err;
1085 }
1086
1087 /*
1088  * Decode setacl reply.
1089  */
1090 static int
1091 nfs3_xdr_setaclres(struct rpc_rqst *req, u32 *p, struct nfs_fattr *fattr)
1092 {
1093         int status = ntohl(*p++);
1094
1095         if (status)
1096                 return -nfs_stat_to_errno(status);
1097         xdr_decode_post_op_attr(p, fattr);
1098         return 0;
1099 }
1100 #endif  /* CONFIG_NFS_V3_ACL */
1101
1102 #ifndef MAX
1103 # define MAX(a, b)      (((a) > (b))? (a) : (b))
1104 #endif
1105
1106 #define PROC(proc, argtype, restype, timer)                             \
1107 [NFS3PROC_##proc] = {                                                   \
1108         .p_proc      = NFS3PROC_##proc,                                 \
1109         .p_encode    = (kxdrproc_t) nfs3_xdr_##argtype,                 \
1110         .p_decode    = (kxdrproc_t) nfs3_xdr_##restype,                 \
1111         .p_bufsiz    = MAX(NFS3_##argtype##_sz,NFS3_##restype##_sz) << 2,       \
1112         .p_timer     = timer                                            \
1113         }
1114
1115 struct rpc_procinfo     nfs3_procedures[] = {
1116   PROC(GETATTR,         fhandle,        attrstat, 1),
1117   PROC(SETATTR,         sattrargs,      wccstat, 0),
1118   PROC(LOOKUP,          diropargs,      lookupres, 2),
1119   PROC(ACCESS,          accessargs,     accessres, 1),
1120   PROC(READLINK,        readlinkargs,   readlinkres, 3),
1121   PROC(READ,            readargs,       readres, 3),
1122   PROC(WRITE,           writeargs,      writeres, 4),
1123   PROC(CREATE,          createargs,     createres, 0),
1124   PROC(MKDIR,           mkdirargs,      createres, 0),
1125   PROC(SYMLINK,         symlinkargs,    createres, 0),
1126   PROC(MKNOD,           mknodargs,      createres, 0),
1127   PROC(REMOVE,          diropargs,      wccstat, 0),
1128   PROC(RMDIR,           diropargs,      wccstat, 0),
1129   PROC(RENAME,          renameargs,     renameres, 0),
1130   PROC(LINK,            linkargs,       linkres, 0),
1131   PROC(READDIR,         readdirargs,    readdirres, 3),
1132   PROC(READDIRPLUS,     readdirargs,    readdirres, 3),
1133   PROC(FSSTAT,          fhandle,        fsstatres, 0),
1134   PROC(FSINFO,          fhandle,        fsinfores, 0),
1135   PROC(PATHCONF,        fhandle,        pathconfres, 0),
1136   PROC(COMMIT,          commitargs,     commitres, 5),
1137 };
1138
1139 struct rpc_version              nfs_version3 = {
1140         .number                 = 3,
1141         .nrprocs                = sizeof(nfs3_procedures)/sizeof(nfs3_procedures[0]),
1142         .procs                  = nfs3_procedures
1143 };
1144
1145 #ifdef CONFIG_NFS_V3_ACL
1146 static struct rpc_procinfo      nfs3_acl_procedures[] = {
1147         [ACLPROC3_GETACL] = {
1148                 .p_proc = ACLPROC3_GETACL,
1149                 .p_encode = (kxdrproc_t) nfs3_xdr_getaclargs,
1150                 .p_decode = (kxdrproc_t) nfs3_xdr_getaclres,
1151                 .p_bufsiz = MAX(ACL3_getaclargs_sz, ACL3_getaclres_sz) << 2,
1152                 .p_timer = 1,
1153         },
1154         [ACLPROC3_SETACL] = {
1155                 .p_proc = ACLPROC3_SETACL,
1156                 .p_encode = (kxdrproc_t) nfs3_xdr_setaclargs,
1157                 .p_decode = (kxdrproc_t) nfs3_xdr_setaclres,
1158                 .p_bufsiz = MAX(ACL3_setaclargs_sz, ACL3_setaclres_sz) << 2,
1159                 .p_timer = 0,
1160         },
1161 };
1162
1163 struct rpc_version              nfsacl_version3 = {
1164         .number                 = 3,
1165         .nrprocs                = sizeof(nfs3_acl_procedures)/
1166                                   sizeof(nfs3_acl_procedures[0]),
1167         .procs                  = nfs3_acl_procedures,
1168 };
1169 #endif  /* CONFIG_NFS_V3_ACL */