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