Merge git://git.kernel.org/pub/scm/linux/kernel/git/herbert/crypto-2.6
[wrt350n-kernel.git] / fs / nfs / nfs2xdr.c
blob1f7ea675e0c5e9489d8316b60969d159f386d8ab
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
30 /* Mapping from NFS error code to "errno" error code. */
31 #define errno_NFSERR_IO EIO
34 * Declare the space requirements for NFS arguments and replies as
35 * number of 32bit-words
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)
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)
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, const 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, 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 * Encode REMOVE argument
222 static int
223 nfs_xdr_removeargs(struct rpc_rqst *req, __be32 *p, const struct nfs_removeargs *args)
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;
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.
236 static int
237 nfs_xdr_readargs(struct rpc_rqst *req, __be32 *p, struct nfs_readargs *args)
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;
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);
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;
259 * Decode READ reply
261 static int
262 nfs_xdr_readres(struct rpc_rqst *req, __be32 *p, struct nfs_readres *res)
264 struct kvec *iov = req->rq_rcv_buf.head;
265 size_t hdrlen;
266 u32 count, recvd;
267 int status;
269 if ((status = ntohl(*p++)))
270 return -nfs_stat_to_errno(status);
271 p = xdr_decode_fattr(p, res->fattr);
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);
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;
292 dprintk("RPC: readres OK count %u\n", count);
293 if (count < res->count)
294 res->count = count;
296 return count;
301 * Write arguments. Splice the buffer to be written into the iovec.
303 static int
304 nfs_xdr_writeargs(struct rpc_rqst *req, __be32 *p, struct nfs_writeargs *args)
306 struct xdr_buf *sndbuf = &req->rq_snd_buf;
307 u32 offset = (u32)args->offset;
308 u32 count = args->count;
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);
317 /* Copy the page array */
318 xdr_encode_pages(sndbuf, args->pages, args->pgbase, count);
319 sndbuf->flags |= XDRBUF_WRITE;
320 return 0;
324 * Encode create arguments
325 * CREATE, MKDIR
327 static int
328 nfs_xdr_createargs(struct rpc_rqst *req, __be32 *p, struct nfs_createargs *args)
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;
338 * Encode RENAME arguments
340 static int
341 nfs_xdr_renameargs(struct rpc_rqst *req, __be32 *p, struct nfs_renameargs *args)
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;
352 * Encode LINK arguments
354 static int
355 nfs_xdr_linkargs(struct rpc_rqst *req, __be32 *p, struct nfs_linkargs *args)
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;
365 * Encode SYMLINK arguments
367 static int
368 nfs_xdr_symlinkargs(struct rpc_rqst *req, __be32 *p, struct nfs_symlinkargs *args)
370 struct xdr_buf *sndbuf = &req->rq_snd_buf;
371 size_t pad;
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);
378 xdr_encode_pages(sndbuf, args->pages, 0, args->pathlen);
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.
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;
394 * Encode arguments to readdir call
396 static int
397 nfs_xdr_readdirargs(struct rpc_rqst *req, __be32 *p, struct nfs_readdirargs *args)
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;
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);
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;
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.
422 static int
423 nfs_xdr_readdirres(struct rpc_rqst *req, __be32 *p, void *dummy)
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;
434 if ((status = ntohl(*p++)))
435 return -nfs_stat_to_errno(status);
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);
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;
466 if (p + 2 > end)
467 goto short_pkt;
468 entry = p;
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;
482 goto out;
483 err_unmap:
484 nr = -errno_NFSERR_IO;
485 goto out;
488 __be32 *
489 nfs_decode_dirent(__be32 *p, struct nfs_entry *entry, int plus)
491 if (!*p++) {
492 if (!*p)
493 return ERR_PTR(-EAGAIN);
494 entry->eof = 1;
495 return ERR_PTR(-EBADCOOKIE);
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];
506 return p;
510 * NFS XDR decode functions
513 * Decode simple status reply
515 static int
516 nfs_xdr_stat(struct rpc_rqst *req, __be32 *p, void *dummy)
518 int status;
520 if ((status = ntohl(*p++)) != 0)
521 status = -nfs_stat_to_errno(status);
522 return status;
526 * Decode attrstat reply
527 * GETATTR, SETATTR, WRITE
529 static int
530 nfs_xdr_attrstat(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
532 int status;
534 if ((status = ntohl(*p++)))
535 return -nfs_stat_to_errno(status);
536 xdr_decode_fattr(p, fattr);
537 return 0;
541 * Decode diropres reply
542 * LOOKUP, CREATE, MKDIR
544 static int
545 nfs_xdr_diropres(struct rpc_rqst *req, __be32 *p, struct nfs_diropok *res)
547 int status;
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;
557 * Encode READLINK args
559 static int
560 nfs_xdr_readlinkargs(struct rpc_rqst *req, __be32 *p, struct nfs_readlinkargs *args)
562 struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth;
563 unsigned int replen;
565 p = xdr_encode_fhandle(p, args->fh);
566 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
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;
575 * Decode READLINK reply
577 static int
578 nfs_xdr_readlinkres(struct rpc_rqst *req, __be32 *p, void *dummy)
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;
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;
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);
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;
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;
619 * Decode WRITE reply
621 static int
622 nfs_xdr_writeres(struct rpc_rqst *req, __be32 *p, struct nfs_writeres *res)
624 res->verf->committed = NFS_FILE_SYNC;
625 return nfs_xdr_attrstat(req, p, res->fattr);
629 * Decode STATFS reply
631 static int
632 nfs_xdr_statfsres(struct rpc_rqst *req, __be32 *p, struct nfs2_fsstat *res)
634 int status;
636 if ((status = ntohl(*p++)))
637 return -nfs_stat_to_errno(status);
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;
648 * We need to translate between nfs status return values and
649 * the local errno values which may not be the same.
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 }
692 * Convert an NFS error code to a local one.
693 * This one is used jointly by NFSv2 and NFSv3.
696 nfs_stat_to_errno(int stat)
698 int i;
700 for (i = 0; nfs_errtbl[i].stat != -1; i++) {
701 if (nfs_errtbl[i].stat == stat)
702 return nfs_errtbl[i].errno;
704 dprintk("nfs_stat_to_errno: bad nfs status return value: %d\n", stat);
705 return nfs_errtbl[i].errno;
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, \
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),
737 struct rpc_version nfs_version2 = {
738 .number = 2,
739 .nrprocs = ARRAY_SIZE(nfs_procedures),
740 .procs = nfs_procedures