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