Merge git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-2.6
[linux-2.6/kvm.git] / fs / nfs / nfs3xdr.c
blob616d3267b7e7b545d02d0bb88c02a48e2cbe6e80
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 int hdrlen, recvd;
510 int status, nr;
511 unsigned int len, pglen;
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 %d > %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;
545 for (nr = 0; *p++; nr++) {
546 if (p + 3 > end)
547 goto short_pkt;
548 p += 2; /* inode # */
549 len = ntohl(*p++); /* string length */
550 p += XDR_QUADLEN(len) + 2; /* name + cookie */
551 if (len > NFS3_MAXNAMLEN) {
552 dprintk("NFS: giant filename in readdir (len %x)!\n",
553 len);
554 goto err_unmap;
557 if (res->plus) {
558 /* post_op_attr */
559 if (p + 2 > end)
560 goto short_pkt;
561 if (*p++) {
562 p += 21;
563 if (p + 1 > end)
564 goto short_pkt;
566 /* post_op_fh3 */
567 if (*p++) {
568 if (p + 1 > end)
569 goto short_pkt;
570 len = ntohl(*p++);
571 if (len > NFS3_FHSIZE) {
572 dprintk("NFS: giant filehandle in "
573 "readdir (len %x)!\n", len);
574 goto err_unmap;
576 p += XDR_QUADLEN(len);
580 if (p + 2 > end)
581 goto short_pkt;
582 entry = p;
584 if (!nr && (entry[0] != 0 || entry[1] == 0))
585 goto short_pkt;
586 out:
587 kunmap_atomic(kaddr, KM_USER0);
588 return nr;
589 short_pkt:
590 entry[0] = entry[1] = 0;
591 /* truncate listing ? */
592 if (!nr) {
593 dprintk("NFS: readdir reply truncated!\n");
594 entry[1] = 1;
596 goto out;
597 err_unmap:
598 nr = -errno_NFSERR_IO;
599 goto out;
602 __be32 *
603 nfs3_decode_dirent(__be32 *p, struct nfs_entry *entry, int plus)
605 struct nfs_entry old = *entry;
607 if (!*p++) {
608 if (!*p)
609 return ERR_PTR(-EAGAIN);
610 entry->eof = 1;
611 return ERR_PTR(-EBADCOOKIE);
614 p = xdr_decode_hyper(p, &entry->ino);
615 entry->len = ntohl(*p++);
616 entry->name = (const char *) p;
617 p += XDR_QUADLEN(entry->len);
618 entry->prev_cookie = entry->cookie;
619 p = xdr_decode_hyper(p, &entry->cookie);
621 if (plus) {
622 entry->fattr->valid = 0;
623 p = xdr_decode_post_op_attr(p, entry->fattr);
624 /* In fact, a post_op_fh3: */
625 if (*p++) {
626 p = xdr_decode_fhandle(p, entry->fh);
627 /* Ugh -- server reply was truncated */
628 if (p == NULL) {
629 dprintk("NFS: FH truncated\n");
630 *entry = old;
631 return ERR_PTR(-EAGAIN);
633 } else
634 memset((u8*)(entry->fh), 0, sizeof(*entry->fh));
637 entry->eof = !p[0] && p[1];
638 return p;
642 * Encode COMMIT arguments
644 static int
645 nfs3_xdr_commitargs(struct rpc_rqst *req, __be32 *p, struct nfs_writeargs *args)
647 p = xdr_encode_fhandle(p, args->fh);
648 p = xdr_encode_hyper(p, args->offset);
649 *p++ = htonl(args->count);
650 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
651 return 0;
654 #ifdef CONFIG_NFS_V3_ACL
656 * Encode GETACL arguments
658 static int
659 nfs3_xdr_getaclargs(struct rpc_rqst *req, __be32 *p,
660 struct nfs3_getaclargs *args)
662 struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth;
663 unsigned int replen;
665 p = xdr_encode_fhandle(p, args->fh);
666 *p++ = htonl(args->mask);
667 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
669 if (args->mask & (NFS_ACL | NFS_DFACL)) {
670 /* Inline the page array */
671 replen = (RPC_REPHDRSIZE + auth->au_rslack +
672 ACL3_getaclres_sz) << 2;
673 xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, 0,
674 NFSACL_MAXPAGES << PAGE_SHIFT);
676 return 0;
680 * Encode SETACL arguments
682 static int
683 nfs3_xdr_setaclargs(struct rpc_rqst *req, __be32 *p,
684 struct nfs3_setaclargs *args)
686 struct xdr_buf *buf = &req->rq_snd_buf;
687 unsigned int base, len_in_head, len = nfsacl_size(
688 (args->mask & NFS_ACL) ? args->acl_access : NULL,
689 (args->mask & NFS_DFACL) ? args->acl_default : NULL);
690 int count, err;
692 p = xdr_encode_fhandle(p, NFS_FH(args->inode));
693 *p++ = htonl(args->mask);
694 base = (char *)p - (char *)buf->head->iov_base;
695 /* put as much of the acls into head as possible. */
696 len_in_head = min_t(unsigned int, buf->head->iov_len - base, len);
697 len -= len_in_head;
698 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p + (len_in_head >> 2));
700 for (count = 0; (count << PAGE_SHIFT) < len; count++) {
701 args->pages[count] = alloc_page(GFP_KERNEL);
702 if (!args->pages[count]) {
703 while (count)
704 __free_page(args->pages[--count]);
705 return -ENOMEM;
708 xdr_encode_pages(buf, args->pages, 0, len);
710 err = nfsacl_encode(buf, base, args->inode,
711 (args->mask & NFS_ACL) ?
712 args->acl_access : NULL, 1, 0);
713 if (err > 0)
714 err = nfsacl_encode(buf, base + err, args->inode,
715 (args->mask & NFS_DFACL) ?
716 args->acl_default : NULL, 1,
717 NFS_ACL_DEFAULT);
718 return (err > 0) ? 0 : err;
720 #endif /* CONFIG_NFS_V3_ACL */
723 * NFS XDR decode functions
727 * Decode attrstat reply.
729 static int
730 nfs3_xdr_attrstat(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
732 int status;
734 if ((status = ntohl(*p++)))
735 return -nfs_stat_to_errno(status);
736 xdr_decode_fattr(p, fattr);
737 return 0;
741 * Decode status+wcc_data reply
742 * SATTR, REMOVE, RMDIR
744 static int
745 nfs3_xdr_wccstat(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
747 int status;
749 if ((status = ntohl(*p++)))
750 status = -nfs_stat_to_errno(status);
751 xdr_decode_wcc_data(p, fattr);
752 return status;
755 static int
756 nfs3_xdr_removeres(struct rpc_rqst *req, __be32 *p, struct nfs_removeres *res)
758 return nfs3_xdr_wccstat(req, p, &res->dir_attr);
762 * Decode LOOKUP reply
764 static int
765 nfs3_xdr_lookupres(struct rpc_rqst *req, __be32 *p, struct nfs3_diropres *res)
767 int status;
769 if ((status = ntohl(*p++))) {
770 status = -nfs_stat_to_errno(status);
771 } else {
772 if (!(p = xdr_decode_fhandle(p, res->fh)))
773 return -errno_NFSERR_IO;
774 p = xdr_decode_post_op_attr(p, res->fattr);
776 xdr_decode_post_op_attr(p, res->dir_attr);
777 return status;
781 * Decode ACCESS reply
783 static int
784 nfs3_xdr_accessres(struct rpc_rqst *req, __be32 *p, struct nfs3_accessres *res)
786 int status = ntohl(*p++);
788 p = xdr_decode_post_op_attr(p, res->fattr);
789 if (status)
790 return -nfs_stat_to_errno(status);
791 res->access = ntohl(*p++);
792 return 0;
795 static int
796 nfs3_xdr_readlinkargs(struct rpc_rqst *req, __be32 *p, struct nfs3_readlinkargs *args)
798 struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth;
799 unsigned int replen;
801 p = xdr_encode_fhandle(p, args->fh);
802 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
804 /* Inline the page array */
805 replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS3_readlinkres_sz) << 2;
806 xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, args->pgbase, args->pglen);
807 return 0;
811 * Decode READLINK reply
813 static int
814 nfs3_xdr_readlinkres(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
816 struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
817 struct kvec *iov = rcvbuf->head;
818 int hdrlen, len, recvd;
819 char *kaddr;
820 int status;
822 status = ntohl(*p++);
823 p = xdr_decode_post_op_attr(p, fattr);
825 if (status != 0)
826 return -nfs_stat_to_errno(status);
828 /* Convert length of symlink */
829 len = ntohl(*p++);
830 if (len >= rcvbuf->page_len || len <= 0) {
831 dprintk("nfs: server returned giant symlink!\n");
832 return -ENAMETOOLONG;
835 hdrlen = (u8 *) p - (u8 *) iov->iov_base;
836 if (iov->iov_len < hdrlen) {
837 dprintk("NFS: READLINK reply header overflowed:"
838 "length %d > %Zu\n", hdrlen, iov->iov_len);
839 return -errno_NFSERR_IO;
840 } else if (iov->iov_len != hdrlen) {
841 dprintk("NFS: READLINK header is short. "
842 "iovec will be shifted.\n");
843 xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen);
845 recvd = req->rq_rcv_buf.len - hdrlen;
846 if (recvd < len) {
847 dprintk("NFS: server cheating in readlink reply: "
848 "count %u > recvd %u\n", len, recvd);
849 return -EIO;
852 /* NULL terminate the string we got */
853 kaddr = (char*)kmap_atomic(rcvbuf->pages[0], KM_USER0);
854 kaddr[len+rcvbuf->page_base] = '\0';
855 kunmap_atomic(kaddr, KM_USER0);
856 return 0;
860 * Decode READ reply
862 static int
863 nfs3_xdr_readres(struct rpc_rqst *req, __be32 *p, struct nfs_readres *res)
865 struct kvec *iov = req->rq_rcv_buf.head;
866 int status, count, ocount, recvd, hdrlen;
868 status = ntohl(*p++);
869 p = xdr_decode_post_op_attr(p, res->fattr);
871 if (status != 0)
872 return -nfs_stat_to_errno(status);
874 /* Decode reply could and EOF flag. NFSv3 is somewhat redundant
875 * in that it puts the count both in the res struct and in the
876 * opaque data count. */
877 count = ntohl(*p++);
878 res->eof = ntohl(*p++);
879 ocount = ntohl(*p++);
881 if (ocount != count) {
882 dprintk("NFS: READ count doesn't match RPC opaque count.\n");
883 return -errno_NFSERR_IO;
886 hdrlen = (u8 *) p - (u8 *) iov->iov_base;
887 if (iov->iov_len < hdrlen) {
888 dprintk("NFS: READ reply header overflowed:"
889 "length %d > %Zu\n", hdrlen, iov->iov_len);
890 return -errno_NFSERR_IO;
891 } else if (iov->iov_len != hdrlen) {
892 dprintk("NFS: READ header is short. iovec will be shifted.\n");
893 xdr_shift_buf(&req->rq_rcv_buf, iov->iov_len - hdrlen);
896 recvd = req->rq_rcv_buf.len - hdrlen;
897 if (count > recvd) {
898 dprintk("NFS: server cheating in read reply: "
899 "count %d > recvd %d\n", count, recvd);
900 count = recvd;
901 res->eof = 0;
904 if (count < res->count)
905 res->count = count;
907 return count;
911 * Decode WRITE response
913 static int
914 nfs3_xdr_writeres(struct rpc_rqst *req, __be32 *p, struct nfs_writeres *res)
916 int status;
918 status = ntohl(*p++);
919 p = xdr_decode_wcc_data(p, res->fattr);
921 if (status != 0)
922 return -nfs_stat_to_errno(status);
924 res->count = ntohl(*p++);
925 res->verf->committed = (enum nfs3_stable_how)ntohl(*p++);
926 res->verf->verifier[0] = *p++;
927 res->verf->verifier[1] = *p++;
929 return res->count;
933 * Decode a CREATE response
935 static int
936 nfs3_xdr_createres(struct rpc_rqst *req, __be32 *p, struct nfs3_diropres *res)
938 int status;
940 status = ntohl(*p++);
941 if (status == 0) {
942 if (*p++) {
943 if (!(p = xdr_decode_fhandle(p, res->fh)))
944 return -errno_NFSERR_IO;
945 p = xdr_decode_post_op_attr(p, res->fattr);
946 } else {
947 memset(res->fh, 0, sizeof(*res->fh));
948 /* Do decode post_op_attr but set it to NULL */
949 p = xdr_decode_post_op_attr(p, res->fattr);
950 res->fattr->valid = 0;
952 } else {
953 status = -nfs_stat_to_errno(status);
955 p = xdr_decode_wcc_data(p, res->dir_attr);
956 return status;
960 * Decode RENAME reply
962 static int
963 nfs3_xdr_renameres(struct rpc_rqst *req, __be32 *p, struct nfs3_renameres *res)
965 int status;
967 if ((status = ntohl(*p++)) != 0)
968 status = -nfs_stat_to_errno(status);
969 p = xdr_decode_wcc_data(p, res->fromattr);
970 p = xdr_decode_wcc_data(p, res->toattr);
971 return status;
975 * Decode LINK reply
977 static int
978 nfs3_xdr_linkres(struct rpc_rqst *req, __be32 *p, struct nfs3_linkres *res)
980 int status;
982 if ((status = ntohl(*p++)) != 0)
983 status = -nfs_stat_to_errno(status);
984 p = xdr_decode_post_op_attr(p, res->fattr);
985 p = xdr_decode_wcc_data(p, res->dir_attr);
986 return status;
990 * Decode FSSTAT reply
992 static int
993 nfs3_xdr_fsstatres(struct rpc_rqst *req, __be32 *p, struct nfs_fsstat *res)
995 int status;
997 status = ntohl(*p++);
999 p = xdr_decode_post_op_attr(p, res->fattr);
1000 if (status != 0)
1001 return -nfs_stat_to_errno(status);
1003 p = xdr_decode_hyper(p, &res->tbytes);
1004 p = xdr_decode_hyper(p, &res->fbytes);
1005 p = xdr_decode_hyper(p, &res->abytes);
1006 p = xdr_decode_hyper(p, &res->tfiles);
1007 p = xdr_decode_hyper(p, &res->ffiles);
1008 p = xdr_decode_hyper(p, &res->afiles);
1010 /* ignore invarsec */
1011 return 0;
1015 * Decode FSINFO reply
1017 static int
1018 nfs3_xdr_fsinfores(struct rpc_rqst *req, __be32 *p, struct nfs_fsinfo *res)
1020 int status;
1022 status = ntohl(*p++);
1024 p = xdr_decode_post_op_attr(p, res->fattr);
1025 if (status != 0)
1026 return -nfs_stat_to_errno(status);
1028 res->rtmax = ntohl(*p++);
1029 res->rtpref = ntohl(*p++);
1030 res->rtmult = ntohl(*p++);
1031 res->wtmax = ntohl(*p++);
1032 res->wtpref = ntohl(*p++);
1033 res->wtmult = ntohl(*p++);
1034 res->dtpref = ntohl(*p++);
1035 p = xdr_decode_hyper(p, &res->maxfilesize);
1037 /* ignore time_delta and properties */
1038 res->lease_time = 0;
1039 return 0;
1043 * Decode PATHCONF reply
1045 static int
1046 nfs3_xdr_pathconfres(struct rpc_rqst *req, __be32 *p, struct nfs_pathconf *res)
1048 int status;
1050 status = ntohl(*p++);
1052 p = xdr_decode_post_op_attr(p, res->fattr);
1053 if (status != 0)
1054 return -nfs_stat_to_errno(status);
1055 res->max_link = ntohl(*p++);
1056 res->max_namelen = ntohl(*p++);
1058 /* ignore remaining fields */
1059 return 0;
1063 * Decode COMMIT reply
1065 static int
1066 nfs3_xdr_commitres(struct rpc_rqst *req, __be32 *p, struct nfs_writeres *res)
1068 int status;
1070 status = ntohl(*p++);
1071 p = xdr_decode_wcc_data(p, res->fattr);
1072 if (status != 0)
1073 return -nfs_stat_to_errno(status);
1075 res->verf->verifier[0] = *p++;
1076 res->verf->verifier[1] = *p++;
1077 return 0;
1080 #ifdef CONFIG_NFS_V3_ACL
1082 * Decode GETACL reply
1084 static int
1085 nfs3_xdr_getaclres(struct rpc_rqst *req, __be32 *p,
1086 struct nfs3_getaclres *res)
1088 struct xdr_buf *buf = &req->rq_rcv_buf;
1089 int status = ntohl(*p++);
1090 struct posix_acl **acl;
1091 unsigned int *aclcnt;
1092 int err, base;
1094 if (status != 0)
1095 return -nfs_stat_to_errno(status);
1096 p = xdr_decode_post_op_attr(p, res->fattr);
1097 res->mask = ntohl(*p++);
1098 if (res->mask & ~(NFS_ACL|NFS_ACLCNT|NFS_DFACL|NFS_DFACLCNT))
1099 return -EINVAL;
1100 base = (char *)p - (char *)req->rq_rcv_buf.head->iov_base;
1102 acl = (res->mask & NFS_ACL) ? &res->acl_access : NULL;
1103 aclcnt = (res->mask & NFS_ACLCNT) ? &res->acl_access_count : NULL;
1104 err = nfsacl_decode(buf, base, aclcnt, acl);
1106 acl = (res->mask & NFS_DFACL) ? &res->acl_default : NULL;
1107 aclcnt = (res->mask & NFS_DFACLCNT) ? &res->acl_default_count : NULL;
1108 if (err > 0)
1109 err = nfsacl_decode(buf, base + err, aclcnt, acl);
1110 return (err > 0) ? 0 : err;
1114 * Decode setacl reply.
1116 static int
1117 nfs3_xdr_setaclres(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
1119 int status = ntohl(*p++);
1121 if (status)
1122 return -nfs_stat_to_errno(status);
1123 xdr_decode_post_op_attr(p, fattr);
1124 return 0;
1126 #endif /* CONFIG_NFS_V3_ACL */
1128 #define PROC(proc, argtype, restype, timer) \
1129 [NFS3PROC_##proc] = { \
1130 .p_proc = NFS3PROC_##proc, \
1131 .p_encode = (kxdrproc_t) nfs3_xdr_##argtype, \
1132 .p_decode = (kxdrproc_t) nfs3_xdr_##restype, \
1133 .p_arglen = NFS3_##argtype##_sz, \
1134 .p_replen = NFS3_##restype##_sz, \
1135 .p_timer = timer, \
1136 .p_statidx = NFS3PROC_##proc, \
1137 .p_name = #proc, \
1140 struct rpc_procinfo nfs3_procedures[] = {
1141 PROC(GETATTR, fhandle, attrstat, 1),
1142 PROC(SETATTR, sattrargs, wccstat, 0),
1143 PROC(LOOKUP, diropargs, lookupres, 2),
1144 PROC(ACCESS, accessargs, accessres, 1),
1145 PROC(READLINK, readlinkargs, readlinkres, 3),
1146 PROC(READ, readargs, readres, 3),
1147 PROC(WRITE, writeargs, writeres, 4),
1148 PROC(CREATE, createargs, createres, 0),
1149 PROC(MKDIR, mkdirargs, createres, 0),
1150 PROC(SYMLINK, symlinkargs, createres, 0),
1151 PROC(MKNOD, mknodargs, createres, 0),
1152 PROC(REMOVE, removeargs, removeres, 0),
1153 PROC(RMDIR, diropargs, wccstat, 0),
1154 PROC(RENAME, renameargs, renameres, 0),
1155 PROC(LINK, linkargs, linkres, 0),
1156 PROC(READDIR, readdirargs, readdirres, 3),
1157 PROC(READDIRPLUS, readdirargs, readdirres, 3),
1158 PROC(FSSTAT, fhandle, fsstatres, 0),
1159 PROC(FSINFO, fhandle, fsinfores, 0),
1160 PROC(PATHCONF, fhandle, pathconfres, 0),
1161 PROC(COMMIT, commitargs, commitres, 5),
1164 struct rpc_version nfs_version3 = {
1165 .number = 3,
1166 .nrprocs = ARRAY_SIZE(nfs3_procedures),
1167 .procs = nfs3_procedures
1170 #ifdef CONFIG_NFS_V3_ACL
1171 static struct rpc_procinfo nfs3_acl_procedures[] = {
1172 [ACLPROC3_GETACL] = {
1173 .p_proc = ACLPROC3_GETACL,
1174 .p_encode = (kxdrproc_t) nfs3_xdr_getaclargs,
1175 .p_decode = (kxdrproc_t) nfs3_xdr_getaclres,
1176 .p_arglen = ACL3_getaclargs_sz,
1177 .p_replen = ACL3_getaclres_sz,
1178 .p_timer = 1,
1179 .p_name = "GETACL",
1181 [ACLPROC3_SETACL] = {
1182 .p_proc = ACLPROC3_SETACL,
1183 .p_encode = (kxdrproc_t) nfs3_xdr_setaclargs,
1184 .p_decode = (kxdrproc_t) nfs3_xdr_setaclres,
1185 .p_arglen = ACL3_setaclargs_sz,
1186 .p_replen = ACL3_setaclres_sz,
1187 .p_timer = 0,
1188 .p_name = "SETACL",
1192 struct rpc_version nfsacl_version3 = {
1193 .number = 3,
1194 .nrprocs = sizeof(nfs3_acl_procedures)/
1195 sizeof(nfs3_acl_procedures[0]),
1196 .procs = nfs3_acl_procedures,
1198 #endif /* CONFIG_NFS_V3_ACL */