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