blob: 19c7911019283e733018ad54da2da0bde15fc824 [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)
Chuck Leverf5fc3c502010-12-14 14:56:42 +000041#define NFS3_wcc_attr_sz (6)
Linus Torvalds1da177e2005-04-16 15:20:36 -070042#define NFS3_pre_op_attr_sz (1+NFS3_wcc_attr_sz)
43#define NFS3_post_op_attr_sz (1+NFS3_fattr_sz)
Chuck Leverf5fc3c502010-12-14 14:56:42 +000044#define NFS3_wcc_data_sz (NFS3_pre_op_attr_sz+NFS3_post_op_attr_sz)
Linus Torvalds1da177e2005-04-16 15:20:36 -070045#define NFS3_diropargs_sz (NFS3_fh_sz+NFS3_filename_sz)
Chuck Leverad96b5b2010-12-14 14:56:01 +000046
47#define NFS3_getattrargs_sz (NFS3_fh_sz)
48#define NFS3_setattrargs_sz (NFS3_fh_sz+NFS3_sattr_sz+3)
49#define NFS3_lookupargs_sz (NFS3_fh_sz+NFS3_filename_sz)
Linus Torvalds1da177e2005-04-16 15:20:36 -070050#define NFS3_accessargs_sz (NFS3_fh_sz+1)
51#define NFS3_readlinkargs_sz (NFS3_fh_sz)
52#define NFS3_readargs_sz (NFS3_fh_sz+3)
53#define NFS3_writeargs_sz (NFS3_fh_sz+5)
54#define NFS3_createargs_sz (NFS3_diropargs_sz+NFS3_sattr_sz)
55#define NFS3_mkdirargs_sz (NFS3_diropargs_sz+NFS3_sattr_sz)
Chuck Lever94a6d752006-08-22 20:06:23 -040056#define NFS3_symlinkargs_sz (NFS3_diropargs_sz+1+NFS3_sattr_sz)
Linus Torvalds1da177e2005-04-16 15:20:36 -070057#define NFS3_mknodargs_sz (NFS3_diropargs_sz+2+NFS3_sattr_sz)
Chuck Leverad96b5b2010-12-14 14:56:01 +000058#define NFS3_removeargs_sz (NFS3_fh_sz+NFS3_filename_sz)
Linus Torvalds1da177e2005-04-16 15:20:36 -070059#define NFS3_renameargs_sz (NFS3_diropargs_sz+NFS3_diropargs_sz)
60#define NFS3_linkargs_sz (NFS3_fh_sz+NFS3_diropargs_sz)
Chuck Leverd9c407b2010-12-14 14:55:50 +000061#define NFS3_readdirargs_sz (NFS3_fh_sz+NFS3_cookieverf_sz+3)
62#define NFS3_readdirplusargs_sz (NFS3_fh_sz+NFS3_cookieverf_sz+4)
Linus Torvalds1da177e2005-04-16 15:20:36 -070063#define NFS3_commitargs_sz (NFS3_fh_sz+3)
64
Chuck Leverf5fc3c502010-12-14 14:56:42 +000065#define NFS3_getattrres_sz (1+NFS3_fattr_sz)
66#define NFS3_setattrres_sz (1+NFS3_wcc_data_sz)
67#define NFS3_removeres_sz (NFS3_setattrres_sz)
Linus Torvalds1da177e2005-04-16 15:20:36 -070068#define NFS3_lookupres_sz (1+NFS3_fh_sz+(2 * NFS3_post_op_attr_sz))
69#define NFS3_accessres_sz (1+NFS3_post_op_attr_sz+1)
70#define NFS3_readlinkres_sz (1+NFS3_post_op_attr_sz+1)
71#define NFS3_readres_sz (1+NFS3_post_op_attr_sz+3)
72#define NFS3_writeres_sz (1+NFS3_wcc_data_sz+4)
73#define NFS3_createres_sz (1+NFS3_fh_sz+NFS3_post_op_attr_sz+NFS3_wcc_data_sz)
74#define NFS3_renameres_sz (1+(2 * NFS3_wcc_data_sz))
75#define NFS3_linkres_sz (1+NFS3_post_op_attr_sz+NFS3_wcc_data_sz)
76#define NFS3_readdirres_sz (1+NFS3_post_op_attr_sz+2)
77#define NFS3_fsstatres_sz (1+NFS3_post_op_attr_sz+13)
78#define NFS3_fsinfores_sz (1+NFS3_post_op_attr_sz+12)
79#define NFS3_pathconfres_sz (1+NFS3_post_op_attr_sz+6)
80#define NFS3_commitres_sz (1+NFS3_wcc_data_sz+2)
81
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +000082#define ACL3_getaclargs_sz (NFS3_fh_sz+1)
Trond Myklebustae46141f2009-03-10 20:33:18 -040083#define ACL3_setaclargs_sz (NFS3_fh_sz+1+ \
84 XDR_QUADLEN(NFS_ACL_INLINE_BUFSIZE))
85#define ACL3_getaclres_sz (1+NFS3_post_op_attr_sz+1+ \
86 XDR_QUADLEN(NFS_ACL_INLINE_BUFSIZE))
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +000087#define ACL3_setaclres_sz (1+NFS3_post_op_attr_sz)
88
Linus Torvalds1da177e2005-04-16 15:20:36 -070089/*
90 * Map file type to S_IFMT bits
91 */
Trond Myklebustbca79472009-03-11 14:10:26 -040092static const umode_t nfs_type2fmt[] = {
93 [NF3BAD] = 0,
94 [NF3REG] = S_IFREG,
95 [NF3DIR] = S_IFDIR,
96 [NF3BLK] = S_IFBLK,
97 [NF3CHR] = S_IFCHR,
98 [NF3LNK] = S_IFLNK,
99 [NF3SOCK] = S_IFSOCK,
100 [NF3FIFO] = S_IFIFO,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700101};
102
103/*
Chuck Leverd9c407b2010-12-14 14:55:50 +0000104 * While encoding arguments, set up the reply buffer in advance to
105 * receive reply data directly into the page cache.
106 */
107static void prepare_reply_buffer(struct rpc_rqst *req, struct page **pages,
108 unsigned int base, unsigned int len,
109 unsigned int bufsize)
110{
111 struct rpc_auth *auth = req->rq_cred->cr_auth;
112 unsigned int replen;
113
114 replen = RPC_REPHDRSIZE + auth->au_rslack + bufsize;
115 xdr_inline_pages(&req->rq_rcv_buf, replen << 2, pages, base, len);
116}
117
Chuck Levere4f93232010-12-14 14:56:30 +0000118/*
119 * Handle decode buffer overflows out-of-line.
120 */
121static void print_overflow_msg(const char *func, const struct xdr_stream *xdr)
122{
123 dprintk("NFS: %s prematurely hit the end of our receive buffer. "
124 "Remaining buffer length is %tu words.\n",
125 func, xdr->end - xdr->p);
126}
127
Chuck Leverd9c407b2010-12-14 14:55:50 +0000128
129/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700130 * Common NFS XDR functions as inlines
131 */
Al Virod61005a2006-10-19 23:28:48 -0700132static inline __be32 *
Al Virod61005a2006-10-19 23:28:48 -0700133xdr_decode_fhandle(__be32 *p, struct nfs_fh *fh)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700134{
135 if ((fh->size = ntohl(*p++)) <= NFS3_FHSIZE) {
136 memcpy(fh->data, p, fh->size);
137 return p + XDR_QUADLEN(fh->size);
138 }
139 return NULL;
140}
141
Bryan Schumakerbabddc72010-10-20 15:44:29 -0400142static inline __be32 *
143xdr_decode_fhandle_stream(struct xdr_stream *xdr, struct nfs_fh *fh)
144{
145 __be32 *p;
146 p = xdr_inline_decode(xdr, 4);
147 if (unlikely(!p))
148 goto out_overflow;
149 fh->size = ntohl(*p++);
150
151 if (fh->size <= NFS3_FHSIZE) {
152 p = xdr_inline_decode(xdr, fh->size);
153 if (unlikely(!p))
154 goto out_overflow;
155 memcpy(fh->data, p, fh->size);
156 return p + XDR_QUADLEN(fh->size);
157 }
158 return NULL;
159
160out_overflow:
161 print_overflow_msg(__func__, xdr);
162 return ERR_PTR(-EIO);
163}
164
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165/*
166 * Encode/decode time.
167 */
Al Virod61005a2006-10-19 23:28:48 -0700168static inline __be32 *
Al Virod61005a2006-10-19 23:28:48 -0700169xdr_decode_time3(__be32 *p, struct timespec *timep)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700170{
171 timep->tv_sec = ntohl(*p++);
172 timep->tv_nsec = ntohl(*p++);
173 return p;
174}
175
Al Virod61005a2006-10-19 23:28:48 -0700176static __be32 *
177xdr_decode_fattr(__be32 *p, struct nfs_fattr *fattr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700178{
179 unsigned int type, major, minor;
Trond Myklebustbca79472009-03-11 14:10:26 -0400180 umode_t fmode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700181
182 type = ntohl(*p++);
Trond Myklebustbca79472009-03-11 14:10:26 -0400183 if (type > NF3FIFO)
184 type = NF3NON;
185 fmode = nfs_type2fmt[type];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700186 fattr->mode = (ntohl(*p++) & ~S_IFMT) | fmode;
187 fattr->nlink = ntohl(*p++);
188 fattr->uid = ntohl(*p++);
189 fattr->gid = ntohl(*p++);
190 p = xdr_decode_hyper(p, &fattr->size);
191 p = xdr_decode_hyper(p, &fattr->du.nfs3.used);
192
193 /* Turn remote device info into Linux-specific dev_t */
194 major = ntohl(*p++);
195 minor = ntohl(*p++);
196 fattr->rdev = MKDEV(major, minor);
197 if (MAJOR(fattr->rdev) != major || MINOR(fattr->rdev) != minor)
198 fattr->rdev = 0;
199
Trond Myklebust8b4bdcf2006-06-09 09:34:19 -0400200 p = xdr_decode_hyper(p, &fattr->fsid.major);
201 fattr->fsid.minor = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700202 p = xdr_decode_hyper(p, &fattr->fileid);
203 p = xdr_decode_time3(p, &fattr->atime);
204 p = xdr_decode_time3(p, &fattr->mtime);
205 p = xdr_decode_time3(p, &fattr->ctime);
206
207 /* Update the mode bits */
Trond Myklebust9e6e70f2009-03-11 14:10:24 -0400208 fattr->valid |= NFS_ATTR_FATTR_V3;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700209 return p;
210}
211
Al Virod61005a2006-10-19 23:28:48 -0700212static inline __be32 *
Al Virod61005a2006-10-19 23:28:48 -0700213xdr_decode_wcc_attr(__be32 *p, struct nfs_fattr *fattr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700214{
215 p = xdr_decode_hyper(p, &fattr->pre_size);
216 p = xdr_decode_time3(p, &fattr->pre_mtime);
217 p = xdr_decode_time3(p, &fattr->pre_ctime);
Trond Myklebust9e6e70f2009-03-11 14:10:24 -0400218 fattr->valid |= NFS_ATTR_FATTR_PRESIZE
219 | NFS_ATTR_FATTR_PREMTIME
220 | NFS_ATTR_FATTR_PRECTIME;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700221 return p;
222}
223
Al Virod61005a2006-10-19 23:28:48 -0700224static inline __be32 *
225xdr_decode_post_op_attr(__be32 *p, struct nfs_fattr *fattr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700226{
227 if (*p++)
228 p = xdr_decode_fattr(p, fattr);
229 return p;
230}
231
Al Virod61005a2006-10-19 23:28:48 -0700232static inline __be32 *
Bryan Schumakerbabddc72010-10-20 15:44:29 -0400233xdr_decode_post_op_attr_stream(struct xdr_stream *xdr, struct nfs_fattr *fattr)
234{
235 __be32 *p;
236
237 p = xdr_inline_decode(xdr, 4);
238 if (unlikely(!p))
239 goto out_overflow;
240 if (ntohl(*p++)) {
241 p = xdr_inline_decode(xdr, 84);
242 if (unlikely(!p))
243 goto out_overflow;
244 p = xdr_decode_fattr(p, fattr);
245 }
246 return p;
247out_overflow:
248 print_overflow_msg(__func__, xdr);
249 return ERR_PTR(-EIO);
250}
251
252static inline __be32 *
Al Virod61005a2006-10-19 23:28:48 -0700253xdr_decode_pre_op_attr(__be32 *p, struct nfs_fattr *fattr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700254{
255 if (*p++)
256 return xdr_decode_wcc_attr(p, fattr);
257 return p;
258}
259
260
Al Virod61005a2006-10-19 23:28:48 -0700261static inline __be32 *
262xdr_decode_wcc_data(__be32 *p, struct nfs_fattr *fattr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700263{
264 p = xdr_decode_pre_op_attr(p, fattr);
265 return xdr_decode_post_op_attr(p, fattr);
266}
267
Chuck Leverd9c407b2010-12-14 14:55:50 +0000268
269/*
270 * Encode/decode NFSv3 basic data types
271 *
272 * Basic NFSv3 data types are defined in section 2.5 of RFC 1813:
273 * "NFS Version 3 Protocol Specification".
274 *
275 * Not all basic data types have their own encoding and decoding
276 * functions. For run-time efficiency, some data types are encoded
277 * or decoded inline.
278 */
279
280static void encode_uint32(struct xdr_stream *xdr, u32 value)
281{
282 __be32 *p = xdr_reserve_space(xdr, 4);
283 *p = cpu_to_be32(value);
284}
285
Chuck Levere4f93232010-12-14 14:56:30 +0000286static int decode_uint32(struct xdr_stream *xdr, u32 *value)
287{
288 __be32 *p;
289
290 p = xdr_inline_decode(xdr, 4);
291 if (unlikely(p == NULL))
292 goto out_overflow;
293 *value = be32_to_cpup(p);
294 return 0;
295out_overflow:
296 print_overflow_msg(__func__, xdr);
297 return -EIO;
298}
299
300static int decode_uint64(struct xdr_stream *xdr, u64 *value)
301{
302 __be32 *p;
303
304 p = xdr_inline_decode(xdr, 8);
305 if (unlikely(p == NULL))
306 goto out_overflow;
307 xdr_decode_hyper(p, value);
308 return 0;
309out_overflow:
310 print_overflow_msg(__func__, xdr);
311 return -EIO;
312}
313
314/*
315 * fileid3
316 *
317 * typedef uint64 fileid3;
318 */
319static int decode_fileid3(struct xdr_stream *xdr, u64 *fileid)
320{
321 return decode_uint64(xdr, fileid);
322}
323
Chuck Leverd9c407b2010-12-14 14:55:50 +0000324/*
325 * filename3
326 *
327 * typedef string filename3<>;
328 */
329static void encode_filename3(struct xdr_stream *xdr,
330 const char *name, u32 length)
331{
332 __be32 *p;
333
334 BUG_ON(length > NFS3_MAXNAMLEN);
335 p = xdr_reserve_space(xdr, 4 + length);
336 xdr_encode_opaque(p, name, length);
337}
338
Chuck Levere4f93232010-12-14 14:56:30 +0000339static int decode_inline_filename3(struct xdr_stream *xdr,
340 const char **name, u32 *length)
341{
342 __be32 *p;
343 u32 count;
344
345 p = xdr_inline_decode(xdr, 4);
346 if (unlikely(p == NULL))
347 goto out_overflow;
348 count = be32_to_cpup(p);
349 if (count > NFS3_MAXNAMLEN)
350 goto out_nametoolong;
351 p = xdr_inline_decode(xdr, count);
352 if (unlikely(p == NULL))
353 goto out_overflow;
354 *name = (const char *)p;
355 *length = count;
356 return 0;
357
358out_nametoolong:
359 dprintk("NFS: returned filename too long: %u\n", count);
360 return -ENAMETOOLONG;
361out_overflow:
362 print_overflow_msg(__func__, xdr);
363 return -EIO;
364}
365
Chuck Leverd9c407b2010-12-14 14:55:50 +0000366/*
367 * nfspath3
368 *
369 * typedef string nfspath3<>;
370 */
371static void encode_nfspath3(struct xdr_stream *xdr, struct page **pages,
372 const u32 length)
373{
374 BUG_ON(length > NFS3_MAXPATHLEN);
375 encode_uint32(xdr, length);
376 xdr_write_pages(xdr, pages, 0, length);
377}
378
Chuck Levere4f93232010-12-14 14:56:30 +0000379static int decode_nfspath3(struct xdr_stream *xdr)
380{
381 u32 recvd, count;
382 size_t hdrlen;
383 __be32 *p;
384
385 p = xdr_inline_decode(xdr, 4);
386 if (unlikely(p == NULL))
387 goto out_overflow;
388 count = be32_to_cpup(p);
389 if (unlikely(count >= xdr->buf->page_len || count > NFS3_MAXPATHLEN))
390 goto out_nametoolong;
391 hdrlen = (u8 *)xdr->p - (u8 *)xdr->iov->iov_base;
392 recvd = xdr->buf->len - hdrlen;
393 if (unlikely(count > recvd))
394 goto out_cheating;
395
396 xdr_read_pages(xdr, count);
397 xdr_terminate_string(xdr->buf, count);
398 return 0;
399
400out_nametoolong:
401 dprintk("NFS: returned pathname too long: %u\n", count);
402 return -ENAMETOOLONG;
403out_cheating:
404 dprintk("NFS: server cheating in pathname result: "
405 "count %u > recvd %u\n", count, recvd);
406 return -EIO;
407out_overflow:
408 print_overflow_msg(__func__, xdr);
409 return -EIO;
410}
411
Chuck Leverd9c407b2010-12-14 14:55:50 +0000412/*
413 * cookie3
414 *
415 * typedef uint64 cookie3
416 */
417static __be32 *xdr_encode_cookie3(__be32 *p, u64 cookie)
418{
419 return xdr_encode_hyper(p, cookie);
420}
421
Chuck Levere4f93232010-12-14 14:56:30 +0000422static int decode_cookie3(struct xdr_stream *xdr, u64 *cookie)
423{
424 return decode_uint64(xdr, cookie);
425}
426
Chuck Leverd9c407b2010-12-14 14:55:50 +0000427/*
428 * cookieverf3
429 *
430 * typedef opaque cookieverf3[NFS3_COOKIEVERFSIZE];
431 */
432static __be32 *xdr_encode_cookieverf3(__be32 *p, const __be32 *verifier)
433{
434 memcpy(p, verifier, NFS3_COOKIEVERFSIZE);
435 return p + XDR_QUADLEN(NFS3_COOKIEVERFSIZE);
436}
437
Chuck Levere4f93232010-12-14 14:56:30 +0000438static int decode_cookieverf3(struct xdr_stream *xdr, __be32 *verifier)
439{
440 __be32 *p;
441
442 p = xdr_inline_decode(xdr, NFS3_COOKIEVERFSIZE);
443 if (unlikely(p == NULL))
444 goto out_overflow;
445 memcpy(verifier, p, NFS3_COOKIEVERFSIZE);
446 return 0;
447out_overflow:
448 print_overflow_msg(__func__, xdr);
449 return -EIO;
450}
451
Chuck Leverd9c407b2010-12-14 14:55:50 +0000452/*
453 * createverf3
454 *
455 * typedef opaque createverf3[NFS3_CREATEVERFSIZE];
456 */
457static void encode_createverf3(struct xdr_stream *xdr, const __be32 *verifier)
458{
459 __be32 *p;
460
461 p = xdr_reserve_space(xdr, NFS3_CREATEVERFSIZE);
462 memcpy(p, verifier, NFS3_CREATEVERFSIZE);
463}
464
Chuck Levere4f93232010-12-14 14:56:30 +0000465static int decode_writeverf3(struct xdr_stream *xdr, __be32 *verifier)
466{
467 __be32 *p;
468
469 p = xdr_inline_decode(xdr, NFS3_WRITEVERFSIZE);
470 if (unlikely(p == NULL))
471 goto out_overflow;
472 memcpy(verifier, p, NFS3_WRITEVERFSIZE);
473 return 0;
474out_overflow:
475 print_overflow_msg(__func__, xdr);
476 return -EIO;
477}
478
479/*
480 * size3
481 *
482 * typedef uint64 size3;
483 */
484static __be32 *xdr_decode_size3(__be32 *p, u64 *size)
485{
486 return xdr_decode_hyper(p, size);
487}
488
489/*
490 * nfsstat3
491 *
492 * enum nfsstat3 {
493 * NFS3_OK = 0,
494 * ...
495 * }
496 */
497#define NFS3_OK NFS_OK
498
499static int decode_nfsstat3(struct xdr_stream *xdr, enum nfs_stat *status)
500{
501 __be32 *p;
502
503 p = xdr_inline_decode(xdr, 4);
504 if (unlikely(p == NULL))
505 goto out_overflow;
506 *status = be32_to_cpup(p);
507 return 0;
508out_overflow:
509 print_overflow_msg(__func__, xdr);
510 return -EIO;
511}
512
Chuck Leverd9c407b2010-12-14 14:55:50 +0000513/*
514 * ftype3
515 *
516 * enum ftype3 {
517 * NF3REG = 1,
518 * NF3DIR = 2,
519 * NF3BLK = 3,
520 * NF3CHR = 4,
521 * NF3LNK = 5,
522 * NF3SOCK = 6,
523 * NF3FIFO = 7
524 * };
525 */
526static void encode_ftype3(struct xdr_stream *xdr, const u32 type)
527{
528 BUG_ON(type > NF3FIFO);
529 encode_uint32(xdr, type);
530}
531
532/*
533 * specdata3
534 *
535 * struct specdata3 {
536 * uint32 specdata1;
537 * uint32 specdata2;
538 * };
539 */
540static void encode_specdata3(struct xdr_stream *xdr, const dev_t rdev)
541{
542 __be32 *p;
543
544 p = xdr_reserve_space(xdr, 8);
545 *p++ = cpu_to_be32(MAJOR(rdev));
546 *p = cpu_to_be32(MINOR(rdev));
547}
548
549/*
550 * nfs_fh3
551 *
552 * struct nfs_fh3 {
553 * opaque data<NFS3_FHSIZE>;
554 * };
555 */
556static void encode_nfs_fh3(struct xdr_stream *xdr, const struct nfs_fh *fh)
557{
558 __be32 *p;
559
560 BUG_ON(fh->size > NFS3_FHSIZE);
561 p = xdr_reserve_space(xdr, 4 + fh->size);
562 xdr_encode_opaque(p, fh->data, fh->size);
563}
564
Chuck Levere4f93232010-12-14 14:56:30 +0000565static int decode_nfs_fh3(struct xdr_stream *xdr, struct nfs_fh *fh)
566{
567 u32 length;
568 __be32 *p;
569
570 p = xdr_inline_decode(xdr, 4);
571 if (unlikely(p == NULL))
572 goto out_overflow;
573 length = be32_to_cpup(p++);
574 if (unlikely(length > NFS3_FHSIZE))
575 goto out_toobig;
576 p = xdr_inline_decode(xdr, length);
577 if (unlikely(p == NULL))
578 goto out_overflow;
579 fh->size = length;
580 memcpy(fh->data, p, length);
581 return 0;
582out_toobig:
583 dprintk("NFS: file handle size (%u) too big\n", length);
584 return -E2BIG;
585out_overflow:
586 print_overflow_msg(__func__, xdr);
587 return -EIO;
588}
589
590static void zero_nfs_fh3(struct nfs_fh *fh)
591{
592 memset(fh, 0, sizeof(*fh));
593}
594
Chuck Leverd9c407b2010-12-14 14:55:50 +0000595/*
Chuck Lever9d5a6432010-12-14 14:56:20 +0000596 * nfstime3
597 *
598 * struct nfstime3 {
599 * uint32 seconds;
600 * uint32 nseconds;
601 * };
602 */
603static __be32 *xdr_encode_nfstime3(__be32 *p, const struct timespec *timep)
604{
605 *p++ = cpu_to_be32(timep->tv_sec);
606 *p++ = cpu_to_be32(timep->tv_nsec);
607 return p;
608}
609
610/*
Chuck Leverd9c407b2010-12-14 14:55:50 +0000611 * sattr3
612 *
613 * enum time_how {
614 * DONT_CHANGE = 0,
615 * SET_TO_SERVER_TIME = 1,
616 * SET_TO_CLIENT_TIME = 2
617 * };
618 *
619 * union set_mode3 switch (bool set_it) {
620 * case TRUE:
621 * mode3 mode;
622 * default:
623 * void;
624 * };
625 *
626 * union set_uid3 switch (bool set_it) {
627 * case TRUE:
628 * uid3 uid;
629 * default:
630 * void;
631 * };
632 *
633 * union set_gid3 switch (bool set_it) {
634 * case TRUE:
635 * gid3 gid;
636 * default:
637 * void;
638 * };
639 *
640 * union set_size3 switch (bool set_it) {
641 * case TRUE:
642 * size3 size;
643 * default:
644 * void;
645 * };
646 *
647 * union set_atime switch (time_how set_it) {
648 * case SET_TO_CLIENT_TIME:
649 * nfstime3 atime;
650 * default:
651 * void;
652 * };
653 *
654 * union set_mtime switch (time_how set_it) {
655 * case SET_TO_CLIENT_TIME:
656 * nfstime3 mtime;
657 * default:
658 * void;
659 * };
660 *
661 * struct sattr3 {
662 * set_mode3 mode;
663 * set_uid3 uid;
664 * set_gid3 gid;
665 * set_size3 size;
666 * set_atime atime;
667 * set_mtime mtime;
668 * };
669 */
670static void encode_sattr3(struct xdr_stream *xdr, const struct iattr *attr)
671{
672 u32 nbytes;
673 __be32 *p;
674
675 /*
676 * In order to make only a single xdr_reserve_space() call,
677 * pre-compute the total number of bytes to be reserved.
678 * Six boolean values, one for each set_foo field, are always
679 * present in the encoded result, so start there.
680 */
681 nbytes = 6 * 4;
682 if (attr->ia_valid & ATTR_MODE)
683 nbytes += 4;
684 if (attr->ia_valid & ATTR_UID)
685 nbytes += 4;
686 if (attr->ia_valid & ATTR_GID)
687 nbytes += 4;
688 if (attr->ia_valid & ATTR_SIZE)
689 nbytes += 8;
690 if (attr->ia_valid & ATTR_ATIME_SET)
691 nbytes += 8;
692 if (attr->ia_valid & ATTR_MTIME_SET)
693 nbytes += 8;
694 p = xdr_reserve_space(xdr, nbytes);
695
Chuck Lever9d5a6432010-12-14 14:56:20 +0000696 if (attr->ia_valid & ATTR_MODE) {
697 *p++ = xdr_one;
698 *p++ = cpu_to_be32(attr->ia_mode & S_IALLUGO);
699 } else
700 *p++ = xdr_zero;
701
702 if (attr->ia_valid & ATTR_UID) {
703 *p++ = xdr_one;
704 *p++ = cpu_to_be32(attr->ia_uid);
705 } else
706 *p++ = xdr_zero;
707
708 if (attr->ia_valid & ATTR_GID) {
709 *p++ = xdr_one;
710 *p++ = cpu_to_be32(attr->ia_gid);
711 } else
712 *p++ = xdr_zero;
713
714 if (attr->ia_valid & ATTR_SIZE) {
715 *p++ = xdr_one;
716 p = xdr_encode_hyper(p, (u64)attr->ia_size);
717 } else
718 *p++ = xdr_zero;
719
720 if (attr->ia_valid & ATTR_ATIME_SET) {
721 *p++ = xdr_two;
722 p = xdr_encode_nfstime3(p, &attr->ia_atime);
723 } else if (attr->ia_valid & ATTR_ATIME) {
724 *p++ = xdr_one;
725 } else
726 *p++ = xdr_zero;
727
728 if (attr->ia_valid & ATTR_MTIME_SET) {
729 *p++ = xdr_two;
730 xdr_encode_nfstime3(p, &attr->ia_mtime);
731 } else if (attr->ia_valid & ATTR_MTIME) {
732 *p = xdr_one;
733 } else
734 *p = xdr_zero;
Chuck Leverd9c407b2010-12-14 14:55:50 +0000735}
736
737/*
Chuck Levere4f93232010-12-14 14:56:30 +0000738 * fattr3
739 *
740 * struct fattr3 {
741 * ftype3 type;
742 * mode3 mode;
743 * uint32 nlink;
744 * uid3 uid;
745 * gid3 gid;
746 * size3 size;
747 * size3 used;
748 * specdata3 rdev;
749 * uint64 fsid;
750 * fileid3 fileid;
751 * nfstime3 atime;
752 * nfstime3 mtime;
753 * nfstime3 ctime;
754 * };
755 */
756static int decode_fattr3(struct xdr_stream *xdr, struct nfs_fattr *fattr)
757{
758 __be32 *p;
759
760 p = xdr_inline_decode(xdr, NFS3_fattr_sz << 2);
761 if (unlikely(p == NULL))
762 goto out_overflow;
763 xdr_decode_fattr(p, fattr);
764 return 0;
765out_overflow:
766 print_overflow_msg(__func__, xdr);
767 return -EIO;
768}
769
770/*
771 * post_op_attr
772 *
773 * union post_op_attr switch (bool attributes_follow) {
774 * case TRUE:
775 * fattr3 attributes;
776 * case FALSE:
777 * void;
778 * };
779 */
780static int decode_post_op_attr(struct xdr_stream *xdr, struct nfs_fattr *fattr)
781{
782 __be32 *p;
783
784 p = xdr_inline_decode(xdr, 4);
785 if (unlikely(p == NULL))
786 goto out_overflow;
787 if (*p != xdr_zero)
788 return decode_fattr3(xdr, fattr);
789 return 0;
790out_overflow:
791 print_overflow_msg(__func__, xdr);
792 return -EIO;
793}
794
795/*
796 * wcc_attr
797 * struct wcc_attr {
798 * size3 size;
799 * nfstime3 mtime;
800 * nfstime3 ctime;
801 * };
802 */
803static int decode_wcc_attr(struct xdr_stream *xdr, struct nfs_fattr *fattr)
804{
805 __be32 *p;
806
807 p = xdr_inline_decode(xdr, NFS3_wcc_attr_sz << 2);
808 if (unlikely(p == NULL))
809 goto out_overflow;
810 xdr_decode_wcc_attr(p, fattr);
811 return 0;
812out_overflow:
813 print_overflow_msg(__func__, xdr);
814 return -EIO;
815}
816
817/*
818 * pre_op_attr
819 * union pre_op_attr switch (bool attributes_follow) {
820 * case TRUE:
821 * wcc_attr attributes;
822 * case FALSE:
823 * void;
824 * };
825 *
826 * wcc_data
827 *
828 * struct wcc_data {
829 * pre_op_attr before;
830 * post_op_attr after;
831 * };
832 */
833static int decode_pre_op_attr(struct xdr_stream *xdr, struct nfs_fattr *fattr)
834{
835 __be32 *p;
836
837 p = xdr_inline_decode(xdr, 4);
838 if (unlikely(p == NULL))
839 goto out_overflow;
840 if (*p != xdr_zero)
841 return decode_wcc_attr(xdr, fattr);
842 return 0;
843out_overflow:
844 print_overflow_msg(__func__, xdr);
845 return -EIO;
846}
847
848static int decode_wcc_data(struct xdr_stream *xdr, struct nfs_fattr *fattr)
849{
850 int error;
851
852 error = decode_pre_op_attr(xdr, fattr);
853 if (unlikely(error))
854 goto out;
855 error = decode_post_op_attr(xdr, fattr);
856out:
857 return error;
858}
859
860/*
861 * post_op_fh3
862 *
863 * union post_op_fh3 switch (bool handle_follows) {
864 * case TRUE:
865 * nfs_fh3 handle;
866 * case FALSE:
867 * void;
868 * };
869 */
870static int decode_post_op_fh3(struct xdr_stream *xdr, struct nfs_fh *fh)
871{
872 __be32 *p = xdr_inline_decode(xdr, 4);
873 if (unlikely(p == NULL))
874 goto out_overflow;
875 if (*p != xdr_zero)
876 return decode_nfs_fh3(xdr, fh);
877 zero_nfs_fh3(fh);
878 return 0;
879out_overflow:
880 print_overflow_msg(__func__, xdr);
881 return -EIO;
882}
883
884/*
Chuck Leverd9c407b2010-12-14 14:55:50 +0000885 * diropargs3
886 *
887 * struct diropargs3 {
888 * nfs_fh3 dir;
889 * filename3 name;
890 * };
891 */
892static void encode_diropargs3(struct xdr_stream *xdr, const struct nfs_fh *fh,
893 const char *name, u32 length)
894{
895 encode_nfs_fh3(xdr, fh);
896 encode_filename3(xdr, name, length);
897}
898
899
Linus Torvalds1da177e2005-04-16 15:20:36 -0700900/*
Chuck Lever499ff712010-12-14 14:56:10 +0000901 * NFSv3 XDR encode functions
902 *
903 * NFSv3 argument types are defined in section 3.3 of RFC 1813:
904 * "NFS Version 3 Protocol Specification".
Linus Torvalds1da177e2005-04-16 15:20:36 -0700905 */
906
907/*
Chuck Leverd9c407b2010-12-14 14:55:50 +0000908 * 3.3.1 GETATTR3args
909 *
910 * struct GETATTR3args {
911 * nfs_fh3 object;
912 * };
913 */
914static int nfs3_xdr_enc_getattr3args(struct rpc_rqst *req, __be32 *p,
915 const struct nfs_fh *fh)
916{
917 struct xdr_stream xdr;
918
919 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
920 encode_nfs_fh3(&xdr, fh);
921 return 0;
922}
923
924/*
Chuck Leverd9c407b2010-12-14 14:55:50 +0000925 * 3.3.2 SETATTR3args
926 *
927 * union sattrguard3 switch (bool check) {
928 * case TRUE:
929 * nfstime3 obj_ctime;
930 * case FALSE:
931 * void;
932 * };
933 *
934 * struct SETATTR3args {
935 * nfs_fh3 object;
936 * sattr3 new_attributes;
937 * sattrguard3 guard;
938 * };
939 */
940static void encode_sattrguard3(struct xdr_stream *xdr,
941 const struct nfs3_sattrargs *args)
942{
943 __be32 *p;
944
945 if (args->guard) {
946 p = xdr_reserve_space(xdr, 4 + 8);
947 *p++ = xdr_one;
Chuck Lever9d5a6432010-12-14 14:56:20 +0000948 xdr_encode_nfstime3(p, &args->guardtime);
Chuck Leverd9c407b2010-12-14 14:55:50 +0000949 } else {
950 p = xdr_reserve_space(xdr, 4);
951 *p = xdr_zero;
952 }
953}
954
955static int nfs3_xdr_enc_setattr3args(struct rpc_rqst *req, __be32 *p,
956 const struct nfs3_sattrargs *args)
957{
958 struct xdr_stream xdr;
959
960 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
961 encode_nfs_fh3(&xdr, args->fh);
962 encode_sattr3(&xdr, args->sattr);
963 encode_sattrguard3(&xdr, args);
964 return 0;
965}
966
967/*
Chuck Leverd9c407b2010-12-14 14:55:50 +0000968 * 3.3.3 LOOKUP3args
969 *
970 * struct LOOKUP3args {
971 * diropargs3 what;
972 * };
973 */
974static int nfs3_xdr_enc_lookup3args(struct rpc_rqst *req, __be32 *p,
975 const struct nfs3_diropargs *args)
976{
977 struct xdr_stream xdr;
978
979 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
980 encode_diropargs3(&xdr, args->fh, args->name, args->len);
981 return 0;
982}
983
984/*
Chuck Leverd9c407b2010-12-14 14:55:50 +0000985 * 3.3.4 ACCESS3args
986 *
987 * struct ACCESS3args {
988 * nfs_fh3 object;
989 * uint32 access;
990 * };
991 */
992static void encode_access3args(struct xdr_stream *xdr,
993 const struct nfs3_accessargs *args)
994{
995 encode_nfs_fh3(xdr, args->fh);
996 encode_uint32(xdr, args->access);
997}
998
999static int nfs3_xdr_enc_access3args(struct rpc_rqst *req, __be32 *p,
1000 const struct nfs3_accessargs *args)
1001{
1002 struct xdr_stream xdr;
1003
1004 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1005 encode_access3args(&xdr, args);
1006 return 0;
1007}
1008
1009/*
1010 * 3.3.5 READLINK3args
1011 *
1012 * struct READLINK3args {
1013 * nfs_fh3 symlink;
1014 * };
1015 */
1016static int nfs3_xdr_enc_readlink3args(struct rpc_rqst *req, __be32 *p,
1017 const struct nfs3_readlinkargs *args)
1018{
1019 struct xdr_stream xdr;
1020
1021 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1022 encode_nfs_fh3(&xdr, args->fh);
1023 prepare_reply_buffer(req, args->pages, args->pgbase,
1024 args->pglen, NFS3_readlinkres_sz);
1025 return 0;
1026}
1027
1028/*
Chuck Leverd9c407b2010-12-14 14:55:50 +00001029 * 3.3.6 READ3args
1030 *
1031 * struct READ3args {
1032 * nfs_fh3 file;
1033 * offset3 offset;
1034 * count3 count;
1035 * };
1036 */
1037static void encode_read3args(struct xdr_stream *xdr,
1038 const struct nfs_readargs *args)
1039{
1040 __be32 *p;
1041
1042 encode_nfs_fh3(xdr, args->fh);
1043
1044 p = xdr_reserve_space(xdr, 8 + 4);
1045 p = xdr_encode_hyper(p, args->offset);
1046 *p = cpu_to_be32(args->count);
1047}
1048
1049static int nfs3_xdr_enc_read3args(struct rpc_rqst *req, __be32 *p,
1050 const struct nfs_readargs *args)
1051{
1052 struct xdr_stream xdr;
1053
1054 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1055 encode_read3args(&xdr, args);
1056 prepare_reply_buffer(req, args->pages, args->pgbase,
1057 args->count, NFS3_readres_sz);
1058 req->rq_rcv_buf.flags |= XDRBUF_READ;
1059 return 0;
1060}
1061
1062/*
Chuck Leverd9c407b2010-12-14 14:55:50 +00001063 * 3.3.7 WRITE3args
1064 *
1065 * enum stable_how {
1066 * UNSTABLE = 0,
1067 * DATA_SYNC = 1,
1068 * FILE_SYNC = 2
1069 * };
1070 *
1071 * struct WRITE3args {
1072 * nfs_fh3 file;
1073 * offset3 offset;
1074 * count3 count;
1075 * stable_how stable;
1076 * opaque data<>;
1077 * };
1078 */
1079static void encode_write3args(struct xdr_stream *xdr,
1080 const struct nfs_writeargs *args)
1081{
1082 __be32 *p;
1083
1084 encode_nfs_fh3(xdr, args->fh);
1085
1086 p = xdr_reserve_space(xdr, 8 + 4 + 4 + 4);
1087 p = xdr_encode_hyper(p, args->offset);
1088 *p++ = cpu_to_be32(args->count);
1089
1090 BUG_ON(args->stable > NFS_FILE_SYNC);
1091 *p++ = cpu_to_be32(args->stable);
1092
1093 *p = cpu_to_be32(args->count);
1094 xdr_write_pages(xdr, args->pages, args->pgbase, args->count);
1095}
1096
1097static int nfs3_xdr_enc_write3args(struct rpc_rqst *req, __be32 *p,
1098 const struct nfs_writeargs *args)
1099{
1100 struct xdr_stream xdr;
1101
1102 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1103 encode_write3args(&xdr, args);
1104 xdr.buf->flags |= XDRBUF_WRITE;
1105 return 0;
1106}
1107
1108/*
Chuck Leverd9c407b2010-12-14 14:55:50 +00001109 * 3.3.8 CREATE3args
1110 *
1111 * enum createmode3 {
1112 * UNCHECKED = 0,
1113 * GUARDED = 1,
1114 * EXCLUSIVE = 2
1115 * };
1116 *
1117 * union createhow3 switch (createmode3 mode) {
1118 * case UNCHECKED:
1119 * case GUARDED:
1120 * sattr3 obj_attributes;
1121 * case EXCLUSIVE:
1122 * createverf3 verf;
1123 * };
1124 *
1125 * struct CREATE3args {
1126 * diropargs3 where;
1127 * createhow3 how;
1128 * };
1129 */
1130static void encode_createhow3(struct xdr_stream *xdr,
1131 const struct nfs3_createargs *args)
1132{
1133 encode_uint32(xdr, args->createmode);
1134 switch (args->createmode) {
1135 case NFS3_CREATE_UNCHECKED:
1136 case NFS3_CREATE_GUARDED:
1137 encode_sattr3(xdr, args->sattr);
1138 break;
1139 case NFS3_CREATE_EXCLUSIVE:
1140 encode_createverf3(xdr, args->verifier);
1141 break;
1142 default:
1143 BUG();
1144 }
1145}
1146
1147static int nfs3_xdr_enc_create3args(struct rpc_rqst *req, __be32 *p,
1148 const struct nfs3_createargs *args)
1149{
1150 struct xdr_stream xdr;
1151
1152 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1153 encode_diropargs3(&xdr, args->fh, args->name, args->len);
1154 encode_createhow3(&xdr, args);
1155 return 0;
1156}
1157
1158/*
Chuck Leverd9c407b2010-12-14 14:55:50 +00001159 * 3.3.9 MKDIR3args
1160 *
1161 * struct MKDIR3args {
1162 * diropargs3 where;
1163 * sattr3 attributes;
1164 * };
1165 */
1166static int nfs3_xdr_enc_mkdir3args(struct rpc_rqst *req, __be32 *p,
1167 const struct nfs3_mkdirargs *args)
1168{
1169 struct xdr_stream xdr;
1170
1171 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1172 encode_diropargs3(&xdr, args->fh, args->name, args->len);
1173 encode_sattr3(&xdr, args->sattr);
1174 return 0;
1175}
1176
1177/*
Chuck Leverd9c407b2010-12-14 14:55:50 +00001178 * 3.3.10 SYMLINK3args
1179 *
1180 * struct symlinkdata3 {
1181 * sattr3 symlink_attributes;
1182 * nfspath3 symlink_data;
1183 * };
1184 *
1185 * struct SYMLINK3args {
1186 * diropargs3 where;
1187 * symlinkdata3 symlink;
1188 * };
1189 */
1190static void encode_symlinkdata3(struct xdr_stream *xdr,
1191 const struct nfs3_symlinkargs *args)
1192{
1193 encode_sattr3(xdr, args->sattr);
1194 encode_nfspath3(xdr, args->pages, args->pathlen);
1195}
1196
1197static int nfs3_xdr_enc_symlink3args(struct rpc_rqst *req, __be32 *p,
1198 const struct nfs3_symlinkargs *args)
1199{
1200 struct xdr_stream xdr;
1201
1202 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1203 encode_diropargs3(&xdr, args->fromfh, args->fromname, args->fromlen);
1204 encode_symlinkdata3(&xdr, args);
1205 return 0;
1206}
1207
1208/*
Chuck Leverd9c407b2010-12-14 14:55:50 +00001209 * 3.3.11 MKNOD3args
1210 *
1211 * struct devicedata3 {
1212 * sattr3 dev_attributes;
1213 * specdata3 spec;
1214 * };
1215 *
1216 * union mknoddata3 switch (ftype3 type) {
1217 * case NF3CHR:
1218 * case NF3BLK:
1219 * devicedata3 device;
1220 * case NF3SOCK:
1221 * case NF3FIFO:
1222 * sattr3 pipe_attributes;
1223 * default:
1224 * void;
1225 * };
1226 *
1227 * struct MKNOD3args {
1228 * diropargs3 where;
1229 * mknoddata3 what;
1230 * };
1231 */
1232static void encode_devicedata3(struct xdr_stream *xdr,
1233 const struct nfs3_mknodargs *args)
1234{
1235 encode_sattr3(xdr, args->sattr);
1236 encode_specdata3(xdr, args->rdev);
1237}
1238
1239static void encode_mknoddata3(struct xdr_stream *xdr,
1240 const struct nfs3_mknodargs *args)
1241{
1242 encode_ftype3(xdr, args->type);
1243 switch (args->type) {
1244 case NF3CHR:
1245 case NF3BLK:
1246 encode_devicedata3(xdr, args);
1247 break;
1248 case NF3SOCK:
1249 case NF3FIFO:
1250 encode_sattr3(xdr, args->sattr);
1251 break;
1252 case NF3REG:
1253 case NF3DIR:
1254 break;
1255 default:
1256 BUG();
1257 }
1258}
1259
1260static int nfs3_xdr_enc_mknod3args(struct rpc_rqst *req, __be32 *p,
1261 const struct nfs3_mknodargs *args)
1262{
1263 struct xdr_stream xdr;
1264
1265 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1266 encode_diropargs3(&xdr, args->fh, args->name, args->len);
1267 encode_mknoddata3(&xdr, args);
1268 return 0;
1269}
1270
1271/*
1272 * 3.3.12 REMOVE3args
1273 *
1274 * struct REMOVE3args {
1275 * diropargs3 object;
1276 * };
1277 */
1278static int nfs3_xdr_enc_remove3args(struct rpc_rqst *req, __be32 *p,
1279 const struct nfs_removeargs *args)
1280{
1281 struct xdr_stream xdr;
1282
1283 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1284 encode_diropargs3(&xdr, args->fh, args->name.name, args->name.len);
1285 return 0;
1286}
1287
1288/*
Chuck Leverd9c407b2010-12-14 14:55:50 +00001289 * 3.3.14 RENAME3args
1290 *
1291 * struct RENAME3args {
1292 * diropargs3 from;
1293 * diropargs3 to;
1294 * };
1295 */
1296static int nfs3_xdr_enc_rename3args(struct rpc_rqst *req, __be32 *p,
1297 const struct nfs_renameargs *args)
1298{
1299 const struct qstr *old = args->old_name;
1300 const struct qstr *new = args->new_name;
1301 struct xdr_stream xdr;
1302
1303 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1304 encode_diropargs3(&xdr, args->old_dir, old->name, old->len);
1305 encode_diropargs3(&xdr, args->new_dir, new->name, new->len);
1306 return 0;
1307}
1308
1309/*
Chuck Leverd9c407b2010-12-14 14:55:50 +00001310 * 3.3.15 LINK3args
1311 *
1312 * struct LINK3args {
1313 * nfs_fh3 file;
1314 * diropargs3 link;
1315 * };
1316 */
1317static int nfs3_xdr_enc_link3args(struct rpc_rqst *req, __be32 *p,
1318 const struct nfs3_linkargs *args)
1319{
1320 struct xdr_stream xdr;
1321
1322 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1323 encode_nfs_fh3(&xdr, args->fromfh);
1324 encode_diropargs3(&xdr, args->tofh, args->toname, args->tolen);
1325 return 0;
1326}
1327
1328/*
Chuck Leverd9c407b2010-12-14 14:55:50 +00001329 * 3.3.16 READDIR3args
1330 *
1331 * struct READDIR3args {
1332 * nfs_fh3 dir;
1333 * cookie3 cookie;
1334 * cookieverf3 cookieverf;
1335 * count3 count;
1336 * };
1337 */
1338static void encode_readdir3args(struct xdr_stream *xdr,
1339 const struct nfs3_readdirargs *args)
1340{
1341 __be32 *p;
1342
1343 encode_nfs_fh3(xdr, args->fh);
1344
1345 p = xdr_reserve_space(xdr, 8 + NFS3_COOKIEVERFSIZE + 4);
1346 p = xdr_encode_cookie3(p, args->cookie);
1347 p = xdr_encode_cookieverf3(p, args->verf);
1348 *p = cpu_to_be32(args->count);
1349}
1350
1351static int nfs3_xdr_enc_readdir3args(struct rpc_rqst *req, __be32 *p,
1352 const struct nfs3_readdirargs *args)
1353{
1354 struct xdr_stream xdr;
1355
1356 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1357 encode_readdir3args(&xdr, args);
1358 prepare_reply_buffer(req, args->pages, 0,
1359 args->count, NFS3_readdirres_sz);
1360 return 0;
1361}
1362
1363/*
1364 * 3.3.17 READDIRPLUS3args
1365 *
1366 * struct READDIRPLUS3args {
1367 * nfs_fh3 dir;
1368 * cookie3 cookie;
1369 * cookieverf3 cookieverf;
1370 * count3 dircount;
1371 * count3 maxcount;
1372 * };
1373 */
1374static void encode_readdirplus3args(struct xdr_stream *xdr,
1375 const struct nfs3_readdirargs *args)
1376{
1377 __be32 *p;
1378
1379 encode_nfs_fh3(xdr, args->fh);
1380
1381 p = xdr_reserve_space(xdr, 8 + NFS3_COOKIEVERFSIZE + 4 + 4);
1382 p = xdr_encode_cookie3(p, args->cookie);
1383 p = xdr_encode_cookieverf3(p, args->verf);
1384
1385 /*
1386 * readdirplus: need dircount + buffer size.
1387 * We just make sure we make dircount big enough
1388 */
1389 *p++ = cpu_to_be32(args->count >> 3);
1390
1391 *p = cpu_to_be32(args->count);
1392}
1393
1394static int nfs3_xdr_enc_readdirplus3args(struct rpc_rqst *req, __be32 *p,
1395 const struct nfs3_readdirargs *args)
1396{
1397 struct xdr_stream xdr;
1398
1399 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1400 encode_readdirplus3args(&xdr, args);
1401 prepare_reply_buffer(req, args->pages, 0,
1402 args->count, NFS3_readdirres_sz);
1403 return 0;
1404}
1405
1406/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001407 * Decode the result of a readdir call.
1408 * We just check for syntactical correctness.
1409 */
1410static int
Al Virod61005a2006-10-19 23:28:48 -07001411nfs3_xdr_readdirres(struct rpc_rqst *req, __be32 *p, struct nfs3_readdirres *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001412{
1413 struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
1414 struct kvec *iov = rcvbuf->head;
1415 struct page **page;
Chuck Leverc957c522007-10-26 13:31:57 -04001416 size_t hdrlen;
Bryan Schumakerafa8ccc2010-10-20 15:44:31 -04001417 u32 recvd, pglen;
Trond Myklebustac396122010-11-15 20:26:22 -05001418 int status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001419
1420 status = ntohl(*p++);
1421 /* Decode post_op_attrs */
1422 p = xdr_decode_post_op_attr(p, res->dir_attr);
1423 if (status)
Benny Halevy856dff32008-03-31 17:39:06 +03001424 return nfs_stat_to_errno(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001425 /* Decode verifier cookie */
1426 if (res->verf) {
1427 res->verf[0] = *p++;
1428 res->verf[1] = *p++;
1429 } else {
1430 p += 2;
1431 }
1432
1433 hdrlen = (u8 *) p - (u8 *) iov->iov_base;
1434 if (iov->iov_len < hdrlen) {
Chuck Leverfe82a182007-09-11 18:01:10 -04001435 dprintk("NFS: READDIR reply header overflowed:"
Chuck Leverc957c522007-10-26 13:31:57 -04001436 "length %Zu > %Zu\n", hdrlen, iov->iov_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001437 return -errno_NFSERR_IO;
1438 } else if (iov->iov_len != hdrlen) {
1439 dprintk("NFS: READDIR header is short. iovec will be shifted.\n");
1440 xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen);
1441 }
1442
1443 pglen = rcvbuf->page_len;
1444 recvd = rcvbuf->len - hdrlen;
1445 if (pglen > recvd)
1446 pglen = recvd;
1447 page = rcvbuf->pages;
Jeff Layton643f8112008-02-22 14:50:00 -05001448
Trond Myklebustac396122010-11-15 20:26:22 -05001449 return pglen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001450}
1451
Linus Torvalds1da177e2005-04-16 15:20:36 -07001452/*
Chuck Leverd9c407b2010-12-14 14:55:50 +00001453 * 3.3.21 COMMIT3args
1454 *
1455 * struct COMMIT3args {
1456 * nfs_fh3 file;
1457 * offset3 offset;
1458 * count3 count;
1459 * };
1460 */
1461static void encode_commit3args(struct xdr_stream *xdr,
1462 const struct nfs_writeargs *args)
1463{
1464 __be32 *p;
1465
1466 encode_nfs_fh3(xdr, args->fh);
1467
1468 p = xdr_reserve_space(xdr, 8 + 4);
1469 p = xdr_encode_hyper(p, args->offset);
1470 *p = cpu_to_be32(args->count);
1471}
1472
1473static int nfs3_xdr_enc_commit3args(struct rpc_rqst *req, __be32 *p,
1474 const struct nfs_writeargs *args)
1475{
1476 struct xdr_stream xdr;
1477
1478 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1479 encode_commit3args(&xdr, args);
1480 return 0;
1481}
1482
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +00001483#ifdef CONFIG_NFS_V3_ACL
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +00001484
Chuck Leverd9c407b2010-12-14 14:55:50 +00001485static int nfs3_xdr_enc_getacl3args(struct rpc_rqst *req, __be32 *p,
1486 const struct nfs3_getaclargs *args)
1487{
1488 struct xdr_stream xdr;
1489
1490 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1491 encode_nfs_fh3(&xdr, args->fh);
1492 encode_uint32(&xdr, args->mask);
1493 if (args->mask & (NFS_ACL | NFS_DFACL))
1494 prepare_reply_buffer(req, args->pages, 0,
1495 NFSACL_MAXPAGES << PAGE_SHIFT,
1496 ACL3_getaclres_sz);
1497 return 0;
1498}
1499
Chuck Leverd9c407b2010-12-14 14:55:50 +00001500static int nfs3_xdr_enc_setacl3args(struct rpc_rqst *req, __be32 *p,
1501 const struct nfs3_setaclargs *args)
1502{
1503 struct xdr_stream xdr;
1504 unsigned int base;
1505 int error;
1506
1507 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1508 encode_nfs_fh3(&xdr, NFS_FH(args->inode));
1509 encode_uint32(&xdr, args->mask);
1510 if (args->npages != 0)
1511 xdr_write_pages(&xdr, args->pages, 0, args->len);
1512
1513 base = req->rq_slen;
1514 error = nfsacl_encode(xdr.buf, base, args->inode,
1515 (args->mask & NFS_ACL) ?
1516 args->acl_access : NULL, 1, 0);
1517 BUG_ON(error < 0);
1518 error = nfsacl_encode(xdr.buf, base + error, args->inode,
1519 (args->mask & NFS_DFACL) ?
1520 args->acl_default : NULL, 1,
1521 NFS_ACL_DEFAULT);
1522 BUG_ON(error < 0);
1523 return 0;
1524}
1525
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +00001526#endif /* CONFIG_NFS_V3_ACL */
1527
Linus Torvalds1da177e2005-04-16 15:20:36 -07001528/*
1529 * NFS XDR decode functions
1530 */
1531
1532/*
1533 * Decode attrstat reply.
1534 */
1535static int
Al Virod61005a2006-10-19 23:28:48 -07001536nfs3_xdr_attrstat(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001537{
1538 int status;
1539
1540 if ((status = ntohl(*p++)))
Benny Halevy856dff32008-03-31 17:39:06 +03001541 return nfs_stat_to_errno(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001542 xdr_decode_fattr(p, fattr);
1543 return 0;
1544}
1545
1546/*
Chuck Levere4f93232010-12-14 14:56:30 +00001547 * 3.3.1 GETATTR3res
1548 *
1549 * struct GETATTR3resok {
1550 * fattr3 obj_attributes;
1551 * };
1552 *
1553 * union GETATTR3res switch (nfsstat3 status) {
1554 * case NFS3_OK:
1555 * GETATTR3resok resok;
1556 * default:
1557 * void;
1558 * };
1559 */
1560static int nfs3_xdr_dec_getattr3res(struct rpc_rqst *req, __be32 *p,
1561 struct nfs_fattr *result)
1562{
1563 struct xdr_stream xdr;
1564 enum nfs_stat status;
1565 int error;
1566
1567 xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
1568 error = decode_nfsstat3(&xdr, &status);
1569 if (unlikely(error))
1570 goto out;
1571 if (status != NFS3_OK)
1572 goto out_default;
1573 error = decode_fattr3(&xdr, result);
1574out:
1575 return error;
1576out_default:
1577 return nfs_stat_to_errno(status);
1578}
1579
1580/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001581 * Decode status+wcc_data reply
1582 * SATTR, REMOVE, RMDIR
1583 */
1584static int
Al Virod61005a2006-10-19 23:28:48 -07001585nfs3_xdr_wccstat(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001586{
1587 int status;
1588
1589 if ((status = ntohl(*p++)))
Benny Halevy856dff32008-03-31 17:39:06 +03001590 status = nfs_stat_to_errno(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001591 xdr_decode_wcc_data(p, fattr);
1592 return status;
1593}
1594
Chuck Levere4f93232010-12-14 14:56:30 +00001595/*
1596 * 3.3.2 SETATTR3res
1597 *
1598 * struct SETATTR3resok {
1599 * wcc_data obj_wcc;
1600 * };
1601 *
1602 * struct SETATTR3resfail {
1603 * wcc_data obj_wcc;
1604 * };
1605 *
1606 * union SETATTR3res switch (nfsstat3 status) {
1607 * case NFS3_OK:
1608 * SETATTR3resok resok;
1609 * default:
1610 * SETATTR3resfail resfail;
1611 * };
1612 */
1613static int nfs3_xdr_dec_setattr3res(struct rpc_rqst *req, __be32 *p,
1614 struct nfs_fattr *result)
1615{
1616 struct xdr_stream xdr;
1617 enum nfs_stat status;
1618 int error;
1619
1620 xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
1621 error = decode_nfsstat3(&xdr, &status);
1622 if (unlikely(error))
1623 goto out;
1624 error = decode_wcc_data(&xdr, result);
1625 if (unlikely(error))
1626 goto out;
1627 if (status != NFS3_OK)
1628 goto out_status;
1629out:
1630 return error;
1631out_status:
1632 return nfs_stat_to_errno(status);
1633}
1634
Trond Myklebust4fdc17b2007-07-14 15:39:57 -04001635static int
1636nfs3_xdr_removeres(struct rpc_rqst *req, __be32 *p, struct nfs_removeres *res)
1637{
Trond Myklebustd3468902010-04-16 16:22:50 -04001638 return nfs3_xdr_wccstat(req, p, res->dir_attr);
Trond Myklebust4fdc17b2007-07-14 15:39:57 -04001639}
1640
Linus Torvalds1da177e2005-04-16 15:20:36 -07001641/*
1642 * Decode LOOKUP reply
1643 */
1644static int
Al Virod61005a2006-10-19 23:28:48 -07001645nfs3_xdr_lookupres(struct rpc_rqst *req, __be32 *p, struct nfs3_diropres *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001646{
1647 int status;
1648
1649 if ((status = ntohl(*p++))) {
Benny Halevy856dff32008-03-31 17:39:06 +03001650 status = nfs_stat_to_errno(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001651 } else {
1652 if (!(p = xdr_decode_fhandle(p, res->fh)))
1653 return -errno_NFSERR_IO;
1654 p = xdr_decode_post_op_attr(p, res->fattr);
1655 }
1656 xdr_decode_post_op_attr(p, res->dir_attr);
1657 return status;
1658}
1659
1660/*
Chuck Levere4f93232010-12-14 14:56:30 +00001661 * 3.3.3 LOOKUP3res
1662 *
1663 * struct LOOKUP3resok {
1664 * nfs_fh3 object;
1665 * post_op_attr obj_attributes;
1666 * post_op_attr dir_attributes;
1667 * };
1668 *
1669 * struct LOOKUP3resfail {
1670 * post_op_attr dir_attributes;
1671 * };
1672 *
1673 * union LOOKUP3res switch (nfsstat3 status) {
1674 * case NFS3_OK:
1675 * LOOKUP3resok resok;
1676 * default:
1677 * LOOKUP3resfail resfail;
1678 * };
1679 */
1680static int nfs3_xdr_dec_lookup3res(struct rpc_rqst *req, __be32 *p,
1681 struct nfs3_diropres *result)
1682{
1683 struct xdr_stream xdr;
1684 enum nfs_stat status;
1685 int error;
1686
1687 xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
1688 error = decode_nfsstat3(&xdr, &status);
1689 if (unlikely(error))
1690 goto out;
1691 if (status != NFS3_OK)
1692 goto out_default;
1693 error = decode_nfs_fh3(&xdr, result->fh);
1694 if (unlikely(error))
1695 goto out;
1696 error = decode_post_op_attr(&xdr, result->fattr);
1697 if (unlikely(error))
1698 goto out;
1699 error = decode_post_op_attr(&xdr, result->dir_attr);
1700out:
1701 return error;
1702out_default:
1703 error = decode_post_op_attr(&xdr, result->dir_attr);
1704 if (unlikely(error))
1705 goto out;
1706 return nfs_stat_to_errno(status);
1707}
1708
1709/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001710 * Decode ACCESS reply
1711 */
1712static int
Al Virod61005a2006-10-19 23:28:48 -07001713nfs3_xdr_accessres(struct rpc_rqst *req, __be32 *p, struct nfs3_accessres *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001714{
1715 int status = ntohl(*p++);
1716
1717 p = xdr_decode_post_op_attr(p, res->fattr);
1718 if (status)
Benny Halevy856dff32008-03-31 17:39:06 +03001719 return nfs_stat_to_errno(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001720 res->access = ntohl(*p++);
1721 return 0;
1722}
1723
Linus Torvalds1da177e2005-04-16 15:20:36 -07001724/*
Chuck Levere4f93232010-12-14 14:56:30 +00001725 * 3.3.4 ACCESS3res
1726 *
1727 * struct ACCESS3resok {
1728 * post_op_attr obj_attributes;
1729 * uint32 access;
1730 * };
1731 *
1732 * struct ACCESS3resfail {
1733 * post_op_attr obj_attributes;
1734 * };
1735 *
1736 * union ACCESS3res switch (nfsstat3 status) {
1737 * case NFS3_OK:
1738 * ACCESS3resok resok;
1739 * default:
1740 * ACCESS3resfail resfail;
1741 * };
1742 */
1743static int nfs3_xdr_dec_access3res(struct rpc_rqst *req, __be32 *p,
1744 struct nfs3_accessres *result)
1745{
1746 struct xdr_stream xdr;
1747 enum nfs_stat status;
1748 int error;
1749
1750 xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
1751 error = decode_nfsstat3(&xdr, &status);
1752 if (unlikely(error))
1753 goto out;
1754 error = decode_post_op_attr(&xdr, result->fattr);
1755 if (unlikely(error))
1756 goto out;
1757 if (status != NFS3_OK)
1758 goto out_default;
1759 error = decode_uint32(&xdr, &result->access);
1760out:
1761 return error;
1762out_default:
1763 return nfs_stat_to_errno(status);
1764}
1765
1766/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001767 * Decode READLINK reply
1768 */
1769static int
Al Virod61005a2006-10-19 23:28:48 -07001770nfs3_xdr_readlinkres(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001771{
1772 struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
1773 struct kvec *iov = rcvbuf->head;
Chuck Leverc957c522007-10-26 13:31:57 -04001774 size_t hdrlen;
1775 u32 len, recvd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001776 int status;
1777
1778 status = ntohl(*p++);
1779 p = xdr_decode_post_op_attr(p, fattr);
1780
1781 if (status != 0)
Benny Halevy856dff32008-03-31 17:39:06 +03001782 return nfs_stat_to_errno(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001783
1784 /* Convert length of symlink */
1785 len = ntohl(*p++);
Chuck Leverc957c522007-10-26 13:31:57 -04001786 if (len >= rcvbuf->page_len) {
Chuck Leverfe82a182007-09-11 18:01:10 -04001787 dprintk("nfs: server returned giant symlink!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001788 return -ENAMETOOLONG;
1789 }
1790
1791 hdrlen = (u8 *) p - (u8 *) iov->iov_base;
1792 if (iov->iov_len < hdrlen) {
Chuck Leverfe82a182007-09-11 18:01:10 -04001793 dprintk("NFS: READLINK reply header overflowed:"
Chuck Leverc957c522007-10-26 13:31:57 -04001794 "length %Zu > %Zu\n", hdrlen, iov->iov_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001795 return -errno_NFSERR_IO;
1796 } else if (iov->iov_len != hdrlen) {
Chuck Leverfe82a182007-09-11 18:01:10 -04001797 dprintk("NFS: READLINK header is short. "
1798 "iovec will be shifted.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001799 xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen);
1800 }
1801 recvd = req->rq_rcv_buf.len - hdrlen;
1802 if (recvd < len) {
Chuck Leverfe82a182007-09-11 18:01:10 -04001803 dprintk("NFS: server cheating in readlink reply: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001804 "count %u > recvd %u\n", len, recvd);
1805 return -EIO;
1806 }
1807
Chuck Leverb4687da2010-09-21 16:55:48 -04001808 xdr_terminate_string(rcvbuf, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001809 return 0;
1810}
1811
1812/*
Chuck Levere4f93232010-12-14 14:56:30 +00001813 * 3.3.5 READLINK3res
1814 *
1815 * struct READLINK3resok {
1816 * post_op_attr symlink_attributes;
1817 * nfspath3 data;
1818 * };
1819 *
1820 * struct READLINK3resfail {
1821 * post_op_attr symlink_attributes;
1822 * };
1823 *
1824 * union READLINK3res switch (nfsstat3 status) {
1825 * case NFS3_OK:
1826 * READLINK3resok resok;
1827 * default:
1828 * READLINK3resfail resfail;
1829 * };
1830 */
1831static int nfs3_xdr_dec_readlink3res(struct rpc_rqst *req, __be32 *p,
1832 struct nfs_fattr *result)
1833{
1834 struct xdr_stream xdr;
1835 enum nfs_stat status;
1836 int error;
1837
1838 xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
1839 error = decode_nfsstat3(&xdr, &status);
1840 if (unlikely(error))
1841 goto out;
1842 error = decode_post_op_attr(&xdr, result);
1843 if (unlikely(error))
1844 goto out;
1845 if (status != NFS3_OK)
1846 goto out_default;
1847 error = decode_nfspath3(&xdr);
1848out:
1849 return error;
1850out_default:
1851 return nfs_stat_to_errno(status);
1852}
1853
1854/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001855 * Decode READ reply
1856 */
1857static int
Al Virod61005a2006-10-19 23:28:48 -07001858nfs3_xdr_readres(struct rpc_rqst *req, __be32 *p, struct nfs_readres *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001859{
1860 struct kvec *iov = req->rq_rcv_buf.head;
Chuck Leverc957c522007-10-26 13:31:57 -04001861 size_t hdrlen;
1862 u32 count, ocount, recvd;
1863 int status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001864
1865 status = ntohl(*p++);
1866 p = xdr_decode_post_op_attr(p, res->fattr);
1867
1868 if (status != 0)
Benny Halevy856dff32008-03-31 17:39:06 +03001869 return nfs_stat_to_errno(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001870
Chuck Leverc957c522007-10-26 13:31:57 -04001871 /* Decode reply count and EOF flag. NFSv3 is somewhat redundant
Linus Torvalds1da177e2005-04-16 15:20:36 -07001872 * in that it puts the count both in the res struct and in the
1873 * opaque data count. */
1874 count = ntohl(*p++);
1875 res->eof = ntohl(*p++);
1876 ocount = ntohl(*p++);
1877
1878 if (ocount != count) {
Chuck Leverfe82a182007-09-11 18:01:10 -04001879 dprintk("NFS: READ count doesn't match RPC opaque count.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001880 return -errno_NFSERR_IO;
1881 }
1882
1883 hdrlen = (u8 *) p - (u8 *) iov->iov_base;
1884 if (iov->iov_len < hdrlen) {
Chuck Leverfe82a182007-09-11 18:01:10 -04001885 dprintk("NFS: READ reply header overflowed:"
Chuck Leverc957c522007-10-26 13:31:57 -04001886 "length %Zu > %Zu\n", hdrlen, iov->iov_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001887 return -errno_NFSERR_IO;
1888 } else if (iov->iov_len != hdrlen) {
1889 dprintk("NFS: READ header is short. iovec will be shifted.\n");
1890 xdr_shift_buf(&req->rq_rcv_buf, iov->iov_len - hdrlen);
1891 }
1892
1893 recvd = req->rq_rcv_buf.len - hdrlen;
1894 if (count > recvd) {
Chuck Leverfe82a182007-09-11 18:01:10 -04001895 dprintk("NFS: server cheating in read reply: "
Chuck Leverc957c522007-10-26 13:31:57 -04001896 "count %u > recvd %u\n", count, recvd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001897 count = recvd;
1898 res->eof = 0;
1899 }
1900
1901 if (count < res->count)
1902 res->count = count;
1903
1904 return count;
1905}
1906
1907/*
Chuck Levere4f93232010-12-14 14:56:30 +00001908 * 3.3.6 READ3res
1909 *
1910 * struct READ3resok {
1911 * post_op_attr file_attributes;
1912 * count3 count;
1913 * bool eof;
1914 * opaque data<>;
1915 * };
1916 *
1917 * struct READ3resfail {
1918 * post_op_attr file_attributes;
1919 * };
1920 *
1921 * union READ3res switch (nfsstat3 status) {
1922 * case NFS3_OK:
1923 * READ3resok resok;
1924 * default:
1925 * READ3resfail resfail;
1926 * };
1927 */
1928static int decode_read3resok(struct xdr_stream *xdr,
1929 struct nfs_readres *result)
1930{
1931 u32 eof, count, ocount, recvd;
1932 size_t hdrlen;
1933 __be32 *p;
1934
1935 p = xdr_inline_decode(xdr, 4 + 4 + 4);
1936 if (unlikely(p == NULL))
1937 goto out_overflow;
1938 count = be32_to_cpup(p++);
1939 eof = be32_to_cpup(p++);
1940 ocount = be32_to_cpup(p++);
1941 if (unlikely(ocount != count))
1942 goto out_mismatch;
1943 hdrlen = (u8 *)xdr->p - (u8 *)xdr->iov->iov_base;
1944 recvd = xdr->buf->len - hdrlen;
1945 if (unlikely(count > recvd))
1946 goto out_cheating;
1947
1948out:
1949 xdr_read_pages(xdr, count);
1950 result->eof = eof;
1951 result->count = count;
1952 return count;
1953out_mismatch:
1954 dprintk("NFS: READ count doesn't match length of opaque: "
1955 "count %u != ocount %u\n", count, ocount);
1956 return -EIO;
1957out_cheating:
1958 dprintk("NFS: server cheating in read result: "
1959 "count %u > recvd %u\n", count, recvd);
1960 count = recvd;
1961 eof = 0;
1962 goto out;
1963out_overflow:
1964 print_overflow_msg(__func__, xdr);
1965 return -EIO;
1966}
1967
1968static int nfs3_xdr_dec_read3res(struct rpc_rqst *req, __be32 *p,
1969 struct nfs_readres *result)
1970{
1971 struct xdr_stream xdr;
1972 enum nfs_stat status;
1973 int error;
1974
1975 xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
1976 error = decode_nfsstat3(&xdr, &status);
1977 if (unlikely(error))
1978 goto out;
1979 error = decode_post_op_attr(&xdr, result->fattr);
1980 if (unlikely(error))
1981 goto out;
1982 if (status != NFS3_OK)
1983 goto out_status;
1984 error = decode_read3resok(&xdr, result);
1985out:
1986 return error;
1987out_status:
1988 return nfs_stat_to_errno(status);
1989}
1990
1991/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001992 * Decode WRITE response
1993 */
1994static int
Al Virod61005a2006-10-19 23:28:48 -07001995nfs3_xdr_writeres(struct rpc_rqst *req, __be32 *p, struct nfs_writeres *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001996{
1997 int status;
1998
1999 status = ntohl(*p++);
2000 p = xdr_decode_wcc_data(p, res->fattr);
2001
2002 if (status != 0)
Benny Halevy856dff32008-03-31 17:39:06 +03002003 return nfs_stat_to_errno(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002004
2005 res->count = ntohl(*p++);
2006 res->verf->committed = (enum nfs3_stable_how)ntohl(*p++);
2007 res->verf->verifier[0] = *p++;
2008 res->verf->verifier[1] = *p++;
2009
2010 return res->count;
2011}
2012
2013/*
Chuck Levere4f93232010-12-14 14:56:30 +00002014 * 3.3.7 WRITE3res
2015 *
2016 * enum stable_how {
2017 * UNSTABLE = 0,
2018 * DATA_SYNC = 1,
2019 * FILE_SYNC = 2
2020 * };
2021 *
2022 * struct WRITE3resok {
2023 * wcc_data file_wcc;
2024 * count3 count;
2025 * stable_how committed;
2026 * writeverf3 verf;
2027 * };
2028 *
2029 * struct WRITE3resfail {
2030 * wcc_data file_wcc;
2031 * };
2032 *
2033 * union WRITE3res switch (nfsstat3 status) {
2034 * case NFS3_OK:
2035 * WRITE3resok resok;
2036 * default:
2037 * WRITE3resfail resfail;
2038 * };
2039 */
2040static int decode_write3resok(struct xdr_stream *xdr,
2041 struct nfs_writeres *result)
2042{
2043 __be32 *p;
2044
2045 p = xdr_inline_decode(xdr, 4 + 4 + NFS3_WRITEVERFSIZE);
2046 if (unlikely(p == NULL))
2047 goto out_overflow;
2048 result->count = be32_to_cpup(p++);
2049 result->verf->committed = be32_to_cpup(p++);
2050 if (unlikely(result->verf->committed > NFS_FILE_SYNC))
2051 goto out_badvalue;
2052 memcpy(result->verf->verifier, p, NFS3_WRITEVERFSIZE);
2053 return result->count;
2054out_badvalue:
2055 dprintk("NFS: bad stable_how value: %u\n", result->verf->committed);
2056 return -EIO;
2057out_overflow:
2058 print_overflow_msg(__func__, xdr);
2059 return -EIO;
2060}
2061
2062static int nfs3_xdr_dec_write3res(struct rpc_rqst *req, __be32 *p,
2063 struct nfs_writeres *result)
2064{
2065 struct xdr_stream xdr;
2066 enum nfs_stat status;
2067 int error;
2068
2069 xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
2070 error = decode_nfsstat3(&xdr, &status);
2071 if (unlikely(error))
2072 goto out;
2073 error = decode_wcc_data(&xdr, result->fattr);
2074 if (unlikely(error))
2075 goto out;
2076 if (status != NFS3_OK)
2077 goto out_status;
2078 error = decode_write3resok(&xdr, result);
2079out:
2080 return error;
2081out_status:
2082 return nfs_stat_to_errno(status);
2083}
2084
2085/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002086 * Decode a CREATE response
2087 */
2088static int
Al Virod61005a2006-10-19 23:28:48 -07002089nfs3_xdr_createres(struct rpc_rqst *req, __be32 *p, struct nfs3_diropres *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002090{
2091 int status;
2092
2093 status = ntohl(*p++);
2094 if (status == 0) {
2095 if (*p++) {
2096 if (!(p = xdr_decode_fhandle(p, res->fh)))
2097 return -errno_NFSERR_IO;
2098 p = xdr_decode_post_op_attr(p, res->fattr);
2099 } else {
2100 memset(res->fh, 0, sizeof(*res->fh));
2101 /* Do decode post_op_attr but set it to NULL */
2102 p = xdr_decode_post_op_attr(p, res->fattr);
2103 res->fattr->valid = 0;
2104 }
2105 } else {
Benny Halevy856dff32008-03-31 17:39:06 +03002106 status = nfs_stat_to_errno(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002107 }
2108 p = xdr_decode_wcc_data(p, res->dir_attr);
2109 return status;
2110}
2111
2112/*
Chuck Levere4f93232010-12-14 14:56:30 +00002113 * 3.3.8 CREATE3res
2114 *
2115 * struct CREATE3resok {
2116 * post_op_fh3 obj;
2117 * post_op_attr obj_attributes;
2118 * wcc_data dir_wcc;
2119 * };
2120 *
2121 * struct CREATE3resfail {
2122 * wcc_data dir_wcc;
2123 * };
2124 *
2125 * union CREATE3res switch (nfsstat3 status) {
2126 * case NFS3_OK:
2127 * CREATE3resok resok;
2128 * default:
2129 * CREATE3resfail resfail;
2130 * };
2131 */
2132static int decode_create3resok(struct xdr_stream *xdr,
2133 struct nfs3_diropres *result)
2134{
2135 int error;
2136
2137 error = decode_post_op_fh3(xdr, result->fh);
2138 if (unlikely(error))
2139 goto out;
2140 error = decode_post_op_attr(xdr, result->fattr);
2141 if (unlikely(error))
2142 goto out;
2143 /* The server isn't required to return a file handle.
2144 * If it didn't, force the client to perform a LOOKUP
2145 * to determine the correct file handle and attribute
2146 * values for the new object. */
2147 if (result->fh->size == 0)
2148 result->fattr->valid = 0;
2149 error = decode_wcc_data(xdr, result->dir_attr);
2150out:
2151 return error;
2152}
2153
2154static int nfs3_xdr_dec_create3res(struct rpc_rqst *req, __be32 *p,
2155 struct nfs3_diropres *result)
2156{
2157 struct xdr_stream xdr;
2158 enum nfs_stat status;
2159 int error;
2160
2161 xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
2162 error = decode_nfsstat3(&xdr, &status);
2163 if (unlikely(error))
2164 goto out;
2165 if (status != NFS3_OK)
2166 goto out_default;
2167 error = decode_create3resok(&xdr, result);
2168out:
2169 return error;
2170out_default:
2171 error = decode_wcc_data(&xdr, result->dir_attr);
2172 if (unlikely(error))
2173 goto out;
2174 return nfs_stat_to_errno(status);
2175}
2176
2177/*
2178 * 3.3.12 REMOVE3res
2179 *
2180 * struct REMOVE3resok {
2181 * wcc_data dir_wcc;
2182 * };
2183 *
2184 * struct REMOVE3resfail {
2185 * wcc_data dir_wcc;
2186 * };
2187 *
2188 * union REMOVE3res switch (nfsstat3 status) {
2189 * case NFS3_OK:
2190 * REMOVE3resok resok;
2191 * default:
2192 * REMOVE3resfail resfail;
2193 * };
2194 */
2195static int nfs3_xdr_dec_remove3res(struct rpc_rqst *req, __be32 *p,
2196 struct nfs_removeres *result)
2197{
2198 struct xdr_stream xdr;
2199 enum nfs_stat status;
2200 int error;
2201
2202 xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
2203 error = decode_nfsstat3(&xdr, &status);
2204 if (unlikely(error))
2205 goto out;
2206 error = decode_wcc_data(&xdr, result->dir_attr);
2207 if (unlikely(error))
2208 goto out;
2209 if (status != NFS3_OK)
2210 goto out_status;
2211out:
2212 return error;
2213out_status:
2214 return nfs_stat_to_errno(status);
2215}
2216
2217/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002218 * Decode RENAME reply
2219 */
2220static int
Jeff Laytone8582a82010-09-17 17:31:06 -04002221nfs3_xdr_renameres(struct rpc_rqst *req, __be32 *p, struct nfs_renameres *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002222{
2223 int status;
2224
2225 if ((status = ntohl(*p++)) != 0)
Benny Halevy856dff32008-03-31 17:39:06 +03002226 status = nfs_stat_to_errno(status);
Jeff Laytone8582a82010-09-17 17:31:06 -04002227 p = xdr_decode_wcc_data(p, res->old_fattr);
2228 p = xdr_decode_wcc_data(p, res->new_fattr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002229 return status;
2230}
2231
2232/*
Chuck Levere4f93232010-12-14 14:56:30 +00002233 * 3.3.14 RENAME3res
2234 *
2235 * struct RENAME3resok {
2236 * wcc_data fromdir_wcc;
2237 * wcc_data todir_wcc;
2238 * };
2239 *
2240 * struct RENAME3resfail {
2241 * wcc_data fromdir_wcc;
2242 * wcc_data todir_wcc;
2243 * };
2244 *
2245 * union RENAME3res switch (nfsstat3 status) {
2246 * case NFS3_OK:
2247 * RENAME3resok resok;
2248 * default:
2249 * RENAME3resfail resfail;
2250 * };
2251 */
2252static int nfs3_xdr_dec_rename3res(struct rpc_rqst *req, __be32 *p,
2253 struct nfs_renameres *result)
2254{
2255 struct xdr_stream xdr;
2256 enum nfs_stat status;
2257 int error;
2258
2259 xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
2260 error = decode_nfsstat3(&xdr, &status);
2261 if (unlikely(error))
2262 goto out;
2263 error = decode_wcc_data(&xdr, result->old_fattr);
2264 if (unlikely(error))
2265 goto out;
2266 error = decode_wcc_data(&xdr, result->new_fattr);
2267 if (unlikely(error))
2268 goto out;
2269 if (status != NFS3_OK)
2270 goto out_status;
2271out:
2272 return error;
2273out_status:
2274 return nfs_stat_to_errno(status);
2275}
2276
2277/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002278 * Decode LINK reply
2279 */
2280static int
Al Virod61005a2006-10-19 23:28:48 -07002281nfs3_xdr_linkres(struct rpc_rqst *req, __be32 *p, struct nfs3_linkres *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002282{
2283 int status;
2284
2285 if ((status = ntohl(*p++)) != 0)
Benny Halevy856dff32008-03-31 17:39:06 +03002286 status = nfs_stat_to_errno(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002287 p = xdr_decode_post_op_attr(p, res->fattr);
2288 p = xdr_decode_wcc_data(p, res->dir_attr);
2289 return status;
2290}
2291
2292/*
Chuck Levere4f93232010-12-14 14:56:30 +00002293 * 3.3.15 LINK3res
2294 *
2295 * struct LINK3resok {
2296 * post_op_attr file_attributes;
2297 * wcc_data linkdir_wcc;
2298 * };
2299 *
2300 * struct LINK3resfail {
2301 * post_op_attr file_attributes;
2302 * wcc_data linkdir_wcc;
2303 * };
2304 *
2305 * union LINK3res switch (nfsstat3 status) {
2306 * case NFS3_OK:
2307 * LINK3resok resok;
2308 * default:
2309 * LINK3resfail resfail;
2310 * };
2311 */
2312static int nfs3_xdr_dec_link3res(struct rpc_rqst *req, __be32 *p,
2313 struct nfs3_linkres *result)
2314{
2315 struct xdr_stream xdr;
2316 enum nfs_stat status;
2317 int error;
2318
2319 xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
2320 error = decode_nfsstat3(&xdr, &status);
2321 if (unlikely(error))
2322 goto out;
2323 error = decode_post_op_attr(&xdr, result->fattr);
2324 if (unlikely(error))
2325 goto out;
2326 error = decode_wcc_data(&xdr, result->dir_attr);
2327 if (unlikely(error))
2328 goto out;
2329 if (status != NFS3_OK)
2330 goto out_status;
2331out:
2332 return error;
2333out_status:
2334 return nfs_stat_to_errno(status);
2335}
2336
2337/**
2338 * nfs3_decode_dirent - Decode a single NFSv3 directory entry stored in
2339 * the local page cache
2340 * @xdr: XDR stream where entry resides
2341 * @entry: buffer to fill in with entry data
2342 * @server: nfs_server data for this directory
2343 * @plus: boolean indicating whether this should be a readdirplus entry
2344 *
2345 * Returns the position of the next item in the buffer, or an ERR_PTR.
2346 *
2347 * This function is not invoked during READDIR reply decoding, but
2348 * rather whenever an application invokes the getdents(2) system call
2349 * on a directory already in our cache.
2350 *
2351 * 3.3.16 entry3
2352 *
2353 * struct entry3 {
2354 * fileid3 fileid;
2355 * filename3 name;
2356 * cookie3 cookie;
2357 * fhandle3 filehandle;
2358 * post_op_attr3 attributes;
2359 * entry3 *nextentry;
2360 * };
2361 *
2362 * 3.3.17 entryplus3
2363 * struct entryplus3 {
2364 * fileid3 fileid;
2365 * filename3 name;
2366 * cookie3 cookie;
2367 * post_op_attr name_attributes;
2368 * post_op_fh3 name_handle;
2369 * entryplus3 *nextentry;
2370 * };
2371 */
2372__be32 *nfs3_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry,
2373 struct nfs_server *server, int plus)
2374{
2375 struct nfs_entry old = *entry;
2376 __be32 *p;
2377 int error;
2378
2379 p = xdr_inline_decode(xdr, 4);
2380 if (unlikely(p == NULL))
2381 goto out_overflow;
2382 if (*p == xdr_zero) {
2383 p = xdr_inline_decode(xdr, 4);
2384 if (unlikely(p == NULL))
2385 goto out_overflow;
2386 if (*p == xdr_zero)
2387 return ERR_PTR(-EAGAIN);
2388 entry->eof = 1;
2389 return ERR_PTR(-EBADCOOKIE);
2390 }
2391
2392 error = decode_fileid3(xdr, &entry->ino);
2393 if (unlikely(error))
2394 return ERR_PTR(error);
2395
2396 error = decode_inline_filename3(xdr, &entry->name, &entry->len);
2397 if (unlikely(error))
2398 return ERR_PTR(error);
2399
2400 entry->prev_cookie = entry->cookie;
2401 error = decode_cookie3(xdr, &entry->cookie);
2402 if (unlikely(error))
2403 return ERR_PTR(error);
2404
2405 entry->d_type = DT_UNKNOWN;
2406
2407 if (plus) {
2408 entry->fattr->valid = 0;
2409 error = decode_post_op_attr(xdr, entry->fattr);
2410 if (unlikely(error))
2411 return ERR_PTR(error);
2412 if (entry->fattr->valid & NFS_ATTR_FATTR_V3)
2413 entry->d_type = nfs_umode_to_dtype(entry->fattr->mode);
2414
2415 /* In fact, a post_op_fh3: */
2416 p = xdr_inline_decode(xdr, 4);
2417 if (unlikely(p == NULL))
2418 goto out_overflow;
2419 if (*p != xdr_zero) {
2420 error = decode_nfs_fh3(xdr, entry->fh);
2421 if (unlikely(error)) {
2422 if (error == -E2BIG)
2423 goto out_truncated;
2424 return ERR_PTR(error);
2425 }
2426 } else
2427 zero_nfs_fh3(entry->fh);
2428 }
2429
2430 /* Peek at the next entry to see if we're at EOD */
2431 p = xdr_inline_peek(xdr, 4 + 4);
2432 entry->eof = 0;
2433 if (p != NULL)
2434 entry->eof = (p[0] == xdr_zero) && (p[1] != xdr_zero);
2435 return p;
2436
2437out_overflow:
2438 print_overflow_msg(__func__, xdr);
2439 return ERR_PTR(-EAGAIN);
2440out_truncated:
2441 dprintk("NFS: directory entry contains invalid file handle\n");
2442 *entry = old;
2443 return ERR_PTR(-EAGAIN);
2444}
2445
2446/*
2447 * 3.3.16 READDIR3res
2448 *
2449 * struct dirlist3 {
2450 * entry3 *entries;
2451 * bool eof;
2452 * };
2453 *
2454 * struct READDIR3resok {
2455 * post_op_attr dir_attributes;
2456 * cookieverf3 cookieverf;
2457 * dirlist3 reply;
2458 * };
2459 *
2460 * struct READDIR3resfail {
2461 * post_op_attr dir_attributes;
2462 * };
2463 *
2464 * union READDIR3res switch (nfsstat3 status) {
2465 * case NFS3_OK:
2466 * READDIR3resok resok;
2467 * default:
2468 * READDIR3resfail resfail;
2469 * };
2470 *
2471 * Read the directory contents into the page cache, but otherwise
2472 * don't touch them. The actual decoding is done by nfs3_decode_entry()
2473 * during subsequent nfs_readdir() calls.
2474 */
2475static int decode_dirlist3(struct xdr_stream *xdr)
2476{
2477 u32 recvd, pglen;
2478 size_t hdrlen;
2479
2480 pglen = xdr->buf->page_len;
2481 hdrlen = (u8 *)xdr->p - (u8 *)xdr->iov->iov_base;
2482 recvd = xdr->buf->len - hdrlen;
2483 if (unlikely(pglen > recvd))
2484 goto out_cheating;
2485out:
2486 xdr_read_pages(xdr, pglen);
2487 return pglen;
2488out_cheating:
2489 dprintk("NFS: server cheating in readdir result: "
2490 "pglen %u > recvd %u\n", pglen, recvd);
2491 pglen = recvd;
2492 goto out;
2493}
2494
2495static int decode_readdir3resok(struct xdr_stream *xdr,
2496 struct nfs3_readdirres *result)
2497{
2498 int error;
2499
2500 error = decode_post_op_attr(xdr, result->dir_attr);
2501 if (unlikely(error))
2502 goto out;
2503 /* XXX: do we need to check if result->verf != NULL ? */
2504 error = decode_cookieverf3(xdr, result->verf);
2505 if (unlikely(error))
2506 goto out;
2507 error = decode_dirlist3(xdr);
2508out:
2509 return error;
2510}
2511
2512static int nfs3_xdr_dec_readdir3res(struct rpc_rqst *req, __be32 *p,
2513 struct nfs3_readdirres *result)
2514{
2515 struct xdr_stream xdr;
2516 enum nfs_stat status;
2517 int error;
2518
2519 xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
2520 error = decode_nfsstat3(&xdr, &status);
2521 if (unlikely(error))
2522 goto out;
2523 if (status != NFS3_OK)
2524 goto out_default;
2525 error = decode_readdir3resok(&xdr, result);
2526out:
2527 return error;
2528out_default:
2529 error = decode_post_op_attr(&xdr, result->dir_attr);
2530 if (unlikely(error))
2531 goto out;
2532 return nfs_stat_to_errno(status);
2533}
2534
2535/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002536 * Decode FSSTAT reply
2537 */
2538static int
Al Virod61005a2006-10-19 23:28:48 -07002539nfs3_xdr_fsstatres(struct rpc_rqst *req, __be32 *p, struct nfs_fsstat *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002540{
2541 int status;
2542
2543 status = ntohl(*p++);
2544
2545 p = xdr_decode_post_op_attr(p, res->fattr);
2546 if (status != 0)
Benny Halevy856dff32008-03-31 17:39:06 +03002547 return nfs_stat_to_errno(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002548
2549 p = xdr_decode_hyper(p, &res->tbytes);
2550 p = xdr_decode_hyper(p, &res->fbytes);
2551 p = xdr_decode_hyper(p, &res->abytes);
2552 p = xdr_decode_hyper(p, &res->tfiles);
2553 p = xdr_decode_hyper(p, &res->ffiles);
2554 p = xdr_decode_hyper(p, &res->afiles);
2555
2556 /* ignore invarsec */
2557 return 0;
2558}
2559
2560/*
Chuck Levere4f93232010-12-14 14:56:30 +00002561 * 3.3.18 FSSTAT3res
2562 *
2563 * struct FSSTAT3resok {
2564 * post_op_attr obj_attributes;
2565 * size3 tbytes;
2566 * size3 fbytes;
2567 * size3 abytes;
2568 * size3 tfiles;
2569 * size3 ffiles;
2570 * size3 afiles;
2571 * uint32 invarsec;
2572 * };
2573 *
2574 * struct FSSTAT3resfail {
2575 * post_op_attr obj_attributes;
2576 * };
2577 *
2578 * union FSSTAT3res switch (nfsstat3 status) {
2579 * case NFS3_OK:
2580 * FSSTAT3resok resok;
2581 * default:
2582 * FSSTAT3resfail resfail;
2583 * };
2584 */
2585static int decode_fsstat3resok(struct xdr_stream *xdr,
2586 struct nfs_fsstat *result)
2587{
2588 __be32 *p;
2589
2590 p = xdr_inline_decode(xdr, 8 * 6 + 4);
2591 if (unlikely(p == NULL))
2592 goto out_overflow;
2593 p = xdr_decode_size3(p, &result->tbytes);
2594 p = xdr_decode_size3(p, &result->fbytes);
2595 p = xdr_decode_size3(p, &result->abytes);
2596 p = xdr_decode_size3(p, &result->tfiles);
2597 p = xdr_decode_size3(p, &result->ffiles);
2598 xdr_decode_size3(p, &result->afiles);
2599 /* ignore invarsec */
2600 return 0;
2601out_overflow:
2602 print_overflow_msg(__func__, xdr);
2603 return -EIO;
2604}
2605
2606static int nfs3_xdr_dec_fsstat3res(struct rpc_rqst *req, __be32 *p,
2607 struct nfs_fsstat *result)
2608{
2609 struct xdr_stream xdr;
2610 enum nfs_stat status;
2611 int error;
2612
2613 xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
2614 error = decode_nfsstat3(&xdr, &status);
2615 if (unlikely(error))
2616 goto out;
2617 error = decode_post_op_attr(&xdr, result->fattr);
2618 if (unlikely(error))
2619 goto out;
2620 if (status != NFS3_OK)
2621 goto out_status;
2622 error = decode_fsstat3resok(&xdr, result);
2623out:
2624 return error;
2625out_status:
2626 return nfs_stat_to_errno(status);
2627}
2628
2629/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002630 * Decode FSINFO reply
2631 */
2632static int
Al Virod61005a2006-10-19 23:28:48 -07002633nfs3_xdr_fsinfores(struct rpc_rqst *req, __be32 *p, struct nfs_fsinfo *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002634{
2635 int status;
2636
2637 status = ntohl(*p++);
2638
2639 p = xdr_decode_post_op_attr(p, res->fattr);
2640 if (status != 0)
Benny Halevy856dff32008-03-31 17:39:06 +03002641 return nfs_stat_to_errno(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002642
2643 res->rtmax = ntohl(*p++);
2644 res->rtpref = ntohl(*p++);
2645 res->rtmult = ntohl(*p++);
2646 res->wtmax = ntohl(*p++);
2647 res->wtpref = ntohl(*p++);
2648 res->wtmult = ntohl(*p++);
2649 res->dtpref = ntohl(*p++);
2650 p = xdr_decode_hyper(p, &res->maxfilesize);
Ricardo Labiaga6b967242010-10-12 16:30:05 -07002651 p = xdr_decode_time3(p, &res->time_delta);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002652
Ricardo Labiaga6b967242010-10-12 16:30:05 -07002653 /* ignore properties */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002654 res->lease_time = 0;
2655 return 0;
2656}
2657
2658/*
Chuck Levere4f93232010-12-14 14:56:30 +00002659 * 3.3.19 FSINFO3res
2660 *
2661 * struct FSINFO3resok {
2662 * post_op_attr obj_attributes;
2663 * uint32 rtmax;
2664 * uint32 rtpref;
2665 * uint32 rtmult;
2666 * uint32 wtmax;
2667 * uint32 wtpref;
2668 * uint32 wtmult;
2669 * uint32 dtpref;
2670 * size3 maxfilesize;
2671 * nfstime3 time_delta;
2672 * uint32 properties;
2673 * };
2674 *
2675 * struct FSINFO3resfail {
2676 * post_op_attr obj_attributes;
2677 * };
2678 *
2679 * union FSINFO3res switch (nfsstat3 status) {
2680 * case NFS3_OK:
2681 * FSINFO3resok resok;
2682 * default:
2683 * FSINFO3resfail resfail;
2684 * };
2685 */
2686static int decode_fsinfo3resok(struct xdr_stream *xdr,
2687 struct nfs_fsinfo *result)
2688{
2689 __be32 *p;
2690
2691 p = xdr_inline_decode(xdr, 4 * 7 + 8 + 8 + 4);
2692 if (unlikely(p == NULL))
2693 goto out_overflow;
2694 result->rtmax = be32_to_cpup(p++);
2695 result->rtpref = be32_to_cpup(p++);
2696 result->rtmult = be32_to_cpup(p++);
2697 result->wtmax = be32_to_cpup(p++);
2698 result->wtpref = be32_to_cpup(p++);
2699 result->wtmult = be32_to_cpup(p++);
2700 result->dtpref = be32_to_cpup(p++);
2701 p = xdr_decode_size3(p, &result->maxfilesize);
2702 xdr_decode_time3(p, &result->time_delta);
2703
2704 /* ignore properties */
2705 result->lease_time = 0;
2706 return 0;
2707out_overflow:
2708 print_overflow_msg(__func__, xdr);
2709 return -EIO;
2710}
2711
2712static int nfs3_xdr_dec_fsinfo3res(struct rpc_rqst *req, __be32 *p,
2713 struct nfs_fsinfo *result)
2714{
2715 struct xdr_stream xdr;
2716 enum nfs_stat status;
2717 int error;
2718
2719 xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
2720 error = decode_nfsstat3(&xdr, &status);
2721 if (unlikely(error))
2722 goto out;
2723 error = decode_post_op_attr(&xdr, result->fattr);
2724 if (unlikely(error))
2725 goto out;
2726 if (status != NFS3_OK)
2727 goto out_status;
2728 error = decode_fsinfo3resok(&xdr, result);
2729out:
2730 return error;
2731out_status:
2732 return nfs_stat_to_errno(status);
2733}
2734
2735/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002736 * Decode PATHCONF reply
2737 */
2738static int
Al Virod61005a2006-10-19 23:28:48 -07002739nfs3_xdr_pathconfres(struct rpc_rqst *req, __be32 *p, struct nfs_pathconf *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002740{
2741 int status;
2742
2743 status = ntohl(*p++);
2744
2745 p = xdr_decode_post_op_attr(p, res->fattr);
2746 if (status != 0)
Benny Halevy856dff32008-03-31 17:39:06 +03002747 return nfs_stat_to_errno(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002748 res->max_link = ntohl(*p++);
2749 res->max_namelen = ntohl(*p++);
2750
2751 /* ignore remaining fields */
2752 return 0;
2753}
2754
2755/*
Chuck Levere4f93232010-12-14 14:56:30 +00002756 * 3.3.20 PATHCONF3res
2757 *
2758 * struct PATHCONF3resok {
2759 * post_op_attr obj_attributes;
2760 * uint32 linkmax;
2761 * uint32 name_max;
2762 * bool no_trunc;
2763 * bool chown_restricted;
2764 * bool case_insensitive;
2765 * bool case_preserving;
2766 * };
2767 *
2768 * struct PATHCONF3resfail {
2769 * post_op_attr obj_attributes;
2770 * };
2771 *
2772 * union PATHCONF3res switch (nfsstat3 status) {
2773 * case NFS3_OK:
2774 * PATHCONF3resok resok;
2775 * default:
2776 * PATHCONF3resfail resfail;
2777 * };
2778 */
2779static int decode_pathconf3resok(struct xdr_stream *xdr,
2780 struct nfs_pathconf *result)
2781{
2782 __be32 *p;
2783
2784 p = xdr_inline_decode(xdr, 4 * 6);
2785 if (unlikely(p == NULL))
2786 goto out_overflow;
2787 result->max_link = be32_to_cpup(p++);
2788 result->max_namelen = be32_to_cpup(p);
2789 /* ignore remaining fields */
2790 return 0;
2791out_overflow:
2792 print_overflow_msg(__func__, xdr);
2793 return -EIO;
2794}
2795
2796static int nfs3_xdr_dec_pathconf3res(struct rpc_rqst *req, __be32 *p,
2797 struct nfs_pathconf *result)
2798{
2799 struct xdr_stream xdr;
2800 enum nfs_stat status;
2801 int error;
2802
2803 xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
2804 error = decode_nfsstat3(&xdr, &status);
2805 if (unlikely(error))
2806 goto out;
2807 error = decode_post_op_attr(&xdr, result->fattr);
2808 if (unlikely(error))
2809 goto out;
2810 if (status != NFS3_OK)
2811 goto out_status;
2812 error = decode_pathconf3resok(&xdr, result);
2813out:
2814 return error;
2815out_status:
2816 return nfs_stat_to_errno(status);
2817}
2818
2819/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002820 * Decode COMMIT reply
2821 */
2822static int
Al Virod61005a2006-10-19 23:28:48 -07002823nfs3_xdr_commitres(struct rpc_rqst *req, __be32 *p, struct nfs_writeres *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002824{
2825 int status;
2826
2827 status = ntohl(*p++);
2828 p = xdr_decode_wcc_data(p, res->fattr);
2829 if (status != 0)
Benny Halevy856dff32008-03-31 17:39:06 +03002830 return nfs_stat_to_errno(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002831
2832 res->verf->verifier[0] = *p++;
2833 res->verf->verifier[1] = *p++;
2834 return 0;
2835}
2836
Chuck Levere4f93232010-12-14 14:56:30 +00002837/*
2838 * 3.3.21 COMMIT3res
2839 *
2840 * struct COMMIT3resok {
2841 * wcc_data file_wcc;
2842 * writeverf3 verf;
2843 * };
2844 *
2845 * struct COMMIT3resfail {
2846 * wcc_data file_wcc;
2847 * };
2848 *
2849 * union COMMIT3res switch (nfsstat3 status) {
2850 * case NFS3_OK:
2851 * COMMIT3resok resok;
2852 * default:
2853 * COMMIT3resfail resfail;
2854 * };
2855 */
2856static int nfs3_xdr_dec_commit3res(struct rpc_rqst *req, __be32 *p,
2857 struct nfs_writeres *result)
2858{
2859 struct xdr_stream xdr;
2860 enum nfs_stat status;
2861 int error;
2862
2863 xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
2864 error = decode_nfsstat3(&xdr, &status);
2865 if (unlikely(error))
2866 goto out;
2867 error = decode_wcc_data(&xdr, result->fattr);
2868 if (unlikely(error))
2869 goto out;
2870 if (status != NFS3_OK)
2871 goto out_status;
2872 error = decode_writeverf3(&xdr, result->verf->verifier);
2873out:
2874 return error;
2875out_status:
2876 return nfs_stat_to_errno(status);
2877}
2878
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +00002879#ifdef CONFIG_NFS_V3_ACL
2880/*
2881 * Decode GETACL reply
2882 */
2883static int
Al Virod61005a2006-10-19 23:28:48 -07002884nfs3_xdr_getaclres(struct rpc_rqst *req, __be32 *p,
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +00002885 struct nfs3_getaclres *res)
2886{
2887 struct xdr_buf *buf = &req->rq_rcv_buf;
2888 int status = ntohl(*p++);
2889 struct posix_acl **acl;
2890 unsigned int *aclcnt;
2891 int err, base;
2892
2893 if (status != 0)
Benny Halevy856dff32008-03-31 17:39:06 +03002894 return nfs_stat_to_errno(status);
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +00002895 p = xdr_decode_post_op_attr(p, res->fattr);
2896 res->mask = ntohl(*p++);
2897 if (res->mask & ~(NFS_ACL|NFS_ACLCNT|NFS_DFACL|NFS_DFACLCNT))
2898 return -EINVAL;
2899 base = (char *)p - (char *)req->rq_rcv_buf.head->iov_base;
2900
2901 acl = (res->mask & NFS_ACL) ? &res->acl_access : NULL;
2902 aclcnt = (res->mask & NFS_ACLCNT) ? &res->acl_access_count : NULL;
2903 err = nfsacl_decode(buf, base, aclcnt, acl);
2904
2905 acl = (res->mask & NFS_DFACL) ? &res->acl_default : NULL;
2906 aclcnt = (res->mask & NFS_DFACLCNT) ? &res->acl_default_count : NULL;
2907 if (err > 0)
2908 err = nfsacl_decode(buf, base + err, aclcnt, acl);
2909 return (err > 0) ? 0 : err;
2910}
2911
Chuck Levere4f93232010-12-14 14:56:30 +00002912static inline int decode_getacl3resok(struct xdr_stream *xdr,
2913 struct nfs3_getaclres *result)
2914{
2915 struct posix_acl **acl;
2916 unsigned int *aclcnt;
2917 size_t hdrlen;
2918 int error;
2919
2920 error = decode_post_op_attr(xdr, result->fattr);
2921 if (unlikely(error))
2922 goto out;
2923 error = decode_uint32(xdr, &result->mask);
2924 if (unlikely(error))
2925 goto out;
2926 error = -EINVAL;
2927 if (result->mask & ~(NFS_ACL|NFS_ACLCNT|NFS_DFACL|NFS_DFACLCNT))
2928 goto out;
2929
2930 hdrlen = (u8 *)xdr->p - (u8 *)xdr->iov->iov_base;
2931
2932 acl = NULL;
2933 if (result->mask & NFS_ACL)
2934 acl = &result->acl_access;
2935 aclcnt = NULL;
2936 if (result->mask & NFS_ACLCNT)
2937 aclcnt = &result->acl_access_count;
2938 error = nfsacl_decode(xdr->buf, hdrlen, aclcnt, acl);
2939 if (unlikely(error <= 0))
2940 goto out;
2941
2942 acl = NULL;
2943 if (result->mask & NFS_DFACL)
2944 acl = &result->acl_default;
2945 aclcnt = NULL;
2946 if (result->mask & NFS_DFACLCNT)
2947 aclcnt = &result->acl_default_count;
2948 error = nfsacl_decode(xdr->buf, hdrlen + error, aclcnt, acl);
2949 if (unlikely(error <= 0))
2950 return error;
2951 error = 0;
2952out:
2953 return error;
2954}
2955
2956static int nfs3_xdr_dec_getacl3res(struct rpc_rqst *req, __be32 *p,
2957 struct nfs3_getaclres *result)
2958{
2959 struct xdr_stream xdr;
2960 enum nfs_stat status;
2961 int error;
2962
2963 xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
2964 error = decode_nfsstat3(&xdr, &status);
2965 if (unlikely(error))
2966 goto out;
2967 if (status != NFS3_OK)
2968 goto out_default;
2969 error = decode_getacl3resok(&xdr, result);
2970out:
2971 return error;
2972out_default:
2973 return nfs_stat_to_errno(status);
2974}
2975
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +00002976/*
2977 * Decode setacl reply.
2978 */
2979static int
Al Virod61005a2006-10-19 23:28:48 -07002980nfs3_xdr_setaclres(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +00002981{
2982 int status = ntohl(*p++);
2983
2984 if (status)
Benny Halevy856dff32008-03-31 17:39:06 +03002985 return nfs_stat_to_errno(status);
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +00002986 xdr_decode_post_op_attr(p, fattr);
2987 return 0;
2988}
Chuck Levere4f93232010-12-14 14:56:30 +00002989
2990static int nfs3_xdr_dec_setacl3res(struct rpc_rqst *req, __be32 *p,
2991 struct nfs_fattr *result)
2992{
2993 struct xdr_stream xdr;
2994 enum nfs_stat status;
2995 int error;
2996
2997 xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
2998 error = decode_nfsstat3(&xdr, &status);
2999 if (unlikely(error))
3000 goto out;
3001 if (status != NFS3_OK)
3002 goto out_default;
3003 error = decode_post_op_attr(&xdr, result);
3004out:
3005 return error;
3006out_default:
3007 return nfs_stat_to_errno(status);
3008}
3009
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +00003010#endif /* CONFIG_NFS_V3_ACL */
3011
Linus Torvalds1da177e2005-04-16 15:20:36 -07003012#define PROC(proc, argtype, restype, timer) \
3013[NFS3PROC_##proc] = { \
3014 .p_proc = NFS3PROC_##proc, \
Chuck Leverad96b5b2010-12-14 14:56:01 +00003015 .p_encode = (kxdrproc_t)nfs3_xdr_enc_##argtype##3args, \
Chuck Leverf5fc3c502010-12-14 14:56:42 +00003016 .p_decode = (kxdrproc_t)nfs3_xdr_dec_##restype##3res, \
Chuck Leverad96b5b2010-12-14 14:56:01 +00003017 .p_arglen = NFS3_##argtype##args_sz, \
Chuck Leverf5fc3c502010-12-14 14:56:42 +00003018 .p_replen = NFS3_##restype##res_sz, \
Chuck Levercc0175c2006-03-20 13:44:22 -05003019 .p_timer = timer, \
3020 .p_statidx = NFS3PROC_##proc, \
3021 .p_name = #proc, \
Linus Torvalds1da177e2005-04-16 15:20:36 -07003022 }
3023
3024struct rpc_procinfo nfs3_procedures[] = {
Chuck Leverf5fc3c502010-12-14 14:56:42 +00003025 PROC(GETATTR, getattr, getattr, 1),
3026 PROC(SETATTR, setattr, setattr, 0),
3027 PROC(LOOKUP, lookup, lookup, 2),
3028 PROC(ACCESS, access, access, 1),
3029 PROC(READLINK, readlink, readlink, 3),
3030 PROC(READ, read, read, 3),
3031 PROC(WRITE, write, write, 4),
3032 PROC(CREATE, create, create, 0),
3033 PROC(MKDIR, mkdir, create, 0),
3034 PROC(SYMLINK, symlink, create, 0),
3035 PROC(MKNOD, mknod, create, 0),
3036 PROC(REMOVE, remove, remove, 0),
3037 PROC(RMDIR, lookup, setattr, 0),
3038 PROC(RENAME, rename, rename, 0),
3039 PROC(LINK, link, link, 0),
3040 PROC(READDIR, readdir, readdir, 3),
3041 PROC(READDIRPLUS, readdirplus, readdir, 3),
3042 PROC(FSSTAT, getattr, fsstat, 0),
3043 PROC(FSINFO, getattr, fsinfo, 0),
3044 PROC(PATHCONF, getattr, pathconf, 0),
3045 PROC(COMMIT, commit, commit, 5),
Linus Torvalds1da177e2005-04-16 15:20:36 -07003046};
3047
3048struct rpc_version nfs_version3 = {
3049 .number = 3,
Tobias Klausere8c96f82006-03-24 03:15:34 -08003050 .nrprocs = ARRAY_SIZE(nfs3_procedures),
Linus Torvalds1da177e2005-04-16 15:20:36 -07003051 .procs = nfs3_procedures
3052};
3053
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +00003054#ifdef CONFIG_NFS_V3_ACL
3055static struct rpc_procinfo nfs3_acl_procedures[] = {
3056 [ACLPROC3_GETACL] = {
3057 .p_proc = ACLPROC3_GETACL,
Chuck Leverad96b5b2010-12-14 14:56:01 +00003058 .p_encode = (kxdrproc_t)nfs3_xdr_enc_getacl3args,
Chuck Leverf5fc3c502010-12-14 14:56:42 +00003059 .p_decode = (kxdrproc_t)nfs3_xdr_dec_getacl3res,
Chuck Lever2bea90d2007-03-29 16:47:53 -04003060 .p_arglen = ACL3_getaclargs_sz,
3061 .p_replen = ACL3_getaclres_sz,
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +00003062 .p_timer = 1,
Chuck Levercc0175c2006-03-20 13:44:22 -05003063 .p_name = "GETACL",
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +00003064 },
3065 [ACLPROC3_SETACL] = {
3066 .p_proc = ACLPROC3_SETACL,
Chuck Leverad96b5b2010-12-14 14:56:01 +00003067 .p_encode = (kxdrproc_t)nfs3_xdr_enc_setacl3args,
Chuck Leverf5fc3c502010-12-14 14:56:42 +00003068 .p_decode = (kxdrproc_t)nfs3_xdr_dec_setacl3res,
Chuck Lever2bea90d2007-03-29 16:47:53 -04003069 .p_arglen = ACL3_setaclargs_sz,
3070 .p_replen = ACL3_setaclres_sz,
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +00003071 .p_timer = 0,
Chuck Levercc0175c2006-03-20 13:44:22 -05003072 .p_name = "SETACL",
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +00003073 },
3074};
3075
3076struct rpc_version nfsacl_version3 = {
3077 .number = 3,
3078 .nrprocs = sizeof(nfs3_acl_procedures)/
3079 sizeof(nfs3_acl_procedures[0]),
3080 .procs = nfs3_acl_procedures,
3081};
3082#endif /* CONFIG_NFS_V3_ACL */