xref: /openbmc/linux/fs/nfs/nfs2xdr.c (revision 1be27f36)
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  */
68 static inline __be32 *
69 xdr_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 
75 static inline __be32 *
76 xdr_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 
84 static inline __be32*
85 xdr_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 
93 static inline __be32*
94 xdr_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 
110 static inline __be32*
111 xdr_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 
119 static __be32 *
120 xdr_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 
148 static inline __be32 *
149 xdr_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  */
185 static int
186 nfs_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  */
196 static int
197 nfs_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  */
209 static int
210 nfs_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  */
223 static int
224 nfs_xdr_readargs(struct rpc_rqst *req, __be32 *p, struct nfs_readargs *args)
225 {
226 	struct rpc_auth	*auth = req->rq_task->tk_msg.rpc_cred->cr_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  */
247 static int
248 nfs_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  */
287 static int
288 nfs_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  */
310 static int
311 nfs_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  */
323 static int
324 nfs_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  */
337 static int
338 nfs_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  */
350 static int
351 nfs_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  */
379 static int
380 nfs_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_msg.rpc_cred->cr_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  */
405 static int
406 nfs_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;
465 err_unmap:
466 	nr = -errno_NFSERR_IO;
467 	goto out;
468 }
469 
470 __be32 *
471 nfs_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  */
497 static int
498 nfs_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  */
511 static int
512 nfs_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  */
526 static int
527 nfs_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  */
541 static int
542 nfs_xdr_readlinkargs(struct rpc_rqst *req, __be32 *p, struct nfs_readlinkargs *args)
543 {
544 	struct rpc_auth	*auth = req->rq_task->tk_msg.rpc_cred->cr_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  */
559 static int
560 nfs_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  */
602 static int
603 nfs_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  */
612 static int
613 nfs_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  */
632 static 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  */
676 int
677 nfs_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 	}
700 struct 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 
718 struct rpc_version		nfs_version2 = {
719 	.number			= 2,
720 	.nrprocs		= ARRAY_SIZE(nfs_procedures),
721 	.procs			= nfs_procedures
722 };
723