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