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/vserver/xid.h>
26 #define NFSDBG_FACILITY NFSDBG_XDR
28 /* Mapping from NFS error code to "errno" error code. */
29 #define errno_NFSERR_IO EIO
31 extern int nfs_stat_to_errno(int);
34 * Declare the space requirements for NFS arguments and replies as
35 * number of 32bit-words
37 #define NFS3_fhandle_sz (1+16)
38 #define NFS3_fh_sz (NFS3_fhandle_sz) /* shorthand */
39 #define NFS3_sattr_sz (15)
40 #define NFS3_filename_sz (1+(NFS3_MAXNAMLEN>>2))
41 #define NFS3_path_sz (1+(NFS3_MAXPATHLEN>>2))
42 #define NFS3_fattr_sz (21)
43 #define NFS3_wcc_attr_sz (6)
44 #define NFS3_pre_op_attr_sz (1+NFS3_wcc_attr_sz)
45 #define NFS3_post_op_attr_sz (1+NFS3_fattr_sz)
46 #define NFS3_wcc_data_sz (NFS3_pre_op_attr_sz+NFS3_post_op_attr_sz)
47 #define NFS3_fsstat_sz
48 #define NFS3_fsinfo_sz
49 #define NFS3_pathconf_sz
50 #define NFS3_entry_sz (NFS3_filename_sz+3)
52 #define NFS3_sattrargs_sz (NFS3_fh_sz+NFS3_sattr_sz+3)
53 #define NFS3_diropargs_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+NFS3_path_sz+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_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)
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)
84 * Map file type to S_IFMT bits
88 unsigned int nfs2type;
102 * Common NFS XDR functions as inlines
105 xdr_encode_fhandle(u32 *p, struct nfs_fh *fh)
107 return xdr_encode_array(p, fh->data, fh->size);
111 xdr_decode_fhandle(u32 *p, struct nfs_fh *fh)
114 * Zero all nonused bytes
116 memset((u8 *)fh, 0, sizeof(*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.
128 xdr_encode_time3(u32 *p, struct timespec *timep)
130 *p++ = htonl(timep->tv_sec);
131 *p++ = htonl(timep->tv_nsec);
136 xdr_decode_time3(u32 *p, struct timespec *timep)
138 timep->tv_sec = ntohl(*p++);
139 timep->tv_nsec = ntohl(*p++);
144 xdr_decode_fattr(u32 *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_u.nfs3);
169 p = xdr_decode_hyper(p, &fattr->fileid);
170 p = xdr_decode_time3(p, &fattr->atime);
171 p = xdr_decode_time3(p, &fattr->mtime);
172 p = xdr_decode_time3(p, &fattr->ctime);
174 /* Update the mode bits */
175 fattr->valid |= (NFS_ATTR_FATTR | NFS_ATTR_FATTR_V3);
176 fattr->timestamp = jiffies;
181 xdr_encode_sattr(u32 *p, struct iattr *attr, int tagxid)
183 if (attr->ia_valid & ATTR_MODE) {
185 *p++ = htonl(attr->ia_mode);
189 if (attr->ia_valid & ATTR_UID ||
190 (tagxid && (attr->ia_valid & ATTR_XID))) {
192 *p++ = htonl(XIDINO_UID(tagxid, attr->ia_uid, attr->ia_xid));
196 if (attr->ia_valid & ATTR_GID ||
197 (tagxid && (attr->ia_valid & ATTR_XID))) {
199 *p++ = htonl(XIDINO_GID(tagxid, attr->ia_gid, attr->ia_xid));
203 if (attr->ia_valid & ATTR_SIZE) {
205 p = xdr_encode_hyper(p, (__u64) attr->ia_size);
209 if (attr->ia_valid & ATTR_ATIME_SET) {
211 p = xdr_encode_time3(p, &attr->ia_atime);
212 } else if (attr->ia_valid & ATTR_ATIME) {
217 if (attr->ia_valid & ATTR_MTIME_SET) {
219 p = xdr_encode_time3(p, &attr->ia_mtime);
220 } else if (attr->ia_valid & ATTR_MTIME) {
229 xdr_decode_wcc_attr(u32 *p, struct nfs_fattr *fattr)
231 p = xdr_decode_hyper(p, &fattr->pre_size);
232 p = xdr_decode_time3(p, &fattr->pre_mtime);
233 p = xdr_decode_time3(p, &fattr->pre_ctime);
234 fattr->valid |= NFS_ATTR_WCC;
239 xdr_decode_post_op_attr(u32 *p, struct nfs_fattr *fattr)
242 p = xdr_decode_fattr(p, fattr);
247 xdr_decode_pre_op_attr(u32 *p, struct nfs_fattr *fattr)
250 return xdr_decode_wcc_attr(p, fattr);
256 xdr_decode_wcc_data(u32 *p, struct nfs_fattr *fattr)
258 p = xdr_decode_pre_op_attr(p, fattr);
259 return xdr_decode_post_op_attr(p, fattr);
263 * NFS encode functions
267 * Encode file handle argument
270 nfs3_xdr_fhandle(struct rpc_rqst *req, u32 *p, struct nfs_fh *fh)
272 p = xdr_encode_fhandle(p, fh);
273 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
278 * Encode SETATTR arguments
281 nfs3_xdr_sattrargs(struct rpc_rqst *req, u32 *p, struct nfs3_sattrargs *args)
283 p = xdr_encode_fhandle(p, args->fh);
284 p = xdr_encode_sattr(p, args->sattr,
285 req->rq_task->tk_client->cl_tagxid);
286 *p++ = htonl(args->guard);
288 p = xdr_encode_time3(p, &args->guardtime);
289 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
294 * Encode directory ops argument
297 nfs3_xdr_diropargs(struct rpc_rqst *req, u32 *p, struct nfs3_diropargs *args)
299 p = xdr_encode_fhandle(p, args->fh);
300 p = xdr_encode_array(p, args->name, args->len);
301 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
306 * Encode access() argument
309 nfs3_xdr_accessargs(struct rpc_rqst *req, u32 *p, struct nfs3_accessargs *args)
311 p = xdr_encode_fhandle(p, args->fh);
312 *p++ = htonl(args->access);
313 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
318 * Arguments to a READ call. Since we read data directly into the page
319 * cache, we also set up the reply iovec here so that iov[1] points
320 * exactly to the page we want to fetch.
323 nfs3_xdr_readargs(struct rpc_rqst *req, u32 *p, struct nfs_readargs *args)
325 struct rpc_auth *auth = req->rq_task->tk_auth;
327 u32 count = args->count;
329 p = xdr_encode_fhandle(p, args->fh);
330 p = xdr_encode_hyper(p, args->offset);
332 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
334 /* Inline the page array */
335 replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS3_readres_sz) << 2;
336 xdr_inline_pages(&req->rq_rcv_buf, replen,
337 args->pages, args->pgbase, count);
342 * Write arguments. Splice the buffer to be written into the iovec.
345 nfs3_xdr_writeargs(struct rpc_rqst *req, u32 *p, struct nfs_writeargs *args)
347 struct xdr_buf *sndbuf = &req->rq_snd_buf;
348 u32 count = args->count;
350 p = xdr_encode_fhandle(p, args->fh);
351 p = xdr_encode_hyper(p, args->offset);
353 *p++ = htonl(args->stable);
355 sndbuf->len = xdr_adjust_iovec(sndbuf->head, p);
357 /* Copy the page array */
358 xdr_encode_pages(sndbuf, args->pages, args->pgbase, count);
363 * Encode CREATE arguments
366 nfs3_xdr_createargs(struct rpc_rqst *req, u32 *p, struct nfs3_createargs *args)
368 p = xdr_encode_fhandle(p, args->fh);
369 p = xdr_encode_array(p, args->name, args->len);
371 *p++ = htonl(args->createmode);
372 if (args->createmode == NFS3_CREATE_EXCLUSIVE) {
373 *p++ = args->verifier[0];
374 *p++ = args->verifier[1];
376 p = xdr_encode_sattr(p, args->sattr,
377 req->rq_task->tk_client->cl_tagxid);
379 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
384 * Encode MKDIR arguments
387 nfs3_xdr_mkdirargs(struct rpc_rqst *req, u32 *p, struct nfs3_mkdirargs *args)
389 p = xdr_encode_fhandle(p, args->fh);
390 p = xdr_encode_array(p, args->name, args->len);
391 p = xdr_encode_sattr(p, args->sattr,
392 req->rq_task->tk_client->cl_tagxid);
393 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
398 * Encode SYMLINK arguments
401 nfs3_xdr_symlinkargs(struct rpc_rqst *req, u32 *p, struct nfs3_symlinkargs *args)
403 p = xdr_encode_fhandle(p, args->fromfh);
404 p = xdr_encode_array(p, args->fromname, args->fromlen);
405 p = xdr_encode_sattr(p, args->sattr,
406 req->rq_task->tk_client->cl_tagxid);
407 p = xdr_encode_array(p, args->topath, args->tolen);
408 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
413 * Encode MKNOD arguments
416 nfs3_xdr_mknodargs(struct rpc_rqst *req, u32 *p, struct nfs3_mknodargs *args)
418 p = xdr_encode_fhandle(p, args->fh);
419 p = xdr_encode_array(p, args->name, args->len);
420 *p++ = htonl(args->type);
421 p = xdr_encode_sattr(p, args->sattr,
422 req->rq_task->tk_client->cl_tagxid);
423 if (args->type == NF3CHR || args->type == NF3BLK) {
424 *p++ = htonl(MAJOR(args->rdev));
425 *p++ = htonl(MINOR(args->rdev));
428 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
433 * Encode RENAME arguments
436 nfs3_xdr_renameargs(struct rpc_rqst *req, u32 *p, struct nfs3_renameargs *args)
438 p = xdr_encode_fhandle(p, args->fromfh);
439 p = xdr_encode_array(p, args->fromname, args->fromlen);
440 p = xdr_encode_fhandle(p, args->tofh);
441 p = xdr_encode_array(p, args->toname, args->tolen);
442 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
447 * Encode LINK arguments
450 nfs3_xdr_linkargs(struct rpc_rqst *req, u32 *p, struct nfs3_linkargs *args)
452 p = xdr_encode_fhandle(p, args->fromfh);
453 p = xdr_encode_fhandle(p, args->tofh);
454 p = xdr_encode_array(p, args->toname, args->tolen);
455 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
460 * Encode arguments to readdir call
463 nfs3_xdr_readdirargs(struct rpc_rqst *req, u32 *p, struct nfs3_readdirargs *args)
465 struct rpc_auth *auth = req->rq_task->tk_auth;
467 u32 count = args->count;
469 p = xdr_encode_fhandle(p, args->fh);
470 p = xdr_encode_hyper(p, args->cookie);
471 *p++ = args->verf[0];
472 *p++ = args->verf[1];
474 /* readdirplus: need dircount + buffer size.
475 * We just make sure we make dircount big enough */
476 *p++ = htonl(count >> 3);
479 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
481 /* Inline the page array */
482 replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS3_readdirres_sz) << 2;
483 xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, 0, count);
488 * Decode the result of a readdir call.
489 * We just check for syntactical correctness.
492 nfs3_xdr_readdirres(struct rpc_rqst *req, u32 *p, struct nfs3_readdirres *res)
494 struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
495 struct kvec *iov = rcvbuf->head;
499 unsigned int len, pglen;
500 u32 *entry, *end, *kaddr;
502 status = ntohl(*p++);
503 /* Decode post_op_attrs */
504 p = xdr_decode_post_op_attr(p, res->dir_attr);
506 return -nfs_stat_to_errno(status);
507 /* Decode verifier cookie */
515 hdrlen = (u8 *) p - (u8 *) iov->iov_base;
516 if (iov->iov_len < hdrlen) {
517 printk(KERN_WARNING "NFS: READDIR reply header overflowed:"
518 "length %d > %Zu\n", hdrlen, iov->iov_len);
519 return -errno_NFSERR_IO;
520 } else if (iov->iov_len != hdrlen) {
521 dprintk("NFS: READDIR header is short. iovec will be shifted.\n");
522 xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen);
525 pglen = rcvbuf->page_len;
526 recvd = rcvbuf->len - hdrlen;
529 page = rcvbuf->pages;
530 kaddr = p = (u32 *)kmap_atomic(*page, KM_USER0);
531 end = (u32 *)((char *)p + pglen);
533 for (nr = 0; *p++; nr++) {
536 p += 2; /* inode # */
537 len = ntohl(*p++); /* string length */
538 p += XDR_QUADLEN(len) + 2; /* name + cookie */
539 if (len > NFS3_MAXNAMLEN) {
540 printk(KERN_WARNING "NFS: giant filename in readdir (len %x)!\n",
559 if (len > NFS3_FHSIZE) {
560 printk(KERN_WARNING "NFS: giant filehandle in "
561 "readdir (len %x)!\n", len);
564 p += XDR_QUADLEN(len);
572 if (!nr && (entry[0] != 0 || entry[1] == 0))
575 kunmap_atomic(kaddr, KM_USER0);
578 entry[0] = entry[1] = 0;
579 /* truncate listing ? */
581 printk(KERN_NOTICE "NFS: readdir reply truncated!\n");
586 nr = -errno_NFSERR_IO;
591 nfs3_decode_dirent(u32 *p, struct nfs_entry *entry, int plus)
593 struct nfs_entry old = *entry;
597 return ERR_PTR(-EAGAIN);
599 return ERR_PTR(-EBADCOOKIE);
602 p = xdr_decode_hyper(p, &entry->ino);
603 entry->len = ntohl(*p++);
604 entry->name = (const char *) p;
605 p += XDR_QUADLEN(entry->len);
606 entry->prev_cookie = entry->cookie;
607 p = xdr_decode_hyper(p, &entry->cookie);
610 entry->fattr->valid = 0;
611 p = xdr_decode_post_op_attr(p, entry->fattr);
612 /* In fact, a post_op_fh3: */
614 p = xdr_decode_fhandle(p, entry->fh);
615 /* Ugh -- server reply was truncated */
617 dprintk("NFS: FH truncated\n");
619 return ERR_PTR(-EAGAIN);
622 memset((u8*)(entry->fh), 0, sizeof(*entry->fh));
625 entry->eof = !p[0] && p[1];
630 * Encode COMMIT arguments
633 nfs3_xdr_commitargs(struct rpc_rqst *req, u32 *p, struct nfs_writeargs *args)
635 p = xdr_encode_fhandle(p, args->fh);
636 p = xdr_encode_hyper(p, args->offset);
637 *p++ = htonl(args->count);
638 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
643 * NFS XDR decode functions
647 * Decode attrstat reply.
650 nfs3_xdr_attrstat(struct rpc_rqst *req, u32 *p, struct nfs_fattr *fattr)
654 if ((status = ntohl(*p++)))
655 return -nfs_stat_to_errno(status);
656 xdr_decode_fattr(p, fattr);
661 * Decode status+wcc_data reply
662 * SATTR, REMOVE, RMDIR
665 nfs3_xdr_wccstat(struct rpc_rqst *req, u32 *p, struct nfs_fattr *fattr)
669 if ((status = ntohl(*p++)))
670 status = -nfs_stat_to_errno(status);
671 xdr_decode_wcc_data(p, fattr);
676 * Decode LOOKUP reply
679 nfs3_xdr_lookupres(struct rpc_rqst *req, u32 *p, struct nfs3_diropres *res)
683 if ((status = ntohl(*p++))) {
684 status = -nfs_stat_to_errno(status);
686 if (!(p = xdr_decode_fhandle(p, res->fh)))
687 return -errno_NFSERR_IO;
688 p = xdr_decode_post_op_attr(p, res->fattr);
690 xdr_decode_post_op_attr(p, res->dir_attr);
695 * Decode ACCESS reply
698 nfs3_xdr_accessres(struct rpc_rqst *req, u32 *p, struct nfs3_accessres *res)
700 int status = ntohl(*p++);
702 p = xdr_decode_post_op_attr(p, res->fattr);
704 return -nfs_stat_to_errno(status);
705 res->access = ntohl(*p++);
710 nfs3_xdr_readlinkargs(struct rpc_rqst *req, u32 *p, struct nfs3_readlinkargs *args)
712 struct rpc_auth *auth = req->rq_task->tk_auth;
713 unsigned int count = args->count - 5;
716 p = xdr_encode_fhandle(p, args->fh);
717 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
719 /* Inline the page array */
720 replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS3_readlinkres_sz) << 2;
721 xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, 0, count);
726 * Decode READLINK reply
729 nfs3_xdr_readlinkres(struct rpc_rqst *req, u32 *p, struct nfs_fattr *fattr)
731 struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
732 struct kvec *iov = rcvbuf->head;
738 status = ntohl(*p++);
739 p = xdr_decode_post_op_attr(p, fattr);
742 return -nfs_stat_to_errno(status);
744 hdrlen = (u8 *) p - (u8 *) iov->iov_base;
745 if (iov->iov_len > hdrlen) {
746 dprintk("NFS: READLINK header is short. iovec will be shifted.\n");
747 xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen);
750 strlen = (u32*)kmap_atomic(rcvbuf->pages[0], KM_USER0);
751 /* Convert length of symlink */
752 len = ntohl(*strlen);
753 if (len > rcvbuf->page_len) {
754 dprintk(KERN_WARNING "nfs: server returned giant symlink!\n");
755 kunmap_atomic(strlen, KM_USER0);
756 return -ENAMETOOLONG;
759 /* NULL terminate the string we got */
760 string = (char *)(strlen + 1);
762 kunmap_atomic(strlen, KM_USER0);
770 nfs3_xdr_readres(struct rpc_rqst *req, u32 *p, struct nfs_readres *res)
772 struct kvec *iov = req->rq_rcv_buf.head;
773 int status, count, ocount, recvd, hdrlen;
775 status = ntohl(*p++);
776 p = xdr_decode_post_op_attr(p, res->fattr);
779 return -nfs_stat_to_errno(status);
781 /* Decode reply could and EOF flag. NFSv3 is somewhat redundant
782 * in that it puts the count both in the res struct and in the
783 * opaque data count. */
785 res->eof = ntohl(*p++);
786 ocount = ntohl(*p++);
788 if (ocount != count) {
789 printk(KERN_WARNING "NFS: READ count doesn't match RPC opaque count.\n");
790 return -errno_NFSERR_IO;
793 hdrlen = (u8 *) p - (u8 *) iov->iov_base;
794 if (iov->iov_len < hdrlen) {
795 printk(KERN_WARNING "NFS: READ reply header overflowed:"
796 "length %d > %Zu\n", hdrlen, iov->iov_len);
797 return -errno_NFSERR_IO;
798 } else if (iov->iov_len != hdrlen) {
799 dprintk("NFS: READ header is short. iovec will be shifted.\n");
800 xdr_shift_buf(&req->rq_rcv_buf, iov->iov_len - hdrlen);
803 recvd = req->rq_rcv_buf.len - hdrlen;
805 printk(KERN_WARNING "NFS: server cheating in read reply: "
806 "count %d > recvd %d\n", count, recvd);
811 if (count < res->count)
818 * Decode WRITE response
821 nfs3_xdr_writeres(struct rpc_rqst *req, u32 *p, struct nfs_writeres *res)
825 status = ntohl(*p++);
826 p = xdr_decode_wcc_data(p, res->fattr);
829 return -nfs_stat_to_errno(status);
831 res->count = ntohl(*p++);
832 res->verf->committed = (enum nfs3_stable_how)ntohl(*p++);
833 res->verf->verifier[0] = *p++;
834 res->verf->verifier[1] = *p++;
840 * Decode a CREATE response
843 nfs3_xdr_createres(struct rpc_rqst *req, u32 *p, struct nfs3_diropres *res)
847 status = ntohl(*p++);
850 if (!(p = xdr_decode_fhandle(p, res->fh)))
851 return -errno_NFSERR_IO;
852 p = xdr_decode_post_op_attr(p, res->fattr);
854 memset(res->fh, 0, sizeof(*res->fh));
855 /* Do decode post_op_attr but set it to NULL */
856 p = xdr_decode_post_op_attr(p, res->fattr);
857 res->fattr->valid = 0;
860 status = -nfs_stat_to_errno(status);
862 p = xdr_decode_wcc_data(p, res->dir_attr);
867 * Decode RENAME reply
870 nfs3_xdr_renameres(struct rpc_rqst *req, u32 *p, struct nfs3_renameres *res)
874 if ((status = ntohl(*p++)) != 0)
875 status = -nfs_stat_to_errno(status);
876 p = xdr_decode_wcc_data(p, res->fromattr);
877 p = xdr_decode_wcc_data(p, res->toattr);
885 nfs3_xdr_linkres(struct rpc_rqst *req, u32 *p, struct nfs3_linkres *res)
889 if ((status = ntohl(*p++)) != 0)
890 status = -nfs_stat_to_errno(status);
891 p = xdr_decode_post_op_attr(p, res->fattr);
892 p = xdr_decode_wcc_data(p, res->dir_attr);
897 * Decode FSSTAT reply
900 nfs3_xdr_fsstatres(struct rpc_rqst *req, u32 *p, struct nfs_fsstat *res)
904 status = ntohl(*p++);
906 p = xdr_decode_post_op_attr(p, res->fattr);
908 return -nfs_stat_to_errno(status);
910 p = xdr_decode_hyper(p, &res->tbytes);
911 p = xdr_decode_hyper(p, &res->fbytes);
912 p = xdr_decode_hyper(p, &res->abytes);
913 p = xdr_decode_hyper(p, &res->tfiles);
914 p = xdr_decode_hyper(p, &res->ffiles);
915 p = xdr_decode_hyper(p, &res->afiles);
917 /* ignore invarsec */
922 * Decode FSINFO reply
925 nfs3_xdr_fsinfores(struct rpc_rqst *req, u32 *p, struct nfs_fsinfo *res)
929 status = ntohl(*p++);
931 p = xdr_decode_post_op_attr(p, res->fattr);
933 return -nfs_stat_to_errno(status);
935 res->rtmax = ntohl(*p++);
936 res->rtpref = ntohl(*p++);
937 res->rtmult = ntohl(*p++);
938 res->wtmax = ntohl(*p++);
939 res->wtpref = ntohl(*p++);
940 res->wtmult = ntohl(*p++);
941 res->dtpref = ntohl(*p++);
942 p = xdr_decode_hyper(p, &res->maxfilesize);
944 /* ignore time_delta and properties */
950 * Decode PATHCONF reply
953 nfs3_xdr_pathconfres(struct rpc_rqst *req, u32 *p, struct nfs_pathconf *res)
957 status = ntohl(*p++);
959 p = xdr_decode_post_op_attr(p, res->fattr);
961 return -nfs_stat_to_errno(status);
962 res->max_link = ntohl(*p++);
963 res->max_namelen = ntohl(*p++);
965 /* ignore remaining fields */
970 * Decode COMMIT reply
973 nfs3_xdr_commitres(struct rpc_rqst *req, u32 *p, struct nfs_writeres *res)
977 status = ntohl(*p++);
978 p = xdr_decode_wcc_data(p, res->fattr);
980 return -nfs_stat_to_errno(status);
982 res->verf->verifier[0] = *p++;
983 res->verf->verifier[1] = *p++;
988 # define MAX(a, b) (((a) > (b))? (a) : (b))
991 #define PROC(proc, argtype, restype, timer) \
992 [NFS3PROC_##proc] = { \
993 .p_proc = NFS3PROC_##proc, \
994 .p_encode = (kxdrproc_t) nfs3_xdr_##argtype, \
995 .p_decode = (kxdrproc_t) nfs3_xdr_##restype, \
996 .p_bufsiz = MAX(NFS3_##argtype##_sz,NFS3_##restype##_sz) << 2, \
1000 struct rpc_procinfo nfs3_procedures[] = {
1001 PROC(GETATTR, fhandle, attrstat, 1),
1002 PROC(SETATTR, sattrargs, wccstat, 0),
1003 PROC(LOOKUP, diropargs, lookupres, 2),
1004 PROC(ACCESS, accessargs, accessres, 1),
1005 PROC(READLINK, readlinkargs, readlinkres, 3),
1006 PROC(READ, readargs, readres, 3),
1007 PROC(WRITE, writeargs, writeres, 4),
1008 PROC(CREATE, createargs, createres, 0),
1009 PROC(MKDIR, mkdirargs, createres, 0),
1010 PROC(SYMLINK, symlinkargs, createres, 0),
1011 PROC(MKNOD, mknodargs, createres, 0),
1012 PROC(REMOVE, diropargs, wccstat, 0),
1013 PROC(RMDIR, diropargs, wccstat, 0),
1014 PROC(RENAME, renameargs, renameres, 0),
1015 PROC(LINK, linkargs, linkres, 0),
1016 PROC(READDIR, readdirargs, readdirres, 3),
1017 PROC(READDIRPLUS, readdirargs, readdirres, 3),
1018 PROC(FSSTAT, fhandle, fsstatres, 0),
1019 PROC(FSINFO, fhandle, fsinfores, 0),
1020 PROC(PATHCONF, fhandle, pathconfres, 0),
1021 PROC(COMMIT, commitargs, commitres, 5),
1024 struct rpc_version nfs_version3 = {
1026 .nrprocs = sizeof(nfs3_procedures)/sizeof(nfs3_procedures[0]),
1027 .procs = nfs3_procedures