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