]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blame - fs/nfs/nfs3xdr.c
NFS: Replace old NFSv3 encoder functions with xdr_stream-based ones
[mirror_ubuntu-bionic-kernel.git] / fs / nfs / nfs3xdr.c
CommitLineData
1da177e4
LT
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>
1da177e4
LT
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>
b7fa0554 22#include <linux/nfsacl.h>
f7b422b1 23#include "internal.h"
1da177e4
LT
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
1da177e4
LT
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)
d9c407b1 40#define NFS3_cookieverf_sz (NFS3_COOKIEVERFSIZE>>2)
1da177e4
LT
41#define NFS3_wcc_attr_sz (6)
42#define NFS3_pre_op_attr_sz (1+NFS3_wcc_attr_sz)
43#define NFS3_post_op_attr_sz (1+NFS3_fattr_sz)
44#define NFS3_wcc_data_sz (NFS3_pre_op_attr_sz+NFS3_post_op_attr_sz)
45#define NFS3_fsstat_sz
46#define NFS3_fsinfo_sz
47#define NFS3_pathconf_sz
48#define NFS3_entry_sz (NFS3_filename_sz+3)
1da177e4 49#define NFS3_diropargs_sz (NFS3_fh_sz+NFS3_filename_sz)
ad96b5b5
CL
50
51#define NFS3_getattrargs_sz (NFS3_fh_sz)
52#define NFS3_setattrargs_sz (NFS3_fh_sz+NFS3_sattr_sz+3)
53#define NFS3_lookupargs_sz (NFS3_fh_sz+NFS3_filename_sz)
1da177e4
LT
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)
94a6d753 60#define NFS3_symlinkargs_sz (NFS3_diropargs_sz+1+NFS3_sattr_sz)
1da177e4 61#define NFS3_mknodargs_sz (NFS3_diropargs_sz+2+NFS3_sattr_sz)
ad96b5b5 62#define NFS3_removeargs_sz (NFS3_fh_sz+NFS3_filename_sz)
1da177e4
LT
63#define NFS3_renameargs_sz (NFS3_diropargs_sz+NFS3_diropargs_sz)
64#define NFS3_linkargs_sz (NFS3_fh_sz+NFS3_diropargs_sz)
d9c407b1
CL
65#define NFS3_readdirargs_sz (NFS3_fh_sz+NFS3_cookieverf_sz+3)
66#define NFS3_readdirplusargs_sz (NFS3_fh_sz+NFS3_cookieverf_sz+4)
1da177e4
LT
67#define NFS3_commitargs_sz (NFS3_fh_sz+3)
68
69#define NFS3_attrstat_sz (1+NFS3_fattr_sz)
70#define NFS3_wccstat_sz (1+NFS3_wcc_data_sz)
4fdc17b2 71#define NFS3_removeres_sz (NFS3_wccstat_sz)
1da177e4
LT
72#define NFS3_lookupres_sz (1+NFS3_fh_sz+(2 * NFS3_post_op_attr_sz))
73#define NFS3_accessres_sz (1+NFS3_post_op_attr_sz+1)
74#define NFS3_readlinkres_sz (1+NFS3_post_op_attr_sz+1)
75#define NFS3_readres_sz (1+NFS3_post_op_attr_sz+3)
76#define NFS3_writeres_sz (1+NFS3_wcc_data_sz+4)
77#define NFS3_createres_sz (1+NFS3_fh_sz+NFS3_post_op_attr_sz+NFS3_wcc_data_sz)
78#define NFS3_renameres_sz (1+(2 * NFS3_wcc_data_sz))
79#define NFS3_linkres_sz (1+NFS3_post_op_attr_sz+NFS3_wcc_data_sz)
80#define NFS3_readdirres_sz (1+NFS3_post_op_attr_sz+2)
81#define NFS3_fsstatres_sz (1+NFS3_post_op_attr_sz+13)
82#define NFS3_fsinfores_sz (1+NFS3_post_op_attr_sz+12)
83#define NFS3_pathconfres_sz (1+NFS3_post_op_attr_sz+6)
84#define NFS3_commitres_sz (1+NFS3_wcc_data_sz+2)
85
b7fa0554 86#define ACL3_getaclargs_sz (NFS3_fh_sz+1)
ae46141f
TM
87#define ACL3_setaclargs_sz (NFS3_fh_sz+1+ \
88 XDR_QUADLEN(NFS_ACL_INLINE_BUFSIZE))
89#define ACL3_getaclres_sz (1+NFS3_post_op_attr_sz+1+ \
90 XDR_QUADLEN(NFS_ACL_INLINE_BUFSIZE))
b7fa0554
AG
91#define ACL3_setaclres_sz (1+NFS3_post_op_attr_sz)
92
1da177e4
LT
93/*
94 * Map file type to S_IFMT bits
95 */
bca79478
TM
96static const umode_t nfs_type2fmt[] = {
97 [NF3BAD] = 0,
98 [NF3REG] = S_IFREG,
99 [NF3DIR] = S_IFDIR,
100 [NF3BLK] = S_IFBLK,
101 [NF3CHR] = S_IFCHR,
102 [NF3LNK] = S_IFLNK,
103 [NF3SOCK] = S_IFSOCK,
104 [NF3FIFO] = S_IFIFO,
1da177e4
LT
105};
106
babddc72
BS
107static void print_overflow_msg(const char *func, const struct xdr_stream *xdr)
108{
109 dprintk("nfs: %s: prematurely hit end of receive buffer. "
110 "Remaining buffer length is %tu words.\n",
111 func, xdr->end - xdr->p);
112}
113
d9c407b1
CL
114/*
115 * While encoding arguments, set up the reply buffer in advance to
116 * receive reply data directly into the page cache.
117 */
118static void prepare_reply_buffer(struct rpc_rqst *req, struct page **pages,
119 unsigned int base, unsigned int len,
120 unsigned int bufsize)
121{
122 struct rpc_auth *auth = req->rq_cred->cr_auth;
123 unsigned int replen;
124
125 replen = RPC_REPHDRSIZE + auth->au_rslack + bufsize;
126 xdr_inline_pages(&req->rq_rcv_buf, replen << 2, pages, base, len);
127}
128
129
1da177e4
LT
130/*
131 * Common NFS XDR functions as inlines
132 */
d61005a6 133static inline __be32 *
4fdc17b2 134xdr_encode_fhandle(__be32 *p, const struct nfs_fh *fh)
1da177e4
LT
135{
136 return xdr_encode_array(p, fh->data, fh->size);
137}
138
d61005a6
AV
139static inline __be32 *
140xdr_decode_fhandle(__be32 *p, struct nfs_fh *fh)
1da177e4
LT
141{
142 if ((fh->size = ntohl(*p++)) <= NFS3_FHSIZE) {
143 memcpy(fh->data, p, fh->size);
144 return p + XDR_QUADLEN(fh->size);
145 }
146 return NULL;
147}
148
babddc72
BS
149static inline __be32 *
150xdr_decode_fhandle_stream(struct xdr_stream *xdr, struct nfs_fh *fh)
151{
152 __be32 *p;
153 p = xdr_inline_decode(xdr, 4);
154 if (unlikely(!p))
155 goto out_overflow;
156 fh->size = ntohl(*p++);
157
158 if (fh->size <= NFS3_FHSIZE) {
159 p = xdr_inline_decode(xdr, fh->size);
160 if (unlikely(!p))
161 goto out_overflow;
162 memcpy(fh->data, p, fh->size);
163 return p + XDR_QUADLEN(fh->size);
164 }
165 return NULL;
166
167out_overflow:
168 print_overflow_msg(__func__, xdr);
169 return ERR_PTR(-EIO);
170}
171
1da177e4
LT
172/*
173 * Encode/decode time.
174 */
d61005a6 175static inline __be32 *
d9c407b1 176xdr_encode_time3(__be32 *p, const struct timespec *timep)
1da177e4
LT
177{
178 *p++ = htonl(timep->tv_sec);
179 *p++ = htonl(timep->tv_nsec);
180 return p;
181}
182
d61005a6
AV
183static inline __be32 *
184xdr_decode_time3(__be32 *p, struct timespec *timep)
1da177e4
LT
185{
186 timep->tv_sec = ntohl(*p++);
187 timep->tv_nsec = ntohl(*p++);
188 return p;
189}
190
d61005a6
AV
191static __be32 *
192xdr_decode_fattr(__be32 *p, struct nfs_fattr *fattr)
1da177e4
LT
193{
194 unsigned int type, major, minor;
bca79478 195 umode_t fmode;
1da177e4
LT
196
197 type = ntohl(*p++);
bca79478
TM
198 if (type > NF3FIFO)
199 type = NF3NON;
200 fmode = nfs_type2fmt[type];
1da177e4
LT
201 fattr->mode = (ntohl(*p++) & ~S_IFMT) | fmode;
202 fattr->nlink = ntohl(*p++);
203 fattr->uid = ntohl(*p++);
204 fattr->gid = ntohl(*p++);
205 p = xdr_decode_hyper(p, &fattr->size);
206 p = xdr_decode_hyper(p, &fattr->du.nfs3.used);
207
208 /* Turn remote device info into Linux-specific dev_t */
209 major = ntohl(*p++);
210 minor = ntohl(*p++);
211 fattr->rdev = MKDEV(major, minor);
212 if (MAJOR(fattr->rdev) != major || MINOR(fattr->rdev) != minor)
213 fattr->rdev = 0;
214
8b4bdcf8
TM
215 p = xdr_decode_hyper(p, &fattr->fsid.major);
216 fattr->fsid.minor = 0;
1da177e4
LT
217 p = xdr_decode_hyper(p, &fattr->fileid);
218 p = xdr_decode_time3(p, &fattr->atime);
219 p = xdr_decode_time3(p, &fattr->mtime);
220 p = xdr_decode_time3(p, &fattr->ctime);
221
222 /* Update the mode bits */
9e6e70f8 223 fattr->valid |= NFS_ATTR_FATTR_V3;
1da177e4
LT
224 return p;
225}
226
d61005a6 227static inline __be32 *
d9c407b1 228xdr_encode_sattr(__be32 *p, const struct iattr *attr)
1da177e4
LT
229{
230 if (attr->ia_valid & ATTR_MODE) {
231 *p++ = xdr_one;
cf3fff54 232 *p++ = htonl(attr->ia_mode & S_IALLUGO);
1da177e4
LT
233 } else {
234 *p++ = xdr_zero;
235 }
236 if (attr->ia_valid & ATTR_UID) {
237 *p++ = xdr_one;
238 *p++ = htonl(attr->ia_uid);
239 } else {
240 *p++ = xdr_zero;
241 }
242 if (attr->ia_valid & ATTR_GID) {
243 *p++ = xdr_one;
244 *p++ = htonl(attr->ia_gid);
245 } else {
246 *p++ = xdr_zero;
247 }
248 if (attr->ia_valid & ATTR_SIZE) {
249 *p++ = xdr_one;
250 p = xdr_encode_hyper(p, (__u64) attr->ia_size);
251 } else {
252 *p++ = xdr_zero;
253 }
254 if (attr->ia_valid & ATTR_ATIME_SET) {
255 *p++ = xdr_two;
256 p = xdr_encode_time3(p, &attr->ia_atime);
257 } else if (attr->ia_valid & ATTR_ATIME) {
258 *p++ = xdr_one;
259 } else {
260 *p++ = xdr_zero;
261 }
262 if (attr->ia_valid & ATTR_MTIME_SET) {
263 *p++ = xdr_two;
264 p = xdr_encode_time3(p, &attr->ia_mtime);
265 } else if (attr->ia_valid & ATTR_MTIME) {
266 *p++ = xdr_one;
267 } else {
268 *p++ = xdr_zero;
269 }
270 return p;
271}
272
d61005a6
AV
273static inline __be32 *
274xdr_decode_wcc_attr(__be32 *p, struct nfs_fattr *fattr)
1da177e4
LT
275{
276 p = xdr_decode_hyper(p, &fattr->pre_size);
277 p = xdr_decode_time3(p, &fattr->pre_mtime);
278 p = xdr_decode_time3(p, &fattr->pre_ctime);
9e6e70f8
TM
279 fattr->valid |= NFS_ATTR_FATTR_PRESIZE
280 | NFS_ATTR_FATTR_PREMTIME
281 | NFS_ATTR_FATTR_PRECTIME;
1da177e4
LT
282 return p;
283}
284
d61005a6
AV
285static inline __be32 *
286xdr_decode_post_op_attr(__be32 *p, struct nfs_fattr *fattr)
1da177e4
LT
287{
288 if (*p++)
289 p = xdr_decode_fattr(p, fattr);
290 return p;
291}
292
babddc72
BS
293static inline __be32 *
294xdr_decode_post_op_attr_stream(struct xdr_stream *xdr, struct nfs_fattr *fattr)
295{
296 __be32 *p;
297
298 p = xdr_inline_decode(xdr, 4);
299 if (unlikely(!p))
300 goto out_overflow;
301 if (ntohl(*p++)) {
302 p = xdr_inline_decode(xdr, 84);
303 if (unlikely(!p))
304 goto out_overflow;
305 p = xdr_decode_fattr(p, fattr);
306 }
307 return p;
308out_overflow:
309 print_overflow_msg(__func__, xdr);
310 return ERR_PTR(-EIO);
311}
312
d61005a6
AV
313static inline __be32 *
314xdr_decode_pre_op_attr(__be32 *p, struct nfs_fattr *fattr)
1da177e4
LT
315{
316 if (*p++)
317 return xdr_decode_wcc_attr(p, fattr);
318 return p;
319}
320
321
d61005a6
AV
322static inline __be32 *
323xdr_decode_wcc_data(__be32 *p, struct nfs_fattr *fattr)
1da177e4
LT
324{
325 p = xdr_decode_pre_op_attr(p, fattr);
326 return xdr_decode_post_op_attr(p, fattr);
327}
328
d9c407b1
CL
329
330/*
331 * Encode/decode NFSv3 basic data types
332 *
333 * Basic NFSv3 data types are defined in section 2.5 of RFC 1813:
334 * "NFS Version 3 Protocol Specification".
335 *
336 * Not all basic data types have their own encoding and decoding
337 * functions. For run-time efficiency, some data types are encoded
338 * or decoded inline.
339 */
340
341static void encode_uint32(struct xdr_stream *xdr, u32 value)
342{
343 __be32 *p = xdr_reserve_space(xdr, 4);
344 *p = cpu_to_be32(value);
345}
346
347/*
348 * filename3
349 *
350 * typedef string filename3<>;
351 */
352static void encode_filename3(struct xdr_stream *xdr,
353 const char *name, u32 length)
354{
355 __be32 *p;
356
357 BUG_ON(length > NFS3_MAXNAMLEN);
358 p = xdr_reserve_space(xdr, 4 + length);
359 xdr_encode_opaque(p, name, length);
360}
361
362/*
363 * nfspath3
364 *
365 * typedef string nfspath3<>;
366 */
367static void encode_nfspath3(struct xdr_stream *xdr, struct page **pages,
368 const u32 length)
369{
370 BUG_ON(length > NFS3_MAXPATHLEN);
371 encode_uint32(xdr, length);
372 xdr_write_pages(xdr, pages, 0, length);
373}
374
375/*
376 * cookie3
377 *
378 * typedef uint64 cookie3
379 */
380static __be32 *xdr_encode_cookie3(__be32 *p, u64 cookie)
381{
382 return xdr_encode_hyper(p, cookie);
383}
384
385/*
386 * cookieverf3
387 *
388 * typedef opaque cookieverf3[NFS3_COOKIEVERFSIZE];
389 */
390static __be32 *xdr_encode_cookieverf3(__be32 *p, const __be32 *verifier)
391{
392 memcpy(p, verifier, NFS3_COOKIEVERFSIZE);
393 return p + XDR_QUADLEN(NFS3_COOKIEVERFSIZE);
394}
395
396/*
397 * createverf3
398 *
399 * typedef opaque createverf3[NFS3_CREATEVERFSIZE];
400 */
401static void encode_createverf3(struct xdr_stream *xdr, const __be32 *verifier)
402{
403 __be32 *p;
404
405 p = xdr_reserve_space(xdr, NFS3_CREATEVERFSIZE);
406 memcpy(p, verifier, NFS3_CREATEVERFSIZE);
407}
408
409/*
410 * ftype3
411 *
412 * enum ftype3 {
413 * NF3REG = 1,
414 * NF3DIR = 2,
415 * NF3BLK = 3,
416 * NF3CHR = 4,
417 * NF3LNK = 5,
418 * NF3SOCK = 6,
419 * NF3FIFO = 7
420 * };
421 */
422static void encode_ftype3(struct xdr_stream *xdr, const u32 type)
423{
424 BUG_ON(type > NF3FIFO);
425 encode_uint32(xdr, type);
426}
427
428/*
429 * specdata3
430 *
431 * struct specdata3 {
432 * uint32 specdata1;
433 * uint32 specdata2;
434 * };
435 */
436static void encode_specdata3(struct xdr_stream *xdr, const dev_t rdev)
437{
438 __be32 *p;
439
440 p = xdr_reserve_space(xdr, 8);
441 *p++ = cpu_to_be32(MAJOR(rdev));
442 *p = cpu_to_be32(MINOR(rdev));
443}
444
445/*
446 * nfs_fh3
447 *
448 * struct nfs_fh3 {
449 * opaque data<NFS3_FHSIZE>;
450 * };
451 */
452static void encode_nfs_fh3(struct xdr_stream *xdr, const struct nfs_fh *fh)
453{
454 __be32 *p;
455
456 BUG_ON(fh->size > NFS3_FHSIZE);
457 p = xdr_reserve_space(xdr, 4 + fh->size);
458 xdr_encode_opaque(p, fh->data, fh->size);
459}
460
461/*
462 * sattr3
463 *
464 * enum time_how {
465 * DONT_CHANGE = 0,
466 * SET_TO_SERVER_TIME = 1,
467 * SET_TO_CLIENT_TIME = 2
468 * };
469 *
470 * union set_mode3 switch (bool set_it) {
471 * case TRUE:
472 * mode3 mode;
473 * default:
474 * void;
475 * };
476 *
477 * union set_uid3 switch (bool set_it) {
478 * case TRUE:
479 * uid3 uid;
480 * default:
481 * void;
482 * };
483 *
484 * union set_gid3 switch (bool set_it) {
485 * case TRUE:
486 * gid3 gid;
487 * default:
488 * void;
489 * };
490 *
491 * union set_size3 switch (bool set_it) {
492 * case TRUE:
493 * size3 size;
494 * default:
495 * void;
496 * };
497 *
498 * union set_atime switch (time_how set_it) {
499 * case SET_TO_CLIENT_TIME:
500 * nfstime3 atime;
501 * default:
502 * void;
503 * };
504 *
505 * union set_mtime switch (time_how set_it) {
506 * case SET_TO_CLIENT_TIME:
507 * nfstime3 mtime;
508 * default:
509 * void;
510 * };
511 *
512 * struct sattr3 {
513 * set_mode3 mode;
514 * set_uid3 uid;
515 * set_gid3 gid;
516 * set_size3 size;
517 * set_atime atime;
518 * set_mtime mtime;
519 * };
520 */
521static void encode_sattr3(struct xdr_stream *xdr, const struct iattr *attr)
522{
523 u32 nbytes;
524 __be32 *p;
525
526 /*
527 * In order to make only a single xdr_reserve_space() call,
528 * pre-compute the total number of bytes to be reserved.
529 * Six boolean values, one for each set_foo field, are always
530 * present in the encoded result, so start there.
531 */
532 nbytes = 6 * 4;
533 if (attr->ia_valid & ATTR_MODE)
534 nbytes += 4;
535 if (attr->ia_valid & ATTR_UID)
536 nbytes += 4;
537 if (attr->ia_valid & ATTR_GID)
538 nbytes += 4;
539 if (attr->ia_valid & ATTR_SIZE)
540 nbytes += 8;
541 if (attr->ia_valid & ATTR_ATIME_SET)
542 nbytes += 8;
543 if (attr->ia_valid & ATTR_MTIME_SET)
544 nbytes += 8;
545 p = xdr_reserve_space(xdr, nbytes);
546
547 xdr_encode_sattr(p, attr);
548}
549
550/*
551 * diropargs3
552 *
553 * struct diropargs3 {
554 * nfs_fh3 dir;
555 * filename3 name;
556 * };
557 */
558static void encode_diropargs3(struct xdr_stream *xdr, const struct nfs_fh *fh,
559 const char *name, u32 length)
560{
561 encode_nfs_fh3(xdr, fh);
562 encode_filename3(xdr, name, length);
563}
564
565
1da177e4
LT
566/*
567 * NFS encode functions
568 */
569
570/*
571 * Encode file handle argument
572 */
573static int
d61005a6 574nfs3_xdr_fhandle(struct rpc_rqst *req, __be32 *p, struct nfs_fh *fh)
1da177e4
LT
575{
576 p = xdr_encode_fhandle(p, fh);
577 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
578 return 0;
579}
580
d9c407b1
CL
581/*
582 * 3.3.1 GETATTR3args
583 *
584 * struct GETATTR3args {
585 * nfs_fh3 object;
586 * };
587 */
588static int nfs3_xdr_enc_getattr3args(struct rpc_rqst *req, __be32 *p,
589 const struct nfs_fh *fh)
590{
591 struct xdr_stream xdr;
592
593 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
594 encode_nfs_fh3(&xdr, fh);
595 return 0;
596}
597
1da177e4
LT
598/*
599 * Encode SETATTR arguments
600 */
601static int
d61005a6 602nfs3_xdr_sattrargs(struct rpc_rqst *req, __be32 *p, struct nfs3_sattrargs *args)
1da177e4
LT
603{
604 p = xdr_encode_fhandle(p, args->fh);
605 p = xdr_encode_sattr(p, args->sattr);
606 *p++ = htonl(args->guard);
607 if (args->guard)
608 p = xdr_encode_time3(p, &args->guardtime);
609 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
610 return 0;
611}
612
d9c407b1
CL
613/*
614 * 3.3.2 SETATTR3args
615 *
616 * union sattrguard3 switch (bool check) {
617 * case TRUE:
618 * nfstime3 obj_ctime;
619 * case FALSE:
620 * void;
621 * };
622 *
623 * struct SETATTR3args {
624 * nfs_fh3 object;
625 * sattr3 new_attributes;
626 * sattrguard3 guard;
627 * };
628 */
629static void encode_sattrguard3(struct xdr_stream *xdr,
630 const struct nfs3_sattrargs *args)
631{
632 __be32 *p;
633
634 if (args->guard) {
635 p = xdr_reserve_space(xdr, 4 + 8);
636 *p++ = xdr_one;
637 xdr_encode_time3(p, &args->guardtime);
638 } else {
639 p = xdr_reserve_space(xdr, 4);
640 *p = xdr_zero;
641 }
642}
643
644static int nfs3_xdr_enc_setattr3args(struct rpc_rqst *req, __be32 *p,
645 const struct nfs3_sattrargs *args)
646{
647 struct xdr_stream xdr;
648
649 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
650 encode_nfs_fh3(&xdr, args->fh);
651 encode_sattr3(&xdr, args->sattr);
652 encode_sattrguard3(&xdr, args);
653 return 0;
654}
655
1da177e4
LT
656/*
657 * Encode directory ops argument
658 */
659static int
d61005a6 660nfs3_xdr_diropargs(struct rpc_rqst *req, __be32 *p, struct nfs3_diropargs *args)
1da177e4
LT
661{
662 p = xdr_encode_fhandle(p, args->fh);
663 p = xdr_encode_array(p, args->name, args->len);
664 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
665 return 0;
666}
667
d9c407b1
CL
668/*
669 * 3.3.3 LOOKUP3args
670 *
671 * struct LOOKUP3args {
672 * diropargs3 what;
673 * };
674 */
675static int nfs3_xdr_enc_lookup3args(struct rpc_rqst *req, __be32 *p,
676 const struct nfs3_diropargs *args)
677{
678 struct xdr_stream xdr;
679
680 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
681 encode_diropargs3(&xdr, args->fh, args->name, args->len);
682 return 0;
683}
684
4fdc17b2
TM
685/*
686 * Encode REMOVE argument
687 */
688static int
689nfs3_xdr_removeargs(struct rpc_rqst *req, __be32 *p, const struct nfs_removeargs *args)
690{
691 p = xdr_encode_fhandle(p, args->fh);
692 p = xdr_encode_array(p, args->name.name, args->name.len);
693 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
694 return 0;
695}
696
1da177e4
LT
697/*
698 * Encode access() argument
699 */
700static int
d61005a6 701nfs3_xdr_accessargs(struct rpc_rqst *req, __be32 *p, struct nfs3_accessargs *args)
1da177e4
LT
702{
703 p = xdr_encode_fhandle(p, args->fh);
704 *p++ = htonl(args->access);
705 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
706 return 0;
707}
708
d9c407b1
CL
709/*
710 * 3.3.4 ACCESS3args
711 *
712 * struct ACCESS3args {
713 * nfs_fh3 object;
714 * uint32 access;
715 * };
716 */
717static void encode_access3args(struct xdr_stream *xdr,
718 const struct nfs3_accessargs *args)
719{
720 encode_nfs_fh3(xdr, args->fh);
721 encode_uint32(xdr, args->access);
722}
723
724static int nfs3_xdr_enc_access3args(struct rpc_rqst *req, __be32 *p,
725 const struct nfs3_accessargs *args)
726{
727 struct xdr_stream xdr;
728
729 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
730 encode_access3args(&xdr, args);
731 return 0;
732}
733
734/*
735 * 3.3.5 READLINK3args
736 *
737 * struct READLINK3args {
738 * nfs_fh3 symlink;
739 * };
740 */
741static int nfs3_xdr_enc_readlink3args(struct rpc_rqst *req, __be32 *p,
742 const struct nfs3_readlinkargs *args)
743{
744 struct xdr_stream xdr;
745
746 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
747 encode_nfs_fh3(&xdr, args->fh);
748 prepare_reply_buffer(req, args->pages, args->pgbase,
749 args->pglen, NFS3_readlinkres_sz);
750 return 0;
751}
752
1da177e4
LT
753/*
754 * Arguments to a READ call. Since we read data directly into the page
755 * cache, we also set up the reply iovec here so that iov[1] points
756 * exactly to the page we want to fetch.
757 */
758static int
d61005a6 759nfs3_xdr_readargs(struct rpc_rqst *req, __be32 *p, struct nfs_readargs *args)
1da177e4 760{
a17c2153 761 struct rpc_auth *auth = req->rq_cred->cr_auth;
1da177e4
LT
762 unsigned int replen;
763 u32 count = args->count;
764
765 p = xdr_encode_fhandle(p, args->fh);
766 p = xdr_encode_hyper(p, args->offset);
767 *p++ = htonl(count);
768 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
769
770 /* Inline the page array */
771 replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS3_readres_sz) << 2;
772 xdr_inline_pages(&req->rq_rcv_buf, replen,
773 args->pages, args->pgbase, count);
4f22ccc3 774 req->rq_rcv_buf.flags |= XDRBUF_READ;
1da177e4
LT
775 return 0;
776}
777
d9c407b1
CL
778/*
779 * 3.3.6 READ3args
780 *
781 * struct READ3args {
782 * nfs_fh3 file;
783 * offset3 offset;
784 * count3 count;
785 * };
786 */
787static void encode_read3args(struct xdr_stream *xdr,
788 const struct nfs_readargs *args)
789{
790 __be32 *p;
791
792 encode_nfs_fh3(xdr, args->fh);
793
794 p = xdr_reserve_space(xdr, 8 + 4);
795 p = xdr_encode_hyper(p, args->offset);
796 *p = cpu_to_be32(args->count);
797}
798
799static int nfs3_xdr_enc_read3args(struct rpc_rqst *req, __be32 *p,
800 const struct nfs_readargs *args)
801{
802 struct xdr_stream xdr;
803
804 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
805 encode_read3args(&xdr, args);
806 prepare_reply_buffer(req, args->pages, args->pgbase,
807 args->count, NFS3_readres_sz);
808 req->rq_rcv_buf.flags |= XDRBUF_READ;
809 return 0;
810}
811
1da177e4
LT
812/*
813 * Write arguments. Splice the buffer to be written into the iovec.
814 */
815static int
d61005a6 816nfs3_xdr_writeargs(struct rpc_rqst *req, __be32 *p, struct nfs_writeargs *args)
1da177e4
LT
817{
818 struct xdr_buf *sndbuf = &req->rq_snd_buf;
819 u32 count = args->count;
820
821 p = xdr_encode_fhandle(p, args->fh);
822 p = xdr_encode_hyper(p, args->offset);
823 *p++ = htonl(count);
824 *p++ = htonl(args->stable);
825 *p++ = htonl(count);
826 sndbuf->len = xdr_adjust_iovec(sndbuf->head, p);
827
828 /* Copy the page array */
829 xdr_encode_pages(sndbuf, args->pages, args->pgbase, count);
4f22ccc3 830 sndbuf->flags |= XDRBUF_WRITE;
1da177e4
LT
831 return 0;
832}
833
d9c407b1
CL
834/*
835 * 3.3.7 WRITE3args
836 *
837 * enum stable_how {
838 * UNSTABLE = 0,
839 * DATA_SYNC = 1,
840 * FILE_SYNC = 2
841 * };
842 *
843 * struct WRITE3args {
844 * nfs_fh3 file;
845 * offset3 offset;
846 * count3 count;
847 * stable_how stable;
848 * opaque data<>;
849 * };
850 */
851static void encode_write3args(struct xdr_stream *xdr,
852 const struct nfs_writeargs *args)
853{
854 __be32 *p;
855
856 encode_nfs_fh3(xdr, args->fh);
857
858 p = xdr_reserve_space(xdr, 8 + 4 + 4 + 4);
859 p = xdr_encode_hyper(p, args->offset);
860 *p++ = cpu_to_be32(args->count);
861
862 BUG_ON(args->stable > NFS_FILE_SYNC);
863 *p++ = cpu_to_be32(args->stable);
864
865 *p = cpu_to_be32(args->count);
866 xdr_write_pages(xdr, args->pages, args->pgbase, args->count);
867}
868
869static int nfs3_xdr_enc_write3args(struct rpc_rqst *req, __be32 *p,
870 const struct nfs_writeargs *args)
871{
872 struct xdr_stream xdr;
873
874 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
875 encode_write3args(&xdr, args);
876 xdr.buf->flags |= XDRBUF_WRITE;
877 return 0;
878}
879
1da177e4
LT
880/*
881 * Encode CREATE arguments
882 */
883static int
d61005a6 884nfs3_xdr_createargs(struct rpc_rqst *req, __be32 *p, struct nfs3_createargs *args)
1da177e4
LT
885{
886 p = xdr_encode_fhandle(p, args->fh);
887 p = xdr_encode_array(p, args->name, args->len);
888
889 *p++ = htonl(args->createmode);
890 if (args->createmode == NFS3_CREATE_EXCLUSIVE) {
891 *p++ = args->verifier[0];
892 *p++ = args->verifier[1];
893 } else
894 p = xdr_encode_sattr(p, args->sattr);
895
896 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
897 return 0;
898}
899
d9c407b1
CL
900/*
901 * 3.3.8 CREATE3args
902 *
903 * enum createmode3 {
904 * UNCHECKED = 0,
905 * GUARDED = 1,
906 * EXCLUSIVE = 2
907 * };
908 *
909 * union createhow3 switch (createmode3 mode) {
910 * case UNCHECKED:
911 * case GUARDED:
912 * sattr3 obj_attributes;
913 * case EXCLUSIVE:
914 * createverf3 verf;
915 * };
916 *
917 * struct CREATE3args {
918 * diropargs3 where;
919 * createhow3 how;
920 * };
921 */
922static void encode_createhow3(struct xdr_stream *xdr,
923 const struct nfs3_createargs *args)
924{
925 encode_uint32(xdr, args->createmode);
926 switch (args->createmode) {
927 case NFS3_CREATE_UNCHECKED:
928 case NFS3_CREATE_GUARDED:
929 encode_sattr3(xdr, args->sattr);
930 break;
931 case NFS3_CREATE_EXCLUSIVE:
932 encode_createverf3(xdr, args->verifier);
933 break;
934 default:
935 BUG();
936 }
937}
938
939static int nfs3_xdr_enc_create3args(struct rpc_rqst *req, __be32 *p,
940 const struct nfs3_createargs *args)
941{
942 struct xdr_stream xdr;
943
944 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
945 encode_diropargs3(&xdr, args->fh, args->name, args->len);
946 encode_createhow3(&xdr, args);
947 return 0;
948}
949
1da177e4
LT
950/*
951 * Encode MKDIR arguments
952 */
953static int
d61005a6 954nfs3_xdr_mkdirargs(struct rpc_rqst *req, __be32 *p, struct nfs3_mkdirargs *args)
1da177e4
LT
955{
956 p = xdr_encode_fhandle(p, args->fh);
957 p = xdr_encode_array(p, args->name, args->len);
958 p = xdr_encode_sattr(p, args->sattr);
959 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
960 return 0;
961}
962
d9c407b1
CL
963/*
964 * 3.3.9 MKDIR3args
965 *
966 * struct MKDIR3args {
967 * diropargs3 where;
968 * sattr3 attributes;
969 * };
970 */
971static int nfs3_xdr_enc_mkdir3args(struct rpc_rqst *req, __be32 *p,
972 const struct nfs3_mkdirargs *args)
973{
974 struct xdr_stream xdr;
975
976 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
977 encode_diropargs3(&xdr, args->fh, args->name, args->len);
978 encode_sattr3(&xdr, args->sattr);
979 return 0;
980}
981
1da177e4
LT
982/*
983 * Encode SYMLINK arguments
984 */
985static int
d61005a6 986nfs3_xdr_symlinkargs(struct rpc_rqst *req, __be32 *p, struct nfs3_symlinkargs *args)
1da177e4
LT
987{
988 p = xdr_encode_fhandle(p, args->fromfh);
989 p = xdr_encode_array(p, args->fromname, args->fromlen);
990 p = xdr_encode_sattr(p, args->sattr);
94a6d753 991 *p++ = htonl(args->pathlen);
1da177e4 992 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
94a6d753
CL
993
994 /* Copy the page */
995 xdr_encode_pages(&req->rq_snd_buf, args->pages, 0, args->pathlen);
1da177e4
LT
996 return 0;
997}
998
d9c407b1
CL
999/*
1000 * 3.3.10 SYMLINK3args
1001 *
1002 * struct symlinkdata3 {
1003 * sattr3 symlink_attributes;
1004 * nfspath3 symlink_data;
1005 * };
1006 *
1007 * struct SYMLINK3args {
1008 * diropargs3 where;
1009 * symlinkdata3 symlink;
1010 * };
1011 */
1012static void encode_symlinkdata3(struct xdr_stream *xdr,
1013 const struct nfs3_symlinkargs *args)
1014{
1015 encode_sattr3(xdr, args->sattr);
1016 encode_nfspath3(xdr, args->pages, args->pathlen);
1017}
1018
1019static int nfs3_xdr_enc_symlink3args(struct rpc_rqst *req, __be32 *p,
1020 const struct nfs3_symlinkargs *args)
1021{
1022 struct xdr_stream xdr;
1023
1024 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1025 encode_diropargs3(&xdr, args->fromfh, args->fromname, args->fromlen);
1026 encode_symlinkdata3(&xdr, args);
1027 return 0;
1028}
1029
1da177e4
LT
1030/*
1031 * Encode MKNOD arguments
1032 */
1033static int
d61005a6 1034nfs3_xdr_mknodargs(struct rpc_rqst *req, __be32 *p, struct nfs3_mknodargs *args)
1da177e4
LT
1035{
1036 p = xdr_encode_fhandle(p, args->fh);
1037 p = xdr_encode_array(p, args->name, args->len);
1038 *p++ = htonl(args->type);
1039 p = xdr_encode_sattr(p, args->sattr);
1040 if (args->type == NF3CHR || args->type == NF3BLK) {
1041 *p++ = htonl(MAJOR(args->rdev));
1042 *p++ = htonl(MINOR(args->rdev));
1043 }
1044
1045 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
1046 return 0;
1047}
1048
d9c407b1
CL
1049/*
1050 * 3.3.11 MKNOD3args
1051 *
1052 * struct devicedata3 {
1053 * sattr3 dev_attributes;
1054 * specdata3 spec;
1055 * };
1056 *
1057 * union mknoddata3 switch (ftype3 type) {
1058 * case NF3CHR:
1059 * case NF3BLK:
1060 * devicedata3 device;
1061 * case NF3SOCK:
1062 * case NF3FIFO:
1063 * sattr3 pipe_attributes;
1064 * default:
1065 * void;
1066 * };
1067 *
1068 * struct MKNOD3args {
1069 * diropargs3 where;
1070 * mknoddata3 what;
1071 * };
1072 */
1073static void encode_devicedata3(struct xdr_stream *xdr,
1074 const struct nfs3_mknodargs *args)
1075{
1076 encode_sattr3(xdr, args->sattr);
1077 encode_specdata3(xdr, args->rdev);
1078}
1079
1080static void encode_mknoddata3(struct xdr_stream *xdr,
1081 const struct nfs3_mknodargs *args)
1082{
1083 encode_ftype3(xdr, args->type);
1084 switch (args->type) {
1085 case NF3CHR:
1086 case NF3BLK:
1087 encode_devicedata3(xdr, args);
1088 break;
1089 case NF3SOCK:
1090 case NF3FIFO:
1091 encode_sattr3(xdr, args->sattr);
1092 break;
1093 case NF3REG:
1094 case NF3DIR:
1095 break;
1096 default:
1097 BUG();
1098 }
1099}
1100
1101static int nfs3_xdr_enc_mknod3args(struct rpc_rqst *req, __be32 *p,
1102 const struct nfs3_mknodargs *args)
1103{
1104 struct xdr_stream xdr;
1105
1106 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1107 encode_diropargs3(&xdr, args->fh, args->name, args->len);
1108 encode_mknoddata3(&xdr, args);
1109 return 0;
1110}
1111
1112/*
1113 * 3.3.12 REMOVE3args
1114 *
1115 * struct REMOVE3args {
1116 * diropargs3 object;
1117 * };
1118 */
1119static int nfs3_xdr_enc_remove3args(struct rpc_rqst *req, __be32 *p,
1120 const struct nfs_removeargs *args)
1121{
1122 struct xdr_stream xdr;
1123
1124 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1125 encode_diropargs3(&xdr, args->fh, args->name.name, args->name.len);
1126 return 0;
1127}
1128
1da177e4
LT
1129/*
1130 * Encode RENAME arguments
1131 */
1132static int
920769f0 1133nfs3_xdr_renameargs(struct rpc_rqst *req, __be32 *p, struct nfs_renameargs *args)
1da177e4 1134{
920769f0
JL
1135 p = xdr_encode_fhandle(p, args->old_dir);
1136 p = xdr_encode_array(p, args->old_name->name, args->old_name->len);
1137 p = xdr_encode_fhandle(p, args->new_dir);
1138 p = xdr_encode_array(p, args->new_name->name, args->new_name->len);
1da177e4
LT
1139 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
1140 return 0;
1141}
1142
d9c407b1
CL
1143/*
1144 * 3.3.14 RENAME3args
1145 *
1146 * struct RENAME3args {
1147 * diropargs3 from;
1148 * diropargs3 to;
1149 * };
1150 */
1151static int nfs3_xdr_enc_rename3args(struct rpc_rqst *req, __be32 *p,
1152 const struct nfs_renameargs *args)
1153{
1154 const struct qstr *old = args->old_name;
1155 const struct qstr *new = args->new_name;
1156 struct xdr_stream xdr;
1157
1158 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1159 encode_diropargs3(&xdr, args->old_dir, old->name, old->len);
1160 encode_diropargs3(&xdr, args->new_dir, new->name, new->len);
1161 return 0;
1162}
1163
1da177e4
LT
1164/*
1165 * Encode LINK arguments
1166 */
1167static int
d61005a6 1168nfs3_xdr_linkargs(struct rpc_rqst *req, __be32 *p, struct nfs3_linkargs *args)
1da177e4
LT
1169{
1170 p = xdr_encode_fhandle(p, args->fromfh);
1171 p = xdr_encode_fhandle(p, args->tofh);
1172 p = xdr_encode_array(p, args->toname, args->tolen);
1173 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
1174 return 0;
1175}
1176
d9c407b1
CL
1177/*
1178 * 3.3.15 LINK3args
1179 *
1180 * struct LINK3args {
1181 * nfs_fh3 file;
1182 * diropargs3 link;
1183 * };
1184 */
1185static int nfs3_xdr_enc_link3args(struct rpc_rqst *req, __be32 *p,
1186 const struct nfs3_linkargs *args)
1187{
1188 struct xdr_stream xdr;
1189
1190 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1191 encode_nfs_fh3(&xdr, args->fromfh);
1192 encode_diropargs3(&xdr, args->tofh, args->toname, args->tolen);
1193 return 0;
1194}
1195
1da177e4
LT
1196/*
1197 * Encode arguments to readdir call
1198 */
1199static int
d61005a6 1200nfs3_xdr_readdirargs(struct rpc_rqst *req, __be32 *p, struct nfs3_readdirargs *args)
1da177e4 1201{
a17c2153 1202 struct rpc_auth *auth = req->rq_cred->cr_auth;
1da177e4
LT
1203 unsigned int replen;
1204 u32 count = args->count;
1205
1206 p = xdr_encode_fhandle(p, args->fh);
1207 p = xdr_encode_hyper(p, args->cookie);
1208 *p++ = args->verf[0];
1209 *p++ = args->verf[1];
1210 if (args->plus) {
1211 /* readdirplus: need dircount + buffer size.
1212 * We just make sure we make dircount big enough */
1213 *p++ = htonl(count >> 3);
1214 }
1215 *p++ = htonl(count);
1216 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
1217
1218 /* Inline the page array */
1219 replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS3_readdirres_sz) << 2;
1220 xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, 0, count);
1221 return 0;
1222}
1223
d9c407b1
CL
1224/*
1225 * 3.3.16 READDIR3args
1226 *
1227 * struct READDIR3args {
1228 * nfs_fh3 dir;
1229 * cookie3 cookie;
1230 * cookieverf3 cookieverf;
1231 * count3 count;
1232 * };
1233 */
1234static void encode_readdir3args(struct xdr_stream *xdr,
1235 const struct nfs3_readdirargs *args)
1236{
1237 __be32 *p;
1238
1239 encode_nfs_fh3(xdr, args->fh);
1240
1241 p = xdr_reserve_space(xdr, 8 + NFS3_COOKIEVERFSIZE + 4);
1242 p = xdr_encode_cookie3(p, args->cookie);
1243 p = xdr_encode_cookieverf3(p, args->verf);
1244 *p = cpu_to_be32(args->count);
1245}
1246
1247static int nfs3_xdr_enc_readdir3args(struct rpc_rqst *req, __be32 *p,
1248 const struct nfs3_readdirargs *args)
1249{
1250 struct xdr_stream xdr;
1251
1252 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1253 encode_readdir3args(&xdr, args);
1254 prepare_reply_buffer(req, args->pages, 0,
1255 args->count, NFS3_readdirres_sz);
1256 return 0;
1257}
1258
1259/*
1260 * 3.3.17 READDIRPLUS3args
1261 *
1262 * struct READDIRPLUS3args {
1263 * nfs_fh3 dir;
1264 * cookie3 cookie;
1265 * cookieverf3 cookieverf;
1266 * count3 dircount;
1267 * count3 maxcount;
1268 * };
1269 */
1270static void encode_readdirplus3args(struct xdr_stream *xdr,
1271 const struct nfs3_readdirargs *args)
1272{
1273 __be32 *p;
1274
1275 encode_nfs_fh3(xdr, args->fh);
1276
1277 p = xdr_reserve_space(xdr, 8 + NFS3_COOKIEVERFSIZE + 4 + 4);
1278 p = xdr_encode_cookie3(p, args->cookie);
1279 p = xdr_encode_cookieverf3(p, args->verf);
1280
1281 /*
1282 * readdirplus: need dircount + buffer size.
1283 * We just make sure we make dircount big enough
1284 */
1285 *p++ = cpu_to_be32(args->count >> 3);
1286
1287 *p = cpu_to_be32(args->count);
1288}
1289
1290static int nfs3_xdr_enc_readdirplus3args(struct rpc_rqst *req, __be32 *p,
1291 const struct nfs3_readdirargs *args)
1292{
1293 struct xdr_stream xdr;
1294
1295 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1296 encode_readdirplus3args(&xdr, args);
1297 prepare_reply_buffer(req, args->pages, 0,
1298 args->count, NFS3_readdirres_sz);
1299 return 0;
1300}
1301
1da177e4
LT
1302/*
1303 * Decode the result of a readdir call.
1304 * We just check for syntactical correctness.
1305 */
1306static int
d61005a6 1307nfs3_xdr_readdirres(struct rpc_rqst *req, __be32 *p, struct nfs3_readdirres *res)
1da177e4
LT
1308{
1309 struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
1310 struct kvec *iov = rcvbuf->head;
1311 struct page **page;
c957c526 1312 size_t hdrlen;
afa8ccc9 1313 u32 recvd, pglen;
ac396128 1314 int status;
1da177e4
LT
1315
1316 status = ntohl(*p++);
1317 /* Decode post_op_attrs */
1318 p = xdr_decode_post_op_attr(p, res->dir_attr);
1319 if (status)
856dff3d 1320 return nfs_stat_to_errno(status);
1da177e4
LT
1321 /* Decode verifier cookie */
1322 if (res->verf) {
1323 res->verf[0] = *p++;
1324 res->verf[1] = *p++;
1325 } else {
1326 p += 2;
1327 }
1328
1329 hdrlen = (u8 *) p - (u8 *) iov->iov_base;
1330 if (iov->iov_len < hdrlen) {
fe82a183 1331 dprintk("NFS: READDIR reply header overflowed:"
c957c526 1332 "length %Zu > %Zu\n", hdrlen, iov->iov_len);
1da177e4
LT
1333 return -errno_NFSERR_IO;
1334 } else if (iov->iov_len != hdrlen) {
1335 dprintk("NFS: READDIR header is short. iovec will be shifted.\n");
1336 xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen);
1337 }
1338
1339 pglen = rcvbuf->page_len;
1340 recvd = rcvbuf->len - hdrlen;
1341 if (pglen > recvd)
1342 pglen = recvd;
1343 page = rcvbuf->pages;
643f8111 1344
ac396128 1345 return pglen;
1da177e4
LT
1346}
1347
0dbb4c67 1348__be32 *
82f2e547 1349nfs3_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry, struct nfs_server *server, int plus)
1da177e4 1350{
babddc72 1351 __be32 *p;
1da177e4
LT
1352 struct nfs_entry old = *entry;
1353
babddc72
BS
1354 p = xdr_inline_decode(xdr, 4);
1355 if (unlikely(!p))
1356 goto out_overflow;
1357 if (!ntohl(*p++)) {
1358 p = xdr_inline_decode(xdr, 4);
1359 if (unlikely(!p))
1360 goto out_overflow;
1361 if (!ntohl(*p++))
1da177e4
LT
1362 return ERR_PTR(-EAGAIN);
1363 entry->eof = 1;
1364 return ERR_PTR(-EBADCOOKIE);
1365 }
1366
babddc72
BS
1367 p = xdr_inline_decode(xdr, 12);
1368 if (unlikely(!p))
1369 goto out_overflow;
1da177e4
LT
1370 p = xdr_decode_hyper(p, &entry->ino);
1371 entry->len = ntohl(*p++);
babddc72
BS
1372
1373 p = xdr_inline_decode(xdr, entry->len + 8);
1374 if (unlikely(!p))
1375 goto out_overflow;
1da177e4
LT
1376 entry->name = (const char *) p;
1377 p += XDR_QUADLEN(entry->len);
1378 entry->prev_cookie = entry->cookie;
1379 p = xdr_decode_hyper(p, &entry->cookie);
1380
0b26a0bf 1381 entry->d_type = DT_UNKNOWN;
1da177e4
LT
1382 if (plus) {
1383 entry->fattr->valid = 0;
babddc72
BS
1384 p = xdr_decode_post_op_attr_stream(xdr, entry->fattr);
1385 if (IS_ERR(p))
1386 goto out_overflow_exit;
0b26a0bf 1387 entry->d_type = nfs_umode_to_dtype(entry->fattr->mode);
1da177e4 1388 /* In fact, a post_op_fh3: */
babddc72
BS
1389 p = xdr_inline_decode(xdr, 4);
1390 if (unlikely(!p))
1391 goto out_overflow;
1da177e4 1392 if (*p++) {
babddc72
BS
1393 p = xdr_decode_fhandle_stream(xdr, entry->fh);
1394 if (IS_ERR(p))
1395 goto out_overflow_exit;
1da177e4
LT
1396 /* Ugh -- server reply was truncated */
1397 if (p == NULL) {
1398 dprintk("NFS: FH truncated\n");
1399 *entry = old;
1400 return ERR_PTR(-EAGAIN);
1401 }
1402 } else
1403 memset((u8*)(entry->fh), 0, sizeof(*entry->fh));
1404 }
1405
babddc72
BS
1406 p = xdr_inline_peek(xdr, 8);
1407 if (p != NULL)
1408 entry->eof = !p[0] && p[1];
1409 else
1410 entry->eof = 0;
1411
1da177e4 1412 return p;
babddc72
BS
1413
1414out_overflow:
1415 print_overflow_msg(__func__, xdr);
1416out_overflow_exit:
463a376e 1417 return ERR_PTR(-EAGAIN);
1da177e4
LT
1418}
1419
1420/*
1421 * Encode COMMIT arguments
1422 */
1423static int
d61005a6 1424nfs3_xdr_commitargs(struct rpc_rqst *req, __be32 *p, struct nfs_writeargs *args)
1da177e4
LT
1425{
1426 p = xdr_encode_fhandle(p, args->fh);
1427 p = xdr_encode_hyper(p, args->offset);
1428 *p++ = htonl(args->count);
1429 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
1430 return 0;
1431}
1432
d9c407b1
CL
1433/*
1434 * 3.3.21 COMMIT3args
1435 *
1436 * struct COMMIT3args {
1437 * nfs_fh3 file;
1438 * offset3 offset;
1439 * count3 count;
1440 * };
1441 */
1442static void encode_commit3args(struct xdr_stream *xdr,
1443 const struct nfs_writeargs *args)
1444{
1445 __be32 *p;
1446
1447 encode_nfs_fh3(xdr, args->fh);
1448
1449 p = xdr_reserve_space(xdr, 8 + 4);
1450 p = xdr_encode_hyper(p, args->offset);
1451 *p = cpu_to_be32(args->count);
1452}
1453
1454static int nfs3_xdr_enc_commit3args(struct rpc_rqst *req, __be32 *p,
1455 const struct nfs_writeargs *args)
1456{
1457 struct xdr_stream xdr;
1458
1459 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1460 encode_commit3args(&xdr, args);
1461 return 0;
1462}
1463
b7fa0554
AG
1464#ifdef CONFIG_NFS_V3_ACL
1465/*
1466 * Encode GETACL arguments
1467 */
1468static int
d61005a6 1469nfs3_xdr_getaclargs(struct rpc_rqst *req, __be32 *p,
b7fa0554
AG
1470 struct nfs3_getaclargs *args)
1471{
a17c2153 1472 struct rpc_auth *auth = req->rq_cred->cr_auth;
b7fa0554
AG
1473 unsigned int replen;
1474
1475 p = xdr_encode_fhandle(p, args->fh);
1476 *p++ = htonl(args->mask);
1477 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
1478
1479 if (args->mask & (NFS_ACL | NFS_DFACL)) {
1480 /* Inline the page array */
1481 replen = (RPC_REPHDRSIZE + auth->au_rslack +
1482 ACL3_getaclres_sz) << 2;
1483 xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, 0,
1484 NFSACL_MAXPAGES << PAGE_SHIFT);
1485 }
1486 return 0;
1487}
1488
d9c407b1
CL
1489static int nfs3_xdr_enc_getacl3args(struct rpc_rqst *req, __be32 *p,
1490 const struct nfs3_getaclargs *args)
1491{
1492 struct xdr_stream xdr;
1493
1494 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1495 encode_nfs_fh3(&xdr, args->fh);
1496 encode_uint32(&xdr, args->mask);
1497 if (args->mask & (NFS_ACL | NFS_DFACL))
1498 prepare_reply_buffer(req, args->pages, 0,
1499 NFSACL_MAXPAGES << PAGE_SHIFT,
1500 ACL3_getaclres_sz);
1501 return 0;
1502}
1503
b7fa0554
AG
1504/*
1505 * Encode SETACL arguments
1506 */
1507static int
d61005a6 1508nfs3_xdr_setaclargs(struct rpc_rqst *req, __be32 *p,
b7fa0554
AG
1509 struct nfs3_setaclargs *args)
1510{
1511 struct xdr_buf *buf = &req->rq_snd_buf;
ae46141f
TM
1512 unsigned int base;
1513 int err;
b7fa0554
AG
1514
1515 p = xdr_encode_fhandle(p, NFS_FH(args->inode));
1516 *p++ = htonl(args->mask);
ae46141f
TM
1517 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
1518 base = req->rq_slen;
1519
1520 if (args->npages != 0)
1521 xdr_encode_pages(buf, args->pages, 0, args->len);
1522 else
83404372
TM
1523 req->rq_slen = xdr_adjust_iovec(req->rq_svec,
1524 p + XDR_QUADLEN(args->len));
b7fa0554
AG
1525
1526 err = nfsacl_encode(buf, base, args->inode,
1527 (args->mask & NFS_ACL) ?
1528 args->acl_access : NULL, 1, 0);
1529 if (err > 0)
1530 err = nfsacl_encode(buf, base + err, args->inode,
1531 (args->mask & NFS_DFACL) ?
1532 args->acl_default : NULL, 1,
1533 NFS_ACL_DEFAULT);
1534 return (err > 0) ? 0 : err;
1535}
d9c407b1
CL
1536
1537static int nfs3_xdr_enc_setacl3args(struct rpc_rqst *req, __be32 *p,
1538 const struct nfs3_setaclargs *args)
1539{
1540 struct xdr_stream xdr;
1541 unsigned int base;
1542 int error;
1543
1544 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1545 encode_nfs_fh3(&xdr, NFS_FH(args->inode));
1546 encode_uint32(&xdr, args->mask);
1547 if (args->npages != 0)
1548 xdr_write_pages(&xdr, args->pages, 0, args->len);
1549
1550 base = req->rq_slen;
1551 error = nfsacl_encode(xdr.buf, base, args->inode,
1552 (args->mask & NFS_ACL) ?
1553 args->acl_access : NULL, 1, 0);
1554 BUG_ON(error < 0);
1555 error = nfsacl_encode(xdr.buf, base + error, args->inode,
1556 (args->mask & NFS_DFACL) ?
1557 args->acl_default : NULL, 1,
1558 NFS_ACL_DEFAULT);
1559 BUG_ON(error < 0);
1560 return 0;
1561}
1562
b7fa0554
AG
1563#endif /* CONFIG_NFS_V3_ACL */
1564
1da177e4
LT
1565/*
1566 * NFS XDR decode functions
1567 */
1568
1569/*
1570 * Decode attrstat reply.
1571 */
1572static int
d61005a6 1573nfs3_xdr_attrstat(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
1da177e4
LT
1574{
1575 int status;
1576
1577 if ((status = ntohl(*p++)))
856dff3d 1578 return nfs_stat_to_errno(status);
1da177e4
LT
1579 xdr_decode_fattr(p, fattr);
1580 return 0;
1581}
1582
1583/*
1584 * Decode status+wcc_data reply
1585 * SATTR, REMOVE, RMDIR
1586 */
1587static int
d61005a6 1588nfs3_xdr_wccstat(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
1da177e4
LT
1589{
1590 int status;
1591
1592 if ((status = ntohl(*p++)))
856dff3d 1593 status = nfs_stat_to_errno(status);
1da177e4
LT
1594 xdr_decode_wcc_data(p, fattr);
1595 return status;
1596}
1597
4fdc17b2
TM
1598static int
1599nfs3_xdr_removeres(struct rpc_rqst *req, __be32 *p, struct nfs_removeres *res)
1600{
d346890b 1601 return nfs3_xdr_wccstat(req, p, res->dir_attr);
4fdc17b2
TM
1602}
1603
1da177e4
LT
1604/*
1605 * Decode LOOKUP reply
1606 */
1607static int
d61005a6 1608nfs3_xdr_lookupres(struct rpc_rqst *req, __be32 *p, struct nfs3_diropres *res)
1da177e4
LT
1609{
1610 int status;
1611
1612 if ((status = ntohl(*p++))) {
856dff3d 1613 status = nfs_stat_to_errno(status);
1da177e4
LT
1614 } else {
1615 if (!(p = xdr_decode_fhandle(p, res->fh)))
1616 return -errno_NFSERR_IO;
1617 p = xdr_decode_post_op_attr(p, res->fattr);
1618 }
1619 xdr_decode_post_op_attr(p, res->dir_attr);
1620 return status;
1621}
1622
1623/*
1624 * Decode ACCESS reply
1625 */
1626static int
d61005a6 1627nfs3_xdr_accessres(struct rpc_rqst *req, __be32 *p, struct nfs3_accessres *res)
1da177e4
LT
1628{
1629 int status = ntohl(*p++);
1630
1631 p = xdr_decode_post_op_attr(p, res->fattr);
1632 if (status)
856dff3d 1633 return nfs_stat_to_errno(status);
1da177e4
LT
1634 res->access = ntohl(*p++);
1635 return 0;
1636}
1637
1638static int
d61005a6 1639nfs3_xdr_readlinkargs(struct rpc_rqst *req, __be32 *p, struct nfs3_readlinkargs *args)
1da177e4 1640{
a17c2153 1641 struct rpc_auth *auth = req->rq_cred->cr_auth;
1da177e4
LT
1642 unsigned int replen;
1643
1644 p = xdr_encode_fhandle(p, args->fh);
1645 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
1646
1647 /* Inline the page array */
1648 replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS3_readlinkres_sz) << 2;
1649 xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, args->pgbase, args->pglen);
1650 return 0;
1651}
1652
1653/*
1654 * Decode READLINK reply
1655 */
1656static int
d61005a6 1657nfs3_xdr_readlinkres(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
1da177e4
LT
1658{
1659 struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
1660 struct kvec *iov = rcvbuf->head;
c957c526
CL
1661 size_t hdrlen;
1662 u32 len, recvd;
1da177e4
LT
1663 int status;
1664
1665 status = ntohl(*p++);
1666 p = xdr_decode_post_op_attr(p, fattr);
1667
1668 if (status != 0)
856dff3d 1669 return nfs_stat_to_errno(status);
1da177e4
LT
1670
1671 /* Convert length of symlink */
1672 len = ntohl(*p++);
c957c526 1673 if (len >= rcvbuf->page_len) {
fe82a183 1674 dprintk("nfs: server returned giant symlink!\n");
1da177e4
LT
1675 return -ENAMETOOLONG;
1676 }
1677
1678 hdrlen = (u8 *) p - (u8 *) iov->iov_base;
1679 if (iov->iov_len < hdrlen) {
fe82a183 1680 dprintk("NFS: READLINK reply header overflowed:"
c957c526 1681 "length %Zu > %Zu\n", hdrlen, iov->iov_len);
1da177e4
LT
1682 return -errno_NFSERR_IO;
1683 } else if (iov->iov_len != hdrlen) {
fe82a183
CL
1684 dprintk("NFS: READLINK header is short. "
1685 "iovec will be shifted.\n");
1da177e4
LT
1686 xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen);
1687 }
1688 recvd = req->rq_rcv_buf.len - hdrlen;
1689 if (recvd < len) {
fe82a183 1690 dprintk("NFS: server cheating in readlink reply: "
1da177e4
LT
1691 "count %u > recvd %u\n", len, recvd);
1692 return -EIO;
1693 }
1694
b4687da7 1695 xdr_terminate_string(rcvbuf, len);
1da177e4
LT
1696 return 0;
1697}
1698
1699/*
1700 * Decode READ reply
1701 */
1702static int
d61005a6 1703nfs3_xdr_readres(struct rpc_rqst *req, __be32 *p, struct nfs_readres *res)
1da177e4
LT
1704{
1705 struct kvec *iov = req->rq_rcv_buf.head;
c957c526
CL
1706 size_t hdrlen;
1707 u32 count, ocount, recvd;
1708 int status;
1da177e4
LT
1709
1710 status = ntohl(*p++);
1711 p = xdr_decode_post_op_attr(p, res->fattr);
1712
1713 if (status != 0)
856dff3d 1714 return nfs_stat_to_errno(status);
1da177e4 1715
c957c526 1716 /* Decode reply count and EOF flag. NFSv3 is somewhat redundant
1da177e4
LT
1717 * in that it puts the count both in the res struct and in the
1718 * opaque data count. */
1719 count = ntohl(*p++);
1720 res->eof = ntohl(*p++);
1721 ocount = ntohl(*p++);
1722
1723 if (ocount != count) {
fe82a183 1724 dprintk("NFS: READ count doesn't match RPC opaque count.\n");
1da177e4
LT
1725 return -errno_NFSERR_IO;
1726 }
1727
1728 hdrlen = (u8 *) p - (u8 *) iov->iov_base;
1729 if (iov->iov_len < hdrlen) {
fe82a183 1730 dprintk("NFS: READ reply header overflowed:"
c957c526 1731 "length %Zu > %Zu\n", hdrlen, iov->iov_len);
1da177e4
LT
1732 return -errno_NFSERR_IO;
1733 } else if (iov->iov_len != hdrlen) {
1734 dprintk("NFS: READ header is short. iovec will be shifted.\n");
1735 xdr_shift_buf(&req->rq_rcv_buf, iov->iov_len - hdrlen);
1736 }
1737
1738 recvd = req->rq_rcv_buf.len - hdrlen;
1739 if (count > recvd) {
fe82a183 1740 dprintk("NFS: server cheating in read reply: "
c957c526 1741 "count %u > recvd %u\n", count, recvd);
1da177e4
LT
1742 count = recvd;
1743 res->eof = 0;
1744 }
1745
1746 if (count < res->count)
1747 res->count = count;
1748
1749 return count;
1750}
1751
1752/*
1753 * Decode WRITE response
1754 */
1755static int
d61005a6 1756nfs3_xdr_writeres(struct rpc_rqst *req, __be32 *p, struct nfs_writeres *res)
1da177e4
LT
1757{
1758 int status;
1759
1760 status = ntohl(*p++);
1761 p = xdr_decode_wcc_data(p, res->fattr);
1762
1763 if (status != 0)
856dff3d 1764 return nfs_stat_to_errno(status);
1da177e4
LT
1765
1766 res->count = ntohl(*p++);
1767 res->verf->committed = (enum nfs3_stable_how)ntohl(*p++);
1768 res->verf->verifier[0] = *p++;
1769 res->verf->verifier[1] = *p++;
1770
1771 return res->count;
1772}
1773
1774/*
1775 * Decode a CREATE response
1776 */
1777static int
d61005a6 1778nfs3_xdr_createres(struct rpc_rqst *req, __be32 *p, struct nfs3_diropres *res)
1da177e4
LT
1779{
1780 int status;
1781
1782 status = ntohl(*p++);
1783 if (status == 0) {
1784 if (*p++) {
1785 if (!(p = xdr_decode_fhandle(p, res->fh)))
1786 return -errno_NFSERR_IO;
1787 p = xdr_decode_post_op_attr(p, res->fattr);
1788 } else {
1789 memset(res->fh, 0, sizeof(*res->fh));
1790 /* Do decode post_op_attr but set it to NULL */
1791 p = xdr_decode_post_op_attr(p, res->fattr);
1792 res->fattr->valid = 0;
1793 }
1794 } else {
856dff3d 1795 status = nfs_stat_to_errno(status);
1da177e4
LT
1796 }
1797 p = xdr_decode_wcc_data(p, res->dir_attr);
1798 return status;
1799}
1800
1801/*
1802 * Decode RENAME reply
1803 */
1804static int
e8582a8b 1805nfs3_xdr_renameres(struct rpc_rqst *req, __be32 *p, struct nfs_renameres *res)
1da177e4
LT
1806{
1807 int status;
1808
1809 if ((status = ntohl(*p++)) != 0)
856dff3d 1810 status = nfs_stat_to_errno(status);
e8582a8b
JL
1811 p = xdr_decode_wcc_data(p, res->old_fattr);
1812 p = xdr_decode_wcc_data(p, res->new_fattr);
1da177e4
LT
1813 return status;
1814}
1815
1816/*
1817 * Decode LINK reply
1818 */
1819static int
d61005a6 1820nfs3_xdr_linkres(struct rpc_rqst *req, __be32 *p, struct nfs3_linkres *res)
1da177e4
LT
1821{
1822 int status;
1823
1824 if ((status = ntohl(*p++)) != 0)
856dff3d 1825 status = nfs_stat_to_errno(status);
1da177e4
LT
1826 p = xdr_decode_post_op_attr(p, res->fattr);
1827 p = xdr_decode_wcc_data(p, res->dir_attr);
1828 return status;
1829}
1830
1831/*
1832 * Decode FSSTAT reply
1833 */
1834static int
d61005a6 1835nfs3_xdr_fsstatres(struct rpc_rqst *req, __be32 *p, struct nfs_fsstat *res)
1da177e4
LT
1836{
1837 int status;
1838
1839 status = ntohl(*p++);
1840
1841 p = xdr_decode_post_op_attr(p, res->fattr);
1842 if (status != 0)
856dff3d 1843 return nfs_stat_to_errno(status);
1da177e4
LT
1844
1845 p = xdr_decode_hyper(p, &res->tbytes);
1846 p = xdr_decode_hyper(p, &res->fbytes);
1847 p = xdr_decode_hyper(p, &res->abytes);
1848 p = xdr_decode_hyper(p, &res->tfiles);
1849 p = xdr_decode_hyper(p, &res->ffiles);
1850 p = xdr_decode_hyper(p, &res->afiles);
1851
1852 /* ignore invarsec */
1853 return 0;
1854}
1855
1856/*
1857 * Decode FSINFO reply
1858 */
1859static int
d61005a6 1860nfs3_xdr_fsinfores(struct rpc_rqst *req, __be32 *p, struct nfs_fsinfo *res)
1da177e4
LT
1861{
1862 int status;
1863
1864 status = ntohl(*p++);
1865
1866 p = xdr_decode_post_op_attr(p, res->fattr);
1867 if (status != 0)
856dff3d 1868 return nfs_stat_to_errno(status);
1da177e4
LT
1869
1870 res->rtmax = ntohl(*p++);
1871 res->rtpref = ntohl(*p++);
1872 res->rtmult = ntohl(*p++);
1873 res->wtmax = ntohl(*p++);
1874 res->wtpref = ntohl(*p++);
1875 res->wtmult = ntohl(*p++);
1876 res->dtpref = ntohl(*p++);
1877 p = xdr_decode_hyper(p, &res->maxfilesize);
6b96724e 1878 p = xdr_decode_time3(p, &res->time_delta);
1da177e4 1879
6b96724e 1880 /* ignore properties */
1da177e4
LT
1881 res->lease_time = 0;
1882 return 0;
1883}
1884
1885/*
1886 * Decode PATHCONF reply
1887 */
1888static int
d61005a6 1889nfs3_xdr_pathconfres(struct rpc_rqst *req, __be32 *p, struct nfs_pathconf *res)
1da177e4
LT
1890{
1891 int status;
1892
1893 status = ntohl(*p++);
1894
1895 p = xdr_decode_post_op_attr(p, res->fattr);
1896 if (status != 0)
856dff3d 1897 return nfs_stat_to_errno(status);
1da177e4
LT
1898 res->max_link = ntohl(*p++);
1899 res->max_namelen = ntohl(*p++);
1900
1901 /* ignore remaining fields */
1902 return 0;
1903}
1904
1905/*
1906 * Decode COMMIT reply
1907 */
1908static int
d61005a6 1909nfs3_xdr_commitres(struct rpc_rqst *req, __be32 *p, struct nfs_writeres *res)
1da177e4
LT
1910{
1911 int status;
1912
1913 status = ntohl(*p++);
1914 p = xdr_decode_wcc_data(p, res->fattr);
1915 if (status != 0)
856dff3d 1916 return nfs_stat_to_errno(status);
1da177e4
LT
1917
1918 res->verf->verifier[0] = *p++;
1919 res->verf->verifier[1] = *p++;
1920 return 0;
1921}
1922
b7fa0554
AG
1923#ifdef CONFIG_NFS_V3_ACL
1924/*
1925 * Decode GETACL reply
1926 */
1927static int
d61005a6 1928nfs3_xdr_getaclres(struct rpc_rqst *req, __be32 *p,
b7fa0554
AG
1929 struct nfs3_getaclres *res)
1930{
1931 struct xdr_buf *buf = &req->rq_rcv_buf;
1932 int status = ntohl(*p++);
1933 struct posix_acl **acl;
1934 unsigned int *aclcnt;
1935 int err, base;
1936
1937 if (status != 0)
856dff3d 1938 return nfs_stat_to_errno(status);
b7fa0554
AG
1939 p = xdr_decode_post_op_attr(p, res->fattr);
1940 res->mask = ntohl(*p++);
1941 if (res->mask & ~(NFS_ACL|NFS_ACLCNT|NFS_DFACL|NFS_DFACLCNT))
1942 return -EINVAL;
1943 base = (char *)p - (char *)req->rq_rcv_buf.head->iov_base;
1944
1945 acl = (res->mask & NFS_ACL) ? &res->acl_access : NULL;
1946 aclcnt = (res->mask & NFS_ACLCNT) ? &res->acl_access_count : NULL;
1947 err = nfsacl_decode(buf, base, aclcnt, acl);
1948
1949 acl = (res->mask & NFS_DFACL) ? &res->acl_default : NULL;
1950 aclcnt = (res->mask & NFS_DFACLCNT) ? &res->acl_default_count : NULL;
1951 if (err > 0)
1952 err = nfsacl_decode(buf, base + err, aclcnt, acl);
1953 return (err > 0) ? 0 : err;
1954}
1955
1956/*
1957 * Decode setacl reply.
1958 */
1959static int
d61005a6 1960nfs3_xdr_setaclres(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
b7fa0554
AG
1961{
1962 int status = ntohl(*p++);
1963
1964 if (status)
856dff3d 1965 return nfs_stat_to_errno(status);
b7fa0554
AG
1966 xdr_decode_post_op_attr(p, fattr);
1967 return 0;
1968}
1969#endif /* CONFIG_NFS_V3_ACL */
1970
1da177e4
LT
1971#define PROC(proc, argtype, restype, timer) \
1972[NFS3PROC_##proc] = { \
1973 .p_proc = NFS3PROC_##proc, \
ad96b5b5 1974 .p_encode = (kxdrproc_t)nfs3_xdr_enc_##argtype##3args, \
1da177e4 1975 .p_decode = (kxdrproc_t) nfs3_xdr_##restype, \
ad96b5b5 1976 .p_arglen = NFS3_##argtype##args_sz, \
2bea90d4 1977 .p_replen = NFS3_##restype##_sz, \
cc0175c1
CL
1978 .p_timer = timer, \
1979 .p_statidx = NFS3PROC_##proc, \
1980 .p_name = #proc, \
1da177e4
LT
1981 }
1982
1983struct rpc_procinfo nfs3_procedures[] = {
ad96b5b5
CL
1984 PROC(GETATTR, getattr, attrstat, 1),
1985 PROC(SETATTR, setattr, wccstat, 0),
1986 PROC(LOOKUP, lookup, lookupres, 2),
1987 PROC(ACCESS, access, accessres, 1),
1988 PROC(READLINK, readlink, readlinkres, 3),
1989 PROC(READ, read, readres, 3),
1990 PROC(WRITE, write, writeres, 4),
1991 PROC(CREATE, create, createres, 0),
1992 PROC(MKDIR, mkdir, createres, 0),
1993 PROC(SYMLINK, symlink, createres, 0),
1994 PROC(MKNOD, mknod, createres, 0),
1995 PROC(REMOVE, remove, removeres, 0),
1996 PROC(RMDIR, lookup, wccstat, 0),
1997 PROC(RENAME, rename, renameres, 0),
1998 PROC(LINK, link, linkres, 0),
1999 PROC(READDIR, readdir, readdirres, 3),
2000 PROC(READDIRPLUS, readdirplus, readdirres, 3),
2001 PROC(FSSTAT, getattr, fsstatres, 0),
2002 PROC(FSINFO, getattr, fsinfores, 0),
2003 PROC(PATHCONF, getattr, pathconfres, 0),
2004 PROC(COMMIT, commit, commitres, 5),
1da177e4
LT
2005};
2006
2007struct rpc_version nfs_version3 = {
2008 .number = 3,
e8c96f8c 2009 .nrprocs = ARRAY_SIZE(nfs3_procedures),
1da177e4
LT
2010 .procs = nfs3_procedures
2011};
2012
b7fa0554
AG
2013#ifdef CONFIG_NFS_V3_ACL
2014static struct rpc_procinfo nfs3_acl_procedures[] = {
2015 [ACLPROC3_GETACL] = {
2016 .p_proc = ACLPROC3_GETACL,
ad96b5b5 2017 .p_encode = (kxdrproc_t)nfs3_xdr_enc_getacl3args,
b7fa0554 2018 .p_decode = (kxdrproc_t) nfs3_xdr_getaclres,
2bea90d4
CL
2019 .p_arglen = ACL3_getaclargs_sz,
2020 .p_replen = ACL3_getaclres_sz,
b7fa0554 2021 .p_timer = 1,
cc0175c1 2022 .p_name = "GETACL",
b7fa0554
AG
2023 },
2024 [ACLPROC3_SETACL] = {
2025 .p_proc = ACLPROC3_SETACL,
ad96b5b5 2026 .p_encode = (kxdrproc_t)nfs3_xdr_enc_setacl3args,
b7fa0554 2027 .p_decode = (kxdrproc_t) nfs3_xdr_setaclres,
2bea90d4
CL
2028 .p_arglen = ACL3_setaclargs_sz,
2029 .p_replen = ACL3_setaclres_sz,
b7fa0554 2030 .p_timer = 0,
cc0175c1 2031 .p_name = "SETACL",
b7fa0554
AG
2032 },
2033};
2034
2035struct rpc_version nfsacl_version3 = {
2036 .number = 3,
2037 .nrprocs = sizeof(nfs3_acl_procedures)/
2038 sizeof(nfs3_acl_procedures[0]),
2039 .procs = nfs3_acl_procedures,
2040};
2041#endif /* CONFIG_NFS_V3_ACL */