xref: /openbmc/linux/fs/nfs/nfs2xdr.c (revision 816724e6)
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 /* #define NFS_PARANOIA 1 */
30 
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)
54 #define NFS_symlinkargs_sz	(NFS_diropargs_sz+NFS_path_sz+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 u32 *
70 xdr_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 
76 static inline u32 *
77 xdr_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 
85 static inline u32*
86 xdr_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 
94 static inline u32*
95 xdr_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 
111 static inline u32*
112 xdr_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 
120 static u32 *
121 xdr_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++);
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 u32 *
150 xdr_encode_sattr(u32 *p, struct iattr *attr)
151 {
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;
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, 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  */
197 static int
198 nfs_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  */
210 static int
211 nfs_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  */
224 static int
225 nfs_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  */
248 static int
249 nfs_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  */
288 static int
289 nfs_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  */
311 static int
312 nfs_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  */
324 static int
325 nfs_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  */
338 static int
339 nfs_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  */
351 static int
352 nfs_xdr_symlinkargs(struct rpc_rqst *req, u32 *p, struct nfs_symlinkargs *args)
353 {
354 	p = xdr_encode_fhandle(p, args->fromfh);
355 	p = xdr_encode_array(p, args->fromname, args->fromlen);
356 	p = xdr_encode_array(p, args->topath, args->tolen);
357 	p = xdr_encode_sattr(p, args->sattr);
358 	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
359 	return 0;
360 }
361 
362 /*
363  * Encode arguments to readdir call
364  */
365 static int
366 nfs_xdr_readdirargs(struct rpc_rqst *req, u32 *p, struct nfs_readdirargs *args)
367 {
368 	struct rpc_task	*task = req->rq_task;
369 	struct rpc_auth	*auth = task->tk_auth;
370 	unsigned int replen;
371 	u32 count = args->count;
372 
373 	p = xdr_encode_fhandle(p, args->fh);
374 	*p++ = htonl(args->cookie);
375 	*p++ = htonl(count); /* see above */
376 	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
377 
378 	/* Inline the page array */
379 	replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS_readdirres_sz) << 2;
380 	xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, 0, count);
381 	return 0;
382 }
383 
384 /*
385  * Decode the result of a readdir call.
386  * We're not really decoding anymore, we just leave the buffer untouched
387  * and only check that it is syntactically correct.
388  * The real decoding happens in nfs_decode_entry below, called directly
389  * from nfs_readdir for each entry.
390  */
391 static int
392 nfs_xdr_readdirres(struct rpc_rqst *req, u32 *p, void *dummy)
393 {
394 	struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
395 	struct kvec *iov = rcvbuf->head;
396 	struct page **page;
397 	int hdrlen, recvd;
398 	int status, nr;
399 	unsigned int len, pglen;
400 	u32 *end, *entry, *kaddr;
401 
402 	if ((status = ntohl(*p++)))
403 		return -nfs_stat_to_errno(status);
404 
405 	hdrlen = (u8 *) p - (u8 *) iov->iov_base;
406 	if (iov->iov_len < hdrlen) {
407 		printk(KERN_WARNING "NFS: READDIR reply header overflowed:"
408 				"length %d > %Zu\n", hdrlen, iov->iov_len);
409 		return -errno_NFSERR_IO;
410 	} else if (iov->iov_len != hdrlen) {
411 		dprintk("NFS: READDIR header is short. iovec will be shifted.\n");
412 		xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen);
413 	}
414 
415 	pglen = rcvbuf->page_len;
416 	recvd = rcvbuf->len - hdrlen;
417 	if (pglen > recvd)
418 		pglen = recvd;
419 	page = rcvbuf->pages;
420 	kaddr = p = (u32 *)kmap_atomic(*page, KM_USER0);
421 	end = (u32 *)((char *)p + pglen);
422 	entry = p;
423 	for (nr = 0; *p++; nr++) {
424 		if (p + 2 > end)
425 			goto short_pkt;
426 		p++; /* fileid */
427 		len = ntohl(*p++);
428 		p += XDR_QUADLEN(len) + 1;	/* name plus cookie */
429 		if (len > NFS2_MAXNAMLEN) {
430 			printk(KERN_WARNING "NFS: giant filename in readdir (len 0x%x)!\n",
431 						len);
432 			goto err_unmap;
433 		}
434 		if (p + 2 > end)
435 			goto short_pkt;
436 		entry = p;
437 	}
438 	if (!nr && (entry[0] != 0 || entry[1] == 0))
439 		goto short_pkt;
440  out:
441 	kunmap_atomic(kaddr, KM_USER0);
442 	return nr;
443  short_pkt:
444 	entry[0] = entry[1] = 0;
445 	/* truncate listing ? */
446 	if (!nr) {
447 		printk(KERN_NOTICE "NFS: readdir reply truncated!\n");
448 		entry[1] = 1;
449 	}
450 	goto out;
451 err_unmap:
452 	nr = -errno_NFSERR_IO;
453 	goto out;
454 }
455 
456 u32 *
457 nfs_decode_dirent(u32 *p, struct nfs_entry *entry, int plus)
458 {
459 	if (!*p++) {
460 		if (!*p)
461 			return ERR_PTR(-EAGAIN);
462 		entry->eof = 1;
463 		return ERR_PTR(-EBADCOOKIE);
464 	}
465 
466 	entry->ino	  = ntohl(*p++);
467 	entry->len	  = ntohl(*p++);
468 	entry->name	  = (const char *) p;
469 	p		 += XDR_QUADLEN(entry->len);
470 	entry->prev_cookie	  = entry->cookie;
471 	entry->cookie	  = ntohl(*p++);
472 	entry->eof	  = !p[0] && p[1];
473 
474 	return p;
475 }
476 
477 /*
478  * NFS XDR decode functions
479  */
480 /*
481  * Decode simple status reply
482  */
483 static int
484 nfs_xdr_stat(struct rpc_rqst *req, u32 *p, void *dummy)
485 {
486 	int	status;
487 
488 	if ((status = ntohl(*p++)) != 0)
489 		status = -nfs_stat_to_errno(status);
490 	return status;
491 }
492 
493 /*
494  * Decode attrstat reply
495  * GETATTR, SETATTR, WRITE
496  */
497 static int
498 nfs_xdr_attrstat(struct rpc_rqst *req, u32 *p, struct nfs_fattr *fattr)
499 {
500 	int	status;
501 
502 	if ((status = ntohl(*p++)))
503 		return -nfs_stat_to_errno(status);
504 	xdr_decode_fattr(p, fattr);
505 	return 0;
506 }
507 
508 /*
509  * Decode diropres reply
510  * LOOKUP, CREATE, MKDIR
511  */
512 static int
513 nfs_xdr_diropres(struct rpc_rqst *req, u32 *p, struct nfs_diropok *res)
514 {
515 	int	status;
516 
517 	if ((status = ntohl(*p++)))
518 		return -nfs_stat_to_errno(status);
519 	p = xdr_decode_fhandle(p, res->fh);
520 	xdr_decode_fattr(p, res->fattr);
521 	return 0;
522 }
523 
524 /*
525  * Encode READLINK args
526  */
527 static int
528 nfs_xdr_readlinkargs(struct rpc_rqst *req, u32 *p, struct nfs_readlinkargs *args)
529 {
530 	struct rpc_auth *auth = req->rq_task->tk_auth;
531 	unsigned int replen;
532 
533 	p = xdr_encode_fhandle(p, args->fh);
534 	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
535 
536 	/* Inline the page array */
537 	replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS_readlinkres_sz) << 2;
538 	xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, args->pgbase, args->pglen);
539 	return 0;
540 }
541 
542 /*
543  * Decode READLINK reply
544  */
545 static int
546 nfs_xdr_readlinkres(struct rpc_rqst *req, u32 *p, void *dummy)
547 {
548 	struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
549 	struct kvec *iov = rcvbuf->head;
550 	int hdrlen, len, recvd;
551 	char	*kaddr;
552 	int	status;
553 
554 	if ((status = ntohl(*p++)))
555 		return -nfs_stat_to_errno(status);
556 	/* Convert length of symlink */
557 	len = ntohl(*p++);
558 	if (len >= rcvbuf->page_len || len <= 0) {
559 		dprintk(KERN_WARNING "nfs: server returned giant symlink!\n");
560 		return -ENAMETOOLONG;
561 	}
562 	hdrlen = (u8 *) p - (u8 *) iov->iov_base;
563 	if (iov->iov_len < hdrlen) {
564 		printk(KERN_WARNING "NFS: READLINK reply header overflowed:"
565 				"length %d > %Zu\n", hdrlen, iov->iov_len);
566 		return -errno_NFSERR_IO;
567 	} else if (iov->iov_len != hdrlen) {
568 		dprintk("NFS: READLINK header is short. iovec will be shifted.\n");
569 		xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen);
570 	}
571 	recvd = req->rq_rcv_buf.len - hdrlen;
572 	if (recvd < len) {
573 		printk(KERN_WARNING "NFS: server cheating in readlink reply: "
574 				"count %u > recvd %u\n", len, recvd);
575 		return -EIO;
576 	}
577 
578 	/* NULL terminate the string we got */
579 	kaddr = (char *)kmap_atomic(rcvbuf->pages[0], KM_USER0);
580 	kaddr[len+rcvbuf->page_base] = '\0';
581 	kunmap_atomic(kaddr, KM_USER0);
582 	return 0;
583 }
584 
585 /*
586  * Decode WRITE reply
587  */
588 static int
589 nfs_xdr_writeres(struct rpc_rqst *req, u32 *p, struct nfs_writeres *res)
590 {
591 	res->verf->committed = NFS_FILE_SYNC;
592 	return nfs_xdr_attrstat(req, p, res->fattr);
593 }
594 
595 /*
596  * Decode STATFS reply
597  */
598 static int
599 nfs_xdr_statfsres(struct rpc_rqst *req, u32 *p, struct nfs2_fsstat *res)
600 {
601 	int	status;
602 
603 	if ((status = ntohl(*p++)))
604 		return -nfs_stat_to_errno(status);
605 
606 	res->tsize  = ntohl(*p++);
607 	res->bsize  = ntohl(*p++);
608 	res->blocks = ntohl(*p++);
609 	res->bfree  = ntohl(*p++);
610 	res->bavail = ntohl(*p++);
611 	return 0;
612 }
613 
614 /*
615  * We need to translate between nfs status return values and
616  * the local errno values which may not be the same.
617  */
618 static struct {
619 	int stat;
620 	int errno;
621 } nfs_errtbl[] = {
622 	{ NFS_OK,		0		},
623 	{ NFSERR_PERM,		EPERM		},
624 	{ NFSERR_NOENT,		ENOENT		},
625 	{ NFSERR_IO,		errno_NFSERR_IO	},
626 	{ NFSERR_NXIO,		ENXIO		},
627 /*	{ NFSERR_EAGAIN,	EAGAIN		}, */
628 	{ NFSERR_ACCES,		EACCES		},
629 	{ NFSERR_EXIST,		EEXIST		},
630 	{ NFSERR_XDEV,		EXDEV		},
631 	{ NFSERR_NODEV,		ENODEV		},
632 	{ NFSERR_NOTDIR,	ENOTDIR		},
633 	{ NFSERR_ISDIR,		EISDIR		},
634 	{ NFSERR_INVAL,		EINVAL		},
635 	{ NFSERR_FBIG,		EFBIG		},
636 	{ NFSERR_NOSPC,		ENOSPC		},
637 	{ NFSERR_ROFS,		EROFS		},
638 	{ NFSERR_MLINK,		EMLINK		},
639 	{ NFSERR_NAMETOOLONG,	ENAMETOOLONG	},
640 	{ NFSERR_NOTEMPTY,	ENOTEMPTY	},
641 	{ NFSERR_DQUOT,		EDQUOT		},
642 	{ NFSERR_STALE,		ESTALE		},
643 	{ NFSERR_REMOTE,	EREMOTE		},
644 #ifdef EWFLUSH
645 	{ NFSERR_WFLUSH,	EWFLUSH		},
646 #endif
647 	{ NFSERR_BADHANDLE,	EBADHANDLE	},
648 	{ NFSERR_NOT_SYNC,	ENOTSYNC	},
649 	{ NFSERR_BAD_COOKIE,	EBADCOOKIE	},
650 	{ NFSERR_NOTSUPP,	ENOTSUPP	},
651 	{ NFSERR_TOOSMALL,	ETOOSMALL	},
652 	{ NFSERR_SERVERFAULT,	ESERVERFAULT	},
653 	{ NFSERR_BADTYPE,	EBADTYPE	},
654 	{ NFSERR_JUKEBOX,	EJUKEBOX	},
655 	{ -1,			EIO		}
656 };
657 
658 /*
659  * Convert an NFS error code to a local one.
660  * This one is used jointly by NFSv2 and NFSv3.
661  */
662 int
663 nfs_stat_to_errno(int stat)
664 {
665 	int i;
666 
667 	for (i = 0; nfs_errtbl[i].stat != -1; i++) {
668 		if (nfs_errtbl[i].stat == stat)
669 			return nfs_errtbl[i].errno;
670 	}
671 	printk(KERN_ERR "nfs_stat_to_errno: bad nfs status return value: %d\n", stat);
672 	return nfs_errtbl[i].errno;
673 }
674 
675 #ifndef MAX
676 # define MAX(a, b)	(((a) > (b))? (a) : (b))
677 #endif
678 
679 #define PROC(proc, argtype, restype, timer)				\
680 [NFSPROC_##proc] = {							\
681 	.p_proc	    =  NFSPROC_##proc,					\
682 	.p_encode   =  (kxdrproc_t) nfs_xdr_##argtype,			\
683 	.p_decode   =  (kxdrproc_t) nfs_xdr_##restype,			\
684 	.p_bufsiz   =  MAX(NFS_##argtype##_sz,NFS_##restype##_sz) << 2,	\
685 	.p_timer    =  timer,						\
686 	.p_statidx  =  NFSPROC_##proc,					\
687 	.p_name     =  #proc,						\
688 	}
689 struct rpc_procinfo	nfs_procedures[] = {
690     PROC(GETATTR,	fhandle,	attrstat, 1),
691     PROC(SETATTR,	sattrargs,	attrstat, 0),
692     PROC(LOOKUP,	diropargs,	diropres, 2),
693     PROC(READLINK,	readlinkargs,	readlinkres, 3),
694     PROC(READ,		readargs,	readres, 3),
695     PROC(WRITE,		writeargs,	writeres, 4),
696     PROC(CREATE,	createargs,	diropres, 0),
697     PROC(REMOVE,	diropargs,	stat, 0),
698     PROC(RENAME,	renameargs,	stat, 0),
699     PROC(LINK,		linkargs,	stat, 0),
700     PROC(SYMLINK,	symlinkargs,	stat, 0),
701     PROC(MKDIR,		createargs,	diropres, 0),
702     PROC(RMDIR,		diropargs,	stat, 0),
703     PROC(READDIR,	readdirargs,	readdirres, 3),
704     PROC(STATFS,	fhandle,	statfsres, 0),
705 };
706 
707 struct rpc_version		nfs_version2 = {
708 	.number			= 2,
709 	.nrprocs		= ARRAY_SIZE(nfs_procedures),
710 	.procs			= nfs_procedures
711 };
712