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)
183 if (attr->ia_valid & ATTR_MODE) {
185 *p++ = htonl(attr->ia_mode);
189 if (attr->ia_valid & ATTR_UID || attr->ia_valid & ATTR_XID) {
191 *p++ = htonl(XIDINO_UID(attr->ia_uid, attr->ia_xid));
195 if (attr->ia_valid & ATTR_GID || attr->ia_valid & ATTR_XID) {
197 *p++ = htonl(XIDINO_GID(attr->ia_gid, attr->ia_xid));
201 if (attr->ia_valid & ATTR_SIZE) {
203 p = xdr_encode_hyper(p, (__u64) attr->ia_size);
207 if (attr->ia_valid & ATTR_ATIME_SET) {
209 p = xdr_encode_time3(p, &attr->ia_atime);
210 } else if (attr->ia_valid & ATTR_ATIME) {
215 if (attr->ia_valid & ATTR_MTIME_SET) {
217 p = xdr_encode_time3(p, &attr->ia_mtime);
218 } else if (attr->ia_valid & ATTR_MTIME) {
227 xdr_decode_wcc_attr(u32 *p, struct nfs_fattr *fattr)
229 p = xdr_decode_hyper(p, &fattr->pre_size);
230 p = xdr_decode_time3(p, &fattr->pre_mtime);
231 p = xdr_decode_time3(p, &fattr->pre_ctime);
232 fattr->valid |= NFS_ATTR_WCC;
237 xdr_decode_post_op_attr(u32 *p, struct nfs_fattr *fattr)
240 p = xdr_decode_fattr(p, fattr);
245 xdr_decode_pre_op_attr(u32 *p, struct nfs_fattr *fattr)
248 return xdr_decode_wcc_attr(p, fattr);
254 xdr_decode_wcc_data(u32 *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, u32 *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, u32 *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, u32 *p, struct nfs3_diropargs *args)
296 p = xdr_encode_fhandle(p, args->fh);
297 p = xdr_encode_array(p, args->name, args->len);
298 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
303 * Encode access() argument
306 nfs3_xdr_accessargs(struct rpc_rqst *req, u32 *p, struct nfs3_accessargs *args)
308 p = xdr_encode_fhandle(p, args->fh);
309 *p++ = htonl(args->access);
310 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
315 * Arguments to a READ call. Since we read data directly into the page
316 * cache, we also set up the reply iovec here so that iov[1] points
317 * exactly to the page we want to fetch.
320 nfs3_xdr_readargs(struct rpc_rqst *req, u32 *p, struct nfs_readargs *args)
322 struct rpc_auth *auth = req->rq_task->tk_auth;
324 u32 count = args->count;
326 p = xdr_encode_fhandle(p, args->fh);
327 p = xdr_encode_hyper(p, args->offset);
329 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
331 /* Inline the page array */
332 replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS3_readres_sz) << 2;
333 xdr_inline_pages(&req->rq_rcv_buf, replen,
334 args->pages, args->pgbase, count);
339 * Write arguments. Splice the buffer to be written into the iovec.
342 nfs3_xdr_writeargs(struct rpc_rqst *req, u32 *p, struct nfs_writeargs *args)
344 struct xdr_buf *sndbuf = &req->rq_snd_buf;
345 u32 count = args->count;
347 p = xdr_encode_fhandle(p, args->fh);
348 p = xdr_encode_hyper(p, args->offset);
350 *p++ = htonl(args->stable);
352 sndbuf->len = xdr_adjust_iovec(sndbuf->head, p);
354 /* Copy the page array */
355 xdr_encode_pages(sndbuf, args->pages, args->pgbase, count);
360 * Encode CREATE arguments
363 nfs3_xdr_createargs(struct rpc_rqst *req, u32 *p, struct nfs3_createargs *args)
365 p = xdr_encode_fhandle(p, args->fh);
366 p = xdr_encode_array(p, args->name, args->len);
368 *p++ = htonl(args->createmode);
369 if (args->createmode == NFS3_CREATE_EXCLUSIVE) {
370 *p++ = args->verifier[0];
371 *p++ = args->verifier[1];
373 p = xdr_encode_sattr(p, args->sattr);
375 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
380 * Encode MKDIR arguments
383 nfs3_xdr_mkdirargs(struct rpc_rqst *req, u32 *p, struct nfs3_mkdirargs *args)
385 p = xdr_encode_fhandle(p, args->fh);
386 p = xdr_encode_array(p, args->name, args->len);
387 p = xdr_encode_sattr(p, args->sattr);
388 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
393 * Encode SYMLINK arguments
396 nfs3_xdr_symlinkargs(struct rpc_rqst *req, u32 *p, struct nfs3_symlinkargs *args)
398 p = xdr_encode_fhandle(p, args->fromfh);
399 p = xdr_encode_array(p, args->fromname, args->fromlen);
400 p = xdr_encode_sattr(p, args->sattr);
401 p = xdr_encode_array(p, args->topath, args->tolen);
402 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
407 * Encode MKNOD arguments
410 nfs3_xdr_mknodargs(struct rpc_rqst *req, u32 *p, struct nfs3_mknodargs *args)
412 p = xdr_encode_fhandle(p, args->fh);
413 p = xdr_encode_array(p, args->name, args->len);
414 *p++ = htonl(args->type);
415 p = xdr_encode_sattr(p, args->sattr);
416 if (args->type == NF3CHR || args->type == NF3BLK) {
417 *p++ = htonl(MAJOR(args->rdev));
418 *p++ = htonl(MINOR(args->rdev));
421 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
426 * Encode RENAME arguments
429 nfs3_xdr_renameargs(struct rpc_rqst *req, u32 *p, struct nfs3_renameargs *args)
431 p = xdr_encode_fhandle(p, args->fromfh);
432 p = xdr_encode_array(p, args->fromname, args->fromlen);
433 p = xdr_encode_fhandle(p, args->tofh);
434 p = xdr_encode_array(p, args->toname, args->tolen);
435 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
440 * Encode LINK arguments
443 nfs3_xdr_linkargs(struct rpc_rqst *req, u32 *p, struct nfs3_linkargs *args)
445 p = xdr_encode_fhandle(p, args->fromfh);
446 p = xdr_encode_fhandle(p, args->tofh);
447 p = xdr_encode_array(p, args->toname, args->tolen);
448 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
453 * Encode arguments to readdir call
456 nfs3_xdr_readdirargs(struct rpc_rqst *req, u32 *p, struct nfs3_readdirargs *args)
458 struct rpc_auth *auth = req->rq_task->tk_auth;
460 u32 count = args->count;
462 p = xdr_encode_fhandle(p, args->fh);
463 p = xdr_encode_hyper(p, args->cookie);
464 *p++ = args->verf[0];
465 *p++ = args->verf[1];
467 /* readdirplus: need dircount + buffer size.
468 * We just make sure we make dircount big enough */
469 *p++ = htonl(count >> 3);
472 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
474 /* Inline the page array */
475 replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS3_readdirres_sz) << 2;
476 xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, 0, count);
481 * Decode the result of a readdir call.
482 * We just check for syntactical correctness.
485 nfs3_xdr_readdirres(struct rpc_rqst *req, u32 *p, struct nfs3_readdirres *res)
487 struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
488 struct iovec *iov = rcvbuf->head;
492 unsigned int len, pglen;
493 u32 *entry, *end, *kaddr;
495 status = ntohl(*p++);
496 /* Decode post_op_attrs */
497 p = xdr_decode_post_op_attr(p, res->dir_attr);
499 return -nfs_stat_to_errno(status);
500 /* Decode verifier cookie */
508 hdrlen = (u8 *) p - (u8 *) iov->iov_base;
509 if (iov->iov_len < hdrlen) {
510 printk(KERN_WARNING "NFS: READDIR reply header overflowed:"
511 "length %d > %Zu\n", hdrlen, iov->iov_len);
512 return -errno_NFSERR_IO;
513 } else if (iov->iov_len != hdrlen) {
514 dprintk("NFS: READDIR header is short. iovec will be shifted.\n");
515 xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen);
518 pglen = rcvbuf->page_len;
519 recvd = rcvbuf->len - hdrlen;
522 page = rcvbuf->pages;
523 kaddr = p = (u32 *)kmap_atomic(*page, KM_USER0);
524 end = (u32 *)((char *)p + pglen);
526 for (nr = 0; *p++; nr++) {
529 p += 2; /* inode # */
530 len = ntohl(*p++); /* string length */
531 p += XDR_QUADLEN(len) + 2; /* name + cookie */
532 if (len > NFS3_MAXNAMLEN) {
533 printk(KERN_WARNING "NFS: giant filename in readdir (len %x)!\n",
552 if (len > NFS3_FHSIZE) {
553 printk(KERN_WARNING "NFS: giant filehandle in "
554 "readdir (len %x)!\n", len);
557 p += XDR_QUADLEN(len);
565 if (!nr && (entry[0] != 0 || entry[1] == 0))
568 kunmap_atomic(kaddr, KM_USER0);
571 entry[0] = entry[1] = 0;
572 /* truncate listing ? */
574 printk(KERN_NOTICE "NFS: readdir reply truncated!\n");
579 nr = -errno_NFSERR_IO;
584 nfs3_decode_dirent(u32 *p, struct nfs_entry *entry, int plus)
586 struct nfs_entry old = *entry;
590 return ERR_PTR(-EAGAIN);
592 return ERR_PTR(-EBADCOOKIE);
595 p = xdr_decode_hyper(p, &entry->ino);
596 entry->len = ntohl(*p++);
597 entry->name = (const char *) p;
598 p += XDR_QUADLEN(entry->len);
599 entry->prev_cookie = entry->cookie;
600 p = xdr_decode_hyper(p, &entry->cookie);
603 entry->fattr->valid = 0;
604 p = xdr_decode_post_op_attr(p, entry->fattr);
605 /* In fact, a post_op_fh3: */
607 p = xdr_decode_fhandle(p, entry->fh);
608 /* Ugh -- server reply was truncated */
610 dprintk("NFS: FH truncated\n");
612 return ERR_PTR(-EAGAIN);
615 memset((u8*)(entry->fh), 0, sizeof(*entry->fh));
618 entry->eof = !p[0] && p[1];
623 * Encode COMMIT arguments
626 nfs3_xdr_commitargs(struct rpc_rqst *req, u32 *p, struct nfs_writeargs *args)
628 p = xdr_encode_fhandle(p, args->fh);
629 p = xdr_encode_hyper(p, args->offset);
630 *p++ = htonl(args->count);
631 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
636 * NFS XDR decode functions
640 * Decode attrstat reply.
643 nfs3_xdr_attrstat(struct rpc_rqst *req, u32 *p, struct nfs_fattr *fattr)
647 if ((status = ntohl(*p++)))
648 return -nfs_stat_to_errno(status);
649 xdr_decode_fattr(p, fattr);
654 * Decode status+wcc_data reply
655 * SATTR, REMOVE, RMDIR
658 nfs3_xdr_wccstat(struct rpc_rqst *req, u32 *p, struct nfs_fattr *fattr)
662 if ((status = ntohl(*p++)))
663 status = -nfs_stat_to_errno(status);
664 xdr_decode_wcc_data(p, fattr);
669 * Decode LOOKUP reply
672 nfs3_xdr_lookupres(struct rpc_rqst *req, u32 *p, struct nfs3_diropres *res)
676 if ((status = ntohl(*p++))) {
677 status = -nfs_stat_to_errno(status);
679 if (!(p = xdr_decode_fhandle(p, res->fh)))
680 return -errno_NFSERR_IO;
681 p = xdr_decode_post_op_attr(p, res->fattr);
683 xdr_decode_post_op_attr(p, res->dir_attr);
688 * Decode ACCESS reply
691 nfs3_xdr_accessres(struct rpc_rqst *req, u32 *p, struct nfs3_accessres *res)
693 int status = ntohl(*p++);
695 p = xdr_decode_post_op_attr(p, res->fattr);
697 return -nfs_stat_to_errno(status);
698 res->access = ntohl(*p++);
703 nfs3_xdr_readlinkargs(struct rpc_rqst *req, u32 *p, struct nfs3_readlinkargs *args)
705 struct rpc_auth *auth = req->rq_task->tk_auth;
706 unsigned int count = args->count - 5;
709 p = xdr_encode_fhandle(p, args->fh);
710 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
712 /* Inline the page array */
713 replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS3_readlinkres_sz) << 2;
714 xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, 0, count);
719 * Decode READLINK reply
722 nfs3_xdr_readlinkres(struct rpc_rqst *req, u32 *p, struct nfs_fattr *fattr)
724 struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
725 struct iovec *iov = rcvbuf->head;
731 status = ntohl(*p++);
732 p = xdr_decode_post_op_attr(p, fattr);
735 return -nfs_stat_to_errno(status);
737 hdrlen = (u8 *) p - (u8 *) iov->iov_base;
738 if (iov->iov_len > hdrlen) {
739 dprintk("NFS: READLINK header is short. iovec will be shifted.\n");
740 xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen);
743 strlen = (u32*)kmap_atomic(rcvbuf->pages[0], KM_USER0);
744 /* Convert length of symlink */
745 len = ntohl(*strlen);
746 if (len > rcvbuf->page_len) {
747 dprintk(KERN_WARNING "nfs: server returned giant symlink!\n");
748 kunmap_atomic(strlen, KM_USER0);
749 return -ENAMETOOLONG;
752 /* NULL terminate the string we got */
753 string = (char *)(strlen + 1);
755 kunmap_atomic(strlen, KM_USER0);
763 nfs3_xdr_readres(struct rpc_rqst *req, u32 *p, struct nfs_readres *res)
765 struct iovec *iov = req->rq_rcv_buf.head;
766 int status, count, ocount, recvd, hdrlen;
768 status = ntohl(*p++);
769 p = xdr_decode_post_op_attr(p, res->fattr);
772 return -nfs_stat_to_errno(status);
774 /* Decode reply could and EOF flag. NFSv3 is somewhat redundant
775 * in that it puts the count both in the res struct and in the
776 * opaque data count. */
778 res->eof = ntohl(*p++);
779 ocount = ntohl(*p++);
781 if (ocount != count) {
782 printk(KERN_WARNING "NFS: READ count doesn't match RPC opaque count.\n");
783 return -errno_NFSERR_IO;
786 hdrlen = (u8 *) p - (u8 *) iov->iov_base;
787 if (iov->iov_len < hdrlen) {
788 printk(KERN_WARNING "NFS: READ reply header overflowed:"
789 "length %d > %Zu\n", hdrlen, iov->iov_len);
790 return -errno_NFSERR_IO;
791 } else if (iov->iov_len != hdrlen) {
792 dprintk("NFS: READ header is short. iovec will be shifted.\n");
793 xdr_shift_buf(&req->rq_rcv_buf, iov->iov_len - hdrlen);
796 recvd = req->rq_rcv_buf.len - hdrlen;
798 printk(KERN_WARNING "NFS: server cheating in read reply: "
799 "count %d > recvd %d\n", count, recvd);
804 if (count < res->count)
811 * Decode WRITE response
814 nfs3_xdr_writeres(struct rpc_rqst *req, u32 *p, struct nfs_writeres *res)
818 status = ntohl(*p++);
819 p = xdr_decode_wcc_data(p, res->fattr);
822 return -nfs_stat_to_errno(status);
824 res->count = ntohl(*p++);
825 res->verf->committed = (enum nfs3_stable_how)ntohl(*p++);
826 res->verf->verifier[0] = *p++;
827 res->verf->verifier[1] = *p++;
833 * Decode a CREATE response
836 nfs3_xdr_createres(struct rpc_rqst *req, u32 *p, struct nfs3_diropres *res)
840 status = ntohl(*p++);
843 if (!(p = xdr_decode_fhandle(p, res->fh)))
844 return -errno_NFSERR_IO;
845 p = xdr_decode_post_op_attr(p, res->fattr);
847 memset(res->fh, 0, sizeof(*res->fh));
848 /* Do decode post_op_attr but set it to NULL */
849 p = xdr_decode_post_op_attr(p, res->fattr);
850 res->fattr->valid = 0;
853 status = -nfs_stat_to_errno(status);
855 p = xdr_decode_wcc_data(p, res->dir_attr);
860 * Decode RENAME reply
863 nfs3_xdr_renameres(struct rpc_rqst *req, u32 *p, struct nfs3_renameres *res)
867 if ((status = ntohl(*p++)) != 0)
868 status = -nfs_stat_to_errno(status);
869 p = xdr_decode_wcc_data(p, res->fromattr);
870 p = xdr_decode_wcc_data(p, res->toattr);
878 nfs3_xdr_linkres(struct rpc_rqst *req, u32 *p, struct nfs3_linkres *res)
882 if ((status = ntohl(*p++)) != 0)
883 status = -nfs_stat_to_errno(status);
884 p = xdr_decode_post_op_attr(p, res->fattr);
885 p = xdr_decode_wcc_data(p, res->dir_attr);
890 * Decode FSSTAT reply
893 nfs3_xdr_fsstatres(struct rpc_rqst *req, u32 *p, struct nfs_fsstat *res)
897 status = ntohl(*p++);
899 p = xdr_decode_post_op_attr(p, res->fattr);
901 return -nfs_stat_to_errno(status);
903 p = xdr_decode_hyper(p, &res->tbytes);
904 p = xdr_decode_hyper(p, &res->fbytes);
905 p = xdr_decode_hyper(p, &res->abytes);
906 p = xdr_decode_hyper(p, &res->tfiles);
907 p = xdr_decode_hyper(p, &res->ffiles);
908 p = xdr_decode_hyper(p, &res->afiles);
910 /* ignore invarsec */
915 * Decode FSINFO reply
918 nfs3_xdr_fsinfores(struct rpc_rqst *req, u32 *p, struct nfs_fsinfo *res)
922 status = ntohl(*p++);
924 p = xdr_decode_post_op_attr(p, res->fattr);
926 return -nfs_stat_to_errno(status);
928 res->rtmax = ntohl(*p++);
929 res->rtpref = ntohl(*p++);
930 res->rtmult = ntohl(*p++);
931 res->wtmax = ntohl(*p++);
932 res->wtpref = ntohl(*p++);
933 res->wtmult = ntohl(*p++);
934 res->dtpref = ntohl(*p++);
935 p = xdr_decode_hyper(p, &res->maxfilesize);
937 /* ignore time_delta and properties */
943 * Decode PATHCONF reply
946 nfs3_xdr_pathconfres(struct rpc_rqst *req, u32 *p, struct nfs_pathconf *res)
950 status = ntohl(*p++);
952 p = xdr_decode_post_op_attr(p, res->fattr);
954 return -nfs_stat_to_errno(status);
955 res->max_link = ntohl(*p++);
956 res->max_namelen = ntohl(*p++);
958 /* ignore remaining fields */
963 * Decode COMMIT reply
966 nfs3_xdr_commitres(struct rpc_rqst *req, u32 *p, struct nfs_writeres *res)
970 status = ntohl(*p++);
971 p = xdr_decode_wcc_data(p, res->fattr);
973 return -nfs_stat_to_errno(status);
975 res->verf->verifier[0] = *p++;
976 res->verf->verifier[1] = *p++;
981 # define MAX(a, b) (((a) > (b))? (a) : (b))
984 #define PROC(proc, argtype, restype, timer) \
985 [NFS3PROC_##proc] = { \
986 .p_proc = NFS3PROC_##proc, \
987 .p_encode = (kxdrproc_t) nfs3_xdr_##argtype, \
988 .p_decode = (kxdrproc_t) nfs3_xdr_##restype, \
989 .p_bufsiz = MAX(NFS3_##argtype##_sz,NFS3_##restype##_sz) << 2, \
993 struct rpc_procinfo nfs3_procedures[] = {
994 PROC(GETATTR, fhandle, attrstat, 1),
995 PROC(SETATTR, sattrargs, wccstat, 0),
996 PROC(LOOKUP, diropargs, lookupres, 2),
997 PROC(ACCESS, accessargs, accessres, 1),
998 PROC(READLINK, readlinkargs, readlinkres, 3),
999 PROC(READ, readargs, readres, 3),
1000 PROC(WRITE, writeargs, writeres, 4),
1001 PROC(CREATE, createargs, createres, 0),
1002 PROC(MKDIR, mkdirargs, createres, 0),
1003 PROC(SYMLINK, symlinkargs, createres, 0),
1004 PROC(MKNOD, mknodargs, createres, 0),
1005 PROC(REMOVE, diropargs, wccstat, 0),
1006 PROC(RMDIR, diropargs, wccstat, 0),
1007 PROC(RENAME, renameargs, renameres, 0),
1008 PROC(LINK, linkargs, linkres, 0),
1009 PROC(READDIR, readdirargs, readdirres, 3),
1010 PROC(READDIRPLUS, readdirargs, readdirres, 3),
1011 PROC(FSSTAT, fhandle, fsstatres, 0),
1012 PROC(FSINFO, fhandle, fsinfores, 0),
1013 PROC(PATHCONF, fhandle, pathconfres, 0),
1014 PROC(COMMIT, commitargs, commitres, 5),
1017 struct rpc_version nfs_version3 = {
1019 .nrprocs = sizeof(nfs3_procedures)/sizeof(nfs3_procedures[0]),
1020 .procs = nfs3_procedures