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/errno.h>
13 #include <linux/string.h>
15 #include <linux/pagemap.h>
16 #include <linux/proc_fs.h>
17 #include <linux/kdev_t.h>
18 #include <linux/sunrpc/clnt.h>
19 #include <linux/nfs.h>
20 #include <linux/nfs3.h>
21 #include <linux/nfs_fs.h>
22 #include <linux/nfsacl.h>
25 #define NFSDBG_FACILITY NFSDBG_XDR
27 /* Mapping from NFS error code to "errno" error code. */
28 #define errno_NFSERR_IO EIO
31 * Declare the space requirements for NFS arguments and replies as
32 * number of 32bit-words
34 #define NFS3_fhandle_sz (1+16)
35 #define NFS3_fh_sz (NFS3_fhandle_sz) /* shorthand */
36 #define NFS3_sattr_sz (15)
37 #define NFS3_filename_sz (1+(NFS3_MAXNAMLEN>>2))
38 #define NFS3_path_sz (1+(NFS3_MAXPATHLEN>>2))
39 #define NFS3_fattr_sz (21)
40 #define NFS3_wcc_attr_sz (6)
41 #define NFS3_pre_op_attr_sz (1+NFS3_wcc_attr_sz)
42 #define NFS3_post_op_attr_sz (1+NFS3_fattr_sz)
43 #define NFS3_wcc_data_sz (NFS3_pre_op_attr_sz+NFS3_post_op_attr_sz)
44 #define NFS3_fsstat_sz
45 #define NFS3_fsinfo_sz
46 #define NFS3_pathconf_sz
47 #define NFS3_entry_sz (NFS3_filename_sz+3)
49 #define NFS3_sattrargs_sz (NFS3_fh_sz+NFS3_sattr_sz+3)
50 #define NFS3_diropargs_sz (NFS3_fh_sz+NFS3_filename_sz)
51 #define NFS3_removeargs_sz (NFS3_fh_sz+NFS3_filename_sz)
52 #define NFS3_accessargs_sz (NFS3_fh_sz+1)
53 #define NFS3_readlinkargs_sz (NFS3_fh_sz)
54 #define NFS3_readargs_sz (NFS3_fh_sz+3)
55 #define NFS3_writeargs_sz (NFS3_fh_sz+5)
56 #define NFS3_createargs_sz (NFS3_diropargs_sz+NFS3_sattr_sz)
57 #define NFS3_mkdirargs_sz (NFS3_diropargs_sz+NFS3_sattr_sz)
58 #define NFS3_symlinkargs_sz (NFS3_diropargs_sz+1+NFS3_sattr_sz)
59 #define NFS3_mknodargs_sz (NFS3_diropargs_sz+2+NFS3_sattr_sz)
60 #define NFS3_renameargs_sz (NFS3_diropargs_sz+NFS3_diropargs_sz)
61 #define NFS3_linkargs_sz (NFS3_fh_sz+NFS3_diropargs_sz)
62 #define NFS3_readdirargs_sz (NFS3_fh_sz+2)
63 #define NFS3_commitargs_sz (NFS3_fh_sz+3)
65 #define NFS3_attrstat_sz (1+NFS3_fattr_sz)
66 #define NFS3_wccstat_sz (1+NFS3_wcc_data_sz)
67 #define NFS3_removeres_sz (NFS3_wccstat_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+ \
84 XDR_QUADLEN(NFS_ACL_INLINE_BUFSIZE))
85 #define ACL3_getaclres_sz (1+NFS3_post_op_attr_sz+1+ \
86 XDR_QUADLEN(NFS_ACL_INLINE_BUFSIZE))
87 #define ACL3_setaclres_sz (1+NFS3_post_op_attr_sz)
90 * Map file type to S_IFMT bits
92 static const umode_t nfs_type2fmt[] = {
104 * Common NFS XDR functions as inlines
106 static inline __be32 *
107 xdr_encode_fhandle(__be32 *p, const struct nfs_fh *fh)
109 return xdr_encode_array(p, fh->data, fh->size);
112 static inline __be32 *
113 xdr_decode_fhandle(__be32 *p, struct nfs_fh *fh)
115 if ((fh->size = ntohl(*p++)) <= NFS3_FHSIZE) {
116 memcpy(fh->data, p, fh->size);
117 return p + XDR_QUADLEN(fh->size);
123 * Encode/decode time.
125 static inline __be32 *
126 xdr_encode_time3(__be32 *p, struct timespec *timep)
128 *p++ = htonl(timep->tv_sec);
129 *p++ = htonl(timep->tv_nsec);
133 static inline __be32 *
134 xdr_decode_time3(__be32 *p, struct timespec *timep)
136 timep->tv_sec = ntohl(*p++);
137 timep->tv_nsec = ntohl(*p++);
142 xdr_decode_fattr(__be32 *p, struct nfs_fattr *fattr)
144 unsigned int type, major, minor;
150 fmode = nfs_type2fmt[type];
151 fattr->mode = (ntohl(*p++) & ~S_IFMT) | fmode;
152 fattr->nlink = ntohl(*p++);
153 fattr->uid = ntohl(*p++);
154 fattr->gid = ntohl(*p++);
155 p = xdr_decode_hyper(p, &fattr->size);
156 p = xdr_decode_hyper(p, &fattr->du.nfs3.used);
158 /* Turn remote device info into Linux-specific dev_t */
161 fattr->rdev = MKDEV(major, minor);
162 if (MAJOR(fattr->rdev) != major || MINOR(fattr->rdev) != minor)
165 p = xdr_decode_hyper(p, &fattr->fsid.major);
166 fattr->fsid.minor = 0;
167 p = xdr_decode_hyper(p, &fattr->fileid);
168 p = xdr_decode_time3(p, &fattr->atime);
169 p = xdr_decode_time3(p, &fattr->mtime);
170 p = xdr_decode_time3(p, &fattr->ctime);
172 /* Update the mode bits */
173 fattr->valid |= NFS_ATTR_FATTR_V3;
177 static inline __be32 *
178 xdr_encode_sattr(__be32 *p, struct iattr *attr)
180 if (attr->ia_valid & ATTR_MODE) {
182 *p++ = htonl(attr->ia_mode & S_IALLUGO);
186 if (attr->ia_valid & ATTR_UID) {
188 *p++ = htonl(attr->ia_uid);
192 if (attr->ia_valid & ATTR_GID) {
194 *p++ = htonl(attr->ia_gid);
198 if (attr->ia_valid & ATTR_SIZE) {
200 p = xdr_encode_hyper(p, (__u64) attr->ia_size);
204 if (attr->ia_valid & ATTR_ATIME_SET) {
206 p = xdr_encode_time3(p, &attr->ia_atime);
207 } else if (attr->ia_valid & ATTR_ATIME) {
212 if (attr->ia_valid & ATTR_MTIME_SET) {
214 p = xdr_encode_time3(p, &attr->ia_mtime);
215 } else if (attr->ia_valid & ATTR_MTIME) {
223 static inline __be32 *
224 xdr_decode_wcc_attr(__be32 *p, struct nfs_fattr *fattr)
226 p = xdr_decode_hyper(p, &fattr->pre_size);
227 p = xdr_decode_time3(p, &fattr->pre_mtime);
228 p = xdr_decode_time3(p, &fattr->pre_ctime);
229 fattr->valid |= NFS_ATTR_FATTR_PRESIZE
230 | NFS_ATTR_FATTR_PREMTIME
231 | NFS_ATTR_FATTR_PRECTIME;
235 static inline __be32 *
236 xdr_decode_post_op_attr(__be32 *p, struct nfs_fattr *fattr)
239 p = xdr_decode_fattr(p, fattr);
243 static inline __be32 *
244 xdr_decode_pre_op_attr(__be32 *p, struct nfs_fattr *fattr)
247 return xdr_decode_wcc_attr(p, fattr);
252 static inline __be32 *
253 xdr_decode_wcc_data(__be32 *p, struct nfs_fattr *fattr)
255 p = xdr_decode_pre_op_attr(p, fattr);
256 return xdr_decode_post_op_attr(p, fattr);
260 * NFS encode functions
264 * Encode file handle argument
267 nfs3_xdr_fhandle(struct rpc_rqst *req, __be32 *p, struct nfs_fh *fh)
269 p = xdr_encode_fhandle(p, fh);
270 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
275 * Encode SETATTR arguments
278 nfs3_xdr_sattrargs(struct rpc_rqst *req, __be32 *p, struct nfs3_sattrargs *args)
280 p = xdr_encode_fhandle(p, args->fh);
281 p = xdr_encode_sattr(p, args->sattr);
282 *p++ = htonl(args->guard);
284 p = xdr_encode_time3(p, &args->guardtime);
285 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
290 * Encode directory ops argument
293 nfs3_xdr_diropargs(struct rpc_rqst *req, __be32 *p, struct nfs3_diropargs *args)
295 p = xdr_encode_fhandle(p, args->fh);
296 p = xdr_encode_array(p, args->name, args->len);
297 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
302 * Encode REMOVE argument
305 nfs3_xdr_removeargs(struct rpc_rqst *req, __be32 *p, const struct nfs_removeargs *args)
307 p = xdr_encode_fhandle(p, args->fh);
308 p = xdr_encode_array(p, args->name.name, args->name.len);
309 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
314 * Encode access() argument
317 nfs3_xdr_accessargs(struct rpc_rqst *req, __be32 *p, struct nfs3_accessargs *args)
319 p = xdr_encode_fhandle(p, args->fh);
320 *p++ = htonl(args->access);
321 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
326 * Arguments to a READ call. Since we read data directly into the page
327 * cache, we also set up the reply iovec here so that iov[1] points
328 * exactly to the page we want to fetch.
331 nfs3_xdr_readargs(struct rpc_rqst *req, __be32 *p, struct nfs_readargs *args)
333 struct rpc_auth *auth = req->rq_cred->cr_auth;
335 u32 count = args->count;
337 p = xdr_encode_fhandle(p, args->fh);
338 p = xdr_encode_hyper(p, args->offset);
340 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
342 /* Inline the page array */
343 replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS3_readres_sz) << 2;
344 xdr_inline_pages(&req->rq_rcv_buf, replen,
345 args->pages, args->pgbase, count);
346 req->rq_rcv_buf.flags |= XDRBUF_READ;
351 * Write arguments. Splice the buffer to be written into the iovec.
354 nfs3_xdr_writeargs(struct rpc_rqst *req, __be32 *p, struct nfs_writeargs *args)
356 struct xdr_buf *sndbuf = &req->rq_snd_buf;
357 u32 count = args->count;
359 p = xdr_encode_fhandle(p, args->fh);
360 p = xdr_encode_hyper(p, args->offset);
362 *p++ = htonl(args->stable);
364 sndbuf->len = xdr_adjust_iovec(sndbuf->head, p);
366 /* Copy the page array */
367 xdr_encode_pages(sndbuf, args->pages, args->pgbase, count);
368 sndbuf->flags |= XDRBUF_WRITE;
373 * Encode CREATE arguments
376 nfs3_xdr_createargs(struct rpc_rqst *req, __be32 *p, struct nfs3_createargs *args)
378 p = xdr_encode_fhandle(p, args->fh);
379 p = xdr_encode_array(p, args->name, args->len);
381 *p++ = htonl(args->createmode);
382 if (args->createmode == NFS3_CREATE_EXCLUSIVE) {
383 *p++ = args->verifier[0];
384 *p++ = args->verifier[1];
386 p = xdr_encode_sattr(p, args->sattr);
388 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
393 * Encode MKDIR arguments
396 nfs3_xdr_mkdirargs(struct rpc_rqst *req, __be32 *p, struct nfs3_mkdirargs *args)
398 p = xdr_encode_fhandle(p, args->fh);
399 p = xdr_encode_array(p, args->name, args->len);
400 p = xdr_encode_sattr(p, args->sattr);
401 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
406 * Encode SYMLINK arguments
409 nfs3_xdr_symlinkargs(struct rpc_rqst *req, __be32 *p, struct nfs3_symlinkargs *args)
411 p = xdr_encode_fhandle(p, args->fromfh);
412 p = xdr_encode_array(p, args->fromname, args->fromlen);
413 p = xdr_encode_sattr(p, args->sattr);
414 *p++ = htonl(args->pathlen);
415 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
418 xdr_encode_pages(&req->rq_snd_buf, args->pages, 0, args->pathlen);
423 * Encode MKNOD arguments
426 nfs3_xdr_mknodargs(struct rpc_rqst *req, __be32 *p, struct nfs3_mknodargs *args)
428 p = xdr_encode_fhandle(p, args->fh);
429 p = xdr_encode_array(p, args->name, args->len);
430 *p++ = htonl(args->type);
431 p = xdr_encode_sattr(p, args->sattr);
432 if (args->type == NF3CHR || args->type == NF3BLK) {
433 *p++ = htonl(MAJOR(args->rdev));
434 *p++ = htonl(MINOR(args->rdev));
437 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
442 * Encode RENAME arguments
445 nfs3_xdr_renameargs(struct rpc_rqst *req, __be32 *p, struct nfs_renameargs *args)
447 p = xdr_encode_fhandle(p, args->old_dir);
448 p = xdr_encode_array(p, args->old_name->name, args->old_name->len);
449 p = xdr_encode_fhandle(p, args->new_dir);
450 p = xdr_encode_array(p, args->new_name->name, args->new_name->len);
451 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
456 * Encode LINK arguments
459 nfs3_xdr_linkargs(struct rpc_rqst *req, __be32 *p, struct nfs3_linkargs *args)
461 p = xdr_encode_fhandle(p, args->fromfh);
462 p = xdr_encode_fhandle(p, args->tofh);
463 p = xdr_encode_array(p, args->toname, args->tolen);
464 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
469 * Encode arguments to readdir call
472 nfs3_xdr_readdirargs(struct rpc_rqst *req, __be32 *p, struct nfs3_readdirargs *args)
474 struct rpc_auth *auth = req->rq_cred->cr_auth;
476 u32 count = args->count;
478 p = xdr_encode_fhandle(p, args->fh);
479 p = xdr_encode_hyper(p, args->cookie);
480 *p++ = args->verf[0];
481 *p++ = args->verf[1];
483 /* readdirplus: need dircount + buffer size.
484 * We just make sure we make dircount big enough */
485 *p++ = htonl(count >> 3);
488 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
490 /* Inline the page array */
491 replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS3_readdirres_sz) << 2;
492 xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, 0, count);
497 * Decode the result of a readdir call.
498 * We just check for syntactical correctness.
501 nfs3_xdr_readdirres(struct rpc_rqst *req, __be32 *p, struct nfs3_readdirres *res)
503 struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
504 struct kvec *iov = rcvbuf->head;
507 u32 len, recvd, pglen;
509 __be32 *entry, *end, *kaddr;
511 status = ntohl(*p++);
512 /* Decode post_op_attrs */
513 p = xdr_decode_post_op_attr(p, res->dir_attr);
515 return nfs_stat_to_errno(status);
516 /* Decode verifier cookie */
524 hdrlen = (u8 *) p - (u8 *) iov->iov_base;
525 if (iov->iov_len < hdrlen) {
526 dprintk("NFS: READDIR reply header overflowed:"
527 "length %Zu > %Zu\n", hdrlen, iov->iov_len);
528 return -errno_NFSERR_IO;
529 } else if (iov->iov_len != hdrlen) {
530 dprintk("NFS: READDIR header is short. iovec will be shifted.\n");
531 xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen);
534 pglen = rcvbuf->page_len;
535 recvd = rcvbuf->len - hdrlen;
538 page = rcvbuf->pages;
539 kaddr = p = kmap_atomic(*page, KM_USER0);
540 end = (__be32 *)((char *)p + pglen);
543 /* Make sure the packet actually has a value_follows and EOF entry */
544 if ((entry + 1) > end)
550 p += 2; /* inode # */
551 len = ntohl(*p++); /* string length */
552 p += XDR_QUADLEN(len) + 2; /* name + cookie */
553 if (len > NFS3_MAXNAMLEN) {
554 dprintk("NFS: giant filename in readdir (len 0x%x)!\n",
573 if (len > NFS3_FHSIZE) {
574 dprintk("NFS: giant filehandle in "
575 "readdir (len 0x%x)!\n", len);
578 p += XDR_QUADLEN(len);
588 * Apparently some server sends responses that are a valid size, but
589 * contain no entries, and have value_follows==0 and EOF==0. For
590 * those, just set the EOF marker.
592 if (!nr && entry[1] == 0) {
593 dprintk("NFS: readdir reply truncated!\n");
597 kunmap_atomic(kaddr, KM_USER0);
601 * When we get a short packet there are 2 possibilities. We can
602 * return an error, or fix up the response to look like a valid
603 * response and return what we have so far. If there are no
604 * entries and the packet was short, then return -EIO. If there
605 * are valid entries in the response, return them and pretend that
606 * the call was successful, but incomplete. The caller can retry the
607 * readdir starting at the last cookie.
609 entry[0] = entry[1] = 0;
611 nr = -errno_NFSERR_IO;
614 nr = -errno_NFSERR_IO;
619 nfs3_decode_dirent(__be32 *p, struct nfs_entry *entry, int plus)
621 struct nfs_entry old = *entry;
625 return ERR_PTR(-EAGAIN);
627 return ERR_PTR(-EBADCOOKIE);
630 p = xdr_decode_hyper(p, &entry->ino);
631 entry->len = ntohl(*p++);
632 entry->name = (const char *) p;
633 p += XDR_QUADLEN(entry->len);
634 entry->prev_cookie = entry->cookie;
635 p = xdr_decode_hyper(p, &entry->cookie);
638 entry->fattr->valid = 0;
639 p = xdr_decode_post_op_attr(p, entry->fattr);
640 /* In fact, a post_op_fh3: */
642 p = xdr_decode_fhandle(p, entry->fh);
643 /* Ugh -- server reply was truncated */
645 dprintk("NFS: FH truncated\n");
647 return ERR_PTR(-EAGAIN);
650 memset((u8*)(entry->fh), 0, sizeof(*entry->fh));
653 entry->eof = !p[0] && p[1];
658 * Encode COMMIT arguments
661 nfs3_xdr_commitargs(struct rpc_rqst *req, __be32 *p, struct nfs_writeargs *args)
663 p = xdr_encode_fhandle(p, args->fh);
664 p = xdr_encode_hyper(p, args->offset);
665 *p++ = htonl(args->count);
666 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
670 #ifdef CONFIG_NFS_V3_ACL
672 * Encode GETACL arguments
675 nfs3_xdr_getaclargs(struct rpc_rqst *req, __be32 *p,
676 struct nfs3_getaclargs *args)
678 struct rpc_auth *auth = req->rq_cred->cr_auth;
681 p = xdr_encode_fhandle(p, args->fh);
682 *p++ = htonl(args->mask);
683 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
685 if (args->mask & (NFS_ACL | NFS_DFACL)) {
686 /* Inline the page array */
687 replen = (RPC_REPHDRSIZE + auth->au_rslack +
688 ACL3_getaclres_sz) << 2;
689 xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, 0,
690 NFSACL_MAXPAGES << PAGE_SHIFT);
696 * Encode SETACL arguments
699 nfs3_xdr_setaclargs(struct rpc_rqst *req, __be32 *p,
700 struct nfs3_setaclargs *args)
702 struct xdr_buf *buf = &req->rq_snd_buf;
706 p = xdr_encode_fhandle(p, NFS_FH(args->inode));
707 *p++ = htonl(args->mask);
708 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
711 if (args->npages != 0)
712 xdr_encode_pages(buf, args->pages, 0, args->len);
714 req->rq_slen = xdr_adjust_iovec(req->rq_svec,
715 p + XDR_QUADLEN(args->len));
717 err = nfsacl_encode(buf, base, args->inode,
718 (args->mask & NFS_ACL) ?
719 args->acl_access : NULL, 1, 0);
721 err = nfsacl_encode(buf, base + err, args->inode,
722 (args->mask & NFS_DFACL) ?
723 args->acl_default : NULL, 1,
725 return (err > 0) ? 0 : err;
727 #endif /* CONFIG_NFS_V3_ACL */
730 * NFS XDR decode functions
734 * Decode attrstat reply.
737 nfs3_xdr_attrstat(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
741 if ((status = ntohl(*p++)))
742 return nfs_stat_to_errno(status);
743 xdr_decode_fattr(p, fattr);
748 * Decode status+wcc_data reply
749 * SATTR, REMOVE, RMDIR
752 nfs3_xdr_wccstat(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
756 if ((status = ntohl(*p++)))
757 status = nfs_stat_to_errno(status);
758 xdr_decode_wcc_data(p, fattr);
763 nfs3_xdr_removeres(struct rpc_rqst *req, __be32 *p, struct nfs_removeres *res)
765 return nfs3_xdr_wccstat(req, p, res->dir_attr);
769 * Decode LOOKUP reply
772 nfs3_xdr_lookupres(struct rpc_rqst *req, __be32 *p, struct nfs3_diropres *res)
776 if ((status = ntohl(*p++))) {
777 status = nfs_stat_to_errno(status);
779 if (!(p = xdr_decode_fhandle(p, res->fh)))
780 return -errno_NFSERR_IO;
781 p = xdr_decode_post_op_attr(p, res->fattr);
783 xdr_decode_post_op_attr(p, res->dir_attr);
788 * Decode ACCESS reply
791 nfs3_xdr_accessres(struct rpc_rqst *req, __be32 *p, struct nfs3_accessres *res)
793 int status = ntohl(*p++);
795 p = xdr_decode_post_op_attr(p, res->fattr);
797 return nfs_stat_to_errno(status);
798 res->access = ntohl(*p++);
803 nfs3_xdr_readlinkargs(struct rpc_rqst *req, __be32 *p, struct nfs3_readlinkargs *args)
805 struct rpc_auth *auth = req->rq_cred->cr_auth;
808 p = xdr_encode_fhandle(p, args->fh);
809 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
811 /* Inline the page array */
812 replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS3_readlinkres_sz) << 2;
813 xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, args->pgbase, args->pglen);
818 * Decode READLINK reply
821 nfs3_xdr_readlinkres(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
823 struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
824 struct kvec *iov = rcvbuf->head;
829 status = ntohl(*p++);
830 p = xdr_decode_post_op_attr(p, fattr);
833 return nfs_stat_to_errno(status);
835 /* Convert length of symlink */
837 if (len >= rcvbuf->page_len) {
838 dprintk("nfs: server returned giant symlink!\n");
839 return -ENAMETOOLONG;
842 hdrlen = (u8 *) p - (u8 *) iov->iov_base;
843 if (iov->iov_len < hdrlen) {
844 dprintk("NFS: READLINK reply header overflowed:"
845 "length %Zu > %Zu\n", hdrlen, iov->iov_len);
846 return -errno_NFSERR_IO;
847 } else if (iov->iov_len != hdrlen) {
848 dprintk("NFS: READLINK header is short. "
849 "iovec will be shifted.\n");
850 xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen);
852 recvd = req->rq_rcv_buf.len - hdrlen;
854 dprintk("NFS: server cheating in readlink reply: "
855 "count %u > recvd %u\n", len, recvd);
859 xdr_terminate_string(rcvbuf, len);
867 nfs3_xdr_readres(struct rpc_rqst *req, __be32 *p, struct nfs_readres *res)
869 struct kvec *iov = req->rq_rcv_buf.head;
871 u32 count, ocount, recvd;
874 status = ntohl(*p++);
875 p = xdr_decode_post_op_attr(p, res->fattr);
878 return nfs_stat_to_errno(status);
880 /* Decode reply count and EOF flag. NFSv3 is somewhat redundant
881 * in that it puts the count both in the res struct and in the
882 * opaque data count. */
884 res->eof = ntohl(*p++);
885 ocount = ntohl(*p++);
887 if (ocount != count) {
888 dprintk("NFS: READ count doesn't match RPC opaque count.\n");
889 return -errno_NFSERR_IO;
892 hdrlen = (u8 *) p - (u8 *) iov->iov_base;
893 if (iov->iov_len < hdrlen) {
894 dprintk("NFS: READ reply header overflowed:"
895 "length %Zu > %Zu\n", hdrlen, iov->iov_len);
896 return -errno_NFSERR_IO;
897 } else if (iov->iov_len != hdrlen) {
898 dprintk("NFS: READ header is short. iovec will be shifted.\n");
899 xdr_shift_buf(&req->rq_rcv_buf, iov->iov_len - hdrlen);
902 recvd = req->rq_rcv_buf.len - hdrlen;
904 dprintk("NFS: server cheating in read reply: "
905 "count %u > recvd %u\n", count, recvd);
910 if (count < res->count)
917 * Decode WRITE response
920 nfs3_xdr_writeres(struct rpc_rqst *req, __be32 *p, struct nfs_writeres *res)
924 status = ntohl(*p++);
925 p = xdr_decode_wcc_data(p, res->fattr);
928 return nfs_stat_to_errno(status);
930 res->count = ntohl(*p++);
931 res->verf->committed = (enum nfs3_stable_how)ntohl(*p++);
932 res->verf->verifier[0] = *p++;
933 res->verf->verifier[1] = *p++;
939 * Decode a CREATE response
942 nfs3_xdr_createres(struct rpc_rqst *req, __be32 *p, struct nfs3_diropres *res)
946 status = ntohl(*p++);
949 if (!(p = xdr_decode_fhandle(p, res->fh)))
950 return -errno_NFSERR_IO;
951 p = xdr_decode_post_op_attr(p, res->fattr);
953 memset(res->fh, 0, sizeof(*res->fh));
954 /* Do decode post_op_attr but set it to NULL */
955 p = xdr_decode_post_op_attr(p, res->fattr);
956 res->fattr->valid = 0;
959 status = nfs_stat_to_errno(status);
961 p = xdr_decode_wcc_data(p, res->dir_attr);
966 * Decode RENAME reply
969 nfs3_xdr_renameres(struct rpc_rqst *req, __be32 *p, struct nfs_renameres *res)
973 if ((status = ntohl(*p++)) != 0)
974 status = nfs_stat_to_errno(status);
975 p = xdr_decode_wcc_data(p, res->old_fattr);
976 p = xdr_decode_wcc_data(p, res->new_fattr);
984 nfs3_xdr_linkres(struct rpc_rqst *req, __be32 *p, struct nfs3_linkres *res)
988 if ((status = ntohl(*p++)) != 0)
989 status = nfs_stat_to_errno(status);
990 p = xdr_decode_post_op_attr(p, res->fattr);
991 p = xdr_decode_wcc_data(p, res->dir_attr);
996 * Decode FSSTAT reply
999 nfs3_xdr_fsstatres(struct rpc_rqst *req, __be32 *p, struct nfs_fsstat *res)
1003 status = ntohl(*p++);
1005 p = xdr_decode_post_op_attr(p, res->fattr);
1007 return nfs_stat_to_errno(status);
1009 p = xdr_decode_hyper(p, &res->tbytes);
1010 p = xdr_decode_hyper(p, &res->fbytes);
1011 p = xdr_decode_hyper(p, &res->abytes);
1012 p = xdr_decode_hyper(p, &res->tfiles);
1013 p = xdr_decode_hyper(p, &res->ffiles);
1014 p = xdr_decode_hyper(p, &res->afiles);
1016 /* ignore invarsec */
1021 * Decode FSINFO reply
1024 nfs3_xdr_fsinfores(struct rpc_rqst *req, __be32 *p, struct nfs_fsinfo *res)
1028 status = ntohl(*p++);
1030 p = xdr_decode_post_op_attr(p, res->fattr);
1032 return nfs_stat_to_errno(status);
1034 res->rtmax = ntohl(*p++);
1035 res->rtpref = ntohl(*p++);
1036 res->rtmult = ntohl(*p++);
1037 res->wtmax = ntohl(*p++);
1038 res->wtpref = ntohl(*p++);
1039 res->wtmult = ntohl(*p++);
1040 res->dtpref = ntohl(*p++);
1041 p = xdr_decode_hyper(p, &res->maxfilesize);
1043 /* ignore time_delta and properties */
1044 res->lease_time = 0;
1049 * Decode PATHCONF reply
1052 nfs3_xdr_pathconfres(struct rpc_rqst *req, __be32 *p, struct nfs_pathconf *res)
1056 status = ntohl(*p++);
1058 p = xdr_decode_post_op_attr(p, res->fattr);
1060 return nfs_stat_to_errno(status);
1061 res->max_link = ntohl(*p++);
1062 res->max_namelen = ntohl(*p++);
1064 /* ignore remaining fields */
1069 * Decode COMMIT reply
1072 nfs3_xdr_commitres(struct rpc_rqst *req, __be32 *p, struct nfs_writeres *res)
1076 status = ntohl(*p++);
1077 p = xdr_decode_wcc_data(p, res->fattr);
1079 return nfs_stat_to_errno(status);
1081 res->verf->verifier[0] = *p++;
1082 res->verf->verifier[1] = *p++;
1086 #ifdef CONFIG_NFS_V3_ACL
1088 * Decode GETACL reply
1091 nfs3_xdr_getaclres(struct rpc_rqst *req, __be32 *p,
1092 struct nfs3_getaclres *res)
1094 struct xdr_buf *buf = &req->rq_rcv_buf;
1095 int status = ntohl(*p++);
1096 struct posix_acl **acl;
1097 unsigned int *aclcnt;
1101 return nfs_stat_to_errno(status);
1102 p = xdr_decode_post_op_attr(p, res->fattr);
1103 res->mask = ntohl(*p++);
1104 if (res->mask & ~(NFS_ACL|NFS_ACLCNT|NFS_DFACL|NFS_DFACLCNT))
1106 base = (char *)p - (char *)req->rq_rcv_buf.head->iov_base;
1108 acl = (res->mask & NFS_ACL) ? &res->acl_access : NULL;
1109 aclcnt = (res->mask & NFS_ACLCNT) ? &res->acl_access_count : NULL;
1110 err = nfsacl_decode(buf, base, aclcnt, acl);
1112 acl = (res->mask & NFS_DFACL) ? &res->acl_default : NULL;
1113 aclcnt = (res->mask & NFS_DFACLCNT) ? &res->acl_default_count : NULL;
1115 err = nfsacl_decode(buf, base + err, aclcnt, acl);
1116 return (err > 0) ? 0 : err;
1120 * Decode setacl reply.
1123 nfs3_xdr_setaclres(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
1125 int status = ntohl(*p++);
1128 return nfs_stat_to_errno(status);
1129 xdr_decode_post_op_attr(p, fattr);
1132 #endif /* CONFIG_NFS_V3_ACL */
1134 #define PROC(proc, argtype, restype, timer) \
1135 [NFS3PROC_##proc] = { \
1136 .p_proc = NFS3PROC_##proc, \
1137 .p_encode = (kxdrproc_t) nfs3_xdr_##argtype, \
1138 .p_decode = (kxdrproc_t) nfs3_xdr_##restype, \
1139 .p_arglen = NFS3_##argtype##_sz, \
1140 .p_replen = NFS3_##restype##_sz, \
1142 .p_statidx = NFS3PROC_##proc, \
1146 struct rpc_procinfo nfs3_procedures[] = {
1147 PROC(GETATTR, fhandle, attrstat, 1),
1148 PROC(SETATTR, sattrargs, wccstat, 0),
1149 PROC(LOOKUP, diropargs, lookupres, 2),
1150 PROC(ACCESS, accessargs, accessres, 1),
1151 PROC(READLINK, readlinkargs, readlinkres, 3),
1152 PROC(READ, readargs, readres, 3),
1153 PROC(WRITE, writeargs, writeres, 4),
1154 PROC(CREATE, createargs, createres, 0),
1155 PROC(MKDIR, mkdirargs, createres, 0),
1156 PROC(SYMLINK, symlinkargs, createres, 0),
1157 PROC(MKNOD, mknodargs, createres, 0),
1158 PROC(REMOVE, removeargs, removeres, 0),
1159 PROC(RMDIR, diropargs, wccstat, 0),
1160 PROC(RENAME, renameargs, renameres, 0),
1161 PROC(LINK, linkargs, linkres, 0),
1162 PROC(READDIR, readdirargs, readdirres, 3),
1163 PROC(READDIRPLUS, readdirargs, readdirres, 3),
1164 PROC(FSSTAT, fhandle, fsstatres, 0),
1165 PROC(FSINFO, fhandle, fsinfores, 0),
1166 PROC(PATHCONF, fhandle, pathconfres, 0),
1167 PROC(COMMIT, commitargs, commitres, 5),
1170 struct rpc_version nfs_version3 = {
1172 .nrprocs = ARRAY_SIZE(nfs3_procedures),
1173 .procs = nfs3_procedures
1176 #ifdef CONFIG_NFS_V3_ACL
1177 static struct rpc_procinfo nfs3_acl_procedures[] = {
1178 [ACLPROC3_GETACL] = {
1179 .p_proc = ACLPROC3_GETACL,
1180 .p_encode = (kxdrproc_t) nfs3_xdr_getaclargs,
1181 .p_decode = (kxdrproc_t) nfs3_xdr_getaclres,
1182 .p_arglen = ACL3_getaclargs_sz,
1183 .p_replen = ACL3_getaclres_sz,
1187 [ACLPROC3_SETACL] = {
1188 .p_proc = ACLPROC3_SETACL,
1189 .p_encode = (kxdrproc_t) nfs3_xdr_setaclargs,
1190 .p_decode = (kxdrproc_t) nfs3_xdr_setaclres,
1191 .p_arglen = ACL3_setaclargs_sz,
1192 .p_replen = ACL3_setaclres_sz,
1198 struct rpc_version nfsacl_version3 = {
1200 .nrprocs = sizeof(nfs3_acl_procedures)/
1201 sizeof(nfs3_acl_procedures[0]),
1202 .procs = nfs3_acl_procedures,
1204 #endif /* CONFIG_NFS_V3_ACL */