xref: /openbmc/linux/fs/nfs/nfs2xdr.c (revision d5cb9783536a41df9f9cba5b0a1d78047ed787f7)
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 
27 #define NFSDBG_FACILITY		NFSDBG_XDR
28 /* #define NFS_PARANOIA 1 */
29 
30 extern int			nfs_stat_to_errno(int stat);
31 
32 /* Mapping from NFS error code to "errno" error code. */
33 #define errno_NFSERR_IO		EIO
34 
35 /*
36  * Declare the space requirements for NFS arguments and replies as
37  * number of 32bit-words
38  */
39 #define NFS_fhandle_sz		(8)
40 #define NFS_sattr_sz		(8)
41 #define NFS_filename_sz		(1+(NFS2_MAXNAMLEN>>2))
42 #define NFS_path_sz		(1+(NFS2_MAXPATHLEN>>2))
43 #define NFS_fattr_sz		(17)
44 #define NFS_info_sz		(5)
45 #define NFS_entry_sz		(NFS_filename_sz+3)
46 
47 #define NFS_diropargs_sz	(NFS_fhandle_sz+NFS_filename_sz)
48 #define NFS_sattrargs_sz	(NFS_fhandle_sz+NFS_sattr_sz)
49 #define NFS_readlinkargs_sz	(NFS_fhandle_sz)
50 #define NFS_readargs_sz		(NFS_fhandle_sz+3)
51 #define NFS_writeargs_sz	(NFS_fhandle_sz+4)
52 #define NFS_createargs_sz	(NFS_diropargs_sz+NFS_sattr_sz)
53 #define NFS_renameargs_sz	(NFS_diropargs_sz+NFS_diropargs_sz)
54 #define NFS_linkargs_sz		(NFS_fhandle_sz+NFS_diropargs_sz)
55 #define NFS_symlinkargs_sz	(NFS_diropargs_sz+NFS_path_sz+NFS_sattr_sz)
56 #define NFS_readdirargs_sz	(NFS_fhandle_sz+2)
57 
58 #define NFS_attrstat_sz		(1+NFS_fattr_sz)
59 #define NFS_diropres_sz		(1+NFS_fhandle_sz+NFS_fattr_sz)
60 #define NFS_readlinkres_sz	(2)
61 #define NFS_readres_sz		(1+NFS_fattr_sz+1)
62 #define NFS_writeres_sz         (NFS_attrstat_sz)
63 #define NFS_stat_sz		(1)
64 #define NFS_readdirres_sz	(1)
65 #define NFS_statfsres_sz	(1+NFS_info_sz)
66 
67 /*
68  * Common NFS XDR functions as inlines
69  */
70 static inline u32 *
71 xdr_encode_fhandle(u32 *p, struct nfs_fh *fhandle)
72 {
73 	memcpy(p, fhandle->data, NFS2_FHSIZE);
74 	return p + XDR_QUADLEN(NFS2_FHSIZE);
75 }
76 
77 static inline u32 *
78 xdr_decode_fhandle(u32 *p, struct nfs_fh *fhandle)
79 {
80 	/* NFSv2 handles have a fixed length */
81 	fhandle->size = NFS2_FHSIZE;
82 	memcpy(fhandle->data, p, NFS2_FHSIZE);
83 	return p + XDR_QUADLEN(NFS2_FHSIZE);
84 }
85 
86 static inline u32*
87 xdr_encode_time(u32 *p, struct timespec *timep)
88 {
89 	*p++ = htonl(timep->tv_sec);
90 	/* Convert nanoseconds into microseconds */
91 	*p++ = htonl(timep->tv_nsec ? timep->tv_nsec / 1000 : 0);
92 	return p;
93 }
94 
95 static inline u32*
96 xdr_encode_current_server_time(u32 *p, struct timespec *timep)
97 {
98 	/*
99 	 * Passing the invalid value useconds=1000000 is a
100 	 * Sun convention for "set to current server time".
101 	 * It's needed to make permissions checks for the
102 	 * "touch" program across v2 mounts to Solaris and
103 	 * Irix boxes work correctly. See description of
104 	 * sattr in section 6.1 of "NFS Illustrated" by
105 	 * Brent Callaghan, Addison-Wesley, ISBN 0-201-32750-5
106 	 */
107 	*p++ = htonl(timep->tv_sec);
108 	*p++ = htonl(1000000);
109 	return p;
110 }
111 
112 static inline u32*
113 xdr_decode_time(u32 *p, struct timespec *timep)
114 {
115 	timep->tv_sec = ntohl(*p++);
116 	/* Convert microseconds into nanoseconds */
117 	timep->tv_nsec = ntohl(*p++) * 1000;
118 	return p;
119 }
120 
121 static u32 *
122 xdr_decode_fattr(u32 *p, struct nfs_fattr *fattr)
123 {
124 	u32 rdev;
125 	fattr->type = (enum nfs_ftype) ntohl(*p++);
126 	fattr->mode = ntohl(*p++);
127 	fattr->nlink = ntohl(*p++);
128 	fattr->uid = ntohl(*p++);
129 	fattr->gid = ntohl(*p++);
130 	fattr->size = ntohl(*p++);
131 	fattr->du.nfs2.blocksize = ntohl(*p++);
132 	rdev = ntohl(*p++);
133 	fattr->du.nfs2.blocks = ntohl(*p++);
134 	fattr->fsid_u.nfs3 = ntohl(*p++);
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 #define SATTR(p, attr, flag, field) \
150         *p++ = (attr->ia_valid & flag) ? htonl(attr->field) : ~(u32) 0
151 static inline u32 *
152 xdr_encode_sattr(u32 *p, struct iattr *attr)
153 {
154 	SATTR(p, attr, ATTR_MODE, ia_mode);
155 	SATTR(p, attr, ATTR_UID, ia_uid);
156 	SATTR(p, attr, ATTR_GID, ia_gid);
157 	SATTR(p, attr, ATTR_SIZE, ia_size);
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++ = ~(u32) 0;
165 		*p++ = ~(u32) 0;
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++ = ~(u32) 0;
174 		*p++ = ~(u32) 0;
175 	}
176   	return p;
177 }
178 #undef SATTR
179 
180 /*
181  * NFS encode functions
182  */
183 /*
184  * Encode file handle argument
185  * GETATTR, READLINK, STATFS
186  */
187 static int
188 nfs_xdr_fhandle(struct rpc_rqst *req, u32 *p, struct nfs_fh *fh)
189 {
190 	p = xdr_encode_fhandle(p, fh);
191 	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
192 	return 0;
193 }
194 
195 /*
196  * Encode SETATTR arguments
197  */
198 static int
199 nfs_xdr_sattrargs(struct rpc_rqst *req, u32 *p, struct nfs_sattrargs *args)
200 {
201 	p = xdr_encode_fhandle(p, args->fh);
202 	p = xdr_encode_sattr(p, args->sattr);
203 	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
204 	return 0;
205 }
206 
207 /*
208  * Encode directory ops argument
209  * LOOKUP, REMOVE, RMDIR
210  */
211 static int
212 nfs_xdr_diropargs(struct rpc_rqst *req, u32 *p, struct nfs_diropargs *args)
213 {
214 	p = xdr_encode_fhandle(p, args->fh);
215 	p = xdr_encode_array(p, args->name, args->len);
216 	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
217 	return 0;
218 }
219 
220 /*
221  * Arguments to a READ call. Since we read data directly into the page
222  * cache, we also set up the reply iovec here so that iov[1] points
223  * exactly to the page we want to fetch.
224  */
225 static int
226 nfs_xdr_readargs(struct rpc_rqst *req, u32 *p, struct nfs_readargs *args)
227 {
228 	struct rpc_auth	*auth = req->rq_task->tk_auth;
229 	unsigned int replen;
230 	u32 offset = (u32)args->offset;
231 	u32 count = args->count;
232 
233 	p = xdr_encode_fhandle(p, args->fh);
234 	*p++ = htonl(offset);
235 	*p++ = htonl(count);
236 	*p++ = htonl(count);
237 	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
238 
239 	/* Inline the page array */
240 	replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS_readres_sz) << 2;
241 	xdr_inline_pages(&req->rq_rcv_buf, replen,
242 			 args->pages, args->pgbase, count);
243 	return 0;
244 }
245 
246 /*
247  * Decode READ reply
248  */
249 static int
250 nfs_xdr_readres(struct rpc_rqst *req, u32 *p, struct nfs_readres *res)
251 {
252 	struct kvec *iov = req->rq_rcv_buf.head;
253 	int	status, count, recvd, hdrlen;
254 
255 	if ((status = ntohl(*p++)))
256 		return -nfs_stat_to_errno(status);
257 	p = xdr_decode_fattr(p, res->fattr);
258 
259 	count = ntohl(*p++);
260 	res->eof = 0;
261 	hdrlen = (u8 *) p - (u8 *) iov->iov_base;
262 	if (iov->iov_len < hdrlen) {
263 		printk(KERN_WARNING "NFS: READ reply header overflowed:"
264 				"length %d > %Zu\n", hdrlen, iov->iov_len);
265 		return -errno_NFSERR_IO;
266 	} else if (iov->iov_len != hdrlen) {
267 		dprintk("NFS: READ header is short. iovec will be shifted.\n");
268 		xdr_shift_buf(&req->rq_rcv_buf, iov->iov_len - hdrlen);
269 	}
270 
271 	recvd = req->rq_rcv_buf.len - hdrlen;
272 	if (count > recvd) {
273 		printk(KERN_WARNING "NFS: server cheating in read reply: "
274 			"count %d > recvd %d\n", count, recvd);
275 		count = recvd;
276 	}
277 
278 	dprintk("RPC:      readres OK count %d\n", count);
279 	if (count < res->count)
280 		res->count = count;
281 
282 	return count;
283 }
284 
285 
286 /*
287  * Write arguments. Splice the buffer to be written into the iovec.
288  */
289 static int
290 nfs_xdr_writeargs(struct rpc_rqst *req, u32 *p, struct nfs_writeargs *args)
291 {
292 	struct xdr_buf *sndbuf = &req->rq_snd_buf;
293 	u32 offset = (u32)args->offset;
294 	u32 count = args->count;
295 
296 	p = xdr_encode_fhandle(p, args->fh);
297 	*p++ = htonl(offset);
298 	*p++ = htonl(offset);
299 	*p++ = htonl(count);
300 	*p++ = htonl(count);
301 	sndbuf->len = xdr_adjust_iovec(sndbuf->head, p);
302 
303 	/* Copy the page array */
304 	xdr_encode_pages(sndbuf, args->pages, args->pgbase, count);
305 	return 0;
306 }
307 
308 /*
309  * Encode create arguments
310  * CREATE, MKDIR
311  */
312 static int
313 nfs_xdr_createargs(struct rpc_rqst *req, u32 *p, struct nfs_createargs *args)
314 {
315 	p = xdr_encode_fhandle(p, args->fh);
316 	p = xdr_encode_array(p, args->name, args->len);
317 	p = xdr_encode_sattr(p, args->sattr);
318 	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
319 	return 0;
320 }
321 
322 /*
323  * Encode RENAME arguments
324  */
325 static int
326 nfs_xdr_renameargs(struct rpc_rqst *req, u32 *p, struct nfs_renameargs *args)
327 {
328 	p = xdr_encode_fhandle(p, args->fromfh);
329 	p = xdr_encode_array(p, args->fromname, args->fromlen);
330 	p = xdr_encode_fhandle(p, args->tofh);
331 	p = xdr_encode_array(p, args->toname, args->tolen);
332 	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
333 	return 0;
334 }
335 
336 /*
337  * Encode LINK arguments
338  */
339 static int
340 nfs_xdr_linkargs(struct rpc_rqst *req, u32 *p, struct nfs_linkargs *args)
341 {
342 	p = xdr_encode_fhandle(p, args->fromfh);
343 	p = xdr_encode_fhandle(p, args->tofh);
344 	p = xdr_encode_array(p, args->toname, args->tolen);
345 	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
346 	return 0;
347 }
348 
349 /*
350  * Encode SYMLINK arguments
351  */
352 static int
353 nfs_xdr_symlinkargs(struct rpc_rqst *req, u32 *p, struct nfs_symlinkargs *args)
354 {
355 	p = xdr_encode_fhandle(p, args->fromfh);
356 	p = xdr_encode_array(p, args->fromname, args->fromlen);
357 	p = xdr_encode_array(p, args->topath, args->tolen);
358 	p = xdr_encode_sattr(p, args->sattr);
359 	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
360 	return 0;
361 }
362 
363 /*
364  * Encode arguments to readdir call
365  */
366 static int
367 nfs_xdr_readdirargs(struct rpc_rqst *req, u32 *p, struct nfs_readdirargs *args)
368 {
369 	struct rpc_task	*task = req->rq_task;
370 	struct rpc_auth	*auth = task->tk_auth;
371 	unsigned int replen;
372 	u32 count = args->count;
373 
374 	p = xdr_encode_fhandle(p, args->fh);
375 	*p++ = htonl(args->cookie);
376 	*p++ = htonl(count); /* see above */
377 	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
378 
379 	/* Inline the page array */
380 	replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS_readdirres_sz) << 2;
381 	xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, 0, count);
382 	return 0;
383 }
384 
385 /*
386  * Decode the result of a readdir call.
387  * We're not really decoding anymore, we just leave the buffer untouched
388  * and only check that it is syntactically correct.
389  * The real decoding happens in nfs_decode_entry below, called directly
390  * from nfs_readdir for each entry.
391  */
392 static int
393 nfs_xdr_readdirres(struct rpc_rqst *req, u32 *p, void *dummy)
394 {
395 	struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
396 	struct kvec *iov = rcvbuf->head;
397 	struct page **page;
398 	int hdrlen, recvd;
399 	int status, nr;
400 	unsigned int len, pglen;
401 	u32 *end, *entry, *kaddr;
402 
403 	if ((status = ntohl(*p++)))
404 		return -nfs_stat_to_errno(status);
405 
406 	hdrlen = (u8 *) p - (u8 *) iov->iov_base;
407 	if (iov->iov_len < hdrlen) {
408 		printk(KERN_WARNING "NFS: READDIR reply header overflowed:"
409 				"length %d > %Zu\n", hdrlen, iov->iov_len);
410 		return -errno_NFSERR_IO;
411 	} else if (iov->iov_len != hdrlen) {
412 		dprintk("NFS: READDIR header is short. iovec will be shifted.\n");
413 		xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen);
414 	}
415 
416 	pglen = rcvbuf->page_len;
417 	recvd = rcvbuf->len - hdrlen;
418 	if (pglen > recvd)
419 		pglen = recvd;
420 	page = rcvbuf->pages;
421 	kaddr = p = (u32 *)kmap_atomic(*page, KM_USER0);
422 	end = (u32 *)((char *)p + pglen);
423 	entry = p;
424 	for (nr = 0; *p++; nr++) {
425 		if (p + 2 > end)
426 			goto short_pkt;
427 		p++; /* fileid */
428 		len = ntohl(*p++);
429 		p += XDR_QUADLEN(len) + 1;	/* name plus cookie */
430 		if (len > NFS2_MAXNAMLEN) {
431 			printk(KERN_WARNING "NFS: giant filename in readdir (len 0x%x)!\n",
432 						len);
433 			goto err_unmap;
434 		}
435 		if (p + 2 > end)
436 			goto short_pkt;
437 		entry = p;
438 	}
439 	if (!nr && (entry[0] != 0 || entry[1] == 0))
440 		goto short_pkt;
441  out:
442 	kunmap_atomic(kaddr, KM_USER0);
443 	return nr;
444  short_pkt:
445 	entry[0] = entry[1] = 0;
446 	/* truncate listing ? */
447 	if (!nr) {
448 		printk(KERN_NOTICE "NFS: readdir reply truncated!\n");
449 		entry[1] = 1;
450 	}
451 	goto out;
452 err_unmap:
453 	nr = -errno_NFSERR_IO;
454 	goto out;
455 }
456 
457 u32 *
458 nfs_decode_dirent(u32 *p, struct nfs_entry *entry, int plus)
459 {
460 	if (!*p++) {
461 		if (!*p)
462 			return ERR_PTR(-EAGAIN);
463 		entry->eof = 1;
464 		return ERR_PTR(-EBADCOOKIE);
465 	}
466 
467 	entry->ino	  = ntohl(*p++);
468 	entry->len	  = ntohl(*p++);
469 	entry->name	  = (const char *) p;
470 	p		 += XDR_QUADLEN(entry->len);
471 	entry->prev_cookie	  = entry->cookie;
472 	entry->cookie	  = ntohl(*p++);
473 	entry->eof	  = !p[0] && p[1];
474 
475 	return p;
476 }
477 
478 /*
479  * NFS XDR decode functions
480  */
481 /*
482  * Decode simple status reply
483  */
484 static int
485 nfs_xdr_stat(struct rpc_rqst *req, u32 *p, void *dummy)
486 {
487 	int	status;
488 
489 	if ((status = ntohl(*p++)) != 0)
490 		status = -nfs_stat_to_errno(status);
491 	return status;
492 }
493 
494 /*
495  * Decode attrstat reply
496  * GETATTR, SETATTR, WRITE
497  */
498 static int
499 nfs_xdr_attrstat(struct rpc_rqst *req, u32 *p, struct nfs_fattr *fattr)
500 {
501 	int	status;
502 
503 	if ((status = ntohl(*p++)))
504 		return -nfs_stat_to_errno(status);
505 	xdr_decode_fattr(p, fattr);
506 	return 0;
507 }
508 
509 /*
510  * Decode diropres reply
511  * LOOKUP, CREATE, MKDIR
512  */
513 static int
514 nfs_xdr_diropres(struct rpc_rqst *req, u32 *p, struct nfs_diropok *res)
515 {
516 	int	status;
517 
518 	if ((status = ntohl(*p++)))
519 		return -nfs_stat_to_errno(status);
520 	p = xdr_decode_fhandle(p, res->fh);
521 	xdr_decode_fattr(p, res->fattr);
522 	return 0;
523 }
524 
525 /*
526  * Encode READLINK args
527  */
528 static int
529 nfs_xdr_readlinkargs(struct rpc_rqst *req, u32 *p, struct nfs_readlinkargs *args)
530 {
531 	struct rpc_auth *auth = req->rq_task->tk_auth;
532 	unsigned int replen;
533 
534 	p = xdr_encode_fhandle(p, args->fh);
535 	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
536 
537 	/* Inline the page array */
538 	replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS_readlinkres_sz) << 2;
539 	xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, args->pgbase, args->pglen);
540 	return 0;
541 }
542 
543 /*
544  * Decode READLINK reply
545  */
546 static int
547 nfs_xdr_readlinkres(struct rpc_rqst *req, u32 *p, void *dummy)
548 {
549 	struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
550 	struct kvec *iov = rcvbuf->head;
551 	int hdrlen, len, recvd;
552 	char	*kaddr;
553 	int	status;
554 
555 	if ((status = ntohl(*p++)))
556 		return -nfs_stat_to_errno(status);
557 	/* Convert length of symlink */
558 	len = ntohl(*p++);
559 	if (len >= rcvbuf->page_len || len <= 0) {
560 		dprintk(KERN_WARNING "nfs: server returned giant symlink!\n");
561 		return -ENAMETOOLONG;
562 	}
563 	hdrlen = (u8 *) p - (u8 *) iov->iov_base;
564 	if (iov->iov_len < hdrlen) {
565 		printk(KERN_WARNING "NFS: READLINK reply header overflowed:"
566 				"length %d > %Zu\n", hdrlen, iov->iov_len);
567 		return -errno_NFSERR_IO;
568 	} else if (iov->iov_len != hdrlen) {
569 		dprintk("NFS: READLINK header is short. iovec will be shifted.\n");
570 		xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen);
571 	}
572 	recvd = req->rq_rcv_buf.len - hdrlen;
573 	if (recvd < len) {
574 		printk(KERN_WARNING "NFS: server cheating in readlink reply: "
575 				"count %u > recvd %u\n", len, recvd);
576 		return -EIO;
577 	}
578 
579 	/* NULL terminate the string we got */
580 	kaddr = (char *)kmap_atomic(rcvbuf->pages[0], KM_USER0);
581 	kaddr[len+rcvbuf->page_base] = '\0';
582 	kunmap_atomic(kaddr, KM_USER0);
583 	return 0;
584 }
585 
586 /*
587  * Decode WRITE reply
588  */
589 static int
590 nfs_xdr_writeres(struct rpc_rqst *req, u32 *p, struct nfs_writeres *res)
591 {
592 	res->verf->committed = NFS_FILE_SYNC;
593 	return nfs_xdr_attrstat(req, p, res->fattr);
594 }
595 
596 /*
597  * Decode STATFS reply
598  */
599 static int
600 nfs_xdr_statfsres(struct rpc_rqst *req, u32 *p, struct nfs2_fsstat *res)
601 {
602 	int	status;
603 
604 	if ((status = ntohl(*p++)))
605 		return -nfs_stat_to_errno(status);
606 
607 	res->tsize  = ntohl(*p++);
608 	res->bsize  = ntohl(*p++);
609 	res->blocks = ntohl(*p++);
610 	res->bfree  = ntohl(*p++);
611 	res->bavail = ntohl(*p++);
612 	return 0;
613 }
614 
615 /*
616  * We need to translate between nfs status return values and
617  * the local errno values which may not be the same.
618  */
619 static struct {
620 	int stat;
621 	int errno;
622 } nfs_errtbl[] = {
623 	{ NFS_OK,		0		},
624 	{ NFSERR_PERM,		EPERM		},
625 	{ NFSERR_NOENT,		ENOENT		},
626 	{ NFSERR_IO,		errno_NFSERR_IO	},
627 	{ NFSERR_NXIO,		ENXIO		},
628 /*	{ NFSERR_EAGAIN,	EAGAIN		}, */
629 	{ NFSERR_ACCES,		EACCES		},
630 	{ NFSERR_EXIST,		EEXIST		},
631 	{ NFSERR_XDEV,		EXDEV		},
632 	{ NFSERR_NODEV,		ENODEV		},
633 	{ NFSERR_NOTDIR,	ENOTDIR		},
634 	{ NFSERR_ISDIR,		EISDIR		},
635 	{ NFSERR_INVAL,		EINVAL		},
636 	{ NFSERR_FBIG,		EFBIG		},
637 	{ NFSERR_NOSPC,		ENOSPC		},
638 	{ NFSERR_ROFS,		EROFS		},
639 	{ NFSERR_MLINK,		EMLINK		},
640 	{ NFSERR_NAMETOOLONG,	ENAMETOOLONG	},
641 	{ NFSERR_NOTEMPTY,	ENOTEMPTY	},
642 	{ NFSERR_DQUOT,		EDQUOT		},
643 	{ NFSERR_STALE,		ESTALE		},
644 	{ NFSERR_REMOTE,	EREMOTE		},
645 #ifdef EWFLUSH
646 	{ NFSERR_WFLUSH,	EWFLUSH		},
647 #endif
648 	{ NFSERR_BADHANDLE,	EBADHANDLE	},
649 	{ NFSERR_NOT_SYNC,	ENOTSYNC	},
650 	{ NFSERR_BAD_COOKIE,	EBADCOOKIE	},
651 	{ NFSERR_NOTSUPP,	ENOTSUPP	},
652 	{ NFSERR_TOOSMALL,	ETOOSMALL	},
653 	{ NFSERR_SERVERFAULT,	ESERVERFAULT	},
654 	{ NFSERR_BADTYPE,	EBADTYPE	},
655 	{ NFSERR_JUKEBOX,	EJUKEBOX	},
656 	{ -1,			EIO		}
657 };
658 
659 /*
660  * Convert an NFS error code to a local one.
661  * This one is used jointly by NFSv2 and NFSv3.
662  */
663 int
664 nfs_stat_to_errno(int stat)
665 {
666 	int i;
667 
668 	for (i = 0; nfs_errtbl[i].stat != -1; i++) {
669 		if (nfs_errtbl[i].stat == stat)
670 			return nfs_errtbl[i].errno;
671 	}
672 	printk(KERN_ERR "nfs_stat_to_errno: bad nfs status return value: %d\n", stat);
673 	return nfs_errtbl[i].errno;
674 }
675 
676 #ifndef MAX
677 # define MAX(a, b)	(((a) > (b))? (a) : (b))
678 #endif
679 
680 #define PROC(proc, argtype, restype, timer)				\
681 [NFSPROC_##proc] = {							\
682 	.p_proc	    =  NFSPROC_##proc,					\
683 	.p_encode   =  (kxdrproc_t) nfs_xdr_##argtype,			\
684 	.p_decode   =  (kxdrproc_t) nfs_xdr_##restype,			\
685 	.p_bufsiz   =  MAX(NFS_##argtype##_sz,NFS_##restype##_sz) << 2,	\
686 	.p_timer    =  timer						\
687 	}
688 struct rpc_procinfo	nfs_procedures[] = {
689     PROC(GETATTR,	fhandle,	attrstat, 1),
690     PROC(SETATTR,	sattrargs,	attrstat, 0),
691     PROC(LOOKUP,	diropargs,	diropres, 2),
692     PROC(READLINK,	readlinkargs,	readlinkres, 3),
693     PROC(READ,		readargs,	readres, 3),
694     PROC(WRITE,		writeargs,	writeres, 4),
695     PROC(CREATE,	createargs,	diropres, 0),
696     PROC(REMOVE,	diropargs,	stat, 0),
697     PROC(RENAME,	renameargs,	stat, 0),
698     PROC(LINK,		linkargs,	stat, 0),
699     PROC(SYMLINK,	symlinkargs,	stat, 0),
700     PROC(MKDIR,		createargs,	diropres, 0),
701     PROC(RMDIR,		diropargs,	stat, 0),
702     PROC(READDIR,	readdirargs,	readdirres, 3),
703     PROC(STATFS,	fhandle,	statfsres, 0),
704 };
705 
706 struct rpc_version		nfs_version2 = {
707 	.number			= 2,
708 	.nrprocs		= sizeof(nfs_procedures)/sizeof(nfs_procedures[0]),
709 	.procs			= nfs_procedures
710 };
711