Linux-2.6.12-rc2
[linux-2.6/linux-acpi-2.6/ibm-acpi-2.6.git] / fs / nfs / nfs3xdr.c
bloba3593d47e5ab7ec3b70d9eeeaf139c91d433564c
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>
25 #define NFSDBG_FACILITY NFSDBG_XDR
27 /* Mapping from NFS error code to "errno" error code. */
28 #define errno_NFSERR_IO EIO
30 extern int nfs_stat_to_errno(int);
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_accessargs_sz (NFS3_fh_sz+1)
54 #define NFS3_readlinkargs_sz (NFS3_fh_sz)
55 #define NFS3_readargs_sz (NFS3_fh_sz+3)
56 #define NFS3_writeargs_sz (NFS3_fh_sz+5)
57 #define NFS3_createargs_sz (NFS3_diropargs_sz+NFS3_sattr_sz)
58 #define NFS3_mkdirargs_sz (NFS3_diropargs_sz+NFS3_sattr_sz)
59 #define NFS3_symlinkargs_sz (NFS3_diropargs_sz+NFS3_path_sz+NFS3_sattr_sz)
60 #define NFS3_mknodargs_sz (NFS3_diropargs_sz+2+NFS3_sattr_sz)
61 #define NFS3_renameargs_sz (NFS3_diropargs_sz+NFS3_diropargs_sz)
62 #define NFS3_linkargs_sz (NFS3_fh_sz+NFS3_diropargs_sz)
63 #define NFS3_readdirargs_sz (NFS3_fh_sz+2)
64 #define NFS3_commitargs_sz (NFS3_fh_sz+3)
66 #define NFS3_attrstat_sz (1+NFS3_fattr_sz)
67 #define NFS3_wccstat_sz (1+NFS3_wcc_data_sz)
68 #define NFS3_lookupres_sz (1+NFS3_fh_sz+(2 * NFS3_post_op_attr_sz))
69 #define NFS3_accessres_sz (1+NFS3_post_op_attr_sz+1)
70 #define NFS3_readlinkres_sz (1+NFS3_post_op_attr_sz+1)
71 #define NFS3_readres_sz (1+NFS3_post_op_attr_sz+3)
72 #define NFS3_writeres_sz (1+NFS3_wcc_data_sz+4)
73 #define NFS3_createres_sz (1+NFS3_fh_sz+NFS3_post_op_attr_sz+NFS3_wcc_data_sz)
74 #define NFS3_renameres_sz (1+(2 * NFS3_wcc_data_sz))
75 #define NFS3_linkres_sz (1+NFS3_post_op_attr_sz+NFS3_wcc_data_sz)
76 #define NFS3_readdirres_sz (1+NFS3_post_op_attr_sz+2)
77 #define NFS3_fsstatres_sz (1+NFS3_post_op_attr_sz+13)
78 #define NFS3_fsinfores_sz (1+NFS3_post_op_attr_sz+12)
79 #define NFS3_pathconfres_sz (1+NFS3_post_op_attr_sz+6)
80 #define NFS3_commitres_sz (1+NFS3_wcc_data_sz+2)
83 * Map file type to S_IFMT bits
85 static struct {
86 unsigned int mode;
87 unsigned int nfs2type;
88 } nfs_type2fmt[] = {
89 { 0, NFNON },
90 { S_IFREG, NFREG },
91 { S_IFDIR, NFDIR },
92 { S_IFBLK, NFBLK },
93 { S_IFCHR, NFCHR },
94 { S_IFLNK, NFLNK },
95 { S_IFSOCK, NFSOCK },
96 { S_IFIFO, NFFIFO },
97 { 0, NFBAD }
101 * Common NFS XDR functions as inlines
103 static inline u32 *
104 xdr_encode_fhandle(u32 *p, struct nfs_fh *fh)
106 return xdr_encode_array(p, fh->data, fh->size);
109 static inline u32 *
110 xdr_decode_fhandle(u32 *p, struct nfs_fh *fh)
112 if ((fh->size = ntohl(*p++)) <= NFS3_FHSIZE) {
113 memcpy(fh->data, p, fh->size);
114 return p + XDR_QUADLEN(fh->size);
116 return NULL;
120 * Encode/decode time.
122 static inline u32 *
123 xdr_encode_time3(u32 *p, struct timespec *timep)
125 *p++ = htonl(timep->tv_sec);
126 *p++ = htonl(timep->tv_nsec);
127 return p;
130 static inline u32 *
131 xdr_decode_time3(u32 *p, struct timespec *timep)
133 timep->tv_sec = ntohl(*p++);
134 timep->tv_nsec = ntohl(*p++);
135 return p;
138 static u32 *
139 xdr_decode_fattr(u32 *p, struct nfs_fattr *fattr)
141 unsigned int type, major, minor;
142 int fmode;
144 type = ntohl(*p++);
145 if (type >= NF3BAD)
146 type = NF3BAD;
147 fmode = nfs_type2fmt[type].mode;
148 fattr->type = nfs_type2fmt[type].nfs2type;
149 fattr->mode = (ntohl(*p++) & ~S_IFMT) | fmode;
150 fattr->nlink = ntohl(*p++);
151 fattr->uid = ntohl(*p++);
152 fattr->gid = ntohl(*p++);
153 p = xdr_decode_hyper(p, &fattr->size);
154 p = xdr_decode_hyper(p, &fattr->du.nfs3.used);
156 /* Turn remote device info into Linux-specific dev_t */
157 major = ntohl(*p++);
158 minor = ntohl(*p++);
159 fattr->rdev = MKDEV(major, minor);
160 if (MAJOR(fattr->rdev) != major || MINOR(fattr->rdev) != minor)
161 fattr->rdev = 0;
163 p = xdr_decode_hyper(p, &fattr->fsid_u.nfs3);
164 p = xdr_decode_hyper(p, &fattr->fileid);
165 p = xdr_decode_time3(p, &fattr->atime);
166 p = xdr_decode_time3(p, &fattr->mtime);
167 p = xdr_decode_time3(p, &fattr->ctime);
169 /* Update the mode bits */
170 fattr->valid |= (NFS_ATTR_FATTR | NFS_ATTR_FATTR_V3);
171 fattr->timestamp = jiffies;
172 return p;
175 static inline u32 *
176 xdr_encode_sattr(u32 *p, struct iattr *attr)
178 if (attr->ia_valid & ATTR_MODE) {
179 *p++ = xdr_one;
180 *p++ = htonl(attr->ia_mode);
181 } else {
182 *p++ = xdr_zero;
184 if (attr->ia_valid & ATTR_UID) {
185 *p++ = xdr_one;
186 *p++ = htonl(attr->ia_uid);
187 } else {
188 *p++ = xdr_zero;
190 if (attr->ia_valid & ATTR_GID) {
191 *p++ = xdr_one;
192 *p++ = htonl(attr->ia_gid);
193 } else {
194 *p++ = xdr_zero;
196 if (attr->ia_valid & ATTR_SIZE) {
197 *p++ = xdr_one;
198 p = xdr_encode_hyper(p, (__u64) attr->ia_size);
199 } else {
200 *p++ = xdr_zero;
202 if (attr->ia_valid & ATTR_ATIME_SET) {
203 *p++ = xdr_two;
204 p = xdr_encode_time3(p, &attr->ia_atime);
205 } else if (attr->ia_valid & ATTR_ATIME) {
206 *p++ = xdr_one;
207 } else {
208 *p++ = xdr_zero;
210 if (attr->ia_valid & ATTR_MTIME_SET) {
211 *p++ = xdr_two;
212 p = xdr_encode_time3(p, &attr->ia_mtime);
213 } else if (attr->ia_valid & ATTR_MTIME) {
214 *p++ = xdr_one;
215 } else {
216 *p++ = xdr_zero;
218 return p;
221 static inline u32 *
222 xdr_decode_wcc_attr(u32 *p, struct nfs_fattr *fattr)
224 p = xdr_decode_hyper(p, &fattr->pre_size);
225 p = xdr_decode_time3(p, &fattr->pre_mtime);
226 p = xdr_decode_time3(p, &fattr->pre_ctime);
227 fattr->valid |= NFS_ATTR_WCC;
228 return p;
231 static inline u32 *
232 xdr_decode_post_op_attr(u32 *p, struct nfs_fattr *fattr)
234 if (*p++)
235 p = xdr_decode_fattr(p, fattr);
236 return p;
239 static inline u32 *
240 xdr_decode_pre_op_attr(u32 *p, struct nfs_fattr *fattr)
242 if (*p++)
243 return xdr_decode_wcc_attr(p, fattr);
244 return p;
248 static inline u32 *
249 xdr_decode_wcc_data(u32 *p, struct nfs_fattr *fattr)
251 p = xdr_decode_pre_op_attr(p, fattr);
252 return xdr_decode_post_op_attr(p, fattr);
256 * NFS encode functions
260 * Encode file handle argument
262 static int
263 nfs3_xdr_fhandle(struct rpc_rqst *req, u32 *p, struct nfs_fh *fh)
265 p = xdr_encode_fhandle(p, fh);
266 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
267 return 0;
271 * Encode SETATTR arguments
273 static int
274 nfs3_xdr_sattrargs(struct rpc_rqst *req, u32 *p, struct nfs3_sattrargs *args)
276 p = xdr_encode_fhandle(p, args->fh);
277 p = xdr_encode_sattr(p, args->sattr);
278 *p++ = htonl(args->guard);
279 if (args->guard)
280 p = xdr_encode_time3(p, &args->guardtime);
281 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
282 return 0;
286 * Encode directory ops argument
288 static int
289 nfs3_xdr_diropargs(struct rpc_rqst *req, u32 *p, struct nfs3_diropargs *args)
291 p = xdr_encode_fhandle(p, args->fh);
292 p = xdr_encode_array(p, args->name, args->len);
293 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
294 return 0;
298 * Encode access() argument
300 static int
301 nfs3_xdr_accessargs(struct rpc_rqst *req, u32 *p, struct nfs3_accessargs *args)
303 p = xdr_encode_fhandle(p, args->fh);
304 *p++ = htonl(args->access);
305 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
306 return 0;
310 * Arguments to a READ call. Since we read data directly into the page
311 * cache, we also set up the reply iovec here so that iov[1] points
312 * exactly to the page we want to fetch.
314 static int
315 nfs3_xdr_readargs(struct rpc_rqst *req, u32 *p, struct nfs_readargs *args)
317 struct rpc_auth *auth = req->rq_task->tk_auth;
318 unsigned int replen;
319 u32 count = args->count;
321 p = xdr_encode_fhandle(p, args->fh);
322 p = xdr_encode_hyper(p, args->offset);
323 *p++ = htonl(count);
324 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
326 /* Inline the page array */
327 replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS3_readres_sz) << 2;
328 xdr_inline_pages(&req->rq_rcv_buf, replen,
329 args->pages, args->pgbase, count);
330 return 0;
334 * Write arguments. Splice the buffer to be written into the iovec.
336 static int
337 nfs3_xdr_writeargs(struct rpc_rqst *req, u32 *p, struct nfs_writeargs *args)
339 struct xdr_buf *sndbuf = &req->rq_snd_buf;
340 u32 count = args->count;
342 p = xdr_encode_fhandle(p, args->fh);
343 p = xdr_encode_hyper(p, args->offset);
344 *p++ = htonl(count);
345 *p++ = htonl(args->stable);
346 *p++ = htonl(count);
347 sndbuf->len = xdr_adjust_iovec(sndbuf->head, p);
349 /* Copy the page array */
350 xdr_encode_pages(sndbuf, args->pages, args->pgbase, count);
351 return 0;
355 * Encode CREATE arguments
357 static int
358 nfs3_xdr_createargs(struct rpc_rqst *req, u32 *p, struct nfs3_createargs *args)
360 p = xdr_encode_fhandle(p, args->fh);
361 p = xdr_encode_array(p, args->name, args->len);
363 *p++ = htonl(args->createmode);
364 if (args->createmode == NFS3_CREATE_EXCLUSIVE) {
365 *p++ = args->verifier[0];
366 *p++ = args->verifier[1];
367 } else
368 p = xdr_encode_sattr(p, args->sattr);
370 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
371 return 0;
375 * Encode MKDIR arguments
377 static int
378 nfs3_xdr_mkdirargs(struct rpc_rqst *req, u32 *p, struct nfs3_mkdirargs *args)
380 p = xdr_encode_fhandle(p, args->fh);
381 p = xdr_encode_array(p, args->name, args->len);
382 p = xdr_encode_sattr(p, args->sattr);
383 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
384 return 0;
388 * Encode SYMLINK arguments
390 static int
391 nfs3_xdr_symlinkargs(struct rpc_rqst *req, u32 *p, struct nfs3_symlinkargs *args)
393 p = xdr_encode_fhandle(p, args->fromfh);
394 p = xdr_encode_array(p, args->fromname, args->fromlen);
395 p = xdr_encode_sattr(p, args->sattr);
396 p = xdr_encode_array(p, args->topath, args->tolen);
397 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
398 return 0;
402 * Encode MKNOD arguments
404 static int
405 nfs3_xdr_mknodargs(struct rpc_rqst *req, u32 *p, struct nfs3_mknodargs *args)
407 p = xdr_encode_fhandle(p, args->fh);
408 p = xdr_encode_array(p, args->name, args->len);
409 *p++ = htonl(args->type);
410 p = xdr_encode_sattr(p, args->sattr);
411 if (args->type == NF3CHR || args->type == NF3BLK) {
412 *p++ = htonl(MAJOR(args->rdev));
413 *p++ = htonl(MINOR(args->rdev));
416 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
417 return 0;
421 * Encode RENAME arguments
423 static int
424 nfs3_xdr_renameargs(struct rpc_rqst *req, u32 *p, struct nfs3_renameargs *args)
426 p = xdr_encode_fhandle(p, args->fromfh);
427 p = xdr_encode_array(p, args->fromname, args->fromlen);
428 p = xdr_encode_fhandle(p, args->tofh);
429 p = xdr_encode_array(p, args->toname, args->tolen);
430 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
431 return 0;
435 * Encode LINK arguments
437 static int
438 nfs3_xdr_linkargs(struct rpc_rqst *req, u32 *p, struct nfs3_linkargs *args)
440 p = xdr_encode_fhandle(p, args->fromfh);
441 p = xdr_encode_fhandle(p, args->tofh);
442 p = xdr_encode_array(p, args->toname, args->tolen);
443 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
444 return 0;
448 * Encode arguments to readdir call
450 static int
451 nfs3_xdr_readdirargs(struct rpc_rqst *req, u32 *p, struct nfs3_readdirargs *args)
453 struct rpc_auth *auth = req->rq_task->tk_auth;
454 unsigned int replen;
455 u32 count = args->count;
457 p = xdr_encode_fhandle(p, args->fh);
458 p = xdr_encode_hyper(p, args->cookie);
459 *p++ = args->verf[0];
460 *p++ = args->verf[1];
461 if (args->plus) {
462 /* readdirplus: need dircount + buffer size.
463 * We just make sure we make dircount big enough */
464 *p++ = htonl(count >> 3);
466 *p++ = htonl(count);
467 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
469 /* Inline the page array */
470 replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS3_readdirres_sz) << 2;
471 xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, 0, count);
472 return 0;
476 * Decode the result of a readdir call.
477 * We just check for syntactical correctness.
479 static int
480 nfs3_xdr_readdirres(struct rpc_rqst *req, u32 *p, struct nfs3_readdirres *res)
482 struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
483 struct kvec *iov = rcvbuf->head;
484 struct page **page;
485 int hdrlen, recvd;
486 int status, nr;
487 unsigned int len, pglen;
488 u32 *entry, *end, *kaddr;
490 status = ntohl(*p++);
491 /* Decode post_op_attrs */
492 p = xdr_decode_post_op_attr(p, res->dir_attr);
493 if (status)
494 return -nfs_stat_to_errno(status);
495 /* Decode verifier cookie */
496 if (res->verf) {
497 res->verf[0] = *p++;
498 res->verf[1] = *p++;
499 } else {
500 p += 2;
503 hdrlen = (u8 *) p - (u8 *) iov->iov_base;
504 if (iov->iov_len < hdrlen) {
505 printk(KERN_WARNING "NFS: READDIR reply header overflowed:"
506 "length %d > %Zu\n", hdrlen, iov->iov_len);
507 return -errno_NFSERR_IO;
508 } else if (iov->iov_len != hdrlen) {
509 dprintk("NFS: READDIR header is short. iovec will be shifted.\n");
510 xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen);
513 pglen = rcvbuf->page_len;
514 recvd = rcvbuf->len - hdrlen;
515 if (pglen > recvd)
516 pglen = recvd;
517 page = rcvbuf->pages;
518 kaddr = p = (u32 *)kmap_atomic(*page, KM_USER0);
519 end = (u32 *)((char *)p + pglen);
520 entry = p;
521 for (nr = 0; *p++; nr++) {
522 if (p + 3 > end)
523 goto short_pkt;
524 p += 2; /* inode # */
525 len = ntohl(*p++); /* string length */
526 p += XDR_QUADLEN(len) + 2; /* name + cookie */
527 if (len > NFS3_MAXNAMLEN) {
528 printk(KERN_WARNING "NFS: giant filename in readdir (len %x)!\n",
529 len);
530 goto err_unmap;
533 if (res->plus) {
534 /* post_op_attr */
535 if (p + 2 > end)
536 goto short_pkt;
537 if (*p++) {
538 p += 21;
539 if (p + 1 > end)
540 goto short_pkt;
542 /* post_op_fh3 */
543 if (*p++) {
544 if (p + 1 > end)
545 goto short_pkt;
546 len = ntohl(*p++);
547 if (len > NFS3_FHSIZE) {
548 printk(KERN_WARNING "NFS: giant filehandle in "
549 "readdir (len %x)!\n", len);
550 goto err_unmap;
552 p += XDR_QUADLEN(len);
556 if (p + 2 > end)
557 goto short_pkt;
558 entry = p;
560 if (!nr && (entry[0] != 0 || entry[1] == 0))
561 goto short_pkt;
562 out:
563 kunmap_atomic(kaddr, KM_USER0);
564 return nr;
565 short_pkt:
566 entry[0] = entry[1] = 0;
567 /* truncate listing ? */
568 if (!nr) {
569 printk(KERN_NOTICE "NFS: readdir reply truncated!\n");
570 entry[1] = 1;
572 goto out;
573 err_unmap:
574 nr = -errno_NFSERR_IO;
575 goto out;
578 u32 *
579 nfs3_decode_dirent(u32 *p, struct nfs_entry *entry, int plus)
581 struct nfs_entry old = *entry;
583 if (!*p++) {
584 if (!*p)
585 return ERR_PTR(-EAGAIN);
586 entry->eof = 1;
587 return ERR_PTR(-EBADCOOKIE);
590 p = xdr_decode_hyper(p, &entry->ino);
591 entry->len = ntohl(*p++);
592 entry->name = (const char *) p;
593 p += XDR_QUADLEN(entry->len);
594 entry->prev_cookie = entry->cookie;
595 p = xdr_decode_hyper(p, &entry->cookie);
597 if (plus) {
598 entry->fattr->valid = 0;
599 p = xdr_decode_post_op_attr(p, entry->fattr);
600 /* In fact, a post_op_fh3: */
601 if (*p++) {
602 p = xdr_decode_fhandle(p, entry->fh);
603 /* Ugh -- server reply was truncated */
604 if (p == NULL) {
605 dprintk("NFS: FH truncated\n");
606 *entry = old;
607 return ERR_PTR(-EAGAIN);
609 } else
610 memset((u8*)(entry->fh), 0, sizeof(*entry->fh));
613 entry->eof = !p[0] && p[1];
614 return p;
618 * Encode COMMIT arguments
620 static int
621 nfs3_xdr_commitargs(struct rpc_rqst *req, u32 *p, struct nfs_writeargs *args)
623 p = xdr_encode_fhandle(p, args->fh);
624 p = xdr_encode_hyper(p, args->offset);
625 *p++ = htonl(args->count);
626 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
627 return 0;
631 * NFS XDR decode functions
635 * Decode attrstat reply.
637 static int
638 nfs3_xdr_attrstat(struct rpc_rqst *req, u32 *p, struct nfs_fattr *fattr)
640 int status;
642 if ((status = ntohl(*p++)))
643 return -nfs_stat_to_errno(status);
644 xdr_decode_fattr(p, fattr);
645 return 0;
649 * Decode status+wcc_data reply
650 * SATTR, REMOVE, RMDIR
652 static int
653 nfs3_xdr_wccstat(struct rpc_rqst *req, u32 *p, struct nfs_fattr *fattr)
655 int status;
657 if ((status = ntohl(*p++)))
658 status = -nfs_stat_to_errno(status);
659 xdr_decode_wcc_data(p, fattr);
660 return status;
664 * Decode LOOKUP reply
666 static int
667 nfs3_xdr_lookupres(struct rpc_rqst *req, u32 *p, struct nfs3_diropres *res)
669 int status;
671 if ((status = ntohl(*p++))) {
672 status = -nfs_stat_to_errno(status);
673 } else {
674 if (!(p = xdr_decode_fhandle(p, res->fh)))
675 return -errno_NFSERR_IO;
676 p = xdr_decode_post_op_attr(p, res->fattr);
678 xdr_decode_post_op_attr(p, res->dir_attr);
679 return status;
683 * Decode ACCESS reply
685 static int
686 nfs3_xdr_accessres(struct rpc_rqst *req, u32 *p, struct nfs3_accessres *res)
688 int status = ntohl(*p++);
690 p = xdr_decode_post_op_attr(p, res->fattr);
691 if (status)
692 return -nfs_stat_to_errno(status);
693 res->access = ntohl(*p++);
694 return 0;
697 static int
698 nfs3_xdr_readlinkargs(struct rpc_rqst *req, u32 *p, struct nfs3_readlinkargs *args)
700 struct rpc_auth *auth = req->rq_task->tk_auth;
701 unsigned int replen;
703 p = xdr_encode_fhandle(p, args->fh);
704 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
706 /* Inline the page array */
707 replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS3_readlinkres_sz) << 2;
708 xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, args->pgbase, args->pglen);
709 return 0;
713 * Decode READLINK reply
715 static int
716 nfs3_xdr_readlinkres(struct rpc_rqst *req, u32 *p, struct nfs_fattr *fattr)
718 struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
719 struct kvec *iov = rcvbuf->head;
720 int hdrlen, len, recvd;
721 char *kaddr;
722 int status;
724 status = ntohl(*p++);
725 p = xdr_decode_post_op_attr(p, fattr);
727 if (status != 0)
728 return -nfs_stat_to_errno(status);
730 /* Convert length of symlink */
731 len = ntohl(*p++);
732 if (len >= rcvbuf->page_len || len <= 0) {
733 dprintk(KERN_WARNING "nfs: server returned giant symlink!\n");
734 return -ENAMETOOLONG;
737 hdrlen = (u8 *) p - (u8 *) iov->iov_base;
738 if (iov->iov_len < hdrlen) {
739 printk(KERN_WARNING "NFS: READLINK reply header overflowed:"
740 "length %d > %Zu\n", hdrlen, iov->iov_len);
741 return -errno_NFSERR_IO;
742 } else if (iov->iov_len != hdrlen) {
743 dprintk("NFS: READLINK header is short. iovec will be shifted.\n");
744 xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen);
746 recvd = req->rq_rcv_buf.len - hdrlen;
747 if (recvd < len) {
748 printk(KERN_WARNING "NFS: server cheating in readlink reply: "
749 "count %u > recvd %u\n", len, recvd);
750 return -EIO;
753 /* NULL terminate the string we got */
754 kaddr = (char*)kmap_atomic(rcvbuf->pages[0], KM_USER0);
755 kaddr[len+rcvbuf->page_base] = '\0';
756 kunmap_atomic(kaddr, KM_USER0);
757 return 0;
761 * Decode READ reply
763 static int
764 nfs3_xdr_readres(struct rpc_rqst *req, u32 *p, struct nfs_readres *res)
766 struct kvec *iov = req->rq_rcv_buf.head;
767 int status, count, ocount, recvd, hdrlen;
769 status = ntohl(*p++);
770 p = xdr_decode_post_op_attr(p, res->fattr);
772 if (status != 0)
773 return -nfs_stat_to_errno(status);
775 /* Decode reply could and EOF flag. NFSv3 is somewhat redundant
776 * in that it puts the count both in the res struct and in the
777 * opaque data count. */
778 count = ntohl(*p++);
779 res->eof = ntohl(*p++);
780 ocount = ntohl(*p++);
782 if (ocount != count) {
783 printk(KERN_WARNING "NFS: READ count doesn't match RPC opaque count.\n");
784 return -errno_NFSERR_IO;
787 hdrlen = (u8 *) p - (u8 *) iov->iov_base;
788 if (iov->iov_len < hdrlen) {
789 printk(KERN_WARNING "NFS: READ reply header overflowed:"
790 "length %d > %Zu\n", hdrlen, iov->iov_len);
791 return -errno_NFSERR_IO;
792 } else if (iov->iov_len != hdrlen) {
793 dprintk("NFS: READ header is short. iovec will be shifted.\n");
794 xdr_shift_buf(&req->rq_rcv_buf, iov->iov_len - hdrlen);
797 recvd = req->rq_rcv_buf.len - hdrlen;
798 if (count > recvd) {
799 printk(KERN_WARNING "NFS: server cheating in read reply: "
800 "count %d > recvd %d\n", count, recvd);
801 count = recvd;
802 res->eof = 0;
805 if (count < res->count)
806 res->count = count;
808 return count;
812 * Decode WRITE response
814 static int
815 nfs3_xdr_writeres(struct rpc_rqst *req, u32 *p, struct nfs_writeres *res)
817 int status;
819 status = ntohl(*p++);
820 p = xdr_decode_wcc_data(p, res->fattr);
822 if (status != 0)
823 return -nfs_stat_to_errno(status);
825 res->count = ntohl(*p++);
826 res->verf->committed = (enum nfs3_stable_how)ntohl(*p++);
827 res->verf->verifier[0] = *p++;
828 res->verf->verifier[1] = *p++;
830 return res->count;
834 * Decode a CREATE response
836 static int
837 nfs3_xdr_createres(struct rpc_rqst *req, u32 *p, struct nfs3_diropres *res)
839 int status;
841 status = ntohl(*p++);
842 if (status == 0) {
843 if (*p++) {
844 if (!(p = xdr_decode_fhandle(p, res->fh)))
845 return -errno_NFSERR_IO;
846 p = xdr_decode_post_op_attr(p, res->fattr);
847 } else {
848 memset(res->fh, 0, sizeof(*res->fh));
849 /* Do decode post_op_attr but set it to NULL */
850 p = xdr_decode_post_op_attr(p, res->fattr);
851 res->fattr->valid = 0;
853 } else {
854 status = -nfs_stat_to_errno(status);
856 p = xdr_decode_wcc_data(p, res->dir_attr);
857 return status;
861 * Decode RENAME reply
863 static int
864 nfs3_xdr_renameres(struct rpc_rqst *req, u32 *p, struct nfs3_renameres *res)
866 int status;
868 if ((status = ntohl(*p++)) != 0)
869 status = -nfs_stat_to_errno(status);
870 p = xdr_decode_wcc_data(p, res->fromattr);
871 p = xdr_decode_wcc_data(p, res->toattr);
872 return status;
876 * Decode LINK reply
878 static int
879 nfs3_xdr_linkres(struct rpc_rqst *req, u32 *p, struct nfs3_linkres *res)
881 int status;
883 if ((status = ntohl(*p++)) != 0)
884 status = -nfs_stat_to_errno(status);
885 p = xdr_decode_post_op_attr(p, res->fattr);
886 p = xdr_decode_wcc_data(p, res->dir_attr);
887 return status;
891 * Decode FSSTAT reply
893 static int
894 nfs3_xdr_fsstatres(struct rpc_rqst *req, u32 *p, struct nfs_fsstat *res)
896 int status;
898 status = ntohl(*p++);
900 p = xdr_decode_post_op_attr(p, res->fattr);
901 if (status != 0)
902 return -nfs_stat_to_errno(status);
904 p = xdr_decode_hyper(p, &res->tbytes);
905 p = xdr_decode_hyper(p, &res->fbytes);
906 p = xdr_decode_hyper(p, &res->abytes);
907 p = xdr_decode_hyper(p, &res->tfiles);
908 p = xdr_decode_hyper(p, &res->ffiles);
909 p = xdr_decode_hyper(p, &res->afiles);
911 /* ignore invarsec */
912 return 0;
916 * Decode FSINFO reply
918 static int
919 nfs3_xdr_fsinfores(struct rpc_rqst *req, u32 *p, struct nfs_fsinfo *res)
921 int status;
923 status = ntohl(*p++);
925 p = xdr_decode_post_op_attr(p, res->fattr);
926 if (status != 0)
927 return -nfs_stat_to_errno(status);
929 res->rtmax = ntohl(*p++);
930 res->rtpref = ntohl(*p++);
931 res->rtmult = ntohl(*p++);
932 res->wtmax = ntohl(*p++);
933 res->wtpref = ntohl(*p++);
934 res->wtmult = ntohl(*p++);
935 res->dtpref = ntohl(*p++);
936 p = xdr_decode_hyper(p, &res->maxfilesize);
938 /* ignore time_delta and properties */
939 res->lease_time = 0;
940 return 0;
944 * Decode PATHCONF reply
946 static int
947 nfs3_xdr_pathconfres(struct rpc_rqst *req, u32 *p, struct nfs_pathconf *res)
949 int status;
951 status = ntohl(*p++);
953 p = xdr_decode_post_op_attr(p, res->fattr);
954 if (status != 0)
955 return -nfs_stat_to_errno(status);
956 res->max_link = ntohl(*p++);
957 res->max_namelen = ntohl(*p++);
959 /* ignore remaining fields */
960 return 0;
964 * Decode COMMIT reply
966 static int
967 nfs3_xdr_commitres(struct rpc_rqst *req, u32 *p, struct nfs_writeres *res)
969 int status;
971 status = ntohl(*p++);
972 p = xdr_decode_wcc_data(p, res->fattr);
973 if (status != 0)
974 return -nfs_stat_to_errno(status);
976 res->verf->verifier[0] = *p++;
977 res->verf->verifier[1] = *p++;
978 return 0;
981 #ifndef MAX
982 # define MAX(a, b) (((a) > (b))? (a) : (b))
983 #endif
985 #define PROC(proc, argtype, restype, timer) \
986 [NFS3PROC_##proc] = { \
987 .p_proc = NFS3PROC_##proc, \
988 .p_encode = (kxdrproc_t) nfs3_xdr_##argtype, \
989 .p_decode = (kxdrproc_t) nfs3_xdr_##restype, \
990 .p_bufsiz = MAX(NFS3_##argtype##_sz,NFS3_##restype##_sz) << 2, \
991 .p_timer = timer \
994 struct rpc_procinfo nfs3_procedures[] = {
995 PROC(GETATTR, fhandle, attrstat, 1),
996 PROC(SETATTR, sattrargs, wccstat, 0),
997 PROC(LOOKUP, diropargs, lookupres, 2),
998 PROC(ACCESS, accessargs, accessres, 1),
999 PROC(READLINK, readlinkargs, readlinkres, 3),
1000 PROC(READ, readargs, readres, 3),
1001 PROC(WRITE, writeargs, writeres, 4),
1002 PROC(CREATE, createargs, createres, 0),
1003 PROC(MKDIR, mkdirargs, createres, 0),
1004 PROC(SYMLINK, symlinkargs, createres, 0),
1005 PROC(MKNOD, mknodargs, createres, 0),
1006 PROC(REMOVE, diropargs, wccstat, 0),
1007 PROC(RMDIR, diropargs, wccstat, 0),
1008 PROC(RENAME, renameargs, renameres, 0),
1009 PROC(LINK, linkargs, linkres, 0),
1010 PROC(READDIR, readdirargs, readdirres, 3),
1011 PROC(READDIRPLUS, readdirargs, readdirres, 3),
1012 PROC(FSSTAT, fhandle, fsstatres, 0),
1013 PROC(FSINFO, fhandle, fsinfores, 0),
1014 PROC(PATHCONF, fhandle, pathconfres, 0),
1015 PROC(COMMIT, commitargs, commitres, 5),
1018 struct rpc_version nfs_version3 = {
1019 .number = 3,
1020 .nrprocs = sizeof(nfs3_procedures)/sizeof(nfs3_procedures[0]),
1021 .procs = nfs3_procedures