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