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/nfsacl.h>
25 #include <linux/vserver/xid.h>
28 #define NFSDBG_FACILITY NFSDBG_XDR
30 /* Mapping from NFS error code to "errno" error code. */
31 #define errno_NFSERR_IO EIO
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+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+2*(2+5*3))
85 #define ACL3_getaclres_sz (1+NFS3_post_op_attr_sz+1+2*(2+5*3))
86 #define ACL3_setaclres_sz (1+NFS3_post_op_attr_sz)
89 * Map file type to S_IFMT bits
93 unsigned int nfs2type;
101 { S_IFSOCK, NFSOCK },
107 * Common NFS XDR functions as inlines
110 xdr_encode_fhandle(u32 *p, struct nfs_fh *fh)
112 return xdr_encode_array(p, fh->data, fh->size);
116 xdr_decode_fhandle(u32 *p, struct nfs_fh *fh)
118 if ((fh->size = ntohl(*p++)) <= NFS3_FHSIZE) {
119 memcpy(fh->data, p, fh->size);
120 return p + XDR_QUADLEN(fh->size);
126 * Encode/decode time.
129 xdr_encode_time3(u32 *p, struct timespec *timep)
131 *p++ = htonl(timep->tv_sec);
132 *p++ = htonl(timep->tv_nsec);
137 xdr_decode_time3(u32 *p, struct timespec *timep)
139 timep->tv_sec = ntohl(*p++);
140 timep->tv_nsec = ntohl(*p++);
145 xdr_decode_fattr(u32 *p, struct nfs_fattr *fattr)
147 unsigned int type, major, minor;
153 fmode = nfs_type2fmt[type].mode;
154 fattr->type = nfs_type2fmt[type].nfs2type;
155 fattr->mode = (ntohl(*p++) & ~S_IFMT) | fmode;
156 fattr->nlink = ntohl(*p++);
157 fattr->uid = ntohl(*p++);
158 fattr->gid = ntohl(*p++);
159 p = xdr_decode_hyper(p, &fattr->size);
160 p = xdr_decode_hyper(p, &fattr->du.nfs3.used);
162 /* Turn remote device info into Linux-specific dev_t */
165 fattr->rdev = MKDEV(major, minor);
166 if (MAJOR(fattr->rdev) != major || MINOR(fattr->rdev) != minor)
169 p = xdr_decode_hyper(p, &fattr->fsid.major);
170 fattr->fsid.minor = 0;
171 p = xdr_decode_hyper(p, &fattr->fileid);
172 p = xdr_decode_time3(p, &fattr->atime);
173 p = xdr_decode_time3(p, &fattr->mtime);
174 p = xdr_decode_time3(p, &fattr->ctime);
176 /* Update the mode bits */
177 fattr->valid |= (NFS_ATTR_FATTR | NFS_ATTR_FATTR_V3);
182 xdr_encode_sattr(u32 *p, struct iattr *attr, int tagxid)
184 if (attr->ia_valid & ATTR_MODE) {
186 *p++ = htonl(attr->ia_mode & S_IALLUGO);
190 if (attr->ia_valid & ATTR_UID ||
191 (tagxid && (attr->ia_valid & ATTR_XID))) {
193 *p++ = htonl(XIDINO_UID(tagxid, attr->ia_uid, attr->ia_xid));
197 if (attr->ia_valid & ATTR_GID ||
198 (tagxid && (attr->ia_valid & ATTR_XID))) {
200 *p++ = htonl(XIDINO_GID(tagxid, attr->ia_gid, attr->ia_xid));
204 if (attr->ia_valid & ATTR_SIZE) {
206 p = xdr_encode_hyper(p, (__u64) attr->ia_size);
210 if (attr->ia_valid & ATTR_ATIME_SET) {
212 p = xdr_encode_time3(p, &attr->ia_atime);
213 } else if (attr->ia_valid & ATTR_ATIME) {
218 if (attr->ia_valid & ATTR_MTIME_SET) {
220 p = xdr_encode_time3(p, &attr->ia_mtime);
221 } else if (attr->ia_valid & ATTR_MTIME) {
230 xdr_decode_wcc_attr(u32 *p, struct nfs_fattr *fattr)
232 p = xdr_decode_hyper(p, &fattr->pre_size);
233 p = xdr_decode_time3(p, &fattr->pre_mtime);
234 p = xdr_decode_time3(p, &fattr->pre_ctime);
235 fattr->valid |= NFS_ATTR_WCC;
240 xdr_decode_post_op_attr(u32 *p, struct nfs_fattr *fattr)
243 p = xdr_decode_fattr(p, fattr);
248 xdr_decode_pre_op_attr(u32 *p, struct nfs_fattr *fattr)
251 return xdr_decode_wcc_attr(p, fattr);
257 xdr_decode_wcc_data(u32 *p, struct nfs_fattr *fattr)
259 p = xdr_decode_pre_op_attr(p, fattr);
260 return xdr_decode_post_op_attr(p, fattr);
264 * NFS encode functions
268 * Encode file handle argument
271 nfs3_xdr_fhandle(struct rpc_rqst *req, u32 *p, struct nfs_fh *fh)
273 p = xdr_encode_fhandle(p, fh);
274 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
279 * Encode SETATTR arguments
282 nfs3_xdr_sattrargs(struct rpc_rqst *req, u32 *p, struct nfs3_sattrargs *args)
284 p = xdr_encode_fhandle(p, args->fh);
285 p = xdr_encode_sattr(p, args->sattr,
286 req->rq_task->tk_client->cl_tagxid);
287 *p++ = htonl(args->guard);
289 p = xdr_encode_time3(p, &args->guardtime);
290 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
295 * Encode directory ops argument
298 nfs3_xdr_diropargs(struct rpc_rqst *req, u32 *p, struct nfs3_diropargs *args)
300 p = xdr_encode_fhandle(p, args->fh);
301 p = xdr_encode_array(p, args->name, args->len);
302 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
307 * Encode access() argument
310 nfs3_xdr_accessargs(struct rpc_rqst *req, u32 *p, struct nfs3_accessargs *args)
312 p = xdr_encode_fhandle(p, args->fh);
313 *p++ = htonl(args->access);
314 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
319 * Arguments to a READ call. Since we read data directly into the page
320 * cache, we also set up the reply iovec here so that iov[1] points
321 * exactly to the page we want to fetch.
324 nfs3_xdr_readargs(struct rpc_rqst *req, u32 *p, struct nfs_readargs *args)
326 struct rpc_auth *auth = req->rq_task->tk_auth;
328 u32 count = args->count;
330 p = xdr_encode_fhandle(p, args->fh);
331 p = xdr_encode_hyper(p, args->offset);
333 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
335 /* Inline the page array */
336 replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS3_readres_sz) << 2;
337 xdr_inline_pages(&req->rq_rcv_buf, replen,
338 args->pages, args->pgbase, count);
343 * Write arguments. Splice the buffer to be written into the iovec.
346 nfs3_xdr_writeargs(struct rpc_rqst *req, u32 *p, struct nfs_writeargs *args)
348 struct xdr_buf *sndbuf = &req->rq_snd_buf;
349 u32 count = args->count;
351 p = xdr_encode_fhandle(p, args->fh);
352 p = xdr_encode_hyper(p, args->offset);
354 *p++ = htonl(args->stable);
356 sndbuf->len = xdr_adjust_iovec(sndbuf->head, p);
358 /* Copy the page array */
359 xdr_encode_pages(sndbuf, args->pages, args->pgbase, count);
364 * Encode CREATE arguments
367 nfs3_xdr_createargs(struct rpc_rqst *req, u32 *p, struct nfs3_createargs *args)
369 p = xdr_encode_fhandle(p, args->fh);
370 p = xdr_encode_array(p, args->name, args->len);
372 *p++ = htonl(args->createmode);
373 if (args->createmode == NFS3_CREATE_EXCLUSIVE) {
374 *p++ = args->verifier[0];
375 *p++ = args->verifier[1];
377 p = xdr_encode_sattr(p, args->sattr,
378 req->rq_task->tk_client->cl_tagxid);
380 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
385 * Encode MKDIR arguments
388 nfs3_xdr_mkdirargs(struct rpc_rqst *req, u32 *p, struct nfs3_mkdirargs *args)
390 p = xdr_encode_fhandle(p, args->fh);
391 p = xdr_encode_array(p, args->name, args->len);
392 p = xdr_encode_sattr(p, args->sattr,
393 req->rq_task->tk_client->cl_tagxid);
394 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
399 * Encode SYMLINK arguments
402 nfs3_xdr_symlinkargs(struct rpc_rqst *req, u32 *p, struct nfs3_symlinkargs *args)
404 p = xdr_encode_fhandle(p, args->fromfh);
405 p = xdr_encode_array(p, args->fromname, args->fromlen);
406 p = xdr_encode_sattr(p, args->sattr,
407 req->rq_task->tk_client->cl_tagxid);
408 p = xdr_encode_array(p, args->topath, args->tolen);
409 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
414 * Encode MKNOD arguments
417 nfs3_xdr_mknodargs(struct rpc_rqst *req, u32 *p, struct nfs3_mknodargs *args)
419 p = xdr_encode_fhandle(p, args->fh);
420 p = xdr_encode_array(p, args->name, args->len);
421 *p++ = htonl(args->type);
422 p = xdr_encode_sattr(p, args->sattr,
423 req->rq_task->tk_client->cl_tagxid);
424 if (args->type == NF3CHR || args->type == NF3BLK) {
425 *p++ = htonl(MAJOR(args->rdev));
426 *p++ = htonl(MINOR(args->rdev));
429 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
434 * Encode RENAME arguments
437 nfs3_xdr_renameargs(struct rpc_rqst *req, u32 *p, struct nfs3_renameargs *args)
439 p = xdr_encode_fhandle(p, args->fromfh);
440 p = xdr_encode_array(p, args->fromname, args->fromlen);
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 LINK arguments
451 nfs3_xdr_linkargs(struct rpc_rqst *req, u32 *p, struct nfs3_linkargs *args)
453 p = xdr_encode_fhandle(p, args->fromfh);
454 p = xdr_encode_fhandle(p, args->tofh);
455 p = xdr_encode_array(p, args->toname, args->tolen);
456 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
461 * Encode arguments to readdir call
464 nfs3_xdr_readdirargs(struct rpc_rqst *req, u32 *p, struct nfs3_readdirargs *args)
466 struct rpc_auth *auth = req->rq_task->tk_auth;
468 u32 count = args->count;
470 p = xdr_encode_fhandle(p, args->fh);
471 p = xdr_encode_hyper(p, args->cookie);
472 *p++ = args->verf[0];
473 *p++ = args->verf[1];
475 /* readdirplus: need dircount + buffer size.
476 * We just make sure we make dircount big enough */
477 *p++ = htonl(count >> 3);
480 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
482 /* Inline the page array */
483 replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS3_readdirres_sz) << 2;
484 xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, 0, count);
489 * Decode the result of a readdir call.
490 * We just check for syntactical correctness.
493 nfs3_xdr_readdirres(struct rpc_rqst *req, u32 *p, struct nfs3_readdirres *res)
495 struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
496 struct kvec *iov = rcvbuf->head;
500 unsigned int len, pglen;
501 u32 *entry, *end, *kaddr;
503 status = ntohl(*p++);
504 /* Decode post_op_attrs */
505 p = xdr_decode_post_op_attr(p, res->dir_attr);
507 return -nfs_stat_to_errno(status);
508 /* Decode verifier cookie */
516 hdrlen = (u8 *) p - (u8 *) iov->iov_base;
517 if (iov->iov_len < hdrlen) {
518 printk(KERN_WARNING "NFS: READDIR reply header overflowed:"
519 "length %d > %Zu\n", hdrlen, iov->iov_len);
520 return -errno_NFSERR_IO;
521 } else if (iov->iov_len != hdrlen) {
522 dprintk("NFS: READDIR header is short. iovec will be shifted.\n");
523 xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen);
526 pglen = rcvbuf->page_len;
527 recvd = rcvbuf->len - hdrlen;
530 page = rcvbuf->pages;
531 kaddr = p = (u32 *)kmap_atomic(*page, KM_USER0);
532 end = (u32 *)((char *)p + pglen);
534 for (nr = 0; *p++; nr++) {
537 p += 2; /* inode # */
538 len = ntohl(*p++); /* string length */
539 p += XDR_QUADLEN(len) + 2; /* name + cookie */
540 if (len > NFS3_MAXNAMLEN) {
541 printk(KERN_WARNING "NFS: giant filename in readdir (len %x)!\n",
560 if (len > NFS3_FHSIZE) {
561 printk(KERN_WARNING "NFS: giant filehandle in "
562 "readdir (len %x)!\n", len);
565 p += XDR_QUADLEN(len);
573 if (!nr && (entry[0] != 0 || entry[1] == 0))
576 kunmap_atomic(kaddr, KM_USER0);
579 entry[0] = entry[1] = 0;
580 /* truncate listing ? */
582 printk(KERN_NOTICE "NFS: readdir reply truncated!\n");
587 nr = -errno_NFSERR_IO;
592 nfs3_decode_dirent(u32 *p, struct nfs_entry *entry, int plus)
594 struct nfs_entry old = *entry;
598 return ERR_PTR(-EAGAIN);
600 return ERR_PTR(-EBADCOOKIE);
603 p = xdr_decode_hyper(p, &entry->ino);
604 entry->len = ntohl(*p++);
605 entry->name = (const char *) p;
606 p += XDR_QUADLEN(entry->len);
607 entry->prev_cookie = entry->cookie;
608 p = xdr_decode_hyper(p, &entry->cookie);
611 entry->fattr->valid = 0;
612 p = xdr_decode_post_op_attr(p, entry->fattr);
613 /* In fact, a post_op_fh3: */
615 p = xdr_decode_fhandle(p, entry->fh);
616 /* Ugh -- server reply was truncated */
618 dprintk("NFS: FH truncated\n");
620 return ERR_PTR(-EAGAIN);
623 memset((u8*)(entry->fh), 0, sizeof(*entry->fh));
626 entry->eof = !p[0] && p[1];
631 * Encode COMMIT arguments
634 nfs3_xdr_commitargs(struct rpc_rqst *req, u32 *p, struct nfs_writeargs *args)
636 p = xdr_encode_fhandle(p, args->fh);
637 p = xdr_encode_hyper(p, args->offset);
638 *p++ = htonl(args->count);
639 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
643 #ifdef CONFIG_NFS_V3_ACL
645 * Encode GETACL arguments
648 nfs3_xdr_getaclargs(struct rpc_rqst *req, u32 *p,
649 struct nfs3_getaclargs *args)
651 struct rpc_auth *auth = req->rq_task->tk_auth;
654 p = xdr_encode_fhandle(p, args->fh);
655 *p++ = htonl(args->mask);
656 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
658 if (args->mask & (NFS_ACL | NFS_DFACL)) {
659 /* Inline the page array */
660 replen = (RPC_REPHDRSIZE + auth->au_rslack +
661 ACL3_getaclres_sz) << 2;
662 xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, 0,
663 NFSACL_MAXPAGES << PAGE_SHIFT);
669 * Encode SETACL arguments
672 nfs3_xdr_setaclargs(struct rpc_rqst *req, u32 *p,
673 struct nfs3_setaclargs *args)
675 struct xdr_buf *buf = &req->rq_snd_buf;
676 unsigned int base, len_in_head, len = nfsacl_size(
677 (args->mask & NFS_ACL) ? args->acl_access : NULL,
678 (args->mask & NFS_DFACL) ? args->acl_default : NULL);
681 p = xdr_encode_fhandle(p, NFS_FH(args->inode));
682 *p++ = htonl(args->mask);
683 base = (char *)p - (char *)buf->head->iov_base;
684 /* put as much of the acls into head as possible. */
685 len_in_head = min_t(unsigned int, buf->head->iov_len - base, len);
687 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p + (len_in_head >> 2));
689 for (count = 0; (count << PAGE_SHIFT) < len; count++) {
690 args->pages[count] = alloc_page(GFP_KERNEL);
691 if (!args->pages[count]) {
693 __free_page(args->pages[--count]);
697 xdr_encode_pages(buf, args->pages, 0, len);
699 err = nfsacl_encode(buf, base, args->inode,
700 (args->mask & NFS_ACL) ?
701 args->acl_access : NULL, 1, 0);
703 err = nfsacl_encode(buf, base + err, args->inode,
704 (args->mask & NFS_DFACL) ?
705 args->acl_default : NULL, 1,
707 return (err > 0) ? 0 : err;
709 #endif /* CONFIG_NFS_V3_ACL */
712 * NFS XDR decode functions
716 * Decode attrstat reply.
719 nfs3_xdr_attrstat(struct rpc_rqst *req, u32 *p, struct nfs_fattr *fattr)
723 if ((status = ntohl(*p++)))
724 return -nfs_stat_to_errno(status);
725 xdr_decode_fattr(p, fattr);
730 * Decode status+wcc_data reply
731 * SATTR, REMOVE, RMDIR
734 nfs3_xdr_wccstat(struct rpc_rqst *req, u32 *p, struct nfs_fattr *fattr)
738 if ((status = ntohl(*p++)))
739 status = -nfs_stat_to_errno(status);
740 xdr_decode_wcc_data(p, fattr);
745 * Decode LOOKUP reply
748 nfs3_xdr_lookupres(struct rpc_rqst *req, u32 *p, struct nfs3_diropres *res)
752 if ((status = ntohl(*p++))) {
753 status = -nfs_stat_to_errno(status);
755 if (!(p = xdr_decode_fhandle(p, res->fh)))
756 return -errno_NFSERR_IO;
757 p = xdr_decode_post_op_attr(p, res->fattr);
759 xdr_decode_post_op_attr(p, res->dir_attr);
764 * Decode ACCESS reply
767 nfs3_xdr_accessres(struct rpc_rqst *req, u32 *p, struct nfs3_accessres *res)
769 int status = ntohl(*p++);
771 p = xdr_decode_post_op_attr(p, res->fattr);
773 return -nfs_stat_to_errno(status);
774 res->access = ntohl(*p++);
779 nfs3_xdr_readlinkargs(struct rpc_rqst *req, u32 *p, struct nfs3_readlinkargs *args)
781 struct rpc_auth *auth = req->rq_task->tk_auth;
784 p = xdr_encode_fhandle(p, args->fh);
785 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
787 /* Inline the page array */
788 replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS3_readlinkres_sz) << 2;
789 xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, args->pgbase, args->pglen);
794 * Decode READLINK reply
797 nfs3_xdr_readlinkres(struct rpc_rqst *req, u32 *p, struct nfs_fattr *fattr)
799 struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
800 struct kvec *iov = rcvbuf->head;
801 int hdrlen, len, recvd;
805 status = ntohl(*p++);
806 p = xdr_decode_post_op_attr(p, fattr);
809 return -nfs_stat_to_errno(status);
811 /* Convert length of symlink */
813 if (len >= rcvbuf->page_len || len <= 0) {
814 dprintk(KERN_WARNING "nfs: server returned giant symlink!\n");
815 return -ENAMETOOLONG;
818 hdrlen = (u8 *) p - (u8 *) iov->iov_base;
819 if (iov->iov_len < hdrlen) {
820 printk(KERN_WARNING "NFS: READLINK reply header overflowed:"
821 "length %d > %Zu\n", hdrlen, iov->iov_len);
822 return -errno_NFSERR_IO;
823 } else if (iov->iov_len != hdrlen) {
824 dprintk("NFS: READLINK header is short. iovec will be shifted.\n");
825 xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen);
827 recvd = req->rq_rcv_buf.len - hdrlen;
829 printk(KERN_WARNING "NFS: server cheating in readlink reply: "
830 "count %u > recvd %u\n", len, recvd);
834 /* NULL terminate the string we got */
835 kaddr = (char*)kmap_atomic(rcvbuf->pages[0], KM_USER0);
836 kaddr[len+rcvbuf->page_base] = '\0';
837 kunmap_atomic(kaddr, KM_USER0);
845 nfs3_xdr_readres(struct rpc_rqst *req, u32 *p, struct nfs_readres *res)
847 struct kvec *iov = req->rq_rcv_buf.head;
848 int status, count, ocount, recvd, hdrlen;
850 status = ntohl(*p++);
851 p = xdr_decode_post_op_attr(p, res->fattr);
854 return -nfs_stat_to_errno(status);
856 /* Decode reply could and EOF flag. NFSv3 is somewhat redundant
857 * in that it puts the count both in the res struct and in the
858 * opaque data count. */
860 res->eof = ntohl(*p++);
861 ocount = ntohl(*p++);
863 if (ocount != count) {
864 printk(KERN_WARNING "NFS: READ count doesn't match RPC opaque count.\n");
865 return -errno_NFSERR_IO;
868 hdrlen = (u8 *) p - (u8 *) iov->iov_base;
869 if (iov->iov_len < hdrlen) {
870 printk(KERN_WARNING "NFS: READ reply header overflowed:"
871 "length %d > %Zu\n", hdrlen, iov->iov_len);
872 return -errno_NFSERR_IO;
873 } else if (iov->iov_len != hdrlen) {
874 dprintk("NFS: READ header is short. iovec will be shifted.\n");
875 xdr_shift_buf(&req->rq_rcv_buf, iov->iov_len - hdrlen);
878 recvd = req->rq_rcv_buf.len - hdrlen;
880 printk(KERN_WARNING "NFS: server cheating in read reply: "
881 "count %d > recvd %d\n", count, recvd);
886 if (count < res->count)
893 * Decode WRITE response
896 nfs3_xdr_writeres(struct rpc_rqst *req, u32 *p, struct nfs_writeres *res)
900 status = ntohl(*p++);
901 p = xdr_decode_wcc_data(p, res->fattr);
904 return -nfs_stat_to_errno(status);
906 res->count = ntohl(*p++);
907 res->verf->committed = (enum nfs3_stable_how)ntohl(*p++);
908 res->verf->verifier[0] = *p++;
909 res->verf->verifier[1] = *p++;
915 * Decode a CREATE response
918 nfs3_xdr_createres(struct rpc_rqst *req, u32 *p, struct nfs3_diropres *res)
922 status = ntohl(*p++);
925 if (!(p = xdr_decode_fhandle(p, res->fh)))
926 return -errno_NFSERR_IO;
927 p = xdr_decode_post_op_attr(p, res->fattr);
929 memset(res->fh, 0, sizeof(*res->fh));
930 /* Do decode post_op_attr but set it to NULL */
931 p = xdr_decode_post_op_attr(p, res->fattr);
932 res->fattr->valid = 0;
935 status = -nfs_stat_to_errno(status);
937 p = xdr_decode_wcc_data(p, res->dir_attr);
942 * Decode RENAME reply
945 nfs3_xdr_renameres(struct rpc_rqst *req, u32 *p, struct nfs3_renameres *res)
949 if ((status = ntohl(*p++)) != 0)
950 status = -nfs_stat_to_errno(status);
951 p = xdr_decode_wcc_data(p, res->fromattr);
952 p = xdr_decode_wcc_data(p, res->toattr);
960 nfs3_xdr_linkres(struct rpc_rqst *req, u32 *p, struct nfs3_linkres *res)
964 if ((status = ntohl(*p++)) != 0)
965 status = -nfs_stat_to_errno(status);
966 p = xdr_decode_post_op_attr(p, res->fattr);
967 p = xdr_decode_wcc_data(p, res->dir_attr);
972 * Decode FSSTAT reply
975 nfs3_xdr_fsstatres(struct rpc_rqst *req, u32 *p, struct nfs_fsstat *res)
979 status = ntohl(*p++);
981 p = xdr_decode_post_op_attr(p, res->fattr);
983 return -nfs_stat_to_errno(status);
985 p = xdr_decode_hyper(p, &res->tbytes);
986 p = xdr_decode_hyper(p, &res->fbytes);
987 p = xdr_decode_hyper(p, &res->abytes);
988 p = xdr_decode_hyper(p, &res->tfiles);
989 p = xdr_decode_hyper(p, &res->ffiles);
990 p = xdr_decode_hyper(p, &res->afiles);
992 /* ignore invarsec */
997 * Decode FSINFO reply
1000 nfs3_xdr_fsinfores(struct rpc_rqst *req, u32 *p, struct nfs_fsinfo *res)
1004 status = ntohl(*p++);
1006 p = xdr_decode_post_op_attr(p, res->fattr);
1008 return -nfs_stat_to_errno(status);
1010 res->rtmax = ntohl(*p++);
1011 res->rtpref = ntohl(*p++);
1012 res->rtmult = ntohl(*p++);
1013 res->wtmax = ntohl(*p++);
1014 res->wtpref = ntohl(*p++);
1015 res->wtmult = ntohl(*p++);
1016 res->dtpref = ntohl(*p++);
1017 p = xdr_decode_hyper(p, &res->maxfilesize);
1019 /* ignore time_delta and properties */
1020 res->lease_time = 0;
1025 * Decode PATHCONF reply
1028 nfs3_xdr_pathconfres(struct rpc_rqst *req, u32 *p, struct nfs_pathconf *res)
1032 status = ntohl(*p++);
1034 p = xdr_decode_post_op_attr(p, res->fattr);
1036 return -nfs_stat_to_errno(status);
1037 res->max_link = ntohl(*p++);
1038 res->max_namelen = ntohl(*p++);
1040 /* ignore remaining fields */
1045 * Decode COMMIT reply
1048 nfs3_xdr_commitres(struct rpc_rqst *req, u32 *p, struct nfs_writeres *res)
1052 status = ntohl(*p++);
1053 p = xdr_decode_wcc_data(p, res->fattr);
1055 return -nfs_stat_to_errno(status);
1057 res->verf->verifier[0] = *p++;
1058 res->verf->verifier[1] = *p++;
1062 #ifdef CONFIG_NFS_V3_ACL
1064 * Decode GETACL reply
1067 nfs3_xdr_getaclres(struct rpc_rqst *req, u32 *p,
1068 struct nfs3_getaclres *res)
1070 struct xdr_buf *buf = &req->rq_rcv_buf;
1071 int status = ntohl(*p++);
1072 struct posix_acl **acl;
1073 unsigned int *aclcnt;
1077 return -nfs_stat_to_errno(status);
1078 p = xdr_decode_post_op_attr(p, res->fattr);
1079 res->mask = ntohl(*p++);
1080 if (res->mask & ~(NFS_ACL|NFS_ACLCNT|NFS_DFACL|NFS_DFACLCNT))
1082 base = (char *)p - (char *)req->rq_rcv_buf.head->iov_base;
1084 acl = (res->mask & NFS_ACL) ? &res->acl_access : NULL;
1085 aclcnt = (res->mask & NFS_ACLCNT) ? &res->acl_access_count : NULL;
1086 err = nfsacl_decode(buf, base, aclcnt, acl);
1088 acl = (res->mask & NFS_DFACL) ? &res->acl_default : NULL;
1089 aclcnt = (res->mask & NFS_DFACLCNT) ? &res->acl_default_count : NULL;
1091 err = nfsacl_decode(buf, base + err, aclcnt, acl);
1092 return (err > 0) ? 0 : err;
1096 * Decode setacl reply.
1099 nfs3_xdr_setaclres(struct rpc_rqst *req, u32 *p, struct nfs_fattr *fattr)
1101 int status = ntohl(*p++);
1104 return -nfs_stat_to_errno(status);
1105 xdr_decode_post_op_attr(p, fattr);
1108 #endif /* CONFIG_NFS_V3_ACL */
1111 # define MAX(a, b) (((a) > (b))? (a) : (b))
1114 #define PROC(proc, argtype, restype, timer) \
1115 [NFS3PROC_##proc] = { \
1116 .p_proc = NFS3PROC_##proc, \
1117 .p_encode = (kxdrproc_t) nfs3_xdr_##argtype, \
1118 .p_decode = (kxdrproc_t) nfs3_xdr_##restype, \
1119 .p_bufsiz = MAX(NFS3_##argtype##_sz,NFS3_##restype##_sz) << 2, \
1121 .p_statidx = NFS3PROC_##proc, \
1125 struct rpc_procinfo nfs3_procedures[] = {
1126 PROC(GETATTR, fhandle, attrstat, 1),
1127 PROC(SETATTR, sattrargs, wccstat, 0),
1128 PROC(LOOKUP, diropargs, lookupres, 2),
1129 PROC(ACCESS, accessargs, accessres, 1),
1130 PROC(READLINK, readlinkargs, readlinkres, 3),
1131 PROC(READ, readargs, readres, 3),
1132 PROC(WRITE, writeargs, writeres, 4),
1133 PROC(CREATE, createargs, createres, 0),
1134 PROC(MKDIR, mkdirargs, createres, 0),
1135 PROC(SYMLINK, symlinkargs, createres, 0),
1136 PROC(MKNOD, mknodargs, createres, 0),
1137 PROC(REMOVE, diropargs, wccstat, 0),
1138 PROC(RMDIR, diropargs, wccstat, 0),
1139 PROC(RENAME, renameargs, renameres, 0),
1140 PROC(LINK, linkargs, linkres, 0),
1141 PROC(READDIR, readdirargs, readdirres, 3),
1142 PROC(READDIRPLUS, readdirargs, readdirres, 3),
1143 PROC(FSSTAT, fhandle, fsstatres, 0),
1144 PROC(FSINFO, fhandle, fsinfores, 0),
1145 PROC(PATHCONF, fhandle, pathconfres, 0),
1146 PROC(COMMIT, commitargs, commitres, 5),
1149 struct rpc_version nfs_version3 = {
1151 .nrprocs = ARRAY_SIZE(nfs3_procedures),
1152 .procs = nfs3_procedures
1155 #ifdef CONFIG_NFS_V3_ACL
1156 static struct rpc_procinfo nfs3_acl_procedures[] = {
1157 [ACLPROC3_GETACL] = {
1158 .p_proc = ACLPROC3_GETACL,
1159 .p_encode = (kxdrproc_t) nfs3_xdr_getaclargs,
1160 .p_decode = (kxdrproc_t) nfs3_xdr_getaclres,
1161 .p_bufsiz = MAX(ACL3_getaclargs_sz, ACL3_getaclres_sz) << 2,
1165 [ACLPROC3_SETACL] = {
1166 .p_proc = ACLPROC3_SETACL,
1167 .p_encode = (kxdrproc_t) nfs3_xdr_setaclargs,
1168 .p_decode = (kxdrproc_t) nfs3_xdr_setaclres,
1169 .p_bufsiz = MAX(ACL3_setaclargs_sz, ACL3_setaclres_sz) << 2,
1175 struct rpc_version nfsacl_version3 = {
1177 .nrprocs = sizeof(nfs3_acl_procedures)/
1178 sizeof(nfs3_acl_procedures[0]),
1179 .procs = nfs3_acl_procedures,
1181 #endif /* CONFIG_NFS_V3_ACL */