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/vs_tag.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+1+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
109 static inline __be32 *
110 xdr_encode_fhandle(__be32 *p, struct nfs_fh *fh)
112 return xdr_encode_array(p, fh->data, fh->size);
115 static inline __be32 *
116 xdr_decode_fhandle(__be32 *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.
128 static inline __be32 *
129 xdr_encode_time3(__be32 *p, struct timespec *timep)
131 *p++ = htonl(timep->tv_sec);
132 *p++ = htonl(timep->tv_nsec);
136 static inline __be32 *
137 xdr_decode_time3(__be32 *p, struct timespec *timep)
139 timep->tv_sec = ntohl(*p++);
140 timep->tv_nsec = ntohl(*p++);
145 xdr_decode_fattr(__be32 *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);
181 static inline __be32 *
182 xdr_encode_sattr(__be32 *p, struct iattr *attr, int tag)
184 if (attr->ia_valid & ATTR_MODE) {
186 *p++ = htonl(attr->ia_mode & S_IALLUGO);
190 if (attr->ia_valid & ATTR_UID ||
191 (tag && (attr->ia_valid & ATTR_TAG))) {
193 *p++ = htonl(TAGINO_UID(tag, attr->ia_uid, attr->ia_tag));
197 if (attr->ia_valid & ATTR_GID ||
198 (tag && (attr->ia_valid & ATTR_TAG))) {
200 *p++ = htonl(TAGINO_GID(tag, attr->ia_gid, attr->ia_tag));
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) {
229 static inline __be32 *
230 xdr_decode_wcc_attr(__be32 *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;
239 static inline __be32 *
240 xdr_decode_post_op_attr(__be32 *p, struct nfs_fattr *fattr)
243 p = xdr_decode_fattr(p, fattr);
247 static inline __be32 *
248 xdr_decode_pre_op_attr(__be32 *p, struct nfs_fattr *fattr)
251 return xdr_decode_wcc_attr(p, fattr);
256 static inline __be32 *
257 xdr_decode_wcc_data(__be32 *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, __be32 *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, __be32 *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_tag);
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, __be32 *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, __be32 *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, __be32 *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, __be32 *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, __be32 *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_tag);
380 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
385 * Encode MKDIR arguments
388 nfs3_xdr_mkdirargs(struct rpc_rqst *req, __be32 *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_tag);
394 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
399 * Encode SYMLINK arguments
402 nfs3_xdr_symlinkargs(struct rpc_rqst *req, __be32 *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_tag);
408 *p++ = htonl(args->pathlen);
409 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
412 xdr_encode_pages(&req->rq_snd_buf, args->pages, 0, args->pathlen);
417 * Encode MKNOD arguments
420 nfs3_xdr_mknodargs(struct rpc_rqst *req, __be32 *p, struct nfs3_mknodargs *args)
422 p = xdr_encode_fhandle(p, args->fh);
423 p = xdr_encode_array(p, args->name, args->len);
424 *p++ = htonl(args->type);
425 p = xdr_encode_sattr(p, args->sattr,
426 req->rq_task->tk_client->cl_tag);
427 if (args->type == NF3CHR || args->type == NF3BLK) {
428 *p++ = htonl(MAJOR(args->rdev));
429 *p++ = htonl(MINOR(args->rdev));
432 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
437 * Encode RENAME arguments
440 nfs3_xdr_renameargs(struct rpc_rqst *req, __be32 *p, struct nfs3_renameargs *args)
442 p = xdr_encode_fhandle(p, args->fromfh);
443 p = xdr_encode_array(p, args->fromname, args->fromlen);
444 p = xdr_encode_fhandle(p, args->tofh);
445 p = xdr_encode_array(p, args->toname, args->tolen);
446 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
451 * Encode LINK arguments
454 nfs3_xdr_linkargs(struct rpc_rqst *req, __be32 *p, struct nfs3_linkargs *args)
456 p = xdr_encode_fhandle(p, args->fromfh);
457 p = xdr_encode_fhandle(p, args->tofh);
458 p = xdr_encode_array(p, args->toname, args->tolen);
459 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
464 * Encode arguments to readdir call
467 nfs3_xdr_readdirargs(struct rpc_rqst *req, __be32 *p, struct nfs3_readdirargs *args)
469 struct rpc_auth *auth = req->rq_task->tk_auth;
471 u32 count = args->count;
473 p = xdr_encode_fhandle(p, args->fh);
474 p = xdr_encode_hyper(p, args->cookie);
475 *p++ = args->verf[0];
476 *p++ = args->verf[1];
478 /* readdirplus: need dircount + buffer size.
479 * We just make sure we make dircount big enough */
480 *p++ = htonl(count >> 3);
483 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
485 /* Inline the page array */
486 replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS3_readdirres_sz) << 2;
487 xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, 0, count);
492 * Decode the result of a readdir call.
493 * We just check for syntactical correctness.
496 nfs3_xdr_readdirres(struct rpc_rqst *req, __be32 *p, struct nfs3_readdirres *res)
498 struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
499 struct kvec *iov = rcvbuf->head;
503 unsigned int len, pglen;
504 __be32 *entry, *end, *kaddr;
506 status = ntohl(*p++);
507 /* Decode post_op_attrs */
508 p = xdr_decode_post_op_attr(p, res->dir_attr);
510 return -nfs_stat_to_errno(status);
511 /* Decode verifier cookie */
519 hdrlen = (u8 *) p - (u8 *) iov->iov_base;
520 if (iov->iov_len < hdrlen) {
521 printk(KERN_WARNING "NFS: READDIR reply header overflowed:"
522 "length %d > %Zu\n", hdrlen, iov->iov_len);
523 return -errno_NFSERR_IO;
524 } else if (iov->iov_len != hdrlen) {
525 dprintk("NFS: READDIR header is short. iovec will be shifted.\n");
526 xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen);
529 pglen = rcvbuf->page_len;
530 recvd = rcvbuf->len - hdrlen;
533 page = rcvbuf->pages;
534 kaddr = p = kmap_atomic(*page, KM_USER0);
535 end = (__be32 *)((char *)p + pglen);
537 for (nr = 0; *p++; nr++) {
540 p += 2; /* inode # */
541 len = ntohl(*p++); /* string length */
542 p += XDR_QUADLEN(len) + 2; /* name + cookie */
543 if (len > NFS3_MAXNAMLEN) {
544 printk(KERN_WARNING "NFS: giant filename in readdir (len %x)!\n",
563 if (len > NFS3_FHSIZE) {
564 printk(KERN_WARNING "NFS: giant filehandle in "
565 "readdir (len %x)!\n", len);
568 p += XDR_QUADLEN(len);
576 if (!nr && (entry[0] != 0 || entry[1] == 0))
579 kunmap_atomic(kaddr, KM_USER0);
582 entry[0] = entry[1] = 0;
583 /* truncate listing ? */
585 printk(KERN_NOTICE "NFS: readdir reply truncated!\n");
590 nr = -errno_NFSERR_IO;
595 nfs3_decode_dirent(__be32 *p, struct nfs_entry *entry, int plus)
597 struct nfs_entry old = *entry;
601 return ERR_PTR(-EAGAIN);
603 return ERR_PTR(-EBADCOOKIE);
606 p = xdr_decode_hyper(p, &entry->ino);
607 entry->len = ntohl(*p++);
608 entry->name = (const char *) p;
609 p += XDR_QUADLEN(entry->len);
610 entry->prev_cookie = entry->cookie;
611 p = xdr_decode_hyper(p, &entry->cookie);
614 entry->fattr->valid = 0;
615 p = xdr_decode_post_op_attr(p, entry->fattr);
616 /* In fact, a post_op_fh3: */
618 p = xdr_decode_fhandle(p, entry->fh);
619 /* Ugh -- server reply was truncated */
621 dprintk("NFS: FH truncated\n");
623 return ERR_PTR(-EAGAIN);
626 memset((u8*)(entry->fh), 0, sizeof(*entry->fh));
629 entry->eof = !p[0] && p[1];
634 * Encode COMMIT arguments
637 nfs3_xdr_commitargs(struct rpc_rqst *req, __be32 *p, struct nfs_writeargs *args)
639 p = xdr_encode_fhandle(p, args->fh);
640 p = xdr_encode_hyper(p, args->offset);
641 *p++ = htonl(args->count);
642 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
646 #ifdef CONFIG_NFS_V3_ACL
648 * Encode GETACL arguments
651 nfs3_xdr_getaclargs(struct rpc_rqst *req, __be32 *p,
652 struct nfs3_getaclargs *args)
654 struct rpc_auth *auth = req->rq_task->tk_auth;
657 p = xdr_encode_fhandle(p, args->fh);
658 *p++ = htonl(args->mask);
659 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
661 if (args->mask & (NFS_ACL | NFS_DFACL)) {
662 /* Inline the page array */
663 replen = (RPC_REPHDRSIZE + auth->au_rslack +
664 ACL3_getaclres_sz) << 2;
665 xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, 0,
666 NFSACL_MAXPAGES << PAGE_SHIFT);
672 * Encode SETACL arguments
675 nfs3_xdr_setaclargs(struct rpc_rqst *req, __be32 *p,
676 struct nfs3_setaclargs *args)
678 struct xdr_buf *buf = &req->rq_snd_buf;
679 unsigned int base, len_in_head, len = nfsacl_size(
680 (args->mask & NFS_ACL) ? args->acl_access : NULL,
681 (args->mask & NFS_DFACL) ? args->acl_default : NULL);
684 p = xdr_encode_fhandle(p, NFS_FH(args->inode));
685 *p++ = htonl(args->mask);
686 base = (char *)p - (char *)buf->head->iov_base;
687 /* put as much of the acls into head as possible. */
688 len_in_head = min_t(unsigned int, buf->head->iov_len - base, len);
690 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p + (len_in_head >> 2));
692 for (count = 0; (count << PAGE_SHIFT) < len; count++) {
693 args->pages[count] = alloc_page(GFP_KERNEL);
694 if (!args->pages[count]) {
696 __free_page(args->pages[--count]);
700 xdr_encode_pages(buf, args->pages, 0, len);
702 err = nfsacl_encode(buf, base, args->inode,
703 (args->mask & NFS_ACL) ?
704 args->acl_access : NULL, 1, 0);
706 err = nfsacl_encode(buf, base + err, args->inode,
707 (args->mask & NFS_DFACL) ?
708 args->acl_default : NULL, 1,
710 return (err > 0) ? 0 : err;
712 #endif /* CONFIG_NFS_V3_ACL */
715 * NFS XDR decode functions
719 * Decode attrstat reply.
722 nfs3_xdr_attrstat(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
726 if ((status = ntohl(*p++)))
727 return -nfs_stat_to_errno(status);
728 xdr_decode_fattr(p, fattr);
733 * Decode status+wcc_data reply
734 * SATTR, REMOVE, RMDIR
737 nfs3_xdr_wccstat(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
741 if ((status = ntohl(*p++)))
742 status = -nfs_stat_to_errno(status);
743 xdr_decode_wcc_data(p, fattr);
748 * Decode LOOKUP reply
751 nfs3_xdr_lookupres(struct rpc_rqst *req, __be32 *p, struct nfs3_diropres *res)
755 if ((status = ntohl(*p++))) {
756 status = -nfs_stat_to_errno(status);
758 if (!(p = xdr_decode_fhandle(p, res->fh)))
759 return -errno_NFSERR_IO;
760 p = xdr_decode_post_op_attr(p, res->fattr);
762 xdr_decode_post_op_attr(p, res->dir_attr);
767 * Decode ACCESS reply
770 nfs3_xdr_accessres(struct rpc_rqst *req, __be32 *p, struct nfs3_accessres *res)
772 int status = ntohl(*p++);
774 p = xdr_decode_post_op_attr(p, res->fattr);
776 return -nfs_stat_to_errno(status);
777 res->access = ntohl(*p++);
782 nfs3_xdr_readlinkargs(struct rpc_rqst *req, __be32 *p, struct nfs3_readlinkargs *args)
784 struct rpc_auth *auth = req->rq_task->tk_auth;
787 p = xdr_encode_fhandle(p, args->fh);
788 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
790 /* Inline the page array */
791 replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS3_readlinkres_sz) << 2;
792 xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, args->pgbase, args->pglen);
797 * Decode READLINK reply
800 nfs3_xdr_readlinkres(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
802 struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
803 struct kvec *iov = rcvbuf->head;
804 int hdrlen, len, recvd;
808 status = ntohl(*p++);
809 p = xdr_decode_post_op_attr(p, fattr);
812 return -nfs_stat_to_errno(status);
814 /* Convert length of symlink */
816 if (len >= rcvbuf->page_len || len <= 0) {
817 dprintk(KERN_WARNING "nfs: server returned giant symlink!\n");
818 return -ENAMETOOLONG;
821 hdrlen = (u8 *) p - (u8 *) iov->iov_base;
822 if (iov->iov_len < hdrlen) {
823 printk(KERN_WARNING "NFS: READLINK reply header overflowed:"
824 "length %d > %Zu\n", hdrlen, iov->iov_len);
825 return -errno_NFSERR_IO;
826 } else if (iov->iov_len != hdrlen) {
827 dprintk("NFS: READLINK header is short. iovec will be shifted.\n");
828 xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen);
830 recvd = req->rq_rcv_buf.len - hdrlen;
832 printk(KERN_WARNING "NFS: server cheating in readlink reply: "
833 "count %u > recvd %u\n", len, recvd);
837 /* NULL terminate the string we got */
838 kaddr = (char*)kmap_atomic(rcvbuf->pages[0], KM_USER0);
839 kaddr[len+rcvbuf->page_base] = '\0';
840 kunmap_atomic(kaddr, KM_USER0);
848 nfs3_xdr_readres(struct rpc_rqst *req, __be32 *p, struct nfs_readres *res)
850 struct kvec *iov = req->rq_rcv_buf.head;
851 int status, count, ocount, recvd, hdrlen;
853 status = ntohl(*p++);
854 p = xdr_decode_post_op_attr(p, res->fattr);
857 return -nfs_stat_to_errno(status);
859 /* Decode reply could and EOF flag. NFSv3 is somewhat redundant
860 * in that it puts the count both in the res struct and in the
861 * opaque data count. */
863 res->eof = ntohl(*p++);
864 ocount = ntohl(*p++);
866 if (ocount != count) {
867 printk(KERN_WARNING "NFS: READ count doesn't match RPC opaque count.\n");
868 return -errno_NFSERR_IO;
871 hdrlen = (u8 *) p - (u8 *) iov->iov_base;
872 if (iov->iov_len < hdrlen) {
873 printk(KERN_WARNING "NFS: READ reply header overflowed:"
874 "length %d > %Zu\n", hdrlen, iov->iov_len);
875 return -errno_NFSERR_IO;
876 } else if (iov->iov_len != hdrlen) {
877 dprintk("NFS: READ header is short. iovec will be shifted.\n");
878 xdr_shift_buf(&req->rq_rcv_buf, iov->iov_len - hdrlen);
881 recvd = req->rq_rcv_buf.len - hdrlen;
883 printk(KERN_WARNING "NFS: server cheating in read reply: "
884 "count %d > recvd %d\n", count, recvd);
889 if (count < res->count)
896 * Decode WRITE response
899 nfs3_xdr_writeres(struct rpc_rqst *req, __be32 *p, struct nfs_writeres *res)
903 status = ntohl(*p++);
904 p = xdr_decode_wcc_data(p, res->fattr);
907 return -nfs_stat_to_errno(status);
909 res->count = ntohl(*p++);
910 res->verf->committed = (enum nfs3_stable_how)ntohl(*p++);
911 res->verf->verifier[0] = *p++;
912 res->verf->verifier[1] = *p++;
918 * Decode a CREATE response
921 nfs3_xdr_createres(struct rpc_rqst *req, __be32 *p, struct nfs3_diropres *res)
925 status = ntohl(*p++);
928 if (!(p = xdr_decode_fhandle(p, res->fh)))
929 return -errno_NFSERR_IO;
930 p = xdr_decode_post_op_attr(p, res->fattr);
932 memset(res->fh, 0, sizeof(*res->fh));
933 /* Do decode post_op_attr but set it to NULL */
934 p = xdr_decode_post_op_attr(p, res->fattr);
935 res->fattr->valid = 0;
938 status = -nfs_stat_to_errno(status);
940 p = xdr_decode_wcc_data(p, res->dir_attr);
945 * Decode RENAME reply
948 nfs3_xdr_renameres(struct rpc_rqst *req, __be32 *p, struct nfs3_renameres *res)
952 if ((status = ntohl(*p++)) != 0)
953 status = -nfs_stat_to_errno(status);
954 p = xdr_decode_wcc_data(p, res->fromattr);
955 p = xdr_decode_wcc_data(p, res->toattr);
963 nfs3_xdr_linkres(struct rpc_rqst *req, __be32 *p, struct nfs3_linkres *res)
967 if ((status = ntohl(*p++)) != 0)
968 status = -nfs_stat_to_errno(status);
969 p = xdr_decode_post_op_attr(p, res->fattr);
970 p = xdr_decode_wcc_data(p, res->dir_attr);
975 * Decode FSSTAT reply
978 nfs3_xdr_fsstatres(struct rpc_rqst *req, __be32 *p, struct nfs_fsstat *res)
982 status = ntohl(*p++);
984 p = xdr_decode_post_op_attr(p, res->fattr);
986 return -nfs_stat_to_errno(status);
988 p = xdr_decode_hyper(p, &res->tbytes);
989 p = xdr_decode_hyper(p, &res->fbytes);
990 p = xdr_decode_hyper(p, &res->abytes);
991 p = xdr_decode_hyper(p, &res->tfiles);
992 p = xdr_decode_hyper(p, &res->ffiles);
993 p = xdr_decode_hyper(p, &res->afiles);
995 /* ignore invarsec */
1000 * Decode FSINFO reply
1003 nfs3_xdr_fsinfores(struct rpc_rqst *req, __be32 *p, struct nfs_fsinfo *res)
1007 status = ntohl(*p++);
1009 p = xdr_decode_post_op_attr(p, res->fattr);
1011 return -nfs_stat_to_errno(status);
1013 res->rtmax = ntohl(*p++);
1014 res->rtpref = ntohl(*p++);
1015 res->rtmult = ntohl(*p++);
1016 res->wtmax = ntohl(*p++);
1017 res->wtpref = ntohl(*p++);
1018 res->wtmult = ntohl(*p++);
1019 res->dtpref = ntohl(*p++);
1020 p = xdr_decode_hyper(p, &res->maxfilesize);
1022 /* ignore time_delta and properties */
1023 res->lease_time = 0;
1028 * Decode PATHCONF reply
1031 nfs3_xdr_pathconfres(struct rpc_rqst *req, __be32 *p, struct nfs_pathconf *res)
1035 status = ntohl(*p++);
1037 p = xdr_decode_post_op_attr(p, res->fattr);
1039 return -nfs_stat_to_errno(status);
1040 res->max_link = ntohl(*p++);
1041 res->max_namelen = ntohl(*p++);
1043 /* ignore remaining fields */
1048 * Decode COMMIT reply
1051 nfs3_xdr_commitres(struct rpc_rqst *req, __be32 *p, struct nfs_writeres *res)
1055 status = ntohl(*p++);
1056 p = xdr_decode_wcc_data(p, res->fattr);
1058 return -nfs_stat_to_errno(status);
1060 res->verf->verifier[0] = *p++;
1061 res->verf->verifier[1] = *p++;
1065 #ifdef CONFIG_NFS_V3_ACL
1067 * Decode GETACL reply
1070 nfs3_xdr_getaclres(struct rpc_rqst *req, __be32 *p,
1071 struct nfs3_getaclres *res)
1073 struct xdr_buf *buf = &req->rq_rcv_buf;
1074 int status = ntohl(*p++);
1075 struct posix_acl **acl;
1076 unsigned int *aclcnt;
1080 return -nfs_stat_to_errno(status);
1081 p = xdr_decode_post_op_attr(p, res->fattr);
1082 res->mask = ntohl(*p++);
1083 if (res->mask & ~(NFS_ACL|NFS_ACLCNT|NFS_DFACL|NFS_DFACLCNT))
1085 base = (char *)p - (char *)req->rq_rcv_buf.head->iov_base;
1087 acl = (res->mask & NFS_ACL) ? &res->acl_access : NULL;
1088 aclcnt = (res->mask & NFS_ACLCNT) ? &res->acl_access_count : NULL;
1089 err = nfsacl_decode(buf, base, aclcnt, acl);
1091 acl = (res->mask & NFS_DFACL) ? &res->acl_default : NULL;
1092 aclcnt = (res->mask & NFS_DFACLCNT) ? &res->acl_default_count : NULL;
1094 err = nfsacl_decode(buf, base + err, aclcnt, acl);
1095 return (err > 0) ? 0 : err;
1099 * Decode setacl reply.
1102 nfs3_xdr_setaclres(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
1104 int status = ntohl(*p++);
1107 return -nfs_stat_to_errno(status);
1108 xdr_decode_post_op_attr(p, fattr);
1111 #endif /* CONFIG_NFS_V3_ACL */
1114 # define MAX(a, b) (((a) > (b))? (a) : (b))
1117 #define PROC(proc, argtype, restype, timer) \
1118 [NFS3PROC_##proc] = { \
1119 .p_proc = NFS3PROC_##proc, \
1120 .p_encode = (kxdrproc_t) nfs3_xdr_##argtype, \
1121 .p_decode = (kxdrproc_t) nfs3_xdr_##restype, \
1122 .p_bufsiz = MAX(NFS3_##argtype##_sz,NFS3_##restype##_sz) << 2, \
1124 .p_statidx = NFS3PROC_##proc, \
1128 struct rpc_procinfo nfs3_procedures[] = {
1129 PROC(GETATTR, fhandle, attrstat, 1),
1130 PROC(SETATTR, sattrargs, wccstat, 0),
1131 PROC(LOOKUP, diropargs, lookupres, 2),
1132 PROC(ACCESS, accessargs, accessres, 1),
1133 PROC(READLINK, readlinkargs, readlinkres, 3),
1134 PROC(READ, readargs, readres, 3),
1135 PROC(WRITE, writeargs, writeres, 4),
1136 PROC(CREATE, createargs, createres, 0),
1137 PROC(MKDIR, mkdirargs, createres, 0),
1138 PROC(SYMLINK, symlinkargs, createres, 0),
1139 PROC(MKNOD, mknodargs, createres, 0),
1140 PROC(REMOVE, diropargs, wccstat, 0),
1141 PROC(RMDIR, diropargs, wccstat, 0),
1142 PROC(RENAME, renameargs, renameres, 0),
1143 PROC(LINK, linkargs, linkres, 0),
1144 PROC(READDIR, readdirargs, readdirres, 3),
1145 PROC(READDIRPLUS, readdirargs, readdirres, 3),
1146 PROC(FSSTAT, fhandle, fsstatres, 0),
1147 PROC(FSINFO, fhandle, fsinfores, 0),
1148 PROC(PATHCONF, fhandle, pathconfres, 0),
1149 PROC(COMMIT, commitargs, commitres, 5),
1152 struct rpc_version nfs_version3 = {
1154 .nrprocs = ARRAY_SIZE(nfs3_procedures),
1155 .procs = nfs3_procedures
1158 #ifdef CONFIG_NFS_V3_ACL
1159 static struct rpc_procinfo nfs3_acl_procedures[] = {
1160 [ACLPROC3_GETACL] = {
1161 .p_proc = ACLPROC3_GETACL,
1162 .p_encode = (kxdrproc_t) nfs3_xdr_getaclargs,
1163 .p_decode = (kxdrproc_t) nfs3_xdr_getaclres,
1164 .p_bufsiz = MAX(ACL3_getaclargs_sz, ACL3_getaclres_sz) << 2,
1168 [ACLPROC3_SETACL] = {
1169 .p_proc = ACLPROC3_SETACL,
1170 .p_encode = (kxdrproc_t) nfs3_xdr_setaclargs,
1171 .p_decode = (kxdrproc_t) nfs3_xdr_setaclres,
1172 .p_bufsiz = MAX(ACL3_setaclargs_sz, ACL3_setaclres_sz) << 2,
1178 struct rpc_version nfsacl_version3 = {
1180 .nrprocs = sizeof(nfs3_acl_procedures)/
1181 sizeof(nfs3_acl_procedures[0]),
1182 .procs = nfs3_acl_procedures,
1184 #endif /* CONFIG_NFS_V3_ACL */