blob: 3d1043f7667c13c759929b75b153b4e36c269532 [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)
49
50#define NFS3_sattrargs_sz (NFS3_fh_sz+NFS3_sattr_sz+3)
51#define NFS3_diropargs_sz (NFS3_fh_sz+NFS3_filename_sz)
Trond Myklebust4fdc17b2007-07-14 15:39:57 -040052#define NFS3_removeargs_sz (NFS3_fh_sz+NFS3_filename_sz)
Linus Torvalds1da177e2005-04-16 15:20:36 -070053#define NFS3_accessargs_sz (NFS3_fh_sz+1)
54#define NFS3_readlinkargs_sz (NFS3_fh_sz)
55#define NFS3_readargs_sz (NFS3_fh_sz+3)
56#define NFS3_writeargs_sz (NFS3_fh_sz+5)
57#define NFS3_createargs_sz (NFS3_diropargs_sz+NFS3_sattr_sz)
58#define NFS3_mkdirargs_sz (NFS3_diropargs_sz+NFS3_sattr_sz)
Chuck Lever94a6d752006-08-22 20:06:23 -040059#define NFS3_symlinkargs_sz (NFS3_diropargs_sz+1+NFS3_sattr_sz)
Linus Torvalds1da177e2005-04-16 15:20:36 -070060#define NFS3_mknodargs_sz (NFS3_diropargs_sz+2+NFS3_sattr_sz)
61#define NFS3_renameargs_sz (NFS3_diropargs_sz+NFS3_diropargs_sz)
62#define NFS3_linkargs_sz (NFS3_fh_sz+NFS3_diropargs_sz)
Chuck Leverd9c407b2010-12-14 14:55:50 +000063#define NFS3_readdirargs_sz (NFS3_fh_sz+NFS3_cookieverf_sz+3)
64#define NFS3_readdirplusargs_sz (NFS3_fh_sz+NFS3_cookieverf_sz+4)
Linus Torvalds1da177e2005-04-16 15:20:36 -070065#define NFS3_commitargs_sz (NFS3_fh_sz+3)
66
67#define NFS3_attrstat_sz (1+NFS3_fattr_sz)
68#define NFS3_wccstat_sz (1+NFS3_wcc_data_sz)
Trond Myklebust4fdc17b2007-07-14 15:39:57 -040069#define NFS3_removeres_sz (NFS3_wccstat_sz)
Linus Torvalds1da177e2005-04-16 15:20:36 -070070#define NFS3_lookupres_sz (1+NFS3_fh_sz+(2 * NFS3_post_op_attr_sz))
71#define NFS3_accessres_sz (1+NFS3_post_op_attr_sz+1)
72#define NFS3_readlinkres_sz (1+NFS3_post_op_attr_sz+1)
73#define NFS3_readres_sz (1+NFS3_post_op_attr_sz+3)
74#define NFS3_writeres_sz (1+NFS3_wcc_data_sz+4)
75#define NFS3_createres_sz (1+NFS3_fh_sz+NFS3_post_op_attr_sz+NFS3_wcc_data_sz)
76#define NFS3_renameres_sz (1+(2 * NFS3_wcc_data_sz))
77#define NFS3_linkres_sz (1+NFS3_post_op_attr_sz+NFS3_wcc_data_sz)
78#define NFS3_readdirres_sz (1+NFS3_post_op_attr_sz+2)
79#define NFS3_fsstatres_sz (1+NFS3_post_op_attr_sz+13)
80#define NFS3_fsinfores_sz (1+NFS3_post_op_attr_sz+12)
81#define NFS3_pathconfres_sz (1+NFS3_post_op_attr_sz+6)
82#define NFS3_commitres_sz (1+NFS3_wcc_data_sz+2)
83
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +000084#define ACL3_getaclargs_sz (NFS3_fh_sz+1)
Trond Myklebustae461412009-03-10 20:33:18 -040085#define ACL3_setaclargs_sz (NFS3_fh_sz+1+ \
86 XDR_QUADLEN(NFS_ACL_INLINE_BUFSIZE))
87#define ACL3_getaclres_sz (1+NFS3_post_op_attr_sz+1+ \
88 XDR_QUADLEN(NFS_ACL_INLINE_BUFSIZE))
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +000089#define ACL3_setaclres_sz (1+NFS3_post_op_attr_sz)
90
Linus Torvalds1da177e2005-04-16 15:20:36 -070091/*
92 * Map file type to S_IFMT bits
93 */
Trond Myklebustbca79472009-03-11 14:10:26 -040094static const umode_t nfs_type2fmt[] = {
95 [NF3BAD] = 0,
96 [NF3REG] = S_IFREG,
97 [NF3DIR] = S_IFDIR,
98 [NF3BLK] = S_IFBLK,
99 [NF3CHR] = S_IFCHR,
100 [NF3LNK] = S_IFLNK,
101 [NF3SOCK] = S_IFSOCK,
102 [NF3FIFO] = S_IFIFO,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700103};
104
Bryan Schumakerbabddc72010-10-20 15:44:29 -0400105static void print_overflow_msg(const char *func, const struct xdr_stream *xdr)
106{
107 dprintk("nfs: %s: prematurely hit end of receive buffer. "
108 "Remaining buffer length is %tu words.\n",
109 func, xdr->end - xdr->p);
110}
111
Linus Torvalds1da177e2005-04-16 15:20:36 -0700112/*
Chuck Leverd9c407b2010-12-14 14:55:50 +0000113 * While encoding arguments, set up the reply buffer in advance to
114 * receive reply data directly into the page cache.
115 */
116static void prepare_reply_buffer(struct rpc_rqst *req, struct page **pages,
117 unsigned int base, unsigned int len,
118 unsigned int bufsize)
119{
120 struct rpc_auth *auth = req->rq_cred->cr_auth;
121 unsigned int replen;
122
123 replen = RPC_REPHDRSIZE + auth->au_rslack + bufsize;
124 xdr_inline_pages(&req->rq_rcv_buf, replen << 2, pages, base, len);
125}
126
127
128/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700129 * Common NFS XDR functions as inlines
130 */
Al Virod61005a2006-10-19 23:28:48 -0700131static inline __be32 *
Trond Myklebust4fdc17b2007-07-14 15:39:57 -0400132xdr_encode_fhandle(__be32 *p, const struct nfs_fh *fh)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700133{
134 return xdr_encode_array(p, fh->data, fh->size);
135}
136
Al Virod61005a2006-10-19 23:28:48 -0700137static inline __be32 *
138xdr_decode_fhandle(__be32 *p, struct nfs_fh *fh)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139{
140 if ((fh->size = ntohl(*p++)) <= NFS3_FHSIZE) {
141 memcpy(fh->data, p, fh->size);
142 return p + XDR_QUADLEN(fh->size);
143 }
144 return NULL;
145}
146
Bryan Schumakerbabddc72010-10-20 15:44:29 -0400147static inline __be32 *
148xdr_decode_fhandle_stream(struct xdr_stream *xdr, struct nfs_fh *fh)
149{
150 __be32 *p;
151 p = xdr_inline_decode(xdr, 4);
152 if (unlikely(!p))
153 goto out_overflow;
154 fh->size = ntohl(*p++);
155
156 if (fh->size <= NFS3_FHSIZE) {
157 p = xdr_inline_decode(xdr, fh->size);
158 if (unlikely(!p))
159 goto out_overflow;
160 memcpy(fh->data, p, fh->size);
161 return p + XDR_QUADLEN(fh->size);
162 }
163 return NULL;
164
165out_overflow:
166 print_overflow_msg(__func__, xdr);
167 return ERR_PTR(-EIO);
168}
169
Linus Torvalds1da177e2005-04-16 15:20:36 -0700170/*
171 * Encode/decode time.
172 */
Al Virod61005a2006-10-19 23:28:48 -0700173static inline __be32 *
Chuck Leverd9c407b2010-12-14 14:55:50 +0000174xdr_encode_time3(__be32 *p, const struct timespec *timep)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700175{
176 *p++ = htonl(timep->tv_sec);
177 *p++ = htonl(timep->tv_nsec);
178 return p;
179}
180
Al Virod61005a2006-10-19 23:28:48 -0700181static inline __be32 *
182xdr_decode_time3(__be32 *p, struct timespec *timep)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700183{
184 timep->tv_sec = ntohl(*p++);
185 timep->tv_nsec = ntohl(*p++);
186 return p;
187}
188
Al Virod61005a2006-10-19 23:28:48 -0700189static __be32 *
190xdr_decode_fattr(__be32 *p, struct nfs_fattr *fattr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700191{
192 unsigned int type, major, minor;
Trond Myklebustbca79472009-03-11 14:10:26 -0400193 umode_t fmode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700194
195 type = ntohl(*p++);
Trond Myklebustbca79472009-03-11 14:10:26 -0400196 if (type > NF3FIFO)
197 type = NF3NON;
198 fmode = nfs_type2fmt[type];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700199 fattr->mode = (ntohl(*p++) & ~S_IFMT) | fmode;
200 fattr->nlink = ntohl(*p++);
201 fattr->uid = ntohl(*p++);
202 fattr->gid = ntohl(*p++);
203 p = xdr_decode_hyper(p, &fattr->size);
204 p = xdr_decode_hyper(p, &fattr->du.nfs3.used);
205
206 /* Turn remote device info into Linux-specific dev_t */
207 major = ntohl(*p++);
208 minor = ntohl(*p++);
209 fattr->rdev = MKDEV(major, minor);
210 if (MAJOR(fattr->rdev) != major || MINOR(fattr->rdev) != minor)
211 fattr->rdev = 0;
212
Trond Myklebust8b4bdcf2006-06-09 09:34:19 -0400213 p = xdr_decode_hyper(p, &fattr->fsid.major);
214 fattr->fsid.minor = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215 p = xdr_decode_hyper(p, &fattr->fileid);
216 p = xdr_decode_time3(p, &fattr->atime);
217 p = xdr_decode_time3(p, &fattr->mtime);
218 p = xdr_decode_time3(p, &fattr->ctime);
219
220 /* Update the mode bits */
Trond Myklebust9e6e70f2009-03-11 14:10:24 -0400221 fattr->valid |= NFS_ATTR_FATTR_V3;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700222 return p;
223}
224
Al Virod61005a2006-10-19 23:28:48 -0700225static inline __be32 *
Chuck Leverd9c407b2010-12-14 14:55:50 +0000226xdr_encode_sattr(__be32 *p, const struct iattr *attr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700227{
228 if (attr->ia_valid & ATTR_MODE) {
229 *p++ = xdr_one;
Trond Myklebustcf3fff52006-01-03 09:55:53 +0100230 *p++ = htonl(attr->ia_mode & S_IALLUGO);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700231 } else {
232 *p++ = xdr_zero;
233 }
234 if (attr->ia_valid & ATTR_UID) {
235 *p++ = xdr_one;
236 *p++ = htonl(attr->ia_uid);
237 } else {
238 *p++ = xdr_zero;
239 }
240 if (attr->ia_valid & ATTR_GID) {
241 *p++ = xdr_one;
242 *p++ = htonl(attr->ia_gid);
243 } else {
244 *p++ = xdr_zero;
245 }
246 if (attr->ia_valid & ATTR_SIZE) {
247 *p++ = xdr_one;
248 p = xdr_encode_hyper(p, (__u64) attr->ia_size);
249 } else {
250 *p++ = xdr_zero;
251 }
252 if (attr->ia_valid & ATTR_ATIME_SET) {
253 *p++ = xdr_two;
254 p = xdr_encode_time3(p, &attr->ia_atime);
255 } else if (attr->ia_valid & ATTR_ATIME) {
256 *p++ = xdr_one;
257 } else {
258 *p++ = xdr_zero;
259 }
260 if (attr->ia_valid & ATTR_MTIME_SET) {
261 *p++ = xdr_two;
262 p = xdr_encode_time3(p, &attr->ia_mtime);
263 } else if (attr->ia_valid & ATTR_MTIME) {
264 *p++ = xdr_one;
265 } else {
266 *p++ = xdr_zero;
267 }
268 return p;
269}
270
Al Virod61005a2006-10-19 23:28:48 -0700271static inline __be32 *
272xdr_decode_wcc_attr(__be32 *p, struct nfs_fattr *fattr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700273{
274 p = xdr_decode_hyper(p, &fattr->pre_size);
275 p = xdr_decode_time3(p, &fattr->pre_mtime);
276 p = xdr_decode_time3(p, &fattr->pre_ctime);
Trond Myklebust9e6e70f2009-03-11 14:10:24 -0400277 fattr->valid |= NFS_ATTR_FATTR_PRESIZE
278 | NFS_ATTR_FATTR_PREMTIME
279 | NFS_ATTR_FATTR_PRECTIME;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700280 return p;
281}
282
Al Virod61005a2006-10-19 23:28:48 -0700283static inline __be32 *
284xdr_decode_post_op_attr(__be32 *p, struct nfs_fattr *fattr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700285{
286 if (*p++)
287 p = xdr_decode_fattr(p, fattr);
288 return p;
289}
290
Al Virod61005a2006-10-19 23:28:48 -0700291static inline __be32 *
Bryan Schumakerbabddc72010-10-20 15:44:29 -0400292xdr_decode_post_op_attr_stream(struct xdr_stream *xdr, struct nfs_fattr *fattr)
293{
294 __be32 *p;
295
296 p = xdr_inline_decode(xdr, 4);
297 if (unlikely(!p))
298 goto out_overflow;
299 if (ntohl(*p++)) {
300 p = xdr_inline_decode(xdr, 84);
301 if (unlikely(!p))
302 goto out_overflow;
303 p = xdr_decode_fattr(p, fattr);
304 }
305 return p;
306out_overflow:
307 print_overflow_msg(__func__, xdr);
308 return ERR_PTR(-EIO);
309}
310
311static inline __be32 *
Al Virod61005a2006-10-19 23:28:48 -0700312xdr_decode_pre_op_attr(__be32 *p, struct nfs_fattr *fattr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700313{
314 if (*p++)
315 return xdr_decode_wcc_attr(p, fattr);
316 return p;
317}
318
319
Al Virod61005a2006-10-19 23:28:48 -0700320static inline __be32 *
321xdr_decode_wcc_data(__be32 *p, struct nfs_fattr *fattr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700322{
323 p = xdr_decode_pre_op_attr(p, fattr);
324 return xdr_decode_post_op_attr(p, fattr);
325}
326
Chuck Leverd9c407b2010-12-14 14:55:50 +0000327
328/*
329 * Encode/decode NFSv3 basic data types
330 *
331 * Basic NFSv3 data types are defined in section 2.5 of RFC 1813:
332 * "NFS Version 3 Protocol Specification".
333 *
334 * Not all basic data types have their own encoding and decoding
335 * functions. For run-time efficiency, some data types are encoded
336 * or decoded inline.
337 */
338
339static void encode_uint32(struct xdr_stream *xdr, u32 value)
340{
341 __be32 *p = xdr_reserve_space(xdr, 4);
342 *p = cpu_to_be32(value);
343}
344
345/*
346 * filename3
347 *
348 * typedef string filename3<>;
349 */
350static void encode_filename3(struct xdr_stream *xdr,
351 const char *name, u32 length)
352{
353 __be32 *p;
354
355 BUG_ON(length > NFS3_MAXNAMLEN);
356 p = xdr_reserve_space(xdr, 4 + length);
357 xdr_encode_opaque(p, name, length);
358}
359
360/*
361 * nfspath3
362 *
363 * typedef string nfspath3<>;
364 */
365static void encode_nfspath3(struct xdr_stream *xdr, struct page **pages,
366 const u32 length)
367{
368 BUG_ON(length > NFS3_MAXPATHLEN);
369 encode_uint32(xdr, length);
370 xdr_write_pages(xdr, pages, 0, length);
371}
372
373/*
374 * cookie3
375 *
376 * typedef uint64 cookie3
377 */
378static __be32 *xdr_encode_cookie3(__be32 *p, u64 cookie)
379{
380 return xdr_encode_hyper(p, cookie);
381}
382
383/*
384 * cookieverf3
385 *
386 * typedef opaque cookieverf3[NFS3_COOKIEVERFSIZE];
387 */
388static __be32 *xdr_encode_cookieverf3(__be32 *p, const __be32 *verifier)
389{
390 memcpy(p, verifier, NFS3_COOKIEVERFSIZE);
391 return p + XDR_QUADLEN(NFS3_COOKIEVERFSIZE);
392}
393
394/*
395 * createverf3
396 *
397 * typedef opaque createverf3[NFS3_CREATEVERFSIZE];
398 */
399static void encode_createverf3(struct xdr_stream *xdr, const __be32 *verifier)
400{
401 __be32 *p;
402
403 p = xdr_reserve_space(xdr, NFS3_CREATEVERFSIZE);
404 memcpy(p, verifier, NFS3_CREATEVERFSIZE);
405}
406
407/*
408 * ftype3
409 *
410 * enum ftype3 {
411 * NF3REG = 1,
412 * NF3DIR = 2,
413 * NF3BLK = 3,
414 * NF3CHR = 4,
415 * NF3LNK = 5,
416 * NF3SOCK = 6,
417 * NF3FIFO = 7
418 * };
419 */
420static void encode_ftype3(struct xdr_stream *xdr, const u32 type)
421{
422 BUG_ON(type > NF3FIFO);
423 encode_uint32(xdr, type);
424}
425
426/*
427 * specdata3
428 *
429 * struct specdata3 {
430 * uint32 specdata1;
431 * uint32 specdata2;
432 * };
433 */
434static void encode_specdata3(struct xdr_stream *xdr, const dev_t rdev)
435{
436 __be32 *p;
437
438 p = xdr_reserve_space(xdr, 8);
439 *p++ = cpu_to_be32(MAJOR(rdev));
440 *p = cpu_to_be32(MINOR(rdev));
441}
442
443/*
444 * nfs_fh3
445 *
446 * struct nfs_fh3 {
447 * opaque data<NFS3_FHSIZE>;
448 * };
449 */
450static void encode_nfs_fh3(struct xdr_stream *xdr, const struct nfs_fh *fh)
451{
452 __be32 *p;
453
454 BUG_ON(fh->size > NFS3_FHSIZE);
455 p = xdr_reserve_space(xdr, 4 + fh->size);
456 xdr_encode_opaque(p, fh->data, fh->size);
457}
458
459/*
460 * sattr3
461 *
462 * enum time_how {
463 * DONT_CHANGE = 0,
464 * SET_TO_SERVER_TIME = 1,
465 * SET_TO_CLIENT_TIME = 2
466 * };
467 *
468 * union set_mode3 switch (bool set_it) {
469 * case TRUE:
470 * mode3 mode;
471 * default:
472 * void;
473 * };
474 *
475 * union set_uid3 switch (bool set_it) {
476 * case TRUE:
477 * uid3 uid;
478 * default:
479 * void;
480 * };
481 *
482 * union set_gid3 switch (bool set_it) {
483 * case TRUE:
484 * gid3 gid;
485 * default:
486 * void;
487 * };
488 *
489 * union set_size3 switch (bool set_it) {
490 * case TRUE:
491 * size3 size;
492 * default:
493 * void;
494 * };
495 *
496 * union set_atime switch (time_how set_it) {
497 * case SET_TO_CLIENT_TIME:
498 * nfstime3 atime;
499 * default:
500 * void;
501 * };
502 *
503 * union set_mtime switch (time_how set_it) {
504 * case SET_TO_CLIENT_TIME:
505 * nfstime3 mtime;
506 * default:
507 * void;
508 * };
509 *
510 * struct sattr3 {
511 * set_mode3 mode;
512 * set_uid3 uid;
513 * set_gid3 gid;
514 * set_size3 size;
515 * set_atime atime;
516 * set_mtime mtime;
517 * };
518 */
519static void encode_sattr3(struct xdr_stream *xdr, const struct iattr *attr)
520{
521 u32 nbytes;
522 __be32 *p;
523
524 /*
525 * In order to make only a single xdr_reserve_space() call,
526 * pre-compute the total number of bytes to be reserved.
527 * Six boolean values, one for each set_foo field, are always
528 * present in the encoded result, so start there.
529 */
530 nbytes = 6 * 4;
531 if (attr->ia_valid & ATTR_MODE)
532 nbytes += 4;
533 if (attr->ia_valid & ATTR_UID)
534 nbytes += 4;
535 if (attr->ia_valid & ATTR_GID)
536 nbytes += 4;
537 if (attr->ia_valid & ATTR_SIZE)
538 nbytes += 8;
539 if (attr->ia_valid & ATTR_ATIME_SET)
540 nbytes += 8;
541 if (attr->ia_valid & ATTR_MTIME_SET)
542 nbytes += 8;
543 p = xdr_reserve_space(xdr, nbytes);
544
545 xdr_encode_sattr(p, attr);
546}
547
548/*
549 * diropargs3
550 *
551 * struct diropargs3 {
552 * nfs_fh3 dir;
553 * filename3 name;
554 * };
555 */
556static void encode_diropargs3(struct xdr_stream *xdr, const struct nfs_fh *fh,
557 const char *name, u32 length)
558{
559 encode_nfs_fh3(xdr, fh);
560 encode_filename3(xdr, name, length);
561}
562
563
Linus Torvalds1da177e2005-04-16 15:20:36 -0700564/*
565 * NFS encode functions
566 */
567
568/*
569 * Encode file handle argument
570 */
571static int
Al Virod61005a2006-10-19 23:28:48 -0700572nfs3_xdr_fhandle(struct rpc_rqst *req, __be32 *p, struct nfs_fh *fh)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700573{
574 p = xdr_encode_fhandle(p, fh);
575 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
576 return 0;
577}
578
579/*
Chuck Leverd9c407b2010-12-14 14:55:50 +0000580 * 3.3.1 GETATTR3args
581 *
582 * struct GETATTR3args {
583 * nfs_fh3 object;
584 * };
585 */
586static int nfs3_xdr_enc_getattr3args(struct rpc_rqst *req, __be32 *p,
587 const struct nfs_fh *fh)
588{
589 struct xdr_stream xdr;
590
591 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
592 encode_nfs_fh3(&xdr, fh);
593 return 0;
594}
595
596/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700597 * Encode SETATTR arguments
598 */
599static int
Al Virod61005a2006-10-19 23:28:48 -0700600nfs3_xdr_sattrargs(struct rpc_rqst *req, __be32 *p, struct nfs3_sattrargs *args)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601{
602 p = xdr_encode_fhandle(p, args->fh);
603 p = xdr_encode_sattr(p, args->sattr);
604 *p++ = htonl(args->guard);
605 if (args->guard)
606 p = xdr_encode_time3(p, &args->guardtime);
607 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
608 return 0;
609}
610
611/*
Chuck Leverd9c407b2010-12-14 14:55:50 +0000612 * 3.3.2 SETATTR3args
613 *
614 * union sattrguard3 switch (bool check) {
615 * case TRUE:
616 * nfstime3 obj_ctime;
617 * case FALSE:
618 * void;
619 * };
620 *
621 * struct SETATTR3args {
622 * nfs_fh3 object;
623 * sattr3 new_attributes;
624 * sattrguard3 guard;
625 * };
626 */
627static void encode_sattrguard3(struct xdr_stream *xdr,
628 const struct nfs3_sattrargs *args)
629{
630 __be32 *p;
631
632 if (args->guard) {
633 p = xdr_reserve_space(xdr, 4 + 8);
634 *p++ = xdr_one;
635 xdr_encode_time3(p, &args->guardtime);
636 } else {
637 p = xdr_reserve_space(xdr, 4);
638 *p = xdr_zero;
639 }
640}
641
642static int nfs3_xdr_enc_setattr3args(struct rpc_rqst *req, __be32 *p,
643 const struct nfs3_sattrargs *args)
644{
645 struct xdr_stream xdr;
646
647 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
648 encode_nfs_fh3(&xdr, args->fh);
649 encode_sattr3(&xdr, args->sattr);
650 encode_sattrguard3(&xdr, args);
651 return 0;
652}
653
654/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655 * Encode directory ops argument
656 */
657static int
Al Virod61005a2006-10-19 23:28:48 -0700658nfs3_xdr_diropargs(struct rpc_rqst *req, __be32 *p, struct nfs3_diropargs *args)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700659{
660 p = xdr_encode_fhandle(p, args->fh);
661 p = xdr_encode_array(p, args->name, args->len);
662 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
663 return 0;
664}
665
666/*
Chuck Leverd9c407b2010-12-14 14:55:50 +0000667 * 3.3.3 LOOKUP3args
668 *
669 * struct LOOKUP3args {
670 * diropargs3 what;
671 * };
672 */
673static int nfs3_xdr_enc_lookup3args(struct rpc_rqst *req, __be32 *p,
674 const struct nfs3_diropargs *args)
675{
676 struct xdr_stream xdr;
677
678 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
679 encode_diropargs3(&xdr, args->fh, args->name, args->len);
680 return 0;
681}
682
683/*
Trond Myklebust4fdc17b2007-07-14 15:39:57 -0400684 * Encode REMOVE argument
685 */
686static int
687nfs3_xdr_removeargs(struct rpc_rqst *req, __be32 *p, const struct nfs_removeargs *args)
688{
689 p = xdr_encode_fhandle(p, args->fh);
690 p = xdr_encode_array(p, args->name.name, args->name.len);
691 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
692 return 0;
693}
694
695/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700696 * Encode access() argument
697 */
698static int
Al Virod61005a2006-10-19 23:28:48 -0700699nfs3_xdr_accessargs(struct rpc_rqst *req, __be32 *p, struct nfs3_accessargs *args)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700700{
701 p = xdr_encode_fhandle(p, args->fh);
702 *p++ = htonl(args->access);
703 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
704 return 0;
705}
706
707/*
Chuck Leverd9c407b2010-12-14 14:55:50 +0000708 * 3.3.4 ACCESS3args
709 *
710 * struct ACCESS3args {
711 * nfs_fh3 object;
712 * uint32 access;
713 * };
714 */
715static void encode_access3args(struct xdr_stream *xdr,
716 const struct nfs3_accessargs *args)
717{
718 encode_nfs_fh3(xdr, args->fh);
719 encode_uint32(xdr, args->access);
720}
721
722static int nfs3_xdr_enc_access3args(struct rpc_rqst *req, __be32 *p,
723 const struct nfs3_accessargs *args)
724{
725 struct xdr_stream xdr;
726
727 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
728 encode_access3args(&xdr, args);
729 return 0;
730}
731
732/*
733 * 3.3.5 READLINK3args
734 *
735 * struct READLINK3args {
736 * nfs_fh3 symlink;
737 * };
738 */
739static int nfs3_xdr_enc_readlink3args(struct rpc_rqst *req, __be32 *p,
740 const struct nfs3_readlinkargs *args)
741{
742 struct xdr_stream xdr;
743
744 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
745 encode_nfs_fh3(&xdr, args->fh);
746 prepare_reply_buffer(req, args->pages, args->pgbase,
747 args->pglen, NFS3_readlinkres_sz);
748 return 0;
749}
750
751/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752 * Arguments to a READ call. Since we read data directly into the page
753 * cache, we also set up the reply iovec here so that iov[1] points
754 * exactly to the page we want to fetch.
755 */
756static int
Al Virod61005a2006-10-19 23:28:48 -0700757nfs3_xdr_readargs(struct rpc_rqst *req, __be32 *p, struct nfs_readargs *args)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700758{
Trond Myklebusta17c2152010-07-31 14:29:08 -0400759 struct rpc_auth *auth = req->rq_cred->cr_auth;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760 unsigned int replen;
761 u32 count = args->count;
762
763 p = xdr_encode_fhandle(p, args->fh);
764 p = xdr_encode_hyper(p, args->offset);
765 *p++ = htonl(count);
766 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
767
768 /* Inline the page array */
769 replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS3_readres_sz) << 2;
770 xdr_inline_pages(&req->rq_rcv_buf, replen,
771 args->pages, args->pgbase, count);
\"Talpey, Thomas\4f22ccc2007-09-10 13:44:58 -0400772 req->rq_rcv_buf.flags |= XDRBUF_READ;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700773 return 0;
774}
775
776/*
Chuck Leverd9c407b2010-12-14 14:55:50 +0000777 * 3.3.6 READ3args
778 *
779 * struct READ3args {
780 * nfs_fh3 file;
781 * offset3 offset;
782 * count3 count;
783 * };
784 */
785static void encode_read3args(struct xdr_stream *xdr,
786 const struct nfs_readargs *args)
787{
788 __be32 *p;
789
790 encode_nfs_fh3(xdr, args->fh);
791
792 p = xdr_reserve_space(xdr, 8 + 4);
793 p = xdr_encode_hyper(p, args->offset);
794 *p = cpu_to_be32(args->count);
795}
796
797static int nfs3_xdr_enc_read3args(struct rpc_rqst *req, __be32 *p,
798 const struct nfs_readargs *args)
799{
800 struct xdr_stream xdr;
801
802 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
803 encode_read3args(&xdr, args);
804 prepare_reply_buffer(req, args->pages, args->pgbase,
805 args->count, NFS3_readres_sz);
806 req->rq_rcv_buf.flags |= XDRBUF_READ;
807 return 0;
808}
809
810/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700811 * Write arguments. Splice the buffer to be written into the iovec.
812 */
813static int
Al Virod61005a2006-10-19 23:28:48 -0700814nfs3_xdr_writeargs(struct rpc_rqst *req, __be32 *p, struct nfs_writeargs *args)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700815{
816 struct xdr_buf *sndbuf = &req->rq_snd_buf;
817 u32 count = args->count;
818
819 p = xdr_encode_fhandle(p, args->fh);
820 p = xdr_encode_hyper(p, args->offset);
821 *p++ = htonl(count);
822 *p++ = htonl(args->stable);
823 *p++ = htonl(count);
824 sndbuf->len = xdr_adjust_iovec(sndbuf->head, p);
825
826 /* Copy the page array */
827 xdr_encode_pages(sndbuf, args->pages, args->pgbase, count);
\"Talpey, Thomas\4f22ccc2007-09-10 13:44:58 -0400828 sndbuf->flags |= XDRBUF_WRITE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700829 return 0;
830}
831
832/*
Chuck Leverd9c407b2010-12-14 14:55:50 +0000833 * 3.3.7 WRITE3args
834 *
835 * enum stable_how {
836 * UNSTABLE = 0,
837 * DATA_SYNC = 1,
838 * FILE_SYNC = 2
839 * };
840 *
841 * struct WRITE3args {
842 * nfs_fh3 file;
843 * offset3 offset;
844 * count3 count;
845 * stable_how stable;
846 * opaque data<>;
847 * };
848 */
849static void encode_write3args(struct xdr_stream *xdr,
850 const struct nfs_writeargs *args)
851{
852 __be32 *p;
853
854 encode_nfs_fh3(xdr, args->fh);
855
856 p = xdr_reserve_space(xdr, 8 + 4 + 4 + 4);
857 p = xdr_encode_hyper(p, args->offset);
858 *p++ = cpu_to_be32(args->count);
859
860 BUG_ON(args->stable > NFS_FILE_SYNC);
861 *p++ = cpu_to_be32(args->stable);
862
863 *p = cpu_to_be32(args->count);
864 xdr_write_pages(xdr, args->pages, args->pgbase, args->count);
865}
866
867static int nfs3_xdr_enc_write3args(struct rpc_rqst *req, __be32 *p,
868 const struct nfs_writeargs *args)
869{
870 struct xdr_stream xdr;
871
872 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
873 encode_write3args(&xdr, args);
874 xdr.buf->flags |= XDRBUF_WRITE;
875 return 0;
876}
877
878/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700879 * Encode CREATE arguments
880 */
881static int
Al Virod61005a2006-10-19 23:28:48 -0700882nfs3_xdr_createargs(struct rpc_rqst *req, __be32 *p, struct nfs3_createargs *args)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883{
884 p = xdr_encode_fhandle(p, args->fh);
885 p = xdr_encode_array(p, args->name, args->len);
886
887 *p++ = htonl(args->createmode);
888 if (args->createmode == NFS3_CREATE_EXCLUSIVE) {
889 *p++ = args->verifier[0];
890 *p++ = args->verifier[1];
891 } else
892 p = xdr_encode_sattr(p, args->sattr);
893
894 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
895 return 0;
896}
897
898/*
Chuck Leverd9c407b2010-12-14 14:55:50 +0000899 * 3.3.8 CREATE3args
900 *
901 * enum createmode3 {
902 * UNCHECKED = 0,
903 * GUARDED = 1,
904 * EXCLUSIVE = 2
905 * };
906 *
907 * union createhow3 switch (createmode3 mode) {
908 * case UNCHECKED:
909 * case GUARDED:
910 * sattr3 obj_attributes;
911 * case EXCLUSIVE:
912 * createverf3 verf;
913 * };
914 *
915 * struct CREATE3args {
916 * diropargs3 where;
917 * createhow3 how;
918 * };
919 */
920static void encode_createhow3(struct xdr_stream *xdr,
921 const struct nfs3_createargs *args)
922{
923 encode_uint32(xdr, args->createmode);
924 switch (args->createmode) {
925 case NFS3_CREATE_UNCHECKED:
926 case NFS3_CREATE_GUARDED:
927 encode_sattr3(xdr, args->sattr);
928 break;
929 case NFS3_CREATE_EXCLUSIVE:
930 encode_createverf3(xdr, args->verifier);
931 break;
932 default:
933 BUG();
934 }
935}
936
937static int nfs3_xdr_enc_create3args(struct rpc_rqst *req, __be32 *p,
938 const struct nfs3_createargs *args)
939{
940 struct xdr_stream xdr;
941
942 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
943 encode_diropargs3(&xdr, args->fh, args->name, args->len);
944 encode_createhow3(&xdr, args);
945 return 0;
946}
947
948/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700949 * Encode MKDIR arguments
950 */
951static int
Al Virod61005a2006-10-19 23:28:48 -0700952nfs3_xdr_mkdirargs(struct rpc_rqst *req, __be32 *p, struct nfs3_mkdirargs *args)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700953{
954 p = xdr_encode_fhandle(p, args->fh);
955 p = xdr_encode_array(p, args->name, args->len);
956 p = xdr_encode_sattr(p, args->sattr);
957 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
958 return 0;
959}
960
961/*
Chuck Leverd9c407b2010-12-14 14:55:50 +0000962 * 3.3.9 MKDIR3args
963 *
964 * struct MKDIR3args {
965 * diropargs3 where;
966 * sattr3 attributes;
967 * };
968 */
969static int nfs3_xdr_enc_mkdir3args(struct rpc_rqst *req, __be32 *p,
970 const struct nfs3_mkdirargs *args)
971{
972 struct xdr_stream xdr;
973
974 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
975 encode_diropargs3(&xdr, args->fh, args->name, args->len);
976 encode_sattr3(&xdr, args->sattr);
977 return 0;
978}
979
980/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700981 * Encode SYMLINK arguments
982 */
983static int
Al Virod61005a2006-10-19 23:28:48 -0700984nfs3_xdr_symlinkargs(struct rpc_rqst *req, __be32 *p, struct nfs3_symlinkargs *args)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700985{
986 p = xdr_encode_fhandle(p, args->fromfh);
987 p = xdr_encode_array(p, args->fromname, args->fromlen);
988 p = xdr_encode_sattr(p, args->sattr);
Chuck Lever94a6d752006-08-22 20:06:23 -0400989 *p++ = htonl(args->pathlen);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700990 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
Chuck Lever94a6d752006-08-22 20:06:23 -0400991
992 /* Copy the page */
993 xdr_encode_pages(&req->rq_snd_buf, args->pages, 0, args->pathlen);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700994 return 0;
995}
996
997/*
Chuck Leverd9c407b2010-12-14 14:55:50 +0000998 * 3.3.10 SYMLINK3args
999 *
1000 * struct symlinkdata3 {
1001 * sattr3 symlink_attributes;
1002 * nfspath3 symlink_data;
1003 * };
1004 *
1005 * struct SYMLINK3args {
1006 * diropargs3 where;
1007 * symlinkdata3 symlink;
1008 * };
1009 */
1010static void encode_symlinkdata3(struct xdr_stream *xdr,
1011 const struct nfs3_symlinkargs *args)
1012{
1013 encode_sattr3(xdr, args->sattr);
1014 encode_nfspath3(xdr, args->pages, args->pathlen);
1015}
1016
1017static int nfs3_xdr_enc_symlink3args(struct rpc_rqst *req, __be32 *p,
1018 const struct nfs3_symlinkargs *args)
1019{
1020 struct xdr_stream xdr;
1021
1022 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1023 encode_diropargs3(&xdr, args->fromfh, args->fromname, args->fromlen);
1024 encode_symlinkdata3(&xdr, args);
1025 return 0;
1026}
1027
1028/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001029 * Encode MKNOD arguments
1030 */
1031static int
Al Virod61005a2006-10-19 23:28:48 -07001032nfs3_xdr_mknodargs(struct rpc_rqst *req, __be32 *p, struct nfs3_mknodargs *args)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001033{
1034 p = xdr_encode_fhandle(p, args->fh);
1035 p = xdr_encode_array(p, args->name, args->len);
1036 *p++ = htonl(args->type);
1037 p = xdr_encode_sattr(p, args->sattr);
1038 if (args->type == NF3CHR || args->type == NF3BLK) {
1039 *p++ = htonl(MAJOR(args->rdev));
1040 *p++ = htonl(MINOR(args->rdev));
1041 }
1042
1043 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
1044 return 0;
1045}
1046
1047/*
Chuck Leverd9c407b2010-12-14 14:55:50 +00001048 * 3.3.11 MKNOD3args
1049 *
1050 * struct devicedata3 {
1051 * sattr3 dev_attributes;
1052 * specdata3 spec;
1053 * };
1054 *
1055 * union mknoddata3 switch (ftype3 type) {
1056 * case NF3CHR:
1057 * case NF3BLK:
1058 * devicedata3 device;
1059 * case NF3SOCK:
1060 * case NF3FIFO:
1061 * sattr3 pipe_attributes;
1062 * default:
1063 * void;
1064 * };
1065 *
1066 * struct MKNOD3args {
1067 * diropargs3 where;
1068 * mknoddata3 what;
1069 * };
1070 */
1071static void encode_devicedata3(struct xdr_stream *xdr,
1072 const struct nfs3_mknodargs *args)
1073{
1074 encode_sattr3(xdr, args->sattr);
1075 encode_specdata3(xdr, args->rdev);
1076}
1077
1078static void encode_mknoddata3(struct xdr_stream *xdr,
1079 const struct nfs3_mknodargs *args)
1080{
1081 encode_ftype3(xdr, args->type);
1082 switch (args->type) {
1083 case NF3CHR:
1084 case NF3BLK:
1085 encode_devicedata3(xdr, args);
1086 break;
1087 case NF3SOCK:
1088 case NF3FIFO:
1089 encode_sattr3(xdr, args->sattr);
1090 break;
1091 case NF3REG:
1092 case NF3DIR:
1093 break;
1094 default:
1095 BUG();
1096 }
1097}
1098
1099static int nfs3_xdr_enc_mknod3args(struct rpc_rqst *req, __be32 *p,
1100 const struct nfs3_mknodargs *args)
1101{
1102 struct xdr_stream xdr;
1103
1104 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1105 encode_diropargs3(&xdr, args->fh, args->name, args->len);
1106 encode_mknoddata3(&xdr, args);
1107 return 0;
1108}
1109
1110/*
1111 * 3.3.12 REMOVE3args
1112 *
1113 * struct REMOVE3args {
1114 * diropargs3 object;
1115 * };
1116 */
1117static int nfs3_xdr_enc_remove3args(struct rpc_rqst *req, __be32 *p,
1118 const struct nfs_removeargs *args)
1119{
1120 struct xdr_stream xdr;
1121
1122 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1123 encode_diropargs3(&xdr, args->fh, args->name.name, args->name.len);
1124 return 0;
1125}
1126
1127/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001128 * Encode RENAME arguments
1129 */
1130static int
Jeff Layton920769f2010-09-17 17:30:25 -04001131nfs3_xdr_renameargs(struct rpc_rqst *req, __be32 *p, struct nfs_renameargs *args)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001132{
Jeff Layton920769f2010-09-17 17:30:25 -04001133 p = xdr_encode_fhandle(p, args->old_dir);
1134 p = xdr_encode_array(p, args->old_name->name, args->old_name->len);
1135 p = xdr_encode_fhandle(p, args->new_dir);
1136 p = xdr_encode_array(p, args->new_name->name, args->new_name->len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001137 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
1138 return 0;
1139}
1140
1141/*
Chuck Leverd9c407b2010-12-14 14:55:50 +00001142 * 3.3.14 RENAME3args
1143 *
1144 * struct RENAME3args {
1145 * diropargs3 from;
1146 * diropargs3 to;
1147 * };
1148 */
1149static int nfs3_xdr_enc_rename3args(struct rpc_rqst *req, __be32 *p,
1150 const struct nfs_renameargs *args)
1151{
1152 const struct qstr *old = args->old_name;
1153 const struct qstr *new = args->new_name;
1154 struct xdr_stream xdr;
1155
1156 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1157 encode_diropargs3(&xdr, args->old_dir, old->name, old->len);
1158 encode_diropargs3(&xdr, args->new_dir, new->name, new->len);
1159 return 0;
1160}
1161
1162/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001163 * Encode LINK arguments
1164 */
1165static int
Al Virod61005a2006-10-19 23:28:48 -07001166nfs3_xdr_linkargs(struct rpc_rqst *req, __be32 *p, struct nfs3_linkargs *args)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001167{
1168 p = xdr_encode_fhandle(p, args->fromfh);
1169 p = xdr_encode_fhandle(p, args->tofh);
1170 p = xdr_encode_array(p, args->toname, args->tolen);
1171 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
1172 return 0;
1173}
1174
1175/*
Chuck Leverd9c407b2010-12-14 14:55:50 +00001176 * 3.3.15 LINK3args
1177 *
1178 * struct LINK3args {
1179 * nfs_fh3 file;
1180 * diropargs3 link;
1181 * };
1182 */
1183static int nfs3_xdr_enc_link3args(struct rpc_rqst *req, __be32 *p,
1184 const struct nfs3_linkargs *args)
1185{
1186 struct xdr_stream xdr;
1187
1188 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1189 encode_nfs_fh3(&xdr, args->fromfh);
1190 encode_diropargs3(&xdr, args->tofh, args->toname, args->tolen);
1191 return 0;
1192}
1193
1194/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001195 * Encode arguments to readdir call
1196 */
1197static int
Al Virod61005a2006-10-19 23:28:48 -07001198nfs3_xdr_readdirargs(struct rpc_rqst *req, __be32 *p, struct nfs3_readdirargs *args)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001199{
Trond Myklebusta17c2152010-07-31 14:29:08 -04001200 struct rpc_auth *auth = req->rq_cred->cr_auth;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001201 unsigned int replen;
1202 u32 count = args->count;
1203
1204 p = xdr_encode_fhandle(p, args->fh);
1205 p = xdr_encode_hyper(p, args->cookie);
1206 *p++ = args->verf[0];
1207 *p++ = args->verf[1];
1208 if (args->plus) {
1209 /* readdirplus: need dircount + buffer size.
1210 * We just make sure we make dircount big enough */
1211 *p++ = htonl(count >> 3);
1212 }
1213 *p++ = htonl(count);
1214 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
1215
1216 /* Inline the page array */
1217 replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS3_readdirres_sz) << 2;
1218 xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, 0, count);
1219 return 0;
1220}
1221
1222/*
Chuck Leverd9c407b2010-12-14 14:55:50 +00001223 * 3.3.16 READDIR3args
1224 *
1225 * struct READDIR3args {
1226 * nfs_fh3 dir;
1227 * cookie3 cookie;
1228 * cookieverf3 cookieverf;
1229 * count3 count;
1230 * };
1231 */
1232static void encode_readdir3args(struct xdr_stream *xdr,
1233 const struct nfs3_readdirargs *args)
1234{
1235 __be32 *p;
1236
1237 encode_nfs_fh3(xdr, args->fh);
1238
1239 p = xdr_reserve_space(xdr, 8 + NFS3_COOKIEVERFSIZE + 4);
1240 p = xdr_encode_cookie3(p, args->cookie);
1241 p = xdr_encode_cookieverf3(p, args->verf);
1242 *p = cpu_to_be32(args->count);
1243}
1244
1245static int nfs3_xdr_enc_readdir3args(struct rpc_rqst *req, __be32 *p,
1246 const struct nfs3_readdirargs *args)
1247{
1248 struct xdr_stream xdr;
1249
1250 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1251 encode_readdir3args(&xdr, args);
1252 prepare_reply_buffer(req, args->pages, 0,
1253 args->count, NFS3_readdirres_sz);
1254 return 0;
1255}
1256
1257/*
1258 * 3.3.17 READDIRPLUS3args
1259 *
1260 * struct READDIRPLUS3args {
1261 * nfs_fh3 dir;
1262 * cookie3 cookie;
1263 * cookieverf3 cookieverf;
1264 * count3 dircount;
1265 * count3 maxcount;
1266 * };
1267 */
1268static void encode_readdirplus3args(struct xdr_stream *xdr,
1269 const struct nfs3_readdirargs *args)
1270{
1271 __be32 *p;
1272
1273 encode_nfs_fh3(xdr, args->fh);
1274
1275 p = xdr_reserve_space(xdr, 8 + NFS3_COOKIEVERFSIZE + 4 + 4);
1276 p = xdr_encode_cookie3(p, args->cookie);
1277 p = xdr_encode_cookieverf3(p, args->verf);
1278
1279 /*
1280 * readdirplus: need dircount + buffer size.
1281 * We just make sure we make dircount big enough
1282 */
1283 *p++ = cpu_to_be32(args->count >> 3);
1284
1285 *p = cpu_to_be32(args->count);
1286}
1287
1288static int nfs3_xdr_enc_readdirplus3args(struct rpc_rqst *req, __be32 *p,
1289 const struct nfs3_readdirargs *args)
1290{
1291 struct xdr_stream xdr;
1292
1293 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1294 encode_readdirplus3args(&xdr, args);
1295 prepare_reply_buffer(req, args->pages, 0,
1296 args->count, NFS3_readdirres_sz);
1297 return 0;
1298}
1299
1300/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001301 * Decode the result of a readdir call.
1302 * We just check for syntactical correctness.
1303 */
1304static int
Al Virod61005a2006-10-19 23:28:48 -07001305nfs3_xdr_readdirres(struct rpc_rqst *req, __be32 *p, struct nfs3_readdirres *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001306{
1307 struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
1308 struct kvec *iov = rcvbuf->head;
1309 struct page **page;
Chuck Leverc957c522007-10-26 13:31:57 -04001310 size_t hdrlen;
Bryan Schumakerafa8ccc2010-10-20 15:44:31 -04001311 u32 recvd, pglen;
Trond Myklebustac396122010-11-15 20:26:22 -05001312 int status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001313
1314 status = ntohl(*p++);
1315 /* Decode post_op_attrs */
1316 p = xdr_decode_post_op_attr(p, res->dir_attr);
1317 if (status)
Benny Halevy856dff32008-03-31 17:39:06 +03001318 return nfs_stat_to_errno(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001319 /* Decode verifier cookie */
1320 if (res->verf) {
1321 res->verf[0] = *p++;
1322 res->verf[1] = *p++;
1323 } else {
1324 p += 2;
1325 }
1326
1327 hdrlen = (u8 *) p - (u8 *) iov->iov_base;
1328 if (iov->iov_len < hdrlen) {
Chuck Leverfe82a182007-09-11 18:01:10 -04001329 dprintk("NFS: READDIR reply header overflowed:"
Chuck Leverc957c522007-10-26 13:31:57 -04001330 "length %Zu > %Zu\n", hdrlen, iov->iov_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001331 return -errno_NFSERR_IO;
1332 } else if (iov->iov_len != hdrlen) {
1333 dprintk("NFS: READDIR header is short. iovec will be shifted.\n");
1334 xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen);
1335 }
1336
1337 pglen = rcvbuf->page_len;
1338 recvd = rcvbuf->len - hdrlen;
1339 if (pglen > recvd)
1340 pglen = recvd;
1341 page = rcvbuf->pages;
Jeff Layton643f8112008-02-22 14:50:00 -05001342
Trond Myklebustac396122010-11-15 20:26:22 -05001343 return pglen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001344}
1345
Al Viro0dbb4c62006-10-19 23:28:49 -07001346__be32 *
Bryan Schumaker82f2e542010-10-21 16:33:18 -04001347nfs3_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry, struct nfs_server *server, int plus)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001348{
Bryan Schumakerbabddc72010-10-20 15:44:29 -04001349 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001350 struct nfs_entry old = *entry;
1351
Bryan Schumakerbabddc72010-10-20 15:44:29 -04001352 p = xdr_inline_decode(xdr, 4);
1353 if (unlikely(!p))
1354 goto out_overflow;
1355 if (!ntohl(*p++)) {
1356 p = xdr_inline_decode(xdr, 4);
1357 if (unlikely(!p))
1358 goto out_overflow;
1359 if (!ntohl(*p++))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001360 return ERR_PTR(-EAGAIN);
1361 entry->eof = 1;
1362 return ERR_PTR(-EBADCOOKIE);
1363 }
1364
Bryan Schumakerbabddc72010-10-20 15:44:29 -04001365 p = xdr_inline_decode(xdr, 12);
1366 if (unlikely(!p))
1367 goto out_overflow;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001368 p = xdr_decode_hyper(p, &entry->ino);
1369 entry->len = ntohl(*p++);
Bryan Schumakerbabddc72010-10-20 15:44:29 -04001370
1371 p = xdr_inline_decode(xdr, entry->len + 8);
1372 if (unlikely(!p))
1373 goto out_overflow;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001374 entry->name = (const char *) p;
1375 p += XDR_QUADLEN(entry->len);
1376 entry->prev_cookie = entry->cookie;
1377 p = xdr_decode_hyper(p, &entry->cookie);
1378
Trond Myklebust0b26a0b2010-11-20 14:26:44 -05001379 entry->d_type = DT_UNKNOWN;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001380 if (plus) {
1381 entry->fattr->valid = 0;
Bryan Schumakerbabddc72010-10-20 15:44:29 -04001382 p = xdr_decode_post_op_attr_stream(xdr, entry->fattr);
1383 if (IS_ERR(p))
1384 goto out_overflow_exit;
Trond Myklebust0b26a0b2010-11-20 14:26:44 -05001385 entry->d_type = nfs_umode_to_dtype(entry->fattr->mode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001386 /* In fact, a post_op_fh3: */
Bryan Schumakerbabddc72010-10-20 15:44:29 -04001387 p = xdr_inline_decode(xdr, 4);
1388 if (unlikely(!p))
1389 goto out_overflow;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001390 if (*p++) {
Bryan Schumakerbabddc72010-10-20 15:44:29 -04001391 p = xdr_decode_fhandle_stream(xdr, entry->fh);
1392 if (IS_ERR(p))
1393 goto out_overflow_exit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001394 /* Ugh -- server reply was truncated */
1395 if (p == NULL) {
1396 dprintk("NFS: FH truncated\n");
1397 *entry = old;
1398 return ERR_PTR(-EAGAIN);
1399 }
1400 } else
1401 memset((u8*)(entry->fh), 0, sizeof(*entry->fh));
1402 }
1403
Bryan Schumakerbabddc72010-10-20 15:44:29 -04001404 p = xdr_inline_peek(xdr, 8);
1405 if (p != NULL)
1406 entry->eof = !p[0] && p[1];
1407 else
1408 entry->eof = 0;
1409
Linus Torvalds1da177e2005-04-16 15:20:36 -07001410 return p;
Bryan Schumakerbabddc72010-10-20 15:44:29 -04001411
1412out_overflow:
1413 print_overflow_msg(__func__, xdr);
1414out_overflow_exit:
Trond Myklebust463a3762010-11-20 12:22:20 -05001415 return ERR_PTR(-EAGAIN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001416}
1417
1418/*
1419 * Encode COMMIT arguments
1420 */
1421static int
Al Virod61005a2006-10-19 23:28:48 -07001422nfs3_xdr_commitargs(struct rpc_rqst *req, __be32 *p, struct nfs_writeargs *args)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001423{
1424 p = xdr_encode_fhandle(p, args->fh);
1425 p = xdr_encode_hyper(p, args->offset);
1426 *p++ = htonl(args->count);
1427 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
1428 return 0;
1429}
1430
Chuck Leverd9c407b2010-12-14 14:55:50 +00001431/*
1432 * 3.3.21 COMMIT3args
1433 *
1434 * struct COMMIT3args {
1435 * nfs_fh3 file;
1436 * offset3 offset;
1437 * count3 count;
1438 * };
1439 */
1440static void encode_commit3args(struct xdr_stream *xdr,
1441 const struct nfs_writeargs *args)
1442{
1443 __be32 *p;
1444
1445 encode_nfs_fh3(xdr, args->fh);
1446
1447 p = xdr_reserve_space(xdr, 8 + 4);
1448 p = xdr_encode_hyper(p, args->offset);
1449 *p = cpu_to_be32(args->count);
1450}
1451
1452static int nfs3_xdr_enc_commit3args(struct rpc_rqst *req, __be32 *p,
1453 const struct nfs_writeargs *args)
1454{
1455 struct xdr_stream xdr;
1456
1457 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1458 encode_commit3args(&xdr, args);
1459 return 0;
1460}
1461
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +00001462#ifdef CONFIG_NFS_V3_ACL
1463/*
1464 * Encode GETACL arguments
1465 */
1466static int
Al Virod61005a2006-10-19 23:28:48 -07001467nfs3_xdr_getaclargs(struct rpc_rqst *req, __be32 *p,
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +00001468 struct nfs3_getaclargs *args)
1469{
Trond Myklebusta17c2152010-07-31 14:29:08 -04001470 struct rpc_auth *auth = req->rq_cred->cr_auth;
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +00001471 unsigned int replen;
1472
1473 p = xdr_encode_fhandle(p, args->fh);
1474 *p++ = htonl(args->mask);
1475 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
1476
1477 if (args->mask & (NFS_ACL | NFS_DFACL)) {
1478 /* Inline the page array */
1479 replen = (RPC_REPHDRSIZE + auth->au_rslack +
1480 ACL3_getaclres_sz) << 2;
1481 xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, 0,
1482 NFSACL_MAXPAGES << PAGE_SHIFT);
1483 }
1484 return 0;
1485}
1486
Chuck Leverd9c407b2010-12-14 14:55:50 +00001487static int nfs3_xdr_enc_getacl3args(struct rpc_rqst *req, __be32 *p,
1488 const struct nfs3_getaclargs *args)
1489{
1490 struct xdr_stream xdr;
1491
1492 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1493 encode_nfs_fh3(&xdr, args->fh);
1494 encode_uint32(&xdr, args->mask);
1495 if (args->mask & (NFS_ACL | NFS_DFACL))
1496 prepare_reply_buffer(req, args->pages, 0,
1497 NFSACL_MAXPAGES << PAGE_SHIFT,
1498 ACL3_getaclres_sz);
1499 return 0;
1500}
1501
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +00001502/*
1503 * Encode SETACL arguments
1504 */
1505static int
Al Virod61005a2006-10-19 23:28:48 -07001506nfs3_xdr_setaclargs(struct rpc_rqst *req, __be32 *p,
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +00001507 struct nfs3_setaclargs *args)
1508{
1509 struct xdr_buf *buf = &req->rq_snd_buf;
Trond Myklebustae461412009-03-10 20:33:18 -04001510 unsigned int base;
1511 int err;
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +00001512
1513 p = xdr_encode_fhandle(p, NFS_FH(args->inode));
1514 *p++ = htonl(args->mask);
Trond Myklebustae461412009-03-10 20:33:18 -04001515 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
1516 base = req->rq_slen;
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +00001517
Trond Myklebustae461412009-03-10 20:33:18 -04001518 if (args->npages != 0)
1519 xdr_encode_pages(buf, args->pages, 0, args->len);
1520 else
Trond Myklebust83404372009-04-20 14:58:35 -04001521 req->rq_slen = xdr_adjust_iovec(req->rq_svec,
1522 p + XDR_QUADLEN(args->len));
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +00001523
1524 err = nfsacl_encode(buf, base, args->inode,
1525 (args->mask & NFS_ACL) ?
1526 args->acl_access : NULL, 1, 0);
1527 if (err > 0)
1528 err = nfsacl_encode(buf, base + err, args->inode,
1529 (args->mask & NFS_DFACL) ?
1530 args->acl_default : NULL, 1,
1531 NFS_ACL_DEFAULT);
1532 return (err > 0) ? 0 : err;
1533}
Chuck Leverd9c407b2010-12-14 14:55:50 +00001534
1535static int nfs3_xdr_enc_setacl3args(struct rpc_rqst *req, __be32 *p,
1536 const struct nfs3_setaclargs *args)
1537{
1538 struct xdr_stream xdr;
1539 unsigned int base;
1540 int error;
1541
1542 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1543 encode_nfs_fh3(&xdr, NFS_FH(args->inode));
1544 encode_uint32(&xdr, args->mask);
1545 if (args->npages != 0)
1546 xdr_write_pages(&xdr, args->pages, 0, args->len);
1547
1548 base = req->rq_slen;
1549 error = nfsacl_encode(xdr.buf, base, args->inode,
1550 (args->mask & NFS_ACL) ?
1551 args->acl_access : NULL, 1, 0);
1552 BUG_ON(error < 0);
1553 error = nfsacl_encode(xdr.buf, base + error, args->inode,
1554 (args->mask & NFS_DFACL) ?
1555 args->acl_default : NULL, 1,
1556 NFS_ACL_DEFAULT);
1557 BUG_ON(error < 0);
1558 return 0;
1559}
1560
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +00001561#endif /* CONFIG_NFS_V3_ACL */
1562
Linus Torvalds1da177e2005-04-16 15:20:36 -07001563/*
1564 * NFS XDR decode functions
1565 */
1566
1567/*
1568 * Decode attrstat reply.
1569 */
1570static int
Al Virod61005a2006-10-19 23:28:48 -07001571nfs3_xdr_attrstat(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001572{
1573 int status;
1574
1575 if ((status = ntohl(*p++)))
Benny Halevy856dff32008-03-31 17:39:06 +03001576 return nfs_stat_to_errno(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001577 xdr_decode_fattr(p, fattr);
1578 return 0;
1579}
1580
1581/*
1582 * Decode status+wcc_data reply
1583 * SATTR, REMOVE, RMDIR
1584 */
1585static int
Al Virod61005a2006-10-19 23:28:48 -07001586nfs3_xdr_wccstat(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001587{
1588 int status;
1589
1590 if ((status = ntohl(*p++)))
Benny Halevy856dff32008-03-31 17:39:06 +03001591 status = nfs_stat_to_errno(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001592 xdr_decode_wcc_data(p, fattr);
1593 return status;
1594}
1595
Trond Myklebust4fdc17b2007-07-14 15:39:57 -04001596static int
1597nfs3_xdr_removeres(struct rpc_rqst *req, __be32 *p, struct nfs_removeres *res)
1598{
Trond Myklebustd3468902010-04-16 16:22:50 -04001599 return nfs3_xdr_wccstat(req, p, res->dir_attr);
Trond Myklebust4fdc17b2007-07-14 15:39:57 -04001600}
1601
Linus Torvalds1da177e2005-04-16 15:20:36 -07001602/*
1603 * Decode LOOKUP reply
1604 */
1605static int
Al Virod61005a2006-10-19 23:28:48 -07001606nfs3_xdr_lookupres(struct rpc_rqst *req, __be32 *p, struct nfs3_diropres *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001607{
1608 int status;
1609
1610 if ((status = ntohl(*p++))) {
Benny Halevy856dff32008-03-31 17:39:06 +03001611 status = nfs_stat_to_errno(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001612 } else {
1613 if (!(p = xdr_decode_fhandle(p, res->fh)))
1614 return -errno_NFSERR_IO;
1615 p = xdr_decode_post_op_attr(p, res->fattr);
1616 }
1617 xdr_decode_post_op_attr(p, res->dir_attr);
1618 return status;
1619}
1620
1621/*
1622 * Decode ACCESS reply
1623 */
1624static int
Al Virod61005a2006-10-19 23:28:48 -07001625nfs3_xdr_accessres(struct rpc_rqst *req, __be32 *p, struct nfs3_accessres *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001626{
1627 int status = ntohl(*p++);
1628
1629 p = xdr_decode_post_op_attr(p, res->fattr);
1630 if (status)
Benny Halevy856dff32008-03-31 17:39:06 +03001631 return nfs_stat_to_errno(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001632 res->access = ntohl(*p++);
1633 return 0;
1634}
1635
1636static int
Al Virod61005a2006-10-19 23:28:48 -07001637nfs3_xdr_readlinkargs(struct rpc_rqst *req, __be32 *p, struct nfs3_readlinkargs *args)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001638{
Trond Myklebusta17c2152010-07-31 14:29:08 -04001639 struct rpc_auth *auth = req->rq_cred->cr_auth;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001640 unsigned int replen;
1641
1642 p = xdr_encode_fhandle(p, args->fh);
1643 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
1644
1645 /* Inline the page array */
1646 replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS3_readlinkres_sz) << 2;
1647 xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, args->pgbase, args->pglen);
1648 return 0;
1649}
1650
1651/*
1652 * Decode READLINK reply
1653 */
1654static int
Al Virod61005a2006-10-19 23:28:48 -07001655nfs3_xdr_readlinkres(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001656{
1657 struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
1658 struct kvec *iov = rcvbuf->head;
Chuck Leverc957c522007-10-26 13:31:57 -04001659 size_t hdrlen;
1660 u32 len, recvd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001661 int status;
1662
1663 status = ntohl(*p++);
1664 p = xdr_decode_post_op_attr(p, fattr);
1665
1666 if (status != 0)
Benny Halevy856dff32008-03-31 17:39:06 +03001667 return nfs_stat_to_errno(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001668
1669 /* Convert length of symlink */
1670 len = ntohl(*p++);
Chuck Leverc957c522007-10-26 13:31:57 -04001671 if (len >= rcvbuf->page_len) {
Chuck Leverfe82a182007-09-11 18:01:10 -04001672 dprintk("nfs: server returned giant symlink!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001673 return -ENAMETOOLONG;
1674 }
1675
1676 hdrlen = (u8 *) p - (u8 *) iov->iov_base;
1677 if (iov->iov_len < hdrlen) {
Chuck Leverfe82a182007-09-11 18:01:10 -04001678 dprintk("NFS: READLINK reply header overflowed:"
Chuck Leverc957c522007-10-26 13:31:57 -04001679 "length %Zu > %Zu\n", hdrlen, iov->iov_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001680 return -errno_NFSERR_IO;
1681 } else if (iov->iov_len != hdrlen) {
Chuck Leverfe82a182007-09-11 18:01:10 -04001682 dprintk("NFS: READLINK header is short. "
1683 "iovec will be shifted.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001684 xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen);
1685 }
1686 recvd = req->rq_rcv_buf.len - hdrlen;
1687 if (recvd < len) {
Chuck Leverfe82a182007-09-11 18:01:10 -04001688 dprintk("NFS: server cheating in readlink reply: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001689 "count %u > recvd %u\n", len, recvd);
1690 return -EIO;
1691 }
1692
Chuck Leverb4687da2010-09-21 16:55:48 -04001693 xdr_terminate_string(rcvbuf, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001694 return 0;
1695}
1696
1697/*
1698 * Decode READ reply
1699 */
1700static int
Al Virod61005a2006-10-19 23:28:48 -07001701nfs3_xdr_readres(struct rpc_rqst *req, __be32 *p, struct nfs_readres *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001702{
1703 struct kvec *iov = req->rq_rcv_buf.head;
Chuck Leverc957c522007-10-26 13:31:57 -04001704 size_t hdrlen;
1705 u32 count, ocount, recvd;
1706 int status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001707
1708 status = ntohl(*p++);
1709 p = xdr_decode_post_op_attr(p, res->fattr);
1710
1711 if (status != 0)
Benny Halevy856dff32008-03-31 17:39:06 +03001712 return nfs_stat_to_errno(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001713
Chuck Leverc957c522007-10-26 13:31:57 -04001714 /* Decode reply count and EOF flag. NFSv3 is somewhat redundant
Linus Torvalds1da177e2005-04-16 15:20:36 -07001715 * in that it puts the count both in the res struct and in the
1716 * opaque data count. */
1717 count = ntohl(*p++);
1718 res->eof = ntohl(*p++);
1719 ocount = ntohl(*p++);
1720
1721 if (ocount != count) {
Chuck Leverfe82a182007-09-11 18:01:10 -04001722 dprintk("NFS: READ count doesn't match RPC opaque count.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001723 return -errno_NFSERR_IO;
1724 }
1725
1726 hdrlen = (u8 *) p - (u8 *) iov->iov_base;
1727 if (iov->iov_len < hdrlen) {
Chuck Leverfe82a182007-09-11 18:01:10 -04001728 dprintk("NFS: READ reply header overflowed:"
Chuck Leverc957c522007-10-26 13:31:57 -04001729 "length %Zu > %Zu\n", hdrlen, iov->iov_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001730 return -errno_NFSERR_IO;
1731 } else if (iov->iov_len != hdrlen) {
1732 dprintk("NFS: READ header is short. iovec will be shifted.\n");
1733 xdr_shift_buf(&req->rq_rcv_buf, iov->iov_len - hdrlen);
1734 }
1735
1736 recvd = req->rq_rcv_buf.len - hdrlen;
1737 if (count > recvd) {
Chuck Leverfe82a182007-09-11 18:01:10 -04001738 dprintk("NFS: server cheating in read reply: "
Chuck Leverc957c522007-10-26 13:31:57 -04001739 "count %u > recvd %u\n", count, recvd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001740 count = recvd;
1741 res->eof = 0;
1742 }
1743
1744 if (count < res->count)
1745 res->count = count;
1746
1747 return count;
1748}
1749
1750/*
1751 * Decode WRITE response
1752 */
1753static int
Al Virod61005a2006-10-19 23:28:48 -07001754nfs3_xdr_writeres(struct rpc_rqst *req, __be32 *p, struct nfs_writeres *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001755{
1756 int status;
1757
1758 status = ntohl(*p++);
1759 p = xdr_decode_wcc_data(p, res->fattr);
1760
1761 if (status != 0)
Benny Halevy856dff32008-03-31 17:39:06 +03001762 return nfs_stat_to_errno(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001763
1764 res->count = ntohl(*p++);
1765 res->verf->committed = (enum nfs3_stable_how)ntohl(*p++);
1766 res->verf->verifier[0] = *p++;
1767 res->verf->verifier[1] = *p++;
1768
1769 return res->count;
1770}
1771
1772/*
1773 * Decode a CREATE response
1774 */
1775static int
Al Virod61005a2006-10-19 23:28:48 -07001776nfs3_xdr_createres(struct rpc_rqst *req, __be32 *p, struct nfs3_diropres *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001777{
1778 int status;
1779
1780 status = ntohl(*p++);
1781 if (status == 0) {
1782 if (*p++) {
1783 if (!(p = xdr_decode_fhandle(p, res->fh)))
1784 return -errno_NFSERR_IO;
1785 p = xdr_decode_post_op_attr(p, res->fattr);
1786 } else {
1787 memset(res->fh, 0, sizeof(*res->fh));
1788 /* Do decode post_op_attr but set it to NULL */
1789 p = xdr_decode_post_op_attr(p, res->fattr);
1790 res->fattr->valid = 0;
1791 }
1792 } else {
Benny Halevy856dff32008-03-31 17:39:06 +03001793 status = nfs_stat_to_errno(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001794 }
1795 p = xdr_decode_wcc_data(p, res->dir_attr);
1796 return status;
1797}
1798
1799/*
1800 * Decode RENAME reply
1801 */
1802static int
Jeff Laytone8582a82010-09-17 17:31:06 -04001803nfs3_xdr_renameres(struct rpc_rqst *req, __be32 *p, struct nfs_renameres *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001804{
1805 int status;
1806
1807 if ((status = ntohl(*p++)) != 0)
Benny Halevy856dff32008-03-31 17:39:06 +03001808 status = nfs_stat_to_errno(status);
Jeff Laytone8582a82010-09-17 17:31:06 -04001809 p = xdr_decode_wcc_data(p, res->old_fattr);
1810 p = xdr_decode_wcc_data(p, res->new_fattr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001811 return status;
1812}
1813
1814/*
1815 * Decode LINK reply
1816 */
1817static int
Al Virod61005a2006-10-19 23:28:48 -07001818nfs3_xdr_linkres(struct rpc_rqst *req, __be32 *p, struct nfs3_linkres *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001819{
1820 int status;
1821
1822 if ((status = ntohl(*p++)) != 0)
Benny Halevy856dff32008-03-31 17:39:06 +03001823 status = nfs_stat_to_errno(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001824 p = xdr_decode_post_op_attr(p, res->fattr);
1825 p = xdr_decode_wcc_data(p, res->dir_attr);
1826 return status;
1827}
1828
1829/*
1830 * Decode FSSTAT reply
1831 */
1832static int
Al Virod61005a2006-10-19 23:28:48 -07001833nfs3_xdr_fsstatres(struct rpc_rqst *req, __be32 *p, struct nfs_fsstat *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001834{
1835 int status;
1836
1837 status = ntohl(*p++);
1838
1839 p = xdr_decode_post_op_attr(p, res->fattr);
1840 if (status != 0)
Benny Halevy856dff32008-03-31 17:39:06 +03001841 return nfs_stat_to_errno(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001842
1843 p = xdr_decode_hyper(p, &res->tbytes);
1844 p = xdr_decode_hyper(p, &res->fbytes);
1845 p = xdr_decode_hyper(p, &res->abytes);
1846 p = xdr_decode_hyper(p, &res->tfiles);
1847 p = xdr_decode_hyper(p, &res->ffiles);
1848 p = xdr_decode_hyper(p, &res->afiles);
1849
1850 /* ignore invarsec */
1851 return 0;
1852}
1853
1854/*
1855 * Decode FSINFO reply
1856 */
1857static int
Al Virod61005a2006-10-19 23:28:48 -07001858nfs3_xdr_fsinfores(struct rpc_rqst *req, __be32 *p, struct nfs_fsinfo *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001859{
1860 int status;
1861
1862 status = ntohl(*p++);
1863
1864 p = xdr_decode_post_op_attr(p, res->fattr);
1865 if (status != 0)
Benny Halevy856dff32008-03-31 17:39:06 +03001866 return nfs_stat_to_errno(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001867
1868 res->rtmax = ntohl(*p++);
1869 res->rtpref = ntohl(*p++);
1870 res->rtmult = ntohl(*p++);
1871 res->wtmax = ntohl(*p++);
1872 res->wtpref = ntohl(*p++);
1873 res->wtmult = ntohl(*p++);
1874 res->dtpref = ntohl(*p++);
1875 p = xdr_decode_hyper(p, &res->maxfilesize);
Ricardo Labiaga6b967242010-10-12 16:30:05 -07001876 p = xdr_decode_time3(p, &res->time_delta);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001877
Ricardo Labiaga6b967242010-10-12 16:30:05 -07001878 /* ignore properties */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001879 res->lease_time = 0;
1880 return 0;
1881}
1882
1883/*
1884 * Decode PATHCONF reply
1885 */
1886static int
Al Virod61005a2006-10-19 23:28:48 -07001887nfs3_xdr_pathconfres(struct rpc_rqst *req, __be32 *p, struct nfs_pathconf *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001888{
1889 int status;
1890
1891 status = ntohl(*p++);
1892
1893 p = xdr_decode_post_op_attr(p, res->fattr);
1894 if (status != 0)
Benny Halevy856dff32008-03-31 17:39:06 +03001895 return nfs_stat_to_errno(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001896 res->max_link = ntohl(*p++);
1897 res->max_namelen = ntohl(*p++);
1898
1899 /* ignore remaining fields */
1900 return 0;
1901}
1902
1903/*
1904 * Decode COMMIT reply
1905 */
1906static int
Al Virod61005a2006-10-19 23:28:48 -07001907nfs3_xdr_commitres(struct rpc_rqst *req, __be32 *p, struct nfs_writeres *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001908{
1909 int status;
1910
1911 status = ntohl(*p++);
1912 p = xdr_decode_wcc_data(p, res->fattr);
1913 if (status != 0)
Benny Halevy856dff32008-03-31 17:39:06 +03001914 return nfs_stat_to_errno(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001915
1916 res->verf->verifier[0] = *p++;
1917 res->verf->verifier[1] = *p++;
1918 return 0;
1919}
1920
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +00001921#ifdef CONFIG_NFS_V3_ACL
1922/*
1923 * Decode GETACL reply
1924 */
1925static int
Al Virod61005a2006-10-19 23:28:48 -07001926nfs3_xdr_getaclres(struct rpc_rqst *req, __be32 *p,
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +00001927 struct nfs3_getaclres *res)
1928{
1929 struct xdr_buf *buf = &req->rq_rcv_buf;
1930 int status = ntohl(*p++);
1931 struct posix_acl **acl;
1932 unsigned int *aclcnt;
1933 int err, base;
1934
1935 if (status != 0)
Benny Halevy856dff32008-03-31 17:39:06 +03001936 return nfs_stat_to_errno(status);
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +00001937 p = xdr_decode_post_op_attr(p, res->fattr);
1938 res->mask = ntohl(*p++);
1939 if (res->mask & ~(NFS_ACL|NFS_ACLCNT|NFS_DFACL|NFS_DFACLCNT))
1940 return -EINVAL;
1941 base = (char *)p - (char *)req->rq_rcv_buf.head->iov_base;
1942
1943 acl = (res->mask & NFS_ACL) ? &res->acl_access : NULL;
1944 aclcnt = (res->mask & NFS_ACLCNT) ? &res->acl_access_count : NULL;
1945 err = nfsacl_decode(buf, base, aclcnt, acl);
1946
1947 acl = (res->mask & NFS_DFACL) ? &res->acl_default : NULL;
1948 aclcnt = (res->mask & NFS_DFACLCNT) ? &res->acl_default_count : NULL;
1949 if (err > 0)
1950 err = nfsacl_decode(buf, base + err, aclcnt, acl);
1951 return (err > 0) ? 0 : err;
1952}
1953
1954/*
1955 * Decode setacl reply.
1956 */
1957static int
Al Virod61005a2006-10-19 23:28:48 -07001958nfs3_xdr_setaclres(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +00001959{
1960 int status = ntohl(*p++);
1961
1962 if (status)
Benny Halevy856dff32008-03-31 17:39:06 +03001963 return nfs_stat_to_errno(status);
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +00001964 xdr_decode_post_op_attr(p, fattr);
1965 return 0;
1966}
1967#endif /* CONFIG_NFS_V3_ACL */
1968
Linus Torvalds1da177e2005-04-16 15:20:36 -07001969#define PROC(proc, argtype, restype, timer) \
1970[NFS3PROC_##proc] = { \
1971 .p_proc = NFS3PROC_##proc, \
1972 .p_encode = (kxdrproc_t) nfs3_xdr_##argtype, \
1973 .p_decode = (kxdrproc_t) nfs3_xdr_##restype, \
Chuck Lever2bea90d2007-03-29 16:47:53 -04001974 .p_arglen = NFS3_##argtype##_sz, \
1975 .p_replen = NFS3_##restype##_sz, \
Chuck Levercc0175c2006-03-20 13:44:22 -05001976 .p_timer = timer, \
1977 .p_statidx = NFS3PROC_##proc, \
1978 .p_name = #proc, \
Linus Torvalds1da177e2005-04-16 15:20:36 -07001979 }
1980
1981struct rpc_procinfo nfs3_procedures[] = {
1982 PROC(GETATTR, fhandle, attrstat, 1),
1983 PROC(SETATTR, sattrargs, wccstat, 0),
1984 PROC(LOOKUP, diropargs, lookupres, 2),
1985 PROC(ACCESS, accessargs, accessres, 1),
1986 PROC(READLINK, readlinkargs, readlinkres, 3),
1987 PROC(READ, readargs, readres, 3),
1988 PROC(WRITE, writeargs, writeres, 4),
1989 PROC(CREATE, createargs, createres, 0),
1990 PROC(MKDIR, mkdirargs, createres, 0),
1991 PROC(SYMLINK, symlinkargs, createres, 0),
1992 PROC(MKNOD, mknodargs, createres, 0),
Trond Myklebust4fdc17b2007-07-14 15:39:57 -04001993 PROC(REMOVE, removeargs, removeres, 0),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001994 PROC(RMDIR, diropargs, wccstat, 0),
1995 PROC(RENAME, renameargs, renameres, 0),
1996 PROC(LINK, linkargs, linkres, 0),
1997 PROC(READDIR, readdirargs, readdirres, 3),
1998 PROC(READDIRPLUS, readdirargs, readdirres, 3),
1999 PROC(FSSTAT, fhandle, fsstatres, 0),
2000 PROC(FSINFO, fhandle, fsinfores, 0),
2001 PROC(PATHCONF, fhandle, pathconfres, 0),
2002 PROC(COMMIT, commitargs, commitres, 5),
2003};
2004
2005struct rpc_version nfs_version3 = {
2006 .number = 3,
Tobias Klausere8c96f82006-03-24 03:15:34 -08002007 .nrprocs = ARRAY_SIZE(nfs3_procedures),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002008 .procs = nfs3_procedures
2009};
2010
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +00002011#ifdef CONFIG_NFS_V3_ACL
2012static struct rpc_procinfo nfs3_acl_procedures[] = {
2013 [ACLPROC3_GETACL] = {
2014 .p_proc = ACLPROC3_GETACL,
2015 .p_encode = (kxdrproc_t) nfs3_xdr_getaclargs,
2016 .p_decode = (kxdrproc_t) nfs3_xdr_getaclres,
Chuck Lever2bea90d2007-03-29 16:47:53 -04002017 .p_arglen = ACL3_getaclargs_sz,
2018 .p_replen = ACL3_getaclres_sz,
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +00002019 .p_timer = 1,
Chuck Levercc0175c2006-03-20 13:44:22 -05002020 .p_name = "GETACL",
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +00002021 },
2022 [ACLPROC3_SETACL] = {
2023 .p_proc = ACLPROC3_SETACL,
2024 .p_encode = (kxdrproc_t) nfs3_xdr_setaclargs,
2025 .p_decode = (kxdrproc_t) nfs3_xdr_setaclres,
Chuck Lever2bea90d2007-03-29 16:47:53 -04002026 .p_arglen = ACL3_setaclargs_sz,
2027 .p_replen = ACL3_setaclres_sz,
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +00002028 .p_timer = 0,
Chuck Levercc0175c2006-03-20 13:44:22 -05002029 .p_name = "SETACL",
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +00002030 },
2031};
2032
2033struct rpc_version nfsacl_version3 = {
2034 .number = 3,
2035 .nrprocs = sizeof(nfs3_acl_procedures)/
2036 sizeof(nfs3_acl_procedures[0]),
2037 .procs = nfs3_acl_procedures,
2038};
2039#endif /* CONFIG_NFS_V3_ACL */