Merge branch 'devel' into for-linus
[sfrench/cifs-2.6.git] / fs / nfs / nfs2xdr.c
1 /*
2  * linux/fs/nfs/nfs2xdr.c
3  *
4  * XDR functions to encode/decode NFS RPC arguments and results.
5  *
6  * Copyright (C) 1992, 1993, 1994  Rick Sladkey
7  * Copyright (C) 1996 Olaf Kirch
8  * 04 Aug 1998  Ion Badulescu <ionut@cs.columbia.edu>
9  *              FIFO's need special handling in NFSv2
10  */
11
12 #include <linux/param.h>
13 #include <linux/time.h>
14 #include <linux/mm.h>
15 #include <linux/slab.h>
16 #include <linux/utsname.h>
17 #include <linux/errno.h>
18 #include <linux/string.h>
19 #include <linux/in.h>
20 #include <linux/pagemap.h>
21 #include <linux/proc_fs.h>
22 #include <linux/sunrpc/clnt.h>
23 #include <linux/nfs.h>
24 #include <linux/nfs2.h>
25 #include <linux/nfs_fs.h>
26 #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, type;
124         type = 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_V2;
140         fattr->rdev = new_decode_dev(rdev);
141         if (type == NFCHR && rdev == NFS2_FIFO_DEV) {
142                 fattr->mode = (fattr->mode & ~S_IFMT) | S_IFIFO;
143                 fattr->rdev = 0;
144         }
145         return p;
146 }
147
148 static inline __be32 *
149 xdr_encode_sattr(__be32 *p, struct iattr *attr)
150 {
151         const __be32 not_set = __constant_htonl(0xFFFFFFFF);
152
153         *p++ = (attr->ia_valid & ATTR_MODE) ? htonl(attr->ia_mode) : not_set;
154         *p++ = (attr->ia_valid & ATTR_UID) ? htonl(attr->ia_uid) : not_set;
155         *p++ = (attr->ia_valid & ATTR_GID) ? htonl(attr->ia_gid) : not_set;
156         *p++ = (attr->ia_valid & ATTR_SIZE) ? htonl(attr->ia_size) : not_set;
157
158         if (attr->ia_valid & ATTR_ATIME_SET) {
159                 p = xdr_encode_time(p, &attr->ia_atime);
160         } else if (attr->ia_valid & ATTR_ATIME) {
161                 p = xdr_encode_current_server_time(p, &attr->ia_atime);
162         } else {
163                 *p++ = not_set;
164                 *p++ = not_set;
165         }
166
167         if (attr->ia_valid & ATTR_MTIME_SET) {
168                 p = xdr_encode_time(p, &attr->ia_mtime);
169         } else if (attr->ia_valid & ATTR_MTIME) {
170                 p = xdr_encode_current_server_time(p, &attr->ia_mtime);
171         } else {
172                 *p++ = not_set; 
173                 *p++ = not_set;
174         }
175         return p;
176 }
177
178 /*
179  * NFS encode functions
180  */
181 /*
182  * Encode file handle argument
183  * GETATTR, READLINK, STATFS
184  */
185 static int
186 nfs_xdr_fhandle(struct rpc_rqst *req, __be32 *p, struct nfs_fh *fh)
187 {
188         p = xdr_encode_fhandle(p, fh);
189         req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
190         return 0;
191 }
192
193 /*
194  * Encode SETATTR arguments
195  */
196 static int
197 nfs_xdr_sattrargs(struct rpc_rqst *req, __be32 *p, struct nfs_sattrargs *args)
198 {
199         p = xdr_encode_fhandle(p, args->fh);
200         p = xdr_encode_sattr(p, args->sattr);
201         req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
202         return 0;
203 }
204
205 /*
206  * Encode directory ops argument
207  * LOOKUP, RMDIR
208  */
209 static int
210 nfs_xdr_diropargs(struct rpc_rqst *req, __be32 *p, struct nfs_diropargs *args)
211 {
212         p = xdr_encode_fhandle(p, args->fh);
213         p = xdr_encode_array(p, args->name, args->len);
214         req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
215         return 0;
216 }
217
218 /*
219  * Encode REMOVE argument
220  */
221 static int
222 nfs_xdr_removeargs(struct rpc_rqst *req, __be32 *p, const struct nfs_removeargs *args)
223 {
224         p = xdr_encode_fhandle(p, args->fh);
225         p = xdr_encode_array(p, args->name.name, args->name.len);
226         req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
227         return 0;
228 }
229
230 /*
231  * Arguments to a READ call. Since we read data directly into the page
232  * cache, we also set up the reply iovec here so that iov[1] points
233  * exactly to the page we want to fetch.
234  */
235 static int
236 nfs_xdr_readargs(struct rpc_rqst *req, __be32 *p, struct nfs_readargs *args)
237 {
238         struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth;
239         unsigned int replen;
240         u32 offset = (u32)args->offset;
241         u32 count = args->count;
242
243         p = xdr_encode_fhandle(p, args->fh);
244         *p++ = htonl(offset);
245         *p++ = htonl(count);
246         *p++ = htonl(count);
247         req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
248
249         /* Inline the page array */
250         replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS_readres_sz) << 2;
251         xdr_inline_pages(&req->rq_rcv_buf, replen,
252                          args->pages, args->pgbase, count);
253         req->rq_rcv_buf.flags |= XDRBUF_READ;
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         size_t hdrlen;
265         u32 count, recvd;
266         int status;
267
268         if ((status = ntohl(*p++)))
269                 return nfs_stat_to_errno(status);
270         p = xdr_decode_fattr(p, res->fattr);
271
272         count = ntohl(*p++);
273         res->eof = 0;
274         hdrlen = (u8 *) p - (u8 *) iov->iov_base;
275         if (iov->iov_len < hdrlen) {
276                 dprintk("NFS: READ reply header overflowed:"
277                                 "length %Zu > %Zu\n", hdrlen, iov->iov_len);
278                 return -errno_NFSERR_IO;
279         } else if (iov->iov_len != hdrlen) {
280                 dprintk("NFS: READ header is short. iovec will be shifted.\n");
281                 xdr_shift_buf(&req->rq_rcv_buf, iov->iov_len - hdrlen);
282         }
283
284         recvd = req->rq_rcv_buf.len - hdrlen;
285         if (count > recvd) {
286                 dprintk("NFS: server cheating in read reply: "
287                         "count %u > recvd %u\n", count, recvd);
288                 count = recvd;
289         }
290
291         dprintk("RPC:      readres OK count %u\n", count);
292         if (count < res->count)
293                 res->count = count;
294
295         return count;
296 }
297
298
299 /*
300  * Write arguments. Splice the buffer to be written into the iovec.
301  */
302 static int
303 nfs_xdr_writeargs(struct rpc_rqst *req, __be32 *p, struct nfs_writeargs *args)
304 {
305         struct xdr_buf *sndbuf = &req->rq_snd_buf;
306         u32 offset = (u32)args->offset;
307         u32 count = args->count;
308
309         p = xdr_encode_fhandle(p, args->fh);
310         *p++ = htonl(offset);
311         *p++ = htonl(offset);
312         *p++ = htonl(count);
313         *p++ = htonl(count);
314         sndbuf->len = xdr_adjust_iovec(sndbuf->head, p);
315
316         /* Copy the page array */
317         xdr_encode_pages(sndbuf, args->pages, args->pgbase, count);
318         sndbuf->flags |= XDRBUF_WRITE;
319         return 0;
320 }
321
322 /*
323  * Encode create arguments
324  * CREATE, MKDIR
325  */
326 static int
327 nfs_xdr_createargs(struct rpc_rqst *req, __be32 *p, struct nfs_createargs *args)
328 {
329         p = xdr_encode_fhandle(p, args->fh);
330         p = xdr_encode_array(p, args->name, args->len);
331         p = xdr_encode_sattr(p, args->sattr);
332         req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
333         return 0;
334 }
335
336 /*
337  * Encode RENAME arguments
338  */
339 static int
340 nfs_xdr_renameargs(struct rpc_rqst *req, __be32 *p, struct nfs_renameargs *args)
341 {
342         p = xdr_encode_fhandle(p, args->fromfh);
343         p = xdr_encode_array(p, args->fromname, args->fromlen);
344         p = xdr_encode_fhandle(p, args->tofh);
345         p = xdr_encode_array(p, args->toname, args->tolen);
346         req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
347         return 0;
348 }
349
350 /*
351  * Encode LINK arguments
352  */
353 static int
354 nfs_xdr_linkargs(struct rpc_rqst *req, __be32 *p, struct nfs_linkargs *args)
355 {
356         p = xdr_encode_fhandle(p, args->fromfh);
357         p = xdr_encode_fhandle(p, args->tofh);
358         p = xdr_encode_array(p, args->toname, args->tolen);
359         req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
360         return 0;
361 }
362
363 /*
364  * Encode SYMLINK arguments
365  */
366 static int
367 nfs_xdr_symlinkargs(struct rpc_rqst *req, __be32 *p, struct nfs_symlinkargs *args)
368 {
369         struct xdr_buf *sndbuf = &req->rq_snd_buf;
370         size_t pad;
371
372         p = xdr_encode_fhandle(p, args->fromfh);
373         p = xdr_encode_array(p, args->fromname, args->fromlen);
374         *p++ = htonl(args->pathlen);
375         sndbuf->len = xdr_adjust_iovec(sndbuf->head, p);
376
377         xdr_encode_pages(sndbuf, args->pages, 0, args->pathlen);
378
379         /*
380          * xdr_encode_pages may have added a few bytes to ensure the
381          * pathname ends on a 4-byte boundary.  Start encoding the
382          * attributes after the pad bytes.
383          */
384         pad = sndbuf->tail->iov_len;
385         if (pad > 0)
386                 p++;
387         p = xdr_encode_sattr(p, args->sattr);
388         sndbuf->len += xdr_adjust_iovec(sndbuf->tail, p) - pad;
389         return 0;
390 }
391
392 /*
393  * Encode arguments to readdir call
394  */
395 static int
396 nfs_xdr_readdirargs(struct rpc_rqst *req, __be32 *p, struct nfs_readdirargs *args)
397 {
398         struct rpc_task *task = req->rq_task;
399         struct rpc_auth *auth = task->tk_msg.rpc_cred->cr_auth;
400         unsigned int replen;
401         u32 count = args->count;
402
403         p = xdr_encode_fhandle(p, args->fh);
404         *p++ = htonl(args->cookie);
405         *p++ = htonl(count); /* see above */
406         req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
407
408         /* Inline the page array */
409         replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS_readdirres_sz) << 2;
410         xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, 0, count);
411         return 0;
412 }
413
414 /*
415  * Decode the result of a readdir call.
416  * We're not really decoding anymore, we just leave the buffer untouched
417  * and only check that it is syntactically correct.
418  * The real decoding happens in nfs_decode_entry below, called directly
419  * from nfs_readdir for each entry.
420  */
421 static int
422 nfs_xdr_readdirres(struct rpc_rqst *req, __be32 *p, void *dummy)
423 {
424         struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
425         struct kvec *iov = rcvbuf->head;
426         struct page **page;
427         size_t hdrlen;
428         unsigned int pglen, recvd;
429         u32 len;
430         int status, nr = 0;
431         __be32 *end, *entry, *kaddr;
432
433         if ((status = ntohl(*p++)))
434                 return nfs_stat_to_errno(status);
435
436         hdrlen = (u8 *) p - (u8 *) iov->iov_base;
437         if (iov->iov_len < hdrlen) {
438                 dprintk("NFS: READDIR reply header overflowed:"
439                                 "length %Zu > %Zu\n", hdrlen, iov->iov_len);
440                 return -errno_NFSERR_IO;
441         } else if (iov->iov_len != hdrlen) {
442                 dprintk("NFS: READDIR header is short. iovec will be shifted.\n");
443                 xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen);
444         }
445
446         pglen = rcvbuf->page_len;
447         recvd = rcvbuf->len - hdrlen;
448         if (pglen > recvd)
449                 pglen = recvd;
450         page = rcvbuf->pages;
451         kaddr = p = kmap_atomic(*page, KM_USER0);
452         end = (__be32 *)((char *)p + pglen);
453         entry = p;
454
455         /* Make sure the packet actually has a value_follows and EOF entry */
456         if ((entry + 1) > end)
457                 goto short_pkt;
458
459         for (; *p++; nr++) {
460                 if (p + 2 > end)
461                         goto short_pkt;
462                 p++; /* fileid */
463                 len = ntohl(*p++);
464                 p += XDR_QUADLEN(len) + 1;      /* name plus cookie */
465                 if (len > NFS2_MAXNAMLEN) {
466                         dprintk("NFS: giant filename in readdir (len 0x%x)!\n",
467                                                 len);
468                         goto err_unmap;
469                 }
470                 if (p + 2 > end)
471                         goto short_pkt;
472                 entry = p;
473         }
474
475         /*
476          * Apparently some server sends responses that are a valid size, but
477          * contain no entries, and have value_follows==0 and EOF==0. For
478          * those, just set the EOF marker.
479          */
480         if (!nr && entry[1] == 0) {
481                 dprintk("NFS: readdir reply truncated!\n");
482                 entry[1] = 1;
483         }
484  out:
485         kunmap_atomic(kaddr, KM_USER0);
486         return nr;
487  short_pkt:
488         /*
489          * When we get a short packet there are 2 possibilities. We can
490          * return an error, or fix up the response to look like a valid
491          * response and return what we have so far. If there are no
492          * entries and the packet was short, then return -EIO. If there
493          * are valid entries in the response, return them and pretend that
494          * the call was successful, but incomplete. The caller can retry the
495          * readdir starting at the last cookie.
496          */
497         entry[0] = entry[1] = 0;
498         if (!nr)
499                 nr = -errno_NFSERR_IO;
500         goto out;
501 err_unmap:
502         nr = -errno_NFSERR_IO;
503         goto out;
504 }
505
506 __be32 *
507 nfs_decode_dirent(__be32 *p, struct nfs_entry *entry, int plus)
508 {
509         if (!*p++) {
510                 if (!*p)
511                         return ERR_PTR(-EAGAIN);
512                 entry->eof = 1;
513                 return ERR_PTR(-EBADCOOKIE);
514         }
515
516         entry->ino        = ntohl(*p++);
517         entry->len        = ntohl(*p++);
518         entry->name       = (const char *) p;
519         p                += XDR_QUADLEN(entry->len);
520         entry->prev_cookie        = entry->cookie;
521         entry->cookie     = ntohl(*p++);
522         entry->eof        = !p[0] && p[1];
523
524         return p;
525 }
526
527 /*
528  * NFS XDR decode functions
529  */
530 /*
531  * Decode simple status reply
532  */
533 static int
534 nfs_xdr_stat(struct rpc_rqst *req, __be32 *p, void *dummy)
535 {
536         int     status;
537
538         if ((status = ntohl(*p++)) != 0)
539                 status = nfs_stat_to_errno(status);
540         return status;
541 }
542
543 /*
544  * Decode attrstat reply
545  * GETATTR, SETATTR, WRITE
546  */
547 static int
548 nfs_xdr_attrstat(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
549 {
550         int     status;
551
552         if ((status = ntohl(*p++)))
553                 return nfs_stat_to_errno(status);
554         xdr_decode_fattr(p, fattr);
555         return 0;
556 }
557
558 /*
559  * Decode diropres reply
560  * LOOKUP, CREATE, MKDIR
561  */
562 static int
563 nfs_xdr_diropres(struct rpc_rqst *req, __be32 *p, struct nfs_diropok *res)
564 {
565         int     status;
566
567         if ((status = ntohl(*p++)))
568                 return nfs_stat_to_errno(status);
569         p = xdr_decode_fhandle(p, res->fh);
570         xdr_decode_fattr(p, res->fattr);
571         return 0;
572 }
573
574 /*
575  * Encode READLINK args
576  */
577 static int
578 nfs_xdr_readlinkargs(struct rpc_rqst *req, __be32 *p, struct nfs_readlinkargs *args)
579 {
580         struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth;
581         unsigned int replen;
582
583         p = xdr_encode_fhandle(p, args->fh);
584         req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
585
586         /* Inline the page array */
587         replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS_readlinkres_sz) << 2;
588         xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, args->pgbase, args->pglen);
589         return 0;
590 }
591
592 /*
593  * Decode READLINK reply
594  */
595 static int
596 nfs_xdr_readlinkres(struct rpc_rqst *req, __be32 *p, void *dummy)
597 {
598         struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
599         struct kvec *iov = rcvbuf->head;
600         size_t hdrlen;
601         u32 len, recvd;
602         char    *kaddr;
603         int     status;
604
605         if ((status = ntohl(*p++)))
606                 return nfs_stat_to_errno(status);
607         /* Convert length of symlink */
608         len = ntohl(*p++);
609         if (len >= rcvbuf->page_len) {
610                 dprintk("nfs: server returned giant symlink!\n");
611                 return -ENAMETOOLONG;
612         }
613         hdrlen = (u8 *) p - (u8 *) iov->iov_base;
614         if (iov->iov_len < hdrlen) {
615                 dprintk("NFS: READLINK reply header overflowed:"
616                                 "length %Zu > %Zu\n", hdrlen, iov->iov_len);
617                 return -errno_NFSERR_IO;
618         } else if (iov->iov_len != hdrlen) {
619                 dprintk("NFS: READLINK header is short. iovec will be shifted.\n");
620                 xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen);
621         }
622         recvd = req->rq_rcv_buf.len - hdrlen;
623         if (recvd < len) {
624                 dprintk("NFS: server cheating in readlink reply: "
625                                 "count %u > recvd %u\n", len, recvd);
626                 return -EIO;
627         }
628
629         /* NULL terminate the string we got */
630         kaddr = (char *)kmap_atomic(rcvbuf->pages[0], KM_USER0);
631         kaddr[len+rcvbuf->page_base] = '\0';
632         kunmap_atomic(kaddr, KM_USER0);
633         return 0;
634 }
635
636 /*
637  * Decode WRITE reply
638  */
639 static int
640 nfs_xdr_writeres(struct rpc_rqst *req, __be32 *p, struct nfs_writeres *res)
641 {
642         res->verf->committed = NFS_FILE_SYNC;
643         return nfs_xdr_attrstat(req, p, res->fattr);
644 }
645
646 /*
647  * Decode STATFS reply
648  */
649 static int
650 nfs_xdr_statfsres(struct rpc_rqst *req, __be32 *p, struct nfs2_fsstat *res)
651 {
652         int     status;
653
654         if ((status = ntohl(*p++)))
655                 return nfs_stat_to_errno(status);
656
657         res->tsize  = ntohl(*p++);
658         res->bsize  = ntohl(*p++);
659         res->blocks = ntohl(*p++);
660         res->bfree  = ntohl(*p++);
661         res->bavail = ntohl(*p++);
662         return 0;
663 }
664
665 /*
666  * We need to translate between nfs status return values and
667  * the local errno values which may not be the same.
668  */
669 static struct {
670         int stat;
671         int errno;
672 } nfs_errtbl[] = {
673         { NFS_OK,               0               },
674         { NFSERR_PERM,          -EPERM          },
675         { NFSERR_NOENT,         -ENOENT         },
676         { NFSERR_IO,            -errno_NFSERR_IO},
677         { NFSERR_NXIO,          -ENXIO          },
678 /*      { NFSERR_EAGAIN,        -EAGAIN         }, */
679         { NFSERR_ACCES,         -EACCES         },
680         { NFSERR_EXIST,         -EEXIST         },
681         { NFSERR_XDEV,          -EXDEV          },
682         { NFSERR_NODEV,         -ENODEV         },
683         { NFSERR_NOTDIR,        -ENOTDIR        },
684         { NFSERR_ISDIR,         -EISDIR         },
685         { NFSERR_INVAL,         -EINVAL         },
686         { NFSERR_FBIG,          -EFBIG          },
687         { NFSERR_NOSPC,         -ENOSPC         },
688         { NFSERR_ROFS,          -EROFS          },
689         { NFSERR_MLINK,         -EMLINK         },
690         { NFSERR_NAMETOOLONG,   -ENAMETOOLONG   },
691         { NFSERR_NOTEMPTY,      -ENOTEMPTY      },
692         { NFSERR_DQUOT,         -EDQUOT         },
693         { NFSERR_STALE,         -ESTALE         },
694         { NFSERR_REMOTE,        -EREMOTE        },
695 #ifdef EWFLUSH
696         { NFSERR_WFLUSH,        -EWFLUSH        },
697 #endif
698         { NFSERR_BADHANDLE,     -EBADHANDLE     },
699         { NFSERR_NOT_SYNC,      -ENOTSYNC       },
700         { NFSERR_BAD_COOKIE,    -EBADCOOKIE     },
701         { NFSERR_NOTSUPP,       -ENOTSUPP       },
702         { NFSERR_TOOSMALL,      -ETOOSMALL      },
703         { NFSERR_SERVERFAULT,   -ESERVERFAULT   },
704         { NFSERR_BADTYPE,       -EBADTYPE       },
705         { NFSERR_JUKEBOX,       -EJUKEBOX       },
706         { -1,                   -EIO            }
707 };
708
709 /*
710  * Convert an NFS error code to a local one.
711  * This one is used jointly by NFSv2 and NFSv3.
712  */
713 int
714 nfs_stat_to_errno(int stat)
715 {
716         int i;
717
718         for (i = 0; nfs_errtbl[i].stat != -1; i++) {
719                 if (nfs_errtbl[i].stat == stat)
720                         return nfs_errtbl[i].errno;
721         }
722         dprintk("nfs_stat_to_errno: bad nfs status return value: %d\n", stat);
723         return nfs_errtbl[i].errno;
724 }
725
726 #define PROC(proc, argtype, restype, timer)                             \
727 [NFSPROC_##proc] = {                                                    \
728         .p_proc     =  NFSPROC_##proc,                                  \
729         .p_encode   =  (kxdrproc_t) nfs_xdr_##argtype,                  \
730         .p_decode   =  (kxdrproc_t) nfs_xdr_##restype,                  \
731         .p_arglen   =  NFS_##argtype##_sz,                              \
732         .p_replen   =  NFS_##restype##_sz,                              \
733         .p_timer    =  timer,                                           \
734         .p_statidx  =  NFSPROC_##proc,                                  \
735         .p_name     =  #proc,                                           \
736         }
737 struct rpc_procinfo     nfs_procedures[] = {
738     PROC(GETATTR,       fhandle,        attrstat, 1),
739     PROC(SETATTR,       sattrargs,      attrstat, 0),
740     PROC(LOOKUP,        diropargs,      diropres, 2),
741     PROC(READLINK,      readlinkargs,   readlinkres, 3),
742     PROC(READ,          readargs,       readres, 3),
743     PROC(WRITE,         writeargs,      writeres, 4),
744     PROC(CREATE,        createargs,     diropres, 0),
745     PROC(REMOVE,        removeargs,     stat, 0),
746     PROC(RENAME,        renameargs,     stat, 0),
747     PROC(LINK,          linkargs,       stat, 0),
748     PROC(SYMLINK,       symlinkargs,    stat, 0),
749     PROC(MKDIR,         createargs,     diropres, 0),
750     PROC(RMDIR,         diropargs,      stat, 0),
751     PROC(READDIR,       readdirargs,    readdirres, 3),
752     PROC(STATFS,        fhandle,        statfsres, 0),
753 };
754
755 struct rpc_version              nfs_version2 = {
756         .number                 = 2,
757         .nrprocs                = ARRAY_SIZE(nfs_procedures),
758         .procs                  = nfs_procedures
759 };