NFS: clean up short packet handling for NFSv3 readdir
[linux-2.6/mini2440.git] / fs / nfs / nfs3xdr.c
blobfb03048ac650d4102bdaa990bdb21ba55245b602
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+2*(2+5*3))
86 #define ACL3_getaclres_sz (1+NFS3_post_op_attr_sz+1+2*(2+5*3))
87 #define ACL3_setaclres_sz (1+NFS3_post_op_attr_sz)
90 * Map file type to S_IFMT bits
92 static struct {
93 unsigned int mode;
94 unsigned int nfs2type;
95 } nfs_type2fmt[] = {
96 { 0, NFNON },
97 { S_IFREG, NFREG },
98 { S_IFDIR, NFDIR },
99 { S_IFBLK, NFBLK },
100 { S_IFCHR, NFCHR },
101 { S_IFLNK, NFLNK },
102 { S_IFSOCK, NFSOCK },
103 { S_IFIFO, NFFIFO },
104 { 0, NFBAD }
108 * Common NFS XDR functions as inlines
110 static inline __be32 *
111 xdr_encode_fhandle(__be32 *p, const struct nfs_fh *fh)
113 return xdr_encode_array(p, fh->data, fh->size);
116 static inline __be32 *
117 xdr_decode_fhandle(__be32 *p, struct nfs_fh *fh)
119 if ((fh->size = ntohl(*p++)) <= NFS3_FHSIZE) {
120 memcpy(fh->data, p, fh->size);
121 return p + XDR_QUADLEN(fh->size);
123 return NULL;
127 * Encode/decode time.
129 static inline __be32 *
130 xdr_encode_time3(__be32 *p, struct timespec *timep)
132 *p++ = htonl(timep->tv_sec);
133 *p++ = htonl(timep->tv_nsec);
134 return p;
137 static inline __be32 *
138 xdr_decode_time3(__be32 *p, struct timespec *timep)
140 timep->tv_sec = ntohl(*p++);
141 timep->tv_nsec = ntohl(*p++);
142 return p;
145 static __be32 *
146 xdr_decode_fattr(__be32 *p, struct nfs_fattr *fattr)
148 unsigned int type, major, minor;
149 int fmode;
151 type = ntohl(*p++);
152 if (type >= NF3BAD)
153 type = NF3BAD;
154 fmode = nfs_type2fmt[type].mode;
155 fattr->type = nfs_type2fmt[type].nfs2type;
156 fattr->mode = (ntohl(*p++) & ~S_IFMT) | fmode;
157 fattr->nlink = ntohl(*p++);
158 fattr->uid = ntohl(*p++);
159 fattr->gid = ntohl(*p++);
160 p = xdr_decode_hyper(p, &fattr->size);
161 p = xdr_decode_hyper(p, &fattr->du.nfs3.used);
163 /* Turn remote device info into Linux-specific dev_t */
164 major = ntohl(*p++);
165 minor = ntohl(*p++);
166 fattr->rdev = MKDEV(major, minor);
167 if (MAJOR(fattr->rdev) != major || MINOR(fattr->rdev) != minor)
168 fattr->rdev = 0;
170 p = xdr_decode_hyper(p, &fattr->fsid.major);
171 fattr->fsid.minor = 0;
172 p = xdr_decode_hyper(p, &fattr->fileid);
173 p = xdr_decode_time3(p, &fattr->atime);
174 p = xdr_decode_time3(p, &fattr->mtime);
175 p = xdr_decode_time3(p, &fattr->ctime);
177 /* Update the mode bits */
178 fattr->valid |= (NFS_ATTR_FATTR | NFS_ATTR_FATTR_V3);
179 return p;
182 static inline __be32 *
183 xdr_encode_sattr(__be32 *p, struct iattr *attr)
185 if (attr->ia_valid & ATTR_MODE) {
186 *p++ = xdr_one;
187 *p++ = htonl(attr->ia_mode & S_IALLUGO);
188 } else {
189 *p++ = xdr_zero;
191 if (attr->ia_valid & ATTR_UID) {
192 *p++ = xdr_one;
193 *p++ = htonl(attr->ia_uid);
194 } else {
195 *p++ = xdr_zero;
197 if (attr->ia_valid & ATTR_GID) {
198 *p++ = xdr_one;
199 *p++ = htonl(attr->ia_gid);
200 } else {
201 *p++ = xdr_zero;
203 if (attr->ia_valid & ATTR_SIZE) {
204 *p++ = xdr_one;
205 p = xdr_encode_hyper(p, (__u64) attr->ia_size);
206 } else {
207 *p++ = xdr_zero;
209 if (attr->ia_valid & ATTR_ATIME_SET) {
210 *p++ = xdr_two;
211 p = xdr_encode_time3(p, &attr->ia_atime);
212 } else if (attr->ia_valid & ATTR_ATIME) {
213 *p++ = xdr_one;
214 } else {
215 *p++ = xdr_zero;
217 if (attr->ia_valid & ATTR_MTIME_SET) {
218 *p++ = xdr_two;
219 p = xdr_encode_time3(p, &attr->ia_mtime);
220 } else if (attr->ia_valid & ATTR_MTIME) {
221 *p++ = xdr_one;
222 } else {
223 *p++ = xdr_zero;
225 return p;
228 static inline __be32 *
229 xdr_decode_wcc_attr(__be32 *p, struct nfs_fattr *fattr)
231 p = xdr_decode_hyper(p, &fattr->pre_size);
232 p = xdr_decode_time3(p, &fattr->pre_mtime);
233 p = xdr_decode_time3(p, &fattr->pre_ctime);
234 fattr->valid |= NFS_ATTR_WCC;
235 return p;
238 static inline __be32 *
239 xdr_decode_post_op_attr(__be32 *p, struct nfs_fattr *fattr)
241 if (*p++)
242 p = xdr_decode_fattr(p, fattr);
243 return p;
246 static inline __be32 *
247 xdr_decode_pre_op_attr(__be32 *p, struct nfs_fattr *fattr)
249 if (*p++)
250 return xdr_decode_wcc_attr(p, fattr);
251 return p;
255 static inline __be32 *
256 xdr_decode_wcc_data(__be32 *p, struct nfs_fattr *fattr)
258 p = xdr_decode_pre_op_attr(p, fattr);
259 return xdr_decode_post_op_attr(p, fattr);
263 * NFS encode functions
267 * Encode file handle argument
269 static int
270 nfs3_xdr_fhandle(struct rpc_rqst *req, __be32 *p, struct nfs_fh *fh)
272 p = xdr_encode_fhandle(p, fh);
273 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
274 return 0;
278 * Encode SETATTR arguments
280 static int
281 nfs3_xdr_sattrargs(struct rpc_rqst *req, __be32 *p, struct nfs3_sattrargs *args)
283 p = xdr_encode_fhandle(p, args->fh);
284 p = xdr_encode_sattr(p, args->sattr);
285 *p++ = htonl(args->guard);
286 if (args->guard)
287 p = xdr_encode_time3(p, &args->guardtime);
288 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
289 return 0;
293 * Encode directory ops argument
295 static int
296 nfs3_xdr_diropargs(struct rpc_rqst *req, __be32 *p, struct nfs3_diropargs *args)
298 p = xdr_encode_fhandle(p, args->fh);
299 p = xdr_encode_array(p, args->name, args->len);
300 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
301 return 0;
305 * Encode REMOVE argument
307 static int
308 nfs3_xdr_removeargs(struct rpc_rqst *req, __be32 *p, const struct nfs_removeargs *args)
310 p = xdr_encode_fhandle(p, args->fh);
311 p = xdr_encode_array(p, args->name.name, args->name.len);
312 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
313 return 0;
317 * Encode access() argument
319 static int
320 nfs3_xdr_accessargs(struct rpc_rqst *req, __be32 *p, struct nfs3_accessargs *args)
322 p = xdr_encode_fhandle(p, args->fh);
323 *p++ = htonl(args->access);
324 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
325 return 0;
329 * Arguments to a READ call. Since we read data directly into the page
330 * cache, we also set up the reply iovec here so that iov[1] points
331 * exactly to the page we want to fetch.
333 static int
334 nfs3_xdr_readargs(struct rpc_rqst *req, __be32 *p, struct nfs_readargs *args)
336 struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth;
337 unsigned int replen;
338 u32 count = args->count;
340 p = xdr_encode_fhandle(p, args->fh);
341 p = xdr_encode_hyper(p, args->offset);
342 *p++ = htonl(count);
343 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
345 /* Inline the page array */
346 replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS3_readres_sz) << 2;
347 xdr_inline_pages(&req->rq_rcv_buf, replen,
348 args->pages, args->pgbase, count);
349 req->rq_rcv_buf.flags |= XDRBUF_READ;
350 return 0;
354 * Write arguments. Splice the buffer to be written into the iovec.
356 static int
357 nfs3_xdr_writeargs(struct rpc_rqst *req, __be32 *p, struct nfs_writeargs *args)
359 struct xdr_buf *sndbuf = &req->rq_snd_buf;
360 u32 count = args->count;
362 p = xdr_encode_fhandle(p, args->fh);
363 p = xdr_encode_hyper(p, args->offset);
364 *p++ = htonl(count);
365 *p++ = htonl(args->stable);
366 *p++ = htonl(count);
367 sndbuf->len = xdr_adjust_iovec(sndbuf->head, p);
369 /* Copy the page array */
370 xdr_encode_pages(sndbuf, args->pages, args->pgbase, count);
371 sndbuf->flags |= XDRBUF_WRITE;
372 return 0;
376 * Encode CREATE arguments
378 static int
379 nfs3_xdr_createargs(struct rpc_rqst *req, __be32 *p, struct nfs3_createargs *args)
381 p = xdr_encode_fhandle(p, args->fh);
382 p = xdr_encode_array(p, args->name, args->len);
384 *p++ = htonl(args->createmode);
385 if (args->createmode == NFS3_CREATE_EXCLUSIVE) {
386 *p++ = args->verifier[0];
387 *p++ = args->verifier[1];
388 } else
389 p = xdr_encode_sattr(p, args->sattr);
391 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
392 return 0;
396 * Encode MKDIR arguments
398 static int
399 nfs3_xdr_mkdirargs(struct rpc_rqst *req, __be32 *p, struct nfs3_mkdirargs *args)
401 p = xdr_encode_fhandle(p, args->fh);
402 p = xdr_encode_array(p, args->name, args->len);
403 p = xdr_encode_sattr(p, args->sattr);
404 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
405 return 0;
409 * Encode SYMLINK arguments
411 static int
412 nfs3_xdr_symlinkargs(struct rpc_rqst *req, __be32 *p, struct nfs3_symlinkargs *args)
414 p = xdr_encode_fhandle(p, args->fromfh);
415 p = xdr_encode_array(p, args->fromname, args->fromlen);
416 p = xdr_encode_sattr(p, args->sattr);
417 *p++ = htonl(args->pathlen);
418 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
420 /* Copy the page */
421 xdr_encode_pages(&req->rq_snd_buf, args->pages, 0, args->pathlen);
422 return 0;
426 * Encode MKNOD arguments
428 static int
429 nfs3_xdr_mknodargs(struct rpc_rqst *req, __be32 *p, struct nfs3_mknodargs *args)
431 p = xdr_encode_fhandle(p, args->fh);
432 p = xdr_encode_array(p, args->name, args->len);
433 *p++ = htonl(args->type);
434 p = xdr_encode_sattr(p, args->sattr);
435 if (args->type == NF3CHR || args->type == NF3BLK) {
436 *p++ = htonl(MAJOR(args->rdev));
437 *p++ = htonl(MINOR(args->rdev));
440 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
441 return 0;
445 * Encode RENAME arguments
447 static int
448 nfs3_xdr_renameargs(struct rpc_rqst *req, __be32 *p, struct nfs3_renameargs *args)
450 p = xdr_encode_fhandle(p, args->fromfh);
451 p = xdr_encode_array(p, args->fromname, args->fromlen);
452 p = xdr_encode_fhandle(p, args->tofh);
453 p = xdr_encode_array(p, args->toname, args->tolen);
454 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
455 return 0;
459 * Encode LINK arguments
461 static int
462 nfs3_xdr_linkargs(struct rpc_rqst *req, __be32 *p, struct nfs3_linkargs *args)
464 p = xdr_encode_fhandle(p, args->fromfh);
465 p = xdr_encode_fhandle(p, args->tofh);
466 p = xdr_encode_array(p, args->toname, args->tolen);
467 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
468 return 0;
472 * Encode arguments to readdir call
474 static int
475 nfs3_xdr_readdirargs(struct rpc_rqst *req, __be32 *p, struct nfs3_readdirargs *args)
477 struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth;
478 unsigned int replen;
479 u32 count = args->count;
481 p = xdr_encode_fhandle(p, args->fh);
482 p = xdr_encode_hyper(p, args->cookie);
483 *p++ = args->verf[0];
484 *p++ = args->verf[1];
485 if (args->plus) {
486 /* readdirplus: need dircount + buffer size.
487 * We just make sure we make dircount big enough */
488 *p++ = htonl(count >> 3);
490 *p++ = htonl(count);
491 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
493 /* Inline the page array */
494 replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS3_readdirres_sz) << 2;
495 xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, 0, count);
496 return 0;
500 * Decode the result of a readdir call.
501 * We just check for syntactical correctness.
503 static int
504 nfs3_xdr_readdirres(struct rpc_rqst *req, __be32 *p, struct nfs3_readdirres *res)
506 struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
507 struct kvec *iov = rcvbuf->head;
508 struct page **page;
509 size_t hdrlen;
510 u32 len, recvd, pglen;
511 int status, nr = 0;
512 __be32 *entry, *end, *kaddr;
514 status = ntohl(*p++);
515 /* Decode post_op_attrs */
516 p = xdr_decode_post_op_attr(p, res->dir_attr);
517 if (status)
518 return -nfs_stat_to_errno(status);
519 /* Decode verifier cookie */
520 if (res->verf) {
521 res->verf[0] = *p++;
522 res->verf[1] = *p++;
523 } else {
524 p += 2;
527 hdrlen = (u8 *) p - (u8 *) iov->iov_base;
528 if (iov->iov_len < hdrlen) {
529 dprintk("NFS: READDIR reply header overflowed:"
530 "length %Zu > %Zu\n", hdrlen, iov->iov_len);
531 return -errno_NFSERR_IO;
532 } else if (iov->iov_len != hdrlen) {
533 dprintk("NFS: READDIR header is short. iovec will be shifted.\n");
534 xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen);
537 pglen = rcvbuf->page_len;
538 recvd = rcvbuf->len - hdrlen;
539 if (pglen > recvd)
540 pglen = recvd;
541 page = rcvbuf->pages;
542 kaddr = p = kmap_atomic(*page, KM_USER0);
543 end = (__be32 *)((char *)p + pglen);
544 entry = p;
546 /* Make sure the packet actually has a value_follows and EOF entry */
547 if ((entry + 1) > end)
548 goto short_pkt;
550 for (; *p++; nr++) {
551 if (p + 3 > end)
552 goto short_pkt;
553 p += 2; /* inode # */
554 len = ntohl(*p++); /* string length */
555 p += XDR_QUADLEN(len) + 2; /* name + cookie */
556 if (len > NFS3_MAXNAMLEN) {
557 dprintk("NFS: giant filename in readdir (len 0x%x)!\n",
558 len);
559 goto err_unmap;
562 if (res->plus) {
563 /* post_op_attr */
564 if (p + 2 > end)
565 goto short_pkt;
566 if (*p++) {
567 p += 21;
568 if (p + 1 > end)
569 goto short_pkt;
571 /* post_op_fh3 */
572 if (*p++) {
573 if (p + 1 > end)
574 goto short_pkt;
575 len = ntohl(*p++);
576 if (len > NFS3_FHSIZE) {
577 dprintk("NFS: giant filehandle in "
578 "readdir (len 0x%x)!\n", len);
579 goto err_unmap;
581 p += XDR_QUADLEN(len);
585 if (p + 2 > end)
586 goto short_pkt;
587 entry = p;
591 * Apparently some server sends responses that are a valid size, but
592 * contain no entries, and have value_follows==0 and EOF==0. For
593 * those, just set the EOF marker.
595 if (!nr && entry[1] == 0) {
596 dprintk("NFS: readdir reply truncated!\n");
597 entry[1] = 1;
599 out:
600 kunmap_atomic(kaddr, KM_USER0);
601 return nr;
602 short_pkt:
604 * When we get a short packet there are 2 possibilities. We can
605 * return an error, or fix up the response to look like a valid
606 * response and return what we have so far. If there are no
607 * entries and the packet was short, then return -EIO. If there
608 * are valid entries in the response, return them and pretend that
609 * the call was successful, but incomplete. The caller can retry the
610 * readdir starting at the last cookie.
612 entry[0] = entry[1] = 0;
613 if (!nr)
614 nr = -errno_NFSERR_IO;
615 goto out;
616 err_unmap:
617 nr = -errno_NFSERR_IO;
618 goto out;
621 __be32 *
622 nfs3_decode_dirent(__be32 *p, struct nfs_entry *entry, int plus)
624 struct nfs_entry old = *entry;
626 if (!*p++) {
627 if (!*p)
628 return ERR_PTR(-EAGAIN);
629 entry->eof = 1;
630 return ERR_PTR(-EBADCOOKIE);
633 p = xdr_decode_hyper(p, &entry->ino);
634 entry->len = ntohl(*p++);
635 entry->name = (const char *) p;
636 p += XDR_QUADLEN(entry->len);
637 entry->prev_cookie = entry->cookie;
638 p = xdr_decode_hyper(p, &entry->cookie);
640 if (plus) {
641 entry->fattr->valid = 0;
642 p = xdr_decode_post_op_attr(p, entry->fattr);
643 /* In fact, a post_op_fh3: */
644 if (*p++) {
645 p = xdr_decode_fhandle(p, entry->fh);
646 /* Ugh -- server reply was truncated */
647 if (p == NULL) {
648 dprintk("NFS: FH truncated\n");
649 *entry = old;
650 return ERR_PTR(-EAGAIN);
652 } else
653 memset((u8*)(entry->fh), 0, sizeof(*entry->fh));
656 entry->eof = !p[0] && p[1];
657 return p;
661 * Encode COMMIT arguments
663 static int
664 nfs3_xdr_commitargs(struct rpc_rqst *req, __be32 *p, struct nfs_writeargs *args)
666 p = xdr_encode_fhandle(p, args->fh);
667 p = xdr_encode_hyper(p, args->offset);
668 *p++ = htonl(args->count);
669 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
670 return 0;
673 #ifdef CONFIG_NFS_V3_ACL
675 * Encode GETACL arguments
677 static int
678 nfs3_xdr_getaclargs(struct rpc_rqst *req, __be32 *p,
679 struct nfs3_getaclargs *args)
681 struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth;
682 unsigned int replen;
684 p = xdr_encode_fhandle(p, args->fh);
685 *p++ = htonl(args->mask);
686 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
688 if (args->mask & (NFS_ACL | NFS_DFACL)) {
689 /* Inline the page array */
690 replen = (RPC_REPHDRSIZE + auth->au_rslack +
691 ACL3_getaclres_sz) << 2;
692 xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, 0,
693 NFSACL_MAXPAGES << PAGE_SHIFT);
695 return 0;
699 * Encode SETACL arguments
701 static int
702 nfs3_xdr_setaclargs(struct rpc_rqst *req, __be32 *p,
703 struct nfs3_setaclargs *args)
705 struct xdr_buf *buf = &req->rq_snd_buf;
706 unsigned int base, len_in_head, len = nfsacl_size(
707 (args->mask & NFS_ACL) ? args->acl_access : NULL,
708 (args->mask & NFS_DFACL) ? args->acl_default : NULL);
709 int count, err;
711 p = xdr_encode_fhandle(p, NFS_FH(args->inode));
712 *p++ = htonl(args->mask);
713 base = (char *)p - (char *)buf->head->iov_base;
714 /* put as much of the acls into head as possible. */
715 len_in_head = min_t(unsigned int, buf->head->iov_len - base, len);
716 len -= len_in_head;
717 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p + (len_in_head >> 2));
719 for (count = 0; (count << PAGE_SHIFT) < len; count++) {
720 args->pages[count] = alloc_page(GFP_KERNEL);
721 if (!args->pages[count]) {
722 while (count)
723 __free_page(args->pages[--count]);
724 return -ENOMEM;
727 xdr_encode_pages(buf, args->pages, 0, len);
729 err = nfsacl_encode(buf, base, args->inode,
730 (args->mask & NFS_ACL) ?
731 args->acl_access : NULL, 1, 0);
732 if (err > 0)
733 err = nfsacl_encode(buf, base + err, args->inode,
734 (args->mask & NFS_DFACL) ?
735 args->acl_default : NULL, 1,
736 NFS_ACL_DEFAULT);
737 return (err > 0) ? 0 : err;
739 #endif /* CONFIG_NFS_V3_ACL */
742 * NFS XDR decode functions
746 * Decode attrstat reply.
748 static int
749 nfs3_xdr_attrstat(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
751 int status;
753 if ((status = ntohl(*p++)))
754 return -nfs_stat_to_errno(status);
755 xdr_decode_fattr(p, fattr);
756 return 0;
760 * Decode status+wcc_data reply
761 * SATTR, REMOVE, RMDIR
763 static int
764 nfs3_xdr_wccstat(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
766 int status;
768 if ((status = ntohl(*p++)))
769 status = -nfs_stat_to_errno(status);
770 xdr_decode_wcc_data(p, fattr);
771 return status;
774 static int
775 nfs3_xdr_removeres(struct rpc_rqst *req, __be32 *p, struct nfs_removeres *res)
777 return nfs3_xdr_wccstat(req, p, &res->dir_attr);
781 * Decode LOOKUP reply
783 static int
784 nfs3_xdr_lookupres(struct rpc_rqst *req, __be32 *p, struct nfs3_diropres *res)
786 int status;
788 if ((status = ntohl(*p++))) {
789 status = -nfs_stat_to_errno(status);
790 } else {
791 if (!(p = xdr_decode_fhandle(p, res->fh)))
792 return -errno_NFSERR_IO;
793 p = xdr_decode_post_op_attr(p, res->fattr);
795 xdr_decode_post_op_attr(p, res->dir_attr);
796 return status;
800 * Decode ACCESS reply
802 static int
803 nfs3_xdr_accessres(struct rpc_rqst *req, __be32 *p, struct nfs3_accessres *res)
805 int status = ntohl(*p++);
807 p = xdr_decode_post_op_attr(p, res->fattr);
808 if (status)
809 return -nfs_stat_to_errno(status);
810 res->access = ntohl(*p++);
811 return 0;
814 static int
815 nfs3_xdr_readlinkargs(struct rpc_rqst *req, __be32 *p, struct nfs3_readlinkargs *args)
817 struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth;
818 unsigned int replen;
820 p = xdr_encode_fhandle(p, args->fh);
821 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
823 /* Inline the page array */
824 replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS3_readlinkres_sz) << 2;
825 xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, args->pgbase, args->pglen);
826 return 0;
830 * Decode READLINK reply
832 static int
833 nfs3_xdr_readlinkres(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
835 struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
836 struct kvec *iov = rcvbuf->head;
837 size_t hdrlen;
838 u32 len, recvd;
839 char *kaddr;
840 int status;
842 status = ntohl(*p++);
843 p = xdr_decode_post_op_attr(p, fattr);
845 if (status != 0)
846 return -nfs_stat_to_errno(status);
848 /* Convert length of symlink */
849 len = ntohl(*p++);
850 if (len >= rcvbuf->page_len) {
851 dprintk("nfs: server returned giant symlink!\n");
852 return -ENAMETOOLONG;
855 hdrlen = (u8 *) p - (u8 *) iov->iov_base;
856 if (iov->iov_len < hdrlen) {
857 dprintk("NFS: READLINK reply header overflowed:"
858 "length %Zu > %Zu\n", hdrlen, iov->iov_len);
859 return -errno_NFSERR_IO;
860 } else if (iov->iov_len != hdrlen) {
861 dprintk("NFS: READLINK header is short. "
862 "iovec will be shifted.\n");
863 xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen);
865 recvd = req->rq_rcv_buf.len - hdrlen;
866 if (recvd < len) {
867 dprintk("NFS: server cheating in readlink reply: "
868 "count %u > recvd %u\n", len, recvd);
869 return -EIO;
872 /* NULL terminate the string we got */
873 kaddr = (char*)kmap_atomic(rcvbuf->pages[0], KM_USER0);
874 kaddr[len+rcvbuf->page_base] = '\0';
875 kunmap_atomic(kaddr, KM_USER0);
876 return 0;
880 * Decode READ reply
882 static int
883 nfs3_xdr_readres(struct rpc_rqst *req, __be32 *p, struct nfs_readres *res)
885 struct kvec *iov = req->rq_rcv_buf.head;
886 size_t hdrlen;
887 u32 count, ocount, recvd;
888 int status;
890 status = ntohl(*p++);
891 p = xdr_decode_post_op_attr(p, res->fattr);
893 if (status != 0)
894 return -nfs_stat_to_errno(status);
896 /* Decode reply count and EOF flag. NFSv3 is somewhat redundant
897 * in that it puts the count both in the res struct and in the
898 * opaque data count. */
899 count = ntohl(*p++);
900 res->eof = ntohl(*p++);
901 ocount = ntohl(*p++);
903 if (ocount != count) {
904 dprintk("NFS: READ count doesn't match RPC opaque count.\n");
905 return -errno_NFSERR_IO;
908 hdrlen = (u8 *) p - (u8 *) iov->iov_base;
909 if (iov->iov_len < hdrlen) {
910 dprintk("NFS: READ reply header overflowed:"
911 "length %Zu > %Zu\n", hdrlen, iov->iov_len);
912 return -errno_NFSERR_IO;
913 } else if (iov->iov_len != hdrlen) {
914 dprintk("NFS: READ header is short. iovec will be shifted.\n");
915 xdr_shift_buf(&req->rq_rcv_buf, iov->iov_len - hdrlen);
918 recvd = req->rq_rcv_buf.len - hdrlen;
919 if (count > recvd) {
920 dprintk("NFS: server cheating in read reply: "
921 "count %u > recvd %u\n", count, recvd);
922 count = recvd;
923 res->eof = 0;
926 if (count < res->count)
927 res->count = count;
929 return count;
933 * Decode WRITE response
935 static int
936 nfs3_xdr_writeres(struct rpc_rqst *req, __be32 *p, struct nfs_writeres *res)
938 int status;
940 status = ntohl(*p++);
941 p = xdr_decode_wcc_data(p, res->fattr);
943 if (status != 0)
944 return -nfs_stat_to_errno(status);
946 res->count = ntohl(*p++);
947 res->verf->committed = (enum nfs3_stable_how)ntohl(*p++);
948 res->verf->verifier[0] = *p++;
949 res->verf->verifier[1] = *p++;
951 return res->count;
955 * Decode a CREATE response
957 static int
958 nfs3_xdr_createres(struct rpc_rqst *req, __be32 *p, struct nfs3_diropres *res)
960 int status;
962 status = ntohl(*p++);
963 if (status == 0) {
964 if (*p++) {
965 if (!(p = xdr_decode_fhandle(p, res->fh)))
966 return -errno_NFSERR_IO;
967 p = xdr_decode_post_op_attr(p, res->fattr);
968 } else {
969 memset(res->fh, 0, sizeof(*res->fh));
970 /* Do decode post_op_attr but set it to NULL */
971 p = xdr_decode_post_op_attr(p, res->fattr);
972 res->fattr->valid = 0;
974 } else {
975 status = -nfs_stat_to_errno(status);
977 p = xdr_decode_wcc_data(p, res->dir_attr);
978 return status;
982 * Decode RENAME reply
984 static int
985 nfs3_xdr_renameres(struct rpc_rqst *req, __be32 *p, struct nfs3_renameres *res)
987 int status;
989 if ((status = ntohl(*p++)) != 0)
990 status = -nfs_stat_to_errno(status);
991 p = xdr_decode_wcc_data(p, res->fromattr);
992 p = xdr_decode_wcc_data(p, res->toattr);
993 return status;
997 * Decode LINK reply
999 static int
1000 nfs3_xdr_linkres(struct rpc_rqst *req, __be32 *p, struct nfs3_linkres *res)
1002 int status;
1004 if ((status = ntohl(*p++)) != 0)
1005 status = -nfs_stat_to_errno(status);
1006 p = xdr_decode_post_op_attr(p, res->fattr);
1007 p = xdr_decode_wcc_data(p, res->dir_attr);
1008 return status;
1012 * Decode FSSTAT reply
1014 static int
1015 nfs3_xdr_fsstatres(struct rpc_rqst *req, __be32 *p, struct nfs_fsstat *res)
1017 int status;
1019 status = ntohl(*p++);
1021 p = xdr_decode_post_op_attr(p, res->fattr);
1022 if (status != 0)
1023 return -nfs_stat_to_errno(status);
1025 p = xdr_decode_hyper(p, &res->tbytes);
1026 p = xdr_decode_hyper(p, &res->fbytes);
1027 p = xdr_decode_hyper(p, &res->abytes);
1028 p = xdr_decode_hyper(p, &res->tfiles);
1029 p = xdr_decode_hyper(p, &res->ffiles);
1030 p = xdr_decode_hyper(p, &res->afiles);
1032 /* ignore invarsec */
1033 return 0;
1037 * Decode FSINFO reply
1039 static int
1040 nfs3_xdr_fsinfores(struct rpc_rqst *req, __be32 *p, struct nfs_fsinfo *res)
1042 int status;
1044 status = ntohl(*p++);
1046 p = xdr_decode_post_op_attr(p, res->fattr);
1047 if (status != 0)
1048 return -nfs_stat_to_errno(status);
1050 res->rtmax = ntohl(*p++);
1051 res->rtpref = ntohl(*p++);
1052 res->rtmult = ntohl(*p++);
1053 res->wtmax = ntohl(*p++);
1054 res->wtpref = ntohl(*p++);
1055 res->wtmult = ntohl(*p++);
1056 res->dtpref = ntohl(*p++);
1057 p = xdr_decode_hyper(p, &res->maxfilesize);
1059 /* ignore time_delta and properties */
1060 res->lease_time = 0;
1061 return 0;
1065 * Decode PATHCONF reply
1067 static int
1068 nfs3_xdr_pathconfres(struct rpc_rqst *req, __be32 *p, struct nfs_pathconf *res)
1070 int status;
1072 status = ntohl(*p++);
1074 p = xdr_decode_post_op_attr(p, res->fattr);
1075 if (status != 0)
1076 return -nfs_stat_to_errno(status);
1077 res->max_link = ntohl(*p++);
1078 res->max_namelen = ntohl(*p++);
1080 /* ignore remaining fields */
1081 return 0;
1085 * Decode COMMIT reply
1087 static int
1088 nfs3_xdr_commitres(struct rpc_rqst *req, __be32 *p, struct nfs_writeres *res)
1090 int status;
1092 status = ntohl(*p++);
1093 p = xdr_decode_wcc_data(p, res->fattr);
1094 if (status != 0)
1095 return -nfs_stat_to_errno(status);
1097 res->verf->verifier[0] = *p++;
1098 res->verf->verifier[1] = *p++;
1099 return 0;
1102 #ifdef CONFIG_NFS_V3_ACL
1104 * Decode GETACL reply
1106 static int
1107 nfs3_xdr_getaclres(struct rpc_rqst *req, __be32 *p,
1108 struct nfs3_getaclres *res)
1110 struct xdr_buf *buf = &req->rq_rcv_buf;
1111 int status = ntohl(*p++);
1112 struct posix_acl **acl;
1113 unsigned int *aclcnt;
1114 int err, base;
1116 if (status != 0)
1117 return -nfs_stat_to_errno(status);
1118 p = xdr_decode_post_op_attr(p, res->fattr);
1119 res->mask = ntohl(*p++);
1120 if (res->mask & ~(NFS_ACL|NFS_ACLCNT|NFS_DFACL|NFS_DFACLCNT))
1121 return -EINVAL;
1122 base = (char *)p - (char *)req->rq_rcv_buf.head->iov_base;
1124 acl = (res->mask & NFS_ACL) ? &res->acl_access : NULL;
1125 aclcnt = (res->mask & NFS_ACLCNT) ? &res->acl_access_count : NULL;
1126 err = nfsacl_decode(buf, base, aclcnt, acl);
1128 acl = (res->mask & NFS_DFACL) ? &res->acl_default : NULL;
1129 aclcnt = (res->mask & NFS_DFACLCNT) ? &res->acl_default_count : NULL;
1130 if (err > 0)
1131 err = nfsacl_decode(buf, base + err, aclcnt, acl);
1132 return (err > 0) ? 0 : err;
1136 * Decode setacl reply.
1138 static int
1139 nfs3_xdr_setaclres(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
1141 int status = ntohl(*p++);
1143 if (status)
1144 return -nfs_stat_to_errno(status);
1145 xdr_decode_post_op_attr(p, fattr);
1146 return 0;
1148 #endif /* CONFIG_NFS_V3_ACL */
1150 #define PROC(proc, argtype, restype, timer) \
1151 [NFS3PROC_##proc] = { \
1152 .p_proc = NFS3PROC_##proc, \
1153 .p_encode = (kxdrproc_t) nfs3_xdr_##argtype, \
1154 .p_decode = (kxdrproc_t) nfs3_xdr_##restype, \
1155 .p_arglen = NFS3_##argtype##_sz, \
1156 .p_replen = NFS3_##restype##_sz, \
1157 .p_timer = timer, \
1158 .p_statidx = NFS3PROC_##proc, \
1159 .p_name = #proc, \
1162 struct rpc_procinfo nfs3_procedures[] = {
1163 PROC(GETATTR, fhandle, attrstat, 1),
1164 PROC(SETATTR, sattrargs, wccstat, 0),
1165 PROC(LOOKUP, diropargs, lookupres, 2),
1166 PROC(ACCESS, accessargs, accessres, 1),
1167 PROC(READLINK, readlinkargs, readlinkres, 3),
1168 PROC(READ, readargs, readres, 3),
1169 PROC(WRITE, writeargs, writeres, 4),
1170 PROC(CREATE, createargs, createres, 0),
1171 PROC(MKDIR, mkdirargs, createres, 0),
1172 PROC(SYMLINK, symlinkargs, createres, 0),
1173 PROC(MKNOD, mknodargs, createres, 0),
1174 PROC(REMOVE, removeargs, removeres, 0),
1175 PROC(RMDIR, diropargs, wccstat, 0),
1176 PROC(RENAME, renameargs, renameres, 0),
1177 PROC(LINK, linkargs, linkres, 0),
1178 PROC(READDIR, readdirargs, readdirres, 3),
1179 PROC(READDIRPLUS, readdirargs, readdirres, 3),
1180 PROC(FSSTAT, fhandle, fsstatres, 0),
1181 PROC(FSINFO, fhandle, fsinfores, 0),
1182 PROC(PATHCONF, fhandle, pathconfres, 0),
1183 PROC(COMMIT, commitargs, commitres, 5),
1186 struct rpc_version nfs_version3 = {
1187 .number = 3,
1188 .nrprocs = ARRAY_SIZE(nfs3_procedures),
1189 .procs = nfs3_procedures
1192 #ifdef CONFIG_NFS_V3_ACL
1193 static struct rpc_procinfo nfs3_acl_procedures[] = {
1194 [ACLPROC3_GETACL] = {
1195 .p_proc = ACLPROC3_GETACL,
1196 .p_encode = (kxdrproc_t) nfs3_xdr_getaclargs,
1197 .p_decode = (kxdrproc_t) nfs3_xdr_getaclres,
1198 .p_arglen = ACL3_getaclargs_sz,
1199 .p_replen = ACL3_getaclres_sz,
1200 .p_timer = 1,
1201 .p_name = "GETACL",
1203 [ACLPROC3_SETACL] = {
1204 .p_proc = ACLPROC3_SETACL,
1205 .p_encode = (kxdrproc_t) nfs3_xdr_setaclargs,
1206 .p_decode = (kxdrproc_t) nfs3_xdr_setaclres,
1207 .p_arglen = ACL3_setaclargs_sz,
1208 .p_replen = ACL3_setaclres_sz,
1209 .p_timer = 0,
1210 .p_name = "SETACL",
1214 struct rpc_version nfsacl_version3 = {
1215 .number = 3,
1216 .nrprocs = sizeof(nfs3_acl_procedures)/
1217 sizeof(nfs3_acl_procedures[0]),
1218 .procs = nfs3_acl_procedures,
1220 #endif /* CONFIG_NFS_V3_ACL */