blob: 0f07c6d55131223e2fa7aa615013dc1256c2dfae [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
107/*
Chuck Leverd9c407b2010-12-14 14:55:50 +0000108 * While encoding arguments, set up the reply buffer in advance to
109 * receive reply data directly into the page cache.
110 */
111static void prepare_reply_buffer(struct rpc_rqst *req, struct page **pages,
112 unsigned int base, unsigned int len,
113 unsigned int bufsize)
114{
115 struct rpc_auth *auth = req->rq_cred->cr_auth;
116 unsigned int replen;
117
118 replen = RPC_REPHDRSIZE + auth->au_rslack + bufsize;
119 xdr_inline_pages(&req->rq_rcv_buf, replen << 2, pages, base, len);
120}
121
Chuck Levere4f93232010-12-14 14:56:30 +0000122/*
123 * Handle decode buffer overflows out-of-line.
124 */
125static void print_overflow_msg(const char *func, const struct xdr_stream *xdr)
126{
127 dprintk("NFS: %s prematurely hit the end of our receive buffer. "
128 "Remaining buffer length is %tu words.\n",
129 func, xdr->end - xdr->p);
130}
131
Chuck Leverd9c407b2010-12-14 14:55:50 +0000132
133/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700134 * Common NFS XDR functions as inlines
135 */
Al Virod61005a2006-10-19 23:28:48 -0700136static inline __be32 *
Al Virod61005a2006-10-19 23:28:48 -0700137xdr_decode_fhandle(__be32 *p, struct nfs_fh *fh)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700138{
139 if ((fh->size = ntohl(*p++)) <= NFS3_FHSIZE) {
140 memcpy(fh->data, p, fh->size);
141 return p + XDR_QUADLEN(fh->size);
142 }
143 return NULL;
144}
145
Bryan Schumakerbabddc72010-10-20 15:44:29 -0400146static inline __be32 *
147xdr_decode_fhandle_stream(struct xdr_stream *xdr, struct nfs_fh *fh)
148{
149 __be32 *p;
150 p = xdr_inline_decode(xdr, 4);
151 if (unlikely(!p))
152 goto out_overflow;
153 fh->size = ntohl(*p++);
154
155 if (fh->size <= NFS3_FHSIZE) {
156 p = xdr_inline_decode(xdr, fh->size);
157 if (unlikely(!p))
158 goto out_overflow;
159 memcpy(fh->data, p, fh->size);
160 return p + XDR_QUADLEN(fh->size);
161 }
162 return NULL;
163
164out_overflow:
165 print_overflow_msg(__func__, xdr);
166 return ERR_PTR(-EIO);
167}
168
Linus Torvalds1da177e2005-04-16 15:20:36 -0700169/*
170 * Encode/decode time.
171 */
Al Virod61005a2006-10-19 23:28:48 -0700172static inline __be32 *
Al Virod61005a2006-10-19 23:28:48 -0700173xdr_decode_time3(__be32 *p, struct timespec *timep)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700174{
175 timep->tv_sec = ntohl(*p++);
176 timep->tv_nsec = ntohl(*p++);
177 return p;
178}
179
Al Virod61005a2006-10-19 23:28:48 -0700180static __be32 *
181xdr_decode_fattr(__be32 *p, struct nfs_fattr *fattr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700182{
183 unsigned int type, major, minor;
Trond Myklebustbca79472009-03-11 14:10:26 -0400184 umode_t fmode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700185
186 type = ntohl(*p++);
Trond Myklebustbca79472009-03-11 14:10:26 -0400187 if (type > NF3FIFO)
188 type = NF3NON;
189 fmode = nfs_type2fmt[type];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700190 fattr->mode = (ntohl(*p++) & ~S_IFMT) | fmode;
191 fattr->nlink = ntohl(*p++);
192 fattr->uid = ntohl(*p++);
193 fattr->gid = ntohl(*p++);
194 p = xdr_decode_hyper(p, &fattr->size);
195 p = xdr_decode_hyper(p, &fattr->du.nfs3.used);
196
197 /* Turn remote device info into Linux-specific dev_t */
198 major = ntohl(*p++);
199 minor = ntohl(*p++);
200 fattr->rdev = MKDEV(major, minor);
201 if (MAJOR(fattr->rdev) != major || MINOR(fattr->rdev) != minor)
202 fattr->rdev = 0;
203
Trond Myklebust8b4bdcf2006-06-09 09:34:19 -0400204 p = xdr_decode_hyper(p, &fattr->fsid.major);
205 fattr->fsid.minor = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700206 p = xdr_decode_hyper(p, &fattr->fileid);
207 p = xdr_decode_time3(p, &fattr->atime);
208 p = xdr_decode_time3(p, &fattr->mtime);
209 p = xdr_decode_time3(p, &fattr->ctime);
210
211 /* Update the mode bits */
Trond Myklebust9e6e70f2009-03-11 14:10:24 -0400212 fattr->valid |= NFS_ATTR_FATTR_V3;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700213 return p;
214}
215
Al Virod61005a2006-10-19 23:28:48 -0700216static inline __be32 *
Al Virod61005a2006-10-19 23:28:48 -0700217xdr_decode_wcc_attr(__be32 *p, struct nfs_fattr *fattr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700218{
219 p = xdr_decode_hyper(p, &fattr->pre_size);
220 p = xdr_decode_time3(p, &fattr->pre_mtime);
221 p = xdr_decode_time3(p, &fattr->pre_ctime);
Trond Myklebust9e6e70f2009-03-11 14:10:24 -0400222 fattr->valid |= NFS_ATTR_FATTR_PRESIZE
223 | NFS_ATTR_FATTR_PREMTIME
224 | NFS_ATTR_FATTR_PRECTIME;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700225 return p;
226}
227
Al Virod61005a2006-10-19 23:28:48 -0700228static inline __be32 *
229xdr_decode_post_op_attr(__be32 *p, struct nfs_fattr *fattr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700230{
231 if (*p++)
232 p = xdr_decode_fattr(p, fattr);
233 return p;
234}
235
Al Virod61005a2006-10-19 23:28:48 -0700236static inline __be32 *
Bryan Schumakerbabddc72010-10-20 15:44:29 -0400237xdr_decode_post_op_attr_stream(struct xdr_stream *xdr, struct nfs_fattr *fattr)
238{
239 __be32 *p;
240
241 p = xdr_inline_decode(xdr, 4);
242 if (unlikely(!p))
243 goto out_overflow;
244 if (ntohl(*p++)) {
245 p = xdr_inline_decode(xdr, 84);
246 if (unlikely(!p))
247 goto out_overflow;
248 p = xdr_decode_fattr(p, fattr);
249 }
250 return p;
251out_overflow:
252 print_overflow_msg(__func__, xdr);
253 return ERR_PTR(-EIO);
254}
255
256static inline __be32 *
Al Virod61005a2006-10-19 23:28:48 -0700257xdr_decode_pre_op_attr(__be32 *p, struct nfs_fattr *fattr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258{
259 if (*p++)
260 return xdr_decode_wcc_attr(p, fattr);
261 return p;
262}
263
264
Al Virod61005a2006-10-19 23:28:48 -0700265static inline __be32 *
266xdr_decode_wcc_data(__be32 *p, struct nfs_fattr *fattr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700267{
268 p = xdr_decode_pre_op_attr(p, fattr);
269 return xdr_decode_post_op_attr(p, fattr);
270}
271
Chuck Leverd9c407b2010-12-14 14:55:50 +0000272
273/*
274 * Encode/decode NFSv3 basic data types
275 *
276 * Basic NFSv3 data types are defined in section 2.5 of RFC 1813:
277 * "NFS Version 3 Protocol Specification".
278 *
279 * Not all basic data types have their own encoding and decoding
280 * functions. For run-time efficiency, some data types are encoded
281 * or decoded inline.
282 */
283
284static void encode_uint32(struct xdr_stream *xdr, u32 value)
285{
286 __be32 *p = xdr_reserve_space(xdr, 4);
287 *p = cpu_to_be32(value);
288}
289
Chuck Levere4f93232010-12-14 14:56:30 +0000290static int decode_uint32(struct xdr_stream *xdr, u32 *value)
291{
292 __be32 *p;
293
294 p = xdr_inline_decode(xdr, 4);
295 if (unlikely(p == NULL))
296 goto out_overflow;
297 *value = be32_to_cpup(p);
298 return 0;
299out_overflow:
300 print_overflow_msg(__func__, xdr);
301 return -EIO;
302}
303
304static int decode_uint64(struct xdr_stream *xdr, u64 *value)
305{
306 __be32 *p;
307
308 p = xdr_inline_decode(xdr, 8);
309 if (unlikely(p == NULL))
310 goto out_overflow;
311 xdr_decode_hyper(p, value);
312 return 0;
313out_overflow:
314 print_overflow_msg(__func__, xdr);
315 return -EIO;
316}
317
318/*
319 * fileid3
320 *
321 * typedef uint64 fileid3;
322 */
323static int decode_fileid3(struct xdr_stream *xdr, u64 *fileid)
324{
325 return decode_uint64(xdr, fileid);
326}
327
Chuck Leverd9c407b2010-12-14 14:55:50 +0000328/*
329 * filename3
330 *
331 * typedef string filename3<>;
332 */
333static void encode_filename3(struct xdr_stream *xdr,
334 const char *name, u32 length)
335{
336 __be32 *p;
337
338 BUG_ON(length > NFS3_MAXNAMLEN);
339 p = xdr_reserve_space(xdr, 4 + length);
340 xdr_encode_opaque(p, name, length);
341}
342
Chuck Levere4f93232010-12-14 14:56:30 +0000343static int decode_inline_filename3(struct xdr_stream *xdr,
344 const char **name, u32 *length)
345{
346 __be32 *p;
347 u32 count;
348
349 p = xdr_inline_decode(xdr, 4);
350 if (unlikely(p == NULL))
351 goto out_overflow;
352 count = be32_to_cpup(p);
353 if (count > NFS3_MAXNAMLEN)
354 goto out_nametoolong;
355 p = xdr_inline_decode(xdr, count);
356 if (unlikely(p == NULL))
357 goto out_overflow;
358 *name = (const char *)p;
359 *length = count;
360 return 0;
361
362out_nametoolong:
363 dprintk("NFS: returned filename too long: %u\n", count);
364 return -ENAMETOOLONG;
365out_overflow:
366 print_overflow_msg(__func__, xdr);
367 return -EIO;
368}
369
Chuck Leverd9c407b2010-12-14 14:55:50 +0000370/*
371 * nfspath3
372 *
373 * typedef string nfspath3<>;
374 */
375static void encode_nfspath3(struct xdr_stream *xdr, struct page **pages,
376 const u32 length)
377{
378 BUG_ON(length > NFS3_MAXPATHLEN);
379 encode_uint32(xdr, length);
380 xdr_write_pages(xdr, pages, 0, length);
381}
382
Chuck Levere4f93232010-12-14 14:56:30 +0000383static int decode_nfspath3(struct xdr_stream *xdr)
384{
385 u32 recvd, count;
386 size_t hdrlen;
387 __be32 *p;
388
389 p = xdr_inline_decode(xdr, 4);
390 if (unlikely(p == NULL))
391 goto out_overflow;
392 count = be32_to_cpup(p);
393 if (unlikely(count >= xdr->buf->page_len || count > NFS3_MAXPATHLEN))
394 goto out_nametoolong;
395 hdrlen = (u8 *)xdr->p - (u8 *)xdr->iov->iov_base;
396 recvd = xdr->buf->len - hdrlen;
397 if (unlikely(count > recvd))
398 goto out_cheating;
399
400 xdr_read_pages(xdr, count);
401 xdr_terminate_string(xdr->buf, count);
402 return 0;
403
404out_nametoolong:
405 dprintk("NFS: returned pathname too long: %u\n", count);
406 return -ENAMETOOLONG;
407out_cheating:
408 dprintk("NFS: server cheating in pathname result: "
409 "count %u > recvd %u\n", count, recvd);
410 return -EIO;
411out_overflow:
412 print_overflow_msg(__func__, xdr);
413 return -EIO;
414}
415
Chuck Leverd9c407b2010-12-14 14:55:50 +0000416/*
417 * cookie3
418 *
419 * typedef uint64 cookie3
420 */
421static __be32 *xdr_encode_cookie3(__be32 *p, u64 cookie)
422{
423 return xdr_encode_hyper(p, cookie);
424}
425
Chuck Levere4f93232010-12-14 14:56:30 +0000426static int decode_cookie3(struct xdr_stream *xdr, u64 *cookie)
427{
428 return decode_uint64(xdr, cookie);
429}
430
Chuck Leverd9c407b2010-12-14 14:55:50 +0000431/*
432 * cookieverf3
433 *
434 * typedef opaque cookieverf3[NFS3_COOKIEVERFSIZE];
435 */
436static __be32 *xdr_encode_cookieverf3(__be32 *p, const __be32 *verifier)
437{
438 memcpy(p, verifier, NFS3_COOKIEVERFSIZE);
439 return p + XDR_QUADLEN(NFS3_COOKIEVERFSIZE);
440}
441
Chuck Levere4f93232010-12-14 14:56:30 +0000442static int decode_cookieverf3(struct xdr_stream *xdr, __be32 *verifier)
443{
444 __be32 *p;
445
446 p = xdr_inline_decode(xdr, NFS3_COOKIEVERFSIZE);
447 if (unlikely(p == NULL))
448 goto out_overflow;
449 memcpy(verifier, p, NFS3_COOKIEVERFSIZE);
450 return 0;
451out_overflow:
452 print_overflow_msg(__func__, xdr);
453 return -EIO;
454}
455
Chuck Leverd9c407b2010-12-14 14:55:50 +0000456/*
457 * createverf3
458 *
459 * typedef opaque createverf3[NFS3_CREATEVERFSIZE];
460 */
461static void encode_createverf3(struct xdr_stream *xdr, const __be32 *verifier)
462{
463 __be32 *p;
464
465 p = xdr_reserve_space(xdr, NFS3_CREATEVERFSIZE);
466 memcpy(p, verifier, NFS3_CREATEVERFSIZE);
467}
468
Chuck Levere4f93232010-12-14 14:56:30 +0000469static int decode_writeverf3(struct xdr_stream *xdr, __be32 *verifier)
470{
471 __be32 *p;
472
473 p = xdr_inline_decode(xdr, NFS3_WRITEVERFSIZE);
474 if (unlikely(p == NULL))
475 goto out_overflow;
476 memcpy(verifier, p, NFS3_WRITEVERFSIZE);
477 return 0;
478out_overflow:
479 print_overflow_msg(__func__, xdr);
480 return -EIO;
481}
482
483/*
484 * size3
485 *
486 * typedef uint64 size3;
487 */
488static __be32 *xdr_decode_size3(__be32 *p, u64 *size)
489{
490 return xdr_decode_hyper(p, size);
491}
492
493/*
494 * nfsstat3
495 *
496 * enum nfsstat3 {
497 * NFS3_OK = 0,
498 * ...
499 * }
500 */
501#define NFS3_OK NFS_OK
502
503static int decode_nfsstat3(struct xdr_stream *xdr, enum nfs_stat *status)
504{
505 __be32 *p;
506
507 p = xdr_inline_decode(xdr, 4);
508 if (unlikely(p == NULL))
509 goto out_overflow;
510 *status = be32_to_cpup(p);
511 return 0;
512out_overflow:
513 print_overflow_msg(__func__, xdr);
514 return -EIO;
515}
516
Chuck Leverd9c407b2010-12-14 14:55:50 +0000517/*
518 * ftype3
519 *
520 * enum ftype3 {
521 * NF3REG = 1,
522 * NF3DIR = 2,
523 * NF3BLK = 3,
524 * NF3CHR = 4,
525 * NF3LNK = 5,
526 * NF3SOCK = 6,
527 * NF3FIFO = 7
528 * };
529 */
530static void encode_ftype3(struct xdr_stream *xdr, const u32 type)
531{
532 BUG_ON(type > NF3FIFO);
533 encode_uint32(xdr, type);
534}
535
536/*
537 * specdata3
538 *
539 * struct specdata3 {
540 * uint32 specdata1;
541 * uint32 specdata2;
542 * };
543 */
544static void encode_specdata3(struct xdr_stream *xdr, const dev_t rdev)
545{
546 __be32 *p;
547
548 p = xdr_reserve_space(xdr, 8);
549 *p++ = cpu_to_be32(MAJOR(rdev));
550 *p = cpu_to_be32(MINOR(rdev));
551}
552
553/*
554 * nfs_fh3
555 *
556 * struct nfs_fh3 {
557 * opaque data<NFS3_FHSIZE>;
558 * };
559 */
560static void encode_nfs_fh3(struct xdr_stream *xdr, const struct nfs_fh *fh)
561{
562 __be32 *p;
563
564 BUG_ON(fh->size > NFS3_FHSIZE);
565 p = xdr_reserve_space(xdr, 4 + fh->size);
566 xdr_encode_opaque(p, fh->data, fh->size);
567}
568
Chuck Levere4f93232010-12-14 14:56:30 +0000569static int decode_nfs_fh3(struct xdr_stream *xdr, struct nfs_fh *fh)
570{
571 u32 length;
572 __be32 *p;
573
574 p = xdr_inline_decode(xdr, 4);
575 if (unlikely(p == NULL))
576 goto out_overflow;
577 length = be32_to_cpup(p++);
578 if (unlikely(length > NFS3_FHSIZE))
579 goto out_toobig;
580 p = xdr_inline_decode(xdr, length);
581 if (unlikely(p == NULL))
582 goto out_overflow;
583 fh->size = length;
584 memcpy(fh->data, p, length);
585 return 0;
586out_toobig:
587 dprintk("NFS: file handle size (%u) too big\n", length);
588 return -E2BIG;
589out_overflow:
590 print_overflow_msg(__func__, xdr);
591 return -EIO;
592}
593
594static void zero_nfs_fh3(struct nfs_fh *fh)
595{
596 memset(fh, 0, sizeof(*fh));
597}
598
Chuck Leverd9c407b2010-12-14 14:55:50 +0000599/*
Chuck Lever9d5a6432010-12-14 14:56:20 +0000600 * nfstime3
601 *
602 * struct nfstime3 {
603 * uint32 seconds;
604 * uint32 nseconds;
605 * };
606 */
607static __be32 *xdr_encode_nfstime3(__be32 *p, const struct timespec *timep)
608{
609 *p++ = cpu_to_be32(timep->tv_sec);
610 *p++ = cpu_to_be32(timep->tv_nsec);
611 return p;
612}
613
614/*
Chuck Leverd9c407b2010-12-14 14:55:50 +0000615 * sattr3
616 *
617 * enum time_how {
618 * DONT_CHANGE = 0,
619 * SET_TO_SERVER_TIME = 1,
620 * SET_TO_CLIENT_TIME = 2
621 * };
622 *
623 * union set_mode3 switch (bool set_it) {
624 * case TRUE:
625 * mode3 mode;
626 * default:
627 * void;
628 * };
629 *
630 * union set_uid3 switch (bool set_it) {
631 * case TRUE:
632 * uid3 uid;
633 * default:
634 * void;
635 * };
636 *
637 * union set_gid3 switch (bool set_it) {
638 * case TRUE:
639 * gid3 gid;
640 * default:
641 * void;
642 * };
643 *
644 * union set_size3 switch (bool set_it) {
645 * case TRUE:
646 * size3 size;
647 * default:
648 * void;
649 * };
650 *
651 * union set_atime switch (time_how set_it) {
652 * case SET_TO_CLIENT_TIME:
653 * nfstime3 atime;
654 * default:
655 * void;
656 * };
657 *
658 * union set_mtime switch (time_how set_it) {
659 * case SET_TO_CLIENT_TIME:
660 * nfstime3 mtime;
661 * default:
662 * void;
663 * };
664 *
665 * struct sattr3 {
666 * set_mode3 mode;
667 * set_uid3 uid;
668 * set_gid3 gid;
669 * set_size3 size;
670 * set_atime atime;
671 * set_mtime mtime;
672 * };
673 */
674static void encode_sattr3(struct xdr_stream *xdr, const struct iattr *attr)
675{
676 u32 nbytes;
677 __be32 *p;
678
679 /*
680 * In order to make only a single xdr_reserve_space() call,
681 * pre-compute the total number of bytes to be reserved.
682 * Six boolean values, one for each set_foo field, are always
683 * present in the encoded result, so start there.
684 */
685 nbytes = 6 * 4;
686 if (attr->ia_valid & ATTR_MODE)
687 nbytes += 4;
688 if (attr->ia_valid & ATTR_UID)
689 nbytes += 4;
690 if (attr->ia_valid & ATTR_GID)
691 nbytes += 4;
692 if (attr->ia_valid & ATTR_SIZE)
693 nbytes += 8;
694 if (attr->ia_valid & ATTR_ATIME_SET)
695 nbytes += 8;
696 if (attr->ia_valid & ATTR_MTIME_SET)
697 nbytes += 8;
698 p = xdr_reserve_space(xdr, nbytes);
699
Chuck Lever9d5a6432010-12-14 14:56:20 +0000700 if (attr->ia_valid & ATTR_MODE) {
701 *p++ = xdr_one;
702 *p++ = cpu_to_be32(attr->ia_mode & S_IALLUGO);
703 } else
704 *p++ = xdr_zero;
705
706 if (attr->ia_valid & ATTR_UID) {
707 *p++ = xdr_one;
708 *p++ = cpu_to_be32(attr->ia_uid);
709 } else
710 *p++ = xdr_zero;
711
712 if (attr->ia_valid & ATTR_GID) {
713 *p++ = xdr_one;
714 *p++ = cpu_to_be32(attr->ia_gid);
715 } else
716 *p++ = xdr_zero;
717
718 if (attr->ia_valid & ATTR_SIZE) {
719 *p++ = xdr_one;
720 p = xdr_encode_hyper(p, (u64)attr->ia_size);
721 } else
722 *p++ = xdr_zero;
723
724 if (attr->ia_valid & ATTR_ATIME_SET) {
725 *p++ = xdr_two;
726 p = xdr_encode_nfstime3(p, &attr->ia_atime);
727 } else if (attr->ia_valid & ATTR_ATIME) {
728 *p++ = xdr_one;
729 } else
730 *p++ = xdr_zero;
731
732 if (attr->ia_valid & ATTR_MTIME_SET) {
733 *p++ = xdr_two;
734 xdr_encode_nfstime3(p, &attr->ia_mtime);
735 } else if (attr->ia_valid & ATTR_MTIME) {
736 *p = xdr_one;
737 } else
738 *p = xdr_zero;
Chuck Leverd9c407b2010-12-14 14:55:50 +0000739}
740
741/*
Chuck Levere4f93232010-12-14 14:56:30 +0000742 * fattr3
743 *
744 * struct fattr3 {
745 * ftype3 type;
746 * mode3 mode;
747 * uint32 nlink;
748 * uid3 uid;
749 * gid3 gid;
750 * size3 size;
751 * size3 used;
752 * specdata3 rdev;
753 * uint64 fsid;
754 * fileid3 fileid;
755 * nfstime3 atime;
756 * nfstime3 mtime;
757 * nfstime3 ctime;
758 * };
759 */
760static int decode_fattr3(struct xdr_stream *xdr, struct nfs_fattr *fattr)
761{
762 __be32 *p;
763
764 p = xdr_inline_decode(xdr, NFS3_fattr_sz << 2);
765 if (unlikely(p == NULL))
766 goto out_overflow;
767 xdr_decode_fattr(p, fattr);
768 return 0;
769out_overflow:
770 print_overflow_msg(__func__, xdr);
771 return -EIO;
772}
773
774/*
775 * post_op_attr
776 *
777 * union post_op_attr switch (bool attributes_follow) {
778 * case TRUE:
779 * fattr3 attributes;
780 * case FALSE:
781 * void;
782 * };
783 */
784static int decode_post_op_attr(struct xdr_stream *xdr, struct nfs_fattr *fattr)
785{
786 __be32 *p;
787
788 p = xdr_inline_decode(xdr, 4);
789 if (unlikely(p == NULL))
790 goto out_overflow;
791 if (*p != xdr_zero)
792 return decode_fattr3(xdr, fattr);
793 return 0;
794out_overflow:
795 print_overflow_msg(__func__, xdr);
796 return -EIO;
797}
798
799/*
800 * wcc_attr
801 * struct wcc_attr {
802 * size3 size;
803 * nfstime3 mtime;
804 * nfstime3 ctime;
805 * };
806 */
807static int decode_wcc_attr(struct xdr_stream *xdr, struct nfs_fattr *fattr)
808{
809 __be32 *p;
810
811 p = xdr_inline_decode(xdr, NFS3_wcc_attr_sz << 2);
812 if (unlikely(p == NULL))
813 goto out_overflow;
814 xdr_decode_wcc_attr(p, fattr);
815 return 0;
816out_overflow:
817 print_overflow_msg(__func__, xdr);
818 return -EIO;
819}
820
821/*
822 * pre_op_attr
823 * union pre_op_attr switch (bool attributes_follow) {
824 * case TRUE:
825 * wcc_attr attributes;
826 * case FALSE:
827 * void;
828 * };
829 *
830 * wcc_data
831 *
832 * struct wcc_data {
833 * pre_op_attr before;
834 * post_op_attr after;
835 * };
836 */
837static int decode_pre_op_attr(struct xdr_stream *xdr, struct nfs_fattr *fattr)
838{
839 __be32 *p;
840
841 p = xdr_inline_decode(xdr, 4);
842 if (unlikely(p == NULL))
843 goto out_overflow;
844 if (*p != xdr_zero)
845 return decode_wcc_attr(xdr, fattr);
846 return 0;
847out_overflow:
848 print_overflow_msg(__func__, xdr);
849 return -EIO;
850}
851
852static int decode_wcc_data(struct xdr_stream *xdr, struct nfs_fattr *fattr)
853{
854 int error;
855
856 error = decode_pre_op_attr(xdr, fattr);
857 if (unlikely(error))
858 goto out;
859 error = decode_post_op_attr(xdr, fattr);
860out:
861 return error;
862}
863
864/*
865 * post_op_fh3
866 *
867 * union post_op_fh3 switch (bool handle_follows) {
868 * case TRUE:
869 * nfs_fh3 handle;
870 * case FALSE:
871 * void;
872 * };
873 */
874static int decode_post_op_fh3(struct xdr_stream *xdr, struct nfs_fh *fh)
875{
876 __be32 *p = xdr_inline_decode(xdr, 4);
877 if (unlikely(p == NULL))
878 goto out_overflow;
879 if (*p != xdr_zero)
880 return decode_nfs_fh3(xdr, fh);
881 zero_nfs_fh3(fh);
882 return 0;
883out_overflow:
884 print_overflow_msg(__func__, xdr);
885 return -EIO;
886}
887
888/*
Chuck Leverd9c407b2010-12-14 14:55:50 +0000889 * diropargs3
890 *
891 * struct diropargs3 {
892 * nfs_fh3 dir;
893 * filename3 name;
894 * };
895 */
896static void encode_diropargs3(struct xdr_stream *xdr, const struct nfs_fh *fh,
897 const char *name, u32 length)
898{
899 encode_nfs_fh3(xdr, fh);
900 encode_filename3(xdr, name, length);
901}
902
903
Linus Torvalds1da177e2005-04-16 15:20:36 -0700904/*
Chuck Lever499ff712010-12-14 14:56:10 +0000905 * NFSv3 XDR encode functions
906 *
907 * NFSv3 argument types are defined in section 3.3 of RFC 1813:
908 * "NFS Version 3 Protocol Specification".
Linus Torvalds1da177e2005-04-16 15:20:36 -0700909 */
910
911/*
Chuck Leverd9c407b2010-12-14 14:55:50 +0000912 * 3.3.1 GETATTR3args
913 *
914 * struct GETATTR3args {
915 * nfs_fh3 object;
916 * };
917 */
918static int nfs3_xdr_enc_getattr3args(struct rpc_rqst *req, __be32 *p,
919 const struct nfs_fh *fh)
920{
921 struct xdr_stream xdr;
922
923 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
924 encode_nfs_fh3(&xdr, fh);
925 return 0;
926}
927
928/*
Chuck Leverd9c407b2010-12-14 14:55:50 +0000929 * 3.3.2 SETATTR3args
930 *
931 * union sattrguard3 switch (bool check) {
932 * case TRUE:
933 * nfstime3 obj_ctime;
934 * case FALSE:
935 * void;
936 * };
937 *
938 * struct SETATTR3args {
939 * nfs_fh3 object;
940 * sattr3 new_attributes;
941 * sattrguard3 guard;
942 * };
943 */
944static void encode_sattrguard3(struct xdr_stream *xdr,
945 const struct nfs3_sattrargs *args)
946{
947 __be32 *p;
948
949 if (args->guard) {
950 p = xdr_reserve_space(xdr, 4 + 8);
951 *p++ = xdr_one;
Chuck Lever9d5a6432010-12-14 14:56:20 +0000952 xdr_encode_nfstime3(p, &args->guardtime);
Chuck Leverd9c407b2010-12-14 14:55:50 +0000953 } else {
954 p = xdr_reserve_space(xdr, 4);
955 *p = xdr_zero;
956 }
957}
958
959static int nfs3_xdr_enc_setattr3args(struct rpc_rqst *req, __be32 *p,
960 const struct nfs3_sattrargs *args)
961{
962 struct xdr_stream xdr;
963
964 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
965 encode_nfs_fh3(&xdr, args->fh);
966 encode_sattr3(&xdr, args->sattr);
967 encode_sattrguard3(&xdr, args);
968 return 0;
969}
970
971/*
Chuck Leverd9c407b2010-12-14 14:55:50 +0000972 * 3.3.3 LOOKUP3args
973 *
974 * struct LOOKUP3args {
975 * diropargs3 what;
976 * };
977 */
978static int nfs3_xdr_enc_lookup3args(struct rpc_rqst *req, __be32 *p,
979 const struct nfs3_diropargs *args)
980{
981 struct xdr_stream xdr;
982
983 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
984 encode_diropargs3(&xdr, args->fh, args->name, args->len);
985 return 0;
986}
987
988/*
Chuck Leverd9c407b2010-12-14 14:55:50 +0000989 * 3.3.4 ACCESS3args
990 *
991 * struct ACCESS3args {
992 * nfs_fh3 object;
993 * uint32 access;
994 * };
995 */
996static void encode_access3args(struct xdr_stream *xdr,
997 const struct nfs3_accessargs *args)
998{
999 encode_nfs_fh3(xdr, args->fh);
1000 encode_uint32(xdr, args->access);
1001}
1002
1003static int nfs3_xdr_enc_access3args(struct rpc_rqst *req, __be32 *p,
1004 const struct nfs3_accessargs *args)
1005{
1006 struct xdr_stream xdr;
1007
1008 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1009 encode_access3args(&xdr, args);
1010 return 0;
1011}
1012
1013/*
1014 * 3.3.5 READLINK3args
1015 *
1016 * struct READLINK3args {
1017 * nfs_fh3 symlink;
1018 * };
1019 */
1020static int nfs3_xdr_enc_readlink3args(struct rpc_rqst *req, __be32 *p,
1021 const struct nfs3_readlinkargs *args)
1022{
1023 struct xdr_stream xdr;
1024
1025 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1026 encode_nfs_fh3(&xdr, args->fh);
1027 prepare_reply_buffer(req, args->pages, args->pgbase,
1028 args->pglen, NFS3_readlinkres_sz);
1029 return 0;
1030}
1031
1032/*
Chuck Leverd9c407b2010-12-14 14:55:50 +00001033 * 3.3.6 READ3args
1034 *
1035 * struct READ3args {
1036 * nfs_fh3 file;
1037 * offset3 offset;
1038 * count3 count;
1039 * };
1040 */
1041static void encode_read3args(struct xdr_stream *xdr,
1042 const struct nfs_readargs *args)
1043{
1044 __be32 *p;
1045
1046 encode_nfs_fh3(xdr, args->fh);
1047
1048 p = xdr_reserve_space(xdr, 8 + 4);
1049 p = xdr_encode_hyper(p, args->offset);
1050 *p = cpu_to_be32(args->count);
1051}
1052
1053static int nfs3_xdr_enc_read3args(struct rpc_rqst *req, __be32 *p,
1054 const struct nfs_readargs *args)
1055{
1056 struct xdr_stream xdr;
1057
1058 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1059 encode_read3args(&xdr, args);
1060 prepare_reply_buffer(req, args->pages, args->pgbase,
1061 args->count, NFS3_readres_sz);
1062 req->rq_rcv_buf.flags |= XDRBUF_READ;
1063 return 0;
1064}
1065
1066/*
Chuck Leverd9c407b2010-12-14 14:55:50 +00001067 * 3.3.7 WRITE3args
1068 *
1069 * enum stable_how {
1070 * UNSTABLE = 0,
1071 * DATA_SYNC = 1,
1072 * FILE_SYNC = 2
1073 * };
1074 *
1075 * struct WRITE3args {
1076 * nfs_fh3 file;
1077 * offset3 offset;
1078 * count3 count;
1079 * stable_how stable;
1080 * opaque data<>;
1081 * };
1082 */
1083static void encode_write3args(struct xdr_stream *xdr,
1084 const struct nfs_writeargs *args)
1085{
1086 __be32 *p;
1087
1088 encode_nfs_fh3(xdr, args->fh);
1089
1090 p = xdr_reserve_space(xdr, 8 + 4 + 4 + 4);
1091 p = xdr_encode_hyper(p, args->offset);
1092 *p++ = cpu_to_be32(args->count);
1093
1094 BUG_ON(args->stable > NFS_FILE_SYNC);
1095 *p++ = cpu_to_be32(args->stable);
1096
1097 *p = cpu_to_be32(args->count);
1098 xdr_write_pages(xdr, args->pages, args->pgbase, args->count);
1099}
1100
1101static int nfs3_xdr_enc_write3args(struct rpc_rqst *req, __be32 *p,
1102 const struct nfs_writeargs *args)
1103{
1104 struct xdr_stream xdr;
1105
1106 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1107 encode_write3args(&xdr, args);
1108 xdr.buf->flags |= XDRBUF_WRITE;
1109 return 0;
1110}
1111
1112/*
Chuck Leverd9c407b2010-12-14 14:55:50 +00001113 * 3.3.8 CREATE3args
1114 *
1115 * enum createmode3 {
1116 * UNCHECKED = 0,
1117 * GUARDED = 1,
1118 * EXCLUSIVE = 2
1119 * };
1120 *
1121 * union createhow3 switch (createmode3 mode) {
1122 * case UNCHECKED:
1123 * case GUARDED:
1124 * sattr3 obj_attributes;
1125 * case EXCLUSIVE:
1126 * createverf3 verf;
1127 * };
1128 *
1129 * struct CREATE3args {
1130 * diropargs3 where;
1131 * createhow3 how;
1132 * };
1133 */
1134static void encode_createhow3(struct xdr_stream *xdr,
1135 const struct nfs3_createargs *args)
1136{
1137 encode_uint32(xdr, args->createmode);
1138 switch (args->createmode) {
1139 case NFS3_CREATE_UNCHECKED:
1140 case NFS3_CREATE_GUARDED:
1141 encode_sattr3(xdr, args->sattr);
1142 break;
1143 case NFS3_CREATE_EXCLUSIVE:
1144 encode_createverf3(xdr, args->verifier);
1145 break;
1146 default:
1147 BUG();
1148 }
1149}
1150
1151static int nfs3_xdr_enc_create3args(struct rpc_rqst *req, __be32 *p,
1152 const struct nfs3_createargs *args)
1153{
1154 struct xdr_stream xdr;
1155
1156 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1157 encode_diropargs3(&xdr, args->fh, args->name, args->len);
1158 encode_createhow3(&xdr, args);
1159 return 0;
1160}
1161
1162/*
Chuck Leverd9c407b2010-12-14 14:55:50 +00001163 * 3.3.9 MKDIR3args
1164 *
1165 * struct MKDIR3args {
1166 * diropargs3 where;
1167 * sattr3 attributes;
1168 * };
1169 */
1170static int nfs3_xdr_enc_mkdir3args(struct rpc_rqst *req, __be32 *p,
1171 const struct nfs3_mkdirargs *args)
1172{
1173 struct xdr_stream xdr;
1174
1175 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1176 encode_diropargs3(&xdr, args->fh, args->name, args->len);
1177 encode_sattr3(&xdr, args->sattr);
1178 return 0;
1179}
1180
1181/*
Chuck Leverd9c407b2010-12-14 14:55:50 +00001182 * 3.3.10 SYMLINK3args
1183 *
1184 * struct symlinkdata3 {
1185 * sattr3 symlink_attributes;
1186 * nfspath3 symlink_data;
1187 * };
1188 *
1189 * struct SYMLINK3args {
1190 * diropargs3 where;
1191 * symlinkdata3 symlink;
1192 * };
1193 */
1194static void encode_symlinkdata3(struct xdr_stream *xdr,
1195 const struct nfs3_symlinkargs *args)
1196{
1197 encode_sattr3(xdr, args->sattr);
1198 encode_nfspath3(xdr, args->pages, args->pathlen);
1199}
1200
1201static int nfs3_xdr_enc_symlink3args(struct rpc_rqst *req, __be32 *p,
1202 const struct nfs3_symlinkargs *args)
1203{
1204 struct xdr_stream xdr;
1205
1206 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1207 encode_diropargs3(&xdr, args->fromfh, args->fromname, args->fromlen);
1208 encode_symlinkdata3(&xdr, args);
1209 return 0;
1210}
1211
1212/*
Chuck Leverd9c407b2010-12-14 14:55:50 +00001213 * 3.3.11 MKNOD3args
1214 *
1215 * struct devicedata3 {
1216 * sattr3 dev_attributes;
1217 * specdata3 spec;
1218 * };
1219 *
1220 * union mknoddata3 switch (ftype3 type) {
1221 * case NF3CHR:
1222 * case NF3BLK:
1223 * devicedata3 device;
1224 * case NF3SOCK:
1225 * case NF3FIFO:
1226 * sattr3 pipe_attributes;
1227 * default:
1228 * void;
1229 * };
1230 *
1231 * struct MKNOD3args {
1232 * diropargs3 where;
1233 * mknoddata3 what;
1234 * };
1235 */
1236static void encode_devicedata3(struct xdr_stream *xdr,
1237 const struct nfs3_mknodargs *args)
1238{
1239 encode_sattr3(xdr, args->sattr);
1240 encode_specdata3(xdr, args->rdev);
1241}
1242
1243static void encode_mknoddata3(struct xdr_stream *xdr,
1244 const struct nfs3_mknodargs *args)
1245{
1246 encode_ftype3(xdr, args->type);
1247 switch (args->type) {
1248 case NF3CHR:
1249 case NF3BLK:
1250 encode_devicedata3(xdr, args);
1251 break;
1252 case NF3SOCK:
1253 case NF3FIFO:
1254 encode_sattr3(xdr, args->sattr);
1255 break;
1256 case NF3REG:
1257 case NF3DIR:
1258 break;
1259 default:
1260 BUG();
1261 }
1262}
1263
1264static int nfs3_xdr_enc_mknod3args(struct rpc_rqst *req, __be32 *p,
1265 const struct nfs3_mknodargs *args)
1266{
1267 struct xdr_stream xdr;
1268
1269 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1270 encode_diropargs3(&xdr, args->fh, args->name, args->len);
1271 encode_mknoddata3(&xdr, args);
1272 return 0;
1273}
1274
1275/*
1276 * 3.3.12 REMOVE3args
1277 *
1278 * struct REMOVE3args {
1279 * diropargs3 object;
1280 * };
1281 */
1282static int nfs3_xdr_enc_remove3args(struct rpc_rqst *req, __be32 *p,
1283 const struct nfs_removeargs *args)
1284{
1285 struct xdr_stream xdr;
1286
1287 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1288 encode_diropargs3(&xdr, args->fh, args->name.name, args->name.len);
1289 return 0;
1290}
1291
1292/*
Chuck Leverd9c407b2010-12-14 14:55:50 +00001293 * 3.3.14 RENAME3args
1294 *
1295 * struct RENAME3args {
1296 * diropargs3 from;
1297 * diropargs3 to;
1298 * };
1299 */
1300static int nfs3_xdr_enc_rename3args(struct rpc_rqst *req, __be32 *p,
1301 const struct nfs_renameargs *args)
1302{
1303 const struct qstr *old = args->old_name;
1304 const struct qstr *new = args->new_name;
1305 struct xdr_stream xdr;
1306
1307 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1308 encode_diropargs3(&xdr, args->old_dir, old->name, old->len);
1309 encode_diropargs3(&xdr, args->new_dir, new->name, new->len);
1310 return 0;
1311}
1312
1313/*
Chuck Leverd9c407b2010-12-14 14:55:50 +00001314 * 3.3.15 LINK3args
1315 *
1316 * struct LINK3args {
1317 * nfs_fh3 file;
1318 * diropargs3 link;
1319 * };
1320 */
1321static int nfs3_xdr_enc_link3args(struct rpc_rqst *req, __be32 *p,
1322 const struct nfs3_linkargs *args)
1323{
1324 struct xdr_stream xdr;
1325
1326 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1327 encode_nfs_fh3(&xdr, args->fromfh);
1328 encode_diropargs3(&xdr, args->tofh, args->toname, args->tolen);
1329 return 0;
1330}
1331
1332/*
Chuck Leverd9c407b2010-12-14 14:55:50 +00001333 * 3.3.16 READDIR3args
1334 *
1335 * struct READDIR3args {
1336 * nfs_fh3 dir;
1337 * cookie3 cookie;
1338 * cookieverf3 cookieverf;
1339 * count3 count;
1340 * };
1341 */
1342static void encode_readdir3args(struct xdr_stream *xdr,
1343 const struct nfs3_readdirargs *args)
1344{
1345 __be32 *p;
1346
1347 encode_nfs_fh3(xdr, args->fh);
1348
1349 p = xdr_reserve_space(xdr, 8 + NFS3_COOKIEVERFSIZE + 4);
1350 p = xdr_encode_cookie3(p, args->cookie);
1351 p = xdr_encode_cookieverf3(p, args->verf);
1352 *p = cpu_to_be32(args->count);
1353}
1354
1355static int nfs3_xdr_enc_readdir3args(struct rpc_rqst *req, __be32 *p,
1356 const struct nfs3_readdirargs *args)
1357{
1358 struct xdr_stream xdr;
1359
1360 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1361 encode_readdir3args(&xdr, args);
1362 prepare_reply_buffer(req, args->pages, 0,
1363 args->count, NFS3_readdirres_sz);
1364 return 0;
1365}
1366
1367/*
1368 * 3.3.17 READDIRPLUS3args
1369 *
1370 * struct READDIRPLUS3args {
1371 * nfs_fh3 dir;
1372 * cookie3 cookie;
1373 * cookieverf3 cookieverf;
1374 * count3 dircount;
1375 * count3 maxcount;
1376 * };
1377 */
1378static void encode_readdirplus3args(struct xdr_stream *xdr,
1379 const struct nfs3_readdirargs *args)
1380{
1381 __be32 *p;
1382
1383 encode_nfs_fh3(xdr, args->fh);
1384
1385 p = xdr_reserve_space(xdr, 8 + NFS3_COOKIEVERFSIZE + 4 + 4);
1386 p = xdr_encode_cookie3(p, args->cookie);
1387 p = xdr_encode_cookieverf3(p, args->verf);
1388
1389 /*
1390 * readdirplus: need dircount + buffer size.
1391 * We just make sure we make dircount big enough
1392 */
1393 *p++ = cpu_to_be32(args->count >> 3);
1394
1395 *p = cpu_to_be32(args->count);
1396}
1397
1398static int nfs3_xdr_enc_readdirplus3args(struct rpc_rqst *req, __be32 *p,
1399 const struct nfs3_readdirargs *args)
1400{
1401 struct xdr_stream xdr;
1402
1403 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1404 encode_readdirplus3args(&xdr, args);
1405 prepare_reply_buffer(req, args->pages, 0,
1406 args->count, NFS3_readdirres_sz);
1407 return 0;
1408}
1409
1410/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001411 * Decode the result of a readdir call.
1412 * We just check for syntactical correctness.
1413 */
1414static int
Al Virod61005a2006-10-19 23:28:48 -07001415nfs3_xdr_readdirres(struct rpc_rqst *req, __be32 *p, struct nfs3_readdirres *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001416{
1417 struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
1418 struct kvec *iov = rcvbuf->head;
1419 struct page **page;
Chuck Leverc957c522007-10-26 13:31:57 -04001420 size_t hdrlen;
Bryan Schumakerafa8ccc2010-10-20 15:44:31 -04001421 u32 recvd, pglen;
Trond Myklebustac396122010-11-15 20:26:22 -05001422 int status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001423
1424 status = ntohl(*p++);
1425 /* Decode post_op_attrs */
1426 p = xdr_decode_post_op_attr(p, res->dir_attr);
1427 if (status)
Benny Halevy856dff32008-03-31 17:39:06 +03001428 return nfs_stat_to_errno(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001429 /* Decode verifier cookie */
1430 if (res->verf) {
1431 res->verf[0] = *p++;
1432 res->verf[1] = *p++;
1433 } else {
1434 p += 2;
1435 }
1436
1437 hdrlen = (u8 *) p - (u8 *) iov->iov_base;
1438 if (iov->iov_len < hdrlen) {
Chuck Leverfe82a182007-09-11 18:01:10 -04001439 dprintk("NFS: READDIR reply header overflowed:"
Chuck Leverc957c522007-10-26 13:31:57 -04001440 "length %Zu > %Zu\n", hdrlen, iov->iov_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001441 return -errno_NFSERR_IO;
1442 } else if (iov->iov_len != hdrlen) {
1443 dprintk("NFS: READDIR header is short. iovec will be shifted.\n");
1444 xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen);
1445 }
1446
1447 pglen = rcvbuf->page_len;
1448 recvd = rcvbuf->len - hdrlen;
1449 if (pglen > recvd)
1450 pglen = recvd;
1451 page = rcvbuf->pages;
Jeff Layton643f8112008-02-22 14:50:00 -05001452
Trond Myklebustac396122010-11-15 20:26:22 -05001453 return pglen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001454}
1455
Linus Torvalds1da177e2005-04-16 15:20:36 -07001456/*
Chuck Leverd9c407b2010-12-14 14:55:50 +00001457 * 3.3.21 COMMIT3args
1458 *
1459 * struct COMMIT3args {
1460 * nfs_fh3 file;
1461 * offset3 offset;
1462 * count3 count;
1463 * };
1464 */
1465static void encode_commit3args(struct xdr_stream *xdr,
1466 const struct nfs_writeargs *args)
1467{
1468 __be32 *p;
1469
1470 encode_nfs_fh3(xdr, args->fh);
1471
1472 p = xdr_reserve_space(xdr, 8 + 4);
1473 p = xdr_encode_hyper(p, args->offset);
1474 *p = cpu_to_be32(args->count);
1475}
1476
1477static int nfs3_xdr_enc_commit3args(struct rpc_rqst *req, __be32 *p,
1478 const struct nfs_writeargs *args)
1479{
1480 struct xdr_stream xdr;
1481
1482 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1483 encode_commit3args(&xdr, args);
1484 return 0;
1485}
1486
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +00001487#ifdef CONFIG_NFS_V3_ACL
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +00001488
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
Chuck Leverd9c407b2010-12-14 14:55:50 +00001504static int nfs3_xdr_enc_setacl3args(struct rpc_rqst *req, __be32 *p,
1505 const struct nfs3_setaclargs *args)
1506{
1507 struct xdr_stream xdr;
1508 unsigned int base;
1509 int error;
1510
1511 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1512 encode_nfs_fh3(&xdr, NFS_FH(args->inode));
1513 encode_uint32(&xdr, args->mask);
1514 if (args->npages != 0)
1515 xdr_write_pages(&xdr, args->pages, 0, args->len);
1516
1517 base = req->rq_slen;
1518 error = nfsacl_encode(xdr.buf, base, args->inode,
1519 (args->mask & NFS_ACL) ?
1520 args->acl_access : NULL, 1, 0);
1521 BUG_ON(error < 0);
1522 error = nfsacl_encode(xdr.buf, base + error, args->inode,
1523 (args->mask & NFS_DFACL) ?
1524 args->acl_default : NULL, 1,
1525 NFS_ACL_DEFAULT);
1526 BUG_ON(error < 0);
1527 return 0;
1528}
1529
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +00001530#endif /* CONFIG_NFS_V3_ACL */
1531
Linus Torvalds1da177e2005-04-16 15:20:36 -07001532/*
1533 * NFS XDR decode functions
1534 */
1535
1536/*
1537 * Decode attrstat reply.
1538 */
1539static int
Al Virod61005a2006-10-19 23:28:48 -07001540nfs3_xdr_attrstat(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001541{
1542 int status;
1543
1544 if ((status = ntohl(*p++)))
Benny Halevy856dff32008-03-31 17:39:06 +03001545 return nfs_stat_to_errno(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001546 xdr_decode_fattr(p, fattr);
1547 return 0;
1548}
1549
1550/*
Chuck Levere4f93232010-12-14 14:56:30 +00001551 * 3.3.1 GETATTR3res
1552 *
1553 * struct GETATTR3resok {
1554 * fattr3 obj_attributes;
1555 * };
1556 *
1557 * union GETATTR3res switch (nfsstat3 status) {
1558 * case NFS3_OK:
1559 * GETATTR3resok resok;
1560 * default:
1561 * void;
1562 * };
1563 */
1564static int nfs3_xdr_dec_getattr3res(struct rpc_rqst *req, __be32 *p,
1565 struct nfs_fattr *result)
1566{
1567 struct xdr_stream xdr;
1568 enum nfs_stat status;
1569 int error;
1570
1571 xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
1572 error = decode_nfsstat3(&xdr, &status);
1573 if (unlikely(error))
1574 goto out;
1575 if (status != NFS3_OK)
1576 goto out_default;
1577 error = decode_fattr3(&xdr, result);
1578out:
1579 return error;
1580out_default:
1581 return nfs_stat_to_errno(status);
1582}
1583
1584/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001585 * Decode status+wcc_data reply
1586 * SATTR, REMOVE, RMDIR
1587 */
1588static int
Al Virod61005a2006-10-19 23:28:48 -07001589nfs3_xdr_wccstat(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001590{
1591 int status;
1592
1593 if ((status = ntohl(*p++)))
Benny Halevy856dff32008-03-31 17:39:06 +03001594 status = nfs_stat_to_errno(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001595 xdr_decode_wcc_data(p, fattr);
1596 return status;
1597}
1598
Chuck Levere4f93232010-12-14 14:56:30 +00001599/*
1600 * 3.3.2 SETATTR3res
1601 *
1602 * struct SETATTR3resok {
1603 * wcc_data obj_wcc;
1604 * };
1605 *
1606 * struct SETATTR3resfail {
1607 * wcc_data obj_wcc;
1608 * };
1609 *
1610 * union SETATTR3res switch (nfsstat3 status) {
1611 * case NFS3_OK:
1612 * SETATTR3resok resok;
1613 * default:
1614 * SETATTR3resfail resfail;
1615 * };
1616 */
1617static int nfs3_xdr_dec_setattr3res(struct rpc_rqst *req, __be32 *p,
1618 struct nfs_fattr *result)
1619{
1620 struct xdr_stream xdr;
1621 enum nfs_stat status;
1622 int error;
1623
1624 xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
1625 error = decode_nfsstat3(&xdr, &status);
1626 if (unlikely(error))
1627 goto out;
1628 error = decode_wcc_data(&xdr, result);
1629 if (unlikely(error))
1630 goto out;
1631 if (status != NFS3_OK)
1632 goto out_status;
1633out:
1634 return error;
1635out_status:
1636 return nfs_stat_to_errno(status);
1637}
1638
Trond Myklebust4fdc17b2007-07-14 15:39:57 -04001639static int
1640nfs3_xdr_removeres(struct rpc_rqst *req, __be32 *p, struct nfs_removeres *res)
1641{
Trond Myklebustd3468902010-04-16 16:22:50 -04001642 return nfs3_xdr_wccstat(req, p, res->dir_attr);
Trond Myklebust4fdc17b2007-07-14 15:39:57 -04001643}
1644
Linus Torvalds1da177e2005-04-16 15:20:36 -07001645/*
1646 * Decode LOOKUP reply
1647 */
1648static int
Al Virod61005a2006-10-19 23:28:48 -07001649nfs3_xdr_lookupres(struct rpc_rqst *req, __be32 *p, struct nfs3_diropres *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001650{
1651 int status;
1652
1653 if ((status = ntohl(*p++))) {
Benny Halevy856dff32008-03-31 17:39:06 +03001654 status = nfs_stat_to_errno(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001655 } else {
1656 if (!(p = xdr_decode_fhandle(p, res->fh)))
1657 return -errno_NFSERR_IO;
1658 p = xdr_decode_post_op_attr(p, res->fattr);
1659 }
1660 xdr_decode_post_op_attr(p, res->dir_attr);
1661 return status;
1662}
1663
1664/*
Chuck Levere4f93232010-12-14 14:56:30 +00001665 * 3.3.3 LOOKUP3res
1666 *
1667 * struct LOOKUP3resok {
1668 * nfs_fh3 object;
1669 * post_op_attr obj_attributes;
1670 * post_op_attr dir_attributes;
1671 * };
1672 *
1673 * struct LOOKUP3resfail {
1674 * post_op_attr dir_attributes;
1675 * };
1676 *
1677 * union LOOKUP3res switch (nfsstat3 status) {
1678 * case NFS3_OK:
1679 * LOOKUP3resok resok;
1680 * default:
1681 * LOOKUP3resfail resfail;
1682 * };
1683 */
1684static int nfs3_xdr_dec_lookup3res(struct rpc_rqst *req, __be32 *p,
1685 struct nfs3_diropres *result)
1686{
1687 struct xdr_stream xdr;
1688 enum nfs_stat status;
1689 int error;
1690
1691 xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
1692 error = decode_nfsstat3(&xdr, &status);
1693 if (unlikely(error))
1694 goto out;
1695 if (status != NFS3_OK)
1696 goto out_default;
1697 error = decode_nfs_fh3(&xdr, result->fh);
1698 if (unlikely(error))
1699 goto out;
1700 error = decode_post_op_attr(&xdr, result->fattr);
1701 if (unlikely(error))
1702 goto out;
1703 error = decode_post_op_attr(&xdr, result->dir_attr);
1704out:
1705 return error;
1706out_default:
1707 error = decode_post_op_attr(&xdr, result->dir_attr);
1708 if (unlikely(error))
1709 goto out;
1710 return nfs_stat_to_errno(status);
1711}
1712
1713/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001714 * Decode ACCESS reply
1715 */
1716static int
Al Virod61005a2006-10-19 23:28:48 -07001717nfs3_xdr_accessres(struct rpc_rqst *req, __be32 *p, struct nfs3_accessres *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001718{
1719 int status = ntohl(*p++);
1720
1721 p = xdr_decode_post_op_attr(p, res->fattr);
1722 if (status)
Benny Halevy856dff32008-03-31 17:39:06 +03001723 return nfs_stat_to_errno(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001724 res->access = ntohl(*p++);
1725 return 0;
1726}
1727
Linus Torvalds1da177e2005-04-16 15:20:36 -07001728/*
Chuck Levere4f93232010-12-14 14:56:30 +00001729 * 3.3.4 ACCESS3res
1730 *
1731 * struct ACCESS3resok {
1732 * post_op_attr obj_attributes;
1733 * uint32 access;
1734 * };
1735 *
1736 * struct ACCESS3resfail {
1737 * post_op_attr obj_attributes;
1738 * };
1739 *
1740 * union ACCESS3res switch (nfsstat3 status) {
1741 * case NFS3_OK:
1742 * ACCESS3resok resok;
1743 * default:
1744 * ACCESS3resfail resfail;
1745 * };
1746 */
1747static int nfs3_xdr_dec_access3res(struct rpc_rqst *req, __be32 *p,
1748 struct nfs3_accessres *result)
1749{
1750 struct xdr_stream xdr;
1751 enum nfs_stat status;
1752 int error;
1753
1754 xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
1755 error = decode_nfsstat3(&xdr, &status);
1756 if (unlikely(error))
1757 goto out;
1758 error = decode_post_op_attr(&xdr, result->fattr);
1759 if (unlikely(error))
1760 goto out;
1761 if (status != NFS3_OK)
1762 goto out_default;
1763 error = decode_uint32(&xdr, &result->access);
1764out:
1765 return error;
1766out_default:
1767 return nfs_stat_to_errno(status);
1768}
1769
1770/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001771 * Decode READLINK reply
1772 */
1773static int
Al Virod61005a2006-10-19 23:28:48 -07001774nfs3_xdr_readlinkres(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001775{
1776 struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
1777 struct kvec *iov = rcvbuf->head;
Chuck Leverc957c522007-10-26 13:31:57 -04001778 size_t hdrlen;
1779 u32 len, recvd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001780 int status;
1781
1782 status = ntohl(*p++);
1783 p = xdr_decode_post_op_attr(p, fattr);
1784
1785 if (status != 0)
Benny Halevy856dff32008-03-31 17:39:06 +03001786 return nfs_stat_to_errno(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001787
1788 /* Convert length of symlink */
1789 len = ntohl(*p++);
Chuck Leverc957c522007-10-26 13:31:57 -04001790 if (len >= rcvbuf->page_len) {
Chuck Leverfe82a182007-09-11 18:01:10 -04001791 dprintk("nfs: server returned giant symlink!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001792 return -ENAMETOOLONG;
1793 }
1794
1795 hdrlen = (u8 *) p - (u8 *) iov->iov_base;
1796 if (iov->iov_len < hdrlen) {
Chuck Leverfe82a182007-09-11 18:01:10 -04001797 dprintk("NFS: READLINK reply header overflowed:"
Chuck Leverc957c522007-10-26 13:31:57 -04001798 "length %Zu > %Zu\n", hdrlen, iov->iov_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001799 return -errno_NFSERR_IO;
1800 } else if (iov->iov_len != hdrlen) {
Chuck Leverfe82a182007-09-11 18:01:10 -04001801 dprintk("NFS: READLINK header is short. "
1802 "iovec will be shifted.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001803 xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen);
1804 }
1805 recvd = req->rq_rcv_buf.len - hdrlen;
1806 if (recvd < len) {
Chuck Leverfe82a182007-09-11 18:01:10 -04001807 dprintk("NFS: server cheating in readlink reply: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001808 "count %u > recvd %u\n", len, recvd);
1809 return -EIO;
1810 }
1811
Chuck Leverb4687da2010-09-21 16:55:48 -04001812 xdr_terminate_string(rcvbuf, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001813 return 0;
1814}
1815
1816/*
Chuck Levere4f93232010-12-14 14:56:30 +00001817 * 3.3.5 READLINK3res
1818 *
1819 * struct READLINK3resok {
1820 * post_op_attr symlink_attributes;
1821 * nfspath3 data;
1822 * };
1823 *
1824 * struct READLINK3resfail {
1825 * post_op_attr symlink_attributes;
1826 * };
1827 *
1828 * union READLINK3res switch (nfsstat3 status) {
1829 * case NFS3_OK:
1830 * READLINK3resok resok;
1831 * default:
1832 * READLINK3resfail resfail;
1833 * };
1834 */
1835static int nfs3_xdr_dec_readlink3res(struct rpc_rqst *req, __be32 *p,
1836 struct nfs_fattr *result)
1837{
1838 struct xdr_stream xdr;
1839 enum nfs_stat status;
1840 int error;
1841
1842 xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
1843 error = decode_nfsstat3(&xdr, &status);
1844 if (unlikely(error))
1845 goto out;
1846 error = decode_post_op_attr(&xdr, result);
1847 if (unlikely(error))
1848 goto out;
1849 if (status != NFS3_OK)
1850 goto out_default;
1851 error = decode_nfspath3(&xdr);
1852out:
1853 return error;
1854out_default:
1855 return nfs_stat_to_errno(status);
1856}
1857
1858/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001859 * Decode READ reply
1860 */
1861static int
Al Virod61005a2006-10-19 23:28:48 -07001862nfs3_xdr_readres(struct rpc_rqst *req, __be32 *p, struct nfs_readres *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001863{
1864 struct kvec *iov = req->rq_rcv_buf.head;
Chuck Leverc957c522007-10-26 13:31:57 -04001865 size_t hdrlen;
1866 u32 count, ocount, recvd;
1867 int status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001868
1869 status = ntohl(*p++);
1870 p = xdr_decode_post_op_attr(p, res->fattr);
1871
1872 if (status != 0)
Benny Halevy856dff32008-03-31 17:39:06 +03001873 return nfs_stat_to_errno(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001874
Chuck Leverc957c522007-10-26 13:31:57 -04001875 /* Decode reply count and EOF flag. NFSv3 is somewhat redundant
Linus Torvalds1da177e2005-04-16 15:20:36 -07001876 * in that it puts the count both in the res struct and in the
1877 * opaque data count. */
1878 count = ntohl(*p++);
1879 res->eof = ntohl(*p++);
1880 ocount = ntohl(*p++);
1881
1882 if (ocount != count) {
Chuck Leverfe82a182007-09-11 18:01:10 -04001883 dprintk("NFS: READ count doesn't match RPC opaque count.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001884 return -errno_NFSERR_IO;
1885 }
1886
1887 hdrlen = (u8 *) p - (u8 *) iov->iov_base;
1888 if (iov->iov_len < hdrlen) {
Chuck Leverfe82a182007-09-11 18:01:10 -04001889 dprintk("NFS: READ reply header overflowed:"
Chuck Leverc957c522007-10-26 13:31:57 -04001890 "length %Zu > %Zu\n", hdrlen, iov->iov_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001891 return -errno_NFSERR_IO;
1892 } else if (iov->iov_len != hdrlen) {
1893 dprintk("NFS: READ header is short. iovec will be shifted.\n");
1894 xdr_shift_buf(&req->rq_rcv_buf, iov->iov_len - hdrlen);
1895 }
1896
1897 recvd = req->rq_rcv_buf.len - hdrlen;
1898 if (count > recvd) {
Chuck Leverfe82a182007-09-11 18:01:10 -04001899 dprintk("NFS: server cheating in read reply: "
Chuck Leverc957c522007-10-26 13:31:57 -04001900 "count %u > recvd %u\n", count, recvd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001901 count = recvd;
1902 res->eof = 0;
1903 }
1904
1905 if (count < res->count)
1906 res->count = count;
1907
1908 return count;
1909}
1910
1911/*
Chuck Levere4f93232010-12-14 14:56:30 +00001912 * 3.3.6 READ3res
1913 *
1914 * struct READ3resok {
1915 * post_op_attr file_attributes;
1916 * count3 count;
1917 * bool eof;
1918 * opaque data<>;
1919 * };
1920 *
1921 * struct READ3resfail {
1922 * post_op_attr file_attributes;
1923 * };
1924 *
1925 * union READ3res switch (nfsstat3 status) {
1926 * case NFS3_OK:
1927 * READ3resok resok;
1928 * default:
1929 * READ3resfail resfail;
1930 * };
1931 */
1932static int decode_read3resok(struct xdr_stream *xdr,
1933 struct nfs_readres *result)
1934{
1935 u32 eof, count, ocount, recvd;
1936 size_t hdrlen;
1937 __be32 *p;
1938
1939 p = xdr_inline_decode(xdr, 4 + 4 + 4);
1940 if (unlikely(p == NULL))
1941 goto out_overflow;
1942 count = be32_to_cpup(p++);
1943 eof = be32_to_cpup(p++);
1944 ocount = be32_to_cpup(p++);
1945 if (unlikely(ocount != count))
1946 goto out_mismatch;
1947 hdrlen = (u8 *)xdr->p - (u8 *)xdr->iov->iov_base;
1948 recvd = xdr->buf->len - hdrlen;
1949 if (unlikely(count > recvd))
1950 goto out_cheating;
1951
1952out:
1953 xdr_read_pages(xdr, count);
1954 result->eof = eof;
1955 result->count = count;
1956 return count;
1957out_mismatch:
1958 dprintk("NFS: READ count doesn't match length of opaque: "
1959 "count %u != ocount %u\n", count, ocount);
1960 return -EIO;
1961out_cheating:
1962 dprintk("NFS: server cheating in read result: "
1963 "count %u > recvd %u\n", count, recvd);
1964 count = recvd;
1965 eof = 0;
1966 goto out;
1967out_overflow:
1968 print_overflow_msg(__func__, xdr);
1969 return -EIO;
1970}
1971
1972static int nfs3_xdr_dec_read3res(struct rpc_rqst *req, __be32 *p,
1973 struct nfs_readres *result)
1974{
1975 struct xdr_stream xdr;
1976 enum nfs_stat status;
1977 int error;
1978
1979 xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
1980 error = decode_nfsstat3(&xdr, &status);
1981 if (unlikely(error))
1982 goto out;
1983 error = decode_post_op_attr(&xdr, result->fattr);
1984 if (unlikely(error))
1985 goto out;
1986 if (status != NFS3_OK)
1987 goto out_status;
1988 error = decode_read3resok(&xdr, result);
1989out:
1990 return error;
1991out_status:
1992 return nfs_stat_to_errno(status);
1993}
1994
1995/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001996 * Decode WRITE response
1997 */
1998static int
Al Virod61005a2006-10-19 23:28:48 -07001999nfs3_xdr_writeres(struct rpc_rqst *req, __be32 *p, struct nfs_writeres *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002000{
2001 int status;
2002
2003 status = ntohl(*p++);
2004 p = xdr_decode_wcc_data(p, res->fattr);
2005
2006 if (status != 0)
Benny Halevy856dff32008-03-31 17:39:06 +03002007 return nfs_stat_to_errno(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002008
2009 res->count = ntohl(*p++);
2010 res->verf->committed = (enum nfs3_stable_how)ntohl(*p++);
2011 res->verf->verifier[0] = *p++;
2012 res->verf->verifier[1] = *p++;
2013
2014 return res->count;
2015}
2016
2017/*
Chuck Levere4f93232010-12-14 14:56:30 +00002018 * 3.3.7 WRITE3res
2019 *
2020 * enum stable_how {
2021 * UNSTABLE = 0,
2022 * DATA_SYNC = 1,
2023 * FILE_SYNC = 2
2024 * };
2025 *
2026 * struct WRITE3resok {
2027 * wcc_data file_wcc;
2028 * count3 count;
2029 * stable_how committed;
2030 * writeverf3 verf;
2031 * };
2032 *
2033 * struct WRITE3resfail {
2034 * wcc_data file_wcc;
2035 * };
2036 *
2037 * union WRITE3res switch (nfsstat3 status) {
2038 * case NFS3_OK:
2039 * WRITE3resok resok;
2040 * default:
2041 * WRITE3resfail resfail;
2042 * };
2043 */
2044static int decode_write3resok(struct xdr_stream *xdr,
2045 struct nfs_writeres *result)
2046{
2047 __be32 *p;
2048
2049 p = xdr_inline_decode(xdr, 4 + 4 + NFS3_WRITEVERFSIZE);
2050 if (unlikely(p == NULL))
2051 goto out_overflow;
2052 result->count = be32_to_cpup(p++);
2053 result->verf->committed = be32_to_cpup(p++);
2054 if (unlikely(result->verf->committed > NFS_FILE_SYNC))
2055 goto out_badvalue;
2056 memcpy(result->verf->verifier, p, NFS3_WRITEVERFSIZE);
2057 return result->count;
2058out_badvalue:
2059 dprintk("NFS: bad stable_how value: %u\n", result->verf->committed);
2060 return -EIO;
2061out_overflow:
2062 print_overflow_msg(__func__, xdr);
2063 return -EIO;
2064}
2065
2066static int nfs3_xdr_dec_write3res(struct rpc_rqst *req, __be32 *p,
2067 struct nfs_writeres *result)
2068{
2069 struct xdr_stream xdr;
2070 enum nfs_stat status;
2071 int error;
2072
2073 xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
2074 error = decode_nfsstat3(&xdr, &status);
2075 if (unlikely(error))
2076 goto out;
2077 error = decode_wcc_data(&xdr, result->fattr);
2078 if (unlikely(error))
2079 goto out;
2080 if (status != NFS3_OK)
2081 goto out_status;
2082 error = decode_write3resok(&xdr, result);
2083out:
2084 return error;
2085out_status:
2086 return nfs_stat_to_errno(status);
2087}
2088
2089/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002090 * Decode a CREATE response
2091 */
2092static int
Al Virod61005a2006-10-19 23:28:48 -07002093nfs3_xdr_createres(struct rpc_rqst *req, __be32 *p, struct nfs3_diropres *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002094{
2095 int status;
2096
2097 status = ntohl(*p++);
2098 if (status == 0) {
2099 if (*p++) {
2100 if (!(p = xdr_decode_fhandle(p, res->fh)))
2101 return -errno_NFSERR_IO;
2102 p = xdr_decode_post_op_attr(p, res->fattr);
2103 } else {
2104 memset(res->fh, 0, sizeof(*res->fh));
2105 /* Do decode post_op_attr but set it to NULL */
2106 p = xdr_decode_post_op_attr(p, res->fattr);
2107 res->fattr->valid = 0;
2108 }
2109 } else {
Benny Halevy856dff32008-03-31 17:39:06 +03002110 status = nfs_stat_to_errno(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002111 }
2112 p = xdr_decode_wcc_data(p, res->dir_attr);
2113 return status;
2114}
2115
2116/*
Chuck Levere4f93232010-12-14 14:56:30 +00002117 * 3.3.8 CREATE3res
2118 *
2119 * struct CREATE3resok {
2120 * post_op_fh3 obj;
2121 * post_op_attr obj_attributes;
2122 * wcc_data dir_wcc;
2123 * };
2124 *
2125 * struct CREATE3resfail {
2126 * wcc_data dir_wcc;
2127 * };
2128 *
2129 * union CREATE3res switch (nfsstat3 status) {
2130 * case NFS3_OK:
2131 * CREATE3resok resok;
2132 * default:
2133 * CREATE3resfail resfail;
2134 * };
2135 */
2136static int decode_create3resok(struct xdr_stream *xdr,
2137 struct nfs3_diropres *result)
2138{
2139 int error;
2140
2141 error = decode_post_op_fh3(xdr, result->fh);
2142 if (unlikely(error))
2143 goto out;
2144 error = decode_post_op_attr(xdr, result->fattr);
2145 if (unlikely(error))
2146 goto out;
2147 /* The server isn't required to return a file handle.
2148 * If it didn't, force the client to perform a LOOKUP
2149 * to determine the correct file handle and attribute
2150 * values for the new object. */
2151 if (result->fh->size == 0)
2152 result->fattr->valid = 0;
2153 error = decode_wcc_data(xdr, result->dir_attr);
2154out:
2155 return error;
2156}
2157
2158static int nfs3_xdr_dec_create3res(struct rpc_rqst *req, __be32 *p,
2159 struct nfs3_diropres *result)
2160{
2161 struct xdr_stream xdr;
2162 enum nfs_stat status;
2163 int error;
2164
2165 xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
2166 error = decode_nfsstat3(&xdr, &status);
2167 if (unlikely(error))
2168 goto out;
2169 if (status != NFS3_OK)
2170 goto out_default;
2171 error = decode_create3resok(&xdr, result);
2172out:
2173 return error;
2174out_default:
2175 error = decode_wcc_data(&xdr, result->dir_attr);
2176 if (unlikely(error))
2177 goto out;
2178 return nfs_stat_to_errno(status);
2179}
2180
2181/*
2182 * 3.3.12 REMOVE3res
2183 *
2184 * struct REMOVE3resok {
2185 * wcc_data dir_wcc;
2186 * };
2187 *
2188 * struct REMOVE3resfail {
2189 * wcc_data dir_wcc;
2190 * };
2191 *
2192 * union REMOVE3res switch (nfsstat3 status) {
2193 * case NFS3_OK:
2194 * REMOVE3resok resok;
2195 * default:
2196 * REMOVE3resfail resfail;
2197 * };
2198 */
2199static int nfs3_xdr_dec_remove3res(struct rpc_rqst *req, __be32 *p,
2200 struct nfs_removeres *result)
2201{
2202 struct xdr_stream xdr;
2203 enum nfs_stat status;
2204 int error;
2205
2206 xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
2207 error = decode_nfsstat3(&xdr, &status);
2208 if (unlikely(error))
2209 goto out;
2210 error = decode_wcc_data(&xdr, result->dir_attr);
2211 if (unlikely(error))
2212 goto out;
2213 if (status != NFS3_OK)
2214 goto out_status;
2215out:
2216 return error;
2217out_status:
2218 return nfs_stat_to_errno(status);
2219}
2220
2221/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002222 * Decode RENAME reply
2223 */
2224static int
Jeff Laytone8582a82010-09-17 17:31:06 -04002225nfs3_xdr_renameres(struct rpc_rqst *req, __be32 *p, struct nfs_renameres *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002226{
2227 int status;
2228
2229 if ((status = ntohl(*p++)) != 0)
Benny Halevy856dff32008-03-31 17:39:06 +03002230 status = nfs_stat_to_errno(status);
Jeff Laytone8582a82010-09-17 17:31:06 -04002231 p = xdr_decode_wcc_data(p, res->old_fattr);
2232 p = xdr_decode_wcc_data(p, res->new_fattr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002233 return status;
2234}
2235
2236/*
Chuck Levere4f93232010-12-14 14:56:30 +00002237 * 3.3.14 RENAME3res
2238 *
2239 * struct RENAME3resok {
2240 * wcc_data fromdir_wcc;
2241 * wcc_data todir_wcc;
2242 * };
2243 *
2244 * struct RENAME3resfail {
2245 * wcc_data fromdir_wcc;
2246 * wcc_data todir_wcc;
2247 * };
2248 *
2249 * union RENAME3res switch (nfsstat3 status) {
2250 * case NFS3_OK:
2251 * RENAME3resok resok;
2252 * default:
2253 * RENAME3resfail resfail;
2254 * };
2255 */
2256static int nfs3_xdr_dec_rename3res(struct rpc_rqst *req, __be32 *p,
2257 struct nfs_renameres *result)
2258{
2259 struct xdr_stream xdr;
2260 enum nfs_stat status;
2261 int error;
2262
2263 xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
2264 error = decode_nfsstat3(&xdr, &status);
2265 if (unlikely(error))
2266 goto out;
2267 error = decode_wcc_data(&xdr, result->old_fattr);
2268 if (unlikely(error))
2269 goto out;
2270 error = decode_wcc_data(&xdr, result->new_fattr);
2271 if (unlikely(error))
2272 goto out;
2273 if (status != NFS3_OK)
2274 goto out_status;
2275out:
2276 return error;
2277out_status:
2278 return nfs_stat_to_errno(status);
2279}
2280
2281/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002282 * Decode LINK reply
2283 */
2284static int
Al Virod61005a2006-10-19 23:28:48 -07002285nfs3_xdr_linkres(struct rpc_rqst *req, __be32 *p, struct nfs3_linkres *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002286{
2287 int status;
2288
2289 if ((status = ntohl(*p++)) != 0)
Benny Halevy856dff32008-03-31 17:39:06 +03002290 status = nfs_stat_to_errno(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002291 p = xdr_decode_post_op_attr(p, res->fattr);
2292 p = xdr_decode_wcc_data(p, res->dir_attr);
2293 return status;
2294}
2295
2296/*
Chuck Levere4f93232010-12-14 14:56:30 +00002297 * 3.3.15 LINK3res
2298 *
2299 * struct LINK3resok {
2300 * post_op_attr file_attributes;
2301 * wcc_data linkdir_wcc;
2302 * };
2303 *
2304 * struct LINK3resfail {
2305 * post_op_attr file_attributes;
2306 * wcc_data linkdir_wcc;
2307 * };
2308 *
2309 * union LINK3res switch (nfsstat3 status) {
2310 * case NFS3_OK:
2311 * LINK3resok resok;
2312 * default:
2313 * LINK3resfail resfail;
2314 * };
2315 */
2316static int nfs3_xdr_dec_link3res(struct rpc_rqst *req, __be32 *p,
2317 struct nfs3_linkres *result)
2318{
2319 struct xdr_stream xdr;
2320 enum nfs_stat status;
2321 int error;
2322
2323 xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
2324 error = decode_nfsstat3(&xdr, &status);
2325 if (unlikely(error))
2326 goto out;
2327 error = decode_post_op_attr(&xdr, result->fattr);
2328 if (unlikely(error))
2329 goto out;
2330 error = decode_wcc_data(&xdr, result->dir_attr);
2331 if (unlikely(error))
2332 goto out;
2333 if (status != NFS3_OK)
2334 goto out_status;
2335out:
2336 return error;
2337out_status:
2338 return nfs_stat_to_errno(status);
2339}
2340
2341/**
2342 * nfs3_decode_dirent - Decode a single NFSv3 directory entry stored in
2343 * the local page cache
2344 * @xdr: XDR stream where entry resides
2345 * @entry: buffer to fill in with entry data
2346 * @server: nfs_server data for this directory
2347 * @plus: boolean indicating whether this should be a readdirplus entry
2348 *
2349 * Returns the position of the next item in the buffer, or an ERR_PTR.
2350 *
2351 * This function is not invoked during READDIR reply decoding, but
2352 * rather whenever an application invokes the getdents(2) system call
2353 * on a directory already in our cache.
2354 *
2355 * 3.3.16 entry3
2356 *
2357 * struct entry3 {
2358 * fileid3 fileid;
2359 * filename3 name;
2360 * cookie3 cookie;
2361 * fhandle3 filehandle;
2362 * post_op_attr3 attributes;
2363 * entry3 *nextentry;
2364 * };
2365 *
2366 * 3.3.17 entryplus3
2367 * struct entryplus3 {
2368 * fileid3 fileid;
2369 * filename3 name;
2370 * cookie3 cookie;
2371 * post_op_attr name_attributes;
2372 * post_op_fh3 name_handle;
2373 * entryplus3 *nextentry;
2374 * };
2375 */
2376__be32 *nfs3_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry,
2377 struct nfs_server *server, int plus)
2378{
2379 struct nfs_entry old = *entry;
2380 __be32 *p;
2381 int error;
2382
2383 p = xdr_inline_decode(xdr, 4);
2384 if (unlikely(p == NULL))
2385 goto out_overflow;
2386 if (*p == xdr_zero) {
2387 p = xdr_inline_decode(xdr, 4);
2388 if (unlikely(p == NULL))
2389 goto out_overflow;
2390 if (*p == xdr_zero)
2391 return ERR_PTR(-EAGAIN);
2392 entry->eof = 1;
2393 return ERR_PTR(-EBADCOOKIE);
2394 }
2395
2396 error = decode_fileid3(xdr, &entry->ino);
2397 if (unlikely(error))
2398 return ERR_PTR(error);
2399
2400 error = decode_inline_filename3(xdr, &entry->name, &entry->len);
2401 if (unlikely(error))
2402 return ERR_PTR(error);
2403
2404 entry->prev_cookie = entry->cookie;
2405 error = decode_cookie3(xdr, &entry->cookie);
2406 if (unlikely(error))
2407 return ERR_PTR(error);
2408
2409 entry->d_type = DT_UNKNOWN;
2410
2411 if (plus) {
2412 entry->fattr->valid = 0;
2413 error = decode_post_op_attr(xdr, entry->fattr);
2414 if (unlikely(error))
2415 return ERR_PTR(error);
2416 if (entry->fattr->valid & NFS_ATTR_FATTR_V3)
2417 entry->d_type = nfs_umode_to_dtype(entry->fattr->mode);
2418
2419 /* In fact, a post_op_fh3: */
2420 p = xdr_inline_decode(xdr, 4);
2421 if (unlikely(p == NULL))
2422 goto out_overflow;
2423 if (*p != xdr_zero) {
2424 error = decode_nfs_fh3(xdr, entry->fh);
2425 if (unlikely(error)) {
2426 if (error == -E2BIG)
2427 goto out_truncated;
2428 return ERR_PTR(error);
2429 }
2430 } else
2431 zero_nfs_fh3(entry->fh);
2432 }
2433
2434 /* Peek at the next entry to see if we're at EOD */
2435 p = xdr_inline_peek(xdr, 4 + 4);
2436 entry->eof = 0;
2437 if (p != NULL)
2438 entry->eof = (p[0] == xdr_zero) && (p[1] != xdr_zero);
2439 return p;
2440
2441out_overflow:
2442 print_overflow_msg(__func__, xdr);
2443 return ERR_PTR(-EAGAIN);
2444out_truncated:
2445 dprintk("NFS: directory entry contains invalid file handle\n");
2446 *entry = old;
2447 return ERR_PTR(-EAGAIN);
2448}
2449
2450/*
2451 * 3.3.16 READDIR3res
2452 *
2453 * struct dirlist3 {
2454 * entry3 *entries;
2455 * bool eof;
2456 * };
2457 *
2458 * struct READDIR3resok {
2459 * post_op_attr dir_attributes;
2460 * cookieverf3 cookieverf;
2461 * dirlist3 reply;
2462 * };
2463 *
2464 * struct READDIR3resfail {
2465 * post_op_attr dir_attributes;
2466 * };
2467 *
2468 * union READDIR3res switch (nfsstat3 status) {
2469 * case NFS3_OK:
2470 * READDIR3resok resok;
2471 * default:
2472 * READDIR3resfail resfail;
2473 * };
2474 *
2475 * Read the directory contents into the page cache, but otherwise
2476 * don't touch them. The actual decoding is done by nfs3_decode_entry()
2477 * during subsequent nfs_readdir() calls.
2478 */
2479static int decode_dirlist3(struct xdr_stream *xdr)
2480{
2481 u32 recvd, pglen;
2482 size_t hdrlen;
2483
2484 pglen = xdr->buf->page_len;
2485 hdrlen = (u8 *)xdr->p - (u8 *)xdr->iov->iov_base;
2486 recvd = xdr->buf->len - hdrlen;
2487 if (unlikely(pglen > recvd))
2488 goto out_cheating;
2489out:
2490 xdr_read_pages(xdr, pglen);
2491 return pglen;
2492out_cheating:
2493 dprintk("NFS: server cheating in readdir result: "
2494 "pglen %u > recvd %u\n", pglen, recvd);
2495 pglen = recvd;
2496 goto out;
2497}
2498
2499static int decode_readdir3resok(struct xdr_stream *xdr,
2500 struct nfs3_readdirres *result)
2501{
2502 int error;
2503
2504 error = decode_post_op_attr(xdr, result->dir_attr);
2505 if (unlikely(error))
2506 goto out;
2507 /* XXX: do we need to check if result->verf != NULL ? */
2508 error = decode_cookieverf3(xdr, result->verf);
2509 if (unlikely(error))
2510 goto out;
2511 error = decode_dirlist3(xdr);
2512out:
2513 return error;
2514}
2515
2516static int nfs3_xdr_dec_readdir3res(struct rpc_rqst *req, __be32 *p,
2517 struct nfs3_readdirres *result)
2518{
2519 struct xdr_stream xdr;
2520 enum nfs_stat status;
2521 int error;
2522
2523 xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
2524 error = decode_nfsstat3(&xdr, &status);
2525 if (unlikely(error))
2526 goto out;
2527 if (status != NFS3_OK)
2528 goto out_default;
2529 error = decode_readdir3resok(&xdr, result);
2530out:
2531 return error;
2532out_default:
2533 error = decode_post_op_attr(&xdr, result->dir_attr);
2534 if (unlikely(error))
2535 goto out;
2536 return nfs_stat_to_errno(status);
2537}
2538
2539/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002540 * Decode FSSTAT reply
2541 */
2542static int
Al Virod61005a2006-10-19 23:28:48 -07002543nfs3_xdr_fsstatres(struct rpc_rqst *req, __be32 *p, struct nfs_fsstat *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002544{
2545 int status;
2546
2547 status = ntohl(*p++);
2548
2549 p = xdr_decode_post_op_attr(p, res->fattr);
2550 if (status != 0)
Benny Halevy856dff32008-03-31 17:39:06 +03002551 return nfs_stat_to_errno(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002552
2553 p = xdr_decode_hyper(p, &res->tbytes);
2554 p = xdr_decode_hyper(p, &res->fbytes);
2555 p = xdr_decode_hyper(p, &res->abytes);
2556 p = xdr_decode_hyper(p, &res->tfiles);
2557 p = xdr_decode_hyper(p, &res->ffiles);
2558 p = xdr_decode_hyper(p, &res->afiles);
2559
2560 /* ignore invarsec */
2561 return 0;
2562}
2563
2564/*
Chuck Levere4f93232010-12-14 14:56:30 +00002565 * 3.3.18 FSSTAT3res
2566 *
2567 * struct FSSTAT3resok {
2568 * post_op_attr obj_attributes;
2569 * size3 tbytes;
2570 * size3 fbytes;
2571 * size3 abytes;
2572 * size3 tfiles;
2573 * size3 ffiles;
2574 * size3 afiles;
2575 * uint32 invarsec;
2576 * };
2577 *
2578 * struct FSSTAT3resfail {
2579 * post_op_attr obj_attributes;
2580 * };
2581 *
2582 * union FSSTAT3res switch (nfsstat3 status) {
2583 * case NFS3_OK:
2584 * FSSTAT3resok resok;
2585 * default:
2586 * FSSTAT3resfail resfail;
2587 * };
2588 */
2589static int decode_fsstat3resok(struct xdr_stream *xdr,
2590 struct nfs_fsstat *result)
2591{
2592 __be32 *p;
2593
2594 p = xdr_inline_decode(xdr, 8 * 6 + 4);
2595 if (unlikely(p == NULL))
2596 goto out_overflow;
2597 p = xdr_decode_size3(p, &result->tbytes);
2598 p = xdr_decode_size3(p, &result->fbytes);
2599 p = xdr_decode_size3(p, &result->abytes);
2600 p = xdr_decode_size3(p, &result->tfiles);
2601 p = xdr_decode_size3(p, &result->ffiles);
2602 xdr_decode_size3(p, &result->afiles);
2603 /* ignore invarsec */
2604 return 0;
2605out_overflow:
2606 print_overflow_msg(__func__, xdr);
2607 return -EIO;
2608}
2609
2610static int nfs3_xdr_dec_fsstat3res(struct rpc_rqst *req, __be32 *p,
2611 struct nfs_fsstat *result)
2612{
2613 struct xdr_stream xdr;
2614 enum nfs_stat status;
2615 int error;
2616
2617 xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
2618 error = decode_nfsstat3(&xdr, &status);
2619 if (unlikely(error))
2620 goto out;
2621 error = decode_post_op_attr(&xdr, result->fattr);
2622 if (unlikely(error))
2623 goto out;
2624 if (status != NFS3_OK)
2625 goto out_status;
2626 error = decode_fsstat3resok(&xdr, result);
2627out:
2628 return error;
2629out_status:
2630 return nfs_stat_to_errno(status);
2631}
2632
2633/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002634 * Decode FSINFO reply
2635 */
2636static int
Al Virod61005a2006-10-19 23:28:48 -07002637nfs3_xdr_fsinfores(struct rpc_rqst *req, __be32 *p, struct nfs_fsinfo *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002638{
2639 int status;
2640
2641 status = ntohl(*p++);
2642
2643 p = xdr_decode_post_op_attr(p, res->fattr);
2644 if (status != 0)
Benny Halevy856dff32008-03-31 17:39:06 +03002645 return nfs_stat_to_errno(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002646
2647 res->rtmax = ntohl(*p++);
2648 res->rtpref = ntohl(*p++);
2649 res->rtmult = ntohl(*p++);
2650 res->wtmax = ntohl(*p++);
2651 res->wtpref = ntohl(*p++);
2652 res->wtmult = ntohl(*p++);
2653 res->dtpref = ntohl(*p++);
2654 p = xdr_decode_hyper(p, &res->maxfilesize);
Ricardo Labiaga6b967242010-10-12 16:30:05 -07002655 p = xdr_decode_time3(p, &res->time_delta);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002656
Ricardo Labiaga6b967242010-10-12 16:30:05 -07002657 /* ignore properties */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002658 res->lease_time = 0;
2659 return 0;
2660}
2661
2662/*
Chuck Levere4f93232010-12-14 14:56:30 +00002663 * 3.3.19 FSINFO3res
2664 *
2665 * struct FSINFO3resok {
2666 * post_op_attr obj_attributes;
2667 * uint32 rtmax;
2668 * uint32 rtpref;
2669 * uint32 rtmult;
2670 * uint32 wtmax;
2671 * uint32 wtpref;
2672 * uint32 wtmult;
2673 * uint32 dtpref;
2674 * size3 maxfilesize;
2675 * nfstime3 time_delta;
2676 * uint32 properties;
2677 * };
2678 *
2679 * struct FSINFO3resfail {
2680 * post_op_attr obj_attributes;
2681 * };
2682 *
2683 * union FSINFO3res switch (nfsstat3 status) {
2684 * case NFS3_OK:
2685 * FSINFO3resok resok;
2686 * default:
2687 * FSINFO3resfail resfail;
2688 * };
2689 */
2690static int decode_fsinfo3resok(struct xdr_stream *xdr,
2691 struct nfs_fsinfo *result)
2692{
2693 __be32 *p;
2694
2695 p = xdr_inline_decode(xdr, 4 * 7 + 8 + 8 + 4);
2696 if (unlikely(p == NULL))
2697 goto out_overflow;
2698 result->rtmax = be32_to_cpup(p++);
2699 result->rtpref = be32_to_cpup(p++);
2700 result->rtmult = be32_to_cpup(p++);
2701 result->wtmax = be32_to_cpup(p++);
2702 result->wtpref = be32_to_cpup(p++);
2703 result->wtmult = be32_to_cpup(p++);
2704 result->dtpref = be32_to_cpup(p++);
2705 p = xdr_decode_size3(p, &result->maxfilesize);
2706 xdr_decode_time3(p, &result->time_delta);
2707
2708 /* ignore properties */
2709 result->lease_time = 0;
2710 return 0;
2711out_overflow:
2712 print_overflow_msg(__func__, xdr);
2713 return -EIO;
2714}
2715
2716static int nfs3_xdr_dec_fsinfo3res(struct rpc_rqst *req, __be32 *p,
2717 struct nfs_fsinfo *result)
2718{
2719 struct xdr_stream xdr;
2720 enum nfs_stat status;
2721 int error;
2722
2723 xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
2724 error = decode_nfsstat3(&xdr, &status);
2725 if (unlikely(error))
2726 goto out;
2727 error = decode_post_op_attr(&xdr, result->fattr);
2728 if (unlikely(error))
2729 goto out;
2730 if (status != NFS3_OK)
2731 goto out_status;
2732 error = decode_fsinfo3resok(&xdr, result);
2733out:
2734 return error;
2735out_status:
2736 return nfs_stat_to_errno(status);
2737}
2738
2739/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002740 * Decode PATHCONF reply
2741 */
2742static int
Al Virod61005a2006-10-19 23:28:48 -07002743nfs3_xdr_pathconfres(struct rpc_rqst *req, __be32 *p, struct nfs_pathconf *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002744{
2745 int status;
2746
2747 status = ntohl(*p++);
2748
2749 p = xdr_decode_post_op_attr(p, res->fattr);
2750 if (status != 0)
Benny Halevy856dff32008-03-31 17:39:06 +03002751 return nfs_stat_to_errno(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002752 res->max_link = ntohl(*p++);
2753 res->max_namelen = ntohl(*p++);
2754
2755 /* ignore remaining fields */
2756 return 0;
2757}
2758
2759/*
Chuck Levere4f93232010-12-14 14:56:30 +00002760 * 3.3.20 PATHCONF3res
2761 *
2762 * struct PATHCONF3resok {
2763 * post_op_attr obj_attributes;
2764 * uint32 linkmax;
2765 * uint32 name_max;
2766 * bool no_trunc;
2767 * bool chown_restricted;
2768 * bool case_insensitive;
2769 * bool case_preserving;
2770 * };
2771 *
2772 * struct PATHCONF3resfail {
2773 * post_op_attr obj_attributes;
2774 * };
2775 *
2776 * union PATHCONF3res switch (nfsstat3 status) {
2777 * case NFS3_OK:
2778 * PATHCONF3resok resok;
2779 * default:
2780 * PATHCONF3resfail resfail;
2781 * };
2782 */
2783static int decode_pathconf3resok(struct xdr_stream *xdr,
2784 struct nfs_pathconf *result)
2785{
2786 __be32 *p;
2787
2788 p = xdr_inline_decode(xdr, 4 * 6);
2789 if (unlikely(p == NULL))
2790 goto out_overflow;
2791 result->max_link = be32_to_cpup(p++);
2792 result->max_namelen = be32_to_cpup(p);
2793 /* ignore remaining fields */
2794 return 0;
2795out_overflow:
2796 print_overflow_msg(__func__, xdr);
2797 return -EIO;
2798}
2799
2800static int nfs3_xdr_dec_pathconf3res(struct rpc_rqst *req, __be32 *p,
2801 struct nfs_pathconf *result)
2802{
2803 struct xdr_stream xdr;
2804 enum nfs_stat status;
2805 int error;
2806
2807 xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
2808 error = decode_nfsstat3(&xdr, &status);
2809 if (unlikely(error))
2810 goto out;
2811 error = decode_post_op_attr(&xdr, result->fattr);
2812 if (unlikely(error))
2813 goto out;
2814 if (status != NFS3_OK)
2815 goto out_status;
2816 error = decode_pathconf3resok(&xdr, result);
2817out:
2818 return error;
2819out_status:
2820 return nfs_stat_to_errno(status);
2821}
2822
2823/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002824 * Decode COMMIT reply
2825 */
2826static int
Al Virod61005a2006-10-19 23:28:48 -07002827nfs3_xdr_commitres(struct rpc_rqst *req, __be32 *p, struct nfs_writeres *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002828{
2829 int status;
2830
2831 status = ntohl(*p++);
2832 p = xdr_decode_wcc_data(p, res->fattr);
2833 if (status != 0)
Benny Halevy856dff32008-03-31 17:39:06 +03002834 return nfs_stat_to_errno(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002835
2836 res->verf->verifier[0] = *p++;
2837 res->verf->verifier[1] = *p++;
2838 return 0;
2839}
2840
Chuck Levere4f93232010-12-14 14:56:30 +00002841/*
2842 * 3.3.21 COMMIT3res
2843 *
2844 * struct COMMIT3resok {
2845 * wcc_data file_wcc;
2846 * writeverf3 verf;
2847 * };
2848 *
2849 * struct COMMIT3resfail {
2850 * wcc_data file_wcc;
2851 * };
2852 *
2853 * union COMMIT3res switch (nfsstat3 status) {
2854 * case NFS3_OK:
2855 * COMMIT3resok resok;
2856 * default:
2857 * COMMIT3resfail resfail;
2858 * };
2859 */
2860static int nfs3_xdr_dec_commit3res(struct rpc_rqst *req, __be32 *p,
2861 struct nfs_writeres *result)
2862{
2863 struct xdr_stream xdr;
2864 enum nfs_stat status;
2865 int error;
2866
2867 xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
2868 error = decode_nfsstat3(&xdr, &status);
2869 if (unlikely(error))
2870 goto out;
2871 error = decode_wcc_data(&xdr, result->fattr);
2872 if (unlikely(error))
2873 goto out;
2874 if (status != NFS3_OK)
2875 goto out_status;
2876 error = decode_writeverf3(&xdr, result->verf->verifier);
2877out:
2878 return error;
2879out_status:
2880 return nfs_stat_to_errno(status);
2881}
2882
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +00002883#ifdef CONFIG_NFS_V3_ACL
2884/*
2885 * Decode GETACL reply
2886 */
2887static int
Al Virod61005a2006-10-19 23:28:48 -07002888nfs3_xdr_getaclres(struct rpc_rqst *req, __be32 *p,
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +00002889 struct nfs3_getaclres *res)
2890{
2891 struct xdr_buf *buf = &req->rq_rcv_buf;
2892 int status = ntohl(*p++);
2893 struct posix_acl **acl;
2894 unsigned int *aclcnt;
2895 int err, base;
2896
2897 if (status != 0)
Benny Halevy856dff32008-03-31 17:39:06 +03002898 return nfs_stat_to_errno(status);
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +00002899 p = xdr_decode_post_op_attr(p, res->fattr);
2900 res->mask = ntohl(*p++);
2901 if (res->mask & ~(NFS_ACL|NFS_ACLCNT|NFS_DFACL|NFS_DFACLCNT))
2902 return -EINVAL;
2903 base = (char *)p - (char *)req->rq_rcv_buf.head->iov_base;
2904
2905 acl = (res->mask & NFS_ACL) ? &res->acl_access : NULL;
2906 aclcnt = (res->mask & NFS_ACLCNT) ? &res->acl_access_count : NULL;
2907 err = nfsacl_decode(buf, base, aclcnt, acl);
2908
2909 acl = (res->mask & NFS_DFACL) ? &res->acl_default : NULL;
2910 aclcnt = (res->mask & NFS_DFACLCNT) ? &res->acl_default_count : NULL;
2911 if (err > 0)
2912 err = nfsacl_decode(buf, base + err, aclcnt, acl);
2913 return (err > 0) ? 0 : err;
2914}
2915
Chuck Levere4f93232010-12-14 14:56:30 +00002916static inline int decode_getacl3resok(struct xdr_stream *xdr,
2917 struct nfs3_getaclres *result)
2918{
2919 struct posix_acl **acl;
2920 unsigned int *aclcnt;
2921 size_t hdrlen;
2922 int error;
2923
2924 error = decode_post_op_attr(xdr, result->fattr);
2925 if (unlikely(error))
2926 goto out;
2927 error = decode_uint32(xdr, &result->mask);
2928 if (unlikely(error))
2929 goto out;
2930 error = -EINVAL;
2931 if (result->mask & ~(NFS_ACL|NFS_ACLCNT|NFS_DFACL|NFS_DFACLCNT))
2932 goto out;
2933
2934 hdrlen = (u8 *)xdr->p - (u8 *)xdr->iov->iov_base;
2935
2936 acl = NULL;
2937 if (result->mask & NFS_ACL)
2938 acl = &result->acl_access;
2939 aclcnt = NULL;
2940 if (result->mask & NFS_ACLCNT)
2941 aclcnt = &result->acl_access_count;
2942 error = nfsacl_decode(xdr->buf, hdrlen, aclcnt, acl);
2943 if (unlikely(error <= 0))
2944 goto out;
2945
2946 acl = NULL;
2947 if (result->mask & NFS_DFACL)
2948 acl = &result->acl_default;
2949 aclcnt = NULL;
2950 if (result->mask & NFS_DFACLCNT)
2951 aclcnt = &result->acl_default_count;
2952 error = nfsacl_decode(xdr->buf, hdrlen + error, aclcnt, acl);
2953 if (unlikely(error <= 0))
2954 return error;
2955 error = 0;
2956out:
2957 return error;
2958}
2959
2960static int nfs3_xdr_dec_getacl3res(struct rpc_rqst *req, __be32 *p,
2961 struct nfs3_getaclres *result)
2962{
2963 struct xdr_stream xdr;
2964 enum nfs_stat status;
2965 int error;
2966
2967 xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
2968 error = decode_nfsstat3(&xdr, &status);
2969 if (unlikely(error))
2970 goto out;
2971 if (status != NFS3_OK)
2972 goto out_default;
2973 error = decode_getacl3resok(&xdr, result);
2974out:
2975 return error;
2976out_default:
2977 return nfs_stat_to_errno(status);
2978}
2979
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +00002980/*
2981 * Decode setacl reply.
2982 */
2983static int
Al Virod61005a2006-10-19 23:28:48 -07002984nfs3_xdr_setaclres(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +00002985{
2986 int status = ntohl(*p++);
2987
2988 if (status)
Benny Halevy856dff32008-03-31 17:39:06 +03002989 return nfs_stat_to_errno(status);
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +00002990 xdr_decode_post_op_attr(p, fattr);
2991 return 0;
2992}
Chuck Levere4f93232010-12-14 14:56:30 +00002993
2994static int nfs3_xdr_dec_setacl3res(struct rpc_rqst *req, __be32 *p,
2995 struct nfs_fattr *result)
2996{
2997 struct xdr_stream xdr;
2998 enum nfs_stat status;
2999 int error;
3000
3001 xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
3002 error = decode_nfsstat3(&xdr, &status);
3003 if (unlikely(error))
3004 goto out;
3005 if (status != NFS3_OK)
3006 goto out_default;
3007 error = decode_post_op_attr(&xdr, result);
3008out:
3009 return error;
3010out_default:
3011 return nfs_stat_to_errno(status);
3012}
3013
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +00003014#endif /* CONFIG_NFS_V3_ACL */
3015
Linus Torvalds1da177e2005-04-16 15:20:36 -07003016#define PROC(proc, argtype, restype, timer) \
3017[NFS3PROC_##proc] = { \
3018 .p_proc = NFS3PROC_##proc, \
Chuck Leverad96b5b2010-12-14 14:56:01 +00003019 .p_encode = (kxdrproc_t)nfs3_xdr_enc_##argtype##3args, \
Linus Torvalds1da177e2005-04-16 15:20:36 -07003020 .p_decode = (kxdrproc_t) nfs3_xdr_##restype, \
Chuck Leverad96b5b2010-12-14 14:56:01 +00003021 .p_arglen = NFS3_##argtype##args_sz, \
Chuck Lever2bea90d2007-03-29 16:47:53 -04003022 .p_replen = NFS3_##restype##_sz, \
Chuck Levercc0175c2006-03-20 13:44:22 -05003023 .p_timer = timer, \
3024 .p_statidx = NFS3PROC_##proc, \
3025 .p_name = #proc, \
Linus Torvalds1da177e2005-04-16 15:20:36 -07003026 }
3027
3028struct rpc_procinfo nfs3_procedures[] = {
Chuck Leverad96b5b2010-12-14 14:56:01 +00003029 PROC(GETATTR, getattr, attrstat, 1),
3030 PROC(SETATTR, setattr, wccstat, 0),
3031 PROC(LOOKUP, lookup, lookupres, 2),
3032 PROC(ACCESS, access, accessres, 1),
3033 PROC(READLINK, readlink, readlinkres, 3),
3034 PROC(READ, read, readres, 3),
3035 PROC(WRITE, write, writeres, 4),
3036 PROC(CREATE, create, createres, 0),
3037 PROC(MKDIR, mkdir, createres, 0),
3038 PROC(SYMLINK, symlink, createres, 0),
3039 PROC(MKNOD, mknod, createres, 0),
3040 PROC(REMOVE, remove, removeres, 0),
3041 PROC(RMDIR, lookup, wccstat, 0),
3042 PROC(RENAME, rename, renameres, 0),
3043 PROC(LINK, link, linkres, 0),
3044 PROC(READDIR, readdir, readdirres, 3),
3045 PROC(READDIRPLUS, readdirplus, readdirres, 3),
3046 PROC(FSSTAT, getattr, fsstatres, 0),
3047 PROC(FSINFO, getattr, fsinfores, 0),
3048 PROC(PATHCONF, getattr, pathconfres, 0),
3049 PROC(COMMIT, commit, commitres, 5),
Linus Torvalds1da177e2005-04-16 15:20:36 -07003050};
3051
3052struct rpc_version nfs_version3 = {
3053 .number = 3,
Tobias Klausere8c96f82006-03-24 03:15:34 -08003054 .nrprocs = ARRAY_SIZE(nfs3_procedures),
Linus Torvalds1da177e2005-04-16 15:20:36 -07003055 .procs = nfs3_procedures
3056};
3057
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +00003058#ifdef CONFIG_NFS_V3_ACL
3059static struct rpc_procinfo nfs3_acl_procedures[] = {
3060 [ACLPROC3_GETACL] = {
3061 .p_proc = ACLPROC3_GETACL,
Chuck Leverad96b5b2010-12-14 14:56:01 +00003062 .p_encode = (kxdrproc_t)nfs3_xdr_enc_getacl3args,
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +00003063 .p_decode = (kxdrproc_t) nfs3_xdr_getaclres,
Chuck Lever2bea90d2007-03-29 16:47:53 -04003064 .p_arglen = ACL3_getaclargs_sz,
3065 .p_replen = ACL3_getaclres_sz,
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +00003066 .p_timer = 1,
Chuck Levercc0175c2006-03-20 13:44:22 -05003067 .p_name = "GETACL",
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +00003068 },
3069 [ACLPROC3_SETACL] = {
3070 .p_proc = ACLPROC3_SETACL,
Chuck Leverad96b5b2010-12-14 14:56:01 +00003071 .p_encode = (kxdrproc_t)nfs3_xdr_enc_setacl3args,
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +00003072 .p_decode = (kxdrproc_t) nfs3_xdr_setaclres,
Chuck Lever2bea90d2007-03-29 16:47:53 -04003073 .p_arglen = ACL3_setaclargs_sz,
3074 .p_replen = ACL3_setaclres_sz,
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +00003075 .p_timer = 0,
Chuck Levercc0175c2006-03-20 13:44:22 -05003076 .p_name = "SETACL",
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +00003077 },
3078};
3079
3080struct rpc_version nfsacl_version3 = {
3081 .number = 3,
3082 .nrprocs = sizeof(nfs3_acl_procedures)/
3083 sizeof(nfs3_acl_procedures[0]),
3084 .procs = nfs3_acl_procedures,
3085};
3086#endif /* CONFIG_NFS_V3_ACL */