blob: bbda89042053a69e6f54b960fee6be3506dd7706 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
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>
Linus Torvalds1da177e2005-04-16 15:20:36 -070012#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>
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +000022#include <linux/nfsacl.h>
David Howellsf7b422b2006-06-09 09:34:33 -040023#include "internal.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070024
25#define NFSDBG_FACILITY NFSDBG_XDR
26
27/* Mapping from NFS error code to "errno" error code. */
28#define errno_NFSERR_IO EIO
29
Linus Torvalds1da177e2005-04-16 15:20:36 -070030/*
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)
Chuck Leverd9c407b2010-12-14 14:55:50 +000040#define NFS3_cookieverf_sz (NFS3_COOKIEVERFSIZE>>2)
Linus Torvalds1da177e2005-04-16 15:20:36 -070041#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)
Linus Torvalds1da177e2005-04-16 15:20:36 -070049#define NFS3_diropargs_sz (NFS3_fh_sz+NFS3_filename_sz)
Chuck Leverad96b5b2010-12-14 14:56:01 +000050
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)
Linus Torvalds1da177e2005-04-16 15:20:36 -070054#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)
Chuck Lever94a6d752006-08-22 20:06:23 -040060#define NFS3_symlinkargs_sz (NFS3_diropargs_sz+1+NFS3_sattr_sz)
Linus Torvalds1da177e2005-04-16 15:20:36 -070061#define NFS3_mknodargs_sz (NFS3_diropargs_sz+2+NFS3_sattr_sz)
Chuck Leverad96b5b2010-12-14 14:56:01 +000062#define NFS3_removeargs_sz (NFS3_fh_sz+NFS3_filename_sz)
Linus Torvalds1da177e2005-04-16 15:20:36 -070063#define NFS3_renameargs_sz (NFS3_diropargs_sz+NFS3_diropargs_sz)
64#define NFS3_linkargs_sz (NFS3_fh_sz+NFS3_diropargs_sz)
Chuck Leverd9c407b2010-12-14 14:55:50 +000065#define NFS3_readdirargs_sz (NFS3_fh_sz+NFS3_cookieverf_sz+3)
66#define NFS3_readdirplusargs_sz (NFS3_fh_sz+NFS3_cookieverf_sz+4)
Linus Torvalds1da177e2005-04-16 15:20:36 -070067#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)
Trond Myklebust4fdc17b2007-07-14 15:39:57 -040071#define NFS3_removeres_sz (NFS3_wccstat_sz)
Linus Torvalds1da177e2005-04-16 15:20:36 -070072#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
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +000086#define ACL3_getaclargs_sz (NFS3_fh_sz+1)
Trond Myklebustae46141f2009-03-10 20:33:18 -040087#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))
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +000091#define ACL3_setaclres_sz (1+NFS3_post_op_attr_sz)
92
Linus Torvalds1da177e2005-04-16 15:20:36 -070093/*
94 * Map file type to S_IFMT bits
95 */
Trond Myklebustbca79472009-03-11 14:10:26 -040096static 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,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700105};
106
Bryan Schumakerbabddc72010-10-20 15:44:29 -0400107static 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
Linus Torvalds1da177e2005-04-16 15:20:36 -0700114/*
Chuck Leverd9c407b2010-12-14 14:55:50 +0000115 * 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
130/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700131 * Common NFS XDR functions as inlines
132 */
Al Virod61005a2006-10-19 23:28:48 -0700133static inline __be32 *
Trond Myklebust4fdc17b2007-07-14 15:39:57 -0400134xdr_encode_fhandle(__be32 *p, const struct nfs_fh *fh)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700135{
136 return xdr_encode_array(p, fh->data, fh->size);
137}
138
Al Virod61005a2006-10-19 23:28:48 -0700139static inline __be32 *
140xdr_decode_fhandle(__be32 *p, struct nfs_fh *fh)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700141{
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
Bryan Schumakerbabddc72010-10-20 15:44:29 -0400149static 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
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172/*
173 * Encode/decode time.
174 */
Al Virod61005a2006-10-19 23:28:48 -0700175static inline __be32 *
Chuck Leverd9c407b2010-12-14 14:55:50 +0000176xdr_encode_time3(__be32 *p, const struct timespec *timep)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700177{
178 *p++ = htonl(timep->tv_sec);
179 *p++ = htonl(timep->tv_nsec);
180 return p;
181}
182
Al Virod61005a2006-10-19 23:28:48 -0700183static inline __be32 *
184xdr_decode_time3(__be32 *p, struct timespec *timep)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700185{
186 timep->tv_sec = ntohl(*p++);
187 timep->tv_nsec = ntohl(*p++);
188 return p;
189}
190
Al Virod61005a2006-10-19 23:28:48 -0700191static __be32 *
192xdr_decode_fattr(__be32 *p, struct nfs_fattr *fattr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700193{
194 unsigned int type, major, minor;
Trond Myklebustbca79472009-03-11 14:10:26 -0400195 umode_t fmode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700196
197 type = ntohl(*p++);
Trond Myklebustbca79472009-03-11 14:10:26 -0400198 if (type > NF3FIFO)
199 type = NF3NON;
200 fmode = nfs_type2fmt[type];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700201 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
Trond Myklebust8b4bdcf2006-06-09 09:34:19 -0400215 p = xdr_decode_hyper(p, &fattr->fsid.major);
216 fattr->fsid.minor = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700217 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 */
Trond Myklebust9e6e70f2009-03-11 14:10:24 -0400223 fattr->valid |= NFS_ATTR_FATTR_V3;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700224 return p;
225}
226
Al Virod61005a2006-10-19 23:28:48 -0700227static inline __be32 *
Chuck Leverd9c407b2010-12-14 14:55:50 +0000228xdr_encode_sattr(__be32 *p, const struct iattr *attr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700229{
230 if (attr->ia_valid & ATTR_MODE) {
231 *p++ = xdr_one;
Trond Myklebustcf3fff52006-01-03 09:55:53 +0100232 *p++ = htonl(attr->ia_mode & S_IALLUGO);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700233 } 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
Al Virod61005a2006-10-19 23:28:48 -0700273static inline __be32 *
274xdr_decode_wcc_attr(__be32 *p, struct nfs_fattr *fattr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700275{
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);
Trond Myklebust9e6e70f2009-03-11 14:10:24 -0400279 fattr->valid |= NFS_ATTR_FATTR_PRESIZE
280 | NFS_ATTR_FATTR_PREMTIME
281 | NFS_ATTR_FATTR_PRECTIME;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700282 return p;
283}
284
Al Virod61005a2006-10-19 23:28:48 -0700285static inline __be32 *
286xdr_decode_post_op_attr(__be32 *p, struct nfs_fattr *fattr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287{
288 if (*p++)
289 p = xdr_decode_fattr(p, fattr);
290 return p;
291}
292
Al Virod61005a2006-10-19 23:28:48 -0700293static inline __be32 *
Bryan Schumakerbabddc72010-10-20 15:44:29 -0400294xdr_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
313static inline __be32 *
Al Virod61005a2006-10-19 23:28:48 -0700314xdr_decode_pre_op_attr(__be32 *p, struct nfs_fattr *fattr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315{
316 if (*p++)
317 return xdr_decode_wcc_attr(p, fattr);
318 return p;
319}
320
321
Al Virod61005a2006-10-19 23:28:48 -0700322static inline __be32 *
323xdr_decode_wcc_data(__be32 *p, struct nfs_fattr *fattr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700324{
325 p = xdr_decode_pre_op_attr(p, fattr);
326 return xdr_decode_post_op_attr(p, fattr);
327}
328
Chuck Leverd9c407b2010-12-14 14:55:50 +0000329
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
Linus Torvalds1da177e2005-04-16 15:20:36 -0700566/*
567 * NFS encode functions
568 */
569
570/*
571 * Encode file handle argument
572 */
573static int
Al Virod61005a2006-10-19 23:28:48 -0700574nfs3_xdr_fhandle(struct rpc_rqst *req, __be32 *p, struct nfs_fh *fh)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700575{
576 p = xdr_encode_fhandle(p, fh);
577 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
578 return 0;
579}
580
581/*
Chuck Leverd9c407b2010-12-14 14:55:50 +0000582 * 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
598/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700599 * Encode SETATTR arguments
600 */
601static int
Al Virod61005a2006-10-19 23:28:48 -0700602nfs3_xdr_sattrargs(struct rpc_rqst *req, __be32 *p, struct nfs3_sattrargs *args)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700603{
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
613/*
Chuck Leverd9c407b2010-12-14 14:55:50 +0000614 * 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
656/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700657 * Encode directory ops argument
658 */
659static int
Al Virod61005a2006-10-19 23:28:48 -0700660nfs3_xdr_diropargs(struct rpc_rqst *req, __be32 *p, struct nfs3_diropargs *args)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700661{
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
668/*
Chuck Leverd9c407b2010-12-14 14:55:50 +0000669 * 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
685/*
Trond Myklebust4fdc17b2007-07-14 15:39:57 -0400686 * 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
697/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700698 * Encode access() argument
699 */
700static int
Al Virod61005a2006-10-19 23:28:48 -0700701nfs3_xdr_accessargs(struct rpc_rqst *req, __be32 *p, struct nfs3_accessargs *args)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702{
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
709/*
Chuck Leverd9c407b2010-12-14 14:55:50 +0000710 * 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
753/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700754 * 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
Al Virod61005a2006-10-19 23:28:48 -0700759nfs3_xdr_readargs(struct rpc_rqst *req, __be32 *p, struct nfs_readargs *args)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760{
Trond Myklebusta17c2152010-07-31 14:29:08 -0400761 struct rpc_auth *auth = req->rq_cred->cr_auth;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762 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);
\"Talpey, Thomas\4f22ccc2007-09-10 13:44:58 -0400774 req->rq_rcv_buf.flags |= XDRBUF_READ;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775 return 0;
776}
777
778/*
Chuck Leverd9c407b2010-12-14 14:55:50 +0000779 * 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
812/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700813 * Write arguments. Splice the buffer to be written into the iovec.
814 */
815static int
Al Virod61005a2006-10-19 23:28:48 -0700816nfs3_xdr_writeargs(struct rpc_rqst *req, __be32 *p, struct nfs_writeargs *args)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700817{
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);
\"Talpey, Thomas\4f22ccc2007-09-10 13:44:58 -0400830 sndbuf->flags |= XDRBUF_WRITE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700831 return 0;
832}
833
834/*
Chuck Leverd9c407b2010-12-14 14:55:50 +0000835 * 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
880/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700881 * Encode CREATE arguments
882 */
883static int
Al Virod61005a2006-10-19 23:28:48 -0700884nfs3_xdr_createargs(struct rpc_rqst *req, __be32 *p, struct nfs3_createargs *args)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700885{
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
900/*
Chuck Leverd9c407b2010-12-14 14:55:50 +0000901 * 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
950/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700951 * Encode MKDIR arguments
952 */
953static int
Al Virod61005a2006-10-19 23:28:48 -0700954nfs3_xdr_mkdirargs(struct rpc_rqst *req, __be32 *p, struct nfs3_mkdirargs *args)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700955{
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
963/*
Chuck Leverd9c407b2010-12-14 14:55:50 +0000964 * 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
982/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700983 * Encode SYMLINK arguments
984 */
985static int
Al Virod61005a2006-10-19 23:28:48 -0700986nfs3_xdr_symlinkargs(struct rpc_rqst *req, __be32 *p, struct nfs3_symlinkargs *args)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700987{
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);
Chuck Lever94a6d752006-08-22 20:06:23 -0400991 *p++ = htonl(args->pathlen);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700992 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
Chuck Lever94a6d752006-08-22 20:06:23 -0400993
994 /* Copy the page */
995 xdr_encode_pages(&req->rq_snd_buf, args->pages, 0, args->pathlen);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700996 return 0;
997}
998
999/*
Chuck Leverd9c407b2010-12-14 14:55:50 +00001000 * 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
1030/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001031 * Encode MKNOD arguments
1032 */
1033static int
Al Virod61005a2006-10-19 23:28:48 -07001034nfs3_xdr_mknodargs(struct rpc_rqst *req, __be32 *p, struct nfs3_mknodargs *args)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001035{
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
1049/*
Chuck Leverd9c407b2010-12-14 14:55:50 +00001050 * 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
1129/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001130 * Encode RENAME arguments
1131 */
1132static int
Jeff Layton920769f2010-09-17 17:30:25 -04001133nfs3_xdr_renameargs(struct rpc_rqst *req, __be32 *p, struct nfs_renameargs *args)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001134{
Jeff Layton920769f2010-09-17 17:30:25 -04001135 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);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001139 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
1140 return 0;
1141}
1142
1143/*
Chuck Leverd9c407b2010-12-14 14:55:50 +00001144 * 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
1164/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001165 * Encode LINK arguments
1166 */
1167static int
Al Virod61005a2006-10-19 23:28:48 -07001168nfs3_xdr_linkargs(struct rpc_rqst *req, __be32 *p, struct nfs3_linkargs *args)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001169{
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
1177/*
Chuck Leverd9c407b2010-12-14 14:55:50 +00001178 * 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
1196/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001197 * Encode arguments to readdir call
1198 */
1199static int
Al Virod61005a2006-10-19 23:28:48 -07001200nfs3_xdr_readdirargs(struct rpc_rqst *req, __be32 *p, struct nfs3_readdirargs *args)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001201{
Trond Myklebusta17c2152010-07-31 14:29:08 -04001202 struct rpc_auth *auth = req->rq_cred->cr_auth;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001203 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
1224/*
Chuck Leverd9c407b2010-12-14 14:55:50 +00001225 * 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
1302/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001303 * Decode the result of a readdir call.
1304 * We just check for syntactical correctness.
1305 */
1306static int
Al Virod61005a2006-10-19 23:28:48 -07001307nfs3_xdr_readdirres(struct rpc_rqst *req, __be32 *p, struct nfs3_readdirres *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001308{
1309 struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
1310 struct kvec *iov = rcvbuf->head;
1311 struct page **page;
Chuck Leverc957c522007-10-26 13:31:57 -04001312 size_t hdrlen;
Bryan Schumakerafa8ccc2010-10-20 15:44:31 -04001313 u32 recvd, pglen;
Trond Myklebustac396122010-11-15 20:26:22 -05001314 int status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001315
1316 status = ntohl(*p++);
1317 /* Decode post_op_attrs */
1318 p = xdr_decode_post_op_attr(p, res->dir_attr);
1319 if (status)
Benny Halevy856dff32008-03-31 17:39:06 +03001320 return nfs_stat_to_errno(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001321 /* 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) {
Chuck Leverfe82a182007-09-11 18:01:10 -04001331 dprintk("NFS: READDIR reply header overflowed:"
Chuck Leverc957c522007-10-26 13:31:57 -04001332 "length %Zu > %Zu\n", hdrlen, iov->iov_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001333 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;
Jeff Layton643f8112008-02-22 14:50:00 -05001344
Trond Myklebustac396122010-11-15 20:26:22 -05001345 return pglen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001346}
1347
Al Viro0dbb4c62006-10-19 23:28:49 -07001348__be32 *
Bryan Schumaker82f2e542010-10-21 16:33:18 -04001349nfs3_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry, struct nfs_server *server, int plus)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001350{
Bryan Schumakerbabddc72010-10-20 15:44:29 -04001351 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001352 struct nfs_entry old = *entry;
1353
Bryan Schumakerbabddc72010-10-20 15:44:29 -04001354 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++))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001362 return ERR_PTR(-EAGAIN);
1363 entry->eof = 1;
1364 return ERR_PTR(-EBADCOOKIE);
1365 }
1366
Bryan Schumakerbabddc72010-10-20 15:44:29 -04001367 p = xdr_inline_decode(xdr, 12);
1368 if (unlikely(!p))
1369 goto out_overflow;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001370 p = xdr_decode_hyper(p, &entry->ino);
1371 entry->len = ntohl(*p++);
Bryan Schumakerbabddc72010-10-20 15:44:29 -04001372
1373 p = xdr_inline_decode(xdr, entry->len + 8);
1374 if (unlikely(!p))
1375 goto out_overflow;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001376 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
Trond Myklebust0b26a0b2010-11-20 14:26:44 -05001381 entry->d_type = DT_UNKNOWN;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001382 if (plus) {
1383 entry->fattr->valid = 0;
Bryan Schumakerbabddc72010-10-20 15:44:29 -04001384 p = xdr_decode_post_op_attr_stream(xdr, entry->fattr);
1385 if (IS_ERR(p))
1386 goto out_overflow_exit;
Trond Myklebust0b26a0b2010-11-20 14:26:44 -05001387 entry->d_type = nfs_umode_to_dtype(entry->fattr->mode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001388 /* In fact, a post_op_fh3: */
Bryan Schumakerbabddc72010-10-20 15:44:29 -04001389 p = xdr_inline_decode(xdr, 4);
1390 if (unlikely(!p))
1391 goto out_overflow;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001392 if (*p++) {
Bryan Schumakerbabddc72010-10-20 15:44:29 -04001393 p = xdr_decode_fhandle_stream(xdr, entry->fh);
1394 if (IS_ERR(p))
1395 goto out_overflow_exit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001396 /* 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
Bryan Schumakerbabddc72010-10-20 15:44:29 -04001406 p = xdr_inline_peek(xdr, 8);
1407 if (p != NULL)
1408 entry->eof = !p[0] && p[1];
1409 else
1410 entry->eof = 0;
1411
Linus Torvalds1da177e2005-04-16 15:20:36 -07001412 return p;
Bryan Schumakerbabddc72010-10-20 15:44:29 -04001413
1414out_overflow:
1415 print_overflow_msg(__func__, xdr);
1416out_overflow_exit:
Trond Myklebust463a3762010-11-20 12:22:20 -05001417 return ERR_PTR(-EAGAIN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001418}
1419
1420/*
1421 * Encode COMMIT arguments
1422 */
1423static int
Al Virod61005a2006-10-19 23:28:48 -07001424nfs3_xdr_commitargs(struct rpc_rqst *req, __be32 *p, struct nfs_writeargs *args)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001425{
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
Chuck Leverd9c407b2010-12-14 14:55:50 +00001433/*
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
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +00001464#ifdef CONFIG_NFS_V3_ACL
1465/*
1466 * Encode GETACL arguments
1467 */
1468static int
Al Virod61005a2006-10-19 23:28:48 -07001469nfs3_xdr_getaclargs(struct rpc_rqst *req, __be32 *p,
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +00001470 struct nfs3_getaclargs *args)
1471{
Trond Myklebusta17c2152010-07-31 14:29:08 -04001472 struct rpc_auth *auth = req->rq_cred->cr_auth;
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +00001473 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
Chuck Leverd9c407b2010-12-14 14:55:50 +00001489static 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
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +00001504/*
1505 * Encode SETACL arguments
1506 */
1507static int
Al Virod61005a2006-10-19 23:28:48 -07001508nfs3_xdr_setaclargs(struct rpc_rqst *req, __be32 *p,
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +00001509 struct nfs3_setaclargs *args)
1510{
1511 struct xdr_buf *buf = &req->rq_snd_buf;
Trond Myklebustae46141f2009-03-10 20:33:18 -04001512 unsigned int base;
1513 int err;
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +00001514
1515 p = xdr_encode_fhandle(p, NFS_FH(args->inode));
1516 *p++ = htonl(args->mask);
Trond Myklebustae46141f2009-03-10 20:33:18 -04001517 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
1518 base = req->rq_slen;
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +00001519
Trond Myklebustae46141f2009-03-10 20:33:18 -04001520 if (args->npages != 0)
1521 xdr_encode_pages(buf, args->pages, 0, args->len);
1522 else
Trond Myklebust83404372009-04-20 14:58:35 -04001523 req->rq_slen = xdr_adjust_iovec(req->rq_svec,
1524 p + XDR_QUADLEN(args->len));
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +00001525
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}
Chuck Leverd9c407b2010-12-14 14:55:50 +00001536
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
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +00001563#endif /* CONFIG_NFS_V3_ACL */
1564
Linus Torvalds1da177e2005-04-16 15:20:36 -07001565/*
1566 * NFS XDR decode functions
1567 */
1568
1569/*
1570 * Decode attrstat reply.
1571 */
1572static int
Al Virod61005a2006-10-19 23:28:48 -07001573nfs3_xdr_attrstat(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001574{
1575 int status;
1576
1577 if ((status = ntohl(*p++)))
Benny Halevy856dff32008-03-31 17:39:06 +03001578 return nfs_stat_to_errno(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001579 xdr_decode_fattr(p, fattr);
1580 return 0;
1581}
1582
1583/*
1584 * Decode status+wcc_data reply
1585 * SATTR, REMOVE, RMDIR
1586 */
1587static int
Al Virod61005a2006-10-19 23:28:48 -07001588nfs3_xdr_wccstat(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001589{
1590 int status;
1591
1592 if ((status = ntohl(*p++)))
Benny Halevy856dff32008-03-31 17:39:06 +03001593 status = nfs_stat_to_errno(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001594 xdr_decode_wcc_data(p, fattr);
1595 return status;
1596}
1597
Trond Myklebust4fdc17b2007-07-14 15:39:57 -04001598static int
1599nfs3_xdr_removeres(struct rpc_rqst *req, __be32 *p, struct nfs_removeres *res)
1600{
Trond Myklebustd3468902010-04-16 16:22:50 -04001601 return nfs3_xdr_wccstat(req, p, res->dir_attr);
Trond Myklebust4fdc17b2007-07-14 15:39:57 -04001602}
1603
Linus Torvalds1da177e2005-04-16 15:20:36 -07001604/*
1605 * Decode LOOKUP reply
1606 */
1607static int
Al Virod61005a2006-10-19 23:28:48 -07001608nfs3_xdr_lookupres(struct rpc_rqst *req, __be32 *p, struct nfs3_diropres *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001609{
1610 int status;
1611
1612 if ((status = ntohl(*p++))) {
Benny Halevy856dff32008-03-31 17:39:06 +03001613 status = nfs_stat_to_errno(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001614 } 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
Al Virod61005a2006-10-19 23:28:48 -07001627nfs3_xdr_accessres(struct rpc_rqst *req, __be32 *p, struct nfs3_accessres *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001628{
1629 int status = ntohl(*p++);
1630
1631 p = xdr_decode_post_op_attr(p, res->fattr);
1632 if (status)
Benny Halevy856dff32008-03-31 17:39:06 +03001633 return nfs_stat_to_errno(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001634 res->access = ntohl(*p++);
1635 return 0;
1636}
1637
1638static int
Al Virod61005a2006-10-19 23:28:48 -07001639nfs3_xdr_readlinkargs(struct rpc_rqst *req, __be32 *p, struct nfs3_readlinkargs *args)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001640{
Trond Myklebusta17c2152010-07-31 14:29:08 -04001641 struct rpc_auth *auth = req->rq_cred->cr_auth;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001642 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
Al Virod61005a2006-10-19 23:28:48 -07001657nfs3_xdr_readlinkres(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001658{
1659 struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
1660 struct kvec *iov = rcvbuf->head;
Chuck Leverc957c522007-10-26 13:31:57 -04001661 size_t hdrlen;
1662 u32 len, recvd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001663 int status;
1664
1665 status = ntohl(*p++);
1666 p = xdr_decode_post_op_attr(p, fattr);
1667
1668 if (status != 0)
Benny Halevy856dff32008-03-31 17:39:06 +03001669 return nfs_stat_to_errno(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001670
1671 /* Convert length of symlink */
1672 len = ntohl(*p++);
Chuck Leverc957c522007-10-26 13:31:57 -04001673 if (len >= rcvbuf->page_len) {
Chuck Leverfe82a182007-09-11 18:01:10 -04001674 dprintk("nfs: server returned giant symlink!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001675 return -ENAMETOOLONG;
1676 }
1677
1678 hdrlen = (u8 *) p - (u8 *) iov->iov_base;
1679 if (iov->iov_len < hdrlen) {
Chuck Leverfe82a182007-09-11 18:01:10 -04001680 dprintk("NFS: READLINK reply header overflowed:"
Chuck Leverc957c522007-10-26 13:31:57 -04001681 "length %Zu > %Zu\n", hdrlen, iov->iov_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001682 return -errno_NFSERR_IO;
1683 } else if (iov->iov_len != hdrlen) {
Chuck Leverfe82a182007-09-11 18:01:10 -04001684 dprintk("NFS: READLINK header is short. "
1685 "iovec will be shifted.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001686 xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen);
1687 }
1688 recvd = req->rq_rcv_buf.len - hdrlen;
1689 if (recvd < len) {
Chuck Leverfe82a182007-09-11 18:01:10 -04001690 dprintk("NFS: server cheating in readlink reply: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001691 "count %u > recvd %u\n", len, recvd);
1692 return -EIO;
1693 }
1694
Chuck Leverb4687da2010-09-21 16:55:48 -04001695 xdr_terminate_string(rcvbuf, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001696 return 0;
1697}
1698
1699/*
1700 * Decode READ reply
1701 */
1702static int
Al Virod61005a2006-10-19 23:28:48 -07001703nfs3_xdr_readres(struct rpc_rqst *req, __be32 *p, struct nfs_readres *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001704{
1705 struct kvec *iov = req->rq_rcv_buf.head;
Chuck Leverc957c522007-10-26 13:31:57 -04001706 size_t hdrlen;
1707 u32 count, ocount, recvd;
1708 int status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001709
1710 status = ntohl(*p++);
1711 p = xdr_decode_post_op_attr(p, res->fattr);
1712
1713 if (status != 0)
Benny Halevy856dff32008-03-31 17:39:06 +03001714 return nfs_stat_to_errno(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001715
Chuck Leverc957c522007-10-26 13:31:57 -04001716 /* Decode reply count and EOF flag. NFSv3 is somewhat redundant
Linus Torvalds1da177e2005-04-16 15:20:36 -07001717 * 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) {
Chuck Leverfe82a182007-09-11 18:01:10 -04001724 dprintk("NFS: READ count doesn't match RPC opaque count.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001725 return -errno_NFSERR_IO;
1726 }
1727
1728 hdrlen = (u8 *) p - (u8 *) iov->iov_base;
1729 if (iov->iov_len < hdrlen) {
Chuck Leverfe82a182007-09-11 18:01:10 -04001730 dprintk("NFS: READ reply header overflowed:"
Chuck Leverc957c522007-10-26 13:31:57 -04001731 "length %Zu > %Zu\n", hdrlen, iov->iov_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001732 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) {
Chuck Leverfe82a182007-09-11 18:01:10 -04001740 dprintk("NFS: server cheating in read reply: "
Chuck Leverc957c522007-10-26 13:31:57 -04001741 "count %u > recvd %u\n", count, recvd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001742 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
Al Virod61005a2006-10-19 23:28:48 -07001756nfs3_xdr_writeres(struct rpc_rqst *req, __be32 *p, struct nfs_writeres *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001757{
1758 int status;
1759
1760 status = ntohl(*p++);
1761 p = xdr_decode_wcc_data(p, res->fattr);
1762
1763 if (status != 0)
Benny Halevy856dff32008-03-31 17:39:06 +03001764 return nfs_stat_to_errno(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001765
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
Al Virod61005a2006-10-19 23:28:48 -07001778nfs3_xdr_createres(struct rpc_rqst *req, __be32 *p, struct nfs3_diropres *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001779{
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 {
Benny Halevy856dff32008-03-31 17:39:06 +03001795 status = nfs_stat_to_errno(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001796 }
1797 p = xdr_decode_wcc_data(p, res->dir_attr);
1798 return status;
1799}
1800
1801/*
1802 * Decode RENAME reply
1803 */
1804static int
Jeff Laytone8582a82010-09-17 17:31:06 -04001805nfs3_xdr_renameres(struct rpc_rqst *req, __be32 *p, struct nfs_renameres *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001806{
1807 int status;
1808
1809 if ((status = ntohl(*p++)) != 0)
Benny Halevy856dff32008-03-31 17:39:06 +03001810 status = nfs_stat_to_errno(status);
Jeff Laytone8582a82010-09-17 17:31:06 -04001811 p = xdr_decode_wcc_data(p, res->old_fattr);
1812 p = xdr_decode_wcc_data(p, res->new_fattr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001813 return status;
1814}
1815
1816/*
1817 * Decode LINK reply
1818 */
1819static int
Al Virod61005a2006-10-19 23:28:48 -07001820nfs3_xdr_linkres(struct rpc_rqst *req, __be32 *p, struct nfs3_linkres *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001821{
1822 int status;
1823
1824 if ((status = ntohl(*p++)) != 0)
Benny Halevy856dff32008-03-31 17:39:06 +03001825 status = nfs_stat_to_errno(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001826 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
Al Virod61005a2006-10-19 23:28:48 -07001835nfs3_xdr_fsstatres(struct rpc_rqst *req, __be32 *p, struct nfs_fsstat *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001836{
1837 int status;
1838
1839 status = ntohl(*p++);
1840
1841 p = xdr_decode_post_op_attr(p, res->fattr);
1842 if (status != 0)
Benny Halevy856dff32008-03-31 17:39:06 +03001843 return nfs_stat_to_errno(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001844
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
Al Virod61005a2006-10-19 23:28:48 -07001860nfs3_xdr_fsinfores(struct rpc_rqst *req, __be32 *p, struct nfs_fsinfo *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001861{
1862 int status;
1863
1864 status = ntohl(*p++);
1865
1866 p = xdr_decode_post_op_attr(p, res->fattr);
1867 if (status != 0)
Benny Halevy856dff32008-03-31 17:39:06 +03001868 return nfs_stat_to_errno(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001869
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);
Ricardo Labiaga6b967242010-10-12 16:30:05 -07001878 p = xdr_decode_time3(p, &res->time_delta);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001879
Ricardo Labiaga6b967242010-10-12 16:30:05 -07001880 /* ignore properties */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001881 res->lease_time = 0;
1882 return 0;
1883}
1884
1885/*
1886 * Decode PATHCONF reply
1887 */
1888static int
Al Virod61005a2006-10-19 23:28:48 -07001889nfs3_xdr_pathconfres(struct rpc_rqst *req, __be32 *p, struct nfs_pathconf *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001890{
1891 int status;
1892
1893 status = ntohl(*p++);
1894
1895 p = xdr_decode_post_op_attr(p, res->fattr);
1896 if (status != 0)
Benny Halevy856dff32008-03-31 17:39:06 +03001897 return nfs_stat_to_errno(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001898 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
Al Virod61005a2006-10-19 23:28:48 -07001909nfs3_xdr_commitres(struct rpc_rqst *req, __be32 *p, struct nfs_writeres *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001910{
1911 int status;
1912
1913 status = ntohl(*p++);
1914 p = xdr_decode_wcc_data(p, res->fattr);
1915 if (status != 0)
Benny Halevy856dff32008-03-31 17:39:06 +03001916 return nfs_stat_to_errno(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001917
1918 res->verf->verifier[0] = *p++;
1919 res->verf->verifier[1] = *p++;
1920 return 0;
1921}
1922
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +00001923#ifdef CONFIG_NFS_V3_ACL
1924/*
1925 * Decode GETACL reply
1926 */
1927static int
Al Virod61005a2006-10-19 23:28:48 -07001928nfs3_xdr_getaclres(struct rpc_rqst *req, __be32 *p,
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +00001929 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)
Benny Halevy856dff32008-03-31 17:39:06 +03001938 return nfs_stat_to_errno(status);
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +00001939 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
Al Virod61005a2006-10-19 23:28:48 -07001960nfs3_xdr_setaclres(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +00001961{
1962 int status = ntohl(*p++);
1963
1964 if (status)
Benny Halevy856dff32008-03-31 17:39:06 +03001965 return nfs_stat_to_errno(status);
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +00001966 xdr_decode_post_op_attr(p, fattr);
1967 return 0;
1968}
1969#endif /* CONFIG_NFS_V3_ACL */
1970
Linus Torvalds1da177e2005-04-16 15:20:36 -07001971#define PROC(proc, argtype, restype, timer) \
1972[NFS3PROC_##proc] = { \
1973 .p_proc = NFS3PROC_##proc, \
Chuck Leverad96b5b2010-12-14 14:56:01 +00001974 .p_encode = (kxdrproc_t)nfs3_xdr_enc_##argtype##3args, \
Linus Torvalds1da177e2005-04-16 15:20:36 -07001975 .p_decode = (kxdrproc_t) nfs3_xdr_##restype, \
Chuck Leverad96b5b2010-12-14 14:56:01 +00001976 .p_arglen = NFS3_##argtype##args_sz, \
Chuck Lever2bea90d2007-03-29 16:47:53 -04001977 .p_replen = NFS3_##restype##_sz, \
Chuck Levercc0175c2006-03-20 13:44:22 -05001978 .p_timer = timer, \
1979 .p_statidx = NFS3PROC_##proc, \
1980 .p_name = #proc, \
Linus Torvalds1da177e2005-04-16 15:20:36 -07001981 }
1982
1983struct rpc_procinfo nfs3_procedures[] = {
Chuck Leverad96b5b2010-12-14 14:56:01 +00001984 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),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002005};
2006
2007struct rpc_version nfs_version3 = {
2008 .number = 3,
Tobias Klausere8c96f82006-03-24 03:15:34 -08002009 .nrprocs = ARRAY_SIZE(nfs3_procedures),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002010 .procs = nfs3_procedures
2011};
2012
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +00002013#ifdef CONFIG_NFS_V3_ACL
2014static struct rpc_procinfo nfs3_acl_procedures[] = {
2015 [ACLPROC3_GETACL] = {
2016 .p_proc = ACLPROC3_GETACL,
Chuck Leverad96b5b2010-12-14 14:56:01 +00002017 .p_encode = (kxdrproc_t)nfs3_xdr_enc_getacl3args,
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +00002018 .p_decode = (kxdrproc_t) nfs3_xdr_getaclres,
Chuck Lever2bea90d2007-03-29 16:47:53 -04002019 .p_arglen = ACL3_getaclargs_sz,
2020 .p_replen = ACL3_getaclres_sz,
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +00002021 .p_timer = 1,
Chuck Levercc0175c2006-03-20 13:44:22 -05002022 .p_name = "GETACL",
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +00002023 },
2024 [ACLPROC3_SETACL] = {
2025 .p_proc = ACLPROC3_SETACL,
Chuck Leverad96b5b2010-12-14 14:56:01 +00002026 .p_encode = (kxdrproc_t)nfs3_xdr_enc_setacl3args,
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +00002027 .p_decode = (kxdrproc_t) nfs3_xdr_setaclres,
Chuck Lever2bea90d2007-03-29 16:47:53 -04002028 .p_arglen = ACL3_setaclargs_sz,
2029 .p_replen = ACL3_setaclres_sz,
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +00002030 .p_timer = 0,
Chuck Levercc0175c2006-03-20 13:44:22 -05002031 .p_name = "SETACL",
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +00002032 },
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 */