1/*
2 * linux/fs/nfs/nfs3xdr.c
3 *
4 * XDR functions to encode/decode NFSv3 RPC arguments and results.
5 *
6 * Copyright (C) 1996, 1997 Olaf Kirch
7 */
8
9#include <linux/param.h>
10#include <linux/time.h>
11#include <linux/mm.h>
12#include <linux/errno.h>
13#include <linux/string.h>
14#include <linux/in.h>
15#include <linux/pagemap.h>
16#include <linux/proc_fs.h>
17#include <linux/kdev_t.h>
18#include <linux/sunrpc/clnt.h>
19#include <linux/nfs.h>
20#include <linux/nfs3.h>
21#include <linux/nfs_fs.h>
22#include <linux/nfsacl.h>
23#include "internal.h"
24
25#define NFSDBG_FACILITY		NFSDBG_XDR
26
27/* Mapping from NFS error code to "errno" error code. */
28#define errno_NFSERR_IO		EIO
29
30/*
31 * Declare the space requirements for NFS arguments and replies as
32 * number of 32bit-words
33 */
34#define NFS3_fhandle_sz		(1+16)
35#define NFS3_fh_sz		(NFS3_fhandle_sz)	/* shorthand */
36#define NFS3_sattr_sz		(15)
37#define NFS3_filename_sz	(1+(NFS3_MAXNAMLEN>>2))
38#define NFS3_path_sz		(1+(NFS3_MAXPATHLEN>>2))
39#define NFS3_fattr_sz		(21)
40#define NFS3_wcc_attr_sz		(6)
41#define NFS3_pre_op_attr_sz	(1+NFS3_wcc_attr_sz)
42#define NFS3_post_op_attr_sz	(1+NFS3_fattr_sz)
43#define NFS3_wcc_data_sz		(NFS3_pre_op_attr_sz+NFS3_post_op_attr_sz)
44#define NFS3_fsstat_sz
45#define NFS3_fsinfo_sz
46#define NFS3_pathconf_sz
47#define NFS3_entry_sz		(NFS3_filename_sz+3)
48
49#define NFS3_sattrargs_sz	(NFS3_fh_sz+NFS3_sattr_sz+3)
50#define NFS3_diropargs_sz	(NFS3_fh_sz+NFS3_filename_sz)
51#define NFS3_removeargs_sz	(NFS3_fh_sz+NFS3_filename_sz)
52#define NFS3_accessargs_sz	(NFS3_fh_sz+1)
53#define NFS3_readlinkargs_sz	(NFS3_fh_sz)
54#define NFS3_readargs_sz	(NFS3_fh_sz+3)
55#define NFS3_writeargs_sz	(NFS3_fh_sz+5)
56#define NFS3_createargs_sz	(NFS3_diropargs_sz+NFS3_sattr_sz)
57#define NFS3_mkdirargs_sz	(NFS3_diropargs_sz+NFS3_sattr_sz)
58#define NFS3_symlinkargs_sz	(NFS3_diropargs_sz+1+NFS3_sattr_sz)
59#define NFS3_mknodargs_sz	(NFS3_diropargs_sz+2+NFS3_sattr_sz)
60#define NFS3_renameargs_sz	(NFS3_diropargs_sz+NFS3_diropargs_sz)
61#define NFS3_linkargs_sz		(NFS3_fh_sz+NFS3_diropargs_sz)
62#define NFS3_readdirargs_sz	(NFS3_fh_sz+2)
63#define NFS3_commitargs_sz	(NFS3_fh_sz+3)
64
65#define NFS3_attrstat_sz	(1+NFS3_fattr_sz)
66#define NFS3_wccstat_sz		(1+NFS3_wcc_data_sz)
67#define NFS3_removeres_sz	(NFS3_wccstat_sz)
68#define NFS3_lookupres_sz	(1+NFS3_fh_sz+(2 * NFS3_post_op_attr_sz))
69#define NFS3_accessres_sz	(1+NFS3_post_op_attr_sz+1)
70#define NFS3_readlinkres_sz	(1+NFS3_post_op_attr_sz+1)
71#define NFS3_readres_sz		(1+NFS3_post_op_attr_sz+3)
72#define NFS3_writeres_sz	(1+NFS3_wcc_data_sz+4)
73#define NFS3_createres_sz	(1+NFS3_fh_sz+NFS3_post_op_attr_sz+NFS3_wcc_data_sz)
74#define NFS3_renameres_sz	(1+(2 * NFS3_wcc_data_sz))
75#define NFS3_linkres_sz		(1+NFS3_post_op_attr_sz+NFS3_wcc_data_sz)
76#define NFS3_readdirres_sz	(1+NFS3_post_op_attr_sz+2)
77#define NFS3_fsstatres_sz	(1+NFS3_post_op_attr_sz+13)
78#define NFS3_fsinfores_sz	(1+NFS3_post_op_attr_sz+12)
79#define NFS3_pathconfres_sz	(1+NFS3_post_op_attr_sz+6)
80#define NFS3_commitres_sz	(1+NFS3_wcc_data_sz+2)
81
82#define ACL3_getaclargs_sz	(NFS3_fh_sz+1)
83#define ACL3_setaclargs_sz	(NFS3_fh_sz+1+ \
84				XDR_QUADLEN(NFS_ACL_INLINE_BUFSIZE))
85#define ACL3_getaclres_sz	(1+NFS3_post_op_attr_sz+1+ \
86				XDR_QUADLEN(NFS_ACL_INLINE_BUFSIZE))
87#define ACL3_setaclres_sz	(1+NFS3_post_op_attr_sz)
88
89/*
90 * Map file type to S_IFMT bits
91 */
92static const umode_t nfs_type2fmt[] = {
93	[NF3BAD] = 0,
94	[NF3REG] = S_IFREG,
95	[NF3DIR] = S_IFDIR,
96	[NF3BLK] = S_IFBLK,
97	[NF3CHR] = S_IFCHR,
98	[NF3LNK] = S_IFLNK,
99	[NF3SOCK] = S_IFSOCK,
100	[NF3FIFO] = S_IFIFO,
101};
102
103/*
104 * Common NFS XDR functions as inlines
105 */
106static inline __be32 *
107xdr_encode_fhandle(__be32 *p, const struct nfs_fh *fh)
108{
109	return xdr_encode_array(p, fh->data, fh->size);
110}
111
112static inline __be32 *
113xdr_decode_fhandle(__be32 *p, struct nfs_fh *fh)
114{
115	if ((fh->size = ntohl(*p++)) <= NFS3_FHSIZE) {
116		memcpy(fh->data, p, fh->size);
117		return p + XDR_QUADLEN(fh->size);
118	}
119	return NULL;
120}
121
122/*
123 * Encode/decode time.
124 */
125static inline __be32 *
126xdr_encode_time3(__be32 *p, struct timespec *timep)
127{
128	*p++ = htonl(timep->tv_sec);
129	*p++ = htonl(timep->tv_nsec);
130	return p;
131}
132
133static inline __be32 *
134xdr_decode_time3(__be32 *p, struct timespec *timep)
135{
136	timep->tv_sec = ntohl(*p++);
137	timep->tv_nsec = ntohl(*p++);
138	return p;
139}
140
141static __be32 *
142xdr_decode_fattr(__be32 *p, struct nfs_fattr *fattr)
143{
144	unsigned int	type, major, minor;
145	umode_t		fmode;
146
147	type = ntohl(*p++);
148	if (type > NF3FIFO)
149		type = NF3NON;
150	fmode = nfs_type2fmt[type];
151	fattr->mode = (ntohl(*p++) & ~S_IFMT) | fmode;
152	fattr->nlink = ntohl(*p++);
153	fattr->uid = ntohl(*p++);
154	fattr->gid = ntohl(*p++);
155	p = xdr_decode_hyper(p, &fattr->size);
156	p = xdr_decode_hyper(p, &fattr->du.nfs3.used);
157
158	/* Turn remote device info into Linux-specific dev_t */
159	major = ntohl(*p++);
160	minor = ntohl(*p++);
161	fattr->rdev = MKDEV(major, minor);
162	if (MAJOR(fattr->rdev) != major || MINOR(fattr->rdev) != minor)
163		fattr->rdev = 0;
164
165	p = xdr_decode_hyper(p, &fattr->fsid.major);
166	fattr->fsid.minor = 0;
167	p = xdr_decode_hyper(p, &fattr->fileid);
168	p = xdr_decode_time3(p, &fattr->atime);
169	p = xdr_decode_time3(p, &fattr->mtime);
170	p = xdr_decode_time3(p, &fattr->ctime);
171
172	/* Update the mode bits */
173	fattr->valid |= NFS_ATTR_FATTR_V3;
174	return p;
175}
176
177static inline __be32 *
178xdr_encode_sattr(__be32 *p, struct iattr *attr)
179{
180	if (attr->ia_valid & ATTR_MODE) {
181		*p++ = xdr_one;
182		*p++ = htonl(attr->ia_mode & S_IALLUGO);
183	} else {
184		*p++ = xdr_zero;
185	}
186	if (attr->ia_valid & ATTR_UID) {
187		*p++ = xdr_one;
188		*p++ = htonl(attr->ia_uid);
189	} else {
190		*p++ = xdr_zero;
191	}
192	if (attr->ia_valid & ATTR_GID) {
193		*p++ = xdr_one;
194		*p++ = htonl(attr->ia_gid);
195	} else {
196		*p++ = xdr_zero;
197	}
198	if (attr->ia_valid & ATTR_SIZE) {
199		*p++ = xdr_one;
200		p = xdr_encode_hyper(p, (__u64) attr->ia_size);
201	} else {
202		*p++ = xdr_zero;
203	}
204	if (attr->ia_valid & ATTR_ATIME_SET) {
205		*p++ = xdr_two;
206		p = xdr_encode_time3(p, &attr->ia_atime);
207	} else if (attr->ia_valid & ATTR_ATIME) {
208		*p++ = xdr_one;
209	} else {
210		*p++ = xdr_zero;
211	}
212	if (attr->ia_valid & ATTR_MTIME_SET) {
213		*p++ = xdr_two;
214		p = xdr_encode_time3(p, &attr->ia_mtime);
215	} else if (attr->ia_valid & ATTR_MTIME) {
216		*p++ = xdr_one;
217	} else {
218		*p++ = xdr_zero;
219	}
220	return p;
221}
222
223static inline __be32 *
224xdr_decode_wcc_attr(__be32 *p, struct nfs_fattr *fattr)
225{
226	p = xdr_decode_hyper(p, &fattr->pre_size);
227	p = xdr_decode_time3(p, &fattr->pre_mtime);
228	p = xdr_decode_time3(p, &fattr->pre_ctime);
229	fattr->valid |= NFS_ATTR_FATTR_PRESIZE
230		| NFS_ATTR_FATTR_PREMTIME
231		| NFS_ATTR_FATTR_PRECTIME;
232	return p;
233}
234
235static inline __be32 *
236xdr_decode_post_op_attr(__be32 *p, struct nfs_fattr *fattr)
237{
238	if (*p++)
239		p = xdr_decode_fattr(p, fattr);
240	return p;
241}
242
243static inline __be32 *
244xdr_decode_pre_op_attr(__be32 *p, struct nfs_fattr *fattr)
245{
246	if (*p++)
247		return xdr_decode_wcc_attr(p, fattr);
248	return p;
249}
250
251
252static inline __be32 *
253xdr_decode_wcc_data(__be32 *p, struct nfs_fattr *fattr)
254{
255	p = xdr_decode_pre_op_attr(p, fattr);
256	return xdr_decode_post_op_attr(p, fattr);
257}
258
259/*
260 * NFS encode functions
261 */
262
263/*
264 * Encode file handle argument
265 */
266static int
267nfs3_xdr_fhandle(struct rpc_rqst *req, __be32 *p, struct nfs_fh *fh)
268{
269	p = xdr_encode_fhandle(p, fh);
270	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
271	return 0;
272}
273
274/*
275 * Encode SETATTR arguments
276 */
277static int
278nfs3_xdr_sattrargs(struct rpc_rqst *req, __be32 *p, struct nfs3_sattrargs *args)
279{
280	p = xdr_encode_fhandle(p, args->fh);
281	p = xdr_encode_sattr(p, args->sattr);
282	*p++ = htonl(args->guard);
283	if (args->guard)
284		p = xdr_encode_time3(p, &args->guardtime);
285	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
286	return 0;
287}
288
289/*
290 * Encode directory ops argument
291 */
292static int
293nfs3_xdr_diropargs(struct rpc_rqst *req, __be32 *p, struct nfs3_diropargs *args)
294{
295	p = xdr_encode_fhandle(p, args->fh);
296	p = xdr_encode_array(p, args->name, args->len);
297	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
298	return 0;
299}
300
301/*
302 * Encode REMOVE argument
303 */
304static int
305nfs3_xdr_removeargs(struct rpc_rqst *req, __be32 *p, const struct nfs_removeargs *args)
306{
307	p = xdr_encode_fhandle(p, args->fh);
308	p = xdr_encode_array(p, args->name.name, args->name.len);
309	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
310	return 0;
311}
312
313/*
314 * Encode access() argument
315 */
316static int
317nfs3_xdr_accessargs(struct rpc_rqst *req, __be32 *p, struct nfs3_accessargs *args)
318{
319	p = xdr_encode_fhandle(p, args->fh);
320	*p++ = htonl(args->access);
321	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
322	return 0;
323}
324
325/*
326 * Arguments to a READ call. Since we read data directly into the page
327 * cache, we also set up the reply iovec here so that iov[1] points
328 * exactly to the page we want to fetch.
329 */
330static int
331nfs3_xdr_readargs(struct rpc_rqst *req, __be32 *p, struct nfs_readargs *args)
332{
333	struct rpc_auth	*auth = req->rq_cred->cr_auth;
334	unsigned int replen;
335	u32 count = args->count;
336
337	p = xdr_encode_fhandle(p, args->fh);
338	p = xdr_encode_hyper(p, args->offset);
339	*p++ = htonl(count);
340	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
341
342	/* Inline the page array */
343	replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS3_readres_sz) << 2;
344	xdr_inline_pages(&req->rq_rcv_buf, replen,
345			 args->pages, args->pgbase, count);
346	req->rq_rcv_buf.flags |= XDRBUF_READ;
347	return 0;
348}
349
350/*
351 * Write arguments. Splice the buffer to be written into the iovec.
352 */
353static int
354nfs3_xdr_writeargs(struct rpc_rqst *req, __be32 *p, struct nfs_writeargs *args)
355{
356	struct xdr_buf *sndbuf = &req->rq_snd_buf;
357	u32 count = args->count;
358
359	p = xdr_encode_fhandle(p, args->fh);
360	p = xdr_encode_hyper(p, args->offset);
361	*p++ = htonl(count);
362	*p++ = htonl(args->stable);
363	*p++ = htonl(count);
364	sndbuf->len = xdr_adjust_iovec(sndbuf->head, p);
365
366	/* Copy the page array */
367	xdr_encode_pages(sndbuf, args->pages, args->pgbase, count);
368	sndbuf->flags |= XDRBUF_WRITE;
369	return 0;
370}
371
372/*
373 * Encode CREATE arguments
374 */
375static int
376nfs3_xdr_createargs(struct rpc_rqst *req, __be32 *p, struct nfs3_createargs *args)
377{
378	p = xdr_encode_fhandle(p, args->fh);
379	p = xdr_encode_array(p, args->name, args->len);
380
381	*p++ = htonl(args->createmode);
382	if (args->createmode == NFS3_CREATE_EXCLUSIVE) {
383		*p++ = args->verifier[0];
384		*p++ = args->verifier[1];
385	} else
386		p = xdr_encode_sattr(p, args->sattr);
387
388	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
389	return 0;
390}
391
392/*
393 * Encode MKDIR arguments
394 */
395static int
396nfs3_xdr_mkdirargs(struct rpc_rqst *req, __be32 *p, struct nfs3_mkdirargs *args)
397{
398	p = xdr_encode_fhandle(p, args->fh);
399	p = xdr_encode_array(p, args->name, args->len);
400	p = xdr_encode_sattr(p, args->sattr);
401	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
402	return 0;
403}
404
405/*
406 * Encode SYMLINK arguments
407 */
408static int
409nfs3_xdr_symlinkargs(struct rpc_rqst *req, __be32 *p, struct nfs3_symlinkargs *args)
410{
411	p = xdr_encode_fhandle(p, args->fromfh);
412	p = xdr_encode_array(p, args->fromname, args->fromlen);
413	p = xdr_encode_sattr(p, args->sattr);
414	*p++ = htonl(args->pathlen);
415	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
416
417	/* Copy the page */
418	xdr_encode_pages(&req->rq_snd_buf, args->pages, 0, args->pathlen);
419	return 0;
420}
421
422/*
423 * Encode MKNOD arguments
424 */
425static int
426nfs3_xdr_mknodargs(struct rpc_rqst *req, __be32 *p, struct nfs3_mknodargs *args)
427{
428	p = xdr_encode_fhandle(p, args->fh);
429	p = xdr_encode_array(p, args->name, args->len);
430	*p++ = htonl(args->type);
431	p = xdr_encode_sattr(p, args->sattr);
432	if (args->type == NF3CHR || args->type == NF3BLK) {
433		*p++ = htonl(MAJOR(args->rdev));
434		*p++ = htonl(MINOR(args->rdev));
435	}
436
437	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
438	return 0;
439}
440
441/*
442 * Encode RENAME arguments
443 */
444static int
445nfs3_xdr_renameargs(struct rpc_rqst *req, __be32 *p, struct nfs3_renameargs *args)
446{
447	p = xdr_encode_fhandle(p, args->fromfh);
448	p = xdr_encode_array(p, args->fromname, args->fromlen);
449	p = xdr_encode_fhandle(p, args->tofh);
450	p = xdr_encode_array(p, args->toname, args->tolen);
451	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
452	return 0;
453}
454
455/*
456 * Encode LINK arguments
457 */
458static int
459nfs3_xdr_linkargs(struct rpc_rqst *req, __be32 *p, struct nfs3_linkargs *args)
460{
461	p = xdr_encode_fhandle(p, args->fromfh);
462	p = xdr_encode_fhandle(p, args->tofh);
463	p = xdr_encode_array(p, args->toname, args->tolen);
464	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
465	return 0;
466}
467
468/*
469 * Encode arguments to readdir call
470 */
471static int
472nfs3_xdr_readdirargs(struct rpc_rqst *req, __be32 *p, struct nfs3_readdirargs *args)
473{
474	struct rpc_auth	*auth = req->rq_cred->cr_auth;
475	unsigned int replen;
476	u32 count = args->count;
477
478	p = xdr_encode_fhandle(p, args->fh);
479	p = xdr_encode_hyper(p, args->cookie);
480	*p++ = args->verf[0];
481	*p++ = args->verf[1];
482	if (args->plus) {
483		/* readdirplus: need dircount + buffer size.
484		 * We just make sure we make dircount big enough */
485		*p++ = htonl(count >> 3);
486	}
487	*p++ = htonl(count);
488	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
489
490	/* Inline the page array */
491	replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS3_readdirres_sz) << 2;
492	xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, 0, count);
493	return 0;
494}
495
496/*
497 * Decode the result of a readdir call.
498 * We just check for syntactical correctness.
499 */
500static int
501nfs3_xdr_readdirres(struct rpc_rqst *req, __be32 *p, struct nfs3_readdirres *res)
502{
503	struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
504	struct kvec *iov = rcvbuf->head;
505	struct page **page;
506	size_t hdrlen;
507	u32 len, recvd, pglen;
508	int status, nr = 0;
509	__be32 *entry, *end, *kaddr;
510
511	status = ntohl(*p++);
512	/* Decode post_op_attrs */
513	p = xdr_decode_post_op_attr(p, res->dir_attr);
514	if (status)
515		return nfs_stat_to_errno(status);
516	/* Decode verifier cookie */
517	if (res->verf) {
518		res->verf[0] = *p++;
519		res->verf[1] = *p++;
520	} else {
521		p += 2;
522	}
523
524	hdrlen = (u8 *) p - (u8 *) iov->iov_base;
525	if (iov->iov_len < hdrlen) {
526		dprintk("NFS: READDIR reply header overflowed:"
527				"length %Zu > %Zu\n", hdrlen, iov->iov_len);
528		return -errno_NFSERR_IO;
529	} else if (iov->iov_len != hdrlen) {
530		dprintk("NFS: READDIR header is short. iovec will be shifted.\n");
531		xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen);
532	}
533
534	pglen = rcvbuf->page_len;
535	recvd = rcvbuf->len - hdrlen;
536	if (pglen > recvd)
537		pglen = recvd;
538	page = rcvbuf->pages;
539	kaddr = p = kmap_atomic(*page, KM_USER0);
540	end = (__be32 *)((char *)p + pglen);
541	entry = p;
542
543	/* Make sure the packet actually has a value_follows and EOF entry */
544	if ((entry + 1) > end)
545		goto short_pkt;
546
547	for (; *p++; nr++) {
548		if (p + 3 > end)
549			goto short_pkt;
550		p += 2;				/* inode # */
551		len = ntohl(*p++);		/* string length */
552		p += XDR_QUADLEN(len) + 2;	/* name + cookie */
553		if (len > NFS3_MAXNAMLEN) {
554			dprintk("NFS: giant filename in readdir (len 0x%x)!\n",
555						len);
556			goto err_unmap;
557		}
558
559		if (res->plus) {
560			/* post_op_attr */
561			if (p + 2 > end)
562				goto short_pkt;
563			if (*p++) {
564				p += 21;
565				if (p + 1 > end)
566					goto short_pkt;
567			}
568			/* post_op_fh3 */
569			if (*p++) {
570				if (p + 1 > end)
571					goto short_pkt;
572				len = ntohl(*p++);
573				if (len > NFS3_FHSIZE) {
574					dprintk("NFS: giant filehandle in "
575						"readdir (len 0x%x)!\n", len);
576					goto err_unmap;
577				}
578				p += XDR_QUADLEN(len);
579			}
580		}
581
582		if (p + 2 > end)
583			goto short_pkt;
584		entry = p;
585	}
586
587	/*
588	 * Apparently some server sends responses that are a valid size, but
589	 * contain no entries, and have value_follows==0 and EOF==0. For
590	 * those, just set the EOF marker.
591	 */
592	if (!nr && entry[1] == 0) {
593		dprintk("NFS: readdir reply truncated!\n");
594		entry[1] = 1;
595	}
596 out:
597	kunmap_atomic(kaddr, KM_USER0);
598	return nr;
599 short_pkt:
600	/*
601	 * When we get a short packet there are 2 possibilities. We can
602	 * return an error, or fix up the response to look like a valid
603	 * response and return what we have so far. If there are no
604	 * entries and the packet was short, then return -EIO. If there
605	 * are valid entries in the response, return them and pretend that
606	 * the call was successful, but incomplete. The caller can retry the
607	 * readdir starting at the last cookie.
608	 */
609	entry[0] = entry[1] = 0;
610	if (!nr)
611		nr = -errno_NFSERR_IO;
612	goto out;
613err_unmap:
614	nr = -errno_NFSERR_IO;
615	goto out;
616}
617
618__be32 *
619nfs3_decode_dirent(__be32 *p, struct nfs_entry *entry, int plus)
620{
621	struct nfs_entry old = *entry;
622
623	if (!*p++) {
624		if (!*p)
625			return ERR_PTR(-EAGAIN);
626		entry->eof = 1;
627		return ERR_PTR(-EBADCOOKIE);
628	}
629
630	p = xdr_decode_hyper(p, &entry->ino);
631	entry->len  = ntohl(*p++);
632	entry->name = (const char *) p;
633	p += XDR_QUADLEN(entry->len);
634	entry->prev_cookie = entry->cookie;
635	p = xdr_decode_hyper(p, &entry->cookie);
636
637	if (plus) {
638		entry->fattr->valid = 0;
639		p = xdr_decode_post_op_attr(p, entry->fattr);
640		/* In fact, a post_op_fh3: */
641		if (*p++) {
642			p = xdr_decode_fhandle(p, entry->fh);
643			/* Ugh -- server reply was truncated */
644			if (p == NULL) {
645				dprintk("NFS: FH truncated\n");
646				*entry = old;
647				return ERR_PTR(-EAGAIN);
648			}
649		} else
650			memset((u8*)(entry->fh), 0, sizeof(*entry->fh));
651	}
652
653	entry->eof = !p[0] && p[1];
654	return p;
655}
656
657/*
658 * Encode COMMIT arguments
659 */
660static int
661nfs3_xdr_commitargs(struct rpc_rqst *req, __be32 *p, struct nfs_writeargs *args)
662{
663	p = xdr_encode_fhandle(p, args->fh);
664	p = xdr_encode_hyper(p, args->offset);
665	*p++ = htonl(args->count);
666	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
667	return 0;
668}
669
670#ifdef CONFIG_NFS_V3_ACL
671/*
672 * Encode GETACL arguments
673 */
674static int
675nfs3_xdr_getaclargs(struct rpc_rqst *req, __be32 *p,
676		    struct nfs3_getaclargs *args)
677{
678	struct rpc_auth	*auth = req->rq_cred->cr_auth;
679	unsigned int replen;
680
681	p = xdr_encode_fhandle(p, args->fh);
682	*p++ = htonl(args->mask);
683	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
684
685	if (args->mask & (NFS_ACL | NFS_DFACL)) {
686		/* Inline the page array */
687		replen = (RPC_REPHDRSIZE + auth->au_rslack +
688			  ACL3_getaclres_sz) << 2;
689		xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, 0,
690				 NFSACL_MAXPAGES << PAGE_SHIFT);
691	}
692	return 0;
693}
694
695/*
696 * Encode SETACL arguments
697 */
698static int
699nfs3_xdr_setaclargs(struct rpc_rqst *req, __be32 *p,
700                   struct nfs3_setaclargs *args)
701{
702	struct xdr_buf *buf = &req->rq_snd_buf;
703	unsigned int base;
704	int err;
705
706	p = xdr_encode_fhandle(p, NFS_FH(args->inode));
707	*p++ = htonl(args->mask);
708	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
709	base = req->rq_slen;
710
711	if (args->npages != 0)
712		xdr_encode_pages(buf, args->pages, 0, args->len);
713	else
714		req->rq_slen = xdr_adjust_iovec(req->rq_svec,
715				p + XDR_QUADLEN(args->len));
716
717	err = nfsacl_encode(buf, base, args->inode,
718			    (args->mask & NFS_ACL) ?
719			    args->acl_access : NULL, 1, 0);
720	if (err > 0)
721		err = nfsacl_encode(buf, base + err, args->inode,
722				    (args->mask & NFS_DFACL) ?
723				    args->acl_default : NULL, 1,
724				    NFS_ACL_DEFAULT);
725	return (err > 0) ? 0 : err;
726}
727#endif  /* CONFIG_NFS_V3_ACL */
728
729/*
730 * NFS XDR decode functions
731 */
732
733/*
734 * Decode attrstat reply.
735 */
736static int
737nfs3_xdr_attrstat(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
738{
739	int	status;
740
741	if ((status = ntohl(*p++)))
742		return nfs_stat_to_errno(status);
743	xdr_decode_fattr(p, fattr);
744	return 0;
745}
746
747/*
748 * Decode status+wcc_data reply
749 * SATTR, REMOVE, RMDIR
750 */
751static int
752nfs3_xdr_wccstat(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
753{
754	int	status;
755
756	if ((status = ntohl(*p++)))
757		status = nfs_stat_to_errno(status);
758	xdr_decode_wcc_data(p, fattr);
759	return status;
760}
761
762static int
763nfs3_xdr_removeres(struct rpc_rqst *req, __be32 *p, struct nfs_removeres *res)
764{
765	return nfs3_xdr_wccstat(req, p, res->dir_attr);
766}
767
768/*
769 * Decode LOOKUP reply
770 */
771static int
772nfs3_xdr_lookupres(struct rpc_rqst *req, __be32 *p, struct nfs3_diropres *res)
773{
774	int	status;
775
776	if ((status = ntohl(*p++))) {
777		status = nfs_stat_to_errno(status);
778	} else {
779		if (!(p = xdr_decode_fhandle(p, res->fh)))
780			return -errno_NFSERR_IO;
781		p = xdr_decode_post_op_attr(p, res->fattr);
782	}
783	xdr_decode_post_op_attr(p, res->dir_attr);
784	return status;
785}
786
787/*
788 * Decode ACCESS reply
789 */
790static int
791nfs3_xdr_accessres(struct rpc_rqst *req, __be32 *p, struct nfs3_accessres *res)
792{
793	int	status = ntohl(*p++);
794
795	p = xdr_decode_post_op_attr(p, res->fattr);
796	if (status)
797		return nfs_stat_to_errno(status);
798	res->access = ntohl(*p++);
799	return 0;
800}
801
802static int
803nfs3_xdr_readlinkargs(struct rpc_rqst *req, __be32 *p, struct nfs3_readlinkargs *args)
804{
805	struct rpc_auth	*auth = req->rq_cred->cr_auth;
806	unsigned int replen;
807
808	p = xdr_encode_fhandle(p, args->fh);
809	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
810
811	/* Inline the page array */
812	replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS3_readlinkres_sz) << 2;
813	xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, args->pgbase, args->pglen);
814	return 0;
815}
816
817/*
818 * Decode READLINK reply
819 */
820static int
821nfs3_xdr_readlinkres(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
822{
823	struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
824	struct kvec *iov = rcvbuf->head;
825	size_t hdrlen;
826	u32 len, recvd;
827	char	*kaddr;
828	int	status;
829
830	status = ntohl(*p++);
831	p = xdr_decode_post_op_attr(p, fattr);
832
833	if (status != 0)
834		return nfs_stat_to_errno(status);
835
836	/* Convert length of symlink */
837	len = ntohl(*p++);
838	if (len >= rcvbuf->page_len) {
839		dprintk("nfs: server returned giant symlink!\n");
840		return -ENAMETOOLONG;
841	}
842
843	hdrlen = (u8 *) p - (u8 *) iov->iov_base;
844	if (iov->iov_len < hdrlen) {
845		dprintk("NFS: READLINK reply header overflowed:"
846				"length %Zu > %Zu\n", hdrlen, iov->iov_len);
847		return -errno_NFSERR_IO;
848	} else if (iov->iov_len != hdrlen) {
849		dprintk("NFS: READLINK header is short. "
850			"iovec will be shifted.\n");
851		xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen);
852	}
853	recvd = req->rq_rcv_buf.len - hdrlen;
854	if (recvd < len) {
855		dprintk("NFS: server cheating in readlink reply: "
856				"count %u > recvd %u\n", len, recvd);
857		return -EIO;
858	}
859
860	/* NULL terminate the string we got */
861	kaddr = (char*)kmap_atomic(rcvbuf->pages[0], KM_USER0);
862	kaddr[len+rcvbuf->page_base] = '\0';
863	kunmap_atomic(kaddr, KM_USER0);
864	return 0;
865}
866
867/*
868 * Decode READ reply
869 */
870static int
871nfs3_xdr_readres(struct rpc_rqst *req, __be32 *p, struct nfs_readres *res)
872{
873	struct kvec *iov = req->rq_rcv_buf.head;
874	size_t hdrlen;
875	u32 count, ocount, recvd;
876	int status;
877
878	status = ntohl(*p++);
879	p = xdr_decode_post_op_attr(p, res->fattr);
880
881	if (status != 0)
882		return nfs_stat_to_errno(status);
883
884	/* Decode reply count and EOF flag. NFSv3 is somewhat redundant
885	 * in that it puts the count both in the res struct and in the
886	 * opaque data count. */
887	count    = ntohl(*p++);
888	res->eof = ntohl(*p++);
889	ocount   = ntohl(*p++);
890
891	if (ocount != count) {
892		dprintk("NFS: READ count doesn't match RPC opaque count.\n");
893		return -errno_NFSERR_IO;
894	}
895
896	hdrlen = (u8 *) p - (u8 *) iov->iov_base;
897	if (iov->iov_len < hdrlen) {
898		dprintk("NFS: READ reply header overflowed:"
899				"length %Zu > %Zu\n", hdrlen, iov->iov_len);
900       		return -errno_NFSERR_IO;
901	} else if (iov->iov_len != hdrlen) {
902		dprintk("NFS: READ header is short. iovec will be shifted.\n");
903		xdr_shift_buf(&req->rq_rcv_buf, iov->iov_len - hdrlen);
904	}
905
906	recvd = req->rq_rcv_buf.len - hdrlen;
907	if (count > recvd) {
908		dprintk("NFS: server cheating in read reply: "
909			"count %u > recvd %u\n", count, recvd);
910		count = recvd;
911		res->eof = 0;
912	}
913
914	if (count < res->count)
915		res->count = count;
916
917	return count;
918}
919
920/*
921 * Decode WRITE response
922 */
923static int
924nfs3_xdr_writeres(struct rpc_rqst *req, __be32 *p, struct nfs_writeres *res)
925{
926	int	status;
927
928	status = ntohl(*p++);
929	p = xdr_decode_wcc_data(p, res->fattr);
930
931	if (status != 0)
932		return nfs_stat_to_errno(status);
933
934	res->count = ntohl(*p++);
935	res->verf->committed = (enum nfs3_stable_how)ntohl(*p++);
936	res->verf->verifier[0] = *p++;
937	res->verf->verifier[1] = *p++;
938
939	return res->count;
940}
941
942/*
943 * Decode a CREATE response
944 */
945static int
946nfs3_xdr_createres(struct rpc_rqst *req, __be32 *p, struct nfs3_diropres *res)
947{
948	int	status;
949
950	status = ntohl(*p++);
951	if (status == 0) {
952		if (*p++) {
953			if (!(p = xdr_decode_fhandle(p, res->fh)))
954				return -errno_NFSERR_IO;
955			p = xdr_decode_post_op_attr(p, res->fattr);
956		} else {
957			memset(res->fh, 0, sizeof(*res->fh));
958			/* Do decode post_op_attr but set it to NULL */
959			p = xdr_decode_post_op_attr(p, res->fattr);
960			res->fattr->valid = 0;
961		}
962	} else {
963		status = nfs_stat_to_errno(status);
964	}
965	p = xdr_decode_wcc_data(p, res->dir_attr);
966	return status;
967}
968
969/*
970 * Decode RENAME reply
971 */
972static int
973nfs3_xdr_renameres(struct rpc_rqst *req, __be32 *p, struct nfs3_renameres *res)
974{
975	int	status;
976
977	if ((status = ntohl(*p++)) != 0)
978		status = nfs_stat_to_errno(status);
979	p = xdr_decode_wcc_data(p, res->fromattr);
980	p = xdr_decode_wcc_data(p, res->toattr);
981	return status;
982}
983
984/*
985 * Decode LINK reply
986 */
987static int
988nfs3_xdr_linkres(struct rpc_rqst *req, __be32 *p, struct nfs3_linkres *res)
989{
990	int	status;
991
992	if ((status = ntohl(*p++)) != 0)
993		status = nfs_stat_to_errno(status);
994	p = xdr_decode_post_op_attr(p, res->fattr);
995	p = xdr_decode_wcc_data(p, res->dir_attr);
996	return status;
997}
998
999/*
1000 * Decode FSSTAT reply
1001 */
1002static int
1003nfs3_xdr_fsstatres(struct rpc_rqst *req, __be32 *p, struct nfs_fsstat *res)
1004{
1005	int		status;
1006
1007	status = ntohl(*p++);
1008
1009	p = xdr_decode_post_op_attr(p, res->fattr);
1010	if (status != 0)
1011		return nfs_stat_to_errno(status);
1012
1013	p = xdr_decode_hyper(p, &res->tbytes);
1014	p = xdr_decode_hyper(p, &res->fbytes);
1015	p = xdr_decode_hyper(p, &res->abytes);
1016	p = xdr_decode_hyper(p, &res->tfiles);
1017	p = xdr_decode_hyper(p, &res->ffiles);
1018	p = xdr_decode_hyper(p, &res->afiles);
1019
1020	/* ignore invarsec */
1021	return 0;
1022}
1023
1024/*
1025 * Decode FSINFO reply
1026 */
1027static int
1028nfs3_xdr_fsinfores(struct rpc_rqst *req, __be32 *p, struct nfs_fsinfo *res)
1029{
1030	int		status;
1031
1032	status = ntohl(*p++);
1033
1034	p = xdr_decode_post_op_attr(p, res->fattr);
1035	if (status != 0)
1036		return nfs_stat_to_errno(status);
1037
1038	res->rtmax  = ntohl(*p++);
1039	res->rtpref = ntohl(*p++);
1040	res->rtmult = ntohl(*p++);
1041	res->wtmax  = ntohl(*p++);
1042	res->wtpref = ntohl(*p++);
1043	res->wtmult = ntohl(*p++);
1044	res->dtpref = ntohl(*p++);
1045	p = xdr_decode_hyper(p, &res->maxfilesize);
1046
1047	/* ignore time_delta and properties */
1048	res->lease_time = 0;
1049	return 0;
1050}
1051
1052/*
1053 * Decode PATHCONF reply
1054 */
1055static int
1056nfs3_xdr_pathconfres(struct rpc_rqst *req, __be32 *p, struct nfs_pathconf *res)
1057{
1058	int		status;
1059
1060	status = ntohl(*p++);
1061
1062	p = xdr_decode_post_op_attr(p, res->fattr);
1063	if (status != 0)
1064		return nfs_stat_to_errno(status);
1065	res->max_link = ntohl(*p++);
1066	res->max_namelen = ntohl(*p++);
1067
1068	/* ignore remaining fields */
1069	return 0;
1070}
1071
1072/*
1073 * Decode COMMIT reply
1074 */
1075static int
1076nfs3_xdr_commitres(struct rpc_rqst *req, __be32 *p, struct nfs_writeres *res)
1077{
1078	int		status;
1079
1080	status = ntohl(*p++);
1081	p = xdr_decode_wcc_data(p, res->fattr);
1082	if (status != 0)
1083		return nfs_stat_to_errno(status);
1084
1085	res->verf->verifier[0] = *p++;
1086	res->verf->verifier[1] = *p++;
1087	return 0;
1088}
1089
1090#ifdef CONFIG_NFS_V3_ACL
1091/*
1092 * Decode GETACL reply
1093 */
1094static int
1095nfs3_xdr_getaclres(struct rpc_rqst *req, __be32 *p,
1096		   struct nfs3_getaclres *res)
1097{
1098	struct xdr_buf *buf = &req->rq_rcv_buf;
1099	int status = ntohl(*p++);
1100	struct posix_acl **acl;
1101	unsigned int *aclcnt;
1102	int err, base;
1103
1104	if (status != 0)
1105		return nfs_stat_to_errno(status);
1106	p = xdr_decode_post_op_attr(p, res->fattr);
1107	res->mask = ntohl(*p++);
1108	if (res->mask & ~(NFS_ACL|NFS_ACLCNT|NFS_DFACL|NFS_DFACLCNT))
1109		return -EINVAL;
1110	base = (char *)p - (char *)req->rq_rcv_buf.head->iov_base;
1111
1112	acl = (res->mask & NFS_ACL) ? &res->acl_access : NULL;
1113	aclcnt = (res->mask & NFS_ACLCNT) ? &res->acl_access_count : NULL;
1114	err = nfsacl_decode(buf, base, aclcnt, acl);
1115
1116	acl = (res->mask & NFS_DFACL) ? &res->acl_default : NULL;
1117	aclcnt = (res->mask & NFS_DFACLCNT) ? &res->acl_default_count : NULL;
1118	if (err > 0)
1119		err = nfsacl_decode(buf, base + err, aclcnt, acl);
1120	return (err > 0) ? 0 : err;
1121}
1122
1123/*
1124 * Decode setacl reply.
1125 */
1126static int
1127nfs3_xdr_setaclres(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
1128{
1129	int status = ntohl(*p++);
1130
1131	if (status)
1132		return nfs_stat_to_errno(status);
1133	xdr_decode_post_op_attr(p, fattr);
1134	return 0;
1135}
1136#endif  /* CONFIG_NFS_V3_ACL */
1137
1138#define PROC(proc, argtype, restype, timer)				\
1139[NFS3PROC_##proc] = {							\
1140	.p_proc      = NFS3PROC_##proc,					\
1141	.p_encode    = (kxdrproc_t) nfs3_xdr_##argtype,			\
1142	.p_decode    = (kxdrproc_t) nfs3_xdr_##restype,			\
1143	.p_arglen    = NFS3_##argtype##_sz,				\
1144	.p_replen    = NFS3_##restype##_sz,				\
1145	.p_timer     = timer,						\
1146	.p_statidx   = NFS3PROC_##proc,					\
1147	.p_name      = #proc,						\
1148	}
1149
1150struct rpc_procinfo	nfs3_procedures[] = {
1151  PROC(GETATTR,		fhandle,	attrstat, 1),
1152  PROC(SETATTR, 	sattrargs,	wccstat, 0),
1153  PROC(LOOKUP,		diropargs,	lookupres, 2),
1154  PROC(ACCESS,		accessargs,	accessres, 1),
1155  PROC(READLINK,	readlinkargs,	readlinkres, 3),
1156  PROC(READ,		readargs,	readres, 3),
1157  PROC(WRITE,		writeargs,	writeres, 4),
1158  PROC(CREATE,		createargs,	createres, 0),
1159  PROC(MKDIR,		mkdirargs,	createres, 0),
1160  PROC(SYMLINK,		symlinkargs,	createres, 0),
1161  PROC(MKNOD,		mknodargs,	createres, 0),
1162  PROC(REMOVE,		removeargs,	removeres, 0),
1163  PROC(RMDIR,		diropargs,	wccstat, 0),
1164  PROC(RENAME,		renameargs,	renameres, 0),
1165  PROC(LINK,		linkargs,	linkres, 0),
1166  PROC(READDIR,		readdirargs,	readdirres, 3),
1167  PROC(READDIRPLUS,	readdirargs,	readdirres, 3),
1168  PROC(FSSTAT,		fhandle,	fsstatres, 0),
1169  PROC(FSINFO,  	fhandle,	fsinfores, 0),
1170  PROC(PATHCONF,	fhandle,	pathconfres, 0),
1171  PROC(COMMIT,		commitargs,	commitres, 5),
1172};
1173
1174struct rpc_version		nfs_version3 = {
1175	.number			= 3,
1176	.nrprocs		= ARRAY_SIZE(nfs3_procedures),
1177	.procs			= nfs3_procedures
1178};
1179
1180#ifdef CONFIG_NFS_V3_ACL
1181static struct rpc_procinfo	nfs3_acl_procedures[] = {
1182	[ACLPROC3_GETACL] = {
1183		.p_proc = ACLPROC3_GETACL,
1184		.p_encode = (kxdrproc_t) nfs3_xdr_getaclargs,
1185		.p_decode = (kxdrproc_t) nfs3_xdr_getaclres,
1186		.p_arglen = ACL3_getaclargs_sz,
1187		.p_replen = ACL3_getaclres_sz,
1188		.p_timer = 1,
1189		.p_name = "GETACL",
1190	},
1191	[ACLPROC3_SETACL] = {
1192		.p_proc = ACLPROC3_SETACL,
1193		.p_encode = (kxdrproc_t) nfs3_xdr_setaclargs,
1194		.p_decode = (kxdrproc_t) nfs3_xdr_setaclres,
1195		.p_arglen = ACL3_setaclargs_sz,
1196		.p_replen = ACL3_setaclres_sz,
1197		.p_timer = 0,
1198		.p_name = "SETACL",
1199	},
1200};
1201
1202struct rpc_version		nfsacl_version3 = {
1203	.number			= 3,
1204	.nrprocs		= sizeof(nfs3_acl_procedures)/
1205				  sizeof(nfs3_acl_procedures[0]),
1206	.procs			= nfs3_acl_procedures,
1207};
1208#endif  /* CONFIG_NFS_V3_ACL */
1209