blob: d9e08f0cf2a057aa2f903781c33adc86839aaf7f [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>
12#include <linux/slab.h>
13#include <linux/utsname.h>
14#include <linux/errno.h>
15#include <linux/string.h>
16#include <linux/in.h>
17#include <linux/pagemap.h>
18#include <linux/proc_fs.h>
19#include <linux/kdev_t.h>
20#include <linux/sunrpc/clnt.h>
21#include <linux/nfs.h>
22#include <linux/nfs3.h>
23#include <linux/nfs_fs.h>
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +000024#include <linux/nfsacl.h>
David Howellsf7b422b2006-06-09 09:34:33 -040025#include "internal.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070026
27#define NFSDBG_FACILITY NFSDBG_XDR
28
29/* Mapping from NFS error code to "errno" error code. */
30#define errno_NFSERR_IO EIO
31
Linus Torvalds1da177e2005-04-16 15:20:36 -070032/*
33 * Declare the space requirements for NFS arguments and replies as
34 * number of 32bit-words
35 */
36#define NFS3_fhandle_sz (1+16)
37#define NFS3_fh_sz (NFS3_fhandle_sz) /* shorthand */
38#define NFS3_sattr_sz (15)
39#define NFS3_filename_sz (1+(NFS3_MAXNAMLEN>>2))
40#define NFS3_path_sz (1+(NFS3_MAXPATHLEN>>2))
41#define NFS3_fattr_sz (21)
42#define NFS3_wcc_attr_sz (6)
43#define NFS3_pre_op_attr_sz (1+NFS3_wcc_attr_sz)
44#define NFS3_post_op_attr_sz (1+NFS3_fattr_sz)
45#define NFS3_wcc_data_sz (NFS3_pre_op_attr_sz+NFS3_post_op_attr_sz)
46#define NFS3_fsstat_sz
47#define NFS3_fsinfo_sz
48#define NFS3_pathconf_sz
49#define NFS3_entry_sz (NFS3_filename_sz+3)
50
51#define NFS3_sattrargs_sz (NFS3_fh_sz+NFS3_sattr_sz+3)
52#define NFS3_diropargs_sz (NFS3_fh_sz+NFS3_filename_sz)
Trond Myklebust4fdc17b2007-07-14 15:39:57 -040053#define NFS3_removeargs_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)
62#define NFS3_renameargs_sz (NFS3_diropargs_sz+NFS3_diropargs_sz)
63#define NFS3_linkargs_sz (NFS3_fh_sz+NFS3_diropargs_sz)
64#define NFS3_readdirargs_sz (NFS3_fh_sz+2)
65#define NFS3_commitargs_sz (NFS3_fh_sz+3)
66
67#define NFS3_attrstat_sz (1+NFS3_fattr_sz)
68#define NFS3_wccstat_sz (1+NFS3_wcc_data_sz)
Trond Myklebust4fdc17b2007-07-14 15:39:57 -040069#define NFS3_removeres_sz (NFS3_wccstat_sz)
Linus Torvalds1da177e2005-04-16 15:20:36 -070070#define NFS3_lookupres_sz (1+NFS3_fh_sz+(2 * NFS3_post_op_attr_sz))
71#define NFS3_accessres_sz (1+NFS3_post_op_attr_sz+1)
72#define NFS3_readlinkres_sz (1+NFS3_post_op_attr_sz+1)
73#define NFS3_readres_sz (1+NFS3_post_op_attr_sz+3)
74#define NFS3_writeres_sz (1+NFS3_wcc_data_sz+4)
75#define NFS3_createres_sz (1+NFS3_fh_sz+NFS3_post_op_attr_sz+NFS3_wcc_data_sz)
76#define NFS3_renameres_sz (1+(2 * NFS3_wcc_data_sz))
77#define NFS3_linkres_sz (1+NFS3_post_op_attr_sz+NFS3_wcc_data_sz)
78#define NFS3_readdirres_sz (1+NFS3_post_op_attr_sz+2)
79#define NFS3_fsstatres_sz (1+NFS3_post_op_attr_sz+13)
80#define NFS3_fsinfores_sz (1+NFS3_post_op_attr_sz+12)
81#define NFS3_pathconfres_sz (1+NFS3_post_op_attr_sz+6)
82#define NFS3_commitres_sz (1+NFS3_wcc_data_sz+2)
83
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +000084#define ACL3_getaclargs_sz (NFS3_fh_sz+1)
85#define ACL3_setaclargs_sz (NFS3_fh_sz+1+2*(2+5*3))
86#define ACL3_getaclres_sz (1+NFS3_post_op_attr_sz+1+2*(2+5*3))
87#define ACL3_setaclres_sz (1+NFS3_post_op_attr_sz)
88
Linus Torvalds1da177e2005-04-16 15:20:36 -070089/*
90 * Map file type to S_IFMT bits
91 */
92static struct {
93 unsigned int mode;
94 unsigned int nfs2type;
95} nfs_type2fmt[] = {
96 { 0, NFNON },
97 { S_IFREG, NFREG },
98 { S_IFDIR, NFDIR },
99 { S_IFBLK, NFBLK },
100 { S_IFCHR, NFCHR },
101 { S_IFLNK, NFLNK },
102 { S_IFSOCK, NFSOCK },
103 { S_IFIFO, NFFIFO },
104 { 0, NFBAD }
105};
106
107/*
108 * Common NFS XDR functions as inlines
109 */
Al Virod61005a2006-10-19 23:28:48 -0700110static inline __be32 *
Trond Myklebust4fdc17b2007-07-14 15:39:57 -0400111xdr_encode_fhandle(__be32 *p, const struct nfs_fh *fh)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700112{
113 return xdr_encode_array(p, fh->data, fh->size);
114}
115
Al Virod61005a2006-10-19 23:28:48 -0700116static inline __be32 *
117xdr_decode_fhandle(__be32 *p, struct nfs_fh *fh)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700118{
119 if ((fh->size = ntohl(*p++)) <= NFS3_FHSIZE) {
120 memcpy(fh->data, p, fh->size);
121 return p + XDR_QUADLEN(fh->size);
122 }
123 return NULL;
124}
125
126/*
127 * Encode/decode time.
128 */
Al Virod61005a2006-10-19 23:28:48 -0700129static inline __be32 *
130xdr_encode_time3(__be32 *p, struct timespec *timep)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700131{
132 *p++ = htonl(timep->tv_sec);
133 *p++ = htonl(timep->tv_nsec);
134 return p;
135}
136
Al Virod61005a2006-10-19 23:28:48 -0700137static inline __be32 *
138xdr_decode_time3(__be32 *p, struct timespec *timep)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139{
140 timep->tv_sec = ntohl(*p++);
141 timep->tv_nsec = ntohl(*p++);
142 return p;
143}
144
Al Virod61005a2006-10-19 23:28:48 -0700145static __be32 *
146xdr_decode_fattr(__be32 *p, struct nfs_fattr *fattr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700147{
148 unsigned int type, major, minor;
149 int fmode;
150
151 type = ntohl(*p++);
152 if (type >= NF3BAD)
153 type = NF3BAD;
154 fmode = nfs_type2fmt[type].mode;
155 fattr->type = nfs_type2fmt[type].nfs2type;
156 fattr->mode = (ntohl(*p++) & ~S_IFMT) | fmode;
157 fattr->nlink = ntohl(*p++);
158 fattr->uid = ntohl(*p++);
159 fattr->gid = ntohl(*p++);
160 p = xdr_decode_hyper(p, &fattr->size);
161 p = xdr_decode_hyper(p, &fattr->du.nfs3.used);
162
163 /* Turn remote device info into Linux-specific dev_t */
164 major = ntohl(*p++);
165 minor = ntohl(*p++);
166 fattr->rdev = MKDEV(major, minor);
167 if (MAJOR(fattr->rdev) != major || MINOR(fattr->rdev) != minor)
168 fattr->rdev = 0;
169
Trond Myklebust8b4bdcf2006-06-09 09:34:19 -0400170 p = xdr_decode_hyper(p, &fattr->fsid.major);
171 fattr->fsid.minor = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172 p = xdr_decode_hyper(p, &fattr->fileid);
173 p = xdr_decode_time3(p, &fattr->atime);
174 p = xdr_decode_time3(p, &fattr->mtime);
175 p = xdr_decode_time3(p, &fattr->ctime);
176
177 /* Update the mode bits */
178 fattr->valid |= (NFS_ATTR_FATTR | NFS_ATTR_FATTR_V3);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700179 return p;
180}
181
Al Virod61005a2006-10-19 23:28:48 -0700182static inline __be32 *
183xdr_encode_sattr(__be32 *p, struct iattr *attr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700184{
185 if (attr->ia_valid & ATTR_MODE) {
186 *p++ = xdr_one;
Trond Myklebustcf3fff52006-01-03 09:55:53 +0100187 *p++ = htonl(attr->ia_mode & S_IALLUGO);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700188 } else {
189 *p++ = xdr_zero;
190 }
191 if (attr->ia_valid & ATTR_UID) {
192 *p++ = xdr_one;
193 *p++ = htonl(attr->ia_uid);
194 } else {
195 *p++ = xdr_zero;
196 }
197 if (attr->ia_valid & ATTR_GID) {
198 *p++ = xdr_one;
199 *p++ = htonl(attr->ia_gid);
200 } else {
201 *p++ = xdr_zero;
202 }
203 if (attr->ia_valid & ATTR_SIZE) {
204 *p++ = xdr_one;
205 p = xdr_encode_hyper(p, (__u64) attr->ia_size);
206 } else {
207 *p++ = xdr_zero;
208 }
209 if (attr->ia_valid & ATTR_ATIME_SET) {
210 *p++ = xdr_two;
211 p = xdr_encode_time3(p, &attr->ia_atime);
212 } else if (attr->ia_valid & ATTR_ATIME) {
213 *p++ = xdr_one;
214 } else {
215 *p++ = xdr_zero;
216 }
217 if (attr->ia_valid & ATTR_MTIME_SET) {
218 *p++ = xdr_two;
219 p = xdr_encode_time3(p, &attr->ia_mtime);
220 } else if (attr->ia_valid & ATTR_MTIME) {
221 *p++ = xdr_one;
222 } else {
223 *p++ = xdr_zero;
224 }
225 return p;
226}
227
Al Virod61005a2006-10-19 23:28:48 -0700228static inline __be32 *
229xdr_decode_wcc_attr(__be32 *p, struct nfs_fattr *fattr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700230{
231 p = xdr_decode_hyper(p, &fattr->pre_size);
232 p = xdr_decode_time3(p, &fattr->pre_mtime);
233 p = xdr_decode_time3(p, &fattr->pre_ctime);
234 fattr->valid |= NFS_ATTR_WCC;
235 return p;
236}
237
Al Virod61005a2006-10-19 23:28:48 -0700238static inline __be32 *
239xdr_decode_post_op_attr(__be32 *p, struct nfs_fattr *fattr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700240{
241 if (*p++)
242 p = xdr_decode_fattr(p, fattr);
243 return p;
244}
245
Al Virod61005a2006-10-19 23:28:48 -0700246static inline __be32 *
247xdr_decode_pre_op_attr(__be32 *p, struct nfs_fattr *fattr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700248{
249 if (*p++)
250 return xdr_decode_wcc_attr(p, fattr);
251 return p;
252}
253
254
Al Virod61005a2006-10-19 23:28:48 -0700255static inline __be32 *
256xdr_decode_wcc_data(__be32 *p, struct nfs_fattr *fattr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700257{
258 p = xdr_decode_pre_op_attr(p, fattr);
259 return xdr_decode_post_op_attr(p, fattr);
260}
261
262/*
263 * NFS encode functions
264 */
265
266/*
267 * Encode file handle argument
268 */
269static int
Al Virod61005a2006-10-19 23:28:48 -0700270nfs3_xdr_fhandle(struct rpc_rqst *req, __be32 *p, struct nfs_fh *fh)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700271{
272 p = xdr_encode_fhandle(p, fh);
273 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
274 return 0;
275}
276
277/*
278 * Encode SETATTR arguments
279 */
280static int
Al Virod61005a2006-10-19 23:28:48 -0700281nfs3_xdr_sattrargs(struct rpc_rqst *req, __be32 *p, struct nfs3_sattrargs *args)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700282{
283 p = xdr_encode_fhandle(p, args->fh);
284 p = xdr_encode_sattr(p, args->sattr);
285 *p++ = htonl(args->guard);
286 if (args->guard)
287 p = xdr_encode_time3(p, &args->guardtime);
288 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
289 return 0;
290}
291
292/*
293 * Encode directory ops argument
294 */
295static int
Al Virod61005a2006-10-19 23:28:48 -0700296nfs3_xdr_diropargs(struct rpc_rqst *req, __be32 *p, struct nfs3_diropargs *args)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700297{
298 p = xdr_encode_fhandle(p, args->fh);
299 p = xdr_encode_array(p, args->name, args->len);
300 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
301 return 0;
302}
303
304/*
Trond Myklebust4fdc17b2007-07-14 15:39:57 -0400305 * Encode REMOVE argument
306 */
307static int
308nfs3_xdr_removeargs(struct rpc_rqst *req, __be32 *p, const struct nfs_removeargs *args)
309{
310 p = xdr_encode_fhandle(p, args->fh);
311 p = xdr_encode_array(p, args->name.name, args->name.len);
312 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
313 return 0;
314}
315
316/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700317 * Encode access() argument
318 */
319static int
Al Virod61005a2006-10-19 23:28:48 -0700320nfs3_xdr_accessargs(struct rpc_rqst *req, __be32 *p, struct nfs3_accessargs *args)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700321{
322 p = xdr_encode_fhandle(p, args->fh);
323 *p++ = htonl(args->access);
324 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
325 return 0;
326}
327
328/*
329 * Arguments to a READ call. Since we read data directly into the page
330 * cache, we also set up the reply iovec here so that iov[1] points
331 * exactly to the page we want to fetch.
332 */
333static int
Al Virod61005a2006-10-19 23:28:48 -0700334nfs3_xdr_readargs(struct rpc_rqst *req, __be32 *p, struct nfs_readargs *args)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700335{
Trond Myklebust1be27f32007-06-27 14:29:04 -0400336 struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700337 unsigned int replen;
338 u32 count = args->count;
339
340 p = xdr_encode_fhandle(p, args->fh);
341 p = xdr_encode_hyper(p, args->offset);
342 *p++ = htonl(count);
343 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
344
345 /* Inline the page array */
346 replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS3_readres_sz) << 2;
347 xdr_inline_pages(&req->rq_rcv_buf, replen,
348 args->pages, args->pgbase, count);
349 return 0;
350}
351
352/*
353 * Write arguments. Splice the buffer to be written into the iovec.
354 */
355static int
Al Virod61005a2006-10-19 23:28:48 -0700356nfs3_xdr_writeargs(struct rpc_rqst *req, __be32 *p, struct nfs_writeargs *args)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357{
358 struct xdr_buf *sndbuf = &req->rq_snd_buf;
359 u32 count = args->count;
360
361 p = xdr_encode_fhandle(p, args->fh);
362 p = xdr_encode_hyper(p, args->offset);
363 *p++ = htonl(count);
364 *p++ = htonl(args->stable);
365 *p++ = htonl(count);
366 sndbuf->len = xdr_adjust_iovec(sndbuf->head, p);
367
368 /* Copy the page array */
369 xdr_encode_pages(sndbuf, args->pages, args->pgbase, count);
370 return 0;
371}
372
373/*
374 * Encode CREATE arguments
375 */
376static int
Al Virod61005a2006-10-19 23:28:48 -0700377nfs3_xdr_createargs(struct rpc_rqst *req, __be32 *p, struct nfs3_createargs *args)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378{
379 p = xdr_encode_fhandle(p, args->fh);
380 p = xdr_encode_array(p, args->name, args->len);
381
382 *p++ = htonl(args->createmode);
383 if (args->createmode == NFS3_CREATE_EXCLUSIVE) {
384 *p++ = args->verifier[0];
385 *p++ = args->verifier[1];
386 } else
387 p = xdr_encode_sattr(p, args->sattr);
388
389 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
390 return 0;
391}
392
393/*
394 * Encode MKDIR arguments
395 */
396static int
Al Virod61005a2006-10-19 23:28:48 -0700397nfs3_xdr_mkdirargs(struct rpc_rqst *req, __be32 *p, struct nfs3_mkdirargs *args)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398{
399 p = xdr_encode_fhandle(p, args->fh);
400 p = xdr_encode_array(p, args->name, args->len);
401 p = xdr_encode_sattr(p, args->sattr);
402 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
403 return 0;
404}
405
406/*
407 * Encode SYMLINK arguments
408 */
409static int
Al Virod61005a2006-10-19 23:28:48 -0700410nfs3_xdr_symlinkargs(struct rpc_rqst *req, __be32 *p, struct nfs3_symlinkargs *args)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700411{
412 p = xdr_encode_fhandle(p, args->fromfh);
413 p = xdr_encode_array(p, args->fromname, args->fromlen);
414 p = xdr_encode_sattr(p, args->sattr);
Chuck Lever94a6d752006-08-22 20:06:23 -0400415 *p++ = htonl(args->pathlen);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700416 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
Chuck Lever94a6d752006-08-22 20:06:23 -0400417
418 /* Copy the page */
419 xdr_encode_pages(&req->rq_snd_buf, args->pages, 0, args->pathlen);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700420 return 0;
421}
422
423/*
424 * Encode MKNOD arguments
425 */
426static int
Al Virod61005a2006-10-19 23:28:48 -0700427nfs3_xdr_mknodargs(struct rpc_rqst *req, __be32 *p, struct nfs3_mknodargs *args)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700428{
429 p = xdr_encode_fhandle(p, args->fh);
430 p = xdr_encode_array(p, args->name, args->len);
431 *p++ = htonl(args->type);
432 p = xdr_encode_sattr(p, args->sattr);
433 if (args->type == NF3CHR || args->type == NF3BLK) {
434 *p++ = htonl(MAJOR(args->rdev));
435 *p++ = htonl(MINOR(args->rdev));
436 }
437
438 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
439 return 0;
440}
441
442/*
443 * Encode RENAME arguments
444 */
445static int
Al Virod61005a2006-10-19 23:28:48 -0700446nfs3_xdr_renameargs(struct rpc_rqst *req, __be32 *p, struct nfs3_renameargs *args)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700447{
448 p = xdr_encode_fhandle(p, args->fromfh);
449 p = xdr_encode_array(p, args->fromname, args->fromlen);
450 p = xdr_encode_fhandle(p, args->tofh);
451 p = xdr_encode_array(p, args->toname, args->tolen);
452 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
453 return 0;
454}
455
456/*
457 * Encode LINK arguments
458 */
459static int
Al Virod61005a2006-10-19 23:28:48 -0700460nfs3_xdr_linkargs(struct rpc_rqst *req, __be32 *p, struct nfs3_linkargs *args)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700461{
462 p = xdr_encode_fhandle(p, args->fromfh);
463 p = xdr_encode_fhandle(p, args->tofh);
464 p = xdr_encode_array(p, args->toname, args->tolen);
465 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
466 return 0;
467}
468
469/*
470 * Encode arguments to readdir call
471 */
472static int
Al Virod61005a2006-10-19 23:28:48 -0700473nfs3_xdr_readdirargs(struct rpc_rqst *req, __be32 *p, struct nfs3_readdirargs *args)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700474{
Trond Myklebust1be27f32007-06-27 14:29:04 -0400475 struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700476 unsigned int replen;
477 u32 count = args->count;
478
479 p = xdr_encode_fhandle(p, args->fh);
480 p = xdr_encode_hyper(p, args->cookie);
481 *p++ = args->verf[0];
482 *p++ = args->verf[1];
483 if (args->plus) {
484 /* readdirplus: need dircount + buffer size.
485 * We just make sure we make dircount big enough */
486 *p++ = htonl(count >> 3);
487 }
488 *p++ = htonl(count);
489 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
490
491 /* Inline the page array */
492 replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS3_readdirres_sz) << 2;
493 xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, 0, count);
494 return 0;
495}
496
497/*
498 * Decode the result of a readdir call.
499 * We just check for syntactical correctness.
500 */
501static int
Al Virod61005a2006-10-19 23:28:48 -0700502nfs3_xdr_readdirres(struct rpc_rqst *req, __be32 *p, struct nfs3_readdirres *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503{
504 struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
505 struct kvec *iov = rcvbuf->head;
506 struct page **page;
507 int hdrlen, recvd;
508 int status, nr;
509 unsigned int len, pglen;
Al Virod61005a2006-10-19 23:28:48 -0700510 __be32 *entry, *end, *kaddr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700511
512 status = ntohl(*p++);
513 /* Decode post_op_attrs */
514 p = xdr_decode_post_op_attr(p, res->dir_attr);
515 if (status)
516 return -nfs_stat_to_errno(status);
517 /* Decode verifier cookie */
518 if (res->verf) {
519 res->verf[0] = *p++;
520 res->verf[1] = *p++;
521 } else {
522 p += 2;
523 }
524
525 hdrlen = (u8 *) p - (u8 *) iov->iov_base;
526 if (iov->iov_len < hdrlen) {
527 printk(KERN_WARNING "NFS: READDIR reply header overflowed:"
528 "length %d > %Zu\n", hdrlen, iov->iov_len);
529 return -errno_NFSERR_IO;
530 } else if (iov->iov_len != hdrlen) {
531 dprintk("NFS: READDIR header is short. iovec will be shifted.\n");
532 xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen);
533 }
534
535 pglen = rcvbuf->page_len;
536 recvd = rcvbuf->len - hdrlen;
537 if (pglen > recvd)
538 pglen = recvd;
539 page = rcvbuf->pages;
Al Virod61005a2006-10-19 23:28:48 -0700540 kaddr = p = kmap_atomic(*page, KM_USER0);
541 end = (__be32 *)((char *)p + pglen);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700542 entry = p;
543 for (nr = 0; *p++; nr++) {
544 if (p + 3 > end)
545 goto short_pkt;
546 p += 2; /* inode # */
547 len = ntohl(*p++); /* string length */
548 p += XDR_QUADLEN(len) + 2; /* name + cookie */
549 if (len > NFS3_MAXNAMLEN) {
550 printk(KERN_WARNING "NFS: giant filename in readdir (len %x)!\n",
551 len);
552 goto err_unmap;
553 }
554
555 if (res->plus) {
556 /* post_op_attr */
557 if (p + 2 > end)
558 goto short_pkt;
559 if (*p++) {
560 p += 21;
561 if (p + 1 > end)
562 goto short_pkt;
563 }
564 /* post_op_fh3 */
565 if (*p++) {
566 if (p + 1 > end)
567 goto short_pkt;
568 len = ntohl(*p++);
569 if (len > NFS3_FHSIZE) {
570 printk(KERN_WARNING "NFS: giant filehandle in "
571 "readdir (len %x)!\n", len);
572 goto err_unmap;
573 }
574 p += XDR_QUADLEN(len);
575 }
576 }
577
578 if (p + 2 > end)
579 goto short_pkt;
580 entry = p;
581 }
582 if (!nr && (entry[0] != 0 || entry[1] == 0))
583 goto short_pkt;
584 out:
585 kunmap_atomic(kaddr, KM_USER0);
586 return nr;
587 short_pkt:
588 entry[0] = entry[1] = 0;
589 /* truncate listing ? */
590 if (!nr) {
591 printk(KERN_NOTICE "NFS: readdir reply truncated!\n");
592 entry[1] = 1;
593 }
594 goto out;
595err_unmap:
596 nr = -errno_NFSERR_IO;
597 goto out;
598}
599
Al Viro0dbb4c62006-10-19 23:28:49 -0700600__be32 *
601nfs3_decode_dirent(__be32 *p, struct nfs_entry *entry, int plus)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700602{
603 struct nfs_entry old = *entry;
604
605 if (!*p++) {
606 if (!*p)
607 return ERR_PTR(-EAGAIN);
608 entry->eof = 1;
609 return ERR_PTR(-EBADCOOKIE);
610 }
611
612 p = xdr_decode_hyper(p, &entry->ino);
613 entry->len = ntohl(*p++);
614 entry->name = (const char *) p;
615 p += XDR_QUADLEN(entry->len);
616 entry->prev_cookie = entry->cookie;
617 p = xdr_decode_hyper(p, &entry->cookie);
618
619 if (plus) {
620 entry->fattr->valid = 0;
621 p = xdr_decode_post_op_attr(p, entry->fattr);
622 /* In fact, a post_op_fh3: */
623 if (*p++) {
624 p = xdr_decode_fhandle(p, entry->fh);
625 /* Ugh -- server reply was truncated */
626 if (p == NULL) {
627 dprintk("NFS: FH truncated\n");
628 *entry = old;
629 return ERR_PTR(-EAGAIN);
630 }
631 } else
632 memset((u8*)(entry->fh), 0, sizeof(*entry->fh));
633 }
634
635 entry->eof = !p[0] && p[1];
636 return p;
637}
638
639/*
640 * Encode COMMIT arguments
641 */
642static int
Al Virod61005a2006-10-19 23:28:48 -0700643nfs3_xdr_commitargs(struct rpc_rqst *req, __be32 *p, struct nfs_writeargs *args)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700644{
645 p = xdr_encode_fhandle(p, args->fh);
646 p = xdr_encode_hyper(p, args->offset);
647 *p++ = htonl(args->count);
648 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
649 return 0;
650}
651
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +0000652#ifdef CONFIG_NFS_V3_ACL
653/*
654 * Encode GETACL arguments
655 */
656static int
Al Virod61005a2006-10-19 23:28:48 -0700657nfs3_xdr_getaclargs(struct rpc_rqst *req, __be32 *p,
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +0000658 struct nfs3_getaclargs *args)
659{
Trond Myklebust1be27f32007-06-27 14:29:04 -0400660 struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth;
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +0000661 unsigned int replen;
662
663 p = xdr_encode_fhandle(p, args->fh);
664 *p++ = htonl(args->mask);
665 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
666
667 if (args->mask & (NFS_ACL | NFS_DFACL)) {
668 /* Inline the page array */
669 replen = (RPC_REPHDRSIZE + auth->au_rslack +
670 ACL3_getaclres_sz) << 2;
671 xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, 0,
672 NFSACL_MAXPAGES << PAGE_SHIFT);
673 }
674 return 0;
675}
676
677/*
678 * Encode SETACL arguments
679 */
680static int
Al Virod61005a2006-10-19 23:28:48 -0700681nfs3_xdr_setaclargs(struct rpc_rqst *req, __be32 *p,
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +0000682 struct nfs3_setaclargs *args)
683{
684 struct xdr_buf *buf = &req->rq_snd_buf;
685 unsigned int base, len_in_head, len = nfsacl_size(
686 (args->mask & NFS_ACL) ? args->acl_access : NULL,
687 (args->mask & NFS_DFACL) ? args->acl_default : NULL);
688 int count, err;
689
690 p = xdr_encode_fhandle(p, NFS_FH(args->inode));
691 *p++ = htonl(args->mask);
692 base = (char *)p - (char *)buf->head->iov_base;
693 /* put as much of the acls into head as possible. */
694 len_in_head = min_t(unsigned int, buf->head->iov_len - base, len);
695 len -= len_in_head;
Andreas Gruenbacher21348422005-06-22 17:16:28 +0000696 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p + (len_in_head >> 2));
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +0000697
698 for (count = 0; (count << PAGE_SHIFT) < len; count++) {
699 args->pages[count] = alloc_page(GFP_KERNEL);
700 if (!args->pages[count]) {
701 while (count)
702 __free_page(args->pages[--count]);
703 return -ENOMEM;
704 }
705 }
706 xdr_encode_pages(buf, args->pages, 0, len);
707
708 err = nfsacl_encode(buf, base, args->inode,
709 (args->mask & NFS_ACL) ?
710 args->acl_access : NULL, 1, 0);
711 if (err > 0)
712 err = nfsacl_encode(buf, base + err, args->inode,
713 (args->mask & NFS_DFACL) ?
714 args->acl_default : NULL, 1,
715 NFS_ACL_DEFAULT);
716 return (err > 0) ? 0 : err;
717}
718#endif /* CONFIG_NFS_V3_ACL */
719
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720/*
721 * NFS XDR decode functions
722 */
723
724/*
725 * Decode attrstat reply.
726 */
727static int
Al Virod61005a2006-10-19 23:28:48 -0700728nfs3_xdr_attrstat(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700729{
730 int status;
731
732 if ((status = ntohl(*p++)))
733 return -nfs_stat_to_errno(status);
734 xdr_decode_fattr(p, fattr);
735 return 0;
736}
737
738/*
739 * Decode status+wcc_data reply
740 * SATTR, REMOVE, RMDIR
741 */
742static int
Al Virod61005a2006-10-19 23:28:48 -0700743nfs3_xdr_wccstat(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700744{
745 int status;
746
747 if ((status = ntohl(*p++)))
748 status = -nfs_stat_to_errno(status);
749 xdr_decode_wcc_data(p, fattr);
750 return status;
751}
752
Trond Myklebust4fdc17b2007-07-14 15:39:57 -0400753static int
754nfs3_xdr_removeres(struct rpc_rqst *req, __be32 *p, struct nfs_removeres *res)
755{
756 return nfs3_xdr_wccstat(req, p, &res->dir_attr);
757}
758
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759/*
760 * Decode LOOKUP reply
761 */
762static int
Al Virod61005a2006-10-19 23:28:48 -0700763nfs3_xdr_lookupres(struct rpc_rqst *req, __be32 *p, struct nfs3_diropres *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700764{
765 int status;
766
767 if ((status = ntohl(*p++))) {
768 status = -nfs_stat_to_errno(status);
769 } else {
770 if (!(p = xdr_decode_fhandle(p, res->fh)))
771 return -errno_NFSERR_IO;
772 p = xdr_decode_post_op_attr(p, res->fattr);
773 }
774 xdr_decode_post_op_attr(p, res->dir_attr);
775 return status;
776}
777
778/*
779 * Decode ACCESS reply
780 */
781static int
Al Virod61005a2006-10-19 23:28:48 -0700782nfs3_xdr_accessres(struct rpc_rqst *req, __be32 *p, struct nfs3_accessres *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700783{
784 int status = ntohl(*p++);
785
786 p = xdr_decode_post_op_attr(p, res->fattr);
787 if (status)
788 return -nfs_stat_to_errno(status);
789 res->access = ntohl(*p++);
790 return 0;
791}
792
793static int
Al Virod61005a2006-10-19 23:28:48 -0700794nfs3_xdr_readlinkargs(struct rpc_rqst *req, __be32 *p, struct nfs3_readlinkargs *args)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795{
Trond Myklebust1be27f32007-06-27 14:29:04 -0400796 struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700797 unsigned int replen;
798
799 p = xdr_encode_fhandle(p, args->fh);
800 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
801
802 /* Inline the page array */
803 replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS3_readlinkres_sz) << 2;
804 xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, args->pgbase, args->pglen);
805 return 0;
806}
807
808/*
809 * Decode READLINK reply
810 */
811static int
Al Virod61005a2006-10-19 23:28:48 -0700812nfs3_xdr_readlinkres(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700813{
814 struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
815 struct kvec *iov = rcvbuf->head;
816 int hdrlen, len, recvd;
817 char *kaddr;
818 int status;
819
820 status = ntohl(*p++);
821 p = xdr_decode_post_op_attr(p, fattr);
822
823 if (status != 0)
824 return -nfs_stat_to_errno(status);
825
826 /* Convert length of symlink */
827 len = ntohl(*p++);
828 if (len >= rcvbuf->page_len || len <= 0) {
829 dprintk(KERN_WARNING "nfs: server returned giant symlink!\n");
830 return -ENAMETOOLONG;
831 }
832
833 hdrlen = (u8 *) p - (u8 *) iov->iov_base;
834 if (iov->iov_len < hdrlen) {
835 printk(KERN_WARNING "NFS: READLINK reply header overflowed:"
836 "length %d > %Zu\n", hdrlen, iov->iov_len);
837 return -errno_NFSERR_IO;
838 } else if (iov->iov_len != hdrlen) {
839 dprintk("NFS: READLINK header is short. iovec will be shifted.\n");
840 xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen);
841 }
842 recvd = req->rq_rcv_buf.len - hdrlen;
843 if (recvd < len) {
844 printk(KERN_WARNING "NFS: server cheating in readlink reply: "
845 "count %u > recvd %u\n", len, recvd);
846 return -EIO;
847 }
848
849 /* NULL terminate the string we got */
850 kaddr = (char*)kmap_atomic(rcvbuf->pages[0], KM_USER0);
851 kaddr[len+rcvbuf->page_base] = '\0';
852 kunmap_atomic(kaddr, KM_USER0);
853 return 0;
854}
855
856/*
857 * Decode READ reply
858 */
859static int
Al Virod61005a2006-10-19 23:28:48 -0700860nfs3_xdr_readres(struct rpc_rqst *req, __be32 *p, struct nfs_readres *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700861{
862 struct kvec *iov = req->rq_rcv_buf.head;
863 int status, count, ocount, recvd, hdrlen;
864
865 status = ntohl(*p++);
866 p = xdr_decode_post_op_attr(p, res->fattr);
867
868 if (status != 0)
869 return -nfs_stat_to_errno(status);
870
871 /* Decode reply could and EOF flag. NFSv3 is somewhat redundant
872 * in that it puts the count both in the res struct and in the
873 * opaque data count. */
874 count = ntohl(*p++);
875 res->eof = ntohl(*p++);
876 ocount = ntohl(*p++);
877
878 if (ocount != count) {
879 printk(KERN_WARNING "NFS: READ count doesn't match RPC opaque count.\n");
880 return -errno_NFSERR_IO;
881 }
882
883 hdrlen = (u8 *) p - (u8 *) iov->iov_base;
884 if (iov->iov_len < hdrlen) {
885 printk(KERN_WARNING "NFS: READ reply header overflowed:"
886 "length %d > %Zu\n", hdrlen, iov->iov_len);
887 return -errno_NFSERR_IO;
888 } else if (iov->iov_len != hdrlen) {
889 dprintk("NFS: READ header is short. iovec will be shifted.\n");
890 xdr_shift_buf(&req->rq_rcv_buf, iov->iov_len - hdrlen);
891 }
892
893 recvd = req->rq_rcv_buf.len - hdrlen;
894 if (count > recvd) {
895 printk(KERN_WARNING "NFS: server cheating in read reply: "
896 "count %d > recvd %d\n", count, recvd);
897 count = recvd;
898 res->eof = 0;
899 }
900
901 if (count < res->count)
902 res->count = count;
903
904 return count;
905}
906
907/*
908 * Decode WRITE response
909 */
910static int
Al Virod61005a2006-10-19 23:28:48 -0700911nfs3_xdr_writeres(struct rpc_rqst *req, __be32 *p, struct nfs_writeres *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700912{
913 int status;
914
915 status = ntohl(*p++);
916 p = xdr_decode_wcc_data(p, res->fattr);
917
918 if (status != 0)
919 return -nfs_stat_to_errno(status);
920
921 res->count = ntohl(*p++);
922 res->verf->committed = (enum nfs3_stable_how)ntohl(*p++);
923 res->verf->verifier[0] = *p++;
924 res->verf->verifier[1] = *p++;
925
926 return res->count;
927}
928
929/*
930 * Decode a CREATE response
931 */
932static int
Al Virod61005a2006-10-19 23:28:48 -0700933nfs3_xdr_createres(struct rpc_rqst *req, __be32 *p, struct nfs3_diropres *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700934{
935 int status;
936
937 status = ntohl(*p++);
938 if (status == 0) {
939 if (*p++) {
940 if (!(p = xdr_decode_fhandle(p, res->fh)))
941 return -errno_NFSERR_IO;
942 p = xdr_decode_post_op_attr(p, res->fattr);
943 } else {
944 memset(res->fh, 0, sizeof(*res->fh));
945 /* Do decode post_op_attr but set it to NULL */
946 p = xdr_decode_post_op_attr(p, res->fattr);
947 res->fattr->valid = 0;
948 }
949 } else {
950 status = -nfs_stat_to_errno(status);
951 }
952 p = xdr_decode_wcc_data(p, res->dir_attr);
953 return status;
954}
955
956/*
957 * Decode RENAME reply
958 */
959static int
Al Virod61005a2006-10-19 23:28:48 -0700960nfs3_xdr_renameres(struct rpc_rqst *req, __be32 *p, struct nfs3_renameres *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700961{
962 int status;
963
964 if ((status = ntohl(*p++)) != 0)
965 status = -nfs_stat_to_errno(status);
966 p = xdr_decode_wcc_data(p, res->fromattr);
967 p = xdr_decode_wcc_data(p, res->toattr);
968 return status;
969}
970
971/*
972 * Decode LINK reply
973 */
974static int
Al Virod61005a2006-10-19 23:28:48 -0700975nfs3_xdr_linkres(struct rpc_rqst *req, __be32 *p, struct nfs3_linkres *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700976{
977 int status;
978
979 if ((status = ntohl(*p++)) != 0)
980 status = -nfs_stat_to_errno(status);
981 p = xdr_decode_post_op_attr(p, res->fattr);
982 p = xdr_decode_wcc_data(p, res->dir_attr);
983 return status;
984}
985
986/*
987 * Decode FSSTAT reply
988 */
989static int
Al Virod61005a2006-10-19 23:28:48 -0700990nfs3_xdr_fsstatres(struct rpc_rqst *req, __be32 *p, struct nfs_fsstat *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700991{
992 int status;
993
994 status = ntohl(*p++);
995
996 p = xdr_decode_post_op_attr(p, res->fattr);
997 if (status != 0)
998 return -nfs_stat_to_errno(status);
999
1000 p = xdr_decode_hyper(p, &res->tbytes);
1001 p = xdr_decode_hyper(p, &res->fbytes);
1002 p = xdr_decode_hyper(p, &res->abytes);
1003 p = xdr_decode_hyper(p, &res->tfiles);
1004 p = xdr_decode_hyper(p, &res->ffiles);
1005 p = xdr_decode_hyper(p, &res->afiles);
1006
1007 /* ignore invarsec */
1008 return 0;
1009}
1010
1011/*
1012 * Decode FSINFO reply
1013 */
1014static int
Al Virod61005a2006-10-19 23:28:48 -07001015nfs3_xdr_fsinfores(struct rpc_rqst *req, __be32 *p, struct nfs_fsinfo *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001016{
1017 int status;
1018
1019 status = ntohl(*p++);
1020
1021 p = xdr_decode_post_op_attr(p, res->fattr);
1022 if (status != 0)
1023 return -nfs_stat_to_errno(status);
1024
1025 res->rtmax = ntohl(*p++);
1026 res->rtpref = ntohl(*p++);
1027 res->rtmult = ntohl(*p++);
1028 res->wtmax = ntohl(*p++);
1029 res->wtpref = ntohl(*p++);
1030 res->wtmult = ntohl(*p++);
1031 res->dtpref = ntohl(*p++);
1032 p = xdr_decode_hyper(p, &res->maxfilesize);
1033
1034 /* ignore time_delta and properties */
1035 res->lease_time = 0;
1036 return 0;
1037}
1038
1039/*
1040 * Decode PATHCONF reply
1041 */
1042static int
Al Virod61005a2006-10-19 23:28:48 -07001043nfs3_xdr_pathconfres(struct rpc_rqst *req, __be32 *p, struct nfs_pathconf *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001044{
1045 int status;
1046
1047 status = ntohl(*p++);
1048
1049 p = xdr_decode_post_op_attr(p, res->fattr);
1050 if (status != 0)
1051 return -nfs_stat_to_errno(status);
1052 res->max_link = ntohl(*p++);
1053 res->max_namelen = ntohl(*p++);
1054
1055 /* ignore remaining fields */
1056 return 0;
1057}
1058
1059/*
1060 * Decode COMMIT reply
1061 */
1062static int
Al Virod61005a2006-10-19 23:28:48 -07001063nfs3_xdr_commitres(struct rpc_rqst *req, __be32 *p, struct nfs_writeres *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001064{
1065 int status;
1066
1067 status = ntohl(*p++);
1068 p = xdr_decode_wcc_data(p, res->fattr);
1069 if (status != 0)
1070 return -nfs_stat_to_errno(status);
1071
1072 res->verf->verifier[0] = *p++;
1073 res->verf->verifier[1] = *p++;
1074 return 0;
1075}
1076
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +00001077#ifdef CONFIG_NFS_V3_ACL
1078/*
1079 * Decode GETACL reply
1080 */
1081static int
Al Virod61005a2006-10-19 23:28:48 -07001082nfs3_xdr_getaclres(struct rpc_rqst *req, __be32 *p,
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +00001083 struct nfs3_getaclres *res)
1084{
1085 struct xdr_buf *buf = &req->rq_rcv_buf;
1086 int status = ntohl(*p++);
1087 struct posix_acl **acl;
1088 unsigned int *aclcnt;
1089 int err, base;
1090
1091 if (status != 0)
1092 return -nfs_stat_to_errno(status);
1093 p = xdr_decode_post_op_attr(p, res->fattr);
1094 res->mask = ntohl(*p++);
1095 if (res->mask & ~(NFS_ACL|NFS_ACLCNT|NFS_DFACL|NFS_DFACLCNT))
1096 return -EINVAL;
1097 base = (char *)p - (char *)req->rq_rcv_buf.head->iov_base;
1098
1099 acl = (res->mask & NFS_ACL) ? &res->acl_access : NULL;
1100 aclcnt = (res->mask & NFS_ACLCNT) ? &res->acl_access_count : NULL;
1101 err = nfsacl_decode(buf, base, aclcnt, acl);
1102
1103 acl = (res->mask & NFS_DFACL) ? &res->acl_default : NULL;
1104 aclcnt = (res->mask & NFS_DFACLCNT) ? &res->acl_default_count : NULL;
1105 if (err > 0)
1106 err = nfsacl_decode(buf, base + err, aclcnt, acl);
1107 return (err > 0) ? 0 : err;
1108}
1109
1110/*
1111 * Decode setacl reply.
1112 */
1113static int
Al Virod61005a2006-10-19 23:28:48 -07001114nfs3_xdr_setaclres(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +00001115{
1116 int status = ntohl(*p++);
1117
1118 if (status)
1119 return -nfs_stat_to_errno(status);
1120 xdr_decode_post_op_attr(p, fattr);
1121 return 0;
1122}
1123#endif /* CONFIG_NFS_V3_ACL */
1124
Linus Torvalds1da177e2005-04-16 15:20:36 -07001125#define PROC(proc, argtype, restype, timer) \
1126[NFS3PROC_##proc] = { \
1127 .p_proc = NFS3PROC_##proc, \
1128 .p_encode = (kxdrproc_t) nfs3_xdr_##argtype, \
1129 .p_decode = (kxdrproc_t) nfs3_xdr_##restype, \
Chuck Lever2bea90d2007-03-29 16:47:53 -04001130 .p_arglen = NFS3_##argtype##_sz, \
1131 .p_replen = NFS3_##restype##_sz, \
Chuck Levercc0175c2006-03-20 13:44:22 -05001132 .p_timer = timer, \
1133 .p_statidx = NFS3PROC_##proc, \
1134 .p_name = #proc, \
Linus Torvalds1da177e2005-04-16 15:20:36 -07001135 }
1136
1137struct rpc_procinfo nfs3_procedures[] = {
1138 PROC(GETATTR, fhandle, attrstat, 1),
1139 PROC(SETATTR, sattrargs, wccstat, 0),
1140 PROC(LOOKUP, diropargs, lookupres, 2),
1141 PROC(ACCESS, accessargs, accessres, 1),
1142 PROC(READLINK, readlinkargs, readlinkres, 3),
1143 PROC(READ, readargs, readres, 3),
1144 PROC(WRITE, writeargs, writeres, 4),
1145 PROC(CREATE, createargs, createres, 0),
1146 PROC(MKDIR, mkdirargs, createres, 0),
1147 PROC(SYMLINK, symlinkargs, createres, 0),
1148 PROC(MKNOD, mknodargs, createres, 0),
Trond Myklebust4fdc17b2007-07-14 15:39:57 -04001149 PROC(REMOVE, removeargs, removeres, 0),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001150 PROC(RMDIR, diropargs, wccstat, 0),
1151 PROC(RENAME, renameargs, renameres, 0),
1152 PROC(LINK, linkargs, linkres, 0),
1153 PROC(READDIR, readdirargs, readdirres, 3),
1154 PROC(READDIRPLUS, readdirargs, readdirres, 3),
1155 PROC(FSSTAT, fhandle, fsstatres, 0),
1156 PROC(FSINFO, fhandle, fsinfores, 0),
1157 PROC(PATHCONF, fhandle, pathconfres, 0),
1158 PROC(COMMIT, commitargs, commitres, 5),
1159};
1160
1161struct rpc_version nfs_version3 = {
1162 .number = 3,
Tobias Klausere8c96f82006-03-24 03:15:34 -08001163 .nrprocs = ARRAY_SIZE(nfs3_procedures),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001164 .procs = nfs3_procedures
1165};
1166
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +00001167#ifdef CONFIG_NFS_V3_ACL
1168static struct rpc_procinfo nfs3_acl_procedures[] = {
1169 [ACLPROC3_GETACL] = {
1170 .p_proc = ACLPROC3_GETACL,
1171 .p_encode = (kxdrproc_t) nfs3_xdr_getaclargs,
1172 .p_decode = (kxdrproc_t) nfs3_xdr_getaclres,
Chuck Lever2bea90d2007-03-29 16:47:53 -04001173 .p_arglen = ACL3_getaclargs_sz,
1174 .p_replen = ACL3_getaclres_sz,
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +00001175 .p_timer = 1,
Chuck Levercc0175c2006-03-20 13:44:22 -05001176 .p_name = "GETACL",
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +00001177 },
1178 [ACLPROC3_SETACL] = {
1179 .p_proc = ACLPROC3_SETACL,
1180 .p_encode = (kxdrproc_t) nfs3_xdr_setaclargs,
1181 .p_decode = (kxdrproc_t) nfs3_xdr_setaclres,
Chuck Lever2bea90d2007-03-29 16:47:53 -04001182 .p_arglen = ACL3_setaclargs_sz,
1183 .p_replen = ACL3_setaclres_sz,
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +00001184 .p_timer = 0,
Chuck Levercc0175c2006-03-20 13:44:22 -05001185 .p_name = "SETACL",
Andreas Gruenbacherb7fa0552005-06-22 17:16:27 +00001186 },
1187};
1188
1189struct rpc_version nfsacl_version3 = {
1190 .number = 3,
1191 .nrprocs = sizeof(nfs3_acl_procedures)/
1192 sizeof(nfs3_acl_procedures[0]),
1193 .procs = nfs3_acl_procedures,
1194};
1195#endif /* CONFIG_NFS_V3_ACL */