proc tty: switch serial_core to ->proc_fops
[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 = 0;
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
456         /* Make sure the packet actually has a value_follows and EOF entry */
457         if ((entry + 1) > end)
458                 goto short_pkt;
459
460         for (; *p++; nr++) {
461                 if (p + 2 > end)
462                         goto short_pkt;
463                 p++; /* fileid */
464                 len = ntohl(*p++);
465                 p += XDR_QUADLEN(len) + 1;      /* name plus cookie */
466                 if (len > NFS2_MAXNAMLEN) {
467                         dprintk("NFS: giant filename in readdir (len 0x%x)!\n",
468                                                 len);
469                         goto err_unmap;
470                 }
471                 if (p + 2 > end)
472                         goto short_pkt;
473                 entry = p;
474         }
475
476         /*
477          * Apparently some server sends responses that are a valid size, but
478          * contain no entries, and have value_follows==0 and EOF==0. For
479          * those, just set the EOF marker.
480          */
481         if (!nr && entry[1] == 0) {
482                 dprintk("NFS: readdir reply truncated!\n");
483                 entry[1] = 1;
484         }
485  out:
486         kunmap_atomic(kaddr, KM_USER0);
487         return nr;
488  short_pkt:
489         /*
490          * When we get a short packet there are 2 possibilities. We can
491          * return an error, or fix up the response to look like a valid
492          * response and return what we have so far. If there are no
493          * entries and the packet was short, then return -EIO. If there
494          * are valid entries in the response, return them and pretend that
495          * the call was successful, but incomplete. The caller can retry the
496          * readdir starting at the last cookie.
497          */
498         entry[0] = entry[1] = 0;
499         if (!nr)
500                 nr = -errno_NFSERR_IO;
501         goto out;
502 err_unmap:
503         nr = -errno_NFSERR_IO;
504         goto out;
505 }
506
507 __be32 *
508 nfs_decode_dirent(__be32 *p, struct nfs_entry *entry, int plus)
509 {
510         if (!*p++) {
511                 if (!*p)
512                         return ERR_PTR(-EAGAIN);
513                 entry->eof = 1;
514                 return ERR_PTR(-EBADCOOKIE);
515         }
516
517         entry->ino        = ntohl(*p++);
518         entry->len        = ntohl(*p++);
519         entry->name       = (const char *) p;
520         p                += XDR_QUADLEN(entry->len);
521         entry->prev_cookie        = entry->cookie;
522         entry->cookie     = ntohl(*p++);
523         entry->eof        = !p[0] && p[1];
524
525         return p;
526 }
527
528 /*
529  * NFS XDR decode functions
530  */
531 /*
532  * Decode simple status reply
533  */
534 static int
535 nfs_xdr_stat(struct rpc_rqst *req, __be32 *p, void *dummy)
536 {
537         int     status;
538
539         if ((status = ntohl(*p++)) != 0)
540                 status = nfs_stat_to_errno(status);
541         return status;
542 }
543
544 /*
545  * Decode attrstat reply
546  * GETATTR, SETATTR, WRITE
547  */
548 static int
549 nfs_xdr_attrstat(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
550 {
551         int     status;
552
553         if ((status = ntohl(*p++)))
554                 return nfs_stat_to_errno(status);
555         xdr_decode_fattr(p, fattr);
556         return 0;
557 }
558
559 /*
560  * Decode diropres reply
561  * LOOKUP, CREATE, MKDIR
562  */
563 static int
564 nfs_xdr_diropres(struct rpc_rqst *req, __be32 *p, struct nfs_diropok *res)
565 {
566         int     status;
567
568         if ((status = ntohl(*p++)))
569                 return nfs_stat_to_errno(status);
570         p = xdr_decode_fhandle(p, res->fh);
571         xdr_decode_fattr(p, res->fattr);
572         return 0;
573 }
574
575 /*
576  * Encode READLINK args
577  */
578 static int
579 nfs_xdr_readlinkargs(struct rpc_rqst *req, __be32 *p, struct nfs_readlinkargs *args)
580 {
581         struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth;
582         unsigned int replen;
583
584         p = xdr_encode_fhandle(p, args->fh);
585         req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
586
587         /* Inline the page array */
588         replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS_readlinkres_sz) << 2;
589         xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, args->pgbase, args->pglen);
590         return 0;
591 }
592
593 /*
594  * Decode READLINK reply
595  */
596 static int
597 nfs_xdr_readlinkres(struct rpc_rqst *req, __be32 *p, void *dummy)
598 {
599         struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
600         struct kvec *iov = rcvbuf->head;
601         size_t hdrlen;
602         u32 len, recvd;
603         char    *kaddr;
604         int     status;
605
606         if ((status = ntohl(*p++)))
607                 return nfs_stat_to_errno(status);
608         /* Convert length of symlink */
609         len = ntohl(*p++);
610         if (len >= rcvbuf->page_len) {
611                 dprintk("nfs: server returned giant symlink!\n");
612                 return -ENAMETOOLONG;
613         }
614         hdrlen = (u8 *) p - (u8 *) iov->iov_base;
615         if (iov->iov_len < hdrlen) {
616                 dprintk("NFS: READLINK reply header overflowed:"
617                                 "length %Zu > %Zu\n", hdrlen, iov->iov_len);
618                 return -errno_NFSERR_IO;
619         } else if (iov->iov_len != hdrlen) {
620                 dprintk("NFS: READLINK header is short. iovec will be shifted.\n");
621                 xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen);
622         }
623         recvd = req->rq_rcv_buf.len - hdrlen;
624         if (recvd < len) {
625                 dprintk("NFS: server cheating in readlink reply: "
626                                 "count %u > recvd %u\n", len, recvd);
627                 return -EIO;
628         }
629
630         /* NULL terminate the string we got */
631         kaddr = (char *)kmap_atomic(rcvbuf->pages[0], KM_USER0);
632         kaddr[len+rcvbuf->page_base] = '\0';
633         kunmap_atomic(kaddr, KM_USER0);
634         return 0;
635 }
636
637 /*
638  * Decode WRITE reply
639  */
640 static int
641 nfs_xdr_writeres(struct rpc_rqst *req, __be32 *p, struct nfs_writeres *res)
642 {
643         res->verf->committed = NFS_FILE_SYNC;
644         return nfs_xdr_attrstat(req, p, res->fattr);
645 }
646
647 /*
648  * Decode STATFS reply
649  */
650 static int
651 nfs_xdr_statfsres(struct rpc_rqst *req, __be32 *p, struct nfs2_fsstat *res)
652 {
653         int     status;
654
655         if ((status = ntohl(*p++)))
656                 return nfs_stat_to_errno(status);
657
658         res->tsize  = ntohl(*p++);
659         res->bsize  = ntohl(*p++);
660         res->blocks = ntohl(*p++);
661         res->bfree  = ntohl(*p++);
662         res->bavail = ntohl(*p++);
663         return 0;
664 }
665
666 /*
667  * We need to translate between nfs status return values and
668  * the local errno values which may not be the same.
669  */
670 static struct {
671         int stat;
672         int errno;
673 } nfs_errtbl[] = {
674         { NFS_OK,               0               },
675         { NFSERR_PERM,          -EPERM          },
676         { NFSERR_NOENT,         -ENOENT         },
677         { NFSERR_IO,            -errno_NFSERR_IO},
678         { NFSERR_NXIO,          -ENXIO          },
679 /*      { NFSERR_EAGAIN,        -EAGAIN         }, */
680         { NFSERR_ACCES,         -EACCES         },
681         { NFSERR_EXIST,         -EEXIST         },
682         { NFSERR_XDEV,          -EXDEV          },
683         { NFSERR_NODEV,         -ENODEV         },
684         { NFSERR_NOTDIR,        -ENOTDIR        },
685         { NFSERR_ISDIR,         -EISDIR         },
686         { NFSERR_INVAL,         -EINVAL         },
687         { NFSERR_FBIG,          -EFBIG          },
688         { NFSERR_NOSPC,         -ENOSPC         },
689         { NFSERR_ROFS,          -EROFS          },
690         { NFSERR_MLINK,         -EMLINK         },
691         { NFSERR_NAMETOOLONG,   -ENAMETOOLONG   },
692         { NFSERR_NOTEMPTY,      -ENOTEMPTY      },
693         { NFSERR_DQUOT,         -EDQUOT         },
694         { NFSERR_STALE,         -ESTALE         },
695         { NFSERR_REMOTE,        -EREMOTE        },
696 #ifdef EWFLUSH
697         { NFSERR_WFLUSH,        -EWFLUSH        },
698 #endif
699         { NFSERR_BADHANDLE,     -EBADHANDLE     },
700         { NFSERR_NOT_SYNC,      -ENOTSYNC       },
701         { NFSERR_BAD_COOKIE,    -EBADCOOKIE     },
702         { NFSERR_NOTSUPP,       -ENOTSUPP       },
703         { NFSERR_TOOSMALL,      -ETOOSMALL      },
704         { NFSERR_SERVERFAULT,   -ESERVERFAULT   },
705         { NFSERR_BADTYPE,       -EBADTYPE       },
706         { NFSERR_JUKEBOX,       -EJUKEBOX       },
707         { -1,                   -EIO            }
708 };
709
710 /*
711  * Convert an NFS error code to a local one.
712  * This one is used jointly by NFSv2 and NFSv3.
713  */
714 int
715 nfs_stat_to_errno(int stat)
716 {
717         int i;
718
719         for (i = 0; nfs_errtbl[i].stat != -1; i++) {
720                 if (nfs_errtbl[i].stat == stat)
721                         return nfs_errtbl[i].errno;
722         }
723         dprintk("nfs_stat_to_errno: bad nfs status return value: %d\n", stat);
724         return nfs_errtbl[i].errno;
725 }
726
727 #define PROC(proc, argtype, restype, timer)                             \
728 [NFSPROC_##proc] = {                                                    \
729         .p_proc     =  NFSPROC_##proc,                                  \
730         .p_encode   =  (kxdrproc_t) nfs_xdr_##argtype,                  \
731         .p_decode   =  (kxdrproc_t) nfs_xdr_##restype,                  \
732         .p_arglen   =  NFS_##argtype##_sz,                              \
733         .p_replen   =  NFS_##restype##_sz,                              \
734         .p_timer    =  timer,                                           \
735         .p_statidx  =  NFSPROC_##proc,                                  \
736         .p_name     =  #proc,                                           \
737         }
738 struct rpc_procinfo     nfs_procedures[] = {
739     PROC(GETATTR,       fhandle,        attrstat, 1),
740     PROC(SETATTR,       sattrargs,      attrstat, 0),
741     PROC(LOOKUP,        diropargs,      diropres, 2),
742     PROC(READLINK,      readlinkargs,   readlinkres, 3),
743     PROC(READ,          readargs,       readres, 3),
744     PROC(WRITE,         writeargs,      writeres, 4),
745     PROC(CREATE,        createargs,     diropres, 0),
746     PROC(REMOVE,        removeargs,     stat, 0),
747     PROC(RENAME,        renameargs,     stat, 0),
748     PROC(LINK,          linkargs,       stat, 0),
749     PROC(SYMLINK,       symlinkargs,    stat, 0),
750     PROC(MKDIR,         createargs,     diropres, 0),
751     PROC(RMDIR,         diropargs,      stat, 0),
752     PROC(READDIR,       readdirargs,    readdirres, 3),
753     PROC(STATFS,        fhandle,        statfsres, 0),
754 };
755
756 struct rpc_version              nfs_version2 = {
757         .number                 = 2,
758         .nrprocs                = ARRAY_SIZE(nfs_procedures),
759         .procs                  = nfs_procedures
760 };