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