xref: /openbmc/linux/fs/nfs/nfs2xdr.c (revision 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2)
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 	fattr->timestamp = jiffies;
147 	return p;
148 }
149 
150 #define SATTR(p, attr, flag, field) \
151         *p++ = (attr->ia_valid & flag) ? htonl(attr->field) : ~(u32) 0
152 static inline u32 *
153 xdr_encode_sattr(u32 *p, struct iattr *attr)
154 {
155 	SATTR(p, attr, ATTR_MODE, ia_mode);
156 	SATTR(p, attr, ATTR_UID, ia_uid);
157 	SATTR(p, attr, ATTR_GID, ia_gid);
158 	SATTR(p, attr, ATTR_SIZE, ia_size);
159 
160 	if (attr->ia_valid & ATTR_ATIME_SET) {
161 		p = xdr_encode_time(p, &attr->ia_atime);
162 	} else if (attr->ia_valid & ATTR_ATIME) {
163 		p = xdr_encode_current_server_time(p, &attr->ia_atime);
164 	} else {
165 		*p++ = ~(u32) 0;
166 		*p++ = ~(u32) 0;
167 	}
168 
169 	if (attr->ia_valid & ATTR_MTIME_SET) {
170 		p = xdr_encode_time(p, &attr->ia_mtime);
171 	} else if (attr->ia_valid & ATTR_MTIME) {
172 		p = xdr_encode_current_server_time(p, &attr->ia_mtime);
173 	} else {
174 		*p++ = ~(u32) 0;
175 		*p++ = ~(u32) 0;
176 	}
177   	return p;
178 }
179 #undef SATTR
180 
181 /*
182  * NFS encode functions
183  */
184 /*
185  * Encode file handle argument
186  * GETATTR, READLINK, STATFS
187  */
188 static int
189 nfs_xdr_fhandle(struct rpc_rqst *req, u32 *p, struct nfs_fh *fh)
190 {
191 	p = xdr_encode_fhandle(p, fh);
192 	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
193 	return 0;
194 }
195 
196 /*
197  * Encode SETATTR arguments
198  */
199 static int
200 nfs_xdr_sattrargs(struct rpc_rqst *req, u32 *p, struct nfs_sattrargs *args)
201 {
202 	p = xdr_encode_fhandle(p, args->fh);
203 	p = xdr_encode_sattr(p, args->sattr);
204 	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
205 	return 0;
206 }
207 
208 /*
209  * Encode directory ops argument
210  * LOOKUP, REMOVE, RMDIR
211  */
212 static int
213 nfs_xdr_diropargs(struct rpc_rqst *req, u32 *p, struct nfs_diropargs *args)
214 {
215 	p = xdr_encode_fhandle(p, args->fh);
216 	p = xdr_encode_array(p, args->name, args->len);
217 	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
218 	return 0;
219 }
220 
221 /*
222  * Arguments to a READ call. Since we read data directly into the page
223  * cache, we also set up the reply iovec here so that iov[1] points
224  * exactly to the page we want to fetch.
225  */
226 static int
227 nfs_xdr_readargs(struct rpc_rqst *req, u32 *p, struct nfs_readargs *args)
228 {
229 	struct rpc_auth	*auth = req->rq_task->tk_auth;
230 	unsigned int replen;
231 	u32 offset = (u32)args->offset;
232 	u32 count = args->count;
233 
234 	p = xdr_encode_fhandle(p, args->fh);
235 	*p++ = htonl(offset);
236 	*p++ = htonl(count);
237 	*p++ = htonl(count);
238 	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
239 
240 	/* Inline the page array */
241 	replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS_readres_sz) << 2;
242 	xdr_inline_pages(&req->rq_rcv_buf, replen,
243 			 args->pages, args->pgbase, count);
244 	return 0;
245 }
246 
247 /*
248  * Decode READ reply
249  */
250 static int
251 nfs_xdr_readres(struct rpc_rqst *req, u32 *p, struct nfs_readres *res)
252 {
253 	struct kvec *iov = req->rq_rcv_buf.head;
254 	int	status, count, recvd, hdrlen;
255 
256 	if ((status = ntohl(*p++)))
257 		return -nfs_stat_to_errno(status);
258 	p = xdr_decode_fattr(p, res->fattr);
259 
260 	count = ntohl(*p++);
261 	res->eof = 0;
262 	hdrlen = (u8 *) p - (u8 *) iov->iov_base;
263 	if (iov->iov_len < hdrlen) {
264 		printk(KERN_WARNING "NFS: READ reply header overflowed:"
265 				"length %d > %Zu\n", hdrlen, iov->iov_len);
266 		return -errno_NFSERR_IO;
267 	} else if (iov->iov_len != hdrlen) {
268 		dprintk("NFS: READ header is short. iovec will be shifted.\n");
269 		xdr_shift_buf(&req->rq_rcv_buf, iov->iov_len - hdrlen);
270 	}
271 
272 	recvd = req->rq_rcv_buf.len - hdrlen;
273 	if (count > recvd) {
274 		printk(KERN_WARNING "NFS: server cheating in read reply: "
275 			"count %d > recvd %d\n", count, recvd);
276 		count = recvd;
277 	}
278 
279 	dprintk("RPC:      readres OK count %d\n", count);
280 	if (count < res->count)
281 		res->count = count;
282 
283 	return count;
284 }
285 
286 
287 /*
288  * Write arguments. Splice the buffer to be written into the iovec.
289  */
290 static int
291 nfs_xdr_writeargs(struct rpc_rqst *req, u32 *p, struct nfs_writeargs *args)
292 {
293 	struct xdr_buf *sndbuf = &req->rq_snd_buf;
294 	u32 offset = (u32)args->offset;
295 	u32 count = args->count;
296 
297 	p = xdr_encode_fhandle(p, args->fh);
298 	*p++ = htonl(offset);
299 	*p++ = htonl(offset);
300 	*p++ = htonl(count);
301 	*p++ = htonl(count);
302 	sndbuf->len = xdr_adjust_iovec(sndbuf->head, p);
303 
304 	/* Copy the page array */
305 	xdr_encode_pages(sndbuf, args->pages, args->pgbase, count);
306 	return 0;
307 }
308 
309 /*
310  * Encode create arguments
311  * CREATE, MKDIR
312  */
313 static int
314 nfs_xdr_createargs(struct rpc_rqst *req, u32 *p, struct nfs_createargs *args)
315 {
316 	p = xdr_encode_fhandle(p, args->fh);
317 	p = xdr_encode_array(p, args->name, args->len);
318 	p = xdr_encode_sattr(p, args->sattr);
319 	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
320 	return 0;
321 }
322 
323 /*
324  * Encode RENAME arguments
325  */
326 static int
327 nfs_xdr_renameargs(struct rpc_rqst *req, u32 *p, struct nfs_renameargs *args)
328 {
329 	p = xdr_encode_fhandle(p, args->fromfh);
330 	p = xdr_encode_array(p, args->fromname, args->fromlen);
331 	p = xdr_encode_fhandle(p, args->tofh);
332 	p = xdr_encode_array(p, args->toname, args->tolen);
333 	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
334 	return 0;
335 }
336 
337 /*
338  * Encode LINK arguments
339  */
340 static int
341 nfs_xdr_linkargs(struct rpc_rqst *req, u32 *p, struct nfs_linkargs *args)
342 {
343 	p = xdr_encode_fhandle(p, args->fromfh);
344 	p = xdr_encode_fhandle(p, args->tofh);
345 	p = xdr_encode_array(p, args->toname, args->tolen);
346 	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
347 	return 0;
348 }
349 
350 /*
351  * Encode SYMLINK arguments
352  */
353 static int
354 nfs_xdr_symlinkargs(struct rpc_rqst *req, u32 *p, struct nfs_symlinkargs *args)
355 {
356 	p = xdr_encode_fhandle(p, args->fromfh);
357 	p = xdr_encode_array(p, args->fromname, args->fromlen);
358 	p = xdr_encode_array(p, args->topath, args->tolen);
359 	p = xdr_encode_sattr(p, args->sattr);
360 	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
361 	return 0;
362 }
363 
364 /*
365  * Encode arguments to readdir call
366  */
367 static int
368 nfs_xdr_readdirargs(struct rpc_rqst *req, u32 *p, struct nfs_readdirargs *args)
369 {
370 	struct rpc_task	*task = req->rq_task;
371 	struct rpc_auth	*auth = task->tk_auth;
372 	unsigned int replen;
373 	u32 count = args->count;
374 
375 	p = xdr_encode_fhandle(p, args->fh);
376 	*p++ = htonl(args->cookie);
377 	*p++ = htonl(count); /* see above */
378 	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
379 
380 	/* Inline the page array */
381 	replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS_readdirres_sz) << 2;
382 	xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, 0, count);
383 	return 0;
384 }
385 
386 /*
387  * Decode the result of a readdir call.
388  * We're not really decoding anymore, we just leave the buffer untouched
389  * and only check that it is syntactically correct.
390  * The real decoding happens in nfs_decode_entry below, called directly
391  * from nfs_readdir for each entry.
392  */
393 static int
394 nfs_xdr_readdirres(struct rpc_rqst *req, u32 *p, void *dummy)
395 {
396 	struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
397 	struct kvec *iov = rcvbuf->head;
398 	struct page **page;
399 	int hdrlen, recvd;
400 	int status, nr;
401 	unsigned int len, pglen;
402 	u32 *end, *entry, *kaddr;
403 
404 	if ((status = ntohl(*p++)))
405 		return -nfs_stat_to_errno(status);
406 
407 	hdrlen = (u8 *) p - (u8 *) iov->iov_base;
408 	if (iov->iov_len < hdrlen) {
409 		printk(KERN_WARNING "NFS: READDIR reply header overflowed:"
410 				"length %d > %Zu\n", hdrlen, iov->iov_len);
411 		return -errno_NFSERR_IO;
412 	} else if (iov->iov_len != hdrlen) {
413 		dprintk("NFS: READDIR header is short. iovec will be shifted.\n");
414 		xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen);
415 	}
416 
417 	pglen = rcvbuf->page_len;
418 	recvd = rcvbuf->len - hdrlen;
419 	if (pglen > recvd)
420 		pglen = recvd;
421 	page = rcvbuf->pages;
422 	kaddr = p = (u32 *)kmap_atomic(*page, KM_USER0);
423 	end = (u32 *)((char *)p + pglen);
424 	entry = p;
425 	for (nr = 0; *p++; nr++) {
426 		if (p + 2 > end)
427 			goto short_pkt;
428 		p++; /* fileid */
429 		len = ntohl(*p++);
430 		p += XDR_QUADLEN(len) + 1;	/* name plus cookie */
431 		if (len > NFS2_MAXNAMLEN) {
432 			printk(KERN_WARNING "NFS: giant filename in readdir (len 0x%x)!\n",
433 						len);
434 			goto err_unmap;
435 		}
436 		if (p + 2 > end)
437 			goto short_pkt;
438 		entry = p;
439 	}
440 	if (!nr && (entry[0] != 0 || entry[1] == 0))
441 		goto short_pkt;
442  out:
443 	kunmap_atomic(kaddr, KM_USER0);
444 	return nr;
445  short_pkt:
446 	entry[0] = entry[1] = 0;
447 	/* truncate listing ? */
448 	if (!nr) {
449 		printk(KERN_NOTICE "NFS: readdir reply truncated!\n");
450 		entry[1] = 1;
451 	}
452 	goto out;
453 err_unmap:
454 	nr = -errno_NFSERR_IO;
455 	goto out;
456 }
457 
458 u32 *
459 nfs_decode_dirent(u32 *p, struct nfs_entry *entry, int plus)
460 {
461 	if (!*p++) {
462 		if (!*p)
463 			return ERR_PTR(-EAGAIN);
464 		entry->eof = 1;
465 		return ERR_PTR(-EBADCOOKIE);
466 	}
467 
468 	entry->ino	  = ntohl(*p++);
469 	entry->len	  = ntohl(*p++);
470 	entry->name	  = (const char *) p;
471 	p		 += XDR_QUADLEN(entry->len);
472 	entry->prev_cookie	  = entry->cookie;
473 	entry->cookie	  = ntohl(*p++);
474 	entry->eof	  = !p[0] && p[1];
475 
476 	return p;
477 }
478 
479 /*
480  * NFS XDR decode functions
481  */
482 /*
483  * Decode simple status reply
484  */
485 static int
486 nfs_xdr_stat(struct rpc_rqst *req, u32 *p, void *dummy)
487 {
488 	int	status;
489 
490 	if ((status = ntohl(*p++)) != 0)
491 		status = -nfs_stat_to_errno(status);
492 	return status;
493 }
494 
495 /*
496  * Decode attrstat reply
497  * GETATTR, SETATTR, WRITE
498  */
499 static int
500 nfs_xdr_attrstat(struct rpc_rqst *req, u32 *p, struct nfs_fattr *fattr)
501 {
502 	int	status;
503 
504 	if ((status = ntohl(*p++)))
505 		return -nfs_stat_to_errno(status);
506 	xdr_decode_fattr(p, fattr);
507 	return 0;
508 }
509 
510 /*
511  * Decode diropres reply
512  * LOOKUP, CREATE, MKDIR
513  */
514 static int
515 nfs_xdr_diropres(struct rpc_rqst *req, u32 *p, struct nfs_diropok *res)
516 {
517 	int	status;
518 
519 	if ((status = ntohl(*p++)))
520 		return -nfs_stat_to_errno(status);
521 	p = xdr_decode_fhandle(p, res->fh);
522 	xdr_decode_fattr(p, res->fattr);
523 	return 0;
524 }
525 
526 /*
527  * Encode READLINK args
528  */
529 static int
530 nfs_xdr_readlinkargs(struct rpc_rqst *req, u32 *p, struct nfs_readlinkargs *args)
531 {
532 	struct rpc_auth *auth = req->rq_task->tk_auth;
533 	unsigned int replen;
534 
535 	p = xdr_encode_fhandle(p, args->fh);
536 	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
537 
538 	/* Inline the page array */
539 	replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS_readlinkres_sz) << 2;
540 	xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, args->pgbase, args->pglen);
541 	return 0;
542 }
543 
544 /*
545  * Decode READLINK reply
546  */
547 static int
548 nfs_xdr_readlinkres(struct rpc_rqst *req, u32 *p, void *dummy)
549 {
550 	struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
551 	struct kvec *iov = rcvbuf->head;
552 	int hdrlen, len, recvd;
553 	char	*kaddr;
554 	int	status;
555 
556 	if ((status = ntohl(*p++)))
557 		return -nfs_stat_to_errno(status);
558 	/* Convert length of symlink */
559 	len = ntohl(*p++);
560 	if (len >= rcvbuf->page_len || len <= 0) {
561 		dprintk(KERN_WARNING "nfs: server returned giant symlink!\n");
562 		return -ENAMETOOLONG;
563 	}
564 	hdrlen = (u8 *) p - (u8 *) iov->iov_base;
565 	if (iov->iov_len < hdrlen) {
566 		printk(KERN_WARNING "NFS: READLINK reply header overflowed:"
567 				"length %d > %Zu\n", hdrlen, iov->iov_len);
568 		return -errno_NFSERR_IO;
569 	} else if (iov->iov_len != hdrlen) {
570 		dprintk("NFS: READLINK header is short. iovec will be shifted.\n");
571 		xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen);
572 	}
573 	recvd = req->rq_rcv_buf.len - hdrlen;
574 	if (recvd < len) {
575 		printk(KERN_WARNING "NFS: server cheating in readlink reply: "
576 				"count %u > recvd %u\n", len, recvd);
577 		return -EIO;
578 	}
579 
580 	/* NULL terminate the string we got */
581 	kaddr = (char *)kmap_atomic(rcvbuf->pages[0], KM_USER0);
582 	kaddr[len+rcvbuf->page_base] = '\0';
583 	kunmap_atomic(kaddr, KM_USER0);
584 	return 0;
585 }
586 
587 /*
588  * Decode WRITE reply
589  */
590 static int
591 nfs_xdr_writeres(struct rpc_rqst *req, u32 *p, struct nfs_writeres *res)
592 {
593 	res->verf->committed = NFS_FILE_SYNC;
594 	return nfs_xdr_attrstat(req, p, res->fattr);
595 }
596 
597 /*
598  * Decode STATFS reply
599  */
600 static int
601 nfs_xdr_statfsres(struct rpc_rqst *req, u32 *p, struct nfs2_fsstat *res)
602 {
603 	int	status;
604 
605 	if ((status = ntohl(*p++)))
606 		return -nfs_stat_to_errno(status);
607 
608 	res->tsize  = ntohl(*p++);
609 	res->bsize  = ntohl(*p++);
610 	res->blocks = ntohl(*p++);
611 	res->bfree  = ntohl(*p++);
612 	res->bavail = ntohl(*p++);
613 	return 0;
614 }
615 
616 /*
617  * We need to translate between nfs status return values and
618  * the local errno values which may not be the same.
619  */
620 static struct {
621 	int stat;
622 	int errno;
623 } nfs_errtbl[] = {
624 	{ NFS_OK,		0		},
625 	{ NFSERR_PERM,		EPERM		},
626 	{ NFSERR_NOENT,		ENOENT		},
627 	{ NFSERR_IO,		errno_NFSERR_IO	},
628 	{ NFSERR_NXIO,		ENXIO		},
629 /*	{ NFSERR_EAGAIN,	EAGAIN		}, */
630 	{ NFSERR_ACCES,		EACCES		},
631 	{ NFSERR_EXIST,		EEXIST		},
632 	{ NFSERR_XDEV,		EXDEV		},
633 	{ NFSERR_NODEV,		ENODEV		},
634 	{ NFSERR_NOTDIR,	ENOTDIR		},
635 	{ NFSERR_ISDIR,		EISDIR		},
636 	{ NFSERR_INVAL,		EINVAL		},
637 	{ NFSERR_FBIG,		EFBIG		},
638 	{ NFSERR_NOSPC,		ENOSPC		},
639 	{ NFSERR_ROFS,		EROFS		},
640 	{ NFSERR_MLINK,		EMLINK		},
641 	{ NFSERR_NAMETOOLONG,	ENAMETOOLONG	},
642 	{ NFSERR_NOTEMPTY,	ENOTEMPTY	},
643 	{ NFSERR_DQUOT,		EDQUOT		},
644 	{ NFSERR_STALE,		ESTALE		},
645 	{ NFSERR_REMOTE,	EREMOTE		},
646 #ifdef EWFLUSH
647 	{ NFSERR_WFLUSH,	EWFLUSH		},
648 #endif
649 	{ NFSERR_BADHANDLE,	EBADHANDLE	},
650 	{ NFSERR_NOT_SYNC,	ENOTSYNC	},
651 	{ NFSERR_BAD_COOKIE,	EBADCOOKIE	},
652 	{ NFSERR_NOTSUPP,	ENOTSUPP	},
653 	{ NFSERR_TOOSMALL,	ETOOSMALL	},
654 	{ NFSERR_SERVERFAULT,	ESERVERFAULT	},
655 	{ NFSERR_BADTYPE,	EBADTYPE	},
656 	{ NFSERR_JUKEBOX,	EJUKEBOX	},
657 	{ -1,			EIO		}
658 };
659 
660 /*
661  * Convert an NFS error code to a local one.
662  * This one is used jointly by NFSv2 and NFSv3.
663  */
664 int
665 nfs_stat_to_errno(int stat)
666 {
667 	int i;
668 
669 	for (i = 0; nfs_errtbl[i].stat != -1; i++) {
670 		if (nfs_errtbl[i].stat == stat)
671 			return nfs_errtbl[i].errno;
672 	}
673 	printk(KERN_ERR "nfs_stat_to_errno: bad nfs status return value: %d\n", stat);
674 	return nfs_errtbl[i].errno;
675 }
676 
677 #ifndef MAX
678 # define MAX(a, b)	(((a) > (b))? (a) : (b))
679 #endif
680 
681 #define PROC(proc, argtype, restype, timer)				\
682 [NFSPROC_##proc] = {							\
683 	.p_proc	    =  NFSPROC_##proc,					\
684 	.p_encode   =  (kxdrproc_t) nfs_xdr_##argtype,			\
685 	.p_decode   =  (kxdrproc_t) nfs_xdr_##restype,			\
686 	.p_bufsiz   =  MAX(NFS_##argtype##_sz,NFS_##restype##_sz) << 2,	\
687 	.p_timer    =  timer						\
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		= sizeof(nfs_procedures)/sizeof(nfs_procedures[0]),
710 	.procs			= nfs_procedures
711 };
712