2 * linux/fs/nfs/nfs3xdr.c
4 * XDR functions to encode/decode NFSv3 RPC arguments and results.
6 * Copyright (C) 1996, 1997 Olaf Kirch
9 #include <linux/param.h>
10 #include <linux/time.h>
12 #include <linux/slab.h>
13 #include <linux/utsname.h>
14 #include <linux/errno.h>
15 #include <linux/string.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>
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_accessargs_sz (NFS3_fh_sz+1)
54 #define NFS3_readlinkargs_sz (NFS3_fh_sz)
55 #define NFS3_readargs_sz (NFS3_fh_sz+3)
56 #define NFS3_writeargs_sz (NFS3_fh_sz+5)
57 #define NFS3_createargs_sz (NFS3_diropargs_sz+NFS3_sattr_sz)
58 #define NFS3_mkdirargs_sz (NFS3_diropargs_sz+NFS3_sattr_sz)
59 #define NFS3_symlinkargs_sz (NFS3_diropargs_sz+1+NFS3_sattr_sz)
60 #define NFS3_mknodargs_sz (NFS3_diropargs_sz+2+NFS3_sattr_sz)
61 #define NFS3_renameargs_sz (NFS3_diropargs_sz+NFS3_diropargs_sz)
62 #define NFS3_linkargs_sz (NFS3_fh_sz+NFS3_diropargs_sz)
63 #define NFS3_readdirargs_sz (NFS3_fh_sz+2)
64 #define NFS3_commitargs_sz (NFS3_fh_sz+3)
66 #define NFS3_attrstat_sz (1+NFS3_fattr_sz)
67 #define NFS3_wccstat_sz (1+NFS3_wcc_data_sz)
68 #define NFS3_lookupres_sz (1+NFS3_fh_sz+(2 * NFS3_post_op_attr_sz))
69 #define NFS3_accessres_sz (1+NFS3_post_op_attr_sz+1)
70 #define NFS3_readlinkres_sz (1+NFS3_post_op_attr_sz+1)
71 #define NFS3_readres_sz (1+NFS3_post_op_attr_sz+3)
72 #define NFS3_writeres_sz (1+NFS3_wcc_data_sz+4)
73 #define NFS3_createres_sz (1+NFS3_fh_sz+NFS3_post_op_attr_sz+NFS3_wcc_data_sz)
74 #define NFS3_renameres_sz (1+(2 * NFS3_wcc_data_sz))
75 #define NFS3_linkres_sz (1+NFS3_post_op_attr_sz+NFS3_wcc_data_sz)
76 #define NFS3_readdirres_sz (1+NFS3_post_op_attr_sz+2)
77 #define NFS3_fsstatres_sz (1+NFS3_post_op_attr_sz+13)
78 #define NFS3_fsinfores_sz (1+NFS3_post_op_attr_sz+12)
79 #define NFS3_pathconfres_sz (1+NFS3_post_op_attr_sz+6)
80 #define NFS3_commitres_sz (1+NFS3_wcc_data_sz+2)
82 #define ACL3_getaclargs_sz (NFS3_fh_sz+1)
83 #define ACL3_setaclargs_sz (NFS3_fh_sz+1+2*(2+5*3))
84 #define ACL3_getaclres_sz (1+NFS3_post_op_attr_sz+1+2*(2+5*3))
85 #define ACL3_setaclres_sz (1+NFS3_post_op_attr_sz)
88 * Map file type to S_IFMT bits
92 unsigned int nfs2type;
100 { S_IFSOCK, NFSOCK },
106 * Common NFS XDR functions as inlines
108 static inline __be32 *
109 xdr_encode_fhandle(__be32 *p, struct nfs_fh *fh)
111 return xdr_encode_array(p, fh->data, fh->size);
114 static inline __be32 *
115 xdr_decode_fhandle(__be32 *p, struct nfs_fh *fh)
117 if ((fh->size = ntohl(*p++)) <= NFS3_FHSIZE) {
118 memcpy(fh->data, p, fh->size);
119 return p + XDR_QUADLEN(fh->size);
125 * Encode/decode time.
127 static inline __be32 *
128 xdr_encode_time3(__be32 *p, struct timespec *timep)
130 *p++ = htonl(timep->tv_sec);
131 *p++ = htonl(timep->tv_nsec);
135 static inline __be32 *
136 xdr_decode_time3(__be32 *p, struct timespec *timep)
138 timep->tv_sec = ntohl(*p++);
139 timep->tv_nsec = ntohl(*p++);
144 xdr_decode_fattr(__be32 *p, struct nfs_fattr *fattr)
146 unsigned int type, major, minor;
152 fmode = nfs_type2fmt[type].mode;
153 fattr->type = nfs_type2fmt[type].nfs2type;
154 fattr->mode = (ntohl(*p++) & ~S_IFMT) | fmode;
155 fattr->nlink = ntohl(*p++);
156 fattr->uid = ntohl(*p++);
157 fattr->gid = ntohl(*p++);
158 p = xdr_decode_hyper(p, &fattr->size);
159 p = xdr_decode_hyper(p, &fattr->du.nfs3.used);
161 /* Turn remote device info into Linux-specific dev_t */
164 fattr->rdev = MKDEV(major, minor);
165 if (MAJOR(fattr->rdev) != major || MINOR(fattr->rdev) != minor)
168 p = xdr_decode_hyper(p, &fattr->fsid.major);
169 fattr->fsid.minor = 0;
170 p = xdr_decode_hyper(p, &fattr->fileid);
171 p = xdr_decode_time3(p, &fattr->atime);
172 p = xdr_decode_time3(p, &fattr->mtime);
173 p = xdr_decode_time3(p, &fattr->ctime);
175 /* Update the mode bits */
176 fattr->valid |= (NFS_ATTR_FATTR | NFS_ATTR_FATTR_V3);
180 static inline __be32 *
181 xdr_encode_sattr(__be32 *p, struct iattr *attr)
183 if (attr->ia_valid & ATTR_MODE) {
185 *p++ = htonl(attr->ia_mode & S_IALLUGO);
189 if (attr->ia_valid & ATTR_UID) {
191 *p++ = htonl(attr->ia_uid);
195 if (attr->ia_valid & ATTR_GID) {
197 *p++ = htonl(attr->ia_gid);
201 if (attr->ia_valid & ATTR_SIZE) {
203 p = xdr_encode_hyper(p, (__u64) attr->ia_size);
207 if (attr->ia_valid & ATTR_ATIME_SET) {
209 p = xdr_encode_time3(p, &attr->ia_atime);
210 } else if (attr->ia_valid & ATTR_ATIME) {
215 if (attr->ia_valid & ATTR_MTIME_SET) {
217 p = xdr_encode_time3(p, &attr->ia_mtime);
218 } else if (attr->ia_valid & ATTR_MTIME) {
226 static inline __be32 *
227 xdr_decode_wcc_attr(__be32 *p, struct nfs_fattr *fattr)
229 p = xdr_decode_hyper(p, &fattr->pre_size);
230 p = xdr_decode_time3(p, &fattr->pre_mtime);
231 p = xdr_decode_time3(p, &fattr->pre_ctime);
232 fattr->valid |= NFS_ATTR_WCC;
236 static inline __be32 *
237 xdr_decode_post_op_attr(__be32 *p, struct nfs_fattr *fattr)
240 p = xdr_decode_fattr(p, fattr);
244 static inline __be32 *
245 xdr_decode_pre_op_attr(__be32 *p, struct nfs_fattr *fattr)
248 return xdr_decode_wcc_attr(p, fattr);
253 static inline __be32 *
254 xdr_decode_wcc_data(__be32 *p, struct nfs_fattr *fattr)
256 p = xdr_decode_pre_op_attr(p, fattr);
257 return xdr_decode_post_op_attr(p, fattr);
261 * NFS encode functions
265 * Encode file handle argument
268 nfs3_xdr_fhandle(struct rpc_rqst *req, __be32 *p, struct nfs_fh *fh)
270 p = xdr_encode_fhandle(p, fh);
271 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
276 * Encode SETATTR arguments
279 nfs3_xdr_sattrargs(struct rpc_rqst *req, __be32 *p, struct nfs3_sattrargs *args)
281 p = xdr_encode_fhandle(p, args->fh);
282 p = xdr_encode_sattr(p, args->sattr);
283 *p++ = htonl(args->guard);
285 p = xdr_encode_time3(p, &args->guardtime);
286 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
291 * Encode directory ops argument
294 nfs3_xdr_diropargs(struct rpc_rqst *req, __be32 *p, struct nfs3_diropargs *args)
296 p = xdr_encode_fhandle(p, args->fh);
297 p = xdr_encode_array(p, args->name, args->len);
298 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
303 * Encode access() argument
306 nfs3_xdr_accessargs(struct rpc_rqst *req, __be32 *p, struct nfs3_accessargs *args)
308 p = xdr_encode_fhandle(p, args->fh);
309 *p++ = htonl(args->access);
310 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
315 * Arguments to a READ call. Since we read data directly into the page
316 * cache, we also set up the reply iovec here so that iov[1] points
317 * exactly to the page we want to fetch.
320 nfs3_xdr_readargs(struct rpc_rqst *req, __be32 *p, struct nfs_readargs *args)
322 struct rpc_auth *auth = req->rq_task->tk_auth;
324 u32 count = args->count;
326 p = xdr_encode_fhandle(p, args->fh);
327 p = xdr_encode_hyper(p, args->offset);
329 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
331 /* Inline the page array */
332 replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS3_readres_sz) << 2;
333 xdr_inline_pages(&req->rq_rcv_buf, replen,
334 args->pages, args->pgbase, count);
339 * Write arguments. Splice the buffer to be written into the iovec.
342 nfs3_xdr_writeargs(struct rpc_rqst *req, __be32 *p, struct nfs_writeargs *args)
344 struct xdr_buf *sndbuf = &req->rq_snd_buf;
345 u32 count = args->count;
347 p = xdr_encode_fhandle(p, args->fh);
348 p = xdr_encode_hyper(p, args->offset);
350 *p++ = htonl(args->stable);
352 sndbuf->len = xdr_adjust_iovec(sndbuf->head, p);
354 /* Copy the page array */
355 xdr_encode_pages(sndbuf, args->pages, args->pgbase, count);
360 * Encode CREATE arguments
363 nfs3_xdr_createargs(struct rpc_rqst *req, __be32 *p, struct nfs3_createargs *args)
365 p = xdr_encode_fhandle(p, args->fh);
366 p = xdr_encode_array(p, args->name, args->len);
368 *p++ = htonl(args->createmode);
369 if (args->createmode == NFS3_CREATE_EXCLUSIVE) {
370 *p++ = args->verifier[0];
371 *p++ = args->verifier[1];
373 p = xdr_encode_sattr(p, args->sattr);
375 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
380 * Encode MKDIR arguments
383 nfs3_xdr_mkdirargs(struct rpc_rqst *req, __be32 *p, struct nfs3_mkdirargs *args)
385 p = xdr_encode_fhandle(p, args->fh);
386 p = xdr_encode_array(p, args->name, args->len);
387 p = xdr_encode_sattr(p, args->sattr);
388 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
393 * Encode SYMLINK arguments
396 nfs3_xdr_symlinkargs(struct rpc_rqst *req, __be32 *p, struct nfs3_symlinkargs *args)
398 p = xdr_encode_fhandle(p, args->fromfh);
399 p = xdr_encode_array(p, args->fromname, args->fromlen);
400 p = xdr_encode_sattr(p, args->sattr);
401 *p++ = htonl(args->pathlen);
402 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
405 xdr_encode_pages(&req->rq_snd_buf, args->pages, 0, args->pathlen);
410 * Encode MKNOD arguments
413 nfs3_xdr_mknodargs(struct rpc_rqst *req, __be32 *p, struct nfs3_mknodargs *args)
415 p = xdr_encode_fhandle(p, args->fh);
416 p = xdr_encode_array(p, args->name, args->len);
417 *p++ = htonl(args->type);
418 p = xdr_encode_sattr(p, args->sattr);
419 if (args->type == NF3CHR || args->type == NF3BLK) {
420 *p++ = htonl(MAJOR(args->rdev));
421 *p++ = htonl(MINOR(args->rdev));
424 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
429 * Encode RENAME arguments
432 nfs3_xdr_renameargs(struct rpc_rqst *req, __be32 *p, struct nfs3_renameargs *args)
434 p = xdr_encode_fhandle(p, args->fromfh);
435 p = xdr_encode_array(p, args->fromname, args->fromlen);
436 p = xdr_encode_fhandle(p, args->tofh);
437 p = xdr_encode_array(p, args->toname, args->tolen);
438 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
443 * Encode LINK arguments
446 nfs3_xdr_linkargs(struct rpc_rqst *req, __be32 *p, struct nfs3_linkargs *args)
448 p = xdr_encode_fhandle(p, args->fromfh);
449 p = xdr_encode_fhandle(p, args->tofh);
450 p = xdr_encode_array(p, args->toname, args->tolen);
451 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
456 * Encode arguments to readdir call
459 nfs3_xdr_readdirargs(struct rpc_rqst *req, __be32 *p, struct nfs3_readdirargs *args)
461 struct rpc_auth *auth = req->rq_task->tk_auth;
463 u32 count = args->count;
465 p = xdr_encode_fhandle(p, args->fh);
466 p = xdr_encode_hyper(p, args->cookie);
467 *p++ = args->verf[0];
468 *p++ = args->verf[1];
470 /* readdirplus: need dircount + buffer size.
471 * We just make sure we make dircount big enough */
472 *p++ = htonl(count >> 3);
475 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
477 /* Inline the page array */
478 replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS3_readdirres_sz) << 2;
479 xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, 0, count);
484 * Decode the result of a readdir call.
485 * We just check for syntactical correctness.
488 nfs3_xdr_readdirres(struct rpc_rqst *req, __be32 *p, struct nfs3_readdirres *res)
490 struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
491 struct kvec *iov = rcvbuf->head;
495 unsigned int len, pglen;
496 __be32 *entry, *end, *kaddr;
498 status = ntohl(*p++);
499 /* Decode post_op_attrs */
500 p = xdr_decode_post_op_attr(p, res->dir_attr);
502 return -nfs_stat_to_errno(status);
503 /* Decode verifier cookie */
511 hdrlen = (u8 *) p - (u8 *) iov->iov_base;
512 if (iov->iov_len < hdrlen) {
513 printk(KERN_WARNING "NFS: READDIR reply header overflowed:"
514 "length %d > %Zu\n", hdrlen, iov->iov_len);
515 return -errno_NFSERR_IO;
516 } else if (iov->iov_len != hdrlen) {
517 dprintk("NFS: READDIR header is short. iovec will be shifted.\n");
518 xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen);
521 pglen = rcvbuf->page_len;
522 recvd = rcvbuf->len - hdrlen;
525 page = rcvbuf->pages;
526 kaddr = p = kmap_atomic(*page, KM_USER0);
527 end = (__be32 *)((char *)p + pglen);
529 for (nr = 0; *p++; nr++) {
532 p += 2; /* inode # */
533 len = ntohl(*p++); /* string length */
534 p += XDR_QUADLEN(len) + 2; /* name + cookie */
535 if (len > NFS3_MAXNAMLEN) {
536 printk(KERN_WARNING "NFS: giant filename in readdir (len %x)!\n",
555 if (len > NFS3_FHSIZE) {
556 printk(KERN_WARNING "NFS: giant filehandle in "
557 "readdir (len %x)!\n", len);
560 p += XDR_QUADLEN(len);
568 if (!nr && (entry[0] != 0 || entry[1] == 0))
571 kunmap_atomic(kaddr, KM_USER0);
574 entry[0] = entry[1] = 0;
575 /* truncate listing ? */
577 printk(KERN_NOTICE "NFS: readdir reply truncated!\n");
582 nr = -errno_NFSERR_IO;
587 nfs3_decode_dirent(__be32 *p, struct nfs_entry *entry, int plus)
589 struct nfs_entry old = *entry;
593 return ERR_PTR(-EAGAIN);
595 return ERR_PTR(-EBADCOOKIE);
598 p = xdr_decode_hyper(p, &entry->ino);
599 entry->len = ntohl(*p++);
600 entry->name = (const char *) p;
601 p += XDR_QUADLEN(entry->len);
602 entry->prev_cookie = entry->cookie;
603 p = xdr_decode_hyper(p, &entry->cookie);
606 entry->fattr->valid = 0;
607 p = xdr_decode_post_op_attr(p, entry->fattr);
608 /* In fact, a post_op_fh3: */
610 p = xdr_decode_fhandle(p, entry->fh);
611 /* Ugh -- server reply was truncated */
613 dprintk("NFS: FH truncated\n");
615 return ERR_PTR(-EAGAIN);
618 memset((u8*)(entry->fh), 0, sizeof(*entry->fh));
621 entry->eof = !p[0] && p[1];
626 * Encode COMMIT arguments
629 nfs3_xdr_commitargs(struct rpc_rqst *req, __be32 *p, struct nfs_writeargs *args)
631 p = xdr_encode_fhandle(p, args->fh);
632 p = xdr_encode_hyper(p, args->offset);
633 *p++ = htonl(args->count);
634 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
638 #ifdef CONFIG_NFS_V3_ACL
640 * Encode GETACL arguments
643 nfs3_xdr_getaclargs(struct rpc_rqst *req, __be32 *p,
644 struct nfs3_getaclargs *args)
646 struct rpc_auth *auth = req->rq_task->tk_auth;
649 p = xdr_encode_fhandle(p, args->fh);
650 *p++ = htonl(args->mask);
651 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
653 if (args->mask & (NFS_ACL | NFS_DFACL)) {
654 /* Inline the page array */
655 replen = (RPC_REPHDRSIZE + auth->au_rslack +
656 ACL3_getaclres_sz) << 2;
657 xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, 0,
658 NFSACL_MAXPAGES << PAGE_SHIFT);
664 * Encode SETACL arguments
667 nfs3_xdr_setaclargs(struct rpc_rqst *req, __be32 *p,
668 struct nfs3_setaclargs *args)
670 struct xdr_buf *buf = &req->rq_snd_buf;
671 unsigned int base, len_in_head, len = nfsacl_size(
672 (args->mask & NFS_ACL) ? args->acl_access : NULL,
673 (args->mask & NFS_DFACL) ? args->acl_default : NULL);
676 p = xdr_encode_fhandle(p, NFS_FH(args->inode));
677 *p++ = htonl(args->mask);
678 base = (char *)p - (char *)buf->head->iov_base;
679 /* put as much of the acls into head as possible. */
680 len_in_head = min_t(unsigned int, buf->head->iov_len - base, len);
682 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p + (len_in_head >> 2));
684 for (count = 0; (count << PAGE_SHIFT) < len; count++) {
685 args->pages[count] = alloc_page(GFP_KERNEL);
686 if (!args->pages[count]) {
688 __free_page(args->pages[--count]);
692 xdr_encode_pages(buf, args->pages, 0, len);
694 err = nfsacl_encode(buf, base, args->inode,
695 (args->mask & NFS_ACL) ?
696 args->acl_access : NULL, 1, 0);
698 err = nfsacl_encode(buf, base + err, args->inode,
699 (args->mask & NFS_DFACL) ?
700 args->acl_default : NULL, 1,
702 return (err > 0) ? 0 : err;
704 #endif /* CONFIG_NFS_V3_ACL */
707 * NFS XDR decode functions
711 * Decode attrstat reply.
714 nfs3_xdr_attrstat(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
718 if ((status = ntohl(*p++)))
719 return -nfs_stat_to_errno(status);
720 xdr_decode_fattr(p, fattr);
725 * Decode status+wcc_data reply
726 * SATTR, REMOVE, RMDIR
729 nfs3_xdr_wccstat(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
733 if ((status = ntohl(*p++)))
734 status = -nfs_stat_to_errno(status);
735 xdr_decode_wcc_data(p, fattr);
740 * Decode LOOKUP reply
743 nfs3_xdr_lookupres(struct rpc_rqst *req, __be32 *p, struct nfs3_diropres *res)
747 if ((status = ntohl(*p++))) {
748 status = -nfs_stat_to_errno(status);
750 if (!(p = xdr_decode_fhandle(p, res->fh)))
751 return -errno_NFSERR_IO;
752 p = xdr_decode_post_op_attr(p, res->fattr);
754 xdr_decode_post_op_attr(p, res->dir_attr);
759 * Decode ACCESS reply
762 nfs3_xdr_accessres(struct rpc_rqst *req, __be32 *p, struct nfs3_accessres *res)
764 int status = ntohl(*p++);
766 p = xdr_decode_post_op_attr(p, res->fattr);
768 return -nfs_stat_to_errno(status);
769 res->access = ntohl(*p++);
774 nfs3_xdr_readlinkargs(struct rpc_rqst *req, __be32 *p, struct nfs3_readlinkargs *args)
776 struct rpc_auth *auth = req->rq_task->tk_auth;
779 p = xdr_encode_fhandle(p, args->fh);
780 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
782 /* Inline the page array */
783 replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS3_readlinkres_sz) << 2;
784 xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, args->pgbase, args->pglen);
789 * Decode READLINK reply
792 nfs3_xdr_readlinkres(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
794 struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
795 struct kvec *iov = rcvbuf->head;
796 int hdrlen, len, recvd;
800 status = ntohl(*p++);
801 p = xdr_decode_post_op_attr(p, fattr);
804 return -nfs_stat_to_errno(status);
806 /* Convert length of symlink */
808 if (len >= rcvbuf->page_len || len <= 0) {
809 dprintk(KERN_WARNING "nfs: server returned giant symlink!\n");
810 return -ENAMETOOLONG;
813 hdrlen = (u8 *) p - (u8 *) iov->iov_base;
814 if (iov->iov_len < hdrlen) {
815 printk(KERN_WARNING "NFS: READLINK reply header overflowed:"
816 "length %d > %Zu\n", hdrlen, iov->iov_len);
817 return -errno_NFSERR_IO;
818 } else if (iov->iov_len != hdrlen) {
819 dprintk("NFS: READLINK header is short. iovec will be shifted.\n");
820 xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen);
822 recvd = req->rq_rcv_buf.len - hdrlen;
824 printk(KERN_WARNING "NFS: server cheating in readlink reply: "
825 "count %u > recvd %u\n", len, recvd);
829 /* NULL terminate the string we got */
830 kaddr = (char*)kmap_atomic(rcvbuf->pages[0], KM_USER0);
831 kaddr[len+rcvbuf->page_base] = '\0';
832 kunmap_atomic(kaddr, KM_USER0);
840 nfs3_xdr_readres(struct rpc_rqst *req, __be32 *p, struct nfs_readres *res)
842 struct kvec *iov = req->rq_rcv_buf.head;
843 int status, count, ocount, recvd, hdrlen;
845 status = ntohl(*p++);
846 p = xdr_decode_post_op_attr(p, res->fattr);
849 return -nfs_stat_to_errno(status);
851 /* Decode reply could and EOF flag. NFSv3 is somewhat redundant
852 * in that it puts the count both in the res struct and in the
853 * opaque data count. */
855 res->eof = ntohl(*p++);
856 ocount = ntohl(*p++);
858 if (ocount != count) {
859 printk(KERN_WARNING "NFS: READ count doesn't match RPC opaque count.\n");
860 return -errno_NFSERR_IO;
863 hdrlen = (u8 *) p - (u8 *) iov->iov_base;
864 if (iov->iov_len < hdrlen) {
865 printk(KERN_WARNING "NFS: READ reply header overflowed:"
866 "length %d > %Zu\n", hdrlen, iov->iov_len);
867 return -errno_NFSERR_IO;
868 } else if (iov->iov_len != hdrlen) {
869 dprintk("NFS: READ header is short. iovec will be shifted.\n");
870 xdr_shift_buf(&req->rq_rcv_buf, iov->iov_len - hdrlen);
873 recvd = req->rq_rcv_buf.len - hdrlen;
875 printk(KERN_WARNING "NFS: server cheating in read reply: "
876 "count %d > recvd %d\n", count, recvd);
881 if (count < res->count)
888 * Decode WRITE response
891 nfs3_xdr_writeres(struct rpc_rqst *req, __be32 *p, struct nfs_writeres *res)
895 status = ntohl(*p++);
896 p = xdr_decode_wcc_data(p, res->fattr);
899 return -nfs_stat_to_errno(status);
901 res->count = ntohl(*p++);
902 res->verf->committed = (enum nfs3_stable_how)ntohl(*p++);
903 res->verf->verifier[0] = *p++;
904 res->verf->verifier[1] = *p++;
910 * Decode a CREATE response
913 nfs3_xdr_createres(struct rpc_rqst *req, __be32 *p, struct nfs3_diropres *res)
917 status = ntohl(*p++);
920 if (!(p = xdr_decode_fhandle(p, res->fh)))
921 return -errno_NFSERR_IO;
922 p = xdr_decode_post_op_attr(p, res->fattr);
924 memset(res->fh, 0, sizeof(*res->fh));
925 /* Do decode post_op_attr but set it to NULL */
926 p = xdr_decode_post_op_attr(p, res->fattr);
927 res->fattr->valid = 0;
930 status = -nfs_stat_to_errno(status);
932 p = xdr_decode_wcc_data(p, res->dir_attr);
937 * Decode RENAME reply
940 nfs3_xdr_renameres(struct rpc_rqst *req, __be32 *p, struct nfs3_renameres *res)
944 if ((status = ntohl(*p++)) != 0)
945 status = -nfs_stat_to_errno(status);
946 p = xdr_decode_wcc_data(p, res->fromattr);
947 p = xdr_decode_wcc_data(p, res->toattr);
955 nfs3_xdr_linkres(struct rpc_rqst *req, __be32 *p, struct nfs3_linkres *res)
959 if ((status = ntohl(*p++)) != 0)
960 status = -nfs_stat_to_errno(status);
961 p = xdr_decode_post_op_attr(p, res->fattr);
962 p = xdr_decode_wcc_data(p, res->dir_attr);
967 * Decode FSSTAT reply
970 nfs3_xdr_fsstatres(struct rpc_rqst *req, __be32 *p, struct nfs_fsstat *res)
974 status = ntohl(*p++);
976 p = xdr_decode_post_op_attr(p, res->fattr);
978 return -nfs_stat_to_errno(status);
980 p = xdr_decode_hyper(p, &res->tbytes);
981 p = xdr_decode_hyper(p, &res->fbytes);
982 p = xdr_decode_hyper(p, &res->abytes);
983 p = xdr_decode_hyper(p, &res->tfiles);
984 p = xdr_decode_hyper(p, &res->ffiles);
985 p = xdr_decode_hyper(p, &res->afiles);
987 /* ignore invarsec */
992 * Decode FSINFO reply
995 nfs3_xdr_fsinfores(struct rpc_rqst *req, __be32 *p, struct nfs_fsinfo *res)
999 status = ntohl(*p++);
1001 p = xdr_decode_post_op_attr(p, res->fattr);
1003 return -nfs_stat_to_errno(status);
1005 res->rtmax = ntohl(*p++);
1006 res->rtpref = ntohl(*p++);
1007 res->rtmult = ntohl(*p++);
1008 res->wtmax = ntohl(*p++);
1009 res->wtpref = ntohl(*p++);
1010 res->wtmult = ntohl(*p++);
1011 res->dtpref = ntohl(*p++);
1012 p = xdr_decode_hyper(p, &res->maxfilesize);
1014 /* ignore time_delta and properties */
1015 res->lease_time = 0;
1020 * Decode PATHCONF reply
1023 nfs3_xdr_pathconfres(struct rpc_rqst *req, __be32 *p, struct nfs_pathconf *res)
1027 status = ntohl(*p++);
1029 p = xdr_decode_post_op_attr(p, res->fattr);
1031 return -nfs_stat_to_errno(status);
1032 res->max_link = ntohl(*p++);
1033 res->max_namelen = ntohl(*p++);
1035 /* ignore remaining fields */
1040 * Decode COMMIT reply
1043 nfs3_xdr_commitres(struct rpc_rqst *req, __be32 *p, struct nfs_writeres *res)
1047 status = ntohl(*p++);
1048 p = xdr_decode_wcc_data(p, res->fattr);
1050 return -nfs_stat_to_errno(status);
1052 res->verf->verifier[0] = *p++;
1053 res->verf->verifier[1] = *p++;
1057 #ifdef CONFIG_NFS_V3_ACL
1059 * Decode GETACL reply
1062 nfs3_xdr_getaclres(struct rpc_rqst *req, __be32 *p,
1063 struct nfs3_getaclres *res)
1065 struct xdr_buf *buf = &req->rq_rcv_buf;
1066 int status = ntohl(*p++);
1067 struct posix_acl **acl;
1068 unsigned int *aclcnt;
1072 return -nfs_stat_to_errno(status);
1073 p = xdr_decode_post_op_attr(p, res->fattr);
1074 res->mask = ntohl(*p++);
1075 if (res->mask & ~(NFS_ACL|NFS_ACLCNT|NFS_DFACL|NFS_DFACLCNT))
1077 base = (char *)p - (char *)req->rq_rcv_buf.head->iov_base;
1079 acl = (res->mask & NFS_ACL) ? &res->acl_access : NULL;
1080 aclcnt = (res->mask & NFS_ACLCNT) ? &res->acl_access_count : NULL;
1081 err = nfsacl_decode(buf, base, aclcnt, acl);
1083 acl = (res->mask & NFS_DFACL) ? &res->acl_default : NULL;
1084 aclcnt = (res->mask & NFS_DFACLCNT) ? &res->acl_default_count : NULL;
1086 err = nfsacl_decode(buf, base + err, aclcnt, acl);
1087 return (err > 0) ? 0 : err;
1091 * Decode setacl reply.
1094 nfs3_xdr_setaclres(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
1096 int status = ntohl(*p++);
1099 return -nfs_stat_to_errno(status);
1100 xdr_decode_post_op_attr(p, fattr);
1103 #endif /* CONFIG_NFS_V3_ACL */
1105 #define PROC(proc, argtype, restype, timer) \
1106 [NFS3PROC_##proc] = { \
1107 .p_proc = NFS3PROC_##proc, \
1108 .p_encode = (kxdrproc_t) nfs3_xdr_##argtype, \
1109 .p_decode = (kxdrproc_t) nfs3_xdr_##restype, \
1110 .p_arglen = NFS3_##argtype##_sz, \
1111 .p_replen = NFS3_##restype##_sz, \
1113 .p_statidx = NFS3PROC_##proc, \
1117 struct rpc_procinfo nfs3_procedures[] = {
1118 PROC(GETATTR, fhandle, attrstat, 1),
1119 PROC(SETATTR, sattrargs, wccstat, 0),
1120 PROC(LOOKUP, diropargs, lookupres, 2),
1121 PROC(ACCESS, accessargs, accessres, 1),
1122 PROC(READLINK, readlinkargs, readlinkres, 3),
1123 PROC(READ, readargs, readres, 3),
1124 PROC(WRITE, writeargs, writeres, 4),
1125 PROC(CREATE, createargs, createres, 0),
1126 PROC(MKDIR, mkdirargs, createres, 0),
1127 PROC(SYMLINK, symlinkargs, createres, 0),
1128 PROC(MKNOD, mknodargs, createres, 0),
1129 PROC(REMOVE, diropargs, wccstat, 0),
1130 PROC(RMDIR, diropargs, wccstat, 0),
1131 PROC(RENAME, renameargs, renameres, 0),
1132 PROC(LINK, linkargs, linkres, 0),
1133 PROC(READDIR, readdirargs, readdirres, 3),
1134 PROC(READDIRPLUS, readdirargs, readdirres, 3),
1135 PROC(FSSTAT, fhandle, fsstatres, 0),
1136 PROC(FSINFO, fhandle, fsinfores, 0),
1137 PROC(PATHCONF, fhandle, pathconfres, 0),
1138 PROC(COMMIT, commitargs, commitres, 5),
1141 struct rpc_version nfs_version3 = {
1143 .nrprocs = ARRAY_SIZE(nfs3_procedures),
1144 .procs = nfs3_procedures
1147 #ifdef CONFIG_NFS_V3_ACL
1148 static struct rpc_procinfo nfs3_acl_procedures[] = {
1149 [ACLPROC3_GETACL] = {
1150 .p_proc = ACLPROC3_GETACL,
1151 .p_encode = (kxdrproc_t) nfs3_xdr_getaclargs,
1152 .p_decode = (kxdrproc_t) nfs3_xdr_getaclres,
1153 .p_arglen = ACL3_getaclargs_sz,
1154 .p_replen = ACL3_getaclres_sz,
1158 [ACLPROC3_SETACL] = {
1159 .p_proc = ACLPROC3_SETACL,
1160 .p_encode = (kxdrproc_t) nfs3_xdr_setaclargs,
1161 .p_decode = (kxdrproc_t) nfs3_xdr_setaclres,
1162 .p_arglen = ACL3_setaclargs_sz,
1163 .p_replen = ACL3_setaclres_sz,
1169 struct rpc_version nfsacl_version3 = {
1171 .nrprocs = sizeof(nfs3_acl_procedures)/
1172 sizeof(nfs3_acl_procedures[0]),
1173 .procs = nfs3_acl_procedures,
1175 #endif /* CONFIG_NFS_V3_ACL */