NFSv4: Support NFSv4 optional attributes in the struct nfs_fattr
[linux-2.6/linux-acpi-2.6/ibm-acpi-2.6.git] / fs / nfs / nfs3xdr.c
blobc0f7d02aced9f6cac57b2ebffc8ff8d7dd351cb7
1 /*
2 * linux/fs/nfs/nfs3xdr.c
4 * XDR functions to encode/decode NFSv3 RPC arguments and results.
6 * Copyright (C) 1996, 1997 Olaf Kirch
7 */
9 #include <linux/param.h>
10 #include <linux/time.h>
11 #include <linux/mm.h>
12 #include <linux/slab.h>
13 #include <linux/utsname.h>
14 #include <linux/errno.h>
15 #include <linux/string.h>
16 #include <linux/in.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 "internal.h"
27 #define NFSDBG_FACILITY NFSDBG_XDR
29 /* Mapping from NFS error code to "errno" error code. */
30 #define errno_NFSERR_IO EIO
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_removeargs_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_removeres_sz (NFS3_wccstat_sz)
70 #define NFS3_lookupres_sz (1+NFS3_fh_sz+(2 * NFS3_post_op_attr_sz))
71 #define NFS3_accessres_sz (1+NFS3_post_op_attr_sz+1)
72 #define NFS3_readlinkres_sz (1+NFS3_post_op_attr_sz+1)
73 #define NFS3_readres_sz (1+NFS3_post_op_attr_sz+3)
74 #define NFS3_writeres_sz (1+NFS3_wcc_data_sz+4)
75 #define NFS3_createres_sz (1+NFS3_fh_sz+NFS3_post_op_attr_sz+NFS3_wcc_data_sz)
76 #define NFS3_renameres_sz (1+(2 * NFS3_wcc_data_sz))
77 #define NFS3_linkres_sz (1+NFS3_post_op_attr_sz+NFS3_wcc_data_sz)
78 #define NFS3_readdirres_sz (1+NFS3_post_op_attr_sz+2)
79 #define NFS3_fsstatres_sz (1+NFS3_post_op_attr_sz+13)
80 #define NFS3_fsinfores_sz (1+NFS3_post_op_attr_sz+12)
81 #define NFS3_pathconfres_sz (1+NFS3_post_op_attr_sz+6)
82 #define NFS3_commitres_sz (1+NFS3_wcc_data_sz+2)
84 #define ACL3_getaclargs_sz (NFS3_fh_sz+1)
85 #define ACL3_setaclargs_sz (NFS3_fh_sz+1+ \
86 XDR_QUADLEN(NFS_ACL_INLINE_BUFSIZE))
87 #define ACL3_getaclres_sz (1+NFS3_post_op_attr_sz+1+ \
88 XDR_QUADLEN(NFS_ACL_INLINE_BUFSIZE))
89 #define ACL3_setaclres_sz (1+NFS3_post_op_attr_sz)
92 * Map file type to S_IFMT bits
94 static struct {
95 unsigned int mode;
96 unsigned int nfs2type;
97 } nfs_type2fmt[] = {
98 { 0, NFNON },
99 { S_IFREG, NFREG },
100 { S_IFDIR, NFDIR },
101 { S_IFBLK, NFBLK },
102 { S_IFCHR, NFCHR },
103 { S_IFLNK, NFLNK },
104 { S_IFSOCK, NFSOCK },
105 { S_IFIFO, NFFIFO },
106 { 0, NFBAD }
110 * Common NFS XDR functions as inlines
112 static inline __be32 *
113 xdr_encode_fhandle(__be32 *p, const struct nfs_fh *fh)
115 return xdr_encode_array(p, fh->data, fh->size);
118 static inline __be32 *
119 xdr_decode_fhandle(__be32 *p, struct nfs_fh *fh)
121 if ((fh->size = ntohl(*p++)) <= NFS3_FHSIZE) {
122 memcpy(fh->data, p, fh->size);
123 return p + XDR_QUADLEN(fh->size);
125 return NULL;
129 * Encode/decode time.
131 static inline __be32 *
132 xdr_encode_time3(__be32 *p, struct timespec *timep)
134 *p++ = htonl(timep->tv_sec);
135 *p++ = htonl(timep->tv_nsec);
136 return p;
139 static inline __be32 *
140 xdr_decode_time3(__be32 *p, struct timespec *timep)
142 timep->tv_sec = ntohl(*p++);
143 timep->tv_nsec = ntohl(*p++);
144 return p;
147 static __be32 *
148 xdr_decode_fattr(__be32 *p, struct nfs_fattr *fattr)
150 unsigned int type, major, minor;
151 int fmode;
153 type = ntohl(*p++);
154 if (type >= NF3BAD)
155 type = NF3BAD;
156 fmode = nfs_type2fmt[type].mode;
157 fattr->type = nfs_type2fmt[type].nfs2type;
158 fattr->mode = (ntohl(*p++) & ~S_IFMT) | fmode;
159 fattr->nlink = ntohl(*p++);
160 fattr->uid = ntohl(*p++);
161 fattr->gid = ntohl(*p++);
162 p = xdr_decode_hyper(p, &fattr->size);
163 p = xdr_decode_hyper(p, &fattr->du.nfs3.used);
165 /* Turn remote device info into Linux-specific dev_t */
166 major = ntohl(*p++);
167 minor = ntohl(*p++);
168 fattr->rdev = MKDEV(major, minor);
169 if (MAJOR(fattr->rdev) != major || MINOR(fattr->rdev) != minor)
170 fattr->rdev = 0;
172 p = xdr_decode_hyper(p, &fattr->fsid.major);
173 fattr->fsid.minor = 0;
174 p = xdr_decode_hyper(p, &fattr->fileid);
175 p = xdr_decode_time3(p, &fattr->atime);
176 p = xdr_decode_time3(p, &fattr->mtime);
177 p = xdr_decode_time3(p, &fattr->ctime);
179 /* Update the mode bits */
180 fattr->valid |= NFS_ATTR_FATTR_V3;
181 return p;
184 static inline __be32 *
185 xdr_encode_sattr(__be32 *p, struct iattr *attr)
187 if (attr->ia_valid & ATTR_MODE) {
188 *p++ = xdr_one;
189 *p++ = htonl(attr->ia_mode & S_IALLUGO);
190 } else {
191 *p++ = xdr_zero;
193 if (attr->ia_valid & ATTR_UID) {
194 *p++ = xdr_one;
195 *p++ = htonl(attr->ia_uid);
196 } else {
197 *p++ = xdr_zero;
199 if (attr->ia_valid & ATTR_GID) {
200 *p++ = xdr_one;
201 *p++ = htonl(attr->ia_gid);
202 } else {
203 *p++ = xdr_zero;
205 if (attr->ia_valid & ATTR_SIZE) {
206 *p++ = xdr_one;
207 p = xdr_encode_hyper(p, (__u64) attr->ia_size);
208 } else {
209 *p++ = xdr_zero;
211 if (attr->ia_valid & ATTR_ATIME_SET) {
212 *p++ = xdr_two;
213 p = xdr_encode_time3(p, &attr->ia_atime);
214 } else if (attr->ia_valid & ATTR_ATIME) {
215 *p++ = xdr_one;
216 } else {
217 *p++ = xdr_zero;
219 if (attr->ia_valid & ATTR_MTIME_SET) {
220 *p++ = xdr_two;
221 p = xdr_encode_time3(p, &attr->ia_mtime);
222 } else if (attr->ia_valid & ATTR_MTIME) {
223 *p++ = xdr_one;
224 } else {
225 *p++ = xdr_zero;
227 return p;
230 static inline __be32 *
231 xdr_decode_wcc_attr(__be32 *p, struct nfs_fattr *fattr)
233 p = xdr_decode_hyper(p, &fattr->pre_size);
234 p = xdr_decode_time3(p, &fattr->pre_mtime);
235 p = xdr_decode_time3(p, &fattr->pre_ctime);
236 fattr->valid |= NFS_ATTR_FATTR_PRESIZE
237 | NFS_ATTR_FATTR_PREMTIME
238 | NFS_ATTR_FATTR_PRECTIME;
239 return p;
242 static inline __be32 *
243 xdr_decode_post_op_attr(__be32 *p, struct nfs_fattr *fattr)
245 if (*p++)
246 p = xdr_decode_fattr(p, fattr);
247 return p;
250 static inline __be32 *
251 xdr_decode_pre_op_attr(__be32 *p, struct nfs_fattr *fattr)
253 if (*p++)
254 return xdr_decode_wcc_attr(p, fattr);
255 return p;
259 static inline __be32 *
260 xdr_decode_wcc_data(__be32 *p, struct nfs_fattr *fattr)
262 p = xdr_decode_pre_op_attr(p, fattr);
263 return xdr_decode_post_op_attr(p, fattr);
267 * NFS encode functions
271 * Encode file handle argument
273 static int
274 nfs3_xdr_fhandle(struct rpc_rqst *req, __be32 *p, struct nfs_fh *fh)
276 p = xdr_encode_fhandle(p, fh);
277 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
278 return 0;
282 * Encode SETATTR arguments
284 static int
285 nfs3_xdr_sattrargs(struct rpc_rqst *req, __be32 *p, struct nfs3_sattrargs *args)
287 p = xdr_encode_fhandle(p, args->fh);
288 p = xdr_encode_sattr(p, args->sattr);
289 *p++ = htonl(args->guard);
290 if (args->guard)
291 p = xdr_encode_time3(p, &args->guardtime);
292 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
293 return 0;
297 * Encode directory ops argument
299 static int
300 nfs3_xdr_diropargs(struct rpc_rqst *req, __be32 *p, struct nfs3_diropargs *args)
302 p = xdr_encode_fhandle(p, args->fh);
303 p = xdr_encode_array(p, args->name, args->len);
304 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
305 return 0;
309 * Encode REMOVE argument
311 static int
312 nfs3_xdr_removeargs(struct rpc_rqst *req, __be32 *p, const struct nfs_removeargs *args)
314 p = xdr_encode_fhandle(p, args->fh);
315 p = xdr_encode_array(p, args->name.name, args->name.len);
316 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
317 return 0;
321 * Encode access() argument
323 static int
324 nfs3_xdr_accessargs(struct rpc_rqst *req, __be32 *p, struct nfs3_accessargs *args)
326 p = xdr_encode_fhandle(p, args->fh);
327 *p++ = htonl(args->access);
328 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
329 return 0;
333 * Arguments to a READ call. Since we read data directly into the page
334 * cache, we also set up the reply iovec here so that iov[1] points
335 * exactly to the page we want to fetch.
337 static int
338 nfs3_xdr_readargs(struct rpc_rqst *req, __be32 *p, struct nfs_readargs *args)
340 struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth;
341 unsigned int replen;
342 u32 count = args->count;
344 p = xdr_encode_fhandle(p, args->fh);
345 p = xdr_encode_hyper(p, args->offset);
346 *p++ = htonl(count);
347 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
349 /* Inline the page array */
350 replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS3_readres_sz) << 2;
351 xdr_inline_pages(&req->rq_rcv_buf, replen,
352 args->pages, args->pgbase, count);
353 req->rq_rcv_buf.flags |= XDRBUF_READ;
354 return 0;
358 * Write arguments. Splice the buffer to be written into the iovec.
360 static int
361 nfs3_xdr_writeargs(struct rpc_rqst *req, __be32 *p, struct nfs_writeargs *args)
363 struct xdr_buf *sndbuf = &req->rq_snd_buf;
364 u32 count = args->count;
366 p = xdr_encode_fhandle(p, args->fh);
367 p = xdr_encode_hyper(p, args->offset);
368 *p++ = htonl(count);
369 *p++ = htonl(args->stable);
370 *p++ = htonl(count);
371 sndbuf->len = xdr_adjust_iovec(sndbuf->head, p);
373 /* Copy the page array */
374 xdr_encode_pages(sndbuf, args->pages, args->pgbase, count);
375 sndbuf->flags |= XDRBUF_WRITE;
376 return 0;
380 * Encode CREATE arguments
382 static int
383 nfs3_xdr_createargs(struct rpc_rqst *req, __be32 *p, struct nfs3_createargs *args)
385 p = xdr_encode_fhandle(p, args->fh);
386 p = xdr_encode_array(p, args->name, args->len);
388 *p++ = htonl(args->createmode);
389 if (args->createmode == NFS3_CREATE_EXCLUSIVE) {
390 *p++ = args->verifier[0];
391 *p++ = args->verifier[1];
392 } else
393 p = xdr_encode_sattr(p, args->sattr);
395 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
396 return 0;
400 * Encode MKDIR arguments
402 static int
403 nfs3_xdr_mkdirargs(struct rpc_rqst *req, __be32 *p, struct nfs3_mkdirargs *args)
405 p = xdr_encode_fhandle(p, args->fh);
406 p = xdr_encode_array(p, args->name, args->len);
407 p = xdr_encode_sattr(p, args->sattr);
408 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
409 return 0;
413 * Encode SYMLINK arguments
415 static int
416 nfs3_xdr_symlinkargs(struct rpc_rqst *req, __be32 *p, struct nfs3_symlinkargs *args)
418 p = xdr_encode_fhandle(p, args->fromfh);
419 p = xdr_encode_array(p, args->fromname, args->fromlen);
420 p = xdr_encode_sattr(p, args->sattr);
421 *p++ = htonl(args->pathlen);
422 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
424 /* Copy the page */
425 xdr_encode_pages(&req->rq_snd_buf, args->pages, 0, args->pathlen);
426 return 0;
430 * Encode MKNOD arguments
432 static int
433 nfs3_xdr_mknodargs(struct rpc_rqst *req, __be32 *p, struct nfs3_mknodargs *args)
435 p = xdr_encode_fhandle(p, args->fh);
436 p = xdr_encode_array(p, args->name, args->len);
437 *p++ = htonl(args->type);
438 p = xdr_encode_sattr(p, args->sattr);
439 if (args->type == NF3CHR || args->type == NF3BLK) {
440 *p++ = htonl(MAJOR(args->rdev));
441 *p++ = htonl(MINOR(args->rdev));
444 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
445 return 0;
449 * Encode RENAME arguments
451 static int
452 nfs3_xdr_renameargs(struct rpc_rqst *req, __be32 *p, struct nfs3_renameargs *args)
454 p = xdr_encode_fhandle(p, args->fromfh);
455 p = xdr_encode_array(p, args->fromname, args->fromlen);
456 p = xdr_encode_fhandle(p, args->tofh);
457 p = xdr_encode_array(p, args->toname, args->tolen);
458 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
459 return 0;
463 * Encode LINK arguments
465 static int
466 nfs3_xdr_linkargs(struct rpc_rqst *req, __be32 *p, struct nfs3_linkargs *args)
468 p = xdr_encode_fhandle(p, args->fromfh);
469 p = xdr_encode_fhandle(p, args->tofh);
470 p = xdr_encode_array(p, args->toname, args->tolen);
471 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
472 return 0;
476 * Encode arguments to readdir call
478 static int
479 nfs3_xdr_readdirargs(struct rpc_rqst *req, __be32 *p, struct nfs3_readdirargs *args)
481 struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth;
482 unsigned int replen;
483 u32 count = args->count;
485 p = xdr_encode_fhandle(p, args->fh);
486 p = xdr_encode_hyper(p, args->cookie);
487 *p++ = args->verf[0];
488 *p++ = args->verf[1];
489 if (args->plus) {
490 /* readdirplus: need dircount + buffer size.
491 * We just make sure we make dircount big enough */
492 *p++ = htonl(count >> 3);
494 *p++ = htonl(count);
495 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
497 /* Inline the page array */
498 replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS3_readdirres_sz) << 2;
499 xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, 0, count);
500 return 0;
504 * Decode the result of a readdir call.
505 * We just check for syntactical correctness.
507 static int
508 nfs3_xdr_readdirres(struct rpc_rqst *req, __be32 *p, struct nfs3_readdirres *res)
510 struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
511 struct kvec *iov = rcvbuf->head;
512 struct page **page;
513 size_t hdrlen;
514 u32 len, recvd, pglen;
515 int status, nr = 0;
516 __be32 *entry, *end, *kaddr;
518 status = ntohl(*p++);
519 /* Decode post_op_attrs */
520 p = xdr_decode_post_op_attr(p, res->dir_attr);
521 if (status)
522 return nfs_stat_to_errno(status);
523 /* Decode verifier cookie */
524 if (res->verf) {
525 res->verf[0] = *p++;
526 res->verf[1] = *p++;
527 } else {
528 p += 2;
531 hdrlen = (u8 *) p - (u8 *) iov->iov_base;
532 if (iov->iov_len < hdrlen) {
533 dprintk("NFS: READDIR reply header overflowed:"
534 "length %Zu > %Zu\n", hdrlen, iov->iov_len);
535 return -errno_NFSERR_IO;
536 } else if (iov->iov_len != hdrlen) {
537 dprintk("NFS: READDIR header is short. iovec will be shifted.\n");
538 xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen);
541 pglen = rcvbuf->page_len;
542 recvd = rcvbuf->len - hdrlen;
543 if (pglen > recvd)
544 pglen = recvd;
545 page = rcvbuf->pages;
546 kaddr = p = kmap_atomic(*page, KM_USER0);
547 end = (__be32 *)((char *)p + pglen);
548 entry = p;
550 /* Make sure the packet actually has a value_follows and EOF entry */
551 if ((entry + 1) > end)
552 goto short_pkt;
554 for (; *p++; nr++) {
555 if (p + 3 > end)
556 goto short_pkt;
557 p += 2; /* inode # */
558 len = ntohl(*p++); /* string length */
559 p += XDR_QUADLEN(len) + 2; /* name + cookie */
560 if (len > NFS3_MAXNAMLEN) {
561 dprintk("NFS: giant filename in readdir (len 0x%x)!\n",
562 len);
563 goto err_unmap;
566 if (res->plus) {
567 /* post_op_attr */
568 if (p + 2 > end)
569 goto short_pkt;
570 if (*p++) {
571 p += 21;
572 if (p + 1 > end)
573 goto short_pkt;
575 /* post_op_fh3 */
576 if (*p++) {
577 if (p + 1 > end)
578 goto short_pkt;
579 len = ntohl(*p++);
580 if (len > NFS3_FHSIZE) {
581 dprintk("NFS: giant filehandle in "
582 "readdir (len 0x%x)!\n", len);
583 goto err_unmap;
585 p += XDR_QUADLEN(len);
589 if (p + 2 > end)
590 goto short_pkt;
591 entry = p;
595 * Apparently some server sends responses that are a valid size, but
596 * contain no entries, and have value_follows==0 and EOF==0. For
597 * those, just set the EOF marker.
599 if (!nr && entry[1] == 0) {
600 dprintk("NFS: readdir reply truncated!\n");
601 entry[1] = 1;
603 out:
604 kunmap_atomic(kaddr, KM_USER0);
605 return nr;
606 short_pkt:
608 * When we get a short packet there are 2 possibilities. We can
609 * return an error, or fix up the response to look like a valid
610 * response and return what we have so far. If there are no
611 * entries and the packet was short, then return -EIO. If there
612 * are valid entries in the response, return them and pretend that
613 * the call was successful, but incomplete. The caller can retry the
614 * readdir starting at the last cookie.
616 entry[0] = entry[1] = 0;
617 if (!nr)
618 nr = -errno_NFSERR_IO;
619 goto out;
620 err_unmap:
621 nr = -errno_NFSERR_IO;
622 goto out;
625 __be32 *
626 nfs3_decode_dirent(__be32 *p, struct nfs_entry *entry, int plus)
628 struct nfs_entry old = *entry;
630 if (!*p++) {
631 if (!*p)
632 return ERR_PTR(-EAGAIN);
633 entry->eof = 1;
634 return ERR_PTR(-EBADCOOKIE);
637 p = xdr_decode_hyper(p, &entry->ino);
638 entry->len = ntohl(*p++);
639 entry->name = (const char *) p;
640 p += XDR_QUADLEN(entry->len);
641 entry->prev_cookie = entry->cookie;
642 p = xdr_decode_hyper(p, &entry->cookie);
644 if (plus) {
645 entry->fattr->valid = 0;
646 p = xdr_decode_post_op_attr(p, entry->fattr);
647 /* In fact, a post_op_fh3: */
648 if (*p++) {
649 p = xdr_decode_fhandle(p, entry->fh);
650 /* Ugh -- server reply was truncated */
651 if (p == NULL) {
652 dprintk("NFS: FH truncated\n");
653 *entry = old;
654 return ERR_PTR(-EAGAIN);
656 } else
657 memset((u8*)(entry->fh), 0, sizeof(*entry->fh));
660 entry->eof = !p[0] && p[1];
661 return p;
665 * Encode COMMIT arguments
667 static int
668 nfs3_xdr_commitargs(struct rpc_rqst *req, __be32 *p, struct nfs_writeargs *args)
670 p = xdr_encode_fhandle(p, args->fh);
671 p = xdr_encode_hyper(p, args->offset);
672 *p++ = htonl(args->count);
673 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
674 return 0;
677 #ifdef CONFIG_NFS_V3_ACL
679 * Encode GETACL arguments
681 static int
682 nfs3_xdr_getaclargs(struct rpc_rqst *req, __be32 *p,
683 struct nfs3_getaclargs *args)
685 struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth;
686 unsigned int replen;
688 p = xdr_encode_fhandle(p, args->fh);
689 *p++ = htonl(args->mask);
690 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
692 if (args->mask & (NFS_ACL | NFS_DFACL)) {
693 /* Inline the page array */
694 replen = (RPC_REPHDRSIZE + auth->au_rslack +
695 ACL3_getaclres_sz) << 2;
696 xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, 0,
697 NFSACL_MAXPAGES << PAGE_SHIFT);
699 return 0;
703 * Encode SETACL arguments
705 static int
706 nfs3_xdr_setaclargs(struct rpc_rqst *req, __be32 *p,
707 struct nfs3_setaclargs *args)
709 struct xdr_buf *buf = &req->rq_snd_buf;
710 unsigned int base;
711 int err;
713 p = xdr_encode_fhandle(p, NFS_FH(args->inode));
714 *p++ = htonl(args->mask);
715 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
716 base = req->rq_slen;
718 if (args->npages != 0)
719 xdr_encode_pages(buf, args->pages, 0, args->len);
720 else
721 req->rq_slen += args->len;
723 err = nfsacl_encode(buf, base, args->inode,
724 (args->mask & NFS_ACL) ?
725 args->acl_access : NULL, 1, 0);
726 if (err > 0)
727 err = nfsacl_encode(buf, base + err, args->inode,
728 (args->mask & NFS_DFACL) ?
729 args->acl_default : NULL, 1,
730 NFS_ACL_DEFAULT);
731 return (err > 0) ? 0 : err;
733 #endif /* CONFIG_NFS_V3_ACL */
736 * NFS XDR decode functions
740 * Decode attrstat reply.
742 static int
743 nfs3_xdr_attrstat(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
745 int status;
747 if ((status = ntohl(*p++)))
748 return nfs_stat_to_errno(status);
749 xdr_decode_fattr(p, fattr);
750 return 0;
754 * Decode status+wcc_data reply
755 * SATTR, REMOVE, RMDIR
757 static int
758 nfs3_xdr_wccstat(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
760 int status;
762 if ((status = ntohl(*p++)))
763 status = nfs_stat_to_errno(status);
764 xdr_decode_wcc_data(p, fattr);
765 return status;
768 static int
769 nfs3_xdr_removeres(struct rpc_rqst *req, __be32 *p, struct nfs_removeres *res)
771 return nfs3_xdr_wccstat(req, p, &res->dir_attr);
775 * Decode LOOKUP reply
777 static int
778 nfs3_xdr_lookupres(struct rpc_rqst *req, __be32 *p, struct nfs3_diropres *res)
780 int status;
782 if ((status = ntohl(*p++))) {
783 status = nfs_stat_to_errno(status);
784 } else {
785 if (!(p = xdr_decode_fhandle(p, res->fh)))
786 return -errno_NFSERR_IO;
787 p = xdr_decode_post_op_attr(p, res->fattr);
789 xdr_decode_post_op_attr(p, res->dir_attr);
790 return status;
794 * Decode ACCESS reply
796 static int
797 nfs3_xdr_accessres(struct rpc_rqst *req, __be32 *p, struct nfs3_accessres *res)
799 int status = ntohl(*p++);
801 p = xdr_decode_post_op_attr(p, res->fattr);
802 if (status)
803 return nfs_stat_to_errno(status);
804 res->access = ntohl(*p++);
805 return 0;
808 static int
809 nfs3_xdr_readlinkargs(struct rpc_rqst *req, __be32 *p, struct nfs3_readlinkargs *args)
811 struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth;
812 unsigned int replen;
814 p = xdr_encode_fhandle(p, args->fh);
815 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
817 /* Inline the page array */
818 replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS3_readlinkres_sz) << 2;
819 xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, args->pgbase, args->pglen);
820 return 0;
824 * Decode READLINK reply
826 static int
827 nfs3_xdr_readlinkres(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
829 struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
830 struct kvec *iov = rcvbuf->head;
831 size_t hdrlen;
832 u32 len, recvd;
833 char *kaddr;
834 int status;
836 status = ntohl(*p++);
837 p = xdr_decode_post_op_attr(p, fattr);
839 if (status != 0)
840 return nfs_stat_to_errno(status);
842 /* Convert length of symlink */
843 len = ntohl(*p++);
844 if (len >= rcvbuf->page_len) {
845 dprintk("nfs: server returned giant symlink!\n");
846 return -ENAMETOOLONG;
849 hdrlen = (u8 *) p - (u8 *) iov->iov_base;
850 if (iov->iov_len < hdrlen) {
851 dprintk("NFS: READLINK reply header overflowed:"
852 "length %Zu > %Zu\n", hdrlen, iov->iov_len);
853 return -errno_NFSERR_IO;
854 } else if (iov->iov_len != hdrlen) {
855 dprintk("NFS: READLINK header is short. "
856 "iovec will be shifted.\n");
857 xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen);
859 recvd = req->rq_rcv_buf.len - hdrlen;
860 if (recvd < len) {
861 dprintk("NFS: server cheating in readlink reply: "
862 "count %u > recvd %u\n", len, recvd);
863 return -EIO;
866 /* NULL terminate the string we got */
867 kaddr = (char*)kmap_atomic(rcvbuf->pages[0], KM_USER0);
868 kaddr[len+rcvbuf->page_base] = '\0';
869 kunmap_atomic(kaddr, KM_USER0);
870 return 0;
874 * Decode READ reply
876 static int
877 nfs3_xdr_readres(struct rpc_rqst *req, __be32 *p, struct nfs_readres *res)
879 struct kvec *iov = req->rq_rcv_buf.head;
880 size_t hdrlen;
881 u32 count, ocount, recvd;
882 int status;
884 status = ntohl(*p++);
885 p = xdr_decode_post_op_attr(p, res->fattr);
887 if (status != 0)
888 return nfs_stat_to_errno(status);
890 /* Decode reply count and EOF flag. NFSv3 is somewhat redundant
891 * in that it puts the count both in the res struct and in the
892 * opaque data count. */
893 count = ntohl(*p++);
894 res->eof = ntohl(*p++);
895 ocount = ntohl(*p++);
897 if (ocount != count) {
898 dprintk("NFS: READ count doesn't match RPC opaque count.\n");
899 return -errno_NFSERR_IO;
902 hdrlen = (u8 *) p - (u8 *) iov->iov_base;
903 if (iov->iov_len < hdrlen) {
904 dprintk("NFS: READ reply header overflowed:"
905 "length %Zu > %Zu\n", hdrlen, iov->iov_len);
906 return -errno_NFSERR_IO;
907 } else if (iov->iov_len != hdrlen) {
908 dprintk("NFS: READ header is short. iovec will be shifted.\n");
909 xdr_shift_buf(&req->rq_rcv_buf, iov->iov_len - hdrlen);
912 recvd = req->rq_rcv_buf.len - hdrlen;
913 if (count > recvd) {
914 dprintk("NFS: server cheating in read reply: "
915 "count %u > recvd %u\n", count, recvd);
916 count = recvd;
917 res->eof = 0;
920 if (count < res->count)
921 res->count = count;
923 return count;
927 * Decode WRITE response
929 static int
930 nfs3_xdr_writeres(struct rpc_rqst *req, __be32 *p, struct nfs_writeres *res)
932 int status;
934 status = ntohl(*p++);
935 p = xdr_decode_wcc_data(p, res->fattr);
937 if (status != 0)
938 return nfs_stat_to_errno(status);
940 res->count = ntohl(*p++);
941 res->verf->committed = (enum nfs3_stable_how)ntohl(*p++);
942 res->verf->verifier[0] = *p++;
943 res->verf->verifier[1] = *p++;
945 return res->count;
949 * Decode a CREATE response
951 static int
952 nfs3_xdr_createres(struct rpc_rqst *req, __be32 *p, struct nfs3_diropres *res)
954 int status;
956 status = ntohl(*p++);
957 if (status == 0) {
958 if (*p++) {
959 if (!(p = xdr_decode_fhandle(p, res->fh)))
960 return -errno_NFSERR_IO;
961 p = xdr_decode_post_op_attr(p, res->fattr);
962 } else {
963 memset(res->fh, 0, sizeof(*res->fh));
964 /* Do decode post_op_attr but set it to NULL */
965 p = xdr_decode_post_op_attr(p, res->fattr);
966 res->fattr->valid = 0;
968 } else {
969 status = nfs_stat_to_errno(status);
971 p = xdr_decode_wcc_data(p, res->dir_attr);
972 return status;
976 * Decode RENAME reply
978 static int
979 nfs3_xdr_renameres(struct rpc_rqst *req, __be32 *p, struct nfs3_renameres *res)
981 int status;
983 if ((status = ntohl(*p++)) != 0)
984 status = nfs_stat_to_errno(status);
985 p = xdr_decode_wcc_data(p, res->fromattr);
986 p = xdr_decode_wcc_data(p, res->toattr);
987 return status;
991 * Decode LINK reply
993 static int
994 nfs3_xdr_linkres(struct rpc_rqst *req, __be32 *p, struct nfs3_linkres *res)
996 int status;
998 if ((status = ntohl(*p++)) != 0)
999 status = nfs_stat_to_errno(status);
1000 p = xdr_decode_post_op_attr(p, res->fattr);
1001 p = xdr_decode_wcc_data(p, res->dir_attr);
1002 return status;
1006 * Decode FSSTAT reply
1008 static int
1009 nfs3_xdr_fsstatres(struct rpc_rqst *req, __be32 *p, struct nfs_fsstat *res)
1011 int status;
1013 status = ntohl(*p++);
1015 p = xdr_decode_post_op_attr(p, res->fattr);
1016 if (status != 0)
1017 return nfs_stat_to_errno(status);
1019 p = xdr_decode_hyper(p, &res->tbytes);
1020 p = xdr_decode_hyper(p, &res->fbytes);
1021 p = xdr_decode_hyper(p, &res->abytes);
1022 p = xdr_decode_hyper(p, &res->tfiles);
1023 p = xdr_decode_hyper(p, &res->ffiles);
1024 p = xdr_decode_hyper(p, &res->afiles);
1026 /* ignore invarsec */
1027 return 0;
1031 * Decode FSINFO reply
1033 static int
1034 nfs3_xdr_fsinfores(struct rpc_rqst *req, __be32 *p, struct nfs_fsinfo *res)
1036 int status;
1038 status = ntohl(*p++);
1040 p = xdr_decode_post_op_attr(p, res->fattr);
1041 if (status != 0)
1042 return nfs_stat_to_errno(status);
1044 res->rtmax = ntohl(*p++);
1045 res->rtpref = ntohl(*p++);
1046 res->rtmult = ntohl(*p++);
1047 res->wtmax = ntohl(*p++);
1048 res->wtpref = ntohl(*p++);
1049 res->wtmult = ntohl(*p++);
1050 res->dtpref = ntohl(*p++);
1051 p = xdr_decode_hyper(p, &res->maxfilesize);
1053 /* ignore time_delta and properties */
1054 res->lease_time = 0;
1055 return 0;
1059 * Decode PATHCONF reply
1061 static int
1062 nfs3_xdr_pathconfres(struct rpc_rqst *req, __be32 *p, struct nfs_pathconf *res)
1064 int status;
1066 status = ntohl(*p++);
1068 p = xdr_decode_post_op_attr(p, res->fattr);
1069 if (status != 0)
1070 return nfs_stat_to_errno(status);
1071 res->max_link = ntohl(*p++);
1072 res->max_namelen = ntohl(*p++);
1074 /* ignore remaining fields */
1075 return 0;
1079 * Decode COMMIT reply
1081 static int
1082 nfs3_xdr_commitres(struct rpc_rqst *req, __be32 *p, struct nfs_writeres *res)
1084 int status;
1086 status = ntohl(*p++);
1087 p = xdr_decode_wcc_data(p, res->fattr);
1088 if (status != 0)
1089 return nfs_stat_to_errno(status);
1091 res->verf->verifier[0] = *p++;
1092 res->verf->verifier[1] = *p++;
1093 return 0;
1096 #ifdef CONFIG_NFS_V3_ACL
1098 * Decode GETACL reply
1100 static int
1101 nfs3_xdr_getaclres(struct rpc_rqst *req, __be32 *p,
1102 struct nfs3_getaclres *res)
1104 struct xdr_buf *buf = &req->rq_rcv_buf;
1105 int status = ntohl(*p++);
1106 struct posix_acl **acl;
1107 unsigned int *aclcnt;
1108 int err, base;
1110 if (status != 0)
1111 return nfs_stat_to_errno(status);
1112 p = xdr_decode_post_op_attr(p, res->fattr);
1113 res->mask = ntohl(*p++);
1114 if (res->mask & ~(NFS_ACL|NFS_ACLCNT|NFS_DFACL|NFS_DFACLCNT))
1115 return -EINVAL;
1116 base = (char *)p - (char *)req->rq_rcv_buf.head->iov_base;
1118 acl = (res->mask & NFS_ACL) ? &res->acl_access : NULL;
1119 aclcnt = (res->mask & NFS_ACLCNT) ? &res->acl_access_count : NULL;
1120 err = nfsacl_decode(buf, base, aclcnt, acl);
1122 acl = (res->mask & NFS_DFACL) ? &res->acl_default : NULL;
1123 aclcnt = (res->mask & NFS_DFACLCNT) ? &res->acl_default_count : NULL;
1124 if (err > 0)
1125 err = nfsacl_decode(buf, base + err, aclcnt, acl);
1126 return (err > 0) ? 0 : err;
1130 * Decode setacl reply.
1132 static int
1133 nfs3_xdr_setaclres(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
1135 int status = ntohl(*p++);
1137 if (status)
1138 return nfs_stat_to_errno(status);
1139 xdr_decode_post_op_attr(p, fattr);
1140 return 0;
1142 #endif /* CONFIG_NFS_V3_ACL */
1144 #define PROC(proc, argtype, restype, timer) \
1145 [NFS3PROC_##proc] = { \
1146 .p_proc = NFS3PROC_##proc, \
1147 .p_encode = (kxdrproc_t) nfs3_xdr_##argtype, \
1148 .p_decode = (kxdrproc_t) nfs3_xdr_##restype, \
1149 .p_arglen = NFS3_##argtype##_sz, \
1150 .p_replen = NFS3_##restype##_sz, \
1151 .p_timer = timer, \
1152 .p_statidx = NFS3PROC_##proc, \
1153 .p_name = #proc, \
1156 struct rpc_procinfo nfs3_procedures[] = {
1157 PROC(GETATTR, fhandle, attrstat, 1),
1158 PROC(SETATTR, sattrargs, wccstat, 0),
1159 PROC(LOOKUP, diropargs, lookupres, 2),
1160 PROC(ACCESS, accessargs, accessres, 1),
1161 PROC(READLINK, readlinkargs, readlinkres, 3),
1162 PROC(READ, readargs, readres, 3),
1163 PROC(WRITE, writeargs, writeres, 4),
1164 PROC(CREATE, createargs, createres, 0),
1165 PROC(MKDIR, mkdirargs, createres, 0),
1166 PROC(SYMLINK, symlinkargs, createres, 0),
1167 PROC(MKNOD, mknodargs, createres, 0),
1168 PROC(REMOVE, removeargs, removeres, 0),
1169 PROC(RMDIR, diropargs, wccstat, 0),
1170 PROC(RENAME, renameargs, renameres, 0),
1171 PROC(LINK, linkargs, linkres, 0),
1172 PROC(READDIR, readdirargs, readdirres, 3),
1173 PROC(READDIRPLUS, readdirargs, readdirres, 3),
1174 PROC(FSSTAT, fhandle, fsstatres, 0),
1175 PROC(FSINFO, fhandle, fsinfores, 0),
1176 PROC(PATHCONF, fhandle, pathconfres, 0),
1177 PROC(COMMIT, commitargs, commitres, 5),
1180 struct rpc_version nfs_version3 = {
1181 .number = 3,
1182 .nrprocs = ARRAY_SIZE(nfs3_procedures),
1183 .procs = nfs3_procedures
1186 #ifdef CONFIG_NFS_V3_ACL
1187 static struct rpc_procinfo nfs3_acl_procedures[] = {
1188 [ACLPROC3_GETACL] = {
1189 .p_proc = ACLPROC3_GETACL,
1190 .p_encode = (kxdrproc_t) nfs3_xdr_getaclargs,
1191 .p_decode = (kxdrproc_t) nfs3_xdr_getaclres,
1192 .p_arglen = ACL3_getaclargs_sz,
1193 .p_replen = ACL3_getaclres_sz,
1194 .p_timer = 1,
1195 .p_name = "GETACL",
1197 [ACLPROC3_SETACL] = {
1198 .p_proc = ACLPROC3_SETACL,
1199 .p_encode = (kxdrproc_t) nfs3_xdr_setaclargs,
1200 .p_decode = (kxdrproc_t) nfs3_xdr_setaclres,
1201 .p_arglen = ACL3_setaclargs_sz,
1202 .p_replen = ACL3_setaclres_sz,
1203 .p_timer = 0,
1204 .p_name = "SETACL",
1208 struct rpc_version nfsacl_version3 = {
1209 .number = 3,
1210 .nrprocs = sizeof(nfs3_acl_procedures)/
1211 sizeof(nfs3_acl_procedures[0]),
1212 .procs = nfs3_acl_procedures,
1214 #endif /* CONFIG_NFS_V3_ACL */