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