blob: b0af263e4db9c2aff0f8162d0ada368ce2fcc0c6 [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 Myklebustae461412009-03-10 20:33:18 -040087#define ACL3_setaclargs_sz (NFS3_fh_sz+1+ \
88 XDR_QUADLEN(NFS_ACL_INLINE_BUFSIZE))
89#define ACL3_getaclres_sz (1+NFS3_post_op_attr_sz+1+ \
90 XDR_QUADLEN(NFS_ACL_INLINE_BUFSIZE))
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +000091#define ACL3_setaclres_sz (1+NFS3_post_op_attr_sz)
92
Linus Torvalds1da177e2005-04-16 15:20:36 -070093/*
94 * Map file type to S_IFMT bits
95 */
Trond Myklebustbca79472009-03-11 14:10:26 -040096static const umode_t nfs_type2fmt[] = {
97 [NF3BAD] = 0,
98 [NF3REG] = S_IFREG,
99 [NF3DIR] = S_IFDIR,
100 [NF3BLK] = S_IFBLK,
101 [NF3CHR] = S_IFCHR,
102 [NF3LNK] = S_IFLNK,
103 [NF3SOCK] = S_IFSOCK,
104 [NF3FIFO] = S_IFIFO,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700105};
106
Bryan Schumakerbabddc72010-10-20 15:44:29 -0400107static void print_overflow_msg(const char *func, const struct xdr_stream *xdr)
108{
109 dprintk("nfs: %s: prematurely hit end of receive buffer. "
110 "Remaining buffer length is %tu words.\n",
111 func, xdr->end - xdr->p);
112}
113
Linus Torvalds1da177e2005-04-16 15:20:36 -0700114/*
Chuck Leverd9c407b2010-12-14 14:55:50 +0000115 * While encoding arguments, set up the reply buffer in advance to
116 * receive reply data directly into the page cache.
117 */
118static void prepare_reply_buffer(struct rpc_rqst *req, struct page **pages,
119 unsigned int base, unsigned int len,
120 unsigned int bufsize)
121{
122 struct rpc_auth *auth = req->rq_cred->cr_auth;
123 unsigned int replen;
124
125 replen = RPC_REPHDRSIZE + auth->au_rslack + bufsize;
126 xdr_inline_pages(&req->rq_rcv_buf, replen << 2, pages, base, len);
127}
128
129
130/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700131 * Common NFS XDR functions as inlines
132 */
Al Virod61005a2006-10-19 23:28:48 -0700133static inline __be32 *
Al Virod61005a2006-10-19 23:28:48 -0700134xdr_decode_fhandle(__be32 *p, struct nfs_fh *fh)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700135{
136 if ((fh->size = ntohl(*p++)) <= NFS3_FHSIZE) {
137 memcpy(fh->data, p, fh->size);
138 return p + XDR_QUADLEN(fh->size);
139 }
140 return NULL;
141}
142
Bryan Schumakerbabddc72010-10-20 15:44:29 -0400143static inline __be32 *
144xdr_decode_fhandle_stream(struct xdr_stream *xdr, struct nfs_fh *fh)
145{
146 __be32 *p;
147 p = xdr_inline_decode(xdr, 4);
148 if (unlikely(!p))
149 goto out_overflow;
150 fh->size = ntohl(*p++);
151
152 if (fh->size <= NFS3_FHSIZE) {
153 p = xdr_inline_decode(xdr, fh->size);
154 if (unlikely(!p))
155 goto out_overflow;
156 memcpy(fh->data, p, fh->size);
157 return p + XDR_QUADLEN(fh->size);
158 }
159 return NULL;
160
161out_overflow:
162 print_overflow_msg(__func__, xdr);
163 return ERR_PTR(-EIO);
164}
165
Linus Torvalds1da177e2005-04-16 15:20:36 -0700166/*
167 * Encode/decode time.
168 */
Al Virod61005a2006-10-19 23:28:48 -0700169static inline __be32 *
Chuck Leverd9c407b2010-12-14 14:55:50 +0000170xdr_encode_time3(__be32 *p, const struct timespec *timep)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700171{
172 *p++ = htonl(timep->tv_sec);
173 *p++ = htonl(timep->tv_nsec);
174 return p;
175}
176
Al Virod61005a2006-10-19 23:28:48 -0700177static inline __be32 *
178xdr_decode_time3(__be32 *p, struct timespec *timep)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700179{
180 timep->tv_sec = ntohl(*p++);
181 timep->tv_nsec = ntohl(*p++);
182 return p;
183}
184
Al Virod61005a2006-10-19 23:28:48 -0700185static __be32 *
186xdr_decode_fattr(__be32 *p, struct nfs_fattr *fattr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700187{
188 unsigned int type, major, minor;
Trond Myklebustbca79472009-03-11 14:10:26 -0400189 umode_t fmode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700190
191 type = ntohl(*p++);
Trond Myklebustbca79472009-03-11 14:10:26 -0400192 if (type > NF3FIFO)
193 type = NF3NON;
194 fmode = nfs_type2fmt[type];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700195 fattr->mode = (ntohl(*p++) & ~S_IFMT) | fmode;
196 fattr->nlink = ntohl(*p++);
197 fattr->uid = ntohl(*p++);
198 fattr->gid = ntohl(*p++);
199 p = xdr_decode_hyper(p, &fattr->size);
200 p = xdr_decode_hyper(p, &fattr->du.nfs3.used);
201
202 /* Turn remote device info into Linux-specific dev_t */
203 major = ntohl(*p++);
204 minor = ntohl(*p++);
205 fattr->rdev = MKDEV(major, minor);
206 if (MAJOR(fattr->rdev) != major || MINOR(fattr->rdev) != minor)
207 fattr->rdev = 0;
208
Trond Myklebust8b4bdcf2006-06-09 09:34:19 -0400209 p = xdr_decode_hyper(p, &fattr->fsid.major);
210 fattr->fsid.minor = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700211 p = xdr_decode_hyper(p, &fattr->fileid);
212 p = xdr_decode_time3(p, &fattr->atime);
213 p = xdr_decode_time3(p, &fattr->mtime);
214 p = xdr_decode_time3(p, &fattr->ctime);
215
216 /* Update the mode bits */
Trond Myklebust9e6e70f2009-03-11 14:10:24 -0400217 fattr->valid |= NFS_ATTR_FATTR_V3;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700218 return p;
219}
220
Al Virod61005a2006-10-19 23:28:48 -0700221static inline __be32 *
Chuck Leverd9c407b2010-12-14 14:55:50 +0000222xdr_encode_sattr(__be32 *p, const struct iattr *attr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700223{
224 if (attr->ia_valid & ATTR_MODE) {
225 *p++ = xdr_one;
Trond Myklebustcf3fff52006-01-03 09:55:53 +0100226 *p++ = htonl(attr->ia_mode & S_IALLUGO);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700227 } else {
228 *p++ = xdr_zero;
229 }
230 if (attr->ia_valid & ATTR_UID) {
231 *p++ = xdr_one;
232 *p++ = htonl(attr->ia_uid);
233 } else {
234 *p++ = xdr_zero;
235 }
236 if (attr->ia_valid & ATTR_GID) {
237 *p++ = xdr_one;
238 *p++ = htonl(attr->ia_gid);
239 } else {
240 *p++ = xdr_zero;
241 }
242 if (attr->ia_valid & ATTR_SIZE) {
243 *p++ = xdr_one;
244 p = xdr_encode_hyper(p, (__u64) attr->ia_size);
245 } else {
246 *p++ = xdr_zero;
247 }
248 if (attr->ia_valid & ATTR_ATIME_SET) {
249 *p++ = xdr_two;
250 p = xdr_encode_time3(p, &attr->ia_atime);
251 } else if (attr->ia_valid & ATTR_ATIME) {
252 *p++ = xdr_one;
253 } else {
254 *p++ = xdr_zero;
255 }
256 if (attr->ia_valid & ATTR_MTIME_SET) {
257 *p++ = xdr_two;
258 p = xdr_encode_time3(p, &attr->ia_mtime);
259 } else if (attr->ia_valid & ATTR_MTIME) {
260 *p++ = xdr_one;
261 } else {
262 *p++ = xdr_zero;
263 }
264 return p;
265}
266
Al Virod61005a2006-10-19 23:28:48 -0700267static inline __be32 *
268xdr_decode_wcc_attr(__be32 *p, struct nfs_fattr *fattr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700269{
270 p = xdr_decode_hyper(p, &fattr->pre_size);
271 p = xdr_decode_time3(p, &fattr->pre_mtime);
272 p = xdr_decode_time3(p, &fattr->pre_ctime);
Trond Myklebust9e6e70f2009-03-11 14:10:24 -0400273 fattr->valid |= NFS_ATTR_FATTR_PRESIZE
274 | NFS_ATTR_FATTR_PREMTIME
275 | NFS_ATTR_FATTR_PRECTIME;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276 return p;
277}
278
Al Virod61005a2006-10-19 23:28:48 -0700279static inline __be32 *
280xdr_decode_post_op_attr(__be32 *p, struct nfs_fattr *fattr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700281{
282 if (*p++)
283 p = xdr_decode_fattr(p, fattr);
284 return p;
285}
286
Al Virod61005a2006-10-19 23:28:48 -0700287static inline __be32 *
Bryan Schumakerbabddc72010-10-20 15:44:29 -0400288xdr_decode_post_op_attr_stream(struct xdr_stream *xdr, struct nfs_fattr *fattr)
289{
290 __be32 *p;
291
292 p = xdr_inline_decode(xdr, 4);
293 if (unlikely(!p))
294 goto out_overflow;
295 if (ntohl(*p++)) {
296 p = xdr_inline_decode(xdr, 84);
297 if (unlikely(!p))
298 goto out_overflow;
299 p = xdr_decode_fattr(p, fattr);
300 }
301 return p;
302out_overflow:
303 print_overflow_msg(__func__, xdr);
304 return ERR_PTR(-EIO);
305}
306
307static inline __be32 *
Al Virod61005a2006-10-19 23:28:48 -0700308xdr_decode_pre_op_attr(__be32 *p, struct nfs_fattr *fattr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700309{
310 if (*p++)
311 return xdr_decode_wcc_attr(p, fattr);
312 return p;
313}
314
315
Al Virod61005a2006-10-19 23:28:48 -0700316static inline __be32 *
317xdr_decode_wcc_data(__be32 *p, struct nfs_fattr *fattr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318{
319 p = xdr_decode_pre_op_attr(p, fattr);
320 return xdr_decode_post_op_attr(p, fattr);
321}
322
Chuck Leverd9c407b2010-12-14 14:55:50 +0000323
324/*
325 * Encode/decode NFSv3 basic data types
326 *
327 * Basic NFSv3 data types are defined in section 2.5 of RFC 1813:
328 * "NFS Version 3 Protocol Specification".
329 *
330 * Not all basic data types have their own encoding and decoding
331 * functions. For run-time efficiency, some data types are encoded
332 * or decoded inline.
333 */
334
335static void encode_uint32(struct xdr_stream *xdr, u32 value)
336{
337 __be32 *p = xdr_reserve_space(xdr, 4);
338 *p = cpu_to_be32(value);
339}
340
341/*
342 * filename3
343 *
344 * typedef string filename3<>;
345 */
346static void encode_filename3(struct xdr_stream *xdr,
347 const char *name, u32 length)
348{
349 __be32 *p;
350
351 BUG_ON(length > NFS3_MAXNAMLEN);
352 p = xdr_reserve_space(xdr, 4 + length);
353 xdr_encode_opaque(p, name, length);
354}
355
356/*
357 * nfspath3
358 *
359 * typedef string nfspath3<>;
360 */
361static void encode_nfspath3(struct xdr_stream *xdr, struct page **pages,
362 const u32 length)
363{
364 BUG_ON(length > NFS3_MAXPATHLEN);
365 encode_uint32(xdr, length);
366 xdr_write_pages(xdr, pages, 0, length);
367}
368
369/*
370 * cookie3
371 *
372 * typedef uint64 cookie3
373 */
374static __be32 *xdr_encode_cookie3(__be32 *p, u64 cookie)
375{
376 return xdr_encode_hyper(p, cookie);
377}
378
379/*
380 * cookieverf3
381 *
382 * typedef opaque cookieverf3[NFS3_COOKIEVERFSIZE];
383 */
384static __be32 *xdr_encode_cookieverf3(__be32 *p, const __be32 *verifier)
385{
386 memcpy(p, verifier, NFS3_COOKIEVERFSIZE);
387 return p + XDR_QUADLEN(NFS3_COOKIEVERFSIZE);
388}
389
390/*
391 * createverf3
392 *
393 * typedef opaque createverf3[NFS3_CREATEVERFSIZE];
394 */
395static void encode_createverf3(struct xdr_stream *xdr, const __be32 *verifier)
396{
397 __be32 *p;
398
399 p = xdr_reserve_space(xdr, NFS3_CREATEVERFSIZE);
400 memcpy(p, verifier, NFS3_CREATEVERFSIZE);
401}
402
403/*
404 * ftype3
405 *
406 * enum ftype3 {
407 * NF3REG = 1,
408 * NF3DIR = 2,
409 * NF3BLK = 3,
410 * NF3CHR = 4,
411 * NF3LNK = 5,
412 * NF3SOCK = 6,
413 * NF3FIFO = 7
414 * };
415 */
416static void encode_ftype3(struct xdr_stream *xdr, const u32 type)
417{
418 BUG_ON(type > NF3FIFO);
419 encode_uint32(xdr, type);
420}
421
422/*
423 * specdata3
424 *
425 * struct specdata3 {
426 * uint32 specdata1;
427 * uint32 specdata2;
428 * };
429 */
430static void encode_specdata3(struct xdr_stream *xdr, const dev_t rdev)
431{
432 __be32 *p;
433
434 p = xdr_reserve_space(xdr, 8);
435 *p++ = cpu_to_be32(MAJOR(rdev));
436 *p = cpu_to_be32(MINOR(rdev));
437}
438
439/*
440 * nfs_fh3
441 *
442 * struct nfs_fh3 {
443 * opaque data<NFS3_FHSIZE>;
444 * };
445 */
446static void encode_nfs_fh3(struct xdr_stream *xdr, const struct nfs_fh *fh)
447{
448 __be32 *p;
449
450 BUG_ON(fh->size > NFS3_FHSIZE);
451 p = xdr_reserve_space(xdr, 4 + fh->size);
452 xdr_encode_opaque(p, fh->data, fh->size);
453}
454
455/*
456 * sattr3
457 *
458 * enum time_how {
459 * DONT_CHANGE = 0,
460 * SET_TO_SERVER_TIME = 1,
461 * SET_TO_CLIENT_TIME = 2
462 * };
463 *
464 * union set_mode3 switch (bool set_it) {
465 * case TRUE:
466 * mode3 mode;
467 * default:
468 * void;
469 * };
470 *
471 * union set_uid3 switch (bool set_it) {
472 * case TRUE:
473 * uid3 uid;
474 * default:
475 * void;
476 * };
477 *
478 * union set_gid3 switch (bool set_it) {
479 * case TRUE:
480 * gid3 gid;
481 * default:
482 * void;
483 * };
484 *
485 * union set_size3 switch (bool set_it) {
486 * case TRUE:
487 * size3 size;
488 * default:
489 * void;
490 * };
491 *
492 * union set_atime switch (time_how set_it) {
493 * case SET_TO_CLIENT_TIME:
494 * nfstime3 atime;
495 * default:
496 * void;
497 * };
498 *
499 * union set_mtime switch (time_how set_it) {
500 * case SET_TO_CLIENT_TIME:
501 * nfstime3 mtime;
502 * default:
503 * void;
504 * };
505 *
506 * struct sattr3 {
507 * set_mode3 mode;
508 * set_uid3 uid;
509 * set_gid3 gid;
510 * set_size3 size;
511 * set_atime atime;
512 * set_mtime mtime;
513 * };
514 */
515static void encode_sattr3(struct xdr_stream *xdr, const struct iattr *attr)
516{
517 u32 nbytes;
518 __be32 *p;
519
520 /*
521 * In order to make only a single xdr_reserve_space() call,
522 * pre-compute the total number of bytes to be reserved.
523 * Six boolean values, one for each set_foo field, are always
524 * present in the encoded result, so start there.
525 */
526 nbytes = 6 * 4;
527 if (attr->ia_valid & ATTR_MODE)
528 nbytes += 4;
529 if (attr->ia_valid & ATTR_UID)
530 nbytes += 4;
531 if (attr->ia_valid & ATTR_GID)
532 nbytes += 4;
533 if (attr->ia_valid & ATTR_SIZE)
534 nbytes += 8;
535 if (attr->ia_valid & ATTR_ATIME_SET)
536 nbytes += 8;
537 if (attr->ia_valid & ATTR_MTIME_SET)
538 nbytes += 8;
539 p = xdr_reserve_space(xdr, nbytes);
540
541 xdr_encode_sattr(p, attr);
542}
543
544/*
545 * diropargs3
546 *
547 * struct diropargs3 {
548 * nfs_fh3 dir;
549 * filename3 name;
550 * };
551 */
552static void encode_diropargs3(struct xdr_stream *xdr, const struct nfs_fh *fh,
553 const char *name, u32 length)
554{
555 encode_nfs_fh3(xdr, fh);
556 encode_filename3(xdr, name, length);
557}
558
559
Linus Torvalds1da177e2005-04-16 15:20:36 -0700560/*
Chuck Lever499ff712010-12-14 14:56:10 +0000561 * NFSv3 XDR encode functions
562 *
563 * NFSv3 argument types are defined in section 3.3 of RFC 1813:
564 * "NFS Version 3 Protocol Specification".
Linus Torvalds1da177e2005-04-16 15:20:36 -0700565 */
566
567/*
Chuck Leverd9c407b2010-12-14 14:55:50 +0000568 * 3.3.1 GETATTR3args
569 *
570 * struct GETATTR3args {
571 * nfs_fh3 object;
572 * };
573 */
574static int nfs3_xdr_enc_getattr3args(struct rpc_rqst *req, __be32 *p,
575 const struct nfs_fh *fh)
576{
577 struct xdr_stream xdr;
578
579 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
580 encode_nfs_fh3(&xdr, fh);
581 return 0;
582}
583
584/*
Chuck Leverd9c407b2010-12-14 14:55:50 +0000585 * 3.3.2 SETATTR3args
586 *
587 * union sattrguard3 switch (bool check) {
588 * case TRUE:
589 * nfstime3 obj_ctime;
590 * case FALSE:
591 * void;
592 * };
593 *
594 * struct SETATTR3args {
595 * nfs_fh3 object;
596 * sattr3 new_attributes;
597 * sattrguard3 guard;
598 * };
599 */
600static void encode_sattrguard3(struct xdr_stream *xdr,
601 const struct nfs3_sattrargs *args)
602{
603 __be32 *p;
604
605 if (args->guard) {
606 p = xdr_reserve_space(xdr, 4 + 8);
607 *p++ = xdr_one;
608 xdr_encode_time3(p, &args->guardtime);
609 } else {
610 p = xdr_reserve_space(xdr, 4);
611 *p = xdr_zero;
612 }
613}
614
615static int nfs3_xdr_enc_setattr3args(struct rpc_rqst *req, __be32 *p,
616 const struct nfs3_sattrargs *args)
617{
618 struct xdr_stream xdr;
619
620 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
621 encode_nfs_fh3(&xdr, args->fh);
622 encode_sattr3(&xdr, args->sattr);
623 encode_sattrguard3(&xdr, args);
624 return 0;
625}
626
627/*
Chuck Leverd9c407b2010-12-14 14:55:50 +0000628 * 3.3.3 LOOKUP3args
629 *
630 * struct LOOKUP3args {
631 * diropargs3 what;
632 * };
633 */
634static int nfs3_xdr_enc_lookup3args(struct rpc_rqst *req, __be32 *p,
635 const struct nfs3_diropargs *args)
636{
637 struct xdr_stream xdr;
638
639 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
640 encode_diropargs3(&xdr, args->fh, args->name, args->len);
641 return 0;
642}
643
644/*
Chuck Leverd9c407b2010-12-14 14:55:50 +0000645 * 3.3.4 ACCESS3args
646 *
647 * struct ACCESS3args {
648 * nfs_fh3 object;
649 * uint32 access;
650 * };
651 */
652static void encode_access3args(struct xdr_stream *xdr,
653 const struct nfs3_accessargs *args)
654{
655 encode_nfs_fh3(xdr, args->fh);
656 encode_uint32(xdr, args->access);
657}
658
659static int nfs3_xdr_enc_access3args(struct rpc_rqst *req, __be32 *p,
660 const struct nfs3_accessargs *args)
661{
662 struct xdr_stream xdr;
663
664 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
665 encode_access3args(&xdr, args);
666 return 0;
667}
668
669/*
670 * 3.3.5 READLINK3args
671 *
672 * struct READLINK3args {
673 * nfs_fh3 symlink;
674 * };
675 */
676static int nfs3_xdr_enc_readlink3args(struct rpc_rqst *req, __be32 *p,
677 const struct nfs3_readlinkargs *args)
678{
679 struct xdr_stream xdr;
680
681 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
682 encode_nfs_fh3(&xdr, args->fh);
683 prepare_reply_buffer(req, args->pages, args->pgbase,
684 args->pglen, NFS3_readlinkres_sz);
685 return 0;
686}
687
688/*
Chuck Leverd9c407b2010-12-14 14:55:50 +0000689 * 3.3.6 READ3args
690 *
691 * struct READ3args {
692 * nfs_fh3 file;
693 * offset3 offset;
694 * count3 count;
695 * };
696 */
697static void encode_read3args(struct xdr_stream *xdr,
698 const struct nfs_readargs *args)
699{
700 __be32 *p;
701
702 encode_nfs_fh3(xdr, args->fh);
703
704 p = xdr_reserve_space(xdr, 8 + 4);
705 p = xdr_encode_hyper(p, args->offset);
706 *p = cpu_to_be32(args->count);
707}
708
709static int nfs3_xdr_enc_read3args(struct rpc_rqst *req, __be32 *p,
710 const struct nfs_readargs *args)
711{
712 struct xdr_stream xdr;
713
714 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
715 encode_read3args(&xdr, args);
716 prepare_reply_buffer(req, args->pages, args->pgbase,
717 args->count, NFS3_readres_sz);
718 req->rq_rcv_buf.flags |= XDRBUF_READ;
719 return 0;
720}
721
722/*
Chuck Leverd9c407b2010-12-14 14:55:50 +0000723 * 3.3.7 WRITE3args
724 *
725 * enum stable_how {
726 * UNSTABLE = 0,
727 * DATA_SYNC = 1,
728 * FILE_SYNC = 2
729 * };
730 *
731 * struct WRITE3args {
732 * nfs_fh3 file;
733 * offset3 offset;
734 * count3 count;
735 * stable_how stable;
736 * opaque data<>;
737 * };
738 */
739static void encode_write3args(struct xdr_stream *xdr,
740 const struct nfs_writeargs *args)
741{
742 __be32 *p;
743
744 encode_nfs_fh3(xdr, args->fh);
745
746 p = xdr_reserve_space(xdr, 8 + 4 + 4 + 4);
747 p = xdr_encode_hyper(p, args->offset);
748 *p++ = cpu_to_be32(args->count);
749
750 BUG_ON(args->stable > NFS_FILE_SYNC);
751 *p++ = cpu_to_be32(args->stable);
752
753 *p = cpu_to_be32(args->count);
754 xdr_write_pages(xdr, args->pages, args->pgbase, args->count);
755}
756
757static int nfs3_xdr_enc_write3args(struct rpc_rqst *req, __be32 *p,
758 const struct nfs_writeargs *args)
759{
760 struct xdr_stream xdr;
761
762 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
763 encode_write3args(&xdr, args);
764 xdr.buf->flags |= XDRBUF_WRITE;
765 return 0;
766}
767
768/*
Chuck Leverd9c407b2010-12-14 14:55:50 +0000769 * 3.3.8 CREATE3args
770 *
771 * enum createmode3 {
772 * UNCHECKED = 0,
773 * GUARDED = 1,
774 * EXCLUSIVE = 2
775 * };
776 *
777 * union createhow3 switch (createmode3 mode) {
778 * case UNCHECKED:
779 * case GUARDED:
780 * sattr3 obj_attributes;
781 * case EXCLUSIVE:
782 * createverf3 verf;
783 * };
784 *
785 * struct CREATE3args {
786 * diropargs3 where;
787 * createhow3 how;
788 * };
789 */
790static void encode_createhow3(struct xdr_stream *xdr,
791 const struct nfs3_createargs *args)
792{
793 encode_uint32(xdr, args->createmode);
794 switch (args->createmode) {
795 case NFS3_CREATE_UNCHECKED:
796 case NFS3_CREATE_GUARDED:
797 encode_sattr3(xdr, args->sattr);
798 break;
799 case NFS3_CREATE_EXCLUSIVE:
800 encode_createverf3(xdr, args->verifier);
801 break;
802 default:
803 BUG();
804 }
805}
806
807static int nfs3_xdr_enc_create3args(struct rpc_rqst *req, __be32 *p,
808 const struct nfs3_createargs *args)
809{
810 struct xdr_stream xdr;
811
812 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
813 encode_diropargs3(&xdr, args->fh, args->name, args->len);
814 encode_createhow3(&xdr, args);
815 return 0;
816}
817
818/*
Chuck Leverd9c407b2010-12-14 14:55:50 +0000819 * 3.3.9 MKDIR3args
820 *
821 * struct MKDIR3args {
822 * diropargs3 where;
823 * sattr3 attributes;
824 * };
825 */
826static int nfs3_xdr_enc_mkdir3args(struct rpc_rqst *req, __be32 *p,
827 const struct nfs3_mkdirargs *args)
828{
829 struct xdr_stream xdr;
830
831 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
832 encode_diropargs3(&xdr, args->fh, args->name, args->len);
833 encode_sattr3(&xdr, args->sattr);
834 return 0;
835}
836
837/*
Chuck Leverd9c407b2010-12-14 14:55:50 +0000838 * 3.3.10 SYMLINK3args
839 *
840 * struct symlinkdata3 {
841 * sattr3 symlink_attributes;
842 * nfspath3 symlink_data;
843 * };
844 *
845 * struct SYMLINK3args {
846 * diropargs3 where;
847 * symlinkdata3 symlink;
848 * };
849 */
850static void encode_symlinkdata3(struct xdr_stream *xdr,
851 const struct nfs3_symlinkargs *args)
852{
853 encode_sattr3(xdr, args->sattr);
854 encode_nfspath3(xdr, args->pages, args->pathlen);
855}
856
857static int nfs3_xdr_enc_symlink3args(struct rpc_rqst *req, __be32 *p,
858 const struct nfs3_symlinkargs *args)
859{
860 struct xdr_stream xdr;
861
862 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
863 encode_diropargs3(&xdr, args->fromfh, args->fromname, args->fromlen);
864 encode_symlinkdata3(&xdr, args);
865 return 0;
866}
867
868/*
Chuck Leverd9c407b2010-12-14 14:55:50 +0000869 * 3.3.11 MKNOD3args
870 *
871 * struct devicedata3 {
872 * sattr3 dev_attributes;
873 * specdata3 spec;
874 * };
875 *
876 * union mknoddata3 switch (ftype3 type) {
877 * case NF3CHR:
878 * case NF3BLK:
879 * devicedata3 device;
880 * case NF3SOCK:
881 * case NF3FIFO:
882 * sattr3 pipe_attributes;
883 * default:
884 * void;
885 * };
886 *
887 * struct MKNOD3args {
888 * diropargs3 where;
889 * mknoddata3 what;
890 * };
891 */
892static void encode_devicedata3(struct xdr_stream *xdr,
893 const struct nfs3_mknodargs *args)
894{
895 encode_sattr3(xdr, args->sattr);
896 encode_specdata3(xdr, args->rdev);
897}
898
899static void encode_mknoddata3(struct xdr_stream *xdr,
900 const struct nfs3_mknodargs *args)
901{
902 encode_ftype3(xdr, args->type);
903 switch (args->type) {
904 case NF3CHR:
905 case NF3BLK:
906 encode_devicedata3(xdr, args);
907 break;
908 case NF3SOCK:
909 case NF3FIFO:
910 encode_sattr3(xdr, args->sattr);
911 break;
912 case NF3REG:
913 case NF3DIR:
914 break;
915 default:
916 BUG();
917 }
918}
919
920static int nfs3_xdr_enc_mknod3args(struct rpc_rqst *req, __be32 *p,
921 const struct nfs3_mknodargs *args)
922{
923 struct xdr_stream xdr;
924
925 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
926 encode_diropargs3(&xdr, args->fh, args->name, args->len);
927 encode_mknoddata3(&xdr, args);
928 return 0;
929}
930
931/*
932 * 3.3.12 REMOVE3args
933 *
934 * struct REMOVE3args {
935 * diropargs3 object;
936 * };
937 */
938static int nfs3_xdr_enc_remove3args(struct rpc_rqst *req, __be32 *p,
939 const struct nfs_removeargs *args)
940{
941 struct xdr_stream xdr;
942
943 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
944 encode_diropargs3(&xdr, args->fh, args->name.name, args->name.len);
945 return 0;
946}
947
948/*
Chuck Leverd9c407b2010-12-14 14:55:50 +0000949 * 3.3.14 RENAME3args
950 *
951 * struct RENAME3args {
952 * diropargs3 from;
953 * diropargs3 to;
954 * };
955 */
956static int nfs3_xdr_enc_rename3args(struct rpc_rqst *req, __be32 *p,
957 const struct nfs_renameargs *args)
958{
959 const struct qstr *old = args->old_name;
960 const struct qstr *new = args->new_name;
961 struct xdr_stream xdr;
962
963 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
964 encode_diropargs3(&xdr, args->old_dir, old->name, old->len);
965 encode_diropargs3(&xdr, args->new_dir, new->name, new->len);
966 return 0;
967}
968
969/*
Chuck Leverd9c407b2010-12-14 14:55:50 +0000970 * 3.3.15 LINK3args
971 *
972 * struct LINK3args {
973 * nfs_fh3 file;
974 * diropargs3 link;
975 * };
976 */
977static int nfs3_xdr_enc_link3args(struct rpc_rqst *req, __be32 *p,
978 const struct nfs3_linkargs *args)
979{
980 struct xdr_stream xdr;
981
982 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
983 encode_nfs_fh3(&xdr, args->fromfh);
984 encode_diropargs3(&xdr, args->tofh, args->toname, args->tolen);
985 return 0;
986}
987
988/*
Chuck Leverd9c407b2010-12-14 14:55:50 +0000989 * 3.3.16 READDIR3args
990 *
991 * struct READDIR3args {
992 * nfs_fh3 dir;
993 * cookie3 cookie;
994 * cookieverf3 cookieverf;
995 * count3 count;
996 * };
997 */
998static void encode_readdir3args(struct xdr_stream *xdr,
999 const struct nfs3_readdirargs *args)
1000{
1001 __be32 *p;
1002
1003 encode_nfs_fh3(xdr, args->fh);
1004
1005 p = xdr_reserve_space(xdr, 8 + NFS3_COOKIEVERFSIZE + 4);
1006 p = xdr_encode_cookie3(p, args->cookie);
1007 p = xdr_encode_cookieverf3(p, args->verf);
1008 *p = cpu_to_be32(args->count);
1009}
1010
1011static int nfs3_xdr_enc_readdir3args(struct rpc_rqst *req, __be32 *p,
1012 const struct nfs3_readdirargs *args)
1013{
1014 struct xdr_stream xdr;
1015
1016 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1017 encode_readdir3args(&xdr, args);
1018 prepare_reply_buffer(req, args->pages, 0,
1019 args->count, NFS3_readdirres_sz);
1020 return 0;
1021}
1022
1023/*
1024 * 3.3.17 READDIRPLUS3args
1025 *
1026 * struct READDIRPLUS3args {
1027 * nfs_fh3 dir;
1028 * cookie3 cookie;
1029 * cookieverf3 cookieverf;
1030 * count3 dircount;
1031 * count3 maxcount;
1032 * };
1033 */
1034static void encode_readdirplus3args(struct xdr_stream *xdr,
1035 const struct nfs3_readdirargs *args)
1036{
1037 __be32 *p;
1038
1039 encode_nfs_fh3(xdr, args->fh);
1040
1041 p = xdr_reserve_space(xdr, 8 + NFS3_COOKIEVERFSIZE + 4 + 4);
1042 p = xdr_encode_cookie3(p, args->cookie);
1043 p = xdr_encode_cookieverf3(p, args->verf);
1044
1045 /*
1046 * readdirplus: need dircount + buffer size.
1047 * We just make sure we make dircount big enough
1048 */
1049 *p++ = cpu_to_be32(args->count >> 3);
1050
1051 *p = cpu_to_be32(args->count);
1052}
1053
1054static int nfs3_xdr_enc_readdirplus3args(struct rpc_rqst *req, __be32 *p,
1055 const struct nfs3_readdirargs *args)
1056{
1057 struct xdr_stream xdr;
1058
1059 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1060 encode_readdirplus3args(&xdr, args);
1061 prepare_reply_buffer(req, args->pages, 0,
1062 args->count, NFS3_readdirres_sz);
1063 return 0;
1064}
1065
1066/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001067 * Decode the result of a readdir call.
1068 * We just check for syntactical correctness.
1069 */
1070static int
Al Virod61005a2006-10-19 23:28:48 -07001071nfs3_xdr_readdirres(struct rpc_rqst *req, __be32 *p, struct nfs3_readdirres *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001072{
1073 struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
1074 struct kvec *iov = rcvbuf->head;
1075 struct page **page;
Chuck Leverc957c522007-10-26 13:31:57 -04001076 size_t hdrlen;
Bryan Schumakerafa8ccc2010-10-20 15:44:31 -04001077 u32 recvd, pglen;
Trond Myklebustac396122010-11-15 20:26:22 -05001078 int status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001079
1080 status = ntohl(*p++);
1081 /* Decode post_op_attrs */
1082 p = xdr_decode_post_op_attr(p, res->dir_attr);
1083 if (status)
Benny Halevy856dff32008-03-31 17:39:06 +03001084 return nfs_stat_to_errno(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001085 /* Decode verifier cookie */
1086 if (res->verf) {
1087 res->verf[0] = *p++;
1088 res->verf[1] = *p++;
1089 } else {
1090 p += 2;
1091 }
1092
1093 hdrlen = (u8 *) p - (u8 *) iov->iov_base;
1094 if (iov->iov_len < hdrlen) {
Chuck Leverfe82a182007-09-11 18:01:10 -04001095 dprintk("NFS: READDIR reply header overflowed:"
Chuck Leverc957c522007-10-26 13:31:57 -04001096 "length %Zu > %Zu\n", hdrlen, iov->iov_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001097 return -errno_NFSERR_IO;
1098 } else if (iov->iov_len != hdrlen) {
1099 dprintk("NFS: READDIR header is short. iovec will be shifted.\n");
1100 xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen);
1101 }
1102
1103 pglen = rcvbuf->page_len;
1104 recvd = rcvbuf->len - hdrlen;
1105 if (pglen > recvd)
1106 pglen = recvd;
1107 page = rcvbuf->pages;
Jeff Layton643f8112008-02-22 14:50:00 -05001108
Trond Myklebustac396122010-11-15 20:26:22 -05001109 return pglen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001110}
1111
Al Viro0dbb4c62006-10-19 23:28:49 -07001112__be32 *
Bryan Schumaker82f2e542010-10-21 16:33:18 -04001113nfs3_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry, struct nfs_server *server, int plus)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001114{
Bryan Schumakerbabddc72010-10-20 15:44:29 -04001115 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001116 struct nfs_entry old = *entry;
1117
Bryan Schumakerbabddc72010-10-20 15:44:29 -04001118 p = xdr_inline_decode(xdr, 4);
1119 if (unlikely(!p))
1120 goto out_overflow;
1121 if (!ntohl(*p++)) {
1122 p = xdr_inline_decode(xdr, 4);
1123 if (unlikely(!p))
1124 goto out_overflow;
1125 if (!ntohl(*p++))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001126 return ERR_PTR(-EAGAIN);
1127 entry->eof = 1;
1128 return ERR_PTR(-EBADCOOKIE);
1129 }
1130
Bryan Schumakerbabddc72010-10-20 15:44:29 -04001131 p = xdr_inline_decode(xdr, 12);
1132 if (unlikely(!p))
1133 goto out_overflow;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001134 p = xdr_decode_hyper(p, &entry->ino);
1135 entry->len = ntohl(*p++);
Bryan Schumakerbabddc72010-10-20 15:44:29 -04001136
1137 p = xdr_inline_decode(xdr, entry->len + 8);
1138 if (unlikely(!p))
1139 goto out_overflow;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001140 entry->name = (const char *) p;
1141 p += XDR_QUADLEN(entry->len);
1142 entry->prev_cookie = entry->cookie;
1143 p = xdr_decode_hyper(p, &entry->cookie);
1144
Trond Myklebust0b26a0b2010-11-20 14:26:44 -05001145 entry->d_type = DT_UNKNOWN;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001146 if (plus) {
1147 entry->fattr->valid = 0;
Bryan Schumakerbabddc72010-10-20 15:44:29 -04001148 p = xdr_decode_post_op_attr_stream(xdr, entry->fattr);
1149 if (IS_ERR(p))
1150 goto out_overflow_exit;
Trond Myklebust0b26a0b2010-11-20 14:26:44 -05001151 entry->d_type = nfs_umode_to_dtype(entry->fattr->mode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001152 /* In fact, a post_op_fh3: */
Bryan Schumakerbabddc72010-10-20 15:44:29 -04001153 p = xdr_inline_decode(xdr, 4);
1154 if (unlikely(!p))
1155 goto out_overflow;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001156 if (*p++) {
Bryan Schumakerbabddc72010-10-20 15:44:29 -04001157 p = xdr_decode_fhandle_stream(xdr, entry->fh);
1158 if (IS_ERR(p))
1159 goto out_overflow_exit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001160 /* Ugh -- server reply was truncated */
1161 if (p == NULL) {
1162 dprintk("NFS: FH truncated\n");
1163 *entry = old;
1164 return ERR_PTR(-EAGAIN);
1165 }
1166 } else
1167 memset((u8*)(entry->fh), 0, sizeof(*entry->fh));
1168 }
1169
Bryan Schumakerbabddc72010-10-20 15:44:29 -04001170 p = xdr_inline_peek(xdr, 8);
1171 if (p != NULL)
1172 entry->eof = !p[0] && p[1];
1173 else
1174 entry->eof = 0;
1175
Linus Torvalds1da177e2005-04-16 15:20:36 -07001176 return p;
Bryan Schumakerbabddc72010-10-20 15:44:29 -04001177
1178out_overflow:
1179 print_overflow_msg(__func__, xdr);
1180out_overflow_exit:
Trond Myklebust463a3762010-11-20 12:22:20 -05001181 return ERR_PTR(-EAGAIN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001182}
1183
1184/*
Chuck Leverd9c407b2010-12-14 14:55:50 +00001185 * 3.3.21 COMMIT3args
1186 *
1187 * struct COMMIT3args {
1188 * nfs_fh3 file;
1189 * offset3 offset;
1190 * count3 count;
1191 * };
1192 */
1193static void encode_commit3args(struct xdr_stream *xdr,
1194 const struct nfs_writeargs *args)
1195{
1196 __be32 *p;
1197
1198 encode_nfs_fh3(xdr, args->fh);
1199
1200 p = xdr_reserve_space(xdr, 8 + 4);
1201 p = xdr_encode_hyper(p, args->offset);
1202 *p = cpu_to_be32(args->count);
1203}
1204
1205static int nfs3_xdr_enc_commit3args(struct rpc_rqst *req, __be32 *p,
1206 const struct nfs_writeargs *args)
1207{
1208 struct xdr_stream xdr;
1209
1210 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1211 encode_commit3args(&xdr, args);
1212 return 0;
1213}
1214
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +00001215#ifdef CONFIG_NFS_V3_ACL
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +00001216
Chuck Leverd9c407b2010-12-14 14:55:50 +00001217static int nfs3_xdr_enc_getacl3args(struct rpc_rqst *req, __be32 *p,
1218 const struct nfs3_getaclargs *args)
1219{
1220 struct xdr_stream xdr;
1221
1222 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1223 encode_nfs_fh3(&xdr, args->fh);
1224 encode_uint32(&xdr, args->mask);
1225 if (args->mask & (NFS_ACL | NFS_DFACL))
1226 prepare_reply_buffer(req, args->pages, 0,
1227 NFSACL_MAXPAGES << PAGE_SHIFT,
1228 ACL3_getaclres_sz);
1229 return 0;
1230}
1231
Chuck Leverd9c407b2010-12-14 14:55:50 +00001232static int nfs3_xdr_enc_setacl3args(struct rpc_rqst *req, __be32 *p,
1233 const struct nfs3_setaclargs *args)
1234{
1235 struct xdr_stream xdr;
1236 unsigned int base;
1237 int error;
1238
1239 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1240 encode_nfs_fh3(&xdr, NFS_FH(args->inode));
1241 encode_uint32(&xdr, args->mask);
1242 if (args->npages != 0)
1243 xdr_write_pages(&xdr, args->pages, 0, args->len);
1244
1245 base = req->rq_slen;
1246 error = nfsacl_encode(xdr.buf, base, args->inode,
1247 (args->mask & NFS_ACL) ?
1248 args->acl_access : NULL, 1, 0);
1249 BUG_ON(error < 0);
1250 error = nfsacl_encode(xdr.buf, base + error, args->inode,
1251 (args->mask & NFS_DFACL) ?
1252 args->acl_default : NULL, 1,
1253 NFS_ACL_DEFAULT);
1254 BUG_ON(error < 0);
1255 return 0;
1256}
1257
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +00001258#endif /* CONFIG_NFS_V3_ACL */
1259
Linus Torvalds1da177e2005-04-16 15:20:36 -07001260/*
1261 * NFS XDR decode functions
1262 */
1263
1264/*
1265 * Decode attrstat reply.
1266 */
1267static int
Al Virod61005a2006-10-19 23:28:48 -07001268nfs3_xdr_attrstat(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001269{
1270 int status;
1271
1272 if ((status = ntohl(*p++)))
Benny Halevy856dff32008-03-31 17:39:06 +03001273 return nfs_stat_to_errno(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001274 xdr_decode_fattr(p, fattr);
1275 return 0;
1276}
1277
1278/*
1279 * Decode status+wcc_data reply
1280 * SATTR, REMOVE, RMDIR
1281 */
1282static int
Al Virod61005a2006-10-19 23:28:48 -07001283nfs3_xdr_wccstat(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001284{
1285 int status;
1286
1287 if ((status = ntohl(*p++)))
Benny Halevy856dff32008-03-31 17:39:06 +03001288 status = nfs_stat_to_errno(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001289 xdr_decode_wcc_data(p, fattr);
1290 return status;
1291}
1292
Trond Myklebust4fdc17b2007-07-14 15:39:57 -04001293static int
1294nfs3_xdr_removeres(struct rpc_rqst *req, __be32 *p, struct nfs_removeres *res)
1295{
Trond Myklebustd3468902010-04-16 16:22:50 -04001296 return nfs3_xdr_wccstat(req, p, res->dir_attr);
Trond Myklebust4fdc17b2007-07-14 15:39:57 -04001297}
1298
Linus Torvalds1da177e2005-04-16 15:20:36 -07001299/*
1300 * Decode LOOKUP reply
1301 */
1302static int
Al Virod61005a2006-10-19 23:28:48 -07001303nfs3_xdr_lookupres(struct rpc_rqst *req, __be32 *p, struct nfs3_diropres *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001304{
1305 int status;
1306
1307 if ((status = ntohl(*p++))) {
Benny Halevy856dff32008-03-31 17:39:06 +03001308 status = nfs_stat_to_errno(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001309 } else {
1310 if (!(p = xdr_decode_fhandle(p, res->fh)))
1311 return -errno_NFSERR_IO;
1312 p = xdr_decode_post_op_attr(p, res->fattr);
1313 }
1314 xdr_decode_post_op_attr(p, res->dir_attr);
1315 return status;
1316}
1317
1318/*
1319 * Decode ACCESS reply
1320 */
1321static int
Al Virod61005a2006-10-19 23:28:48 -07001322nfs3_xdr_accessres(struct rpc_rqst *req, __be32 *p, struct nfs3_accessres *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001323{
1324 int status = ntohl(*p++);
1325
1326 p = xdr_decode_post_op_attr(p, res->fattr);
1327 if (status)
Benny Halevy856dff32008-03-31 17:39:06 +03001328 return nfs_stat_to_errno(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001329 res->access = ntohl(*p++);
1330 return 0;
1331}
1332
Linus Torvalds1da177e2005-04-16 15:20:36 -07001333/*
1334 * Decode READLINK reply
1335 */
1336static int
Al Virod61005a2006-10-19 23:28:48 -07001337nfs3_xdr_readlinkres(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001338{
1339 struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
1340 struct kvec *iov = rcvbuf->head;
Chuck Leverc957c522007-10-26 13:31:57 -04001341 size_t hdrlen;
1342 u32 len, recvd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001343 int status;
1344
1345 status = ntohl(*p++);
1346 p = xdr_decode_post_op_attr(p, fattr);
1347
1348 if (status != 0)
Benny Halevy856dff32008-03-31 17:39:06 +03001349 return nfs_stat_to_errno(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001350
1351 /* Convert length of symlink */
1352 len = ntohl(*p++);
Chuck Leverc957c522007-10-26 13:31:57 -04001353 if (len >= rcvbuf->page_len) {
Chuck Leverfe82a182007-09-11 18:01:10 -04001354 dprintk("nfs: server returned giant symlink!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001355 return -ENAMETOOLONG;
1356 }
1357
1358 hdrlen = (u8 *) p - (u8 *) iov->iov_base;
1359 if (iov->iov_len < hdrlen) {
Chuck Leverfe82a182007-09-11 18:01:10 -04001360 dprintk("NFS: READLINK reply header overflowed:"
Chuck Leverc957c522007-10-26 13:31:57 -04001361 "length %Zu > %Zu\n", hdrlen, iov->iov_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001362 return -errno_NFSERR_IO;
1363 } else if (iov->iov_len != hdrlen) {
Chuck Leverfe82a182007-09-11 18:01:10 -04001364 dprintk("NFS: READLINK header is short. "
1365 "iovec will be shifted.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001366 xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen);
1367 }
1368 recvd = req->rq_rcv_buf.len - hdrlen;
1369 if (recvd < len) {
Chuck Leverfe82a182007-09-11 18:01:10 -04001370 dprintk("NFS: server cheating in readlink reply: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001371 "count %u > recvd %u\n", len, recvd);
1372 return -EIO;
1373 }
1374
Chuck Leverb4687da2010-09-21 16:55:48 -04001375 xdr_terminate_string(rcvbuf, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001376 return 0;
1377}
1378
1379/*
1380 * Decode READ reply
1381 */
1382static int
Al Virod61005a2006-10-19 23:28:48 -07001383nfs3_xdr_readres(struct rpc_rqst *req, __be32 *p, struct nfs_readres *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001384{
1385 struct kvec *iov = req->rq_rcv_buf.head;
Chuck Leverc957c522007-10-26 13:31:57 -04001386 size_t hdrlen;
1387 u32 count, ocount, recvd;
1388 int status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001389
1390 status = ntohl(*p++);
1391 p = xdr_decode_post_op_attr(p, res->fattr);
1392
1393 if (status != 0)
Benny Halevy856dff32008-03-31 17:39:06 +03001394 return nfs_stat_to_errno(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001395
Chuck Leverc957c522007-10-26 13:31:57 -04001396 /* Decode reply count and EOF flag. NFSv3 is somewhat redundant
Linus Torvalds1da177e2005-04-16 15:20:36 -07001397 * in that it puts the count both in the res struct and in the
1398 * opaque data count. */
1399 count = ntohl(*p++);
1400 res->eof = ntohl(*p++);
1401 ocount = ntohl(*p++);
1402
1403 if (ocount != count) {
Chuck Leverfe82a182007-09-11 18:01:10 -04001404 dprintk("NFS: READ count doesn't match RPC opaque count.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001405 return -errno_NFSERR_IO;
1406 }
1407
1408 hdrlen = (u8 *) p - (u8 *) iov->iov_base;
1409 if (iov->iov_len < hdrlen) {
Chuck Leverfe82a182007-09-11 18:01:10 -04001410 dprintk("NFS: READ reply header overflowed:"
Chuck Leverc957c522007-10-26 13:31:57 -04001411 "length %Zu > %Zu\n", hdrlen, iov->iov_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001412 return -errno_NFSERR_IO;
1413 } else if (iov->iov_len != hdrlen) {
1414 dprintk("NFS: READ header is short. iovec will be shifted.\n");
1415 xdr_shift_buf(&req->rq_rcv_buf, iov->iov_len - hdrlen);
1416 }
1417
1418 recvd = req->rq_rcv_buf.len - hdrlen;
1419 if (count > recvd) {
Chuck Leverfe82a182007-09-11 18:01:10 -04001420 dprintk("NFS: server cheating in read reply: "
Chuck Leverc957c522007-10-26 13:31:57 -04001421 "count %u > recvd %u\n", count, recvd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001422 count = recvd;
1423 res->eof = 0;
1424 }
1425
1426 if (count < res->count)
1427 res->count = count;
1428
1429 return count;
1430}
1431
1432/*
1433 * Decode WRITE response
1434 */
1435static int
Al Virod61005a2006-10-19 23:28:48 -07001436nfs3_xdr_writeres(struct rpc_rqst *req, __be32 *p, struct nfs_writeres *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001437{
1438 int status;
1439
1440 status = ntohl(*p++);
1441 p = xdr_decode_wcc_data(p, res->fattr);
1442
1443 if (status != 0)
Benny Halevy856dff32008-03-31 17:39:06 +03001444 return nfs_stat_to_errno(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001445
1446 res->count = ntohl(*p++);
1447 res->verf->committed = (enum nfs3_stable_how)ntohl(*p++);
1448 res->verf->verifier[0] = *p++;
1449 res->verf->verifier[1] = *p++;
1450
1451 return res->count;
1452}
1453
1454/*
1455 * Decode a CREATE response
1456 */
1457static int
Al Virod61005a2006-10-19 23:28:48 -07001458nfs3_xdr_createres(struct rpc_rqst *req, __be32 *p, struct nfs3_diropres *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001459{
1460 int status;
1461
1462 status = ntohl(*p++);
1463 if (status == 0) {
1464 if (*p++) {
1465 if (!(p = xdr_decode_fhandle(p, res->fh)))
1466 return -errno_NFSERR_IO;
1467 p = xdr_decode_post_op_attr(p, res->fattr);
1468 } else {
1469 memset(res->fh, 0, sizeof(*res->fh));
1470 /* Do decode post_op_attr but set it to NULL */
1471 p = xdr_decode_post_op_attr(p, res->fattr);
1472 res->fattr->valid = 0;
1473 }
1474 } else {
Benny Halevy856dff32008-03-31 17:39:06 +03001475 status = nfs_stat_to_errno(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001476 }
1477 p = xdr_decode_wcc_data(p, res->dir_attr);
1478 return status;
1479}
1480
1481/*
1482 * Decode RENAME reply
1483 */
1484static int
Jeff Laytone8582a82010-09-17 17:31:06 -04001485nfs3_xdr_renameres(struct rpc_rqst *req, __be32 *p, struct nfs_renameres *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001486{
1487 int status;
1488
1489 if ((status = ntohl(*p++)) != 0)
Benny Halevy856dff32008-03-31 17:39:06 +03001490 status = nfs_stat_to_errno(status);
Jeff Laytone8582a82010-09-17 17:31:06 -04001491 p = xdr_decode_wcc_data(p, res->old_fattr);
1492 p = xdr_decode_wcc_data(p, res->new_fattr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001493 return status;
1494}
1495
1496/*
1497 * Decode LINK reply
1498 */
1499static int
Al Virod61005a2006-10-19 23:28:48 -07001500nfs3_xdr_linkres(struct rpc_rqst *req, __be32 *p, struct nfs3_linkres *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001501{
1502 int status;
1503
1504 if ((status = ntohl(*p++)) != 0)
Benny Halevy856dff32008-03-31 17:39:06 +03001505 status = nfs_stat_to_errno(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001506 p = xdr_decode_post_op_attr(p, res->fattr);
1507 p = xdr_decode_wcc_data(p, res->dir_attr);
1508 return status;
1509}
1510
1511/*
1512 * Decode FSSTAT reply
1513 */
1514static int
Al Virod61005a2006-10-19 23:28:48 -07001515nfs3_xdr_fsstatres(struct rpc_rqst *req, __be32 *p, struct nfs_fsstat *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001516{
1517 int status;
1518
1519 status = ntohl(*p++);
1520
1521 p = xdr_decode_post_op_attr(p, res->fattr);
1522 if (status != 0)
Benny Halevy856dff32008-03-31 17:39:06 +03001523 return nfs_stat_to_errno(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001524
1525 p = xdr_decode_hyper(p, &res->tbytes);
1526 p = xdr_decode_hyper(p, &res->fbytes);
1527 p = xdr_decode_hyper(p, &res->abytes);
1528 p = xdr_decode_hyper(p, &res->tfiles);
1529 p = xdr_decode_hyper(p, &res->ffiles);
1530 p = xdr_decode_hyper(p, &res->afiles);
1531
1532 /* ignore invarsec */
1533 return 0;
1534}
1535
1536/*
1537 * Decode FSINFO reply
1538 */
1539static int
Al Virod61005a2006-10-19 23:28:48 -07001540nfs3_xdr_fsinfores(struct rpc_rqst *req, __be32 *p, struct nfs_fsinfo *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001541{
1542 int status;
1543
1544 status = ntohl(*p++);
1545
1546 p = xdr_decode_post_op_attr(p, res->fattr);
1547 if (status != 0)
Benny Halevy856dff32008-03-31 17:39:06 +03001548 return nfs_stat_to_errno(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001549
1550 res->rtmax = ntohl(*p++);
1551 res->rtpref = ntohl(*p++);
1552 res->rtmult = ntohl(*p++);
1553 res->wtmax = ntohl(*p++);
1554 res->wtpref = ntohl(*p++);
1555 res->wtmult = ntohl(*p++);
1556 res->dtpref = ntohl(*p++);
1557 p = xdr_decode_hyper(p, &res->maxfilesize);
Ricardo Labiaga6b967242010-10-12 16:30:05 -07001558 p = xdr_decode_time3(p, &res->time_delta);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001559
Ricardo Labiaga6b967242010-10-12 16:30:05 -07001560 /* ignore properties */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001561 res->lease_time = 0;
1562 return 0;
1563}
1564
1565/*
1566 * Decode PATHCONF reply
1567 */
1568static int
Al Virod61005a2006-10-19 23:28:48 -07001569nfs3_xdr_pathconfres(struct rpc_rqst *req, __be32 *p, struct nfs_pathconf *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001570{
1571 int status;
1572
1573 status = ntohl(*p++);
1574
1575 p = xdr_decode_post_op_attr(p, res->fattr);
1576 if (status != 0)
Benny Halevy856dff32008-03-31 17:39:06 +03001577 return nfs_stat_to_errno(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001578 res->max_link = ntohl(*p++);
1579 res->max_namelen = ntohl(*p++);
1580
1581 /* ignore remaining fields */
1582 return 0;
1583}
1584
1585/*
1586 * Decode COMMIT reply
1587 */
1588static int
Al Virod61005a2006-10-19 23:28:48 -07001589nfs3_xdr_commitres(struct rpc_rqst *req, __be32 *p, struct nfs_writeres *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001590{
1591 int status;
1592
1593 status = ntohl(*p++);
1594 p = xdr_decode_wcc_data(p, res->fattr);
1595 if (status != 0)
Benny Halevy856dff32008-03-31 17:39:06 +03001596 return nfs_stat_to_errno(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001597
1598 res->verf->verifier[0] = *p++;
1599 res->verf->verifier[1] = *p++;
1600 return 0;
1601}
1602
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +00001603#ifdef CONFIG_NFS_V3_ACL
1604/*
1605 * Decode GETACL reply
1606 */
1607static int
Al Virod61005a2006-10-19 23:28:48 -07001608nfs3_xdr_getaclres(struct rpc_rqst *req, __be32 *p,
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +00001609 struct nfs3_getaclres *res)
1610{
1611 struct xdr_buf *buf = &req->rq_rcv_buf;
1612 int status = ntohl(*p++);
1613 struct posix_acl **acl;
1614 unsigned int *aclcnt;
1615 int err, base;
1616
1617 if (status != 0)
Benny Halevy856dff32008-03-31 17:39:06 +03001618 return nfs_stat_to_errno(status);
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +00001619 p = xdr_decode_post_op_attr(p, res->fattr);
1620 res->mask = ntohl(*p++);
1621 if (res->mask & ~(NFS_ACL|NFS_ACLCNT|NFS_DFACL|NFS_DFACLCNT))
1622 return -EINVAL;
1623 base = (char *)p - (char *)req->rq_rcv_buf.head->iov_base;
1624
1625 acl = (res->mask & NFS_ACL) ? &res->acl_access : NULL;
1626 aclcnt = (res->mask & NFS_ACLCNT) ? &res->acl_access_count : NULL;
1627 err = nfsacl_decode(buf, base, aclcnt, acl);
1628
1629 acl = (res->mask & NFS_DFACL) ? &res->acl_default : NULL;
1630 aclcnt = (res->mask & NFS_DFACLCNT) ? &res->acl_default_count : NULL;
1631 if (err > 0)
1632 err = nfsacl_decode(buf, base + err, aclcnt, acl);
1633 return (err > 0) ? 0 : err;
1634}
1635
1636/*
1637 * Decode setacl reply.
1638 */
1639static int
Al Virod61005a2006-10-19 23:28:48 -07001640nfs3_xdr_setaclres(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +00001641{
1642 int status = ntohl(*p++);
1643
1644 if (status)
Benny Halevy856dff32008-03-31 17:39:06 +03001645 return nfs_stat_to_errno(status);
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +00001646 xdr_decode_post_op_attr(p, fattr);
1647 return 0;
1648}
1649#endif /* CONFIG_NFS_V3_ACL */
1650
Linus Torvalds1da177e2005-04-16 15:20:36 -07001651#define PROC(proc, argtype, restype, timer) \
1652[NFS3PROC_##proc] = { \
1653 .p_proc = NFS3PROC_##proc, \
Chuck Leverad96b5b2010-12-14 14:56:01 +00001654 .p_encode = (kxdrproc_t)nfs3_xdr_enc_##argtype##3args, \
Linus Torvalds1da177e2005-04-16 15:20:36 -07001655 .p_decode = (kxdrproc_t) nfs3_xdr_##restype, \
Chuck Leverad96b5b2010-12-14 14:56:01 +00001656 .p_arglen = NFS3_##argtype##args_sz, \
Chuck Lever2bea90d2007-03-29 16:47:53 -04001657 .p_replen = NFS3_##restype##_sz, \
Chuck Levercc0175c2006-03-20 13:44:22 -05001658 .p_timer = timer, \
1659 .p_statidx = NFS3PROC_##proc, \
1660 .p_name = #proc, \
Linus Torvalds1da177e2005-04-16 15:20:36 -07001661 }
1662
1663struct rpc_procinfo nfs3_procedures[] = {
Chuck Leverad96b5b2010-12-14 14:56:01 +00001664 PROC(GETATTR, getattr, attrstat, 1),
1665 PROC(SETATTR, setattr, wccstat, 0),
1666 PROC(LOOKUP, lookup, lookupres, 2),
1667 PROC(ACCESS, access, accessres, 1),
1668 PROC(READLINK, readlink, readlinkres, 3),
1669 PROC(READ, read, readres, 3),
1670 PROC(WRITE, write, writeres, 4),
1671 PROC(CREATE, create, createres, 0),
1672 PROC(MKDIR, mkdir, createres, 0),
1673 PROC(SYMLINK, symlink, createres, 0),
1674 PROC(MKNOD, mknod, createres, 0),
1675 PROC(REMOVE, remove, removeres, 0),
1676 PROC(RMDIR, lookup, wccstat, 0),
1677 PROC(RENAME, rename, renameres, 0),
1678 PROC(LINK, link, linkres, 0),
1679 PROC(READDIR, readdir, readdirres, 3),
1680 PROC(READDIRPLUS, readdirplus, readdirres, 3),
1681 PROC(FSSTAT, getattr, fsstatres, 0),
1682 PROC(FSINFO, getattr, fsinfores, 0),
1683 PROC(PATHCONF, getattr, pathconfres, 0),
1684 PROC(COMMIT, commit, commitres, 5),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001685};
1686
1687struct rpc_version nfs_version3 = {
1688 .number = 3,
Tobias Klausere8c96f82006-03-24 03:15:34 -08001689 .nrprocs = ARRAY_SIZE(nfs3_procedures),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001690 .procs = nfs3_procedures
1691};
1692
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +00001693#ifdef CONFIG_NFS_V3_ACL
1694static struct rpc_procinfo nfs3_acl_procedures[] = {
1695 [ACLPROC3_GETACL] = {
1696 .p_proc = ACLPROC3_GETACL,
Chuck Leverad96b5b2010-12-14 14:56:01 +00001697 .p_encode = (kxdrproc_t)nfs3_xdr_enc_getacl3args,
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +00001698 .p_decode = (kxdrproc_t) nfs3_xdr_getaclres,
Chuck Lever2bea90d2007-03-29 16:47:53 -04001699 .p_arglen = ACL3_getaclargs_sz,
1700 .p_replen = ACL3_getaclres_sz,
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +00001701 .p_timer = 1,
Chuck Levercc0175c2006-03-20 13:44:22 -05001702 .p_name = "GETACL",
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +00001703 },
1704 [ACLPROC3_SETACL] = {
1705 .p_proc = ACLPROC3_SETACL,
Chuck Leverad96b5b2010-12-14 14:56:01 +00001706 .p_encode = (kxdrproc_t)nfs3_xdr_enc_setacl3args,
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +00001707 .p_decode = (kxdrproc_t) nfs3_xdr_setaclres,
Chuck Lever2bea90d2007-03-29 16:47:53 -04001708 .p_arglen = ACL3_setaclargs_sz,
1709 .p_replen = ACL3_setaclres_sz,
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +00001710 .p_timer = 0,
Chuck Levercc0175c2006-03-20 13:44:22 -05001711 .p_name = "SETACL",
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +00001712 },
1713};
1714
1715struct rpc_version nfsacl_version3 = {
1716 .number = 3,
1717 .nrprocs = sizeof(nfs3_acl_procedures)/
1718 sizeof(nfs3_acl_procedures[0]),
1719 .procs = nfs3_acl_procedures,
1720};
1721#endif /* CONFIG_NFS_V3_ACL */