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