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