added 2.6.29.6 aldebaran kernel
[nao-ulib.git] / kernel / 2.6.29.6-aldebaran-rt / fs / nfs / nfs3xdr.c
blob4bd49c1358cd69b517533d90540566d1647d9421
1 /*
2 * linux/fs/nfs/nfs3xdr.c
4 * XDR functions to encode/decode NFSv3 RPC arguments and results.
6 * Copyright (C) 1996, 1997 Olaf Kirch
7 */
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>
24 #include <linux/nfsacl.h>
25 #include "internal.h"
27 #define NFSDBG_FACILITY NFSDBG_XDR
29 /* Mapping from NFS error code to "errno" error code. */
30 #define errno_NFSERR_IO EIO
33 * Declare the space requirements for NFS arguments and replies as
34 * number of 32bit-words
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)
51 #define NFS3_sattrargs_sz (NFS3_fh_sz+NFS3_sattr_sz+3)
52 #define NFS3_diropargs_sz (NFS3_fh_sz+NFS3_filename_sz)
53 #define NFS3_removeargs_sz (NFS3_fh_sz+NFS3_filename_sz)
54 #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)
60 #define NFS3_symlinkargs_sz (NFS3_diropargs_sz+1+NFS3_sattr_sz)
61 #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)
67 #define NFS3_attrstat_sz (1+NFS3_fattr_sz)
68 #define NFS3_wccstat_sz (1+NFS3_wcc_data_sz)
69 #define NFS3_removeres_sz (NFS3_wccstat_sz)
70 #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)
84 #define ACL3_getaclargs_sz (NFS3_fh_sz+1)
85 #define ACL3_setaclargs_sz (NFS3_fh_sz+1+ \
86 XDR_QUADLEN(NFS_ACL_INLINE_BUFSIZE))
87 #define ACL3_getaclres_sz (1+NFS3_post_op_attr_sz+1+ \
88 XDR_QUADLEN(NFS_ACL_INLINE_BUFSIZE))
89 #define ACL3_setaclres_sz (1+NFS3_post_op_attr_sz)
92 * Map file type to S_IFMT bits
94 static struct {
95 unsigned int mode;
96 unsigned int nfs2type;
97 } nfs_type2fmt[] = {
98 { 0, NFNON },
99 { S_IFREG, NFREG },
100 { S_IFDIR, NFDIR },
101 { S_IFBLK, NFBLK },
102 { S_IFCHR, NFCHR },
103 { S_IFLNK, NFLNK },
104 { S_IFSOCK, NFSOCK },
105 { S_IFIFO, NFFIFO },
106 { 0, NFBAD }
110 * Common NFS XDR functions as inlines
112 static inline __be32 *
113 xdr_encode_fhandle(__be32 *p, const struct nfs_fh *fh)
115 return xdr_encode_array(p, fh->data, fh->size);
118 static inline __be32 *
119 xdr_decode_fhandle(__be32 *p, struct nfs_fh *fh)
121 if ((fh->size = ntohl(*p++)) <= NFS3_FHSIZE) {
122 memcpy(fh->data, p, fh->size);
123 return p + XDR_QUADLEN(fh->size);
125 return NULL;
129 * Encode/decode time.
131 static inline __be32 *
132 xdr_encode_time3(__be32 *p, struct timespec *timep)
134 *p++ = htonl(timep->tv_sec);
135 *p++ = htonl(timep->tv_nsec);
136 return p;
139 static inline __be32 *
140 xdr_decode_time3(__be32 *p, struct timespec *timep)
142 timep->tv_sec = ntohl(*p++);
143 timep->tv_nsec = ntohl(*p++);
144 return p;
147 static __be32 *
148 xdr_decode_fattr(__be32 *p, struct nfs_fattr *fattr)
150 unsigned int type, major, minor;
151 int fmode;
153 type = ntohl(*p++);
154 if (type >= NF3BAD)
155 type = NF3BAD;
156 fmode = nfs_type2fmt[type].mode;
157 fattr->type = nfs_type2fmt[type].nfs2type;
158 fattr->mode = (ntohl(*p++) & ~S_IFMT) | fmode;
159 fattr->nlink = ntohl(*p++);
160 fattr->uid = ntohl(*p++);
161 fattr->gid = ntohl(*p++);
162 p = xdr_decode_hyper(p, &fattr->size);
163 p = xdr_decode_hyper(p, &fattr->du.nfs3.used);
165 /* Turn remote device info into Linux-specific dev_t */
166 major = ntohl(*p++);
167 minor = ntohl(*p++);
168 fattr->rdev = MKDEV(major, minor);
169 if (MAJOR(fattr->rdev) != major || MINOR(fattr->rdev) != minor)
170 fattr->rdev = 0;
172 p = xdr_decode_hyper(p, &fattr->fsid.major);
173 fattr->fsid.minor = 0;
174 p = xdr_decode_hyper(p, &fattr->fileid);
175 p = xdr_decode_time3(p, &fattr->atime);
176 p = xdr_decode_time3(p, &fattr->mtime);
177 p = xdr_decode_time3(p, &fattr->ctime);
179 /* Update the mode bits */
180 fattr->valid |= (NFS_ATTR_FATTR | NFS_ATTR_FATTR_V3);
181 return p;
184 static inline __be32 *
185 xdr_encode_sattr(__be32 *p, struct iattr *attr)
187 if (attr->ia_valid & ATTR_MODE) {
188 *p++ = xdr_one;
189 *p++ = htonl(attr->ia_mode & S_IALLUGO);
190 } else {
191 *p++ = xdr_zero;
193 if (attr->ia_valid & ATTR_UID) {
194 *p++ = xdr_one;
195 *p++ = htonl(attr->ia_uid);
196 } else {
197 *p++ = xdr_zero;
199 if (attr->ia_valid & ATTR_GID) {
200 *p++ = xdr_one;
201 *p++ = htonl(attr->ia_gid);
202 } else {
203 *p++ = xdr_zero;
205 if (attr->ia_valid & ATTR_SIZE) {
206 *p++ = xdr_one;
207 p = xdr_encode_hyper(p, (__u64) attr->ia_size);
208 } else {
209 *p++ = xdr_zero;
211 if (attr->ia_valid & ATTR_ATIME_SET) {
212 *p++ = xdr_two;
213 p = xdr_encode_time3(p, &attr->ia_atime);
214 } else if (attr->ia_valid & ATTR_ATIME) {
215 *p++ = xdr_one;
216 } else {
217 *p++ = xdr_zero;
219 if (attr->ia_valid & ATTR_MTIME_SET) {
220 *p++ = xdr_two;
221 p = xdr_encode_time3(p, &attr->ia_mtime);
222 } else if (attr->ia_valid & ATTR_MTIME) {
223 *p++ = xdr_one;
224 } else {
225 *p++ = xdr_zero;
227 return p;
230 static inline __be32 *
231 xdr_decode_wcc_attr(__be32 *p, struct nfs_fattr *fattr)
233 p = xdr_decode_hyper(p, &fattr->pre_size);
234 p = xdr_decode_time3(p, &fattr->pre_mtime);
235 p = xdr_decode_time3(p, &fattr->pre_ctime);
236 fattr->valid |= NFS_ATTR_WCC;
237 return p;
240 static inline __be32 *
241 xdr_decode_post_op_attr(__be32 *p, struct nfs_fattr *fattr)
243 if (*p++)
244 p = xdr_decode_fattr(p, fattr);
245 return p;
248 static inline __be32 *
249 xdr_decode_pre_op_attr(__be32 *p, struct nfs_fattr *fattr)
251 if (*p++)
252 return xdr_decode_wcc_attr(p, fattr);
253 return p;
257 static inline __be32 *
258 xdr_decode_wcc_data(__be32 *p, struct nfs_fattr *fattr)
260 p = xdr_decode_pre_op_attr(p, fattr);
261 return xdr_decode_post_op_attr(p, fattr);
265 * NFS encode functions
269 * Encode file handle argument
271 static int
272 nfs3_xdr_fhandle(struct rpc_rqst *req, __be32 *p, struct nfs_fh *fh)
274 p = xdr_encode_fhandle(p, fh);
275 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
276 return 0;
280 * Encode SETATTR arguments
282 static int
283 nfs3_xdr_sattrargs(struct rpc_rqst *req, __be32 *p, struct nfs3_sattrargs *args)
285 p = xdr_encode_fhandle(p, args->fh);
286 p = xdr_encode_sattr(p, args->sattr);
287 *p++ = htonl(args->guard);
288 if (args->guard)
289 p = xdr_encode_time3(p, &args->guardtime);
290 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
291 return 0;
295 * Encode directory ops argument
297 static int
298 nfs3_xdr_diropargs(struct rpc_rqst *req, __be32 *p, struct nfs3_diropargs *args)
300 p = xdr_encode_fhandle(p, args->fh);
301 p = xdr_encode_array(p, args->name, args->len);
302 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
303 return 0;
307 * Encode REMOVE argument
309 static int
310 nfs3_xdr_removeargs(struct rpc_rqst *req, __be32 *p, const struct nfs_removeargs *args)
312 p = xdr_encode_fhandle(p, args->fh);
313 p = xdr_encode_array(p, args->name.name, args->name.len);
314 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
315 return 0;
319 * Encode access() argument
321 static int
322 nfs3_xdr_accessargs(struct rpc_rqst *req, __be32 *p, struct nfs3_accessargs *args)
324 p = xdr_encode_fhandle(p, args->fh);
325 *p++ = htonl(args->access);
326 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
327 return 0;
331 * Arguments to a READ call. Since we read data directly into the page
332 * cache, we also set up the reply iovec here so that iov[1] points
333 * exactly to the page we want to fetch.
335 static int
336 nfs3_xdr_readargs(struct rpc_rqst *req, __be32 *p, struct nfs_readargs *args)
338 struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth;
339 unsigned int replen;
340 u32 count = args->count;
342 p = xdr_encode_fhandle(p, args->fh);
343 p = xdr_encode_hyper(p, args->offset);
344 *p++ = htonl(count);
345 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
347 /* Inline the page array */
348 replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS3_readres_sz) << 2;
349 xdr_inline_pages(&req->rq_rcv_buf, replen,
350 args->pages, args->pgbase, count);
351 req->rq_rcv_buf.flags |= XDRBUF_READ;
352 return 0;
356 * Write arguments. Splice the buffer to be written into the iovec.
358 static int
359 nfs3_xdr_writeargs(struct rpc_rqst *req, __be32 *p, struct nfs_writeargs *args)
361 struct xdr_buf *sndbuf = &req->rq_snd_buf;
362 u32 count = args->count;
364 p = xdr_encode_fhandle(p, args->fh);
365 p = xdr_encode_hyper(p, args->offset);
366 *p++ = htonl(count);
367 *p++ = htonl(args->stable);
368 *p++ = htonl(count);
369 sndbuf->len = xdr_adjust_iovec(sndbuf->head, p);
371 /* Copy the page array */
372 xdr_encode_pages(sndbuf, args->pages, args->pgbase, count);
373 sndbuf->flags |= XDRBUF_WRITE;
374 return 0;
378 * Encode CREATE arguments
380 static int
381 nfs3_xdr_createargs(struct rpc_rqst *req, __be32 *p, struct nfs3_createargs *args)
383 p = xdr_encode_fhandle(p, args->fh);
384 p = xdr_encode_array(p, args->name, args->len);
386 *p++ = htonl(args->createmode);
387 if (args->createmode == NFS3_CREATE_EXCLUSIVE) {
388 *p++ = args->verifier[0];
389 *p++ = args->verifier[1];
390 } else
391 p = xdr_encode_sattr(p, args->sattr);
393 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
394 return 0;
398 * Encode MKDIR arguments
400 static int
401 nfs3_xdr_mkdirargs(struct rpc_rqst *req, __be32 *p, struct nfs3_mkdirargs *args)
403 p = xdr_encode_fhandle(p, args->fh);
404 p = xdr_encode_array(p, args->name, args->len);
405 p = xdr_encode_sattr(p, args->sattr);
406 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
407 return 0;
411 * Encode SYMLINK arguments
413 static int
414 nfs3_xdr_symlinkargs(struct rpc_rqst *req, __be32 *p, struct nfs3_symlinkargs *args)
416 p = xdr_encode_fhandle(p, args->fromfh);
417 p = xdr_encode_array(p, args->fromname, args->fromlen);
418 p = xdr_encode_sattr(p, args->sattr);
419 *p++ = htonl(args->pathlen);
420 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
422 /* Copy the page */
423 xdr_encode_pages(&req->rq_snd_buf, args->pages, 0, args->pathlen);
424 return 0;
428 * Encode MKNOD arguments
430 static int
431 nfs3_xdr_mknodargs(struct rpc_rqst *req, __be32 *p, struct nfs3_mknodargs *args)
433 p = xdr_encode_fhandle(p, args->fh);
434 p = xdr_encode_array(p, args->name, args->len);
435 *p++ = htonl(args->type);
436 p = xdr_encode_sattr(p, args->sattr);
437 if (args->type == NF3CHR || args->type == NF3BLK) {
438 *p++ = htonl(MAJOR(args->rdev));
439 *p++ = htonl(MINOR(args->rdev));
442 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
443 return 0;
447 * Encode RENAME arguments
449 static int
450 nfs3_xdr_renameargs(struct rpc_rqst *req, __be32 *p, struct nfs3_renameargs *args)
452 p = xdr_encode_fhandle(p, args->fromfh);
453 p = xdr_encode_array(p, args->fromname, args->fromlen);
454 p = xdr_encode_fhandle(p, args->tofh);
455 p = xdr_encode_array(p, args->toname, args->tolen);
456 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
457 return 0;
461 * Encode LINK arguments
463 static int
464 nfs3_xdr_linkargs(struct rpc_rqst *req, __be32 *p, struct nfs3_linkargs *args)
466 p = xdr_encode_fhandle(p, args->fromfh);
467 p = xdr_encode_fhandle(p, args->tofh);
468 p = xdr_encode_array(p, args->toname, args->tolen);
469 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
470 return 0;
474 * Encode arguments to readdir call
476 static int
477 nfs3_xdr_readdirargs(struct rpc_rqst *req, __be32 *p, struct nfs3_readdirargs *args)
479 struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth;
480 unsigned int replen;
481 u32 count = args->count;
483 p = xdr_encode_fhandle(p, args->fh);
484 p = xdr_encode_hyper(p, args->cookie);
485 *p++ = args->verf[0];
486 *p++ = args->verf[1];
487 if (args->plus) {
488 /* readdirplus: need dircount + buffer size.
489 * We just make sure we make dircount big enough */
490 *p++ = htonl(count >> 3);
492 *p++ = htonl(count);
493 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
495 /* Inline the page array */
496 replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS3_readdirres_sz) << 2;
497 xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, 0, count);
498 return 0;
502 * Decode the result of a readdir call.
503 * We just check for syntactical correctness.
505 static int
506 nfs3_xdr_readdirres(struct rpc_rqst *req, __be32 *p, struct nfs3_readdirres *res)
508 struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
509 struct kvec *iov = rcvbuf->head;
510 struct page **page;
511 size_t hdrlen;
512 u32 len, recvd, pglen;
513 int status, nr = 0;
514 __be32 *entry, *end, *kaddr;
516 status = ntohl(*p++);
517 /* Decode post_op_attrs */
518 p = xdr_decode_post_op_attr(p, res->dir_attr);
519 if (status)
520 return nfs_stat_to_errno(status);
521 /* Decode verifier cookie */
522 if (res->verf) {
523 res->verf[0] = *p++;
524 res->verf[1] = *p++;
525 } else {
526 p += 2;
529 hdrlen = (u8 *) p - (u8 *) iov->iov_base;
530 if (iov->iov_len < hdrlen) {
531 dprintk("NFS: READDIR reply header overflowed:"
532 "length %Zu > %Zu\n", hdrlen, iov->iov_len);
533 return -errno_NFSERR_IO;
534 } else if (iov->iov_len != hdrlen) {
535 dprintk("NFS: READDIR header is short. iovec will be shifted.\n");
536 xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen);
539 pglen = rcvbuf->page_len;
540 recvd = rcvbuf->len - hdrlen;
541 if (pglen > recvd)
542 pglen = recvd;
543 page = rcvbuf->pages;
544 kaddr = p = kmap_atomic(*page, KM_USER0);
545 end = (__be32 *)((char *)p + pglen);
546 entry = p;
548 /* Make sure the packet actually has a value_follows and EOF entry */
549 if ((entry + 1) > end)
550 goto short_pkt;
552 for (; *p++; nr++) {
553 if (p + 3 > end)
554 goto short_pkt;
555 p += 2; /* inode # */
556 len = ntohl(*p++); /* string length */
557 p += XDR_QUADLEN(len) + 2; /* name + cookie */
558 if (len > NFS3_MAXNAMLEN) {
559 dprintk("NFS: giant filename in readdir (len 0x%x)!\n",
560 len);
561 goto err_unmap;
564 if (res->plus) {
565 /* post_op_attr */
566 if (p + 2 > end)
567 goto short_pkt;
568 if (*p++) {
569 p += 21;
570 if (p + 1 > end)
571 goto short_pkt;
573 /* post_op_fh3 */
574 if (*p++) {
575 if (p + 1 > end)
576 goto short_pkt;
577 len = ntohl(*p++);
578 if (len > NFS3_FHSIZE) {
579 dprintk("NFS: giant filehandle in "
580 "readdir (len 0x%x)!\n", len);
581 goto err_unmap;
583 p += XDR_QUADLEN(len);
587 if (p + 2 > end)
588 goto short_pkt;
589 entry = p;
593 * Apparently some server sends responses that are a valid size, but
594 * contain no entries, and have value_follows==0 and EOF==0. For
595 * those, just set the EOF marker.
597 if (!nr && entry[1] == 0) {
598 dprintk("NFS: readdir reply truncated!\n");
599 entry[1] = 1;
601 out:
602 kunmap_atomic(kaddr, KM_USER0);
603 return nr;
604 short_pkt:
606 * When we get a short packet there are 2 possibilities. We can
607 * return an error, or fix up the response to look like a valid
608 * response and return what we have so far. If there are no
609 * entries and the packet was short, then return -EIO. If there
610 * are valid entries in the response, return them and pretend that
611 * the call was successful, but incomplete. The caller can retry the
612 * readdir starting at the last cookie.
614 entry[0] = entry[1] = 0;
615 if (!nr)
616 nr = -errno_NFSERR_IO;
617 goto out;
618 err_unmap:
619 nr = -errno_NFSERR_IO;
620 goto out;
623 __be32 *
624 nfs3_decode_dirent(__be32 *p, struct nfs_entry *entry, int plus)
626 struct nfs_entry old = *entry;
628 if (!*p++) {
629 if (!*p)
630 return ERR_PTR(-EAGAIN);
631 entry->eof = 1;
632 return ERR_PTR(-EBADCOOKIE);
635 p = xdr_decode_hyper(p, &entry->ino);
636 entry->len = ntohl(*p++);
637 entry->name = (const char *) p;
638 p += XDR_QUADLEN(entry->len);
639 entry->prev_cookie = entry->cookie;
640 p = xdr_decode_hyper(p, &entry->cookie);
642 if (plus) {
643 entry->fattr->valid = 0;
644 p = xdr_decode_post_op_attr(p, entry->fattr);
645 /* In fact, a post_op_fh3: */
646 if (*p++) {
647 p = xdr_decode_fhandle(p, entry->fh);
648 /* Ugh -- server reply was truncated */
649 if (p == NULL) {
650 dprintk("NFS: FH truncated\n");
651 *entry = old;
652 return ERR_PTR(-EAGAIN);
654 } else
655 memset((u8*)(entry->fh), 0, sizeof(*entry->fh));
658 entry->eof = !p[0] && p[1];
659 return p;
663 * Encode COMMIT arguments
665 static int
666 nfs3_xdr_commitargs(struct rpc_rqst *req, __be32 *p, struct nfs_writeargs *args)
668 p = xdr_encode_fhandle(p, args->fh);
669 p = xdr_encode_hyper(p, args->offset);
670 *p++ = htonl(args->count);
671 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
672 return 0;
675 #ifdef CONFIG_NFS_V3_ACL
677 * Encode GETACL arguments
679 static int
680 nfs3_xdr_getaclargs(struct rpc_rqst *req, __be32 *p,
681 struct nfs3_getaclargs *args)
683 struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth;
684 unsigned int replen;
686 p = xdr_encode_fhandle(p, args->fh);
687 *p++ = htonl(args->mask);
688 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
690 if (args->mask & (NFS_ACL | NFS_DFACL)) {
691 /* Inline the page array */
692 replen = (RPC_REPHDRSIZE + auth->au_rslack +
693 ACL3_getaclres_sz) << 2;
694 xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, 0,
695 NFSACL_MAXPAGES << PAGE_SHIFT);
697 return 0;
701 * Encode SETACL arguments
703 static int
704 nfs3_xdr_setaclargs(struct rpc_rqst *req, __be32 *p,
705 struct nfs3_setaclargs *args)
707 struct xdr_buf *buf = &req->rq_snd_buf;
708 unsigned int base;
709 int err;
711 p = xdr_encode_fhandle(p, NFS_FH(args->inode));
712 *p++ = htonl(args->mask);
713 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
714 base = req->rq_slen;
716 if (args->npages != 0)
717 xdr_encode_pages(buf, args->pages, 0, args->len);
718 else
719 req->rq_slen = xdr_adjust_iovec(req->rq_svec,
720 p + XDR_QUADLEN(args->len));
722 err = nfsacl_encode(buf, base, args->inode,
723 (args->mask & NFS_ACL) ?
724 args->acl_access : NULL, 1, 0);
725 if (err > 0)
726 err = nfsacl_encode(buf, base + err, args->inode,
727 (args->mask & NFS_DFACL) ?
728 args->acl_default : NULL, 1,
729 NFS_ACL_DEFAULT);
730 return (err > 0) ? 0 : err;
732 #endif /* CONFIG_NFS_V3_ACL */
735 * NFS XDR decode functions
739 * Decode attrstat reply.
741 static int
742 nfs3_xdr_attrstat(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
744 int status;
746 if ((status = ntohl(*p++)))
747 return nfs_stat_to_errno(status);
748 xdr_decode_fattr(p, fattr);
749 return 0;
753 * Decode status+wcc_data reply
754 * SATTR, REMOVE, RMDIR
756 static int
757 nfs3_xdr_wccstat(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
759 int status;
761 if ((status = ntohl(*p++)))
762 status = nfs_stat_to_errno(status);
763 xdr_decode_wcc_data(p, fattr);
764 return status;
767 static int
768 nfs3_xdr_removeres(struct rpc_rqst *req, __be32 *p, struct nfs_removeres *res)
770 return nfs3_xdr_wccstat(req, p, &res->dir_attr);
774 * Decode LOOKUP reply
776 static int
777 nfs3_xdr_lookupres(struct rpc_rqst *req, __be32 *p, struct nfs3_diropres *res)
779 int status;
781 if ((status = ntohl(*p++))) {
782 status = nfs_stat_to_errno(status);
783 } else {
784 if (!(p = xdr_decode_fhandle(p, res->fh)))
785 return -errno_NFSERR_IO;
786 p = xdr_decode_post_op_attr(p, res->fattr);
788 xdr_decode_post_op_attr(p, res->dir_attr);
789 return status;
793 * Decode ACCESS reply
795 static int
796 nfs3_xdr_accessres(struct rpc_rqst *req, __be32 *p, struct nfs3_accessres *res)
798 int status = ntohl(*p++);
800 p = xdr_decode_post_op_attr(p, res->fattr);
801 if (status)
802 return nfs_stat_to_errno(status);
803 res->access = ntohl(*p++);
804 return 0;
807 static int
808 nfs3_xdr_readlinkargs(struct rpc_rqst *req, __be32 *p, struct nfs3_readlinkargs *args)
810 struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth;
811 unsigned int replen;
813 p = xdr_encode_fhandle(p, args->fh);
814 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
816 /* Inline the page array */
817 replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS3_readlinkres_sz) << 2;
818 xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, args->pgbase, args->pglen);
819 return 0;
823 * Decode READLINK reply
825 static int
826 nfs3_xdr_readlinkres(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
828 struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
829 struct kvec *iov = rcvbuf->head;
830 size_t hdrlen;
831 u32 len, recvd;
832 char *kaddr;
833 int status;
835 status = ntohl(*p++);
836 p = xdr_decode_post_op_attr(p, fattr);
838 if (status != 0)
839 return nfs_stat_to_errno(status);
841 /* Convert length of symlink */
842 len = ntohl(*p++);
843 if (len >= rcvbuf->page_len) {
844 dprintk("nfs: server returned giant symlink!\n");
845 return -ENAMETOOLONG;
848 hdrlen = (u8 *) p - (u8 *) iov->iov_base;
849 if (iov->iov_len < hdrlen) {
850 dprintk("NFS: READLINK reply header overflowed:"
851 "length %Zu > %Zu\n", hdrlen, iov->iov_len);
852 return -errno_NFSERR_IO;
853 } else if (iov->iov_len != hdrlen) {
854 dprintk("NFS: READLINK header is short. "
855 "iovec will be shifted.\n");
856 xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen);
858 recvd = req->rq_rcv_buf.len - hdrlen;
859 if (recvd < len) {
860 dprintk("NFS: server cheating in readlink reply: "
861 "count %u > recvd %u\n", len, recvd);
862 return -EIO;
865 /* NULL terminate the string we got */
866 kaddr = (char*)kmap_atomic(rcvbuf->pages[0], KM_USER0);
867 kaddr[len+rcvbuf->page_base] = '\0';
868 kunmap_atomic(kaddr, KM_USER0);
869 return 0;
873 * Decode READ reply
875 static int
876 nfs3_xdr_readres(struct rpc_rqst *req, __be32 *p, struct nfs_readres *res)
878 struct kvec *iov = req->rq_rcv_buf.head;
879 size_t hdrlen;
880 u32 count, ocount, recvd;
881 int status;
883 status = ntohl(*p++);
884 p = xdr_decode_post_op_attr(p, res->fattr);
886 if (status != 0)
887 return nfs_stat_to_errno(status);
889 /* Decode reply count and EOF flag. NFSv3 is somewhat redundant
890 * in that it puts the count both in the res struct and in the
891 * opaque data count. */
892 count = ntohl(*p++);
893 res->eof = ntohl(*p++);
894 ocount = ntohl(*p++);
896 if (ocount != count) {
897 dprintk("NFS: READ count doesn't match RPC opaque count.\n");
898 return -errno_NFSERR_IO;
901 hdrlen = (u8 *) p - (u8 *) iov->iov_base;
902 if (iov->iov_len < hdrlen) {
903 dprintk("NFS: READ reply header overflowed:"
904 "length %Zu > %Zu\n", hdrlen, iov->iov_len);
905 return -errno_NFSERR_IO;
906 } else if (iov->iov_len != hdrlen) {
907 dprintk("NFS: READ header is short. iovec will be shifted.\n");
908 xdr_shift_buf(&req->rq_rcv_buf, iov->iov_len - hdrlen);
911 recvd = req->rq_rcv_buf.len - hdrlen;
912 if (count > recvd) {
913 dprintk("NFS: server cheating in read reply: "
914 "count %u > recvd %u\n", count, recvd);
915 count = recvd;
916 res->eof = 0;
919 if (count < res->count)
920 res->count = count;
922 return count;
926 * Decode WRITE response
928 static int
929 nfs3_xdr_writeres(struct rpc_rqst *req, __be32 *p, struct nfs_writeres *res)
931 int status;
933 status = ntohl(*p++);
934 p = xdr_decode_wcc_data(p, res->fattr);
936 if (status != 0)
937 return nfs_stat_to_errno(status);
939 res->count = ntohl(*p++);
940 res->verf->committed = (enum nfs3_stable_how)ntohl(*p++);
941 res->verf->verifier[0] = *p++;
942 res->verf->verifier[1] = *p++;
944 return res->count;
948 * Decode a CREATE response
950 static int
951 nfs3_xdr_createres(struct rpc_rqst *req, __be32 *p, struct nfs3_diropres *res)
953 int status;
955 status = ntohl(*p++);
956 if (status == 0) {
957 if (*p++) {
958 if (!(p = xdr_decode_fhandle(p, res->fh)))
959 return -errno_NFSERR_IO;
960 p = xdr_decode_post_op_attr(p, res->fattr);
961 } else {
962 memset(res->fh, 0, sizeof(*res->fh));
963 /* Do decode post_op_attr but set it to NULL */
964 p = xdr_decode_post_op_attr(p, res->fattr);
965 res->fattr->valid = 0;
967 } else {
968 status = nfs_stat_to_errno(status);
970 p = xdr_decode_wcc_data(p, res->dir_attr);
971 return status;
975 * Decode RENAME reply
977 static int
978 nfs3_xdr_renameres(struct rpc_rqst *req, __be32 *p, struct nfs3_renameres *res)
980 int status;
982 if ((status = ntohl(*p++)) != 0)
983 status = nfs_stat_to_errno(status);
984 p = xdr_decode_wcc_data(p, res->fromattr);
985 p = xdr_decode_wcc_data(p, res->toattr);
986 return status;
990 * Decode LINK reply
992 static int
993 nfs3_xdr_linkres(struct rpc_rqst *req, __be32 *p, struct nfs3_linkres *res)
995 int status;
997 if ((status = ntohl(*p++)) != 0)
998 status = nfs_stat_to_errno(status);
999 p = xdr_decode_post_op_attr(p, res->fattr);
1000 p = xdr_decode_wcc_data(p, res->dir_attr);
1001 return status;
1005 * Decode FSSTAT reply
1007 static int
1008 nfs3_xdr_fsstatres(struct rpc_rqst *req, __be32 *p, struct nfs_fsstat *res)
1010 int status;
1012 status = ntohl(*p++);
1014 p = xdr_decode_post_op_attr(p, res->fattr);
1015 if (status != 0)
1016 return nfs_stat_to_errno(status);
1018 p = xdr_decode_hyper(p, &res->tbytes);
1019 p = xdr_decode_hyper(p, &res->fbytes);
1020 p = xdr_decode_hyper(p, &res->abytes);
1021 p = xdr_decode_hyper(p, &res->tfiles);
1022 p = xdr_decode_hyper(p, &res->ffiles);
1023 p = xdr_decode_hyper(p, &res->afiles);
1025 /* ignore invarsec */
1026 return 0;
1030 * Decode FSINFO reply
1032 static int
1033 nfs3_xdr_fsinfores(struct rpc_rqst *req, __be32 *p, struct nfs_fsinfo *res)
1035 int status;
1037 status = ntohl(*p++);
1039 p = xdr_decode_post_op_attr(p, res->fattr);
1040 if (status != 0)
1041 return nfs_stat_to_errno(status);
1043 res->rtmax = ntohl(*p++);
1044 res->rtpref = ntohl(*p++);
1045 res->rtmult = ntohl(*p++);
1046 res->wtmax = ntohl(*p++);
1047 res->wtpref = ntohl(*p++);
1048 res->wtmult = ntohl(*p++);
1049 res->dtpref = ntohl(*p++);
1050 p = xdr_decode_hyper(p, &res->maxfilesize);
1052 /* ignore time_delta and properties */
1053 res->lease_time = 0;
1054 return 0;
1058 * Decode PATHCONF reply
1060 static int
1061 nfs3_xdr_pathconfres(struct rpc_rqst *req, __be32 *p, struct nfs_pathconf *res)
1063 int status;
1065 status = ntohl(*p++);
1067 p = xdr_decode_post_op_attr(p, res->fattr);
1068 if (status != 0)
1069 return nfs_stat_to_errno(status);
1070 res->max_link = ntohl(*p++);
1071 res->max_namelen = ntohl(*p++);
1073 /* ignore remaining fields */
1074 return 0;
1078 * Decode COMMIT reply
1080 static int
1081 nfs3_xdr_commitres(struct rpc_rqst *req, __be32 *p, struct nfs_writeres *res)
1083 int status;
1085 status = ntohl(*p++);
1086 p = xdr_decode_wcc_data(p, res->fattr);
1087 if (status != 0)
1088 return nfs_stat_to_errno(status);
1090 res->verf->verifier[0] = *p++;
1091 res->verf->verifier[1] = *p++;
1092 return 0;
1095 #ifdef CONFIG_NFS_V3_ACL
1097 * Decode GETACL reply
1099 static int
1100 nfs3_xdr_getaclres(struct rpc_rqst *req, __be32 *p,
1101 struct nfs3_getaclres *res)
1103 struct xdr_buf *buf = &req->rq_rcv_buf;
1104 int status = ntohl(*p++);
1105 struct posix_acl **acl;
1106 unsigned int *aclcnt;
1107 int err, base;
1109 if (status != 0)
1110 return nfs_stat_to_errno(status);
1111 p = xdr_decode_post_op_attr(p, res->fattr);
1112 res->mask = ntohl(*p++);
1113 if (res->mask & ~(NFS_ACL|NFS_ACLCNT|NFS_DFACL|NFS_DFACLCNT))
1114 return -EINVAL;
1115 base = (char *)p - (char *)req->rq_rcv_buf.head->iov_base;
1117 acl = (res->mask & NFS_ACL) ? &res->acl_access : NULL;
1118 aclcnt = (res->mask & NFS_ACLCNT) ? &res->acl_access_count : NULL;
1119 err = nfsacl_decode(buf, base, aclcnt, acl);
1121 acl = (res->mask & NFS_DFACL) ? &res->acl_default : NULL;
1122 aclcnt = (res->mask & NFS_DFACLCNT) ? &res->acl_default_count : NULL;
1123 if (err > 0)
1124 err = nfsacl_decode(buf, base + err, aclcnt, acl);
1125 return (err > 0) ? 0 : err;
1129 * Decode setacl reply.
1131 static int
1132 nfs3_xdr_setaclres(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
1134 int status = ntohl(*p++);
1136 if (status)
1137 return nfs_stat_to_errno(status);
1138 xdr_decode_post_op_attr(p, fattr);
1139 return 0;
1141 #endif /* CONFIG_NFS_V3_ACL */
1143 #define PROC(proc, argtype, restype, timer) \
1144 [NFS3PROC_##proc] = { \
1145 .p_proc = NFS3PROC_##proc, \
1146 .p_encode = (kxdrproc_t) nfs3_xdr_##argtype, \
1147 .p_decode = (kxdrproc_t) nfs3_xdr_##restype, \
1148 .p_arglen = NFS3_##argtype##_sz, \
1149 .p_replen = NFS3_##restype##_sz, \
1150 .p_timer = timer, \
1151 .p_statidx = NFS3PROC_##proc, \
1152 .p_name = #proc, \
1155 struct rpc_procinfo nfs3_procedures[] = {
1156 PROC(GETATTR, fhandle, attrstat, 1),
1157 PROC(SETATTR, sattrargs, wccstat, 0),
1158 PROC(LOOKUP, diropargs, lookupres, 2),
1159 PROC(ACCESS, accessargs, accessres, 1),
1160 PROC(READLINK, readlinkargs, readlinkres, 3),
1161 PROC(READ, readargs, readres, 3),
1162 PROC(WRITE, writeargs, writeres, 4),
1163 PROC(CREATE, createargs, createres, 0),
1164 PROC(MKDIR, mkdirargs, createres, 0),
1165 PROC(SYMLINK, symlinkargs, createres, 0),
1166 PROC(MKNOD, mknodargs, createres, 0),
1167 PROC(REMOVE, removeargs, removeres, 0),
1168 PROC(RMDIR, diropargs, wccstat, 0),
1169 PROC(RENAME, renameargs, renameres, 0),
1170 PROC(LINK, linkargs, linkres, 0),
1171 PROC(READDIR, readdirargs, readdirres, 3),
1172 PROC(READDIRPLUS, readdirargs, readdirres, 3),
1173 PROC(FSSTAT, fhandle, fsstatres, 0),
1174 PROC(FSINFO, fhandle, fsinfores, 0),
1175 PROC(PATHCONF, fhandle, pathconfres, 0),
1176 PROC(COMMIT, commitargs, commitres, 5),
1179 struct rpc_version nfs_version3 = {
1180 .number = 3,
1181 .nrprocs = ARRAY_SIZE(nfs3_procedures),
1182 .procs = nfs3_procedures
1185 #ifdef CONFIG_NFS_V3_ACL
1186 static struct rpc_procinfo nfs3_acl_procedures[] = {
1187 [ACLPROC3_GETACL] = {
1188 .p_proc = ACLPROC3_GETACL,
1189 .p_encode = (kxdrproc_t) nfs3_xdr_getaclargs,
1190 .p_decode = (kxdrproc_t) nfs3_xdr_getaclres,
1191 .p_arglen = ACL3_getaclargs_sz,
1192 .p_replen = ACL3_getaclres_sz,
1193 .p_timer = 1,
1194 .p_name = "GETACL",
1196 [ACLPROC3_SETACL] = {
1197 .p_proc = ACLPROC3_SETACL,
1198 .p_encode = (kxdrproc_t) nfs3_xdr_setaclargs,
1199 .p_decode = (kxdrproc_t) nfs3_xdr_setaclres,
1200 .p_arglen = ACL3_setaclargs_sz,
1201 .p_replen = ACL3_setaclres_sz,
1202 .p_timer = 0,
1203 .p_name = "SETACL",
1207 struct rpc_version nfsacl_version3 = {
1208 .number = 3,
1209 .nrprocs = sizeof(nfs3_acl_procedures)/
1210 sizeof(nfs3_acl_procedures[0]),
1211 .procs = nfs3_acl_procedures,
1213 #endif /* CONFIG_NFS_V3_ACL */