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