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/errno.h>
14 #include <linux/string.h>
16 #include <linux/pagemap.h>
17 #include <linux/proc_fs.h>
18 #include <linux/kdev_t.h>
19 #include <linux/sunrpc/clnt.h>
20 #include <linux/nfs.h>
21 #include <linux/nfs3.h>
22 #include <linux/nfs_fs.h>
23 #include <linux/nfsacl.h>
26 #define NFSDBG_FACILITY NFSDBG_XDR
28 /* Mapping from NFS error code to "errno" error code. */
29 #define errno_NFSERR_IO EIO
32 * Declare the space requirements for NFS arguments and replies as
33 * number of 32bit-words
35 #define NFS3_fhandle_sz (1+16)
36 #define NFS3_fh_sz (NFS3_fhandle_sz) /* shorthand */
37 #define NFS3_sattr_sz (15)
38 #define NFS3_filename_sz (1+(NFS3_MAXNAMLEN>>2))
39 #define NFS3_path_sz (1+(NFS3_MAXPATHLEN>>2))
40 #define NFS3_fattr_sz (21)
41 #define NFS3_wcc_attr_sz (6)
42 #define NFS3_pre_op_attr_sz (1+NFS3_wcc_attr_sz)
43 #define NFS3_post_op_attr_sz (1+NFS3_fattr_sz)
44 #define NFS3_wcc_data_sz (NFS3_pre_op_attr_sz+NFS3_post_op_attr_sz)
45 #define NFS3_fsstat_sz
46 #define NFS3_fsinfo_sz
47 #define NFS3_pathconf_sz
48 #define NFS3_entry_sz (NFS3_filename_sz+3)
50 #define NFS3_sattrargs_sz (NFS3_fh_sz+NFS3_sattr_sz+3)
51 #define NFS3_diropargs_sz (NFS3_fh_sz+NFS3_filename_sz)
52 #define NFS3_removeargs_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_removeres_sz (NFS3_wccstat_sz)
69 #define NFS3_lookupres_sz (1+NFS3_fh_sz+(2 * NFS3_post_op_attr_sz))
70 #define NFS3_accessres_sz (1+NFS3_post_op_attr_sz+1)
71 #define NFS3_readlinkres_sz (1+NFS3_post_op_attr_sz+1)
72 #define NFS3_readres_sz (1+NFS3_post_op_attr_sz+3)
73 #define NFS3_writeres_sz (1+NFS3_wcc_data_sz+4)
74 #define NFS3_createres_sz (1+NFS3_fh_sz+NFS3_post_op_attr_sz+NFS3_wcc_data_sz)
75 #define NFS3_renameres_sz (1+(2 * NFS3_wcc_data_sz))
76 #define NFS3_linkres_sz (1+NFS3_post_op_attr_sz+NFS3_wcc_data_sz)
77 #define NFS3_readdirres_sz (1+NFS3_post_op_attr_sz+2)
78 #define NFS3_fsstatres_sz (1+NFS3_post_op_attr_sz+13)
79 #define NFS3_fsinfores_sz (1+NFS3_post_op_attr_sz+12)
80 #define NFS3_pathconfres_sz (1+NFS3_post_op_attr_sz+6)
81 #define NFS3_commitres_sz (1+NFS3_wcc_data_sz+2)
83 #define ACL3_getaclargs_sz (NFS3_fh_sz+1)
84 #define ACL3_setaclargs_sz (NFS3_fh_sz+1+ \
85 XDR_QUADLEN(NFS_ACL_INLINE_BUFSIZE))
86 #define ACL3_getaclres_sz (1+NFS3_post_op_attr_sz+1+ \
87 XDR_QUADLEN(NFS_ACL_INLINE_BUFSIZE))
88 #define ACL3_setaclres_sz (1+NFS3_post_op_attr_sz)
91 * Map file type to S_IFMT bits
93 static const umode_t nfs_type2fmt[] = {
100 [NF3SOCK] = S_IFSOCK,
105 * Common NFS XDR functions as inlines
107 static inline __be32 *
108 xdr_encode_fhandle(__be32 *p, const struct nfs_fh *fh)
110 return xdr_encode_array(p, fh->data, fh->size);
113 static inline __be32 *
114 xdr_decode_fhandle(__be32 *p, struct nfs_fh *fh)
116 if ((fh->size = ntohl(*p++)) <= NFS3_FHSIZE) {
117 memcpy(fh->data, p, fh->size);
118 return p + XDR_QUADLEN(fh->size);
124 * Encode/decode time.
126 static inline __be32 *
127 xdr_encode_time3(__be32 *p, struct timespec *timep)
129 *p++ = htonl(timep->tv_sec);
130 *p++ = htonl(timep->tv_nsec);
134 static inline __be32 *
135 xdr_decode_time3(__be32 *p, struct timespec *timep)
137 timep->tv_sec = ntohl(*p++);
138 timep->tv_nsec = ntohl(*p++);
143 xdr_decode_fattr(__be32 *p, struct nfs_fattr *fattr)
145 unsigned int type, major, minor;
151 fmode = nfs_type2fmt[type];
152 fattr->mode = (ntohl(*p++) & ~S_IFMT) | fmode;
153 fattr->nlink = ntohl(*p++);
154 fattr->uid = ntohl(*p++);
155 fattr->gid = ntohl(*p++);
156 p = xdr_decode_hyper(p, &fattr->size);
157 p = xdr_decode_hyper(p, &fattr->du.nfs3.used);
159 /* Turn remote device info into Linux-specific dev_t */
162 fattr->rdev = MKDEV(major, minor);
163 if (MAJOR(fattr->rdev) != major || MINOR(fattr->rdev) != minor)
166 p = xdr_decode_hyper(p, &fattr->fsid.major);
167 fattr->fsid.minor = 0;
168 p = xdr_decode_hyper(p, &fattr->fileid);
169 p = xdr_decode_time3(p, &fattr->atime);
170 p = xdr_decode_time3(p, &fattr->mtime);
171 p = xdr_decode_time3(p, &fattr->ctime);
173 /* Update the mode bits */
174 fattr->valid |= NFS_ATTR_FATTR_V3;
178 static inline __be32 *
179 xdr_encode_sattr(__be32 *p, struct iattr *attr)
181 if (attr->ia_valid & ATTR_MODE) {
183 *p++ = htonl(attr->ia_mode & S_IALLUGO);
187 if (attr->ia_valid & ATTR_UID) {
189 *p++ = htonl(attr->ia_uid);
193 if (attr->ia_valid & ATTR_GID) {
195 *p++ = htonl(attr->ia_gid);
199 if (attr->ia_valid & ATTR_SIZE) {
201 p = xdr_encode_hyper(p, (__u64) attr->ia_size);
205 if (attr->ia_valid & ATTR_ATIME_SET) {
207 p = xdr_encode_time3(p, &attr->ia_atime);
208 } else if (attr->ia_valid & ATTR_ATIME) {
213 if (attr->ia_valid & ATTR_MTIME_SET) {
215 p = xdr_encode_time3(p, &attr->ia_mtime);
216 } else if (attr->ia_valid & ATTR_MTIME) {
224 static inline __be32 *
225 xdr_decode_wcc_attr(__be32 *p, struct nfs_fattr *fattr)
227 p = xdr_decode_hyper(p, &fattr->pre_size);
228 p = xdr_decode_time3(p, &fattr->pre_mtime);
229 p = xdr_decode_time3(p, &fattr->pre_ctime);
230 fattr->valid |= NFS_ATTR_FATTR_PRESIZE
231 | NFS_ATTR_FATTR_PREMTIME
232 | NFS_ATTR_FATTR_PRECTIME;
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 REMOVE argument
306 nfs3_xdr_removeargs(struct rpc_rqst *req, __be32 *p, const struct nfs_removeargs *args)
308 p = xdr_encode_fhandle(p, args->fh);
309 p = xdr_encode_array(p, args->name.name, args->name.len);
310 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
315 * Encode access() argument
318 nfs3_xdr_accessargs(struct rpc_rqst *req, __be32 *p, struct nfs3_accessargs *args)
320 p = xdr_encode_fhandle(p, args->fh);
321 *p++ = htonl(args->access);
322 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
327 * Arguments to a READ call. Since we read data directly into the page
328 * cache, we also set up the reply iovec here so that iov[1] points
329 * exactly to the page we want to fetch.
332 nfs3_xdr_readargs(struct rpc_rqst *req, __be32 *p, struct nfs_readargs *args)
334 struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth;
336 u32 count = args->count;
338 p = xdr_encode_fhandle(p, args->fh);
339 p = xdr_encode_hyper(p, args->offset);
341 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
343 /* Inline the page array */
344 replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS3_readres_sz) << 2;
345 xdr_inline_pages(&req->rq_rcv_buf, replen,
346 args->pages, args->pgbase, count);
347 req->rq_rcv_buf.flags |= XDRBUF_READ;
352 * Write arguments. Splice the buffer to be written into the iovec.
355 nfs3_xdr_writeargs(struct rpc_rqst *req, __be32 *p, struct nfs_writeargs *args)
357 struct xdr_buf *sndbuf = &req->rq_snd_buf;
358 u32 count = args->count;
360 p = xdr_encode_fhandle(p, args->fh);
361 p = xdr_encode_hyper(p, args->offset);
363 *p++ = htonl(args->stable);
365 sndbuf->len = xdr_adjust_iovec(sndbuf->head, p);
367 /* Copy the page array */
368 xdr_encode_pages(sndbuf, args->pages, args->pgbase, count);
369 sndbuf->flags |= XDRBUF_WRITE;
374 * Encode CREATE arguments
377 nfs3_xdr_createargs(struct rpc_rqst *req, __be32 *p, struct nfs3_createargs *args)
379 p = xdr_encode_fhandle(p, args->fh);
380 p = xdr_encode_array(p, args->name, args->len);
382 *p++ = htonl(args->createmode);
383 if (args->createmode == NFS3_CREATE_EXCLUSIVE) {
384 *p++ = args->verifier[0];
385 *p++ = args->verifier[1];
387 p = xdr_encode_sattr(p, args->sattr);
389 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
394 * Encode MKDIR arguments
397 nfs3_xdr_mkdirargs(struct rpc_rqst *req, __be32 *p, struct nfs3_mkdirargs *args)
399 p = xdr_encode_fhandle(p, args->fh);
400 p = xdr_encode_array(p, args->name, args->len);
401 p = xdr_encode_sattr(p, args->sattr);
402 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
407 * Encode SYMLINK arguments
410 nfs3_xdr_symlinkargs(struct rpc_rqst *req, __be32 *p, struct nfs3_symlinkargs *args)
412 p = xdr_encode_fhandle(p, args->fromfh);
413 p = xdr_encode_array(p, args->fromname, args->fromlen);
414 p = xdr_encode_sattr(p, args->sattr);
415 *p++ = htonl(args->pathlen);
416 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
419 xdr_encode_pages(&req->rq_snd_buf, args->pages, 0, args->pathlen);
424 * Encode MKNOD arguments
427 nfs3_xdr_mknodargs(struct rpc_rqst *req, __be32 *p, struct nfs3_mknodargs *args)
429 p = xdr_encode_fhandle(p, args->fh);
430 p = xdr_encode_array(p, args->name, args->len);
431 *p++ = htonl(args->type);
432 p = xdr_encode_sattr(p, args->sattr);
433 if (args->type == NF3CHR || args->type == NF3BLK) {
434 *p++ = htonl(MAJOR(args->rdev));
435 *p++ = htonl(MINOR(args->rdev));
438 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
443 * Encode RENAME arguments
446 nfs3_xdr_renameargs(struct rpc_rqst *req, __be32 *p, struct nfs3_renameargs *args)
448 p = xdr_encode_fhandle(p, args->fromfh);
449 p = xdr_encode_array(p, args->fromname, args->fromlen);
450 p = xdr_encode_fhandle(p, args->tofh);
451 p = xdr_encode_array(p, args->toname, args->tolen);
452 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
457 * Encode LINK arguments
460 nfs3_xdr_linkargs(struct rpc_rqst *req, __be32 *p, struct nfs3_linkargs *args)
462 p = xdr_encode_fhandle(p, args->fromfh);
463 p = xdr_encode_fhandle(p, args->tofh);
464 p = xdr_encode_array(p, args->toname, args->tolen);
465 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
470 * Encode arguments to readdir call
473 nfs3_xdr_readdirargs(struct rpc_rqst *req, __be32 *p, struct nfs3_readdirargs *args)
475 struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth;
477 u32 count = args->count;
479 p = xdr_encode_fhandle(p, args->fh);
480 p = xdr_encode_hyper(p, args->cookie);
481 *p++ = args->verf[0];
482 *p++ = args->verf[1];
484 /* readdirplus: need dircount + buffer size.
485 * We just make sure we make dircount big enough */
486 *p++ = htonl(count >> 3);
489 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
491 /* Inline the page array */
492 replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS3_readdirres_sz) << 2;
493 xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, 0, count);
498 * Decode the result of a readdir call.
499 * We just check for syntactical correctness.
502 nfs3_xdr_readdirres(struct rpc_rqst *req, __be32 *p, struct nfs3_readdirres *res)
504 struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
505 struct kvec *iov = rcvbuf->head;
508 u32 len, recvd, pglen;
510 __be32 *entry, *end, *kaddr;
512 status = ntohl(*p++);
513 /* Decode post_op_attrs */
514 p = xdr_decode_post_op_attr(p, res->dir_attr);
516 return nfs_stat_to_errno(status);
517 /* Decode verifier cookie */
525 hdrlen = (u8 *) p - (u8 *) iov->iov_base;
526 if (iov->iov_len < hdrlen) {
527 dprintk("NFS: READDIR reply header overflowed:"
528 "length %Zu > %Zu\n", hdrlen, iov->iov_len);
529 return -errno_NFSERR_IO;
530 } else if (iov->iov_len != hdrlen) {
531 dprintk("NFS: READDIR header is short. iovec will be shifted.\n");
532 xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen);
535 pglen = rcvbuf->page_len;
536 recvd = rcvbuf->len - hdrlen;
539 page = rcvbuf->pages;
540 kaddr = p = kmap_atomic(*page, KM_USER0);
541 end = (__be32 *)((char *)p + pglen);
544 /* Make sure the packet actually has a value_follows and EOF entry */
545 if ((entry + 1) > end)
551 p += 2; /* inode # */
552 len = ntohl(*p++); /* string length */
553 p += XDR_QUADLEN(len) + 2; /* name + cookie */
554 if (len > NFS3_MAXNAMLEN) {
555 dprintk("NFS: giant filename in readdir (len 0x%x)!\n",
574 if (len > NFS3_FHSIZE) {
575 dprintk("NFS: giant filehandle in "
576 "readdir (len 0x%x)!\n", len);
579 p += XDR_QUADLEN(len);
589 * Apparently some server sends responses that are a valid size, but
590 * contain no entries, and have value_follows==0 and EOF==0. For
591 * those, just set the EOF marker.
593 if (!nr && entry[1] == 0) {
594 dprintk("NFS: readdir reply truncated!\n");
598 kunmap_atomic(kaddr, KM_USER0);
602 * When we get a short packet there are 2 possibilities. We can
603 * return an error, or fix up the response to look like a valid
604 * response and return what we have so far. If there are no
605 * entries and the packet was short, then return -EIO. If there
606 * are valid entries in the response, return them and pretend that
607 * the call was successful, but incomplete. The caller can retry the
608 * readdir starting at the last cookie.
610 entry[0] = entry[1] = 0;
612 nr = -errno_NFSERR_IO;
615 nr = -errno_NFSERR_IO;
620 nfs3_decode_dirent(__be32 *p, struct nfs_entry *entry, int plus)
622 struct nfs_entry old = *entry;
626 return ERR_PTR(-EAGAIN);
628 return ERR_PTR(-EBADCOOKIE);
631 p = xdr_decode_hyper(p, &entry->ino);
632 entry->len = ntohl(*p++);
633 entry->name = (const char *) p;
634 p += XDR_QUADLEN(entry->len);
635 entry->prev_cookie = entry->cookie;
636 p = xdr_decode_hyper(p, &entry->cookie);
639 entry->fattr->valid = 0;
640 p = xdr_decode_post_op_attr(p, entry->fattr);
641 /* In fact, a post_op_fh3: */
643 p = xdr_decode_fhandle(p, entry->fh);
644 /* Ugh -- server reply was truncated */
646 dprintk("NFS: FH truncated\n");
648 return ERR_PTR(-EAGAIN);
651 memset((u8*)(entry->fh), 0, sizeof(*entry->fh));
654 entry->eof = !p[0] && p[1];
659 * Encode COMMIT arguments
662 nfs3_xdr_commitargs(struct rpc_rqst *req, __be32 *p, struct nfs_writeargs *args)
664 p = xdr_encode_fhandle(p, args->fh);
665 p = xdr_encode_hyper(p, args->offset);
666 *p++ = htonl(args->count);
667 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
671 #ifdef CONFIG_NFS_V3_ACL
673 * Encode GETACL arguments
676 nfs3_xdr_getaclargs(struct rpc_rqst *req, __be32 *p,
677 struct nfs3_getaclargs *args)
679 struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth;
682 p = xdr_encode_fhandle(p, args->fh);
683 *p++ = htonl(args->mask);
684 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
686 if (args->mask & (NFS_ACL | NFS_DFACL)) {
687 /* Inline the page array */
688 replen = (RPC_REPHDRSIZE + auth->au_rslack +
689 ACL3_getaclres_sz) << 2;
690 xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, 0,
691 NFSACL_MAXPAGES << PAGE_SHIFT);
697 * Encode SETACL arguments
700 nfs3_xdr_setaclargs(struct rpc_rqst *req, __be32 *p,
701 struct nfs3_setaclargs *args)
703 struct xdr_buf *buf = &req->rq_snd_buf;
707 p = xdr_encode_fhandle(p, NFS_FH(args->inode));
708 *p++ = htonl(args->mask);
709 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
712 if (args->npages != 0)
713 xdr_encode_pages(buf, args->pages, 0, args->len);
715 req->rq_slen = xdr_adjust_iovec(req->rq_svec,
716 p + XDR_QUADLEN(args->len));
718 err = nfsacl_encode(buf, base, args->inode,
719 (args->mask & NFS_ACL) ?
720 args->acl_access : NULL, 1, 0);
722 err = nfsacl_encode(buf, base + err, args->inode,
723 (args->mask & NFS_DFACL) ?
724 args->acl_default : NULL, 1,
726 return (err > 0) ? 0 : err;
728 #endif /* CONFIG_NFS_V3_ACL */
731 * NFS XDR decode functions
735 * Decode attrstat reply.
738 nfs3_xdr_attrstat(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
742 if ((status = ntohl(*p++)))
743 return nfs_stat_to_errno(status);
744 xdr_decode_fattr(p, fattr);
749 * Decode status+wcc_data reply
750 * SATTR, REMOVE, RMDIR
753 nfs3_xdr_wccstat(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
757 if ((status = ntohl(*p++)))
758 status = nfs_stat_to_errno(status);
759 xdr_decode_wcc_data(p, fattr);
764 nfs3_xdr_removeres(struct rpc_rqst *req, __be32 *p, struct nfs_removeres *res)
766 return nfs3_xdr_wccstat(req, p, &res->dir_attr);
770 * Decode LOOKUP reply
773 nfs3_xdr_lookupres(struct rpc_rqst *req, __be32 *p, struct nfs3_diropres *res)
777 if ((status = ntohl(*p++))) {
778 status = nfs_stat_to_errno(status);
780 if (!(p = xdr_decode_fhandle(p, res->fh)))
781 return -errno_NFSERR_IO;
782 p = xdr_decode_post_op_attr(p, res->fattr);
784 xdr_decode_post_op_attr(p, res->dir_attr);
789 * Decode ACCESS reply
792 nfs3_xdr_accessres(struct rpc_rqst *req, __be32 *p, struct nfs3_accessres *res)
794 int status = ntohl(*p++);
796 p = xdr_decode_post_op_attr(p, res->fattr);
798 return nfs_stat_to_errno(status);
799 res->access = ntohl(*p++);
804 nfs3_xdr_readlinkargs(struct rpc_rqst *req, __be32 *p, struct nfs3_readlinkargs *args)
806 struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth;
809 p = xdr_encode_fhandle(p, args->fh);
810 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
812 /* Inline the page array */
813 replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS3_readlinkres_sz) << 2;
814 xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, args->pgbase, args->pglen);
819 * Decode READLINK reply
822 nfs3_xdr_readlinkres(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
824 struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
825 struct kvec *iov = rcvbuf->head;
831 status = ntohl(*p++);
832 p = xdr_decode_post_op_attr(p, fattr);
835 return nfs_stat_to_errno(status);
837 /* Convert length of symlink */
839 if (len >= rcvbuf->page_len) {
840 dprintk("nfs: server returned giant symlink!\n");
841 return -ENAMETOOLONG;
844 hdrlen = (u8 *) p - (u8 *) iov->iov_base;
845 if (iov->iov_len < hdrlen) {
846 dprintk("NFS: READLINK reply header overflowed:"
847 "length %Zu > %Zu\n", hdrlen, iov->iov_len);
848 return -errno_NFSERR_IO;
849 } else if (iov->iov_len != hdrlen) {
850 dprintk("NFS: READLINK header is short. "
851 "iovec will be shifted.\n");
852 xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen);
854 recvd = req->rq_rcv_buf.len - hdrlen;
856 dprintk("NFS: server cheating in readlink reply: "
857 "count %u > recvd %u\n", len, recvd);
861 /* NULL terminate the string we got */
862 kaddr = (char*)kmap_atomic(rcvbuf->pages[0], KM_USER0);
863 kaddr[len+rcvbuf->page_base] = '\0';
864 kunmap_atomic(kaddr, KM_USER0);
872 nfs3_xdr_readres(struct rpc_rqst *req, __be32 *p, struct nfs_readres *res)
874 struct kvec *iov = req->rq_rcv_buf.head;
876 u32 count, ocount, recvd;
879 status = ntohl(*p++);
880 p = xdr_decode_post_op_attr(p, res->fattr);
883 return nfs_stat_to_errno(status);
885 /* Decode reply count and EOF flag. NFSv3 is somewhat redundant
886 * in that it puts the count both in the res struct and in the
887 * opaque data count. */
889 res->eof = ntohl(*p++);
890 ocount = ntohl(*p++);
892 if (ocount != count) {
893 dprintk("NFS: READ count doesn't match RPC opaque count.\n");
894 return -errno_NFSERR_IO;
897 hdrlen = (u8 *) p - (u8 *) iov->iov_base;
898 if (iov->iov_len < hdrlen) {
899 dprintk("NFS: READ reply header overflowed:"
900 "length %Zu > %Zu\n", hdrlen, iov->iov_len);
901 return -errno_NFSERR_IO;
902 } else if (iov->iov_len != hdrlen) {
903 dprintk("NFS: READ header is short. iovec will be shifted.\n");
904 xdr_shift_buf(&req->rq_rcv_buf, iov->iov_len - hdrlen);
907 recvd = req->rq_rcv_buf.len - hdrlen;
909 dprintk("NFS: server cheating in read reply: "
910 "count %u > recvd %u\n", count, recvd);
915 if (count < res->count)
922 * Decode WRITE response
925 nfs3_xdr_writeres(struct rpc_rqst *req, __be32 *p, struct nfs_writeres *res)
929 status = ntohl(*p++);
930 p = xdr_decode_wcc_data(p, res->fattr);
933 return nfs_stat_to_errno(status);
935 res->count = ntohl(*p++);
936 res->verf->committed = (enum nfs3_stable_how)ntohl(*p++);
937 res->verf->verifier[0] = *p++;
938 res->verf->verifier[1] = *p++;
944 * Decode a CREATE response
947 nfs3_xdr_createres(struct rpc_rqst *req, __be32 *p, struct nfs3_diropres *res)
951 status = ntohl(*p++);
954 if (!(p = xdr_decode_fhandle(p, res->fh)))
955 return -errno_NFSERR_IO;
956 p = xdr_decode_post_op_attr(p, res->fattr);
958 memset(res->fh, 0, sizeof(*res->fh));
959 /* Do decode post_op_attr but set it to NULL */
960 p = xdr_decode_post_op_attr(p, res->fattr);
961 res->fattr->valid = 0;
964 status = nfs_stat_to_errno(status);
966 p = xdr_decode_wcc_data(p, res->dir_attr);
971 * Decode RENAME reply
974 nfs3_xdr_renameres(struct rpc_rqst *req, __be32 *p, struct nfs3_renameres *res)
978 if ((status = ntohl(*p++)) != 0)
979 status = nfs_stat_to_errno(status);
980 p = xdr_decode_wcc_data(p, res->fromattr);
981 p = xdr_decode_wcc_data(p, res->toattr);
989 nfs3_xdr_linkres(struct rpc_rqst *req, __be32 *p, struct nfs3_linkres *res)
993 if ((status = ntohl(*p++)) != 0)
994 status = nfs_stat_to_errno(status);
995 p = xdr_decode_post_op_attr(p, res->fattr);
996 p = xdr_decode_wcc_data(p, res->dir_attr);
1001 * Decode FSSTAT reply
1004 nfs3_xdr_fsstatres(struct rpc_rqst *req, __be32 *p, struct nfs_fsstat *res)
1008 status = ntohl(*p++);
1010 p = xdr_decode_post_op_attr(p, res->fattr);
1012 return nfs_stat_to_errno(status);
1014 p = xdr_decode_hyper(p, &res->tbytes);
1015 p = xdr_decode_hyper(p, &res->fbytes);
1016 p = xdr_decode_hyper(p, &res->abytes);
1017 p = xdr_decode_hyper(p, &res->tfiles);
1018 p = xdr_decode_hyper(p, &res->ffiles);
1019 p = xdr_decode_hyper(p, &res->afiles);
1021 /* ignore invarsec */
1026 * Decode FSINFO reply
1029 nfs3_xdr_fsinfores(struct rpc_rqst *req, __be32 *p, struct nfs_fsinfo *res)
1033 status = ntohl(*p++);
1035 p = xdr_decode_post_op_attr(p, res->fattr);
1037 return nfs_stat_to_errno(status);
1039 res->rtmax = ntohl(*p++);
1040 res->rtpref = ntohl(*p++);
1041 res->rtmult = ntohl(*p++);
1042 res->wtmax = ntohl(*p++);
1043 res->wtpref = ntohl(*p++);
1044 res->wtmult = ntohl(*p++);
1045 res->dtpref = ntohl(*p++);
1046 p = xdr_decode_hyper(p, &res->maxfilesize);
1048 /* ignore time_delta and properties */
1049 res->lease_time = 0;
1054 * Decode PATHCONF reply
1057 nfs3_xdr_pathconfres(struct rpc_rqst *req, __be32 *p, struct nfs_pathconf *res)
1061 status = ntohl(*p++);
1063 p = xdr_decode_post_op_attr(p, res->fattr);
1065 return nfs_stat_to_errno(status);
1066 res->max_link = ntohl(*p++);
1067 res->max_namelen = ntohl(*p++);
1069 /* ignore remaining fields */
1074 * Decode COMMIT reply
1077 nfs3_xdr_commitres(struct rpc_rqst *req, __be32 *p, struct nfs_writeres *res)
1081 status = ntohl(*p++);
1082 p = xdr_decode_wcc_data(p, res->fattr);
1084 return nfs_stat_to_errno(status);
1086 res->verf->verifier[0] = *p++;
1087 res->verf->verifier[1] = *p++;
1091 #ifdef CONFIG_NFS_V3_ACL
1093 * Decode GETACL reply
1096 nfs3_xdr_getaclres(struct rpc_rqst *req, __be32 *p,
1097 struct nfs3_getaclres *res)
1099 struct xdr_buf *buf = &req->rq_rcv_buf;
1100 int status = ntohl(*p++);
1101 struct posix_acl **acl;
1102 unsigned int *aclcnt;
1106 return nfs_stat_to_errno(status);
1107 p = xdr_decode_post_op_attr(p, res->fattr);
1108 res->mask = ntohl(*p++);
1109 if (res->mask & ~(NFS_ACL|NFS_ACLCNT|NFS_DFACL|NFS_DFACLCNT))
1111 base = (char *)p - (char *)req->rq_rcv_buf.head->iov_base;
1113 acl = (res->mask & NFS_ACL) ? &res->acl_access : NULL;
1114 aclcnt = (res->mask & NFS_ACLCNT) ? &res->acl_access_count : NULL;
1115 err = nfsacl_decode(buf, base, aclcnt, acl);
1117 acl = (res->mask & NFS_DFACL) ? &res->acl_default : NULL;
1118 aclcnt = (res->mask & NFS_DFACLCNT) ? &res->acl_default_count : NULL;
1120 err = nfsacl_decode(buf, base + err, aclcnt, acl);
1121 return (err > 0) ? 0 : err;
1125 * Decode setacl reply.
1128 nfs3_xdr_setaclres(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
1130 int status = ntohl(*p++);
1133 return nfs_stat_to_errno(status);
1134 xdr_decode_post_op_attr(p, fattr);
1137 #endif /* CONFIG_NFS_V3_ACL */
1139 #define PROC(proc, argtype, restype, timer) \
1140 [NFS3PROC_##proc] = { \
1141 .p_proc = NFS3PROC_##proc, \
1142 .p_encode = (kxdrproc_t) nfs3_xdr_##argtype, \
1143 .p_decode = (kxdrproc_t) nfs3_xdr_##restype, \
1144 .p_arglen = NFS3_##argtype##_sz, \
1145 .p_replen = NFS3_##restype##_sz, \
1147 .p_statidx = NFS3PROC_##proc, \
1151 struct rpc_procinfo nfs3_procedures[] = {
1152 PROC(GETATTR, fhandle, attrstat, 1),
1153 PROC(SETATTR, sattrargs, wccstat, 0),
1154 PROC(LOOKUP, diropargs, lookupres, 2),
1155 PROC(ACCESS, accessargs, accessres, 1),
1156 PROC(READLINK, readlinkargs, readlinkres, 3),
1157 PROC(READ, readargs, readres, 3),
1158 PROC(WRITE, writeargs, writeres, 4),
1159 PROC(CREATE, createargs, createres, 0),
1160 PROC(MKDIR, mkdirargs, createres, 0),
1161 PROC(SYMLINK, symlinkargs, createres, 0),
1162 PROC(MKNOD, mknodargs, createres, 0),
1163 PROC(REMOVE, removeargs, removeres, 0),
1164 PROC(RMDIR, diropargs, wccstat, 0),
1165 PROC(RENAME, renameargs, renameres, 0),
1166 PROC(LINK, linkargs, linkres, 0),
1167 PROC(READDIR, readdirargs, readdirres, 3),
1168 PROC(READDIRPLUS, readdirargs, readdirres, 3),
1169 PROC(FSSTAT, fhandle, fsstatres, 0),
1170 PROC(FSINFO, fhandle, fsinfores, 0),
1171 PROC(PATHCONF, fhandle, pathconfres, 0),
1172 PROC(COMMIT, commitargs, commitres, 5),
1175 struct rpc_version nfs_version3 = {
1177 .nrprocs = ARRAY_SIZE(nfs3_procedures),
1178 .procs = nfs3_procedures
1181 #ifdef CONFIG_NFS_V3_ACL
1182 static struct rpc_procinfo nfs3_acl_procedures[] = {
1183 [ACLPROC3_GETACL] = {
1184 .p_proc = ACLPROC3_GETACL,
1185 .p_encode = (kxdrproc_t) nfs3_xdr_getaclargs,
1186 .p_decode = (kxdrproc_t) nfs3_xdr_getaclres,
1187 .p_arglen = ACL3_getaclargs_sz,
1188 .p_replen = ACL3_getaclres_sz,
1192 [ACLPROC3_SETACL] = {
1193 .p_proc = ACLPROC3_SETACL,
1194 .p_encode = (kxdrproc_t) nfs3_xdr_setaclargs,
1195 .p_decode = (kxdrproc_t) nfs3_xdr_setaclres,
1196 .p_arglen = ACL3_setaclargs_sz,
1197 .p_replen = ACL3_setaclres_sz,
1203 struct rpc_version nfsacl_version3 = {
1205 .nrprocs = sizeof(nfs3_acl_procedures)/
1206 sizeof(nfs3_acl_procedures[0]),
1207 .procs = nfs3_acl_procedures,
1209 #endif /* CONFIG_NFS_V3_ACL */