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_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
96 unsigned int nfs2type;
104 { S_IFSOCK, NFSOCK },
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);
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);
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++);
148 xdr_decode_fattr(__be32 *p, struct nfs_fattr *fattr)
150 unsigned int type, major, minor;
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 */
168 fattr->rdev = MKDEV(major, minor);
169 if (MAJOR(fattr->rdev) != major || MINOR(fattr->rdev) != minor)
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_V3;
184 static inline __be32 *
185 xdr_encode_sattr(__be32 *p, struct iattr *attr)
187 if (attr->ia_valid & ATTR_MODE) {
189 *p++ = htonl(attr->ia_mode & S_IALLUGO);
193 if (attr->ia_valid & ATTR_UID) {
195 *p++ = htonl(attr->ia_uid);
199 if (attr->ia_valid & ATTR_GID) {
201 *p++ = htonl(attr->ia_gid);
205 if (attr->ia_valid & ATTR_SIZE) {
207 p = xdr_encode_hyper(p, (__u64) attr->ia_size);
211 if (attr->ia_valid & ATTR_ATIME_SET) {
213 p = xdr_encode_time3(p, &attr->ia_atime);
214 } else if (attr->ia_valid & ATTR_ATIME) {
219 if (attr->ia_valid & ATTR_MTIME_SET) {
221 p = xdr_encode_time3(p, &attr->ia_mtime);
222 } else if (attr->ia_valid & ATTR_MTIME) {
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_FATTR_PRESIZE
237 | NFS_ATTR_FATTR_PREMTIME
238 | NFS_ATTR_FATTR_PRECTIME;
242 static inline __be32 *
243 xdr_decode_post_op_attr(__be32 *p, struct nfs_fattr *fattr)
246 p = xdr_decode_fattr(p, fattr);
250 static inline __be32 *
251 xdr_decode_pre_op_attr(__be32 *p, struct nfs_fattr *fattr)
254 return xdr_decode_wcc_attr(p, fattr);
259 static inline __be32 *
260 xdr_decode_wcc_data(__be32 *p, struct nfs_fattr *fattr)
262 p = xdr_decode_pre_op_attr(p, fattr);
263 return xdr_decode_post_op_attr(p, fattr);
267 * NFS encode functions
271 * Encode file handle argument
274 nfs3_xdr_fhandle(struct rpc_rqst *req, __be32 *p, struct nfs_fh *fh)
276 p = xdr_encode_fhandle(p, fh);
277 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
282 * Encode SETATTR arguments
285 nfs3_xdr_sattrargs(struct rpc_rqst *req, __be32 *p, struct nfs3_sattrargs *args)
287 p = xdr_encode_fhandle(p, args->fh);
288 p = xdr_encode_sattr(p, args->sattr);
289 *p++ = htonl(args->guard);
291 p = xdr_encode_time3(p, &args->guardtime);
292 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
297 * Encode directory ops argument
300 nfs3_xdr_diropargs(struct rpc_rqst *req, __be32 *p, struct nfs3_diropargs *args)
302 p = xdr_encode_fhandle(p, args->fh);
303 p = xdr_encode_array(p, args->name, args->len);
304 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
309 * Encode REMOVE argument
312 nfs3_xdr_removeargs(struct rpc_rqst *req, __be32 *p, const struct nfs_removeargs *args)
314 p = xdr_encode_fhandle(p, args->fh);
315 p = xdr_encode_array(p, args->name.name, args->name.len);
316 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
321 * Encode access() argument
324 nfs3_xdr_accessargs(struct rpc_rqst *req, __be32 *p, struct nfs3_accessargs *args)
326 p = xdr_encode_fhandle(p, args->fh);
327 *p++ = htonl(args->access);
328 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
333 * Arguments to a READ call. Since we read data directly into the page
334 * cache, we also set up the reply iovec here so that iov[1] points
335 * exactly to the page we want to fetch.
338 nfs3_xdr_readargs(struct rpc_rqst *req, __be32 *p, struct nfs_readargs *args)
340 struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth;
342 u32 count = args->count;
344 p = xdr_encode_fhandle(p, args->fh);
345 p = xdr_encode_hyper(p, args->offset);
347 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
349 /* Inline the page array */
350 replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS3_readres_sz) << 2;
351 xdr_inline_pages(&req->rq_rcv_buf, replen,
352 args->pages, args->pgbase, count);
353 req->rq_rcv_buf.flags |= XDRBUF_READ;
358 * Write arguments. Splice the buffer to be written into the iovec.
361 nfs3_xdr_writeargs(struct rpc_rqst *req, __be32 *p, struct nfs_writeargs *args)
363 struct xdr_buf *sndbuf = &req->rq_snd_buf;
364 u32 count = args->count;
366 p = xdr_encode_fhandle(p, args->fh);
367 p = xdr_encode_hyper(p, args->offset);
369 *p++ = htonl(args->stable);
371 sndbuf->len = xdr_adjust_iovec(sndbuf->head, p);
373 /* Copy the page array */
374 xdr_encode_pages(sndbuf, args->pages, args->pgbase, count);
375 sndbuf->flags |= XDRBUF_WRITE;
380 * Encode CREATE arguments
383 nfs3_xdr_createargs(struct rpc_rqst *req, __be32 *p, struct nfs3_createargs *args)
385 p = xdr_encode_fhandle(p, args->fh);
386 p = xdr_encode_array(p, args->name, args->len);
388 *p++ = htonl(args->createmode);
389 if (args->createmode == NFS3_CREATE_EXCLUSIVE) {
390 *p++ = args->verifier[0];
391 *p++ = args->verifier[1];
393 p = xdr_encode_sattr(p, args->sattr);
395 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
400 * Encode MKDIR arguments
403 nfs3_xdr_mkdirargs(struct rpc_rqst *req, __be32 *p, struct nfs3_mkdirargs *args)
405 p = xdr_encode_fhandle(p, args->fh);
406 p = xdr_encode_array(p, args->name, args->len);
407 p = xdr_encode_sattr(p, args->sattr);
408 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
413 * Encode SYMLINK arguments
416 nfs3_xdr_symlinkargs(struct rpc_rqst *req, __be32 *p, struct nfs3_symlinkargs *args)
418 p = xdr_encode_fhandle(p, args->fromfh);
419 p = xdr_encode_array(p, args->fromname, args->fromlen);
420 p = xdr_encode_sattr(p, args->sattr);
421 *p++ = htonl(args->pathlen);
422 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
425 xdr_encode_pages(&req->rq_snd_buf, args->pages, 0, args->pathlen);
430 * Encode MKNOD arguments
433 nfs3_xdr_mknodargs(struct rpc_rqst *req, __be32 *p, struct nfs3_mknodargs *args)
435 p = xdr_encode_fhandle(p, args->fh);
436 p = xdr_encode_array(p, args->name, args->len);
437 *p++ = htonl(args->type);
438 p = xdr_encode_sattr(p, args->sattr);
439 if (args->type == NF3CHR || args->type == NF3BLK) {
440 *p++ = htonl(MAJOR(args->rdev));
441 *p++ = htonl(MINOR(args->rdev));
444 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
449 * Encode RENAME arguments
452 nfs3_xdr_renameargs(struct rpc_rqst *req, __be32 *p, struct nfs3_renameargs *args)
454 p = xdr_encode_fhandle(p, args->fromfh);
455 p = xdr_encode_array(p, args->fromname, args->fromlen);
456 p = xdr_encode_fhandle(p, args->tofh);
457 p = xdr_encode_array(p, args->toname, args->tolen);
458 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
463 * Encode LINK arguments
466 nfs3_xdr_linkargs(struct rpc_rqst *req, __be32 *p, struct nfs3_linkargs *args)
468 p = xdr_encode_fhandle(p, args->fromfh);
469 p = xdr_encode_fhandle(p, args->tofh);
470 p = xdr_encode_array(p, args->toname, args->tolen);
471 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
476 * Encode arguments to readdir call
479 nfs3_xdr_readdirargs(struct rpc_rqst *req, __be32 *p, struct nfs3_readdirargs *args)
481 struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth;
483 u32 count = args->count;
485 p = xdr_encode_fhandle(p, args->fh);
486 p = xdr_encode_hyper(p, args->cookie);
487 *p++ = args->verf[0];
488 *p++ = args->verf[1];
490 /* readdirplus: need dircount + buffer size.
491 * We just make sure we make dircount big enough */
492 *p++ = htonl(count >> 3);
495 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
497 /* Inline the page array */
498 replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS3_readdirres_sz) << 2;
499 xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, 0, count);
504 * Decode the result of a readdir call.
505 * We just check for syntactical correctness.
508 nfs3_xdr_readdirres(struct rpc_rqst *req, __be32 *p, struct nfs3_readdirres *res)
510 struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
511 struct kvec *iov = rcvbuf->head;
514 u32 len, recvd, pglen;
516 __be32 *entry, *end, *kaddr;
518 status = ntohl(*p++);
519 /* Decode post_op_attrs */
520 p = xdr_decode_post_op_attr(p, res->dir_attr);
522 return nfs_stat_to_errno(status);
523 /* Decode verifier cookie */
531 hdrlen = (u8 *) p - (u8 *) iov->iov_base;
532 if (iov->iov_len < hdrlen) {
533 dprintk("NFS: READDIR reply header overflowed:"
534 "length %Zu > %Zu\n", hdrlen, iov->iov_len);
535 return -errno_NFSERR_IO;
536 } else if (iov->iov_len != hdrlen) {
537 dprintk("NFS: READDIR header is short. iovec will be shifted.\n");
538 xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen);
541 pglen = rcvbuf->page_len;
542 recvd = rcvbuf->len - hdrlen;
545 page = rcvbuf->pages;
546 kaddr = p = kmap_atomic(*page, KM_USER0);
547 end = (__be32 *)((char *)p + pglen);
550 /* Make sure the packet actually has a value_follows and EOF entry */
551 if ((entry + 1) > end)
557 p += 2; /* inode # */
558 len = ntohl(*p++); /* string length */
559 p += XDR_QUADLEN(len) + 2; /* name + cookie */
560 if (len > NFS3_MAXNAMLEN) {
561 dprintk("NFS: giant filename in readdir (len 0x%x)!\n",
580 if (len > NFS3_FHSIZE) {
581 dprintk("NFS: giant filehandle in "
582 "readdir (len 0x%x)!\n", len);
585 p += XDR_QUADLEN(len);
595 * Apparently some server sends responses that are a valid size, but
596 * contain no entries, and have value_follows==0 and EOF==0. For
597 * those, just set the EOF marker.
599 if (!nr && entry[1] == 0) {
600 dprintk("NFS: readdir reply truncated!\n");
604 kunmap_atomic(kaddr, KM_USER0);
608 * When we get a short packet there are 2 possibilities. We can
609 * return an error, or fix up the response to look like a valid
610 * response and return what we have so far. If there are no
611 * entries and the packet was short, then return -EIO. If there
612 * are valid entries in the response, return them and pretend that
613 * the call was successful, but incomplete. The caller can retry the
614 * readdir starting at the last cookie.
616 entry[0] = entry[1] = 0;
618 nr = -errno_NFSERR_IO;
621 nr = -errno_NFSERR_IO;
626 nfs3_decode_dirent(__be32 *p, struct nfs_entry *entry, int plus)
628 struct nfs_entry old = *entry;
632 return ERR_PTR(-EAGAIN);
634 return ERR_PTR(-EBADCOOKIE);
637 p = xdr_decode_hyper(p, &entry->ino);
638 entry->len = ntohl(*p++);
639 entry->name = (const char *) p;
640 p += XDR_QUADLEN(entry->len);
641 entry->prev_cookie = entry->cookie;
642 p = xdr_decode_hyper(p, &entry->cookie);
645 entry->fattr->valid = 0;
646 p = xdr_decode_post_op_attr(p, entry->fattr);
647 /* In fact, a post_op_fh3: */
649 p = xdr_decode_fhandle(p, entry->fh);
650 /* Ugh -- server reply was truncated */
652 dprintk("NFS: FH truncated\n");
654 return ERR_PTR(-EAGAIN);
657 memset((u8*)(entry->fh), 0, sizeof(*entry->fh));
660 entry->eof = !p[0] && p[1];
665 * Encode COMMIT arguments
668 nfs3_xdr_commitargs(struct rpc_rqst *req, __be32 *p, struct nfs_writeargs *args)
670 p = xdr_encode_fhandle(p, args->fh);
671 p = xdr_encode_hyper(p, args->offset);
672 *p++ = htonl(args->count);
673 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
677 #ifdef CONFIG_NFS_V3_ACL
679 * Encode GETACL arguments
682 nfs3_xdr_getaclargs(struct rpc_rqst *req, __be32 *p,
683 struct nfs3_getaclargs *args)
685 struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth;
688 p = xdr_encode_fhandle(p, args->fh);
689 *p++ = htonl(args->mask);
690 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
692 if (args->mask & (NFS_ACL | NFS_DFACL)) {
693 /* Inline the page array */
694 replen = (RPC_REPHDRSIZE + auth->au_rslack +
695 ACL3_getaclres_sz) << 2;
696 xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, 0,
697 NFSACL_MAXPAGES << PAGE_SHIFT);
703 * Encode SETACL arguments
706 nfs3_xdr_setaclargs(struct rpc_rqst *req, __be32 *p,
707 struct nfs3_setaclargs *args)
709 struct xdr_buf *buf = &req->rq_snd_buf;
713 p = xdr_encode_fhandle(p, NFS_FH(args->inode));
714 *p++ = htonl(args->mask);
715 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
718 if (args->npages != 0)
719 xdr_encode_pages(buf, args->pages, 0, args->len);
721 req->rq_slen += args->len;
723 err = nfsacl_encode(buf, base, args->inode,
724 (args->mask & NFS_ACL) ?
725 args->acl_access : NULL, 1, 0);
727 err = nfsacl_encode(buf, base + err, args->inode,
728 (args->mask & NFS_DFACL) ?
729 args->acl_default : NULL, 1,
731 return (err > 0) ? 0 : err;
733 #endif /* CONFIG_NFS_V3_ACL */
736 * NFS XDR decode functions
740 * Decode attrstat reply.
743 nfs3_xdr_attrstat(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
747 if ((status = ntohl(*p++)))
748 return nfs_stat_to_errno(status);
749 xdr_decode_fattr(p, fattr);
754 * Decode status+wcc_data reply
755 * SATTR, REMOVE, RMDIR
758 nfs3_xdr_wccstat(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
762 if ((status = ntohl(*p++)))
763 status = nfs_stat_to_errno(status);
764 xdr_decode_wcc_data(p, fattr);
769 nfs3_xdr_removeres(struct rpc_rqst *req, __be32 *p, struct nfs_removeres *res)
771 return nfs3_xdr_wccstat(req, p, &res->dir_attr);
775 * Decode LOOKUP reply
778 nfs3_xdr_lookupres(struct rpc_rqst *req, __be32 *p, struct nfs3_diropres *res)
782 if ((status = ntohl(*p++))) {
783 status = nfs_stat_to_errno(status);
785 if (!(p = xdr_decode_fhandle(p, res->fh)))
786 return -errno_NFSERR_IO;
787 p = xdr_decode_post_op_attr(p, res->fattr);
789 xdr_decode_post_op_attr(p, res->dir_attr);
794 * Decode ACCESS reply
797 nfs3_xdr_accessres(struct rpc_rqst *req, __be32 *p, struct nfs3_accessres *res)
799 int status = ntohl(*p++);
801 p = xdr_decode_post_op_attr(p, res->fattr);
803 return nfs_stat_to_errno(status);
804 res->access = ntohl(*p++);
809 nfs3_xdr_readlinkargs(struct rpc_rqst *req, __be32 *p, struct nfs3_readlinkargs *args)
811 struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth;
814 p = xdr_encode_fhandle(p, args->fh);
815 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
817 /* Inline the page array */
818 replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS3_readlinkres_sz) << 2;
819 xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, args->pgbase, args->pglen);
824 * Decode READLINK reply
827 nfs3_xdr_readlinkres(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
829 struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
830 struct kvec *iov = rcvbuf->head;
836 status = ntohl(*p++);
837 p = xdr_decode_post_op_attr(p, fattr);
840 return nfs_stat_to_errno(status);
842 /* Convert length of symlink */
844 if (len >= rcvbuf->page_len) {
845 dprintk("nfs: server returned giant symlink!\n");
846 return -ENAMETOOLONG;
849 hdrlen = (u8 *) p - (u8 *) iov->iov_base;
850 if (iov->iov_len < hdrlen) {
851 dprintk("NFS: READLINK reply header overflowed:"
852 "length %Zu > %Zu\n", hdrlen, iov->iov_len);
853 return -errno_NFSERR_IO;
854 } else if (iov->iov_len != hdrlen) {
855 dprintk("NFS: READLINK header is short. "
856 "iovec will be shifted.\n");
857 xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen);
859 recvd = req->rq_rcv_buf.len - hdrlen;
861 dprintk("NFS: server cheating in readlink reply: "
862 "count %u > recvd %u\n", len, recvd);
866 /* NULL terminate the string we got */
867 kaddr = (char*)kmap_atomic(rcvbuf->pages[0], KM_USER0);
868 kaddr[len+rcvbuf->page_base] = '\0';
869 kunmap_atomic(kaddr, KM_USER0);
877 nfs3_xdr_readres(struct rpc_rqst *req, __be32 *p, struct nfs_readres *res)
879 struct kvec *iov = req->rq_rcv_buf.head;
881 u32 count, ocount, recvd;
884 status = ntohl(*p++);
885 p = xdr_decode_post_op_attr(p, res->fattr);
888 return nfs_stat_to_errno(status);
890 /* Decode reply count and EOF flag. NFSv3 is somewhat redundant
891 * in that it puts the count both in the res struct and in the
892 * opaque data count. */
894 res->eof = ntohl(*p++);
895 ocount = ntohl(*p++);
897 if (ocount != count) {
898 dprintk("NFS: READ count doesn't match RPC opaque count.\n");
899 return -errno_NFSERR_IO;
902 hdrlen = (u8 *) p - (u8 *) iov->iov_base;
903 if (iov->iov_len < hdrlen) {
904 dprintk("NFS: READ reply header overflowed:"
905 "length %Zu > %Zu\n", hdrlen, iov->iov_len);
906 return -errno_NFSERR_IO;
907 } else if (iov->iov_len != hdrlen) {
908 dprintk("NFS: READ header is short. iovec will be shifted.\n");
909 xdr_shift_buf(&req->rq_rcv_buf, iov->iov_len - hdrlen);
912 recvd = req->rq_rcv_buf.len - hdrlen;
914 dprintk("NFS: server cheating in read reply: "
915 "count %u > recvd %u\n", count, recvd);
920 if (count < res->count)
927 * Decode WRITE response
930 nfs3_xdr_writeres(struct rpc_rqst *req, __be32 *p, struct nfs_writeres *res)
934 status = ntohl(*p++);
935 p = xdr_decode_wcc_data(p, res->fattr);
938 return nfs_stat_to_errno(status);
940 res->count = ntohl(*p++);
941 res->verf->committed = (enum nfs3_stable_how)ntohl(*p++);
942 res->verf->verifier[0] = *p++;
943 res->verf->verifier[1] = *p++;
949 * Decode a CREATE response
952 nfs3_xdr_createres(struct rpc_rqst *req, __be32 *p, struct nfs3_diropres *res)
956 status = ntohl(*p++);
959 if (!(p = xdr_decode_fhandle(p, res->fh)))
960 return -errno_NFSERR_IO;
961 p = xdr_decode_post_op_attr(p, res->fattr);
963 memset(res->fh, 0, sizeof(*res->fh));
964 /* Do decode post_op_attr but set it to NULL */
965 p = xdr_decode_post_op_attr(p, res->fattr);
966 res->fattr->valid = 0;
969 status = nfs_stat_to_errno(status);
971 p = xdr_decode_wcc_data(p, res->dir_attr);
976 * Decode RENAME reply
979 nfs3_xdr_renameres(struct rpc_rqst *req, __be32 *p, struct nfs3_renameres *res)
983 if ((status = ntohl(*p++)) != 0)
984 status = nfs_stat_to_errno(status);
985 p = xdr_decode_wcc_data(p, res->fromattr);
986 p = xdr_decode_wcc_data(p, res->toattr);
994 nfs3_xdr_linkres(struct rpc_rqst *req, __be32 *p, struct nfs3_linkres *res)
998 if ((status = ntohl(*p++)) != 0)
999 status = nfs_stat_to_errno(status);
1000 p = xdr_decode_post_op_attr(p, res->fattr);
1001 p = xdr_decode_wcc_data(p, res->dir_attr);
1006 * Decode FSSTAT reply
1009 nfs3_xdr_fsstatres(struct rpc_rqst *req, __be32 *p, struct nfs_fsstat *res)
1013 status = ntohl(*p++);
1015 p = xdr_decode_post_op_attr(p, res->fattr);
1017 return nfs_stat_to_errno(status);
1019 p = xdr_decode_hyper(p, &res->tbytes);
1020 p = xdr_decode_hyper(p, &res->fbytes);
1021 p = xdr_decode_hyper(p, &res->abytes);
1022 p = xdr_decode_hyper(p, &res->tfiles);
1023 p = xdr_decode_hyper(p, &res->ffiles);
1024 p = xdr_decode_hyper(p, &res->afiles);
1026 /* ignore invarsec */
1031 * Decode FSINFO reply
1034 nfs3_xdr_fsinfores(struct rpc_rqst *req, __be32 *p, struct nfs_fsinfo *res)
1038 status = ntohl(*p++);
1040 p = xdr_decode_post_op_attr(p, res->fattr);
1042 return nfs_stat_to_errno(status);
1044 res->rtmax = ntohl(*p++);
1045 res->rtpref = ntohl(*p++);
1046 res->rtmult = ntohl(*p++);
1047 res->wtmax = ntohl(*p++);
1048 res->wtpref = ntohl(*p++);
1049 res->wtmult = ntohl(*p++);
1050 res->dtpref = ntohl(*p++);
1051 p = xdr_decode_hyper(p, &res->maxfilesize);
1053 /* ignore time_delta and properties */
1054 res->lease_time = 0;
1059 * Decode PATHCONF reply
1062 nfs3_xdr_pathconfres(struct rpc_rqst *req, __be32 *p, struct nfs_pathconf *res)
1066 status = ntohl(*p++);
1068 p = xdr_decode_post_op_attr(p, res->fattr);
1070 return nfs_stat_to_errno(status);
1071 res->max_link = ntohl(*p++);
1072 res->max_namelen = ntohl(*p++);
1074 /* ignore remaining fields */
1079 * Decode COMMIT reply
1082 nfs3_xdr_commitres(struct rpc_rqst *req, __be32 *p, struct nfs_writeres *res)
1086 status = ntohl(*p++);
1087 p = xdr_decode_wcc_data(p, res->fattr);
1089 return nfs_stat_to_errno(status);
1091 res->verf->verifier[0] = *p++;
1092 res->verf->verifier[1] = *p++;
1096 #ifdef CONFIG_NFS_V3_ACL
1098 * Decode GETACL reply
1101 nfs3_xdr_getaclres(struct rpc_rqst *req, __be32 *p,
1102 struct nfs3_getaclres *res)
1104 struct xdr_buf *buf = &req->rq_rcv_buf;
1105 int status = ntohl(*p++);
1106 struct posix_acl **acl;
1107 unsigned int *aclcnt;
1111 return nfs_stat_to_errno(status);
1112 p = xdr_decode_post_op_attr(p, res->fattr);
1113 res->mask = ntohl(*p++);
1114 if (res->mask & ~(NFS_ACL|NFS_ACLCNT|NFS_DFACL|NFS_DFACLCNT))
1116 base = (char *)p - (char *)req->rq_rcv_buf.head->iov_base;
1118 acl = (res->mask & NFS_ACL) ? &res->acl_access : NULL;
1119 aclcnt = (res->mask & NFS_ACLCNT) ? &res->acl_access_count : NULL;
1120 err = nfsacl_decode(buf, base, aclcnt, acl);
1122 acl = (res->mask & NFS_DFACL) ? &res->acl_default : NULL;
1123 aclcnt = (res->mask & NFS_DFACLCNT) ? &res->acl_default_count : NULL;
1125 err = nfsacl_decode(buf, base + err, aclcnt, acl);
1126 return (err > 0) ? 0 : err;
1130 * Decode setacl reply.
1133 nfs3_xdr_setaclres(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
1135 int status = ntohl(*p++);
1138 return nfs_stat_to_errno(status);
1139 xdr_decode_post_op_attr(p, fattr);
1142 #endif /* CONFIG_NFS_V3_ACL */
1144 #define PROC(proc, argtype, restype, timer) \
1145 [NFS3PROC_##proc] = { \
1146 .p_proc = NFS3PROC_##proc, \
1147 .p_encode = (kxdrproc_t) nfs3_xdr_##argtype, \
1148 .p_decode = (kxdrproc_t) nfs3_xdr_##restype, \
1149 .p_arglen = NFS3_##argtype##_sz, \
1150 .p_replen = NFS3_##restype##_sz, \
1152 .p_statidx = NFS3PROC_##proc, \
1156 struct rpc_procinfo nfs3_procedures[] = {
1157 PROC(GETATTR, fhandle, attrstat, 1),
1158 PROC(SETATTR, sattrargs, wccstat, 0),
1159 PROC(LOOKUP, diropargs, lookupres, 2),
1160 PROC(ACCESS, accessargs, accessres, 1),
1161 PROC(READLINK, readlinkargs, readlinkres, 3),
1162 PROC(READ, readargs, readres, 3),
1163 PROC(WRITE, writeargs, writeres, 4),
1164 PROC(CREATE, createargs, createres, 0),
1165 PROC(MKDIR, mkdirargs, createres, 0),
1166 PROC(SYMLINK, symlinkargs, createres, 0),
1167 PROC(MKNOD, mknodargs, createres, 0),
1168 PROC(REMOVE, removeargs, removeres, 0),
1169 PROC(RMDIR, diropargs, wccstat, 0),
1170 PROC(RENAME, renameargs, renameres, 0),
1171 PROC(LINK, linkargs, linkres, 0),
1172 PROC(READDIR, readdirargs, readdirres, 3),
1173 PROC(READDIRPLUS, readdirargs, readdirres, 3),
1174 PROC(FSSTAT, fhandle, fsstatres, 0),
1175 PROC(FSINFO, fhandle, fsinfores, 0),
1176 PROC(PATHCONF, fhandle, pathconfres, 0),
1177 PROC(COMMIT, commitargs, commitres, 5),
1180 struct rpc_version nfs_version3 = {
1182 .nrprocs = ARRAY_SIZE(nfs3_procedures),
1183 .procs = nfs3_procedures
1186 #ifdef CONFIG_NFS_V3_ACL
1187 static struct rpc_procinfo nfs3_acl_procedures[] = {
1188 [ACLPROC3_GETACL] = {
1189 .p_proc = ACLPROC3_GETACL,
1190 .p_encode = (kxdrproc_t) nfs3_xdr_getaclargs,
1191 .p_decode = (kxdrproc_t) nfs3_xdr_getaclres,
1192 .p_arglen = ACL3_getaclargs_sz,
1193 .p_replen = ACL3_getaclres_sz,
1197 [ACLPROC3_SETACL] = {
1198 .p_proc = ACLPROC3_SETACL,
1199 .p_encode = (kxdrproc_t) nfs3_xdr_setaclargs,
1200 .p_decode = (kxdrproc_t) nfs3_xdr_setaclres,
1201 .p_arglen = ACL3_setaclargs_sz,
1202 .p_replen = ACL3_setaclres_sz,
1208 struct rpc_version nfsacl_version3 = {
1210 .nrprocs = sizeof(nfs3_acl_procedures)/
1211 sizeof(nfs3_acl_procedures[0]),
1212 .procs = nfs3_acl_procedures,
1214 #endif /* CONFIG_NFS_V3_ACL */