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