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