]> bbs.cooldavid.org Git - net-next-2.6.git/blame - fs/nfs/nfs2xdr.c
[PATCH] lockd endianness annotations
[net-next-2.6.git] / fs / nfs / nfs2xdr.c
CommitLineData
1da177e4
LT
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>
816724e6 26#include "internal.h"
1da177e4
LT
27
28#define NFSDBG_FACILITY NFSDBG_XDR
29/* #define NFS_PARANOIA 1 */
30
1da177e4
LT
31/* Mapping from NFS error code to "errno" error code. */
32#define errno_NFSERR_IO EIO
33
34/*
35 * Declare the space requirements for NFS arguments and replies as
36 * number of 32bit-words
37 */
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)
45
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)
94a6d753 54#define NFS_symlinkargs_sz (NFS_diropargs_sz+1+NFS_sattr_sz)
1da177e4
LT
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 */
69static inline u32 *
70xdr_encode_fhandle(u32 *p, struct nfs_fh *fhandle)
71{
72 memcpy(p, fhandle->data, NFS2_FHSIZE);
73 return p + XDR_QUADLEN(NFS2_FHSIZE);
74}
75
76static inline u32 *
77xdr_decode_fhandle(u32 *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
85static inline u32*
86xdr_encode_time(u32 *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
94static inline u32*
95xdr_encode_current_server_time(u32 *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
111static inline u32*
112xdr_decode_time(u32 *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
120static u32 *
121xdr_decode_fattr(u32 *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++);
8b4bdcf8
TM
133 fattr->fsid.major = ntohl(*p++);
134 fattr->fsid.minor = 0;
1da177e4
LT
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 }
1da177e4
LT
146 return p;
147}
148
1da177e4
LT
149static inline u32 *
150xdr_encode_sattr(u32 *p, struct iattr *attr)
151{
eadb8c14
TM
152 const u32 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;
1da177e4
LT
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 {
eadb8c14
TM
164 *p++ = not_set;
165 *p++ = not_set;
1da177e4
LT
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 {
eadb8c14
TM
173 *p++ = not_set;
174 *p++ = not_set;
1da177e4
LT
175 }
176 return p;
177}
1da177e4
LT
178
179/*
180 * NFS encode functions
181 */
182/*
183 * Encode file handle argument
184 * GETATTR, READLINK, STATFS
185 */
186static int
187nfs_xdr_fhandle(struct rpc_rqst *req, u32 *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 */
197static int
198nfs_xdr_sattrargs(struct rpc_rqst *req, u32 *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, REMOVE, RMDIR
209 */
210static int
211nfs_xdr_diropargs(struct rpc_rqst *req, u32 *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 * 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.
223 */
224static int
225nfs_xdr_readargs(struct rpc_rqst *req, u32 *p, struct nfs_readargs *args)
226{
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;
231
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);
237
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;
243}
244
245/*
246 * Decode READ reply
247 */
248static int
249nfs_xdr_readres(struct rpc_rqst *req, u32 *p, struct nfs_readres *res)
250{
251 struct kvec *iov = req->rq_rcv_buf.head;
252 int status, count, recvd, hdrlen;
253
254 if ((status = ntohl(*p++)))
255 return -nfs_stat_to_errno(status);
256 p = xdr_decode_fattr(p, res->fattr);
257
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);
268 }
269
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;
275 }
276
277 dprintk("RPC: readres OK count %d\n", count);
278 if (count < res->count)
279 res->count = count;
280
281 return count;
282}
283
284
285/*
286 * Write arguments. Splice the buffer to be written into the iovec.
287 */
288static int
289nfs_xdr_writeargs(struct rpc_rqst *req, u32 *p, struct nfs_writeargs *args)
290{
291 struct xdr_buf *sndbuf = &req->rq_snd_buf;
292 u32 offset = (u32)args->offset;
293 u32 count = args->count;
294
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);
301
302 /* Copy the page array */
303 xdr_encode_pages(sndbuf, args->pages, args->pgbase, count);
304 return 0;
305}
306
307/*
308 * Encode create arguments
309 * CREATE, MKDIR
310 */
311static int
312nfs_xdr_createargs(struct rpc_rqst *req, u32 *p, struct nfs_createargs *args)
313{
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;
319}
320
321/*
322 * Encode RENAME arguments
323 */
324static int
325nfs_xdr_renameargs(struct rpc_rqst *req, u32 *p, struct nfs_renameargs *args)
326{
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;
333}
334
335/*
336 * Encode LINK arguments
337 */
338static int
339nfs_xdr_linkargs(struct rpc_rqst *req, u32 *p, struct nfs_linkargs *args)
340{
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;
346}
347
348/*
349 * Encode SYMLINK arguments
350 */
351static int
352nfs_xdr_symlinkargs(struct rpc_rqst *req, u32 *p, struct nfs_symlinkargs *args)
353{
94a6d753
CL
354 struct xdr_buf *sndbuf = &req->rq_snd_buf;
355 size_t pad;
356
1da177e4
LT
357 p = xdr_encode_fhandle(p, args->fromfh);
358 p = xdr_encode_array(p, args->fromname, args->fromlen);
94a6d753
CL
359 *p++ = htonl(args->pathlen);
360 sndbuf->len = xdr_adjust_iovec(sndbuf->head, p);
361
362 xdr_encode_pages(sndbuf, args->pages, 0, args->pathlen);
363
364 /*
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.
368 */
369 pad = sndbuf->tail->iov_len;
370 if (pad > 0)
371 p++;
1da177e4 372 p = xdr_encode_sattr(p, args->sattr);
94a6d753 373 sndbuf->len += xdr_adjust_iovec(sndbuf->tail, p) - pad;
1da177e4
LT
374 return 0;
375}
376
377/*
378 * Encode arguments to readdir call
379 */
380static int
381nfs_xdr_readdirargs(struct rpc_rqst *req, u32 *p, struct nfs_readdirargs *args)
382{
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;
387
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);
392
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;
397}
398
399/*
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.
405 */
406static int
407nfs_xdr_readdirres(struct rpc_rqst *req, u32 *p, void *dummy)
408{
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 u32 *end, *entry, *kaddr;
416
417 if ((status = ntohl(*p++)))
418 return -nfs_stat_to_errno(status);
419
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);
428 }
429
430 pglen = rcvbuf->page_len;
431 recvd = rcvbuf->len - hdrlen;
432 if (pglen > recvd)
433 pglen = recvd;
434 page = rcvbuf->pages;
435 kaddr = p = (u32 *)kmap_atomic(*page, KM_USER0);
436 end = (u32 *)((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;
448 }
449 if (p + 2 > end)
450 goto short_pkt;
451 entry = p;
452 }
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;
464 }
465 goto out;
466err_unmap:
467 nr = -errno_NFSERR_IO;
468 goto out;
469}
470
471u32 *
472nfs_decode_dirent(u32 *p, struct nfs_entry *entry, int plus)
473{
474 if (!*p++) {
475 if (!*p)
476 return ERR_PTR(-EAGAIN);
477 entry->eof = 1;
478 return ERR_PTR(-EBADCOOKIE);
479 }
480
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];
488
489 return p;
490}
491
492/*
493 * NFS XDR decode functions
494 */
495/*
496 * Decode simple status reply
497 */
498static int
499nfs_xdr_stat(struct rpc_rqst *req, u32 *p, void *dummy)
500{
501 int status;
502
503 if ((status = ntohl(*p++)) != 0)
504 status = -nfs_stat_to_errno(status);
505 return status;
506}
507
508/*
509 * Decode attrstat reply
510 * GETATTR, SETATTR, WRITE
511 */
512static int
513nfs_xdr_attrstat(struct rpc_rqst *req, u32 *p, struct nfs_fattr *fattr)
514{
515 int status;
516
517 if ((status = ntohl(*p++)))
518 return -nfs_stat_to_errno(status);
519 xdr_decode_fattr(p, fattr);
520 return 0;
521}
522
523/*
524 * Decode diropres reply
525 * LOOKUP, CREATE, MKDIR
526 */
527static int
528nfs_xdr_diropres(struct rpc_rqst *req, u32 *p, struct nfs_diropok *res)
529{
530 int status;
531
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;
537}
538
539/*
540 * Encode READLINK args
541 */
542static int
543nfs_xdr_readlinkargs(struct rpc_rqst *req, u32 *p, struct nfs_readlinkargs *args)
544{
545 struct rpc_auth *auth = req->rq_task->tk_auth;
546 unsigned int replen;
547
548 p = xdr_encode_fhandle(p, args->fh);
549 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
550
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;
555}
556
557/*
558 * Decode READLINK reply
559 */
560static int
561nfs_xdr_readlinkres(struct rpc_rqst *req, u32 *p, void *dummy)
562{
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;
568
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;
576 }
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);
585 }
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;
591 }
592
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;
598}
599
600/*
601 * Decode WRITE reply
602 */
603static int
604nfs_xdr_writeres(struct rpc_rqst *req, u32 *p, struct nfs_writeres *res)
605{
606 res->verf->committed = NFS_FILE_SYNC;
607 return nfs_xdr_attrstat(req, p, res->fattr);
608}
609
610/*
611 * Decode STATFS reply
612 */
613static int
614nfs_xdr_statfsres(struct rpc_rqst *req, u32 *p, struct nfs2_fsstat *res)
615{
616 int status;
617
618 if ((status = ntohl(*p++)))
619 return -nfs_stat_to_errno(status);
620
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;
627}
628
629/*
630 * We need to translate between nfs status return values and
631 * the local errno values which may not be the same.
632 */
633static 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 }
671};
672
673/*
674 * Convert an NFS error code to a local one.
675 * This one is used jointly by NFSv2 and NFSv3.
676 */
677int
678nfs_stat_to_errno(int stat)
679{
680 int i;
681
682 for (i = 0; nfs_errtbl[i].stat != -1; i++) {
683 if (nfs_errtbl[i].stat == stat)
684 return nfs_errtbl[i].errno;
685 }
686 printk(KERN_ERR "nfs_stat_to_errno: bad nfs status return value: %d\n", stat);
687 return nfs_errtbl[i].errno;
688}
689
690#ifndef MAX
691# define MAX(a, b) (((a) > (b))? (a) : (b))
692#endif
693
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, \
cc0175c1
CL
700 .p_timer = timer, \
701 .p_statidx = NFSPROC_##proc, \
702 .p_name = #proc, \
1da177e4
LT
703 }
704struct 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),
720};
721
722struct rpc_version nfs_version2 = {
723 .number = 2,
e8c96f8c 724 .nrprocs = ARRAY_SIZE(nfs_procedures),
1da177e4
LT
725 .procs = nfs_procedures
726};