blob: 119844d0b4d5622e42db6dcc9933f4c2e4e12295 [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 *
Al Virod61005a2006-10-19 23:28:48 -0700170xdr_decode_time3(__be32 *p, struct timespec *timep)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700171{
172 timep->tv_sec = ntohl(*p++);
173 timep->tv_nsec = ntohl(*p++);
174 return p;
175}
176
Al Virod61005a2006-10-19 23:28:48 -0700177static __be32 *
178xdr_decode_fattr(__be32 *p, struct nfs_fattr *fattr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700179{
180 unsigned int type, major, minor;
Trond Myklebustbca79472009-03-11 14:10:26 -0400181 umode_t fmode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700182
183 type = ntohl(*p++);
Trond Myklebustbca79472009-03-11 14:10:26 -0400184 if (type > NF3FIFO)
185 type = NF3NON;
186 fmode = nfs_type2fmt[type];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700187 fattr->mode = (ntohl(*p++) & ~S_IFMT) | fmode;
188 fattr->nlink = ntohl(*p++);
189 fattr->uid = ntohl(*p++);
190 fattr->gid = ntohl(*p++);
191 p = xdr_decode_hyper(p, &fattr->size);
192 p = xdr_decode_hyper(p, &fattr->du.nfs3.used);
193
194 /* Turn remote device info into Linux-specific dev_t */
195 major = ntohl(*p++);
196 minor = ntohl(*p++);
197 fattr->rdev = MKDEV(major, minor);
198 if (MAJOR(fattr->rdev) != major || MINOR(fattr->rdev) != minor)
199 fattr->rdev = 0;
200
Trond Myklebust8b4bdcf2006-06-09 09:34:19 -0400201 p = xdr_decode_hyper(p, &fattr->fsid.major);
202 fattr->fsid.minor = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700203 p = xdr_decode_hyper(p, &fattr->fileid);
204 p = xdr_decode_time3(p, &fattr->atime);
205 p = xdr_decode_time3(p, &fattr->mtime);
206 p = xdr_decode_time3(p, &fattr->ctime);
207
208 /* Update the mode bits */
Trond Myklebust9e6e70f2009-03-11 14:10:24 -0400209 fattr->valid |= NFS_ATTR_FATTR_V3;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700210 return p;
211}
212
Al Virod61005a2006-10-19 23:28:48 -0700213static inline __be32 *
Al Virod61005a2006-10-19 23:28:48 -0700214xdr_decode_wcc_attr(__be32 *p, struct nfs_fattr *fattr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215{
216 p = xdr_decode_hyper(p, &fattr->pre_size);
217 p = xdr_decode_time3(p, &fattr->pre_mtime);
218 p = xdr_decode_time3(p, &fattr->pre_ctime);
Trond Myklebust9e6e70f2009-03-11 14:10:24 -0400219 fattr->valid |= NFS_ATTR_FATTR_PRESIZE
220 | NFS_ATTR_FATTR_PREMTIME
221 | NFS_ATTR_FATTR_PRECTIME;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700222 return p;
223}
224
Al Virod61005a2006-10-19 23:28:48 -0700225static inline __be32 *
226xdr_decode_post_op_attr(__be32 *p, struct nfs_fattr *fattr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700227{
228 if (*p++)
229 p = xdr_decode_fattr(p, fattr);
230 return p;
231}
232
Al Virod61005a2006-10-19 23:28:48 -0700233static inline __be32 *
Bryan Schumakerbabddc72010-10-20 15:44:29 -0400234xdr_decode_post_op_attr_stream(struct xdr_stream *xdr, struct nfs_fattr *fattr)
235{
236 __be32 *p;
237
238 p = xdr_inline_decode(xdr, 4);
239 if (unlikely(!p))
240 goto out_overflow;
241 if (ntohl(*p++)) {
242 p = xdr_inline_decode(xdr, 84);
243 if (unlikely(!p))
244 goto out_overflow;
245 p = xdr_decode_fattr(p, fattr);
246 }
247 return p;
248out_overflow:
249 print_overflow_msg(__func__, xdr);
250 return ERR_PTR(-EIO);
251}
252
253static inline __be32 *
Al Virod61005a2006-10-19 23:28:48 -0700254xdr_decode_pre_op_attr(__be32 *p, struct nfs_fattr *fattr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700255{
256 if (*p++)
257 return xdr_decode_wcc_attr(p, fattr);
258 return p;
259}
260
261
Al Virod61005a2006-10-19 23:28:48 -0700262static inline __be32 *
263xdr_decode_wcc_data(__be32 *p, struct nfs_fattr *fattr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700264{
265 p = xdr_decode_pre_op_attr(p, fattr);
266 return xdr_decode_post_op_attr(p, fattr);
267}
268
Chuck Leverd9c407b2010-12-14 14:55:50 +0000269
270/*
271 * Encode/decode NFSv3 basic data types
272 *
273 * Basic NFSv3 data types are defined in section 2.5 of RFC 1813:
274 * "NFS Version 3 Protocol Specification".
275 *
276 * Not all basic data types have their own encoding and decoding
277 * functions. For run-time efficiency, some data types are encoded
278 * or decoded inline.
279 */
280
281static void encode_uint32(struct xdr_stream *xdr, u32 value)
282{
283 __be32 *p = xdr_reserve_space(xdr, 4);
284 *p = cpu_to_be32(value);
285}
286
287/*
288 * filename3
289 *
290 * typedef string filename3<>;
291 */
292static void encode_filename3(struct xdr_stream *xdr,
293 const char *name, u32 length)
294{
295 __be32 *p;
296
297 BUG_ON(length > NFS3_MAXNAMLEN);
298 p = xdr_reserve_space(xdr, 4 + length);
299 xdr_encode_opaque(p, name, length);
300}
301
302/*
303 * nfspath3
304 *
305 * typedef string nfspath3<>;
306 */
307static void encode_nfspath3(struct xdr_stream *xdr, struct page **pages,
308 const u32 length)
309{
310 BUG_ON(length > NFS3_MAXPATHLEN);
311 encode_uint32(xdr, length);
312 xdr_write_pages(xdr, pages, 0, length);
313}
314
315/*
316 * cookie3
317 *
318 * typedef uint64 cookie3
319 */
320static __be32 *xdr_encode_cookie3(__be32 *p, u64 cookie)
321{
322 return xdr_encode_hyper(p, cookie);
323}
324
325/*
326 * cookieverf3
327 *
328 * typedef opaque cookieverf3[NFS3_COOKIEVERFSIZE];
329 */
330static __be32 *xdr_encode_cookieverf3(__be32 *p, const __be32 *verifier)
331{
332 memcpy(p, verifier, NFS3_COOKIEVERFSIZE);
333 return p + XDR_QUADLEN(NFS3_COOKIEVERFSIZE);
334}
335
336/*
337 * createverf3
338 *
339 * typedef opaque createverf3[NFS3_CREATEVERFSIZE];
340 */
341static void encode_createverf3(struct xdr_stream *xdr, const __be32 *verifier)
342{
343 __be32 *p;
344
345 p = xdr_reserve_space(xdr, NFS3_CREATEVERFSIZE);
346 memcpy(p, verifier, NFS3_CREATEVERFSIZE);
347}
348
349/*
350 * ftype3
351 *
352 * enum ftype3 {
353 * NF3REG = 1,
354 * NF3DIR = 2,
355 * NF3BLK = 3,
356 * NF3CHR = 4,
357 * NF3LNK = 5,
358 * NF3SOCK = 6,
359 * NF3FIFO = 7
360 * };
361 */
362static void encode_ftype3(struct xdr_stream *xdr, const u32 type)
363{
364 BUG_ON(type > NF3FIFO);
365 encode_uint32(xdr, type);
366}
367
368/*
369 * specdata3
370 *
371 * struct specdata3 {
372 * uint32 specdata1;
373 * uint32 specdata2;
374 * };
375 */
376static void encode_specdata3(struct xdr_stream *xdr, const dev_t rdev)
377{
378 __be32 *p;
379
380 p = xdr_reserve_space(xdr, 8);
381 *p++ = cpu_to_be32(MAJOR(rdev));
382 *p = cpu_to_be32(MINOR(rdev));
383}
384
385/*
386 * nfs_fh3
387 *
388 * struct nfs_fh3 {
389 * opaque data<NFS3_FHSIZE>;
390 * };
391 */
392static void encode_nfs_fh3(struct xdr_stream *xdr, const struct nfs_fh *fh)
393{
394 __be32 *p;
395
396 BUG_ON(fh->size > NFS3_FHSIZE);
397 p = xdr_reserve_space(xdr, 4 + fh->size);
398 xdr_encode_opaque(p, fh->data, fh->size);
399}
400
401/*
Chuck Lever9d5a6432010-12-14 14:56:20 +0000402 * nfstime3
403 *
404 * struct nfstime3 {
405 * uint32 seconds;
406 * uint32 nseconds;
407 * };
408 */
409static __be32 *xdr_encode_nfstime3(__be32 *p, const struct timespec *timep)
410{
411 *p++ = cpu_to_be32(timep->tv_sec);
412 *p++ = cpu_to_be32(timep->tv_nsec);
413 return p;
414}
415
416/*
Chuck Leverd9c407b2010-12-14 14:55:50 +0000417 * sattr3
418 *
419 * enum time_how {
420 * DONT_CHANGE = 0,
421 * SET_TO_SERVER_TIME = 1,
422 * SET_TO_CLIENT_TIME = 2
423 * };
424 *
425 * union set_mode3 switch (bool set_it) {
426 * case TRUE:
427 * mode3 mode;
428 * default:
429 * void;
430 * };
431 *
432 * union set_uid3 switch (bool set_it) {
433 * case TRUE:
434 * uid3 uid;
435 * default:
436 * void;
437 * };
438 *
439 * union set_gid3 switch (bool set_it) {
440 * case TRUE:
441 * gid3 gid;
442 * default:
443 * void;
444 * };
445 *
446 * union set_size3 switch (bool set_it) {
447 * case TRUE:
448 * size3 size;
449 * default:
450 * void;
451 * };
452 *
453 * union set_atime switch (time_how set_it) {
454 * case SET_TO_CLIENT_TIME:
455 * nfstime3 atime;
456 * default:
457 * void;
458 * };
459 *
460 * union set_mtime switch (time_how set_it) {
461 * case SET_TO_CLIENT_TIME:
462 * nfstime3 mtime;
463 * default:
464 * void;
465 * };
466 *
467 * struct sattr3 {
468 * set_mode3 mode;
469 * set_uid3 uid;
470 * set_gid3 gid;
471 * set_size3 size;
472 * set_atime atime;
473 * set_mtime mtime;
474 * };
475 */
476static void encode_sattr3(struct xdr_stream *xdr, const struct iattr *attr)
477{
478 u32 nbytes;
479 __be32 *p;
480
481 /*
482 * In order to make only a single xdr_reserve_space() call,
483 * pre-compute the total number of bytes to be reserved.
484 * Six boolean values, one for each set_foo field, are always
485 * present in the encoded result, so start there.
486 */
487 nbytes = 6 * 4;
488 if (attr->ia_valid & ATTR_MODE)
489 nbytes += 4;
490 if (attr->ia_valid & ATTR_UID)
491 nbytes += 4;
492 if (attr->ia_valid & ATTR_GID)
493 nbytes += 4;
494 if (attr->ia_valid & ATTR_SIZE)
495 nbytes += 8;
496 if (attr->ia_valid & ATTR_ATIME_SET)
497 nbytes += 8;
498 if (attr->ia_valid & ATTR_MTIME_SET)
499 nbytes += 8;
500 p = xdr_reserve_space(xdr, nbytes);
501
Chuck Lever9d5a6432010-12-14 14:56:20 +0000502 if (attr->ia_valid & ATTR_MODE) {
503 *p++ = xdr_one;
504 *p++ = cpu_to_be32(attr->ia_mode & S_IALLUGO);
505 } else
506 *p++ = xdr_zero;
507
508 if (attr->ia_valid & ATTR_UID) {
509 *p++ = xdr_one;
510 *p++ = cpu_to_be32(attr->ia_uid);
511 } else
512 *p++ = xdr_zero;
513
514 if (attr->ia_valid & ATTR_GID) {
515 *p++ = xdr_one;
516 *p++ = cpu_to_be32(attr->ia_gid);
517 } else
518 *p++ = xdr_zero;
519
520 if (attr->ia_valid & ATTR_SIZE) {
521 *p++ = xdr_one;
522 p = xdr_encode_hyper(p, (u64)attr->ia_size);
523 } else
524 *p++ = xdr_zero;
525
526 if (attr->ia_valid & ATTR_ATIME_SET) {
527 *p++ = xdr_two;
528 p = xdr_encode_nfstime3(p, &attr->ia_atime);
529 } else if (attr->ia_valid & ATTR_ATIME) {
530 *p++ = xdr_one;
531 } else
532 *p++ = xdr_zero;
533
534 if (attr->ia_valid & ATTR_MTIME_SET) {
535 *p++ = xdr_two;
536 xdr_encode_nfstime3(p, &attr->ia_mtime);
537 } else if (attr->ia_valid & ATTR_MTIME) {
538 *p = xdr_one;
539 } else
540 *p = xdr_zero;
Chuck Leverd9c407b2010-12-14 14:55:50 +0000541}
542
543/*
544 * diropargs3
545 *
546 * struct diropargs3 {
547 * nfs_fh3 dir;
548 * filename3 name;
549 * };
550 */
551static void encode_diropargs3(struct xdr_stream *xdr, const struct nfs_fh *fh,
552 const char *name, u32 length)
553{
554 encode_nfs_fh3(xdr, fh);
555 encode_filename3(xdr, name, length);
556}
557
558
Linus Torvalds1da177e2005-04-16 15:20:36 -0700559/*
Chuck Lever499ff712010-12-14 14:56:10 +0000560 * NFSv3 XDR encode functions
561 *
562 * NFSv3 argument types are defined in section 3.3 of RFC 1813:
563 * "NFS Version 3 Protocol Specification".
Linus Torvalds1da177e2005-04-16 15:20:36 -0700564 */
565
566/*
Chuck Leverd9c407b2010-12-14 14:55:50 +0000567 * 3.3.1 GETATTR3args
568 *
569 * struct GETATTR3args {
570 * nfs_fh3 object;
571 * };
572 */
573static int nfs3_xdr_enc_getattr3args(struct rpc_rqst *req, __be32 *p,
574 const struct nfs_fh *fh)
575{
576 struct xdr_stream xdr;
577
578 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
579 encode_nfs_fh3(&xdr, fh);
580 return 0;
581}
582
583/*
Chuck Leverd9c407b2010-12-14 14:55:50 +0000584 * 3.3.2 SETATTR3args
585 *
586 * union sattrguard3 switch (bool check) {
587 * case TRUE:
588 * nfstime3 obj_ctime;
589 * case FALSE:
590 * void;
591 * };
592 *
593 * struct SETATTR3args {
594 * nfs_fh3 object;
595 * sattr3 new_attributes;
596 * sattrguard3 guard;
597 * };
598 */
599static void encode_sattrguard3(struct xdr_stream *xdr,
600 const struct nfs3_sattrargs *args)
601{
602 __be32 *p;
603
604 if (args->guard) {
605 p = xdr_reserve_space(xdr, 4 + 8);
606 *p++ = xdr_one;
Chuck Lever9d5a6432010-12-14 14:56:20 +0000607 xdr_encode_nfstime3(p, &args->guardtime);
Chuck Leverd9c407b2010-12-14 14:55:50 +0000608 } else {
609 p = xdr_reserve_space(xdr, 4);
610 *p = xdr_zero;
611 }
612}
613
614static int nfs3_xdr_enc_setattr3args(struct rpc_rqst *req, __be32 *p,
615 const struct nfs3_sattrargs *args)
616{
617 struct xdr_stream xdr;
618
619 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
620 encode_nfs_fh3(&xdr, args->fh);
621 encode_sattr3(&xdr, args->sattr);
622 encode_sattrguard3(&xdr, args);
623 return 0;
624}
625
626/*
Chuck Leverd9c407b2010-12-14 14:55:50 +0000627 * 3.3.3 LOOKUP3args
628 *
629 * struct LOOKUP3args {
630 * diropargs3 what;
631 * };
632 */
633static int nfs3_xdr_enc_lookup3args(struct rpc_rqst *req, __be32 *p,
634 const struct nfs3_diropargs *args)
635{
636 struct xdr_stream xdr;
637
638 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
639 encode_diropargs3(&xdr, args->fh, args->name, args->len);
640 return 0;
641}
642
643/*
Chuck Leverd9c407b2010-12-14 14:55:50 +0000644 * 3.3.4 ACCESS3args
645 *
646 * struct ACCESS3args {
647 * nfs_fh3 object;
648 * uint32 access;
649 * };
650 */
651static void encode_access3args(struct xdr_stream *xdr,
652 const struct nfs3_accessargs *args)
653{
654 encode_nfs_fh3(xdr, args->fh);
655 encode_uint32(xdr, args->access);
656}
657
658static int nfs3_xdr_enc_access3args(struct rpc_rqst *req, __be32 *p,
659 const struct nfs3_accessargs *args)
660{
661 struct xdr_stream xdr;
662
663 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
664 encode_access3args(&xdr, args);
665 return 0;
666}
667
668/*
669 * 3.3.5 READLINK3args
670 *
671 * struct READLINK3args {
672 * nfs_fh3 symlink;
673 * };
674 */
675static int nfs3_xdr_enc_readlink3args(struct rpc_rqst *req, __be32 *p,
676 const struct nfs3_readlinkargs *args)
677{
678 struct xdr_stream xdr;
679
680 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
681 encode_nfs_fh3(&xdr, args->fh);
682 prepare_reply_buffer(req, args->pages, args->pgbase,
683 args->pglen, NFS3_readlinkres_sz);
684 return 0;
685}
686
687/*
Chuck Leverd9c407b2010-12-14 14:55:50 +0000688 * 3.3.6 READ3args
689 *
690 * struct READ3args {
691 * nfs_fh3 file;
692 * offset3 offset;
693 * count3 count;
694 * };
695 */
696static void encode_read3args(struct xdr_stream *xdr,
697 const struct nfs_readargs *args)
698{
699 __be32 *p;
700
701 encode_nfs_fh3(xdr, args->fh);
702
703 p = xdr_reserve_space(xdr, 8 + 4);
704 p = xdr_encode_hyper(p, args->offset);
705 *p = cpu_to_be32(args->count);
706}
707
708static int nfs3_xdr_enc_read3args(struct rpc_rqst *req, __be32 *p,
709 const struct nfs_readargs *args)
710{
711 struct xdr_stream xdr;
712
713 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
714 encode_read3args(&xdr, args);
715 prepare_reply_buffer(req, args->pages, args->pgbase,
716 args->count, NFS3_readres_sz);
717 req->rq_rcv_buf.flags |= XDRBUF_READ;
718 return 0;
719}
720
721/*
Chuck Leverd9c407b2010-12-14 14:55:50 +0000722 * 3.3.7 WRITE3args
723 *
724 * enum stable_how {
725 * UNSTABLE = 0,
726 * DATA_SYNC = 1,
727 * FILE_SYNC = 2
728 * };
729 *
730 * struct WRITE3args {
731 * nfs_fh3 file;
732 * offset3 offset;
733 * count3 count;
734 * stable_how stable;
735 * opaque data<>;
736 * };
737 */
738static void encode_write3args(struct xdr_stream *xdr,
739 const struct nfs_writeargs *args)
740{
741 __be32 *p;
742
743 encode_nfs_fh3(xdr, args->fh);
744
745 p = xdr_reserve_space(xdr, 8 + 4 + 4 + 4);
746 p = xdr_encode_hyper(p, args->offset);
747 *p++ = cpu_to_be32(args->count);
748
749 BUG_ON(args->stable > NFS_FILE_SYNC);
750 *p++ = cpu_to_be32(args->stable);
751
752 *p = cpu_to_be32(args->count);
753 xdr_write_pages(xdr, args->pages, args->pgbase, args->count);
754}
755
756static int nfs3_xdr_enc_write3args(struct rpc_rqst *req, __be32 *p,
757 const struct nfs_writeargs *args)
758{
759 struct xdr_stream xdr;
760
761 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
762 encode_write3args(&xdr, args);
763 xdr.buf->flags |= XDRBUF_WRITE;
764 return 0;
765}
766
767/*
Chuck Leverd9c407b2010-12-14 14:55:50 +0000768 * 3.3.8 CREATE3args
769 *
770 * enum createmode3 {
771 * UNCHECKED = 0,
772 * GUARDED = 1,
773 * EXCLUSIVE = 2
774 * };
775 *
776 * union createhow3 switch (createmode3 mode) {
777 * case UNCHECKED:
778 * case GUARDED:
779 * sattr3 obj_attributes;
780 * case EXCLUSIVE:
781 * createverf3 verf;
782 * };
783 *
784 * struct CREATE3args {
785 * diropargs3 where;
786 * createhow3 how;
787 * };
788 */
789static void encode_createhow3(struct xdr_stream *xdr,
790 const struct nfs3_createargs *args)
791{
792 encode_uint32(xdr, args->createmode);
793 switch (args->createmode) {
794 case NFS3_CREATE_UNCHECKED:
795 case NFS3_CREATE_GUARDED:
796 encode_sattr3(xdr, args->sattr);
797 break;
798 case NFS3_CREATE_EXCLUSIVE:
799 encode_createverf3(xdr, args->verifier);
800 break;
801 default:
802 BUG();
803 }
804}
805
806static int nfs3_xdr_enc_create3args(struct rpc_rqst *req, __be32 *p,
807 const struct nfs3_createargs *args)
808{
809 struct xdr_stream xdr;
810
811 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
812 encode_diropargs3(&xdr, args->fh, args->name, args->len);
813 encode_createhow3(&xdr, args);
814 return 0;
815}
816
817/*
Chuck Leverd9c407b2010-12-14 14:55:50 +0000818 * 3.3.9 MKDIR3args
819 *
820 * struct MKDIR3args {
821 * diropargs3 where;
822 * sattr3 attributes;
823 * };
824 */
825static int nfs3_xdr_enc_mkdir3args(struct rpc_rqst *req, __be32 *p,
826 const struct nfs3_mkdirargs *args)
827{
828 struct xdr_stream xdr;
829
830 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
831 encode_diropargs3(&xdr, args->fh, args->name, args->len);
832 encode_sattr3(&xdr, args->sattr);
833 return 0;
834}
835
836/*
Chuck Leverd9c407b2010-12-14 14:55:50 +0000837 * 3.3.10 SYMLINK3args
838 *
839 * struct symlinkdata3 {
840 * sattr3 symlink_attributes;
841 * nfspath3 symlink_data;
842 * };
843 *
844 * struct SYMLINK3args {
845 * diropargs3 where;
846 * symlinkdata3 symlink;
847 * };
848 */
849static void encode_symlinkdata3(struct xdr_stream *xdr,
850 const struct nfs3_symlinkargs *args)
851{
852 encode_sattr3(xdr, args->sattr);
853 encode_nfspath3(xdr, args->pages, args->pathlen);
854}
855
856static int nfs3_xdr_enc_symlink3args(struct rpc_rqst *req, __be32 *p,
857 const struct nfs3_symlinkargs *args)
858{
859 struct xdr_stream xdr;
860
861 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
862 encode_diropargs3(&xdr, args->fromfh, args->fromname, args->fromlen);
863 encode_symlinkdata3(&xdr, args);
864 return 0;
865}
866
867/*
Chuck Leverd9c407b2010-12-14 14:55:50 +0000868 * 3.3.11 MKNOD3args
869 *
870 * struct devicedata3 {
871 * sattr3 dev_attributes;
872 * specdata3 spec;
873 * };
874 *
875 * union mknoddata3 switch (ftype3 type) {
876 * case NF3CHR:
877 * case NF3BLK:
878 * devicedata3 device;
879 * case NF3SOCK:
880 * case NF3FIFO:
881 * sattr3 pipe_attributes;
882 * default:
883 * void;
884 * };
885 *
886 * struct MKNOD3args {
887 * diropargs3 where;
888 * mknoddata3 what;
889 * };
890 */
891static void encode_devicedata3(struct xdr_stream *xdr,
892 const struct nfs3_mknodargs *args)
893{
894 encode_sattr3(xdr, args->sattr);
895 encode_specdata3(xdr, args->rdev);
896}
897
898static void encode_mknoddata3(struct xdr_stream *xdr,
899 const struct nfs3_mknodargs *args)
900{
901 encode_ftype3(xdr, args->type);
902 switch (args->type) {
903 case NF3CHR:
904 case NF3BLK:
905 encode_devicedata3(xdr, args);
906 break;
907 case NF3SOCK:
908 case NF3FIFO:
909 encode_sattr3(xdr, args->sattr);
910 break;
911 case NF3REG:
912 case NF3DIR:
913 break;
914 default:
915 BUG();
916 }
917}
918
919static int nfs3_xdr_enc_mknod3args(struct rpc_rqst *req, __be32 *p,
920 const struct nfs3_mknodargs *args)
921{
922 struct xdr_stream xdr;
923
924 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
925 encode_diropargs3(&xdr, args->fh, args->name, args->len);
926 encode_mknoddata3(&xdr, args);
927 return 0;
928}
929
930/*
931 * 3.3.12 REMOVE3args
932 *
933 * struct REMOVE3args {
934 * diropargs3 object;
935 * };
936 */
937static int nfs3_xdr_enc_remove3args(struct rpc_rqst *req, __be32 *p,
938 const struct nfs_removeargs *args)
939{
940 struct xdr_stream xdr;
941
942 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
943 encode_diropargs3(&xdr, args->fh, args->name.name, args->name.len);
944 return 0;
945}
946
947/*
Chuck Leverd9c407b2010-12-14 14:55:50 +0000948 * 3.3.14 RENAME3args
949 *
950 * struct RENAME3args {
951 * diropargs3 from;
952 * diropargs3 to;
953 * };
954 */
955static int nfs3_xdr_enc_rename3args(struct rpc_rqst *req, __be32 *p,
956 const struct nfs_renameargs *args)
957{
958 const struct qstr *old = args->old_name;
959 const struct qstr *new = args->new_name;
960 struct xdr_stream xdr;
961
962 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
963 encode_diropargs3(&xdr, args->old_dir, old->name, old->len);
964 encode_diropargs3(&xdr, args->new_dir, new->name, new->len);
965 return 0;
966}
967
968/*
Chuck Leverd9c407b2010-12-14 14:55:50 +0000969 * 3.3.15 LINK3args
970 *
971 * struct LINK3args {
972 * nfs_fh3 file;
973 * diropargs3 link;
974 * };
975 */
976static int nfs3_xdr_enc_link3args(struct rpc_rqst *req, __be32 *p,
977 const struct nfs3_linkargs *args)
978{
979 struct xdr_stream xdr;
980
981 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
982 encode_nfs_fh3(&xdr, args->fromfh);
983 encode_diropargs3(&xdr, args->tofh, args->toname, args->tolen);
984 return 0;
985}
986
987/*
Chuck Leverd9c407b2010-12-14 14:55:50 +0000988 * 3.3.16 READDIR3args
989 *
990 * struct READDIR3args {
991 * nfs_fh3 dir;
992 * cookie3 cookie;
993 * cookieverf3 cookieverf;
994 * count3 count;
995 * };
996 */
997static void encode_readdir3args(struct xdr_stream *xdr,
998 const struct nfs3_readdirargs *args)
999{
1000 __be32 *p;
1001
1002 encode_nfs_fh3(xdr, args->fh);
1003
1004 p = xdr_reserve_space(xdr, 8 + NFS3_COOKIEVERFSIZE + 4);
1005 p = xdr_encode_cookie3(p, args->cookie);
1006 p = xdr_encode_cookieverf3(p, args->verf);
1007 *p = cpu_to_be32(args->count);
1008}
1009
1010static int nfs3_xdr_enc_readdir3args(struct rpc_rqst *req, __be32 *p,
1011 const struct nfs3_readdirargs *args)
1012{
1013 struct xdr_stream xdr;
1014
1015 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1016 encode_readdir3args(&xdr, args);
1017 prepare_reply_buffer(req, args->pages, 0,
1018 args->count, NFS3_readdirres_sz);
1019 return 0;
1020}
1021
1022/*
1023 * 3.3.17 READDIRPLUS3args
1024 *
1025 * struct READDIRPLUS3args {
1026 * nfs_fh3 dir;
1027 * cookie3 cookie;
1028 * cookieverf3 cookieverf;
1029 * count3 dircount;
1030 * count3 maxcount;
1031 * };
1032 */
1033static void encode_readdirplus3args(struct xdr_stream *xdr,
1034 const struct nfs3_readdirargs *args)
1035{
1036 __be32 *p;
1037
1038 encode_nfs_fh3(xdr, args->fh);
1039
1040 p = xdr_reserve_space(xdr, 8 + NFS3_COOKIEVERFSIZE + 4 + 4);
1041 p = xdr_encode_cookie3(p, args->cookie);
1042 p = xdr_encode_cookieverf3(p, args->verf);
1043
1044 /*
1045 * readdirplus: need dircount + buffer size.
1046 * We just make sure we make dircount big enough
1047 */
1048 *p++ = cpu_to_be32(args->count >> 3);
1049
1050 *p = cpu_to_be32(args->count);
1051}
1052
1053static int nfs3_xdr_enc_readdirplus3args(struct rpc_rqst *req, __be32 *p,
1054 const struct nfs3_readdirargs *args)
1055{
1056 struct xdr_stream xdr;
1057
1058 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1059 encode_readdirplus3args(&xdr, args);
1060 prepare_reply_buffer(req, args->pages, 0,
1061 args->count, NFS3_readdirres_sz);
1062 return 0;
1063}
1064
1065/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001066 * Decode the result of a readdir call.
1067 * We just check for syntactical correctness.
1068 */
1069static int
Al Virod61005a2006-10-19 23:28:48 -07001070nfs3_xdr_readdirres(struct rpc_rqst *req, __be32 *p, struct nfs3_readdirres *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001071{
1072 struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
1073 struct kvec *iov = rcvbuf->head;
1074 struct page **page;
Chuck Leverc957c522007-10-26 13:31:57 -04001075 size_t hdrlen;
Bryan Schumakerafa8ccc2010-10-20 15:44:31 -04001076 u32 recvd, pglen;
Trond Myklebustac396122010-11-15 20:26:22 -05001077 int status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001078
1079 status = ntohl(*p++);
1080 /* Decode post_op_attrs */
1081 p = xdr_decode_post_op_attr(p, res->dir_attr);
1082 if (status)
Benny Halevy856dff32008-03-31 17:39:06 +03001083 return nfs_stat_to_errno(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001084 /* Decode verifier cookie */
1085 if (res->verf) {
1086 res->verf[0] = *p++;
1087 res->verf[1] = *p++;
1088 } else {
1089 p += 2;
1090 }
1091
1092 hdrlen = (u8 *) p - (u8 *) iov->iov_base;
1093 if (iov->iov_len < hdrlen) {
Chuck Leverfe82a182007-09-11 18:01:10 -04001094 dprintk("NFS: READDIR reply header overflowed:"
Chuck Leverc957c522007-10-26 13:31:57 -04001095 "length %Zu > %Zu\n", hdrlen, iov->iov_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001096 return -errno_NFSERR_IO;
1097 } else if (iov->iov_len != hdrlen) {
1098 dprintk("NFS: READDIR header is short. iovec will be shifted.\n");
1099 xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen);
1100 }
1101
1102 pglen = rcvbuf->page_len;
1103 recvd = rcvbuf->len - hdrlen;
1104 if (pglen > recvd)
1105 pglen = recvd;
1106 page = rcvbuf->pages;
Jeff Layton643f8112008-02-22 14:50:00 -05001107
Trond Myklebustac396122010-11-15 20:26:22 -05001108 return pglen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001109}
1110
Al Viro0dbb4c62006-10-19 23:28:49 -07001111__be32 *
Bryan Schumaker82f2e542010-10-21 16:33:18 -04001112nfs3_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry, struct nfs_server *server, int plus)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001113{
Bryan Schumakerbabddc72010-10-20 15:44:29 -04001114 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001115 struct nfs_entry old = *entry;
1116
Bryan Schumakerbabddc72010-10-20 15:44:29 -04001117 p = xdr_inline_decode(xdr, 4);
1118 if (unlikely(!p))
1119 goto out_overflow;
1120 if (!ntohl(*p++)) {
1121 p = xdr_inline_decode(xdr, 4);
1122 if (unlikely(!p))
1123 goto out_overflow;
1124 if (!ntohl(*p++))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001125 return ERR_PTR(-EAGAIN);
1126 entry->eof = 1;
1127 return ERR_PTR(-EBADCOOKIE);
1128 }
1129
Bryan Schumakerbabddc72010-10-20 15:44:29 -04001130 p = xdr_inline_decode(xdr, 12);
1131 if (unlikely(!p))
1132 goto out_overflow;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001133 p = xdr_decode_hyper(p, &entry->ino);
1134 entry->len = ntohl(*p++);
Bryan Schumakerbabddc72010-10-20 15:44:29 -04001135
1136 p = xdr_inline_decode(xdr, entry->len + 8);
1137 if (unlikely(!p))
1138 goto out_overflow;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001139 entry->name = (const char *) p;
1140 p += XDR_QUADLEN(entry->len);
1141 entry->prev_cookie = entry->cookie;
1142 p = xdr_decode_hyper(p, &entry->cookie);
1143
Trond Myklebust0b26a0b2010-11-20 14:26:44 -05001144 entry->d_type = DT_UNKNOWN;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001145 if (plus) {
1146 entry->fattr->valid = 0;
Bryan Schumakerbabddc72010-10-20 15:44:29 -04001147 p = xdr_decode_post_op_attr_stream(xdr, entry->fattr);
1148 if (IS_ERR(p))
1149 goto out_overflow_exit;
Trond Myklebust0b26a0b2010-11-20 14:26:44 -05001150 entry->d_type = nfs_umode_to_dtype(entry->fattr->mode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001151 /* In fact, a post_op_fh3: */
Bryan Schumakerbabddc72010-10-20 15:44:29 -04001152 p = xdr_inline_decode(xdr, 4);
1153 if (unlikely(!p))
1154 goto out_overflow;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001155 if (*p++) {
Bryan Schumakerbabddc72010-10-20 15:44:29 -04001156 p = xdr_decode_fhandle_stream(xdr, entry->fh);
1157 if (IS_ERR(p))
1158 goto out_overflow_exit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001159 /* Ugh -- server reply was truncated */
1160 if (p == NULL) {
1161 dprintk("NFS: FH truncated\n");
1162 *entry = old;
1163 return ERR_PTR(-EAGAIN);
1164 }
1165 } else
1166 memset((u8*)(entry->fh), 0, sizeof(*entry->fh));
1167 }
1168
Bryan Schumakerbabddc72010-10-20 15:44:29 -04001169 p = xdr_inline_peek(xdr, 8);
1170 if (p != NULL)
1171 entry->eof = !p[0] && p[1];
1172 else
1173 entry->eof = 0;
1174
Linus Torvalds1da177e2005-04-16 15:20:36 -07001175 return p;
Bryan Schumakerbabddc72010-10-20 15:44:29 -04001176
1177out_overflow:
1178 print_overflow_msg(__func__, xdr);
1179out_overflow_exit:
Trond Myklebust463a3762010-11-20 12:22:20 -05001180 return ERR_PTR(-EAGAIN);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001181}
1182
1183/*
Chuck Leverd9c407b2010-12-14 14:55:50 +00001184 * 3.3.21 COMMIT3args
1185 *
1186 * struct COMMIT3args {
1187 * nfs_fh3 file;
1188 * offset3 offset;
1189 * count3 count;
1190 * };
1191 */
1192static void encode_commit3args(struct xdr_stream *xdr,
1193 const struct nfs_writeargs *args)
1194{
1195 __be32 *p;
1196
1197 encode_nfs_fh3(xdr, args->fh);
1198
1199 p = xdr_reserve_space(xdr, 8 + 4);
1200 p = xdr_encode_hyper(p, args->offset);
1201 *p = cpu_to_be32(args->count);
1202}
1203
1204static int nfs3_xdr_enc_commit3args(struct rpc_rqst *req, __be32 *p,
1205 const struct nfs_writeargs *args)
1206{
1207 struct xdr_stream xdr;
1208
1209 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1210 encode_commit3args(&xdr, args);
1211 return 0;
1212}
1213
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +00001214#ifdef CONFIG_NFS_V3_ACL
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +00001215
Chuck Leverd9c407b2010-12-14 14:55:50 +00001216static int nfs3_xdr_enc_getacl3args(struct rpc_rqst *req, __be32 *p,
1217 const struct nfs3_getaclargs *args)
1218{
1219 struct xdr_stream xdr;
1220
1221 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1222 encode_nfs_fh3(&xdr, args->fh);
1223 encode_uint32(&xdr, args->mask);
1224 if (args->mask & (NFS_ACL | NFS_DFACL))
1225 prepare_reply_buffer(req, args->pages, 0,
1226 NFSACL_MAXPAGES << PAGE_SHIFT,
1227 ACL3_getaclres_sz);
1228 return 0;
1229}
1230
Chuck Leverd9c407b2010-12-14 14:55:50 +00001231static int nfs3_xdr_enc_setacl3args(struct rpc_rqst *req, __be32 *p,
1232 const struct nfs3_setaclargs *args)
1233{
1234 struct xdr_stream xdr;
1235 unsigned int base;
1236 int error;
1237
1238 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1239 encode_nfs_fh3(&xdr, NFS_FH(args->inode));
1240 encode_uint32(&xdr, args->mask);
1241 if (args->npages != 0)
1242 xdr_write_pages(&xdr, args->pages, 0, args->len);
1243
1244 base = req->rq_slen;
1245 error = nfsacl_encode(xdr.buf, base, args->inode,
1246 (args->mask & NFS_ACL) ?
1247 args->acl_access : NULL, 1, 0);
1248 BUG_ON(error < 0);
1249 error = nfsacl_encode(xdr.buf, base + error, args->inode,
1250 (args->mask & NFS_DFACL) ?
1251 args->acl_default : NULL, 1,
1252 NFS_ACL_DEFAULT);
1253 BUG_ON(error < 0);
1254 return 0;
1255}
1256
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +00001257#endif /* CONFIG_NFS_V3_ACL */
1258
Linus Torvalds1da177e2005-04-16 15:20:36 -07001259/*
1260 * NFS XDR decode functions
1261 */
1262
1263/*
1264 * Decode attrstat reply.
1265 */
1266static int
Al Virod61005a2006-10-19 23:28:48 -07001267nfs3_xdr_attrstat(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001268{
1269 int status;
1270
1271 if ((status = ntohl(*p++)))
Benny Halevy856dff32008-03-31 17:39:06 +03001272 return nfs_stat_to_errno(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001273 xdr_decode_fattr(p, fattr);
1274 return 0;
1275}
1276
1277/*
1278 * Decode status+wcc_data reply
1279 * SATTR, REMOVE, RMDIR
1280 */
1281static int
Al Virod61005a2006-10-19 23:28:48 -07001282nfs3_xdr_wccstat(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001283{
1284 int status;
1285
1286 if ((status = ntohl(*p++)))
Benny Halevy856dff32008-03-31 17:39:06 +03001287 status = nfs_stat_to_errno(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001288 xdr_decode_wcc_data(p, fattr);
1289 return status;
1290}
1291
Trond Myklebust4fdc17b2007-07-14 15:39:57 -04001292static int
1293nfs3_xdr_removeres(struct rpc_rqst *req, __be32 *p, struct nfs_removeres *res)
1294{
Trond Myklebustd3468902010-04-16 16:22:50 -04001295 return nfs3_xdr_wccstat(req, p, res->dir_attr);
Trond Myklebust4fdc17b2007-07-14 15:39:57 -04001296}
1297
Linus Torvalds1da177e2005-04-16 15:20:36 -07001298/*
1299 * Decode LOOKUP reply
1300 */
1301static int
Al Virod61005a2006-10-19 23:28:48 -07001302nfs3_xdr_lookupres(struct rpc_rqst *req, __be32 *p, struct nfs3_diropres *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001303{
1304 int status;
1305
1306 if ((status = ntohl(*p++))) {
Benny Halevy856dff32008-03-31 17:39:06 +03001307 status = nfs_stat_to_errno(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001308 } else {
1309 if (!(p = xdr_decode_fhandle(p, res->fh)))
1310 return -errno_NFSERR_IO;
1311 p = xdr_decode_post_op_attr(p, res->fattr);
1312 }
1313 xdr_decode_post_op_attr(p, res->dir_attr);
1314 return status;
1315}
1316
1317/*
1318 * Decode ACCESS reply
1319 */
1320static int
Al Virod61005a2006-10-19 23:28:48 -07001321nfs3_xdr_accessres(struct rpc_rqst *req, __be32 *p, struct nfs3_accessres *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001322{
1323 int status = ntohl(*p++);
1324
1325 p = xdr_decode_post_op_attr(p, res->fattr);
1326 if (status)
Benny Halevy856dff32008-03-31 17:39:06 +03001327 return nfs_stat_to_errno(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001328 res->access = ntohl(*p++);
1329 return 0;
1330}
1331
Linus Torvalds1da177e2005-04-16 15:20:36 -07001332/*
1333 * Decode READLINK reply
1334 */
1335static int
Al Virod61005a2006-10-19 23:28:48 -07001336nfs3_xdr_readlinkres(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001337{
1338 struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
1339 struct kvec *iov = rcvbuf->head;
Chuck Leverc957c522007-10-26 13:31:57 -04001340 size_t hdrlen;
1341 u32 len, recvd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001342 int status;
1343
1344 status = ntohl(*p++);
1345 p = xdr_decode_post_op_attr(p, fattr);
1346
1347 if (status != 0)
Benny Halevy856dff32008-03-31 17:39:06 +03001348 return nfs_stat_to_errno(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001349
1350 /* Convert length of symlink */
1351 len = ntohl(*p++);
Chuck Leverc957c522007-10-26 13:31:57 -04001352 if (len >= rcvbuf->page_len) {
Chuck Leverfe82a182007-09-11 18:01:10 -04001353 dprintk("nfs: server returned giant symlink!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001354 return -ENAMETOOLONG;
1355 }
1356
1357 hdrlen = (u8 *) p - (u8 *) iov->iov_base;
1358 if (iov->iov_len < hdrlen) {
Chuck Leverfe82a182007-09-11 18:01:10 -04001359 dprintk("NFS: READLINK reply header overflowed:"
Chuck Leverc957c522007-10-26 13:31:57 -04001360 "length %Zu > %Zu\n", hdrlen, iov->iov_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001361 return -errno_NFSERR_IO;
1362 } else if (iov->iov_len != hdrlen) {
Chuck Leverfe82a182007-09-11 18:01:10 -04001363 dprintk("NFS: READLINK header is short. "
1364 "iovec will be shifted.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001365 xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen);
1366 }
1367 recvd = req->rq_rcv_buf.len - hdrlen;
1368 if (recvd < len) {
Chuck Leverfe82a182007-09-11 18:01:10 -04001369 dprintk("NFS: server cheating in readlink reply: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001370 "count %u > recvd %u\n", len, recvd);
1371 return -EIO;
1372 }
1373
Chuck Leverb4687da2010-09-21 16:55:48 -04001374 xdr_terminate_string(rcvbuf, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001375 return 0;
1376}
1377
1378/*
1379 * Decode READ reply
1380 */
1381static int
Al Virod61005a2006-10-19 23:28:48 -07001382nfs3_xdr_readres(struct rpc_rqst *req, __be32 *p, struct nfs_readres *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001383{
1384 struct kvec *iov = req->rq_rcv_buf.head;
Chuck Leverc957c522007-10-26 13:31:57 -04001385 size_t hdrlen;
1386 u32 count, ocount, recvd;
1387 int status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001388
1389 status = ntohl(*p++);
1390 p = xdr_decode_post_op_attr(p, res->fattr);
1391
1392 if (status != 0)
Benny Halevy856dff32008-03-31 17:39:06 +03001393 return nfs_stat_to_errno(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001394
Chuck Leverc957c522007-10-26 13:31:57 -04001395 /* Decode reply count and EOF flag. NFSv3 is somewhat redundant
Linus Torvalds1da177e2005-04-16 15:20:36 -07001396 * in that it puts the count both in the res struct and in the
1397 * opaque data count. */
1398 count = ntohl(*p++);
1399 res->eof = ntohl(*p++);
1400 ocount = ntohl(*p++);
1401
1402 if (ocount != count) {
Chuck Leverfe82a182007-09-11 18:01:10 -04001403 dprintk("NFS: READ count doesn't match RPC opaque count.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001404 return -errno_NFSERR_IO;
1405 }
1406
1407 hdrlen = (u8 *) p - (u8 *) iov->iov_base;
1408 if (iov->iov_len < hdrlen) {
Chuck Leverfe82a182007-09-11 18:01:10 -04001409 dprintk("NFS: READ reply header overflowed:"
Chuck Leverc957c522007-10-26 13:31:57 -04001410 "length %Zu > %Zu\n", hdrlen, iov->iov_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001411 return -errno_NFSERR_IO;
1412 } else if (iov->iov_len != hdrlen) {
1413 dprintk("NFS: READ header is short. iovec will be shifted.\n");
1414 xdr_shift_buf(&req->rq_rcv_buf, iov->iov_len - hdrlen);
1415 }
1416
1417 recvd = req->rq_rcv_buf.len - hdrlen;
1418 if (count > recvd) {
Chuck Leverfe82a182007-09-11 18:01:10 -04001419 dprintk("NFS: server cheating in read reply: "
Chuck Leverc957c522007-10-26 13:31:57 -04001420 "count %u > recvd %u\n", count, recvd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001421 count = recvd;
1422 res->eof = 0;
1423 }
1424
1425 if (count < res->count)
1426 res->count = count;
1427
1428 return count;
1429}
1430
1431/*
1432 * Decode WRITE response
1433 */
1434static int
Al Virod61005a2006-10-19 23:28:48 -07001435nfs3_xdr_writeres(struct rpc_rqst *req, __be32 *p, struct nfs_writeres *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001436{
1437 int status;
1438
1439 status = ntohl(*p++);
1440 p = xdr_decode_wcc_data(p, res->fattr);
1441
1442 if (status != 0)
Benny Halevy856dff32008-03-31 17:39:06 +03001443 return nfs_stat_to_errno(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001444
1445 res->count = ntohl(*p++);
1446 res->verf->committed = (enum nfs3_stable_how)ntohl(*p++);
1447 res->verf->verifier[0] = *p++;
1448 res->verf->verifier[1] = *p++;
1449
1450 return res->count;
1451}
1452
1453/*
1454 * Decode a CREATE response
1455 */
1456static int
Al Virod61005a2006-10-19 23:28:48 -07001457nfs3_xdr_createres(struct rpc_rqst *req, __be32 *p, struct nfs3_diropres *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001458{
1459 int status;
1460
1461 status = ntohl(*p++);
1462 if (status == 0) {
1463 if (*p++) {
1464 if (!(p = xdr_decode_fhandle(p, res->fh)))
1465 return -errno_NFSERR_IO;
1466 p = xdr_decode_post_op_attr(p, res->fattr);
1467 } else {
1468 memset(res->fh, 0, sizeof(*res->fh));
1469 /* Do decode post_op_attr but set it to NULL */
1470 p = xdr_decode_post_op_attr(p, res->fattr);
1471 res->fattr->valid = 0;
1472 }
1473 } else {
Benny Halevy856dff32008-03-31 17:39:06 +03001474 status = nfs_stat_to_errno(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001475 }
1476 p = xdr_decode_wcc_data(p, res->dir_attr);
1477 return status;
1478}
1479
1480/*
1481 * Decode RENAME reply
1482 */
1483static int
Jeff Laytone8582a82010-09-17 17:31:06 -04001484nfs3_xdr_renameres(struct rpc_rqst *req, __be32 *p, struct nfs_renameres *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001485{
1486 int status;
1487
1488 if ((status = ntohl(*p++)) != 0)
Benny Halevy856dff32008-03-31 17:39:06 +03001489 status = nfs_stat_to_errno(status);
Jeff Laytone8582a82010-09-17 17:31:06 -04001490 p = xdr_decode_wcc_data(p, res->old_fattr);
1491 p = xdr_decode_wcc_data(p, res->new_fattr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001492 return status;
1493}
1494
1495/*
1496 * Decode LINK reply
1497 */
1498static int
Al Virod61005a2006-10-19 23:28:48 -07001499nfs3_xdr_linkres(struct rpc_rqst *req, __be32 *p, struct nfs3_linkres *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001500{
1501 int status;
1502
1503 if ((status = ntohl(*p++)) != 0)
Benny Halevy856dff32008-03-31 17:39:06 +03001504 status = nfs_stat_to_errno(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001505 p = xdr_decode_post_op_attr(p, res->fattr);
1506 p = xdr_decode_wcc_data(p, res->dir_attr);
1507 return status;
1508}
1509
1510/*
1511 * Decode FSSTAT reply
1512 */
1513static int
Al Virod61005a2006-10-19 23:28:48 -07001514nfs3_xdr_fsstatres(struct rpc_rqst *req, __be32 *p, struct nfs_fsstat *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001515{
1516 int status;
1517
1518 status = ntohl(*p++);
1519
1520 p = xdr_decode_post_op_attr(p, res->fattr);
1521 if (status != 0)
Benny Halevy856dff32008-03-31 17:39:06 +03001522 return nfs_stat_to_errno(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001523
1524 p = xdr_decode_hyper(p, &res->tbytes);
1525 p = xdr_decode_hyper(p, &res->fbytes);
1526 p = xdr_decode_hyper(p, &res->abytes);
1527 p = xdr_decode_hyper(p, &res->tfiles);
1528 p = xdr_decode_hyper(p, &res->ffiles);
1529 p = xdr_decode_hyper(p, &res->afiles);
1530
1531 /* ignore invarsec */
1532 return 0;
1533}
1534
1535/*
1536 * Decode FSINFO reply
1537 */
1538static int
Al Virod61005a2006-10-19 23:28:48 -07001539nfs3_xdr_fsinfores(struct rpc_rqst *req, __be32 *p, struct nfs_fsinfo *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001540{
1541 int status;
1542
1543 status = ntohl(*p++);
1544
1545 p = xdr_decode_post_op_attr(p, res->fattr);
1546 if (status != 0)
Benny Halevy856dff32008-03-31 17:39:06 +03001547 return nfs_stat_to_errno(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001548
1549 res->rtmax = ntohl(*p++);
1550 res->rtpref = ntohl(*p++);
1551 res->rtmult = ntohl(*p++);
1552 res->wtmax = ntohl(*p++);
1553 res->wtpref = ntohl(*p++);
1554 res->wtmult = ntohl(*p++);
1555 res->dtpref = ntohl(*p++);
1556 p = xdr_decode_hyper(p, &res->maxfilesize);
Ricardo Labiaga6b967242010-10-12 16:30:05 -07001557 p = xdr_decode_time3(p, &res->time_delta);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001558
Ricardo Labiaga6b967242010-10-12 16:30:05 -07001559 /* ignore properties */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001560 res->lease_time = 0;
1561 return 0;
1562}
1563
1564/*
1565 * Decode PATHCONF reply
1566 */
1567static int
Al Virod61005a2006-10-19 23:28:48 -07001568nfs3_xdr_pathconfres(struct rpc_rqst *req, __be32 *p, struct nfs_pathconf *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001569{
1570 int status;
1571
1572 status = ntohl(*p++);
1573
1574 p = xdr_decode_post_op_attr(p, res->fattr);
1575 if (status != 0)
Benny Halevy856dff32008-03-31 17:39:06 +03001576 return nfs_stat_to_errno(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001577 res->max_link = ntohl(*p++);
1578 res->max_namelen = ntohl(*p++);
1579
1580 /* ignore remaining fields */
1581 return 0;
1582}
1583
1584/*
1585 * Decode COMMIT reply
1586 */
1587static int
Al Virod61005a2006-10-19 23:28:48 -07001588nfs3_xdr_commitres(struct rpc_rqst *req, __be32 *p, struct nfs_writeres *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001589{
1590 int status;
1591
1592 status = ntohl(*p++);
1593 p = xdr_decode_wcc_data(p, res->fattr);
1594 if (status != 0)
Benny Halevy856dff32008-03-31 17:39:06 +03001595 return nfs_stat_to_errno(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001596
1597 res->verf->verifier[0] = *p++;
1598 res->verf->verifier[1] = *p++;
1599 return 0;
1600}
1601
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +00001602#ifdef CONFIG_NFS_V3_ACL
1603/*
1604 * Decode GETACL reply
1605 */
1606static int
Al Virod61005a2006-10-19 23:28:48 -07001607nfs3_xdr_getaclres(struct rpc_rqst *req, __be32 *p,
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +00001608 struct nfs3_getaclres *res)
1609{
1610 struct xdr_buf *buf = &req->rq_rcv_buf;
1611 int status = ntohl(*p++);
1612 struct posix_acl **acl;
1613 unsigned int *aclcnt;
1614 int err, base;
1615
1616 if (status != 0)
Benny Halevy856dff32008-03-31 17:39:06 +03001617 return nfs_stat_to_errno(status);
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +00001618 p = xdr_decode_post_op_attr(p, res->fattr);
1619 res->mask = ntohl(*p++);
1620 if (res->mask & ~(NFS_ACL|NFS_ACLCNT|NFS_DFACL|NFS_DFACLCNT))
1621 return -EINVAL;
1622 base = (char *)p - (char *)req->rq_rcv_buf.head->iov_base;
1623
1624 acl = (res->mask & NFS_ACL) ? &res->acl_access : NULL;
1625 aclcnt = (res->mask & NFS_ACLCNT) ? &res->acl_access_count : NULL;
1626 err = nfsacl_decode(buf, base, aclcnt, acl);
1627
1628 acl = (res->mask & NFS_DFACL) ? &res->acl_default : NULL;
1629 aclcnt = (res->mask & NFS_DFACLCNT) ? &res->acl_default_count : NULL;
1630 if (err > 0)
1631 err = nfsacl_decode(buf, base + err, aclcnt, acl);
1632 return (err > 0) ? 0 : err;
1633}
1634
1635/*
1636 * Decode setacl reply.
1637 */
1638static int
Al Virod61005a2006-10-19 23:28:48 -07001639nfs3_xdr_setaclres(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +00001640{
1641 int status = ntohl(*p++);
1642
1643 if (status)
Benny Halevy856dff32008-03-31 17:39:06 +03001644 return nfs_stat_to_errno(status);
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +00001645 xdr_decode_post_op_attr(p, fattr);
1646 return 0;
1647}
1648#endif /* CONFIG_NFS_V3_ACL */
1649
Linus Torvalds1da177e2005-04-16 15:20:36 -07001650#define PROC(proc, argtype, restype, timer) \
1651[NFS3PROC_##proc] = { \
1652 .p_proc = NFS3PROC_##proc, \
Chuck Leverad96b5b2010-12-14 14:56:01 +00001653 .p_encode = (kxdrproc_t)nfs3_xdr_enc_##argtype##3args, \
Linus Torvalds1da177e2005-04-16 15:20:36 -07001654 .p_decode = (kxdrproc_t) nfs3_xdr_##restype, \
Chuck Leverad96b5b2010-12-14 14:56:01 +00001655 .p_arglen = NFS3_##argtype##args_sz, \
Chuck Lever2bea90d2007-03-29 16:47:53 -04001656 .p_replen = NFS3_##restype##_sz, \
Chuck Levercc0175c2006-03-20 13:44:22 -05001657 .p_timer = timer, \
1658 .p_statidx = NFS3PROC_##proc, \
1659 .p_name = #proc, \
Linus Torvalds1da177e2005-04-16 15:20:36 -07001660 }
1661
1662struct rpc_procinfo nfs3_procedures[] = {
Chuck Leverad96b5b2010-12-14 14:56:01 +00001663 PROC(GETATTR, getattr, attrstat, 1),
1664 PROC(SETATTR, setattr, wccstat, 0),
1665 PROC(LOOKUP, lookup, lookupres, 2),
1666 PROC(ACCESS, access, accessres, 1),
1667 PROC(READLINK, readlink, readlinkres, 3),
1668 PROC(READ, read, readres, 3),
1669 PROC(WRITE, write, writeres, 4),
1670 PROC(CREATE, create, createres, 0),
1671 PROC(MKDIR, mkdir, createres, 0),
1672 PROC(SYMLINK, symlink, createres, 0),
1673 PROC(MKNOD, mknod, createres, 0),
1674 PROC(REMOVE, remove, removeres, 0),
1675 PROC(RMDIR, lookup, wccstat, 0),
1676 PROC(RENAME, rename, renameres, 0),
1677 PROC(LINK, link, linkres, 0),
1678 PROC(READDIR, readdir, readdirres, 3),
1679 PROC(READDIRPLUS, readdirplus, readdirres, 3),
1680 PROC(FSSTAT, getattr, fsstatres, 0),
1681 PROC(FSINFO, getattr, fsinfores, 0),
1682 PROC(PATHCONF, getattr, pathconfres, 0),
1683 PROC(COMMIT, commit, commitres, 5),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001684};
1685
1686struct rpc_version nfs_version3 = {
1687 .number = 3,
Tobias Klausere8c96f82006-03-24 03:15:34 -08001688 .nrprocs = ARRAY_SIZE(nfs3_procedures),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001689 .procs = nfs3_procedures
1690};
1691
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +00001692#ifdef CONFIG_NFS_V3_ACL
1693static struct rpc_procinfo nfs3_acl_procedures[] = {
1694 [ACLPROC3_GETACL] = {
1695 .p_proc = ACLPROC3_GETACL,
Chuck Leverad96b5b2010-12-14 14:56:01 +00001696 .p_encode = (kxdrproc_t)nfs3_xdr_enc_getacl3args,
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +00001697 .p_decode = (kxdrproc_t) nfs3_xdr_getaclres,
Chuck Lever2bea90d2007-03-29 16:47:53 -04001698 .p_arglen = ACL3_getaclargs_sz,
1699 .p_replen = ACL3_getaclres_sz,
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +00001700 .p_timer = 1,
Chuck Levercc0175c2006-03-20 13:44:22 -05001701 .p_name = "GETACL",
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +00001702 },
1703 [ACLPROC3_SETACL] = {
1704 .p_proc = ACLPROC3_SETACL,
Chuck Leverad96b5b2010-12-14 14:56:01 +00001705 .p_encode = (kxdrproc_t)nfs3_xdr_enc_setacl3args,
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +00001706 .p_decode = (kxdrproc_t) nfs3_xdr_setaclres,
Chuck Lever2bea90d2007-03-29 16:47:53 -04001707 .p_arglen = ACL3_setaclargs_sz,
1708 .p_replen = ACL3_setaclres_sz,
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +00001709 .p_timer = 0,
Chuck Levercc0175c2006-03-20 13:44:22 -05001710 .p_name = "SETACL",
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +00001711 },
1712};
1713
1714struct rpc_version nfsacl_version3 = {
1715 .number = 3,
1716 .nrprocs = sizeof(nfs3_acl_procedures)/
1717 sizeof(nfs3_acl_procedures[0]),
1718 .procs = nfs3_acl_procedures,
1719};
1720#endif /* CONFIG_NFS_V3_ACL */