[MTD] [MAPS] ck804xrom warning fix
[linux-2.6/openmoko-kernel.git] / fs / nfs / nfs2xdr.c
blob3be4e72a0227e71030709b019dd35db28897a34e
1 /*
2 * linux/fs/nfs/nfs2xdr.c
4 * XDR functions to encode/decode NFS RPC arguments and results.
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
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"
28 #define NFSDBG_FACILITY NFSDBG_XDR
29 /* #define NFS_PARANOIA 1 */
31 /* Mapping from NFS error code to "errno" error code. */
32 #define errno_NFSERR_IO EIO
35 * Declare the space requirements for NFS arguments and replies as
36 * number of 32bit-words
38 #define NFS_fhandle_sz (8)
39 #define NFS_sattr_sz (8)
40 #define NFS_filename_sz (1+(NFS2_MAXNAMLEN>>2))
41 #define NFS_path_sz (1+(NFS2_MAXPATHLEN>>2))
42 #define NFS_fattr_sz (17)
43 #define NFS_info_sz (5)
44 #define NFS_entry_sz (NFS_filename_sz+3)
46 #define NFS_diropargs_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)
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)
67 * Common NFS XDR functions as inlines
69 static inline __be32 *
70 xdr_encode_fhandle(__be32 *p, struct nfs_fh *fhandle)
72 memcpy(p, fhandle->data, NFS2_FHSIZE);
73 return p + XDR_QUADLEN(NFS2_FHSIZE);
76 static inline __be32 *
77 xdr_decode_fhandle(__be32 *p, struct nfs_fh *fhandle)
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);
85 static inline __be32*
86 xdr_encode_time(__be32 *p, struct timespec *timep)
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;
94 static inline __be32*
95 xdr_encode_current_server_time(__be32 *p, struct timespec *timep)
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
106 *p++ = htonl(timep->tv_sec);
107 *p++ = htonl(1000000);
108 return p;
111 static inline __be32*
112 xdr_decode_time(__be32 *p, struct timespec *timep)
114 timep->tv_sec = ntohl(*p++);
115 /* Convert microseconds into nanoseconds */
116 timep->tv_nsec = ntohl(*p++) * 1000;
117 return p;
120 static __be32 *
121 xdr_decode_fattr(__be32 *p, struct nfs_fattr *fattr)
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;
146 return p;
149 static inline __be32 *
150 xdr_encode_sattr(__be32 *p, struct iattr *attr)
152 const __be32 not_set = __constant_htonl(0xFFFFFFFF);
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;
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;
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;
176 return p;
180 * NFS encode functions
183 * Encode file handle argument
184 * GETATTR, READLINK, STATFS
186 static int
187 nfs_xdr_fhandle(struct rpc_rqst *req, __be32 *p, struct nfs_fh *fh)
189 p = xdr_encode_fhandle(p, fh);
190 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
191 return 0;
195 * Encode SETATTR arguments
197 static int
198 nfs_xdr_sattrargs(struct rpc_rqst *req, __be32 *p, struct nfs_sattrargs *args)
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;
207 * Encode directory ops argument
208 * LOOKUP, REMOVE, RMDIR
210 static int
211 nfs_xdr_diropargs(struct rpc_rqst *req, __be32 *p, struct nfs_diropargs *args)
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;
220 * Arguments to a READ call. Since we read data directly into the page
221 * cache, we also set up the reply iovec here so that iov[1] points
222 * exactly to the page we want to fetch.
224 static int
225 nfs_xdr_readargs(struct rpc_rqst *req, __be32 *p, struct nfs_readargs *args)
227 struct rpc_auth *auth = req->rq_task->tk_auth;
228 unsigned int replen;
229 u32 offset = (u32)args->offset;
230 u32 count = args->count;
232 p = xdr_encode_fhandle(p, args->fh);
233 *p++ = htonl(offset);
234 *p++ = htonl(count);
235 *p++ = htonl(count);
236 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
238 /* Inline the page array */
239 replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS_readres_sz) << 2;
240 xdr_inline_pages(&req->rq_rcv_buf, replen,
241 args->pages, args->pgbase, count);
242 return 0;
246 * Decode READ reply
248 static int
249 nfs_xdr_readres(struct rpc_rqst *req, __be32 *p, struct nfs_readres *res)
251 struct kvec *iov = req->rq_rcv_buf.head;
252 int status, count, recvd, hdrlen;
254 if ((status = ntohl(*p++)))
255 return -nfs_stat_to_errno(status);
256 p = xdr_decode_fattr(p, res->fattr);
258 count = ntohl(*p++);
259 res->eof = 0;
260 hdrlen = (u8 *) p - (u8 *) iov->iov_base;
261 if (iov->iov_len < hdrlen) {
262 printk(KERN_WARNING "NFS: READ reply header overflowed:"
263 "length %d > %Zu\n", hdrlen, iov->iov_len);
264 return -errno_NFSERR_IO;
265 } else if (iov->iov_len != hdrlen) {
266 dprintk("NFS: READ header is short. iovec will be shifted.\n");
267 xdr_shift_buf(&req->rq_rcv_buf, iov->iov_len - hdrlen);
270 recvd = req->rq_rcv_buf.len - hdrlen;
271 if (count > recvd) {
272 printk(KERN_WARNING "NFS: server cheating in read reply: "
273 "count %d > recvd %d\n", count, recvd);
274 count = recvd;
277 dprintk("RPC: readres OK count %d\n", count);
278 if (count < res->count)
279 res->count = count;
281 return count;
286 * Write arguments. Splice the buffer to be written into the iovec.
288 static int
289 nfs_xdr_writeargs(struct rpc_rqst *req, __be32 *p, struct nfs_writeargs *args)
291 struct xdr_buf *sndbuf = &req->rq_snd_buf;
292 u32 offset = (u32)args->offset;
293 u32 count = args->count;
295 p = xdr_encode_fhandle(p, args->fh);
296 *p++ = htonl(offset);
297 *p++ = htonl(offset);
298 *p++ = htonl(count);
299 *p++ = htonl(count);
300 sndbuf->len = xdr_adjust_iovec(sndbuf->head, p);
302 /* Copy the page array */
303 xdr_encode_pages(sndbuf, args->pages, args->pgbase, count);
304 return 0;
308 * Encode create arguments
309 * CREATE, MKDIR
311 static int
312 nfs_xdr_createargs(struct rpc_rqst *req, __be32 *p, struct nfs_createargs *args)
314 p = xdr_encode_fhandle(p, args->fh);
315 p = xdr_encode_array(p, args->name, args->len);
316 p = xdr_encode_sattr(p, args->sattr);
317 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
318 return 0;
322 * Encode RENAME arguments
324 static int
325 nfs_xdr_renameargs(struct rpc_rqst *req, __be32 *p, struct nfs_renameargs *args)
327 p = xdr_encode_fhandle(p, args->fromfh);
328 p = xdr_encode_array(p, args->fromname, args->fromlen);
329 p = xdr_encode_fhandle(p, args->tofh);
330 p = xdr_encode_array(p, args->toname, args->tolen);
331 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
332 return 0;
336 * Encode LINK arguments
338 static int
339 nfs_xdr_linkargs(struct rpc_rqst *req, __be32 *p, struct nfs_linkargs *args)
341 p = xdr_encode_fhandle(p, args->fromfh);
342 p = xdr_encode_fhandle(p, args->tofh);
343 p = xdr_encode_array(p, args->toname, args->tolen);
344 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
345 return 0;
349 * Encode SYMLINK arguments
351 static int
352 nfs_xdr_symlinkargs(struct rpc_rqst *req, __be32 *p, struct nfs_symlinkargs *args)
354 struct xdr_buf *sndbuf = &req->rq_snd_buf;
355 size_t pad;
357 p = xdr_encode_fhandle(p, args->fromfh);
358 p = xdr_encode_array(p, args->fromname, args->fromlen);
359 *p++ = htonl(args->pathlen);
360 sndbuf->len = xdr_adjust_iovec(sndbuf->head, p);
362 xdr_encode_pages(sndbuf, args->pages, 0, args->pathlen);
365 * xdr_encode_pages may have added a few bytes to ensure the
366 * pathname ends on a 4-byte boundary. Start encoding the
367 * attributes after the pad bytes.
369 pad = sndbuf->tail->iov_len;
370 if (pad > 0)
371 p++;
372 p = xdr_encode_sattr(p, args->sattr);
373 sndbuf->len += xdr_adjust_iovec(sndbuf->tail, p) - pad;
374 return 0;
378 * Encode arguments to readdir call
380 static int
381 nfs_xdr_readdirargs(struct rpc_rqst *req, __be32 *p, struct nfs_readdirargs *args)
383 struct rpc_task *task = req->rq_task;
384 struct rpc_auth *auth = task->tk_auth;
385 unsigned int replen;
386 u32 count = args->count;
388 p = xdr_encode_fhandle(p, args->fh);
389 *p++ = htonl(args->cookie);
390 *p++ = htonl(count); /* see above */
391 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
393 /* Inline the page array */
394 replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS_readdirres_sz) << 2;
395 xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, 0, count);
396 return 0;
400 * Decode the result of a readdir call.
401 * We're not really decoding anymore, we just leave the buffer untouched
402 * and only check that it is syntactically correct.
403 * The real decoding happens in nfs_decode_entry below, called directly
404 * from nfs_readdir for each entry.
406 static int
407 nfs_xdr_readdirres(struct rpc_rqst *req, __be32 *p, void *dummy)
409 struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
410 struct kvec *iov = rcvbuf->head;
411 struct page **page;
412 int hdrlen, recvd;
413 int status, nr;
414 unsigned int len, pglen;
415 __be32 *end, *entry, *kaddr;
417 if ((status = ntohl(*p++)))
418 return -nfs_stat_to_errno(status);
420 hdrlen = (u8 *) p - (u8 *) iov->iov_base;
421 if (iov->iov_len < hdrlen) {
422 printk(KERN_WARNING "NFS: READDIR reply header overflowed:"
423 "length %d > %Zu\n", hdrlen, iov->iov_len);
424 return -errno_NFSERR_IO;
425 } else if (iov->iov_len != hdrlen) {
426 dprintk("NFS: READDIR header is short. iovec will be shifted.\n");
427 xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen);
430 pglen = rcvbuf->page_len;
431 recvd = rcvbuf->len - hdrlen;
432 if (pglen > recvd)
433 pglen = recvd;
434 page = rcvbuf->pages;
435 kaddr = p = kmap_atomic(*page, KM_USER0);
436 end = (__be32 *)((char *)p + pglen);
437 entry = p;
438 for (nr = 0; *p++; nr++) {
439 if (p + 2 > end)
440 goto short_pkt;
441 p++; /* fileid */
442 len = ntohl(*p++);
443 p += XDR_QUADLEN(len) + 1; /* name plus cookie */
444 if (len > NFS2_MAXNAMLEN) {
445 printk(KERN_WARNING "NFS: giant filename in readdir (len 0x%x)!\n",
446 len);
447 goto err_unmap;
449 if (p + 2 > end)
450 goto short_pkt;
451 entry = p;
453 if (!nr && (entry[0] != 0 || entry[1] == 0))
454 goto short_pkt;
455 out:
456 kunmap_atomic(kaddr, KM_USER0);
457 return nr;
458 short_pkt:
459 entry[0] = entry[1] = 0;
460 /* truncate listing ? */
461 if (!nr) {
462 printk(KERN_NOTICE "NFS: readdir reply truncated!\n");
463 entry[1] = 1;
465 goto out;
466 err_unmap:
467 nr = -errno_NFSERR_IO;
468 goto out;
471 __be32 *
472 nfs_decode_dirent(__be32 *p, struct nfs_entry *entry, int plus)
474 if (!*p++) {
475 if (!*p)
476 return ERR_PTR(-EAGAIN);
477 entry->eof = 1;
478 return ERR_PTR(-EBADCOOKIE);
481 entry->ino = ntohl(*p++);
482 entry->len = ntohl(*p++);
483 entry->name = (const char *) p;
484 p += XDR_QUADLEN(entry->len);
485 entry->prev_cookie = entry->cookie;
486 entry->cookie = ntohl(*p++);
487 entry->eof = !p[0] && p[1];
489 return p;
493 * NFS XDR decode functions
496 * Decode simple status reply
498 static int
499 nfs_xdr_stat(struct rpc_rqst *req, __be32 *p, void *dummy)
501 int status;
503 if ((status = ntohl(*p++)) != 0)
504 status = -nfs_stat_to_errno(status);
505 return status;
509 * Decode attrstat reply
510 * GETATTR, SETATTR, WRITE
512 static int
513 nfs_xdr_attrstat(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
515 int status;
517 if ((status = ntohl(*p++)))
518 return -nfs_stat_to_errno(status);
519 xdr_decode_fattr(p, fattr);
520 return 0;
524 * Decode diropres reply
525 * LOOKUP, CREATE, MKDIR
527 static int
528 nfs_xdr_diropres(struct rpc_rqst *req, __be32 *p, struct nfs_diropok *res)
530 int status;
532 if ((status = ntohl(*p++)))
533 return -nfs_stat_to_errno(status);
534 p = xdr_decode_fhandle(p, res->fh);
535 xdr_decode_fattr(p, res->fattr);
536 return 0;
540 * Encode READLINK args
542 static int
543 nfs_xdr_readlinkargs(struct rpc_rqst *req, __be32 *p, struct nfs_readlinkargs *args)
545 struct rpc_auth *auth = req->rq_task->tk_auth;
546 unsigned int replen;
548 p = xdr_encode_fhandle(p, args->fh);
549 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
551 /* Inline the page array */
552 replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS_readlinkres_sz) << 2;
553 xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, args->pgbase, args->pglen);
554 return 0;
558 * Decode READLINK reply
560 static int
561 nfs_xdr_readlinkres(struct rpc_rqst *req, __be32 *p, void *dummy)
563 struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
564 struct kvec *iov = rcvbuf->head;
565 int hdrlen, len, recvd;
566 char *kaddr;
567 int status;
569 if ((status = ntohl(*p++)))
570 return -nfs_stat_to_errno(status);
571 /* Convert length of symlink */
572 len = ntohl(*p++);
573 if (len >= rcvbuf->page_len || len <= 0) {
574 dprintk(KERN_WARNING "nfs: server returned giant symlink!\n");
575 return -ENAMETOOLONG;
577 hdrlen = (u8 *) p - (u8 *) iov->iov_base;
578 if (iov->iov_len < hdrlen) {
579 printk(KERN_WARNING "NFS: READLINK reply header overflowed:"
580 "length %d > %Zu\n", hdrlen, iov->iov_len);
581 return -errno_NFSERR_IO;
582 } else if (iov->iov_len != hdrlen) {
583 dprintk("NFS: READLINK header is short. iovec will be shifted.\n");
584 xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen);
586 recvd = req->rq_rcv_buf.len - hdrlen;
587 if (recvd < len) {
588 printk(KERN_WARNING "NFS: server cheating in readlink reply: "
589 "count %u > recvd %u\n", len, recvd);
590 return -EIO;
593 /* NULL terminate the string we got */
594 kaddr = (char *)kmap_atomic(rcvbuf->pages[0], KM_USER0);
595 kaddr[len+rcvbuf->page_base] = '\0';
596 kunmap_atomic(kaddr, KM_USER0);
597 return 0;
601 * Decode WRITE reply
603 static int
604 nfs_xdr_writeres(struct rpc_rqst *req, __be32 *p, struct nfs_writeres *res)
606 res->verf->committed = NFS_FILE_SYNC;
607 return nfs_xdr_attrstat(req, p, res->fattr);
611 * Decode STATFS reply
613 static int
614 nfs_xdr_statfsres(struct rpc_rqst *req, __be32 *p, struct nfs2_fsstat *res)
616 int status;
618 if ((status = ntohl(*p++)))
619 return -nfs_stat_to_errno(status);
621 res->tsize = ntohl(*p++);
622 res->bsize = ntohl(*p++);
623 res->blocks = ntohl(*p++);
624 res->bfree = ntohl(*p++);
625 res->bavail = ntohl(*p++);
626 return 0;
630 * We need to translate between nfs status return values and
631 * the local errno values which may not be the same.
633 static struct {
634 int stat;
635 int errno;
636 } nfs_errtbl[] = {
637 { NFS_OK, 0 },
638 { NFSERR_PERM, EPERM },
639 { NFSERR_NOENT, ENOENT },
640 { NFSERR_IO, errno_NFSERR_IO },
641 { NFSERR_NXIO, ENXIO },
642 /* { NFSERR_EAGAIN, EAGAIN }, */
643 { NFSERR_ACCES, EACCES },
644 { NFSERR_EXIST, EEXIST },
645 { NFSERR_XDEV, EXDEV },
646 { NFSERR_NODEV, ENODEV },
647 { NFSERR_NOTDIR, ENOTDIR },
648 { NFSERR_ISDIR, EISDIR },
649 { NFSERR_INVAL, EINVAL },
650 { NFSERR_FBIG, EFBIG },
651 { NFSERR_NOSPC, ENOSPC },
652 { NFSERR_ROFS, EROFS },
653 { NFSERR_MLINK, EMLINK },
654 { NFSERR_NAMETOOLONG, ENAMETOOLONG },
655 { NFSERR_NOTEMPTY, ENOTEMPTY },
656 { NFSERR_DQUOT, EDQUOT },
657 { NFSERR_STALE, ESTALE },
658 { NFSERR_REMOTE, EREMOTE },
659 #ifdef EWFLUSH
660 { NFSERR_WFLUSH, EWFLUSH },
661 #endif
662 { NFSERR_BADHANDLE, EBADHANDLE },
663 { NFSERR_NOT_SYNC, ENOTSYNC },
664 { NFSERR_BAD_COOKIE, EBADCOOKIE },
665 { NFSERR_NOTSUPP, ENOTSUPP },
666 { NFSERR_TOOSMALL, ETOOSMALL },
667 { NFSERR_SERVERFAULT, ESERVERFAULT },
668 { NFSERR_BADTYPE, EBADTYPE },
669 { NFSERR_JUKEBOX, EJUKEBOX },
670 { -1, EIO }
674 * Convert an NFS error code to a local one.
675 * This one is used jointly by NFSv2 and NFSv3.
678 nfs_stat_to_errno(int stat)
680 int i;
682 for (i = 0; nfs_errtbl[i].stat != -1; i++) {
683 if (nfs_errtbl[i].stat == stat)
684 return nfs_errtbl[i].errno;
686 printk(KERN_ERR "nfs_stat_to_errno: bad nfs status return value: %d\n", stat);
687 return nfs_errtbl[i].errno;
690 #ifndef MAX
691 # define MAX(a, b) (((a) > (b))? (a) : (b))
692 #endif
694 #define PROC(proc, argtype, restype, timer) \
695 [NFSPROC_##proc] = { \
696 .p_proc = NFSPROC_##proc, \
697 .p_encode = (kxdrproc_t) nfs_xdr_##argtype, \
698 .p_decode = (kxdrproc_t) nfs_xdr_##restype, \
699 .p_bufsiz = MAX(NFS_##argtype##_sz,NFS_##restype##_sz) << 2, \
700 .p_timer = timer, \
701 .p_statidx = NFSPROC_##proc, \
702 .p_name = #proc, \
704 struct rpc_procinfo nfs_procedures[] = {
705 PROC(GETATTR, fhandle, attrstat, 1),
706 PROC(SETATTR, sattrargs, attrstat, 0),
707 PROC(LOOKUP, diropargs, diropres, 2),
708 PROC(READLINK, readlinkargs, readlinkres, 3),
709 PROC(READ, readargs, readres, 3),
710 PROC(WRITE, writeargs, writeres, 4),
711 PROC(CREATE, createargs, diropres, 0),
712 PROC(REMOVE, diropargs, stat, 0),
713 PROC(RENAME, renameargs, stat, 0),
714 PROC(LINK, linkargs, stat, 0),
715 PROC(SYMLINK, symlinkargs, stat, 0),
716 PROC(MKDIR, createargs, diropres, 0),
717 PROC(RMDIR, diropargs, stat, 0),
718 PROC(READDIR, readdirargs, readdirres, 3),
719 PROC(STATFS, fhandle, statfsres, 0),
722 struct rpc_version nfs_version2 = {
723 .number = 2,
724 .nrprocs = ARRAY_SIZE(nfs_procedures),
725 .procs = nfs_procedures