patch-2_6_7-vs1_9_1_12
[linux-2.6.git] / fs / nfs / nfs2xdr.c
1 /*
2  * linux/fs/nfs/nfs2xdr.c
3  *
4  * XDR functions to encode/decode NFS RPC arguments and results.
5  *
6  * Copyright (C) 1992, 1993, 1994  Rick Sladkey
7  * Copyright (C) 1996 Olaf Kirch
8  * 04 Aug 1998  Ion Badulescu <ionut@cs.columbia.edu>
9  *              FIFO's need special handling in NFSv2
10  */
11
12 #include <linux/param.h>
13 #include <linux/time.h>
14 #include <linux/mm.h>
15 #include <linux/slab.h>
16 #include <linux/utsname.h>
17 #include <linux/errno.h>
18 #include <linux/string.h>
19 #include <linux/in.h>
20 #include <linux/pagemap.h>
21 #include <linux/proc_fs.h>
22 #include <linux/sunrpc/clnt.h>
23 #include <linux/nfs.h>
24 #include <linux/nfs2.h>
25 #include <linux/nfs_fs.h>
26
27 #define NFSDBG_FACILITY         NFSDBG_XDR
28 /* #define NFS_PARANOIA 1 */
29
30 extern int                      nfs_stat_to_errno(int stat);
31
32 /* Mapping from NFS error code to "errno" error code. */
33 #define errno_NFSERR_IO         EIO
34
35 /*
36  * Declare the space requirements for NFS arguments and replies as
37  * number of 32bit-words
38  */
39 #define NFS_fhandle_sz          (8)
40 #define NFS_sattr_sz            (8)
41 #define NFS_filename_sz         (1+(NFS2_MAXNAMLEN>>2))
42 #define NFS_path_sz             (1+(NFS2_MAXPATHLEN>>2))
43 #define NFS_fattr_sz            (17)
44 #define NFS_info_sz             (5)
45 #define NFS_entry_sz            (NFS_filename_sz+3)
46
47 #define NFS_diropargs_sz        (NFS_fhandle_sz+NFS_filename_sz)
48 #define NFS_sattrargs_sz        (NFS_fhandle_sz+NFS_sattr_sz)
49 #define NFS_readlinkargs_sz     (NFS_fhandle_sz)
50 #define NFS_readargs_sz         (NFS_fhandle_sz+3)
51 #define NFS_writeargs_sz        (NFS_fhandle_sz+4)
52 #define NFS_createargs_sz       (NFS_diropargs_sz+NFS_sattr_sz)
53 #define NFS_renameargs_sz       (NFS_diropargs_sz+NFS_diropargs_sz)
54 #define NFS_linkargs_sz         (NFS_fhandle_sz+NFS_diropargs_sz)
55 #define NFS_symlinkargs_sz      (NFS_diropargs_sz+NFS_path_sz+NFS_sattr_sz)
56 #define NFS_readdirargs_sz      (NFS_fhandle_sz+2)
57
58 #define NFS_attrstat_sz         (1+NFS_fattr_sz)
59 #define NFS_diropres_sz         (1+NFS_fhandle_sz+NFS_fattr_sz)
60 #define NFS_readlinkres_sz      (1)
61 #define NFS_readres_sz          (1+NFS_fattr_sz+1)
62 #define NFS_writeres_sz         (NFS_attrstat_sz)
63 #define NFS_stat_sz             (1)
64 #define NFS_readdirres_sz       (1)
65 #define NFS_statfsres_sz        (1+NFS_info_sz)
66
67 /*
68  * Common NFS XDR functions as inlines
69  */
70 static inline u32 *
71 xdr_encode_fhandle(u32 *p, struct nfs_fh *fhandle)
72 {
73         memcpy(p, fhandle->data, NFS2_FHSIZE);
74         return p + XDR_QUADLEN(NFS2_FHSIZE);
75 }
76
77 static inline u32 *
78 xdr_decode_fhandle(u32 *p, struct nfs_fh *fhandle)
79 {
80         /* Zero handle first to allow comparisons */
81         memset(fhandle, 0, sizeof(*fhandle));
82         /* NFSv2 handles have a fixed length */
83         fhandle->size = NFS2_FHSIZE;
84         memcpy(fhandle->data, p, NFS2_FHSIZE);
85         return p + XDR_QUADLEN(NFS2_FHSIZE);
86 }
87
88 static inline u32*
89 xdr_encode_time(u32 *p, struct timespec *timep)
90 {
91         *p++ = htonl(timep->tv_sec);
92         /* Convert nanoseconds into microseconds */
93         *p++ = htonl(timep->tv_nsec ? timep->tv_nsec / 1000 : 0);
94         return p;
95 }
96
97 static inline u32*
98 xdr_decode_time(u32 *p, struct timespec *timep)
99 {
100         timep->tv_sec = ntohl(*p++);
101         /* Convert microseconds into nanoseconds */
102         timep->tv_nsec = ntohl(*p++) * 1000;
103         return p;
104 }
105
106 static u32 *
107 xdr_decode_fattr(u32 *p, struct nfs_fattr *fattr)
108 {
109         u32 rdev;
110         fattr->type = (enum nfs_ftype) ntohl(*p++);
111         fattr->mode = ntohl(*p++);
112         fattr->nlink = ntohl(*p++);
113         fattr->uid = ntohl(*p++);
114         fattr->gid = ntohl(*p++);
115         fattr->size = ntohl(*p++);
116         fattr->du.nfs2.blocksize = ntohl(*p++);
117         rdev = ntohl(*p++);
118         fattr->du.nfs2.blocks = ntohl(*p++);
119         fattr->fsid_u.nfs3 = ntohl(*p++);
120         fattr->fileid = ntohl(*p++);
121         p = xdr_decode_time(p, &fattr->atime);
122         p = xdr_decode_time(p, &fattr->mtime);
123         p = xdr_decode_time(p, &fattr->ctime);
124         fattr->valid |= NFS_ATTR_FATTR;
125         fattr->rdev = new_decode_dev(rdev);
126         if (fattr->type == NFCHR && rdev == NFS2_FIFO_DEV) {
127                 fattr->type = NFFIFO;
128                 fattr->mode = (fattr->mode & ~S_IFMT) | S_IFIFO;
129                 fattr->rdev = 0;
130         }
131         fattr->timestamp = jiffies;
132         return p;
133 }
134
135 #define SATTR(p, attr, flag, field) \
136         *p++ = (attr->ia_valid & flag) ? htonl(attr->field) : ~(u32) 0
137 static inline u32 *
138 xdr_encode_sattr(u32 *p, struct iattr *attr)
139 {
140         SATTR(p, attr, ATTR_MODE, ia_mode);
141         SATTR(p, attr, ATTR_UID, ia_uid);
142         SATTR(p, attr, ATTR_GID, ia_gid);
143         SATTR(p, attr, ATTR_SIZE, ia_size);
144
145         if (attr->ia_valid & (ATTR_ATIME|ATTR_ATIME_SET)) {
146                 p = xdr_encode_time(p, &attr->ia_atime);
147         } else {
148                 *p++ = ~(u32) 0;
149                 *p++ = ~(u32) 0;
150         }
151
152         if (attr->ia_valid & (ATTR_MTIME|ATTR_MTIME_SET)) {
153                 p = xdr_encode_time(p, &attr->ia_mtime);
154         } else {
155                 *p++ = ~(u32) 0;        
156                 *p++ = ~(u32) 0;
157         }
158         return p;
159 }
160 #undef SATTR
161
162 /*
163  * NFS encode functions
164  */
165 /*
166  * Encode file handle argument
167  * GETATTR, READLINK, STATFS
168  */
169 static int
170 nfs_xdr_fhandle(struct rpc_rqst *req, u32 *p, struct nfs_fh *fh)
171 {
172         p = xdr_encode_fhandle(p, fh);
173         req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
174         return 0;
175 }
176
177 /*
178  * Encode SETATTR arguments
179  */
180 static int
181 nfs_xdr_sattrargs(struct rpc_rqst *req, u32 *p, struct nfs_sattrargs *args)
182 {
183         p = xdr_encode_fhandle(p, args->fh);
184         p = xdr_encode_sattr(p, args->sattr);
185         req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
186         return 0;
187 }
188
189 /*
190  * Encode directory ops argument
191  * LOOKUP, REMOVE, RMDIR
192  */
193 static int
194 nfs_xdr_diropargs(struct rpc_rqst *req, u32 *p, struct nfs_diropargs *args)
195 {
196         p = xdr_encode_fhandle(p, args->fh);
197         p = xdr_encode_array(p, args->name, args->len);
198         req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
199         return 0;
200 }
201
202 /*
203  * Arguments to a READ call. Since we read data directly into the page
204  * cache, we also set up the reply iovec here so that iov[1] points
205  * exactly to the page we want to fetch.
206  */
207 static int
208 nfs_xdr_readargs(struct rpc_rqst *req, u32 *p, struct nfs_readargs *args)
209 {
210         struct rpc_auth *auth = req->rq_task->tk_auth;
211         unsigned int replen;
212         u32 offset = (u32)args->offset;
213         u32 count = args->count;
214
215         p = xdr_encode_fhandle(p, args->fh);
216         *p++ = htonl(offset);
217         *p++ = htonl(count);
218         *p++ = htonl(count);
219         req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
220
221         /* Inline the page array */
222         replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS_readres_sz) << 2;
223         xdr_inline_pages(&req->rq_rcv_buf, replen,
224                          args->pages, args->pgbase, count);
225         return 0;
226 }
227
228 /*
229  * Decode READ reply
230  */
231 static int
232 nfs_xdr_readres(struct rpc_rqst *req, u32 *p, struct nfs_readres *res)
233 {
234         struct iovec *iov = req->rq_rcv_buf.head;
235         int     status, count, recvd, hdrlen;
236
237         if ((status = ntohl(*p++)))
238                 return -nfs_stat_to_errno(status);
239         p = xdr_decode_fattr(p, res->fattr);
240
241         count = ntohl(*p++);
242         res->eof = 0;
243         hdrlen = (u8 *) p - (u8 *) iov->iov_base;
244         if (iov->iov_len < hdrlen) {
245                 printk(KERN_WARNING "NFS: READ reply header overflowed:"
246                                 "length %d > %Zu\n", hdrlen, iov->iov_len);
247                 return -errno_NFSERR_IO;
248         } else if (iov->iov_len != hdrlen) {
249                 dprintk("NFS: READ header is short. iovec will be shifted.\n");
250                 xdr_shift_buf(&req->rq_rcv_buf, iov->iov_len - hdrlen);
251         }
252
253         recvd = req->rq_rcv_buf.len - hdrlen;
254         if (count > recvd) {
255                 printk(KERN_WARNING "NFS: server cheating in read reply: "
256                         "count %d > recvd %d\n", count, recvd);
257                 count = recvd;
258         }
259
260         dprintk("RPC:      readres OK count %d\n", count);
261         if (count < res->count)
262                 res->count = count;
263
264         return count;
265 }
266
267
268 /*
269  * Write arguments. Splice the buffer to be written into the iovec.
270  */
271 static int
272 nfs_xdr_writeargs(struct rpc_rqst *req, u32 *p, struct nfs_writeargs *args)
273 {
274         struct xdr_buf *sndbuf = &req->rq_snd_buf;
275         u32 offset = (u32)args->offset;
276         u32 count = args->count;
277
278         p = xdr_encode_fhandle(p, args->fh);
279         *p++ = htonl(offset);
280         *p++ = htonl(offset);
281         *p++ = htonl(count);
282         *p++ = htonl(count);
283         sndbuf->len = xdr_adjust_iovec(sndbuf->head, p);
284
285         /* Copy the page array */
286         xdr_encode_pages(sndbuf, args->pages, args->pgbase, count);
287         return 0;
288 }
289
290 /*
291  * Encode create arguments
292  * CREATE, MKDIR
293  */
294 static int
295 nfs_xdr_createargs(struct rpc_rqst *req, u32 *p, struct nfs_createargs *args)
296 {
297         p = xdr_encode_fhandle(p, args->fh);
298         p = xdr_encode_array(p, args->name, args->len);
299         p = xdr_encode_sattr(p, args->sattr);
300         req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
301         return 0;
302 }
303
304 /*
305  * Encode RENAME arguments
306  */
307 static int
308 nfs_xdr_renameargs(struct rpc_rqst *req, u32 *p, struct nfs_renameargs *args)
309 {
310         p = xdr_encode_fhandle(p, args->fromfh);
311         p = xdr_encode_array(p, args->fromname, args->fromlen);
312         p = xdr_encode_fhandle(p, args->tofh);
313         p = xdr_encode_array(p, args->toname, args->tolen);
314         req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
315         return 0;
316 }
317
318 /*
319  * Encode LINK arguments
320  */
321 static int
322 nfs_xdr_linkargs(struct rpc_rqst *req, u32 *p, struct nfs_linkargs *args)
323 {
324         p = xdr_encode_fhandle(p, args->fromfh);
325         p = xdr_encode_fhandle(p, args->tofh);
326         p = xdr_encode_array(p, args->toname, args->tolen);
327         req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
328         return 0;
329 }
330
331 /*
332  * Encode SYMLINK arguments
333  */
334 static int
335 nfs_xdr_symlinkargs(struct rpc_rqst *req, u32 *p, struct nfs_symlinkargs *args)
336 {
337         p = xdr_encode_fhandle(p, args->fromfh);
338         p = xdr_encode_array(p, args->fromname, args->fromlen);
339         p = xdr_encode_array(p, args->topath, args->tolen);
340         p = xdr_encode_sattr(p, args->sattr);
341         req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
342         return 0;
343 }
344
345 /*
346  * Encode arguments to readdir call
347  */
348 static int
349 nfs_xdr_readdirargs(struct rpc_rqst *req, u32 *p, struct nfs_readdirargs *args)
350 {
351         struct rpc_task *task = req->rq_task;
352         struct rpc_auth *auth = task->tk_auth;
353         unsigned int replen;
354         u32 count = args->count;
355
356         p = xdr_encode_fhandle(p, args->fh);
357         *p++ = htonl(args->cookie);
358         *p++ = htonl(count); /* see above */
359         req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
360
361         /* Inline the page array */
362         replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS_readdirres_sz) << 2;
363         xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, 0, count);
364         return 0;
365 }
366
367 /*
368  * Decode the result of a readdir call.
369  * We're not really decoding anymore, we just leave the buffer untouched
370  * and only check that it is syntactically correct.
371  * The real decoding happens in nfs_decode_entry below, called directly
372  * from nfs_readdir for each entry.
373  */
374 static int
375 nfs_xdr_readdirres(struct rpc_rqst *req, u32 *p, void *dummy)
376 {
377         struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
378         struct iovec *iov = rcvbuf->head;
379         struct page **page;
380         int hdrlen, recvd;
381         int status, nr;
382         unsigned int len, pglen;
383         u32 *end, *entry, *kaddr;
384
385         if ((status = ntohl(*p++)))
386                 return -nfs_stat_to_errno(status);
387
388         hdrlen = (u8 *) p - (u8 *) iov->iov_base;
389         if (iov->iov_len < hdrlen) {
390                 printk(KERN_WARNING "NFS: READDIR reply header overflowed:"
391                                 "length %d > %Zu\n", hdrlen, iov->iov_len);
392                 return -errno_NFSERR_IO;
393         } else if (iov->iov_len != hdrlen) {
394                 dprintk("NFS: READDIR header is short. iovec will be shifted.\n");
395                 xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen);
396         }
397
398         pglen = rcvbuf->page_len;
399         recvd = rcvbuf->len - hdrlen;
400         if (pglen > recvd)
401                 pglen = recvd;
402         page = rcvbuf->pages;
403         kaddr = p = (u32 *)kmap_atomic(*page, KM_USER0);
404         end = (u32 *)((char *)p + pglen);
405         entry = p;
406         for (nr = 0; *p++; nr++) {
407                 if (p + 2 > end)
408                         goto short_pkt;
409                 p++; /* fileid */
410                 len = ntohl(*p++);
411                 p += XDR_QUADLEN(len) + 1;      /* name plus cookie */
412                 if (len > NFS2_MAXNAMLEN) {
413                         printk(KERN_WARNING "NFS: giant filename in readdir (len 0x%x)!\n",
414                                                 len);
415                         goto err_unmap;
416                 }
417                 if (p + 2 > end)
418                         goto short_pkt;
419                 entry = p;
420         }
421         if (!nr && (entry[0] != 0 || entry[1] == 0))
422                 goto short_pkt;
423  out:
424         kunmap_atomic(kaddr, KM_USER0);
425         return nr;
426  short_pkt:
427         entry[0] = entry[1] = 0;
428         /* truncate listing ? */
429         if (!nr) {
430                 printk(KERN_NOTICE "NFS: readdir reply truncated!\n");
431                 entry[1] = 1;
432         }
433         goto out;
434 err_unmap:
435         nr = -errno_NFSERR_IO;
436         goto out;
437 }
438
439 u32 *
440 nfs_decode_dirent(u32 *p, struct nfs_entry *entry, int plus)
441 {
442         if (!*p++) {
443                 if (!*p)
444                         return ERR_PTR(-EAGAIN);
445                 entry->eof = 1;
446                 return ERR_PTR(-EBADCOOKIE);
447         }
448
449         entry->ino        = ntohl(*p++);
450         entry->len        = ntohl(*p++);
451         entry->name       = (const char *) p;
452         p                += XDR_QUADLEN(entry->len);
453         entry->prev_cookie        = entry->cookie;
454         entry->cookie     = ntohl(*p++);
455         entry->eof        = !p[0] && p[1];
456
457         return p;
458 }
459
460 /*
461  * NFS XDR decode functions
462  */
463 /*
464  * Decode simple status reply
465  */
466 static int
467 nfs_xdr_stat(struct rpc_rqst *req, u32 *p, void *dummy)
468 {
469         int     status;
470
471         if ((status = ntohl(*p++)) != 0)
472                 status = -nfs_stat_to_errno(status);
473         return status;
474 }
475
476 /*
477  * Decode attrstat reply
478  * GETATTR, SETATTR, WRITE
479  */
480 static int
481 nfs_xdr_attrstat(struct rpc_rqst *req, u32 *p, struct nfs_fattr *fattr)
482 {
483         int     status;
484
485         if ((status = ntohl(*p++)))
486                 return -nfs_stat_to_errno(status);
487         xdr_decode_fattr(p, fattr);
488         return 0;
489 }
490
491 /*
492  * Decode diropres reply
493  * LOOKUP, CREATE, MKDIR
494  */
495 static int
496 nfs_xdr_diropres(struct rpc_rqst *req, u32 *p, struct nfs_diropok *res)
497 {
498         int     status;
499
500         if ((status = ntohl(*p++)))
501                 return -nfs_stat_to_errno(status);
502         p = xdr_decode_fhandle(p, res->fh);
503         xdr_decode_fattr(p, res->fattr);
504         return 0;
505 }
506
507 /*
508  * Encode READLINK args
509  */
510 static int
511 nfs_xdr_readlinkargs(struct rpc_rqst *req, u32 *p, struct nfs_readlinkargs *args)
512 {
513         struct rpc_auth *auth = req->rq_task->tk_auth;
514         unsigned int count = args->count - 5;
515         unsigned int replen;
516
517         p = xdr_encode_fhandle(p, args->fh);
518         req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
519
520         /* Inline the page array */
521         replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS_readlinkres_sz) << 2;
522         xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, 0, count);
523         return 0;
524 }
525
526 /*
527  * Decode READLINK reply
528  */
529 static int
530 nfs_xdr_readlinkres(struct rpc_rqst *req, u32 *p, void *dummy)
531 {
532         struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
533         struct iovec *iov = rcvbuf->head;
534         unsigned int hdrlen;
535         u32     *strlen, len;
536         char    *string;
537         int     status;
538
539         if ((status = ntohl(*p++)))
540                 return -nfs_stat_to_errno(status);
541         hdrlen = (u8 *) p - (u8 *) iov->iov_base;
542         if (iov->iov_len > hdrlen) {
543                 dprintk("NFS: READLINK header is short. iovec will be shifted.\n");
544                 xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen);
545         }
546
547         strlen = (u32*)kmap_atomic(rcvbuf->pages[0], KM_USER0);
548         /* Convert length of symlink */
549         len = ntohl(*strlen);
550         if (len > rcvbuf->page_len) {
551                 dprintk(KERN_WARNING "nfs: server returned giant symlink!\n");
552                 kunmap_atomic(strlen, KM_USER0);
553                 return -ENAMETOOLONG;
554         }
555         *strlen = len;
556         /* NULL terminate the string we got */
557         string = (char *)(strlen + 1);
558         string[len] = '\0';
559         kunmap_atomic(strlen, KM_USER0);
560         return 0;
561 }
562
563 /*
564  * Decode WRITE reply
565  */
566 static int
567 nfs_xdr_writeres(struct rpc_rqst *req, u32 *p, struct nfs_writeres *res)
568 {
569         res->verf->committed = NFS_FILE_SYNC;
570         return nfs_xdr_attrstat(req, p, res->fattr);
571 }
572
573 /*
574  * Decode STATFS reply
575  */
576 static int
577 nfs_xdr_statfsres(struct rpc_rqst *req, u32 *p, struct nfs2_fsstat *res)
578 {
579         int     status;
580
581         if ((status = ntohl(*p++)))
582                 return -nfs_stat_to_errno(status);
583
584         res->tsize  = ntohl(*p++);
585         res->bsize  = ntohl(*p++);
586         res->blocks = ntohl(*p++);
587         res->bfree  = ntohl(*p++);
588         res->bavail = ntohl(*p++);
589         return 0;
590 }
591
592 /*
593  * We need to translate between nfs status return values and
594  * the local errno values which may not be the same.
595  */
596 static struct {
597         int stat;
598         int errno;
599 } nfs_errtbl[] = {
600         { NFS_OK,               0               },
601         { NFSERR_PERM,          EPERM           },
602         { NFSERR_NOENT,         ENOENT          },
603         { NFSERR_IO,            errno_NFSERR_IO },
604         { NFSERR_NXIO,          ENXIO           },
605 /*      { NFSERR_EAGAIN,        EAGAIN          }, */
606         { NFSERR_ACCES,         EACCES          },
607         { NFSERR_EXIST,         EEXIST          },
608         { NFSERR_XDEV,          EXDEV           },
609         { NFSERR_NODEV,         ENODEV          },
610         { NFSERR_NOTDIR,        ENOTDIR         },
611         { NFSERR_ISDIR,         EISDIR          },
612         { NFSERR_INVAL,         EINVAL          },
613         { NFSERR_FBIG,          EFBIG           },
614         { NFSERR_NOSPC,         ENOSPC          },
615         { NFSERR_ROFS,          EROFS           },
616         { NFSERR_MLINK,         EMLINK          },
617         { NFSERR_NAMETOOLONG,   ENAMETOOLONG    },
618         { NFSERR_NOTEMPTY,      ENOTEMPTY       },
619         { NFSERR_DQUOT,         EDQUOT          },
620         { NFSERR_STALE,         ESTALE          },
621         { NFSERR_REMOTE,        EREMOTE         },
622 #ifdef EWFLUSH
623         { NFSERR_WFLUSH,        EWFLUSH         },
624 #endif
625         { NFSERR_BADHANDLE,     EBADHANDLE      },
626         { NFSERR_NOT_SYNC,      ENOTSYNC        },
627         { NFSERR_BAD_COOKIE,    EBADCOOKIE      },
628         { NFSERR_NOTSUPP,       ENOTSUPP        },
629         { NFSERR_TOOSMALL,      ETOOSMALL       },
630         { NFSERR_SERVERFAULT,   ESERVERFAULT    },
631         { NFSERR_BADTYPE,       EBADTYPE        },
632         { NFSERR_JUKEBOX,       EJUKEBOX        },
633         { -1,                   EIO             }
634 };
635
636 /*
637  * Convert an NFS error code to a local one.
638  * This one is used jointly by NFSv2 and NFSv3.
639  */
640 int
641 nfs_stat_to_errno(int stat)
642 {
643         int i;
644
645         for (i = 0; nfs_errtbl[i].stat != -1; i++) {
646                 if (nfs_errtbl[i].stat == stat)
647                         return nfs_errtbl[i].errno;
648         }
649         printk(KERN_ERR "nfs_stat_to_errno: bad nfs status return value: %d\n", stat);
650         return nfs_errtbl[i].errno;
651 }
652
653 #ifndef MAX
654 # define MAX(a, b)      (((a) > (b))? (a) : (b))
655 #endif
656
657 #define PROC(proc, argtype, restype, timer)                             \
658 [NFSPROC_##proc] = {                                                    \
659         .p_proc     =  NFSPROC_##proc,                                  \
660         .p_encode   =  (kxdrproc_t) nfs_xdr_##argtype,                  \
661         .p_decode   =  (kxdrproc_t) nfs_xdr_##restype,                  \
662         .p_bufsiz   =  MAX(NFS_##argtype##_sz,NFS_##restype##_sz) << 2, \
663         .p_timer    =  timer                                            \
664         }
665 struct rpc_procinfo     nfs_procedures[] = {
666     PROC(GETATTR,       fhandle,        attrstat, 1),
667     PROC(SETATTR,       sattrargs,      attrstat, 0),
668     PROC(LOOKUP,        diropargs,      diropres, 2),
669     PROC(READLINK,      readlinkargs,   readlinkres, 3),
670     PROC(READ,          readargs,       readres, 3),
671     PROC(WRITE,         writeargs,      writeres, 4),
672     PROC(CREATE,        createargs,     diropres, 0),
673     PROC(REMOVE,        diropargs,      stat, 0),
674     PROC(RENAME,        renameargs,     stat, 0),
675     PROC(LINK,          linkargs,       stat, 0),
676     PROC(SYMLINK,       symlinkargs,    stat, 0),
677     PROC(MKDIR,         createargs,     diropres, 0),
678     PROC(RMDIR,         diropargs,      stat, 0),
679     PROC(READDIR,       readdirargs,    readdirres, 3),
680     PROC(STATFS,        fhandle,        statfsres, 0),
681 };
682
683 struct rpc_version              nfs_version2 = {
684         .number                 = 2,
685         .nrprocs                = sizeof(nfs_procedures)/sizeof(nfs_procedures[0]),
686         .procs                  = nfs_procedures
687 };