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