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>
25 #define NFSDBG_FACILITY NFSDBG_XDR
27 /* Mapping from NFS error code to "errno" error code. */
28 #define errno_NFSERR_IO EIO
30 extern int nfs_stat_to_errno(int);
33 * Declare the space requirements for NFS arguments and replies as
34 * number of 32bit-words
36 #define NFS3_fhandle_sz (1+16)
37 #define NFS3_fh_sz (NFS3_fhandle_sz) /* shorthand */
38 #define NFS3_sattr_sz (15)
39 #define NFS3_filename_sz (1+(NFS3_MAXNAMLEN>>2))
40 #define NFS3_path_sz (1+(NFS3_MAXPATHLEN>>2))
41 #define NFS3_fattr_sz (21)
42 #define NFS3_wcc_attr_sz (6)
43 #define NFS3_pre_op_attr_sz (1+NFS3_wcc_attr_sz)
44 #define NFS3_post_op_attr_sz (1+NFS3_fattr_sz)
45 #define NFS3_wcc_data_sz (NFS3_pre_op_attr_sz+NFS3_post_op_attr_sz)
46 #define NFS3_fsstat_sz
47 #define NFS3_fsinfo_sz
48 #define NFS3_pathconf_sz
49 #define NFS3_entry_sz (NFS3_filename_sz+3)
51 #define NFS3_sattrargs_sz (NFS3_fh_sz+NFS3_sattr_sz+3)
52 #define NFS3_diropargs_sz (NFS3_fh_sz+NFS3_filename_sz)
53 #define NFS3_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+NFS3_path_sz+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_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)
83 * Map file type to S_IFMT bits
87 unsigned int nfs2type;
101 * Common NFS XDR functions as inlines
104 xdr_encode_fhandle(u32 *p, struct nfs_fh *fh)
106 return xdr_encode_array(p, fh->data, fh->size);
110 xdr_decode_fhandle(u32 *p, struct nfs_fh *fh)
112 if ((fh->size = ntohl(*p++)) <= NFS3_FHSIZE) {
113 memcpy(fh->data, p, fh->size);
114 return p + XDR_QUADLEN(fh->size);
120 * Encode/decode time.
123 xdr_encode_time3(u32 *p, struct timespec *timep)
125 *p++ = htonl(timep->tv_sec);
126 *p++ = htonl(timep->tv_nsec);
131 xdr_decode_time3(u32 *p, struct timespec *timep)
133 timep->tv_sec = ntohl(*p++);
134 timep->tv_nsec = ntohl(*p++);
139 xdr_decode_fattr(u32 *p, struct nfs_fattr *fattr)
141 unsigned int type, major, minor;
147 fmode = nfs_type2fmt[type].mode;
148 fattr->type = nfs_type2fmt[type].nfs2type;
149 fattr->mode = (ntohl(*p++) & ~S_IFMT) | fmode;
150 fattr->nlink = ntohl(*p++);
151 fattr->uid = ntohl(*p++);
152 fattr->gid = ntohl(*p++);
153 p = xdr_decode_hyper(p, &fattr->size);
154 p = xdr_decode_hyper(p, &fattr->du.nfs3.used);
156 /* Turn remote device info into Linux-specific dev_t */
159 fattr->rdev = MKDEV(major, minor);
160 if (MAJOR(fattr->rdev) != major || MINOR(fattr->rdev) != minor)
163 p = xdr_decode_hyper(p, &fattr->fsid_u.nfs3);
164 p = xdr_decode_hyper(p, &fattr->fileid);
165 p = xdr_decode_time3(p, &fattr->atime);
166 p = xdr_decode_time3(p, &fattr->mtime);
167 p = xdr_decode_time3(p, &fattr->ctime);
169 /* Update the mode bits */
170 fattr->valid |= (NFS_ATTR_FATTR | NFS_ATTR_FATTR_V3);
171 fattr->timestamp = jiffies;
176 xdr_encode_sattr(u32 *p, struct iattr *attr)
178 if (attr->ia_valid & ATTR_MODE) {
180 *p++ = htonl(attr->ia_mode);
184 if (attr->ia_valid & ATTR_UID) {
186 *p++ = htonl(attr->ia_uid);
190 if (attr->ia_valid & ATTR_GID) {
192 *p++ = htonl(attr->ia_gid);
196 if (attr->ia_valid & ATTR_SIZE) {
198 p = xdr_encode_hyper(p, (__u64) attr->ia_size);
202 if (attr->ia_valid & ATTR_ATIME_SET) {
204 p = xdr_encode_time3(p, &attr->ia_atime);
205 } else if (attr->ia_valid & ATTR_ATIME) {
210 if (attr->ia_valid & ATTR_MTIME_SET) {
212 p = xdr_encode_time3(p, &attr->ia_mtime);
213 } else if (attr->ia_valid & ATTR_MTIME) {
222 xdr_decode_wcc_attr(u32 *p, struct nfs_fattr *fattr)
224 p = xdr_decode_hyper(p, &fattr->pre_size);
225 p = xdr_decode_time3(p, &fattr->pre_mtime);
226 p = xdr_decode_time3(p, &fattr->pre_ctime);
227 fattr->valid |= NFS_ATTR_WCC;
232 xdr_decode_post_op_attr(u32 *p, struct nfs_fattr *fattr)
235 p = xdr_decode_fattr(p, fattr);
240 xdr_decode_pre_op_attr(u32 *p, struct nfs_fattr *fattr)
243 return xdr_decode_wcc_attr(p, fattr);
249 xdr_decode_wcc_data(u32 *p, struct nfs_fattr *fattr)
251 p = xdr_decode_pre_op_attr(p, fattr);
252 return xdr_decode_post_op_attr(p, fattr);
256 * NFS encode functions
260 * Encode file handle argument
263 nfs3_xdr_fhandle(struct rpc_rqst *req, u32 *p, struct nfs_fh *fh)
265 p = xdr_encode_fhandle(p, fh);
266 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
271 * Encode SETATTR arguments
274 nfs3_xdr_sattrargs(struct rpc_rqst *req, u32 *p, struct nfs3_sattrargs *args)
276 p = xdr_encode_fhandle(p, args->fh);
277 p = xdr_encode_sattr(p, args->sattr);
278 *p++ = htonl(args->guard);
280 p = xdr_encode_time3(p, &args->guardtime);
281 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
286 * Encode directory ops argument
289 nfs3_xdr_diropargs(struct rpc_rqst *req, u32 *p, struct nfs3_diropargs *args)
291 p = xdr_encode_fhandle(p, args->fh);
292 p = xdr_encode_array(p, args->name, args->len);
293 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
298 * Encode access() argument
301 nfs3_xdr_accessargs(struct rpc_rqst *req, u32 *p, struct nfs3_accessargs *args)
303 p = xdr_encode_fhandle(p, args->fh);
304 *p++ = htonl(args->access);
305 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
310 * Arguments to a READ call. Since we read data directly into the page
311 * cache, we also set up the reply iovec here so that iov[1] points
312 * exactly to the page we want to fetch.
315 nfs3_xdr_readargs(struct rpc_rqst *req, u32 *p, struct nfs_readargs *args)
317 struct rpc_auth *auth = req->rq_task->tk_auth;
319 u32 count = args->count;
321 p = xdr_encode_fhandle(p, args->fh);
322 p = xdr_encode_hyper(p, args->offset);
324 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
326 /* Inline the page array */
327 replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS3_readres_sz) << 2;
328 xdr_inline_pages(&req->rq_rcv_buf, replen,
329 args->pages, args->pgbase, count);
334 * Write arguments. Splice the buffer to be written into the iovec.
337 nfs3_xdr_writeargs(struct rpc_rqst *req, u32 *p, struct nfs_writeargs *args)
339 struct xdr_buf *sndbuf = &req->rq_snd_buf;
340 u32 count = args->count;
342 p = xdr_encode_fhandle(p, args->fh);
343 p = xdr_encode_hyper(p, args->offset);
345 *p++ = htonl(args->stable);
347 sndbuf->len = xdr_adjust_iovec(sndbuf->head, p);
349 /* Copy the page array */
350 xdr_encode_pages(sndbuf, args->pages, args->pgbase, count);
355 * Encode CREATE arguments
358 nfs3_xdr_createargs(struct rpc_rqst *req, u32 *p, struct nfs3_createargs *args)
360 p = xdr_encode_fhandle(p, args->fh);
361 p = xdr_encode_array(p, args->name, args->len);
363 *p++ = htonl(args->createmode);
364 if (args->createmode == NFS3_CREATE_EXCLUSIVE) {
365 *p++ = args->verifier[0];
366 *p++ = args->verifier[1];
368 p = xdr_encode_sattr(p, args->sattr);
370 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
375 * Encode MKDIR arguments
378 nfs3_xdr_mkdirargs(struct rpc_rqst *req, u32 *p, struct nfs3_mkdirargs *args)
380 p = xdr_encode_fhandle(p, args->fh);
381 p = xdr_encode_array(p, args->name, args->len);
382 p = xdr_encode_sattr(p, args->sattr);
383 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
388 * Encode SYMLINK arguments
391 nfs3_xdr_symlinkargs(struct rpc_rqst *req, u32 *p, struct nfs3_symlinkargs *args)
393 p = xdr_encode_fhandle(p, args->fromfh);
394 p = xdr_encode_array(p, args->fromname, args->fromlen);
395 p = xdr_encode_sattr(p, args->sattr);
396 p = xdr_encode_array(p, args->topath, args->tolen);
397 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
402 * Encode MKNOD arguments
405 nfs3_xdr_mknodargs(struct rpc_rqst *req, u32 *p, struct nfs3_mknodargs *args)
407 p = xdr_encode_fhandle(p, args->fh);
408 p = xdr_encode_array(p, args->name, args->len);
409 *p++ = htonl(args->type);
410 p = xdr_encode_sattr(p, args->sattr);
411 if (args->type == NF3CHR || args->type == NF3BLK) {
412 *p++ = htonl(MAJOR(args->rdev));
413 *p++ = htonl(MINOR(args->rdev));
416 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
421 * Encode RENAME arguments
424 nfs3_xdr_renameargs(struct rpc_rqst *req, u32 *p, struct nfs3_renameargs *args)
426 p = xdr_encode_fhandle(p, args->fromfh);
427 p = xdr_encode_array(p, args->fromname, args->fromlen);
428 p = xdr_encode_fhandle(p, args->tofh);
429 p = xdr_encode_array(p, args->toname, args->tolen);
430 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
435 * Encode LINK arguments
438 nfs3_xdr_linkargs(struct rpc_rqst *req, u32 *p, struct nfs3_linkargs *args)
440 p = xdr_encode_fhandle(p, args->fromfh);
441 p = xdr_encode_fhandle(p, args->tofh);
442 p = xdr_encode_array(p, args->toname, args->tolen);
443 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
448 * Encode arguments to readdir call
451 nfs3_xdr_readdirargs(struct rpc_rqst *req, u32 *p, struct nfs3_readdirargs *args)
453 struct rpc_auth *auth = req->rq_task->tk_auth;
455 u32 count = args->count;
457 p = xdr_encode_fhandle(p, args->fh);
458 p = xdr_encode_hyper(p, args->cookie);
459 *p++ = args->verf[0];
460 *p++ = args->verf[1];
462 /* readdirplus: need dircount + buffer size.
463 * We just make sure we make dircount big enough */
464 *p++ = htonl(count >> 3);
467 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
469 /* Inline the page array */
470 replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS3_readdirres_sz) << 2;
471 xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, 0, count);
476 * Decode the result of a readdir call.
477 * We just check for syntactical correctness.
480 nfs3_xdr_readdirres(struct rpc_rqst *req, u32 *p, struct nfs3_readdirres *res)
482 struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
483 struct kvec *iov = rcvbuf->head;
487 unsigned int len, pglen;
488 u32 *entry, *end, *kaddr;
490 status = ntohl(*p++);
491 /* Decode post_op_attrs */
492 p = xdr_decode_post_op_attr(p, res->dir_attr);
494 return -nfs_stat_to_errno(status);
495 /* Decode verifier cookie */
503 hdrlen = (u8 *) p - (u8 *) iov->iov_base;
504 if (iov->iov_len < hdrlen) {
505 printk(KERN_WARNING "NFS: READDIR reply header overflowed:"
506 "length %d > %Zu\n", hdrlen, iov->iov_len);
507 return -errno_NFSERR_IO;
508 } else if (iov->iov_len != hdrlen) {
509 dprintk("NFS: READDIR header is short. iovec will be shifted.\n");
510 xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen);
513 pglen = rcvbuf->page_len;
514 recvd = rcvbuf->len - hdrlen;
517 page = rcvbuf->pages;
518 kaddr = p = (u32 *)kmap_atomic(*page, KM_USER0);
519 end = (u32 *)((char *)p + pglen);
521 for (nr = 0; *p++; nr++) {
524 p += 2; /* inode # */
525 len = ntohl(*p++); /* string length */
526 p += XDR_QUADLEN(len) + 2; /* name + cookie */
527 if (len > NFS3_MAXNAMLEN) {
528 printk(KERN_WARNING "NFS: giant filename in readdir (len %x)!\n",
547 if (len > NFS3_FHSIZE) {
548 printk(KERN_WARNING "NFS: giant filehandle in "
549 "readdir (len %x)!\n", len);
552 p += XDR_QUADLEN(len);
560 if (!nr && (entry[0] != 0 || entry[1] == 0))
563 kunmap_atomic(kaddr, KM_USER0);
566 entry[0] = entry[1] = 0;
567 /* truncate listing ? */
569 printk(KERN_NOTICE "NFS: readdir reply truncated!\n");
574 nr = -errno_NFSERR_IO;
579 nfs3_decode_dirent(u32 *p, struct nfs_entry *entry, int plus)
581 struct nfs_entry old = *entry;
585 return ERR_PTR(-EAGAIN);
587 return ERR_PTR(-EBADCOOKIE);
590 p = xdr_decode_hyper(p, &entry->ino);
591 entry->len = ntohl(*p++);
592 entry->name = (const char *) p;
593 p += XDR_QUADLEN(entry->len);
594 entry->prev_cookie = entry->cookie;
595 p = xdr_decode_hyper(p, &entry->cookie);
598 entry->fattr->valid = 0;
599 p = xdr_decode_post_op_attr(p, entry->fattr);
600 /* In fact, a post_op_fh3: */
602 p = xdr_decode_fhandle(p, entry->fh);
603 /* Ugh -- server reply was truncated */
605 dprintk("NFS: FH truncated\n");
607 return ERR_PTR(-EAGAIN);
610 memset((u8*)(entry->fh), 0, sizeof(*entry->fh));
613 entry->eof = !p[0] && p[1];
618 * Encode COMMIT arguments
621 nfs3_xdr_commitargs(struct rpc_rqst *req, u32 *p, struct nfs_writeargs *args)
623 p = xdr_encode_fhandle(p, args->fh);
624 p = xdr_encode_hyper(p, args->offset);
625 *p++ = htonl(args->count);
626 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
631 * NFS XDR decode functions
635 * Decode attrstat reply.
638 nfs3_xdr_attrstat(struct rpc_rqst *req, u32 *p, struct nfs_fattr *fattr)
642 if ((status = ntohl(*p++)))
643 return -nfs_stat_to_errno(status);
644 xdr_decode_fattr(p, fattr);
649 * Decode status+wcc_data reply
650 * SATTR, REMOVE, RMDIR
653 nfs3_xdr_wccstat(struct rpc_rqst *req, u32 *p, struct nfs_fattr *fattr)
657 if ((status = ntohl(*p++)))
658 status = -nfs_stat_to_errno(status);
659 xdr_decode_wcc_data(p, fattr);
664 * Decode LOOKUP reply
667 nfs3_xdr_lookupres(struct rpc_rqst *req, u32 *p, struct nfs3_diropres *res)
671 if ((status = ntohl(*p++))) {
672 status = -nfs_stat_to_errno(status);
674 if (!(p = xdr_decode_fhandle(p, res->fh)))
675 return -errno_NFSERR_IO;
676 p = xdr_decode_post_op_attr(p, res->fattr);
678 xdr_decode_post_op_attr(p, res->dir_attr);
683 * Decode ACCESS reply
686 nfs3_xdr_accessres(struct rpc_rqst *req, u32 *p, struct nfs3_accessres *res)
688 int status = ntohl(*p++);
690 p = xdr_decode_post_op_attr(p, res->fattr);
692 return -nfs_stat_to_errno(status);
693 res->access = ntohl(*p++);
698 nfs3_xdr_readlinkargs(struct rpc_rqst *req, u32 *p, struct nfs3_readlinkargs *args)
700 struct rpc_auth *auth = req->rq_task->tk_auth;
703 p = xdr_encode_fhandle(p, args->fh);
704 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
706 /* Inline the page array */
707 replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS3_readlinkres_sz) << 2;
708 xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, args->pgbase, args->pglen);
713 * Decode READLINK reply
716 nfs3_xdr_readlinkres(struct rpc_rqst *req, u32 *p, struct nfs_fattr *fattr)
718 struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
719 struct kvec *iov = rcvbuf->head;
720 int hdrlen, len, recvd;
724 status = ntohl(*p++);
725 p = xdr_decode_post_op_attr(p, fattr);
728 return -nfs_stat_to_errno(status);
730 /* Convert length of symlink */
732 if (len >= rcvbuf->page_len || len <= 0) {
733 dprintk(KERN_WARNING "nfs: server returned giant symlink!\n");
734 return -ENAMETOOLONG;
737 hdrlen = (u8 *) p - (u8 *) iov->iov_base;
738 if (iov->iov_len < hdrlen) {
739 printk(KERN_WARNING "NFS: READLINK reply header overflowed:"
740 "length %d > %Zu\n", hdrlen, iov->iov_len);
741 return -errno_NFSERR_IO;
742 } else if (iov->iov_len != hdrlen) {
743 dprintk("NFS: READLINK header is short. iovec will be shifted.\n");
744 xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen);
746 recvd = req->rq_rcv_buf.len - hdrlen;
748 printk(KERN_WARNING "NFS: server cheating in readlink reply: "
749 "count %u > recvd %u\n", len, recvd);
753 /* NULL terminate the string we got */
754 kaddr = (char*)kmap_atomic(rcvbuf->pages[0], KM_USER0);
755 kaddr[len+rcvbuf->page_base] = '\0';
756 kunmap_atomic(kaddr, KM_USER0);
764 nfs3_xdr_readres(struct rpc_rqst *req, u32 *p, struct nfs_readres *res)
766 struct kvec *iov = req->rq_rcv_buf.head;
767 int status, count, ocount, recvd, hdrlen;
769 status = ntohl(*p++);
770 p = xdr_decode_post_op_attr(p, res->fattr);
773 return -nfs_stat_to_errno(status);
775 /* Decode reply could and EOF flag. NFSv3 is somewhat redundant
776 * in that it puts the count both in the res struct and in the
777 * opaque data count. */
779 res->eof = ntohl(*p++);
780 ocount = ntohl(*p++);
782 if (ocount != count) {
783 printk(KERN_WARNING "NFS: READ count doesn't match RPC opaque count.\n");
784 return -errno_NFSERR_IO;
787 hdrlen = (u8 *) p - (u8 *) iov->iov_base;
788 if (iov->iov_len < hdrlen) {
789 printk(KERN_WARNING "NFS: READ reply header overflowed:"
790 "length %d > %Zu\n", hdrlen, iov->iov_len);
791 return -errno_NFSERR_IO;
792 } else if (iov->iov_len != hdrlen) {
793 dprintk("NFS: READ header is short. iovec will be shifted.\n");
794 xdr_shift_buf(&req->rq_rcv_buf, iov->iov_len - hdrlen);
797 recvd = req->rq_rcv_buf.len - hdrlen;
799 printk(KERN_WARNING "NFS: server cheating in read reply: "
800 "count %d > recvd %d\n", count, recvd);
805 if (count < res->count)
812 * Decode WRITE response
815 nfs3_xdr_writeres(struct rpc_rqst *req, u32 *p, struct nfs_writeres *res)
819 status = ntohl(*p++);
820 p = xdr_decode_wcc_data(p, res->fattr);
823 return -nfs_stat_to_errno(status);
825 res->count = ntohl(*p++);
826 res->verf->committed = (enum nfs3_stable_how)ntohl(*p++);
827 res->verf->verifier[0] = *p++;
828 res->verf->verifier[1] = *p++;
834 * Decode a CREATE response
837 nfs3_xdr_createres(struct rpc_rqst *req, u32 *p, struct nfs3_diropres *res)
841 status = ntohl(*p++);
844 if (!(p = xdr_decode_fhandle(p, res->fh)))
845 return -errno_NFSERR_IO;
846 p = xdr_decode_post_op_attr(p, res->fattr);
848 memset(res->fh, 0, sizeof(*res->fh));
849 /* Do decode post_op_attr but set it to NULL */
850 p = xdr_decode_post_op_attr(p, res->fattr);
851 res->fattr->valid = 0;
854 status = -nfs_stat_to_errno(status);
856 p = xdr_decode_wcc_data(p, res->dir_attr);
861 * Decode RENAME reply
864 nfs3_xdr_renameres(struct rpc_rqst *req, u32 *p, struct nfs3_renameres *res)
868 if ((status = ntohl(*p++)) != 0)
869 status = -nfs_stat_to_errno(status);
870 p = xdr_decode_wcc_data(p, res->fromattr);
871 p = xdr_decode_wcc_data(p, res->toattr);
879 nfs3_xdr_linkres(struct rpc_rqst *req, u32 *p, struct nfs3_linkres *res)
883 if ((status = ntohl(*p++)) != 0)
884 status = -nfs_stat_to_errno(status);
885 p = xdr_decode_post_op_attr(p, res->fattr);
886 p = xdr_decode_wcc_data(p, res->dir_attr);
891 * Decode FSSTAT reply
894 nfs3_xdr_fsstatres(struct rpc_rqst *req, u32 *p, struct nfs_fsstat *res)
898 status = ntohl(*p++);
900 p = xdr_decode_post_op_attr(p, res->fattr);
902 return -nfs_stat_to_errno(status);
904 p = xdr_decode_hyper(p, &res->tbytes);
905 p = xdr_decode_hyper(p, &res->fbytes);
906 p = xdr_decode_hyper(p, &res->abytes);
907 p = xdr_decode_hyper(p, &res->tfiles);
908 p = xdr_decode_hyper(p, &res->ffiles);
909 p = xdr_decode_hyper(p, &res->afiles);
911 /* ignore invarsec */
916 * Decode FSINFO reply
919 nfs3_xdr_fsinfores(struct rpc_rqst *req, u32 *p, struct nfs_fsinfo *res)
923 status = ntohl(*p++);
925 p = xdr_decode_post_op_attr(p, res->fattr);
927 return -nfs_stat_to_errno(status);
929 res->rtmax = ntohl(*p++);
930 res->rtpref = ntohl(*p++);
931 res->rtmult = ntohl(*p++);
932 res->wtmax = ntohl(*p++);
933 res->wtpref = ntohl(*p++);
934 res->wtmult = ntohl(*p++);
935 res->dtpref = ntohl(*p++);
936 p = xdr_decode_hyper(p, &res->maxfilesize);
938 /* ignore time_delta and properties */
944 * Decode PATHCONF reply
947 nfs3_xdr_pathconfres(struct rpc_rqst *req, u32 *p, struct nfs_pathconf *res)
951 status = ntohl(*p++);
953 p = xdr_decode_post_op_attr(p, res->fattr);
955 return -nfs_stat_to_errno(status);
956 res->max_link = ntohl(*p++);
957 res->max_namelen = ntohl(*p++);
959 /* ignore remaining fields */
964 * Decode COMMIT reply
967 nfs3_xdr_commitres(struct rpc_rqst *req, u32 *p, struct nfs_writeres *res)
971 status = ntohl(*p++);
972 p = xdr_decode_wcc_data(p, res->fattr);
974 return -nfs_stat_to_errno(status);
976 res->verf->verifier[0] = *p++;
977 res->verf->verifier[1] = *p++;
982 # define MAX(a, b) (((a) > (b))? (a) : (b))
985 #define PROC(proc, argtype, restype, timer) \
986 [NFS3PROC_##proc] = { \
987 .p_proc = NFS3PROC_##proc, \
988 .p_encode = (kxdrproc_t) nfs3_xdr_##argtype, \
989 .p_decode = (kxdrproc_t) nfs3_xdr_##restype, \
990 .p_bufsiz = MAX(NFS3_##argtype##_sz,NFS3_##restype##_sz) << 2, \
994 struct rpc_procinfo nfs3_procedures[] = {
995 PROC(GETATTR, fhandle, attrstat, 1),
996 PROC(SETATTR, sattrargs, wccstat, 0),
997 PROC(LOOKUP, diropargs, lookupres, 2),
998 PROC(ACCESS, accessargs, accessres, 1),
999 PROC(READLINK, readlinkargs, readlinkres, 3),
1000 PROC(READ, readargs, readres, 3),
1001 PROC(WRITE, writeargs, writeres, 4),
1002 PROC(CREATE, createargs, createres, 0),
1003 PROC(MKDIR, mkdirargs, createres, 0),
1004 PROC(SYMLINK, symlinkargs, createres, 0),
1005 PROC(MKNOD, mknodargs, createres, 0),
1006 PROC(REMOVE, diropargs, wccstat, 0),
1007 PROC(RMDIR, diropargs, wccstat, 0),
1008 PROC(RENAME, renameargs, renameres, 0),
1009 PROC(LINK, linkargs, linkres, 0),
1010 PROC(READDIR, readdirargs, readdirres, 3),
1011 PROC(READDIRPLUS, readdirargs, readdirres, 3),
1012 PROC(FSSTAT, fhandle, fsstatres, 0),
1013 PROC(FSINFO, fhandle, fsinfores, 0),
1014 PROC(PATHCONF, fhandle, pathconfres, 0),
1015 PROC(COMMIT, commitargs, commitres, 5),
1018 struct rpc_version nfs_version3 = {
1020 .nrprocs = sizeof(nfs3_procedures)/sizeof(nfs3_procedures[0]),
1021 .procs = nfs3_procedures