Merge branch 'upstream-linus' of master.kernel.org:/pub/scm/linux/kernel/git/jgarzik...
[linux-2.6] / 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 /* #define NFS_PARANOIA 1 */
30
31 /* Mapping from NFS error code to "errno" error code. */
32 #define errno_NFSERR_IO         EIO
33
34 /*
35  * Declare the space requirements for NFS arguments and replies as
36  * number of 32bit-words
37  */
38 #define NFS_fhandle_sz          (8)
39 #define NFS_sattr_sz            (8)
40 #define NFS_filename_sz         (1+(NFS2_MAXNAMLEN>>2))
41 #define NFS_path_sz             (1+(NFS2_MAXPATHLEN>>2))
42 #define NFS_fattr_sz            (17)
43 #define NFS_info_sz             (5)
44 #define NFS_entry_sz            (NFS_filename_sz+3)
45
46 #define NFS_diropargs_sz        (NFS_fhandle_sz+NFS_filename_sz)
47 #define NFS_sattrargs_sz        (NFS_fhandle_sz+NFS_sattr_sz)
48 #define NFS_readlinkargs_sz     (NFS_fhandle_sz)
49 #define NFS_readargs_sz         (NFS_fhandle_sz+3)
50 #define NFS_writeargs_sz        (NFS_fhandle_sz+4)
51 #define NFS_createargs_sz       (NFS_diropargs_sz+NFS_sattr_sz)
52 #define NFS_renameargs_sz       (NFS_diropargs_sz+NFS_diropargs_sz)
53 #define NFS_linkargs_sz         (NFS_fhandle_sz+NFS_diropargs_sz)
54 #define NFS_symlinkargs_sz      (NFS_diropargs_sz+1+NFS_sattr_sz)
55 #define NFS_readdirargs_sz      (NFS_fhandle_sz+2)
56
57 #define NFS_attrstat_sz         (1+NFS_fattr_sz)
58 #define NFS_diropres_sz         (1+NFS_fhandle_sz+NFS_fattr_sz)
59 #define NFS_readlinkres_sz      (2)
60 #define NFS_readres_sz          (1+NFS_fattr_sz+1)
61 #define NFS_writeres_sz         (NFS_attrstat_sz)
62 #define NFS_stat_sz             (1)
63 #define NFS_readdirres_sz       (1)
64 #define NFS_statfsres_sz        (1+NFS_info_sz)
65
66 /*
67  * Common NFS XDR functions as inlines
68  */
69 static inline __be32 *
70 xdr_encode_fhandle(__be32 *p, struct nfs_fh *fhandle)
71 {
72         memcpy(p, fhandle->data, NFS2_FHSIZE);
73         return p + XDR_QUADLEN(NFS2_FHSIZE);
74 }
75
76 static inline __be32 *
77 xdr_decode_fhandle(__be32 *p, struct nfs_fh *fhandle)
78 {
79         /* NFSv2 handles have a fixed length */
80         fhandle->size = NFS2_FHSIZE;
81         memcpy(fhandle->data, p, NFS2_FHSIZE);
82         return p + XDR_QUADLEN(NFS2_FHSIZE);
83 }
84
85 static inline __be32*
86 xdr_encode_time(__be32 *p, struct timespec *timep)
87 {
88         *p++ = htonl(timep->tv_sec);
89         /* Convert nanoseconds into microseconds */
90         *p++ = htonl(timep->tv_nsec ? timep->tv_nsec / 1000 : 0);
91         return p;
92 }
93
94 static inline __be32*
95 xdr_encode_current_server_time(__be32 *p, struct timespec *timep)
96 {
97         /*
98          * Passing the invalid value useconds=1000000 is a
99          * Sun convention for "set to current server time".
100          * It's needed to make permissions checks for the
101          * "touch" program across v2 mounts to Solaris and
102          * Irix boxes work correctly. See description of
103          * sattr in section 6.1 of "NFS Illustrated" by
104          * Brent Callaghan, Addison-Wesley, ISBN 0-201-32750-5
105          */
106         *p++ = htonl(timep->tv_sec);
107         *p++ = htonl(1000000);
108         return p;
109 }
110
111 static inline __be32*
112 xdr_decode_time(__be32 *p, struct timespec *timep)
113 {
114         timep->tv_sec = ntohl(*p++);
115         /* Convert microseconds into nanoseconds */
116         timep->tv_nsec = ntohl(*p++) * 1000;
117         return p;
118 }
119
120 static __be32 *
121 xdr_decode_fattr(__be32 *p, struct nfs_fattr *fattr)
122 {
123         u32 rdev;
124         fattr->type = (enum nfs_ftype) ntohl(*p++);
125         fattr->mode = ntohl(*p++);
126         fattr->nlink = ntohl(*p++);
127         fattr->uid = ntohl(*p++);
128         fattr->gid = ntohl(*p++);
129         fattr->size = ntohl(*p++);
130         fattr->du.nfs2.blocksize = ntohl(*p++);
131         rdev = ntohl(*p++);
132         fattr->du.nfs2.blocks = ntohl(*p++);
133         fattr->fsid.major = ntohl(*p++);
134         fattr->fsid.minor = 0;
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 __be32 *
150 xdr_encode_sattr(__be32 *p, struct iattr *attr)
151 {
152         const __be32 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, __be32 *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, __be32 *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, __be32 *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, __be32 *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, __be32 *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, __be32 *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, __be32 *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, __be32 *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, __be32 *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, __be32 *p, struct nfs_symlinkargs *args)
353 {
354         struct xdr_buf *sndbuf = &req->rq_snd_buf;
355         size_t pad;
356
357         p = xdr_encode_fhandle(p, args->fromfh);
358         p = xdr_encode_array(p, args->fromname, args->fromlen);
359         *p++ = htonl(args->pathlen);
360         sndbuf->len = xdr_adjust_iovec(sndbuf->head, p);
361
362         xdr_encode_pages(sndbuf, args->pages, 0, args->pathlen);
363
364         /*
365          * xdr_encode_pages may have added a few bytes to ensure the
366          * pathname ends on a 4-byte boundary.  Start encoding the
367          * attributes after the pad bytes.
368          */
369         pad = sndbuf->tail->iov_len;
370         if (pad > 0)
371                 p++;
372         p = xdr_encode_sattr(p, args->sattr);
373         sndbuf->len += xdr_adjust_iovec(sndbuf->tail, p) - pad;
374         return 0;
375 }
376
377 /*
378  * Encode arguments to readdir call
379  */
380 static int
381 nfs_xdr_readdirargs(struct rpc_rqst *req, __be32 *p, struct nfs_readdirargs *args)
382 {
383         struct rpc_task *task = req->rq_task;
384         struct rpc_auth *auth = task->tk_auth;
385         unsigned int replen;
386         u32 count = args->count;
387
388         p = xdr_encode_fhandle(p, args->fh);
389         *p++ = htonl(args->cookie);
390         *p++ = htonl(count); /* see above */
391         req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
392
393         /* Inline the page array */
394         replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS_readdirres_sz) << 2;
395         xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, 0, count);
396         return 0;
397 }
398
399 /*
400  * Decode the result of a readdir call.
401  * We're not really decoding anymore, we just leave the buffer untouched
402  * and only check that it is syntactically correct.
403  * The real decoding happens in nfs_decode_entry below, called directly
404  * from nfs_readdir for each entry.
405  */
406 static int
407 nfs_xdr_readdirres(struct rpc_rqst *req, __be32 *p, void *dummy)
408 {
409         struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
410         struct kvec *iov = rcvbuf->head;
411         struct page **page;
412         int hdrlen, recvd;
413         int status, nr;
414         unsigned int len, pglen;
415         __be32 *end, *entry, *kaddr;
416
417         if ((status = ntohl(*p++)))
418                 return -nfs_stat_to_errno(status);
419
420         hdrlen = (u8 *) p - (u8 *) iov->iov_base;
421         if (iov->iov_len < hdrlen) {
422                 printk(KERN_WARNING "NFS: READDIR reply header overflowed:"
423                                 "length %d > %Zu\n", hdrlen, iov->iov_len);
424                 return -errno_NFSERR_IO;
425         } else if (iov->iov_len != hdrlen) {
426                 dprintk("NFS: READDIR header is short. iovec will be shifted.\n");
427                 xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen);
428         }
429
430         pglen = rcvbuf->page_len;
431         recvd = rcvbuf->len - hdrlen;
432         if (pglen > recvd)
433                 pglen = recvd;
434         page = rcvbuf->pages;
435         kaddr = p = kmap_atomic(*page, KM_USER0);
436         end = (__be32 *)((char *)p + pglen);
437         entry = p;
438         for (nr = 0; *p++; nr++) {
439                 if (p + 2 > end)
440                         goto short_pkt;
441                 p++; /* fileid */
442                 len = ntohl(*p++);
443                 p += XDR_QUADLEN(len) + 1;      /* name plus cookie */
444                 if (len > NFS2_MAXNAMLEN) {
445                         printk(KERN_WARNING "NFS: giant filename in readdir (len 0x%x)!\n",
446                                                 len);
447                         goto err_unmap;
448                 }
449                 if (p + 2 > end)
450                         goto short_pkt;
451                 entry = p;
452         }
453         if (!nr && (entry[0] != 0 || entry[1] == 0))
454                 goto short_pkt;
455  out:
456         kunmap_atomic(kaddr, KM_USER0);
457         return nr;
458  short_pkt:
459         entry[0] = entry[1] = 0;
460         /* truncate listing ? */
461         if (!nr) {
462                 printk(KERN_NOTICE "NFS: readdir reply truncated!\n");
463                 entry[1] = 1;
464         }
465         goto out;
466 err_unmap:
467         nr = -errno_NFSERR_IO;
468         goto out;
469 }
470
471 __be32 *
472 nfs_decode_dirent(__be32 *p, struct nfs_entry *entry, int plus)
473 {
474         if (!*p++) {
475                 if (!*p)
476                         return ERR_PTR(-EAGAIN);
477                 entry->eof = 1;
478                 return ERR_PTR(-EBADCOOKIE);
479         }
480
481         entry->ino        = ntohl(*p++);
482         entry->len        = ntohl(*p++);
483         entry->name       = (const char *) p;
484         p                += XDR_QUADLEN(entry->len);
485         entry->prev_cookie        = entry->cookie;
486         entry->cookie     = ntohl(*p++);
487         entry->eof        = !p[0] && p[1];
488
489         return p;
490 }
491
492 /*
493  * NFS XDR decode functions
494  */
495 /*
496  * Decode simple status reply
497  */
498 static int
499 nfs_xdr_stat(struct rpc_rqst *req, __be32 *p, void *dummy)
500 {
501         int     status;
502
503         if ((status = ntohl(*p++)) != 0)
504                 status = -nfs_stat_to_errno(status);
505         return status;
506 }
507
508 /*
509  * Decode attrstat reply
510  * GETATTR, SETATTR, WRITE
511  */
512 static int
513 nfs_xdr_attrstat(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
514 {
515         int     status;
516
517         if ((status = ntohl(*p++)))
518                 return -nfs_stat_to_errno(status);
519         xdr_decode_fattr(p, fattr);
520         return 0;
521 }
522
523 /*
524  * Decode diropres reply
525  * LOOKUP, CREATE, MKDIR
526  */
527 static int
528 nfs_xdr_diropres(struct rpc_rqst *req, __be32 *p, struct nfs_diropok *res)
529 {
530         int     status;
531
532         if ((status = ntohl(*p++)))
533                 return -nfs_stat_to_errno(status);
534         p = xdr_decode_fhandle(p, res->fh);
535         xdr_decode_fattr(p, res->fattr);
536         return 0;
537 }
538
539 /*
540  * Encode READLINK args
541  */
542 static int
543 nfs_xdr_readlinkargs(struct rpc_rqst *req, __be32 *p, struct nfs_readlinkargs *args)
544 {
545         struct rpc_auth *auth = req->rq_task->tk_auth;
546         unsigned int replen;
547
548         p = xdr_encode_fhandle(p, args->fh);
549         req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
550
551         /* Inline the page array */
552         replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS_readlinkres_sz) << 2;
553         xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, args->pgbase, args->pglen);
554         return 0;
555 }
556
557 /*
558  * Decode READLINK reply
559  */
560 static int
561 nfs_xdr_readlinkres(struct rpc_rqst *req, __be32 *p, void *dummy)
562 {
563         struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
564         struct kvec *iov = rcvbuf->head;
565         int hdrlen, len, recvd;
566         char    *kaddr;
567         int     status;
568
569         if ((status = ntohl(*p++)))
570                 return -nfs_stat_to_errno(status);
571         /* Convert length of symlink */
572         len = ntohl(*p++);
573         if (len >= rcvbuf->page_len || len <= 0) {
574                 dprintk(KERN_WARNING "nfs: server returned giant symlink!\n");
575                 return -ENAMETOOLONG;
576         }
577         hdrlen = (u8 *) p - (u8 *) iov->iov_base;
578         if (iov->iov_len < hdrlen) {
579                 printk(KERN_WARNING "NFS: READLINK reply header overflowed:"
580                                 "length %d > %Zu\n", hdrlen, iov->iov_len);
581                 return -errno_NFSERR_IO;
582         } else if (iov->iov_len != hdrlen) {
583                 dprintk("NFS: READLINK header is short. iovec will be shifted.\n");
584                 xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen);
585         }
586         recvd = req->rq_rcv_buf.len - hdrlen;
587         if (recvd < len) {
588                 printk(KERN_WARNING "NFS: server cheating in readlink reply: "
589                                 "count %u > recvd %u\n", len, recvd);
590                 return -EIO;
591         }
592
593         /* NULL terminate the string we got */
594         kaddr = (char *)kmap_atomic(rcvbuf->pages[0], KM_USER0);
595         kaddr[len+rcvbuf->page_base] = '\0';
596         kunmap_atomic(kaddr, KM_USER0);
597         return 0;
598 }
599
600 /*
601  * Decode WRITE reply
602  */
603 static int
604 nfs_xdr_writeres(struct rpc_rqst *req, __be32 *p, struct nfs_writeres *res)
605 {
606         res->verf->committed = NFS_FILE_SYNC;
607         return nfs_xdr_attrstat(req, p, res->fattr);
608 }
609
610 /*
611  * Decode STATFS reply
612  */
613 static int
614 nfs_xdr_statfsres(struct rpc_rqst *req, __be32 *p, struct nfs2_fsstat *res)
615 {
616         int     status;
617
618         if ((status = ntohl(*p++)))
619                 return -nfs_stat_to_errno(status);
620
621         res->tsize  = ntohl(*p++);
622         res->bsize  = ntohl(*p++);
623         res->blocks = ntohl(*p++);
624         res->bfree  = ntohl(*p++);
625         res->bavail = ntohl(*p++);
626         return 0;
627 }
628
629 /*
630  * We need to translate between nfs status return values and
631  * the local errno values which may not be the same.
632  */
633 static struct {
634         int stat;
635         int errno;
636 } nfs_errtbl[] = {
637         { NFS_OK,               0               },
638         { NFSERR_PERM,          EPERM           },
639         { NFSERR_NOENT,         ENOENT          },
640         { NFSERR_IO,            errno_NFSERR_IO },
641         { NFSERR_NXIO,          ENXIO           },
642 /*      { NFSERR_EAGAIN,        EAGAIN          }, */
643         { NFSERR_ACCES,         EACCES          },
644         { NFSERR_EXIST,         EEXIST          },
645         { NFSERR_XDEV,          EXDEV           },
646         { NFSERR_NODEV,         ENODEV          },
647         { NFSERR_NOTDIR,        ENOTDIR         },
648         { NFSERR_ISDIR,         EISDIR          },
649         { NFSERR_INVAL,         EINVAL          },
650         { NFSERR_FBIG,          EFBIG           },
651         { NFSERR_NOSPC,         ENOSPC          },
652         { NFSERR_ROFS,          EROFS           },
653         { NFSERR_MLINK,         EMLINK          },
654         { NFSERR_NAMETOOLONG,   ENAMETOOLONG    },
655         { NFSERR_NOTEMPTY,      ENOTEMPTY       },
656         { NFSERR_DQUOT,         EDQUOT          },
657         { NFSERR_STALE,         ESTALE          },
658         { NFSERR_REMOTE,        EREMOTE         },
659 #ifdef EWFLUSH
660         { NFSERR_WFLUSH,        EWFLUSH         },
661 #endif
662         { NFSERR_BADHANDLE,     EBADHANDLE      },
663         { NFSERR_NOT_SYNC,      ENOTSYNC        },
664         { NFSERR_BAD_COOKIE,    EBADCOOKIE      },
665         { NFSERR_NOTSUPP,       ENOTSUPP        },
666         { NFSERR_TOOSMALL,      ETOOSMALL       },
667         { NFSERR_SERVERFAULT,   ESERVERFAULT    },
668         { NFSERR_BADTYPE,       EBADTYPE        },
669         { NFSERR_JUKEBOX,       EJUKEBOX        },
670         { -1,                   EIO             }
671 };
672
673 /*
674  * Convert an NFS error code to a local one.
675  * This one is used jointly by NFSv2 and NFSv3.
676  */
677 int
678 nfs_stat_to_errno(int stat)
679 {
680         int i;
681
682         for (i = 0; nfs_errtbl[i].stat != -1; i++) {
683                 if (nfs_errtbl[i].stat == stat)
684                         return nfs_errtbl[i].errno;
685         }
686         printk(KERN_ERR "nfs_stat_to_errno: bad nfs status return value: %d\n", stat);
687         return nfs_errtbl[i].errno;
688 }
689
690 #ifndef MAX
691 # define MAX(a, b)      (((a) > (b))? (a) : (b))
692 #endif
693
694 #define PROC(proc, argtype, restype, timer)                             \
695 [NFSPROC_##proc] = {                                                    \
696         .p_proc     =  NFSPROC_##proc,                                  \
697         .p_encode   =  (kxdrproc_t) nfs_xdr_##argtype,                  \
698         .p_decode   =  (kxdrproc_t) nfs_xdr_##restype,                  \
699         .p_bufsiz   =  MAX(NFS_##argtype##_sz,NFS_##restype##_sz) << 2, \
700         .p_timer    =  timer,                                           \
701         .p_statidx  =  NFSPROC_##proc,                                  \
702         .p_name     =  #proc,                                           \
703         }
704 struct rpc_procinfo     nfs_procedures[] = {
705     PROC(GETATTR,       fhandle,        attrstat, 1),
706     PROC(SETATTR,       sattrargs,      attrstat, 0),
707     PROC(LOOKUP,        diropargs,      diropres, 2),
708     PROC(READLINK,      readlinkargs,   readlinkres, 3),
709     PROC(READ,          readargs,       readres, 3),
710     PROC(WRITE,         writeargs,      writeres, 4),
711     PROC(CREATE,        createargs,     diropres, 0),
712     PROC(REMOVE,        diropargs,      stat, 0),
713     PROC(RENAME,        renameargs,     stat, 0),
714     PROC(LINK,          linkargs,       stat, 0),
715     PROC(SYMLINK,       symlinkargs,    stat, 0),
716     PROC(MKDIR,         createargs,     diropres, 0),
717     PROC(RMDIR,         diropargs,      stat, 0),
718     PROC(READDIR,       readdirargs,    readdirres, 3),
719     PROC(STATFS,        fhandle,        statfsres, 0),
720 };
721
722 struct rpc_version              nfs_version2 = {
723         .number                 = 2,
724         .nrprocs                = ARRAY_SIZE(nfs_procedures),
725         .procs                  = nfs_procedures
726 };