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