xref: /openbmc/linux/fs/nfs/nfs2xdr.c (revision fe82a183)
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_removeargs_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+1+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 __be32 *
70 xdr_encode_fhandle(__be32 *p, const struct nfs_fh *fhandle)
71 {
72 	memcpy(p, fhandle->data, NFS2_FHSIZE);
73 	return p + XDR_QUADLEN(NFS2_FHSIZE);
74 }
75 
76 static inline __be32 *
77 xdr_decode_fhandle(__be32 *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 __be32*
86 xdr_encode_time(__be32 *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 __be32*
95 xdr_encode_current_server_time(__be32 *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 __be32*
112 xdr_decode_time(__be32 *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 __be32 *
121 xdr_decode_fattr(__be32 *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 __be32 *
150 xdr_encode_sattr(__be32 *p, struct iattr *attr)
151 {
152 	const __be32 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, __be32 *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, __be32 *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, RMDIR
209  */
210 static int
211 nfs_xdr_diropargs(struct rpc_rqst *req, __be32 *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  * Encode REMOVE argument
221  */
222 static int
223 nfs_xdr_removeargs(struct rpc_rqst *req, __be32 *p, const struct nfs_removeargs *args)
224 {
225 	p = xdr_encode_fhandle(p, args->fh);
226 	p = xdr_encode_array(p, args->name.name, args->name.len);
227 	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
228 	return 0;
229 }
230 
231 /*
232  * Arguments to a READ call. Since we read data directly into the page
233  * cache, we also set up the reply iovec here so that iov[1] points
234  * exactly to the page we want to fetch.
235  */
236 static int
237 nfs_xdr_readargs(struct rpc_rqst *req, __be32 *p, struct nfs_readargs *args)
238 {
239 	struct rpc_auth	*auth = req->rq_task->tk_msg.rpc_cred->cr_auth;
240 	unsigned int replen;
241 	u32 offset = (u32)args->offset;
242 	u32 count = args->count;
243 
244 	p = xdr_encode_fhandle(p, args->fh);
245 	*p++ = htonl(offset);
246 	*p++ = htonl(count);
247 	*p++ = htonl(count);
248 	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
249 
250 	/* Inline the page array */
251 	replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS_readres_sz) << 2;
252 	xdr_inline_pages(&req->rq_rcv_buf, replen,
253 			 args->pages, args->pgbase, count);
254 	return 0;
255 }
256 
257 /*
258  * Decode READ reply
259  */
260 static int
261 nfs_xdr_readres(struct rpc_rqst *req, __be32 *p, struct nfs_readres *res)
262 {
263 	struct kvec *iov = req->rq_rcv_buf.head;
264 	int	status, count, recvd, hdrlen;
265 
266 	if ((status = ntohl(*p++)))
267 		return -nfs_stat_to_errno(status);
268 	p = xdr_decode_fattr(p, res->fattr);
269 
270 	count = ntohl(*p++);
271 	res->eof = 0;
272 	hdrlen = (u8 *) p - (u8 *) iov->iov_base;
273 	if (iov->iov_len < hdrlen) {
274 		dprintk("NFS: READ reply header overflowed:"
275 				"length %d > %Zu\n", hdrlen, iov->iov_len);
276 		return -errno_NFSERR_IO;
277 	} else if (iov->iov_len != hdrlen) {
278 		dprintk("NFS: READ header is short. iovec will be shifted.\n");
279 		xdr_shift_buf(&req->rq_rcv_buf, iov->iov_len - hdrlen);
280 	}
281 
282 	recvd = req->rq_rcv_buf.len - hdrlen;
283 	if (count > recvd) {
284 		dprintk("NFS: server cheating in read reply: "
285 			"count %d > recvd %d\n", count, recvd);
286 		count = recvd;
287 	}
288 
289 	dprintk("RPC:      readres OK count %d\n", count);
290 	if (count < res->count)
291 		res->count = count;
292 
293 	return count;
294 }
295 
296 
297 /*
298  * Write arguments. Splice the buffer to be written into the iovec.
299  */
300 static int
301 nfs_xdr_writeargs(struct rpc_rqst *req, __be32 *p, struct nfs_writeargs *args)
302 {
303 	struct xdr_buf *sndbuf = &req->rq_snd_buf;
304 	u32 offset = (u32)args->offset;
305 	u32 count = args->count;
306 
307 	p = xdr_encode_fhandle(p, args->fh);
308 	*p++ = htonl(offset);
309 	*p++ = htonl(offset);
310 	*p++ = htonl(count);
311 	*p++ = htonl(count);
312 	sndbuf->len = xdr_adjust_iovec(sndbuf->head, p);
313 
314 	/* Copy the page array */
315 	xdr_encode_pages(sndbuf, args->pages, args->pgbase, count);
316 	return 0;
317 }
318 
319 /*
320  * Encode create arguments
321  * CREATE, MKDIR
322  */
323 static int
324 nfs_xdr_createargs(struct rpc_rqst *req, __be32 *p, struct nfs_createargs *args)
325 {
326 	p = xdr_encode_fhandle(p, args->fh);
327 	p = xdr_encode_array(p, args->name, args->len);
328 	p = xdr_encode_sattr(p, args->sattr);
329 	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
330 	return 0;
331 }
332 
333 /*
334  * Encode RENAME arguments
335  */
336 static int
337 nfs_xdr_renameargs(struct rpc_rqst *req, __be32 *p, struct nfs_renameargs *args)
338 {
339 	p = xdr_encode_fhandle(p, args->fromfh);
340 	p = xdr_encode_array(p, args->fromname, args->fromlen);
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 LINK arguments
349  */
350 static int
351 nfs_xdr_linkargs(struct rpc_rqst *req, __be32 *p, struct nfs_linkargs *args)
352 {
353 	p = xdr_encode_fhandle(p, args->fromfh);
354 	p = xdr_encode_fhandle(p, args->tofh);
355 	p = xdr_encode_array(p, args->toname, args->tolen);
356 	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
357 	return 0;
358 }
359 
360 /*
361  * Encode SYMLINK arguments
362  */
363 static int
364 nfs_xdr_symlinkargs(struct rpc_rqst *req, __be32 *p, struct nfs_symlinkargs *args)
365 {
366 	struct xdr_buf *sndbuf = &req->rq_snd_buf;
367 	size_t pad;
368 
369 	p = xdr_encode_fhandle(p, args->fromfh);
370 	p = xdr_encode_array(p, args->fromname, args->fromlen);
371 	*p++ = htonl(args->pathlen);
372 	sndbuf->len = xdr_adjust_iovec(sndbuf->head, p);
373 
374 	xdr_encode_pages(sndbuf, args->pages, 0, args->pathlen);
375 
376 	/*
377 	 * xdr_encode_pages may have added a few bytes to ensure the
378 	 * pathname ends on a 4-byte boundary.  Start encoding the
379 	 * attributes after the pad bytes.
380 	 */
381 	pad = sndbuf->tail->iov_len;
382 	if (pad > 0)
383 		p++;
384 	p = xdr_encode_sattr(p, args->sattr);
385 	sndbuf->len += xdr_adjust_iovec(sndbuf->tail, p) - pad;
386 	return 0;
387 }
388 
389 /*
390  * Encode arguments to readdir call
391  */
392 static int
393 nfs_xdr_readdirargs(struct rpc_rqst *req, __be32 *p, struct nfs_readdirargs *args)
394 {
395 	struct rpc_task	*task = req->rq_task;
396 	struct rpc_auth	*auth = task->tk_msg.rpc_cred->cr_auth;
397 	unsigned int replen;
398 	u32 count = args->count;
399 
400 	p = xdr_encode_fhandle(p, args->fh);
401 	*p++ = htonl(args->cookie);
402 	*p++ = htonl(count); /* see above */
403 	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
404 
405 	/* Inline the page array */
406 	replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS_readdirres_sz) << 2;
407 	xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, 0, count);
408 	return 0;
409 }
410 
411 /*
412  * Decode the result of a readdir call.
413  * We're not really decoding anymore, we just leave the buffer untouched
414  * and only check that it is syntactically correct.
415  * The real decoding happens in nfs_decode_entry below, called directly
416  * from nfs_readdir for each entry.
417  */
418 static int
419 nfs_xdr_readdirres(struct rpc_rqst *req, __be32 *p, void *dummy)
420 {
421 	struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
422 	struct kvec *iov = rcvbuf->head;
423 	struct page **page;
424 	int hdrlen, recvd;
425 	int status, nr;
426 	unsigned int len, pglen;
427 	__be32 *end, *entry, *kaddr;
428 
429 	if ((status = ntohl(*p++)))
430 		return -nfs_stat_to_errno(status);
431 
432 	hdrlen = (u8 *) p - (u8 *) iov->iov_base;
433 	if (iov->iov_len < hdrlen) {
434 		dprintk("NFS: READDIR reply header overflowed:"
435 				"length %d > %Zu\n", hdrlen, iov->iov_len);
436 		return -errno_NFSERR_IO;
437 	} else if (iov->iov_len != hdrlen) {
438 		dprintk("NFS: READDIR header is short. iovec will be shifted.\n");
439 		xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen);
440 	}
441 
442 	pglen = rcvbuf->page_len;
443 	recvd = rcvbuf->len - hdrlen;
444 	if (pglen > recvd)
445 		pglen = recvd;
446 	page = rcvbuf->pages;
447 	kaddr = p = kmap_atomic(*page, KM_USER0);
448 	end = (__be32 *)((char *)p + pglen);
449 	entry = p;
450 	for (nr = 0; *p++; nr++) {
451 		if (p + 2 > end)
452 			goto short_pkt;
453 		p++; /* fileid */
454 		len = ntohl(*p++);
455 		p += XDR_QUADLEN(len) + 1;	/* name plus cookie */
456 		if (len > NFS2_MAXNAMLEN) {
457 			dprintk("NFS: giant filename in readdir (len 0x%x)!\n",
458 						len);
459 			goto err_unmap;
460 		}
461 		if (p + 2 > end)
462 			goto short_pkt;
463 		entry = p;
464 	}
465 	if (!nr && (entry[0] != 0 || entry[1] == 0))
466 		goto short_pkt;
467  out:
468 	kunmap_atomic(kaddr, KM_USER0);
469 	return nr;
470  short_pkt:
471 	entry[0] = entry[1] = 0;
472 	/* truncate listing ? */
473 	if (!nr) {
474 		dprintk("NFS: readdir reply truncated!\n");
475 		entry[1] = 1;
476 	}
477 	goto out;
478 err_unmap:
479 	nr = -errno_NFSERR_IO;
480 	goto out;
481 }
482 
483 __be32 *
484 nfs_decode_dirent(__be32 *p, struct nfs_entry *entry, int plus)
485 {
486 	if (!*p++) {
487 		if (!*p)
488 			return ERR_PTR(-EAGAIN);
489 		entry->eof = 1;
490 		return ERR_PTR(-EBADCOOKIE);
491 	}
492 
493 	entry->ino	  = ntohl(*p++);
494 	entry->len	  = ntohl(*p++);
495 	entry->name	  = (const char *) p;
496 	p		 += XDR_QUADLEN(entry->len);
497 	entry->prev_cookie	  = entry->cookie;
498 	entry->cookie	  = ntohl(*p++);
499 	entry->eof	  = !p[0] && p[1];
500 
501 	return p;
502 }
503 
504 /*
505  * NFS XDR decode functions
506  */
507 /*
508  * Decode simple status reply
509  */
510 static int
511 nfs_xdr_stat(struct rpc_rqst *req, __be32 *p, void *dummy)
512 {
513 	int	status;
514 
515 	if ((status = ntohl(*p++)) != 0)
516 		status = -nfs_stat_to_errno(status);
517 	return status;
518 }
519 
520 /*
521  * Decode attrstat reply
522  * GETATTR, SETATTR, WRITE
523  */
524 static int
525 nfs_xdr_attrstat(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
526 {
527 	int	status;
528 
529 	if ((status = ntohl(*p++)))
530 		return -nfs_stat_to_errno(status);
531 	xdr_decode_fattr(p, fattr);
532 	return 0;
533 }
534 
535 /*
536  * Decode diropres reply
537  * LOOKUP, CREATE, MKDIR
538  */
539 static int
540 nfs_xdr_diropres(struct rpc_rqst *req, __be32 *p, struct nfs_diropok *res)
541 {
542 	int	status;
543 
544 	if ((status = ntohl(*p++)))
545 		return -nfs_stat_to_errno(status);
546 	p = xdr_decode_fhandle(p, res->fh);
547 	xdr_decode_fattr(p, res->fattr);
548 	return 0;
549 }
550 
551 /*
552  * Encode READLINK args
553  */
554 static int
555 nfs_xdr_readlinkargs(struct rpc_rqst *req, __be32 *p, struct nfs_readlinkargs *args)
556 {
557 	struct rpc_auth	*auth = req->rq_task->tk_msg.rpc_cred->cr_auth;
558 	unsigned int replen;
559 
560 	p = xdr_encode_fhandle(p, args->fh);
561 	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
562 
563 	/* Inline the page array */
564 	replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS_readlinkres_sz) << 2;
565 	xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, args->pgbase, args->pglen);
566 	return 0;
567 }
568 
569 /*
570  * Decode READLINK reply
571  */
572 static int
573 nfs_xdr_readlinkres(struct rpc_rqst *req, __be32 *p, void *dummy)
574 {
575 	struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
576 	struct kvec *iov = rcvbuf->head;
577 	int hdrlen, len, recvd;
578 	char	*kaddr;
579 	int	status;
580 
581 	if ((status = ntohl(*p++)))
582 		return -nfs_stat_to_errno(status);
583 	/* Convert length of symlink */
584 	len = ntohl(*p++);
585 	if (len >= rcvbuf->page_len || len <= 0) {
586 		dprintk("nfs: server returned giant symlink!\n");
587 		return -ENAMETOOLONG;
588 	}
589 	hdrlen = (u8 *) p - (u8 *) iov->iov_base;
590 	if (iov->iov_len < hdrlen) {
591 		dprintk("NFS: READLINK reply header overflowed:"
592 				"length %d > %Zu\n", hdrlen, iov->iov_len);
593 		return -errno_NFSERR_IO;
594 	} else if (iov->iov_len != hdrlen) {
595 		dprintk("NFS: READLINK header is short. iovec will be shifted.\n");
596 		xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen);
597 	}
598 	recvd = req->rq_rcv_buf.len - hdrlen;
599 	if (recvd < len) {
600 		dprintk("NFS: server cheating in readlink reply: "
601 				"count %u > recvd %u\n", len, recvd);
602 		return -EIO;
603 	}
604 
605 	/* NULL terminate the string we got */
606 	kaddr = (char *)kmap_atomic(rcvbuf->pages[0], KM_USER0);
607 	kaddr[len+rcvbuf->page_base] = '\0';
608 	kunmap_atomic(kaddr, KM_USER0);
609 	return 0;
610 }
611 
612 /*
613  * Decode WRITE reply
614  */
615 static int
616 nfs_xdr_writeres(struct rpc_rqst *req, __be32 *p, struct nfs_writeres *res)
617 {
618 	res->verf->committed = NFS_FILE_SYNC;
619 	return nfs_xdr_attrstat(req, p, res->fattr);
620 }
621 
622 /*
623  * Decode STATFS reply
624  */
625 static int
626 nfs_xdr_statfsres(struct rpc_rqst *req, __be32 *p, struct nfs2_fsstat *res)
627 {
628 	int	status;
629 
630 	if ((status = ntohl(*p++)))
631 		return -nfs_stat_to_errno(status);
632 
633 	res->tsize  = ntohl(*p++);
634 	res->bsize  = ntohl(*p++);
635 	res->blocks = ntohl(*p++);
636 	res->bfree  = ntohl(*p++);
637 	res->bavail = ntohl(*p++);
638 	return 0;
639 }
640 
641 /*
642  * We need to translate between nfs status return values and
643  * the local errno values which may not be the same.
644  */
645 static struct {
646 	int stat;
647 	int errno;
648 } nfs_errtbl[] = {
649 	{ NFS_OK,		0		},
650 	{ NFSERR_PERM,		EPERM		},
651 	{ NFSERR_NOENT,		ENOENT		},
652 	{ NFSERR_IO,		errno_NFSERR_IO	},
653 	{ NFSERR_NXIO,		ENXIO		},
654 /*	{ NFSERR_EAGAIN,	EAGAIN		}, */
655 	{ NFSERR_ACCES,		EACCES		},
656 	{ NFSERR_EXIST,		EEXIST		},
657 	{ NFSERR_XDEV,		EXDEV		},
658 	{ NFSERR_NODEV,		ENODEV		},
659 	{ NFSERR_NOTDIR,	ENOTDIR		},
660 	{ NFSERR_ISDIR,		EISDIR		},
661 	{ NFSERR_INVAL,		EINVAL		},
662 	{ NFSERR_FBIG,		EFBIG		},
663 	{ NFSERR_NOSPC,		ENOSPC		},
664 	{ NFSERR_ROFS,		EROFS		},
665 	{ NFSERR_MLINK,		EMLINK		},
666 	{ NFSERR_NAMETOOLONG,	ENAMETOOLONG	},
667 	{ NFSERR_NOTEMPTY,	ENOTEMPTY	},
668 	{ NFSERR_DQUOT,		EDQUOT		},
669 	{ NFSERR_STALE,		ESTALE		},
670 	{ NFSERR_REMOTE,	EREMOTE		},
671 #ifdef EWFLUSH
672 	{ NFSERR_WFLUSH,	EWFLUSH		},
673 #endif
674 	{ NFSERR_BADHANDLE,	EBADHANDLE	},
675 	{ NFSERR_NOT_SYNC,	ENOTSYNC	},
676 	{ NFSERR_BAD_COOKIE,	EBADCOOKIE	},
677 	{ NFSERR_NOTSUPP,	ENOTSUPP	},
678 	{ NFSERR_TOOSMALL,	ETOOSMALL	},
679 	{ NFSERR_SERVERFAULT,	ESERVERFAULT	},
680 	{ NFSERR_BADTYPE,	EBADTYPE	},
681 	{ NFSERR_JUKEBOX,	EJUKEBOX	},
682 	{ -1,			EIO		}
683 };
684 
685 /*
686  * Convert an NFS error code to a local one.
687  * This one is used jointly by NFSv2 and NFSv3.
688  */
689 int
690 nfs_stat_to_errno(int stat)
691 {
692 	int i;
693 
694 	for (i = 0; nfs_errtbl[i].stat != -1; i++) {
695 		if (nfs_errtbl[i].stat == stat)
696 			return nfs_errtbl[i].errno;
697 	}
698 	dprintk("nfs_stat_to_errno: bad nfs status return value: %d\n", stat);
699 	return nfs_errtbl[i].errno;
700 }
701 
702 #define PROC(proc, argtype, restype, timer)				\
703 [NFSPROC_##proc] = {							\
704 	.p_proc	    =  NFSPROC_##proc,					\
705 	.p_encode   =  (kxdrproc_t) nfs_xdr_##argtype,			\
706 	.p_decode   =  (kxdrproc_t) nfs_xdr_##restype,			\
707 	.p_arglen   =  NFS_##argtype##_sz,				\
708 	.p_replen   =  NFS_##restype##_sz,				\
709 	.p_timer    =  timer,						\
710 	.p_statidx  =  NFSPROC_##proc,					\
711 	.p_name     =  #proc,						\
712 	}
713 struct rpc_procinfo	nfs_procedures[] = {
714     PROC(GETATTR,	fhandle,	attrstat, 1),
715     PROC(SETATTR,	sattrargs,	attrstat, 0),
716     PROC(LOOKUP,	diropargs,	diropres, 2),
717     PROC(READLINK,	readlinkargs,	readlinkres, 3),
718     PROC(READ,		readargs,	readres, 3),
719     PROC(WRITE,		writeargs,	writeres, 4),
720     PROC(CREATE,	createargs,	diropres, 0),
721     PROC(REMOVE,	removeargs,	stat, 0),
722     PROC(RENAME,	renameargs,	stat, 0),
723     PROC(LINK,		linkargs,	stat, 0),
724     PROC(SYMLINK,	symlinkargs,	stat, 0),
725     PROC(MKDIR,		createargs,	diropres, 0),
726     PROC(RMDIR,		diropargs,	stat, 0),
727     PROC(READDIR,	readdirargs,	readdirres, 3),
728     PROC(STATFS,	fhandle,	statfsres, 0),
729 };
730 
731 struct rpc_version		nfs_version2 = {
732 	.number			= 2,
733 	.nrprocs		= ARRAY_SIZE(nfs_procedures),
734 	.procs			= nfs_procedures
735 };
736