powerpc: Update compat_arch_ptrace
[linux-2.6/btrfs-unstable.git] / fs / nfs / nfs3xdr.c
blobf6cc60f06dac4e517f7743bb3c0c148106807120
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/errno.h>
13 #include <linux/string.h>
14 #include <linux/in.h>
15 #include <linux/pagemap.h>
16 #include <linux/proc_fs.h>
17 #include <linux/kdev_t.h>
18 #include <linux/sunrpc/clnt.h>
19 #include <linux/nfs.h>
20 #include <linux/nfs3.h>
21 #include <linux/nfs_fs.h>
22 #include <linux/nfsacl.h>
23 #include "internal.h"
25 #define NFSDBG_FACILITY NFSDBG_XDR
27 /* Mapping from NFS error code to "errno" error code. */
28 #define errno_NFSERR_IO EIO
31 * Declare the space requirements for NFS arguments and replies as
32 * number of 32bit-words
34 #define NFS3_fhandle_sz (1+16)
35 #define NFS3_fh_sz (NFS3_fhandle_sz) /* shorthand */
36 #define NFS3_sattr_sz (15)
37 #define NFS3_filename_sz (1+(NFS3_MAXNAMLEN>>2))
38 #define NFS3_path_sz (1+(NFS3_MAXPATHLEN>>2))
39 #define NFS3_fattr_sz (21)
40 #define NFS3_wcc_attr_sz (6)
41 #define NFS3_pre_op_attr_sz (1+NFS3_wcc_attr_sz)
42 #define NFS3_post_op_attr_sz (1+NFS3_fattr_sz)
43 #define NFS3_wcc_data_sz (NFS3_pre_op_attr_sz+NFS3_post_op_attr_sz)
44 #define NFS3_fsstat_sz
45 #define NFS3_fsinfo_sz
46 #define NFS3_pathconf_sz
47 #define NFS3_entry_sz (NFS3_filename_sz+3)
49 #define NFS3_sattrargs_sz (NFS3_fh_sz+NFS3_sattr_sz+3)
50 #define NFS3_diropargs_sz (NFS3_fh_sz+NFS3_filename_sz)
51 #define NFS3_removeargs_sz (NFS3_fh_sz+NFS3_filename_sz)
52 #define NFS3_accessargs_sz (NFS3_fh_sz+1)
53 #define NFS3_readlinkargs_sz (NFS3_fh_sz)
54 #define NFS3_readargs_sz (NFS3_fh_sz+3)
55 #define NFS3_writeargs_sz (NFS3_fh_sz+5)
56 #define NFS3_createargs_sz (NFS3_diropargs_sz+NFS3_sattr_sz)
57 #define NFS3_mkdirargs_sz (NFS3_diropargs_sz+NFS3_sattr_sz)
58 #define NFS3_symlinkargs_sz (NFS3_diropargs_sz+1+NFS3_sattr_sz)
59 #define NFS3_mknodargs_sz (NFS3_diropargs_sz+2+NFS3_sattr_sz)
60 #define NFS3_renameargs_sz (NFS3_diropargs_sz+NFS3_diropargs_sz)
61 #define NFS3_linkargs_sz (NFS3_fh_sz+NFS3_diropargs_sz)
62 #define NFS3_readdirargs_sz (NFS3_fh_sz+2)
63 #define NFS3_commitargs_sz (NFS3_fh_sz+3)
65 #define NFS3_attrstat_sz (1+NFS3_fattr_sz)
66 #define NFS3_wccstat_sz (1+NFS3_wcc_data_sz)
67 #define NFS3_removeres_sz (NFS3_wccstat_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)
82 #define ACL3_getaclargs_sz (NFS3_fh_sz+1)
83 #define ACL3_setaclargs_sz (NFS3_fh_sz+1+ \
84 XDR_QUADLEN(NFS_ACL_INLINE_BUFSIZE))
85 #define ACL3_getaclres_sz (1+NFS3_post_op_attr_sz+1+ \
86 XDR_QUADLEN(NFS_ACL_INLINE_BUFSIZE))
87 #define ACL3_setaclres_sz (1+NFS3_post_op_attr_sz)
90 * Map file type to S_IFMT bits
92 static const umode_t nfs_type2fmt[] = {
93 [NF3BAD] = 0,
94 [NF3REG] = S_IFREG,
95 [NF3DIR] = S_IFDIR,
96 [NF3BLK] = S_IFBLK,
97 [NF3CHR] = S_IFCHR,
98 [NF3LNK] = S_IFLNK,
99 [NF3SOCK] = S_IFSOCK,
100 [NF3FIFO] = S_IFIFO,
103 static void print_overflow_msg(const char *func, const struct xdr_stream *xdr)
105 dprintk("nfs: %s: prematurely hit end of receive buffer. "
106 "Remaining buffer length is %tu words.\n",
107 func, xdr->end - xdr->p);
111 * Common NFS XDR functions as inlines
113 static inline __be32 *
114 xdr_encode_fhandle(__be32 *p, const struct nfs_fh *fh)
116 return xdr_encode_array(p, fh->data, fh->size);
119 static inline __be32 *
120 xdr_decode_fhandle(__be32 *p, struct nfs_fh *fh)
122 if ((fh->size = ntohl(*p++)) <= NFS3_FHSIZE) {
123 memcpy(fh->data, p, fh->size);
124 return p + XDR_QUADLEN(fh->size);
126 return NULL;
129 static inline __be32 *
130 xdr_decode_fhandle_stream(struct xdr_stream *xdr, struct nfs_fh *fh)
132 __be32 *p;
133 p = xdr_inline_decode(xdr, 4);
134 if (unlikely(!p))
135 goto out_overflow;
136 fh->size = ntohl(*p++);
138 if (fh->size <= NFS3_FHSIZE) {
139 p = xdr_inline_decode(xdr, fh->size);
140 if (unlikely(!p))
141 goto out_overflow;
142 memcpy(fh->data, p, fh->size);
143 return p + XDR_QUADLEN(fh->size);
145 return NULL;
147 out_overflow:
148 print_overflow_msg(__func__, xdr);
149 return ERR_PTR(-EIO);
153 * Encode/decode time.
155 static inline __be32 *
156 xdr_encode_time3(__be32 *p, struct timespec *timep)
158 *p++ = htonl(timep->tv_sec);
159 *p++ = htonl(timep->tv_nsec);
160 return p;
163 static inline __be32 *
164 xdr_decode_time3(__be32 *p, struct timespec *timep)
166 timep->tv_sec = ntohl(*p++);
167 timep->tv_nsec = ntohl(*p++);
168 return p;
171 static __be32 *
172 xdr_decode_fattr(__be32 *p, struct nfs_fattr *fattr)
174 unsigned int type, major, minor;
175 umode_t fmode;
177 type = ntohl(*p++);
178 if (type > NF3FIFO)
179 type = NF3NON;
180 fmode = nfs_type2fmt[type];
181 fattr->mode = (ntohl(*p++) & ~S_IFMT) | fmode;
182 fattr->nlink = ntohl(*p++);
183 fattr->uid = ntohl(*p++);
184 fattr->gid = ntohl(*p++);
185 p = xdr_decode_hyper(p, &fattr->size);
186 p = xdr_decode_hyper(p, &fattr->du.nfs3.used);
188 /* Turn remote device info into Linux-specific dev_t */
189 major = ntohl(*p++);
190 minor = ntohl(*p++);
191 fattr->rdev = MKDEV(major, minor);
192 if (MAJOR(fattr->rdev) != major || MINOR(fattr->rdev) != minor)
193 fattr->rdev = 0;
195 p = xdr_decode_hyper(p, &fattr->fsid.major);
196 fattr->fsid.minor = 0;
197 p = xdr_decode_hyper(p, &fattr->fileid);
198 p = xdr_decode_time3(p, &fattr->atime);
199 p = xdr_decode_time3(p, &fattr->mtime);
200 p = xdr_decode_time3(p, &fattr->ctime);
202 /* Update the mode bits */
203 fattr->valid |= NFS_ATTR_FATTR_V3;
204 return p;
207 static inline __be32 *
208 xdr_encode_sattr(__be32 *p, struct iattr *attr)
210 if (attr->ia_valid & ATTR_MODE) {
211 *p++ = xdr_one;
212 *p++ = htonl(attr->ia_mode & S_IALLUGO);
213 } else {
214 *p++ = xdr_zero;
216 if (attr->ia_valid & ATTR_UID) {
217 *p++ = xdr_one;
218 *p++ = htonl(attr->ia_uid);
219 } else {
220 *p++ = xdr_zero;
222 if (attr->ia_valid & ATTR_GID) {
223 *p++ = xdr_one;
224 *p++ = htonl(attr->ia_gid);
225 } else {
226 *p++ = xdr_zero;
228 if (attr->ia_valid & ATTR_SIZE) {
229 *p++ = xdr_one;
230 p = xdr_encode_hyper(p, (__u64) attr->ia_size);
231 } else {
232 *p++ = xdr_zero;
234 if (attr->ia_valid & ATTR_ATIME_SET) {
235 *p++ = xdr_two;
236 p = xdr_encode_time3(p, &attr->ia_atime);
237 } else if (attr->ia_valid & ATTR_ATIME) {
238 *p++ = xdr_one;
239 } else {
240 *p++ = xdr_zero;
242 if (attr->ia_valid & ATTR_MTIME_SET) {
243 *p++ = xdr_two;
244 p = xdr_encode_time3(p, &attr->ia_mtime);
245 } else if (attr->ia_valid & ATTR_MTIME) {
246 *p++ = xdr_one;
247 } else {
248 *p++ = xdr_zero;
250 return p;
253 static inline __be32 *
254 xdr_decode_wcc_attr(__be32 *p, struct nfs_fattr *fattr)
256 p = xdr_decode_hyper(p, &fattr->pre_size);
257 p = xdr_decode_time3(p, &fattr->pre_mtime);
258 p = xdr_decode_time3(p, &fattr->pre_ctime);
259 fattr->valid |= NFS_ATTR_FATTR_PRESIZE
260 | NFS_ATTR_FATTR_PREMTIME
261 | NFS_ATTR_FATTR_PRECTIME;
262 return p;
265 static inline __be32 *
266 xdr_decode_post_op_attr(__be32 *p, struct nfs_fattr *fattr)
268 if (*p++)
269 p = xdr_decode_fattr(p, fattr);
270 return p;
273 static inline __be32 *
274 xdr_decode_post_op_attr_stream(struct xdr_stream *xdr, struct nfs_fattr *fattr)
276 __be32 *p;
278 p = xdr_inline_decode(xdr, 4);
279 if (unlikely(!p))
280 goto out_overflow;
281 if (ntohl(*p++)) {
282 p = xdr_inline_decode(xdr, 84);
283 if (unlikely(!p))
284 goto out_overflow;
285 p = xdr_decode_fattr(p, fattr);
287 return p;
288 out_overflow:
289 print_overflow_msg(__func__, xdr);
290 return ERR_PTR(-EIO);
293 static inline __be32 *
294 xdr_decode_pre_op_attr(__be32 *p, struct nfs_fattr *fattr)
296 if (*p++)
297 return xdr_decode_wcc_attr(p, fattr);
298 return p;
302 static inline __be32 *
303 xdr_decode_wcc_data(__be32 *p, struct nfs_fattr *fattr)
305 p = xdr_decode_pre_op_attr(p, fattr);
306 return xdr_decode_post_op_attr(p, fattr);
310 * NFS encode functions
314 * Encode file handle argument
316 static int
317 nfs3_xdr_fhandle(struct rpc_rqst *req, __be32 *p, struct nfs_fh *fh)
319 p = xdr_encode_fhandle(p, fh);
320 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
321 return 0;
325 * Encode SETATTR arguments
327 static int
328 nfs3_xdr_sattrargs(struct rpc_rqst *req, __be32 *p, struct nfs3_sattrargs *args)
330 p = xdr_encode_fhandle(p, args->fh);
331 p = xdr_encode_sattr(p, args->sattr);
332 *p++ = htonl(args->guard);
333 if (args->guard)
334 p = xdr_encode_time3(p, &args->guardtime);
335 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
336 return 0;
340 * Encode directory ops argument
342 static int
343 nfs3_xdr_diropargs(struct rpc_rqst *req, __be32 *p, struct nfs3_diropargs *args)
345 p = xdr_encode_fhandle(p, args->fh);
346 p = xdr_encode_array(p, args->name, args->len);
347 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
348 return 0;
352 * Encode REMOVE argument
354 static int
355 nfs3_xdr_removeargs(struct rpc_rqst *req, __be32 *p, const struct nfs_removeargs *args)
357 p = xdr_encode_fhandle(p, args->fh);
358 p = xdr_encode_array(p, args->name.name, args->name.len);
359 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
360 return 0;
364 * Encode access() argument
366 static int
367 nfs3_xdr_accessargs(struct rpc_rqst *req, __be32 *p, struct nfs3_accessargs *args)
369 p = xdr_encode_fhandle(p, args->fh);
370 *p++ = htonl(args->access);
371 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
372 return 0;
376 * Arguments to a READ call. Since we read data directly into the page
377 * cache, we also set up the reply iovec here so that iov[1] points
378 * exactly to the page we want to fetch.
380 static int
381 nfs3_xdr_readargs(struct rpc_rqst *req, __be32 *p, struct nfs_readargs *args)
383 struct rpc_auth *auth = req->rq_cred->cr_auth;
384 unsigned int replen;
385 u32 count = args->count;
387 p = xdr_encode_fhandle(p, args->fh);
388 p = xdr_encode_hyper(p, args->offset);
389 *p++ = htonl(count);
390 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
392 /* Inline the page array */
393 replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS3_readres_sz) << 2;
394 xdr_inline_pages(&req->rq_rcv_buf, replen,
395 args->pages, args->pgbase, count);
396 req->rq_rcv_buf.flags |= XDRBUF_READ;
397 return 0;
401 * Write arguments. Splice the buffer to be written into the iovec.
403 static int
404 nfs3_xdr_writeargs(struct rpc_rqst *req, __be32 *p, struct nfs_writeargs *args)
406 struct xdr_buf *sndbuf = &req->rq_snd_buf;
407 u32 count = args->count;
409 p = xdr_encode_fhandle(p, args->fh);
410 p = xdr_encode_hyper(p, args->offset);
411 *p++ = htonl(count);
412 *p++ = htonl(args->stable);
413 *p++ = htonl(count);
414 sndbuf->len = xdr_adjust_iovec(sndbuf->head, p);
416 /* Copy the page array */
417 xdr_encode_pages(sndbuf, args->pages, args->pgbase, count);
418 sndbuf->flags |= XDRBUF_WRITE;
419 return 0;
423 * Encode CREATE arguments
425 static int
426 nfs3_xdr_createargs(struct rpc_rqst *req, __be32 *p, struct nfs3_createargs *args)
428 p = xdr_encode_fhandle(p, args->fh);
429 p = xdr_encode_array(p, args->name, args->len);
431 *p++ = htonl(args->createmode);
432 if (args->createmode == NFS3_CREATE_EXCLUSIVE) {
433 *p++ = args->verifier[0];
434 *p++ = args->verifier[1];
435 } else
436 p = xdr_encode_sattr(p, args->sattr);
438 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
439 return 0;
443 * Encode MKDIR arguments
445 static int
446 nfs3_xdr_mkdirargs(struct rpc_rqst *req, __be32 *p, struct nfs3_mkdirargs *args)
448 p = xdr_encode_fhandle(p, args->fh);
449 p = xdr_encode_array(p, args->name, args->len);
450 p = xdr_encode_sattr(p, args->sattr);
451 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
452 return 0;
456 * Encode SYMLINK arguments
458 static int
459 nfs3_xdr_symlinkargs(struct rpc_rqst *req, __be32 *p, struct nfs3_symlinkargs *args)
461 p = xdr_encode_fhandle(p, args->fromfh);
462 p = xdr_encode_array(p, args->fromname, args->fromlen);
463 p = xdr_encode_sattr(p, args->sattr);
464 *p++ = htonl(args->pathlen);
465 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
467 /* Copy the page */
468 xdr_encode_pages(&req->rq_snd_buf, args->pages, 0, args->pathlen);
469 return 0;
473 * Encode MKNOD arguments
475 static int
476 nfs3_xdr_mknodargs(struct rpc_rqst *req, __be32 *p, struct nfs3_mknodargs *args)
478 p = xdr_encode_fhandle(p, args->fh);
479 p = xdr_encode_array(p, args->name, args->len);
480 *p++ = htonl(args->type);
481 p = xdr_encode_sattr(p, args->sattr);
482 if (args->type == NF3CHR || args->type == NF3BLK) {
483 *p++ = htonl(MAJOR(args->rdev));
484 *p++ = htonl(MINOR(args->rdev));
487 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
488 return 0;
492 * Encode RENAME arguments
494 static int
495 nfs3_xdr_renameargs(struct rpc_rqst *req, __be32 *p, struct nfs_renameargs *args)
497 p = xdr_encode_fhandle(p, args->old_dir);
498 p = xdr_encode_array(p, args->old_name->name, args->old_name->len);
499 p = xdr_encode_fhandle(p, args->new_dir);
500 p = xdr_encode_array(p, args->new_name->name, args->new_name->len);
501 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
502 return 0;
506 * Encode LINK arguments
508 static int
509 nfs3_xdr_linkargs(struct rpc_rqst *req, __be32 *p, struct nfs3_linkargs *args)
511 p = xdr_encode_fhandle(p, args->fromfh);
512 p = xdr_encode_fhandle(p, args->tofh);
513 p = xdr_encode_array(p, args->toname, args->tolen);
514 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
515 return 0;
519 * Encode arguments to readdir call
521 static int
522 nfs3_xdr_readdirargs(struct rpc_rqst *req, __be32 *p, struct nfs3_readdirargs *args)
524 struct rpc_auth *auth = req->rq_cred->cr_auth;
525 unsigned int replen;
526 u32 count = args->count;
528 p = xdr_encode_fhandle(p, args->fh);
529 p = xdr_encode_hyper(p, args->cookie);
530 *p++ = args->verf[0];
531 *p++ = args->verf[1];
532 if (args->plus) {
533 /* readdirplus: need dircount + buffer size.
534 * We just make sure we make dircount big enough */
535 *p++ = htonl(count >> 3);
537 *p++ = htonl(count);
538 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
540 /* Inline the page array */
541 replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS3_readdirres_sz) << 2;
542 xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, 0, count);
543 return 0;
547 * Decode the result of a readdir call.
548 * We just check for syntactical correctness.
550 static int
551 nfs3_xdr_readdirres(struct rpc_rqst *req, __be32 *p, struct nfs3_readdirres *res)
553 struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
554 struct kvec *iov = rcvbuf->head;
555 struct page **page;
556 size_t hdrlen;
557 u32 recvd, pglen;
558 int status;
560 status = ntohl(*p++);
561 /* Decode post_op_attrs */
562 p = xdr_decode_post_op_attr(p, res->dir_attr);
563 if (status)
564 return nfs_stat_to_errno(status);
565 /* Decode verifier cookie */
566 if (res->verf) {
567 res->verf[0] = *p++;
568 res->verf[1] = *p++;
569 } else {
570 p += 2;
573 hdrlen = (u8 *) p - (u8 *) iov->iov_base;
574 if (iov->iov_len < hdrlen) {
575 dprintk("NFS: READDIR reply header overflowed:"
576 "length %Zu > %Zu\n", hdrlen, iov->iov_len);
577 return -errno_NFSERR_IO;
578 } else if (iov->iov_len != hdrlen) {
579 dprintk("NFS: READDIR header is short. iovec will be shifted.\n");
580 xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen);
583 pglen = rcvbuf->page_len;
584 recvd = rcvbuf->len - hdrlen;
585 if (pglen > recvd)
586 pglen = recvd;
587 page = rcvbuf->pages;
589 return pglen;
592 __be32 *
593 nfs3_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry, struct nfs_server *server, int plus)
595 __be32 *p;
596 struct nfs_entry old = *entry;
598 p = xdr_inline_decode(xdr, 4);
599 if (unlikely(!p))
600 goto out_overflow;
601 if (!ntohl(*p++)) {
602 p = xdr_inline_decode(xdr, 4);
603 if (unlikely(!p))
604 goto out_overflow;
605 if (!ntohl(*p++))
606 return ERR_PTR(-EAGAIN);
607 entry->eof = 1;
608 return ERR_PTR(-EBADCOOKIE);
611 p = xdr_inline_decode(xdr, 12);
612 if (unlikely(!p))
613 goto out_overflow;
614 p = xdr_decode_hyper(p, &entry->ino);
615 entry->len = ntohl(*p++);
617 p = xdr_inline_decode(xdr, entry->len + 8);
618 if (unlikely(!p))
619 goto out_overflow;
620 entry->name = (const char *) p;
621 p += XDR_QUADLEN(entry->len);
622 entry->prev_cookie = entry->cookie;
623 p = xdr_decode_hyper(p, &entry->cookie);
625 entry->d_type = DT_UNKNOWN;
626 if (plus) {
627 entry->fattr->valid = 0;
628 p = xdr_decode_post_op_attr_stream(xdr, entry->fattr);
629 if (IS_ERR(p))
630 goto out_overflow_exit;
631 entry->d_type = nfs_umode_to_dtype(entry->fattr->mode);
632 /* In fact, a post_op_fh3: */
633 p = xdr_inline_decode(xdr, 4);
634 if (unlikely(!p))
635 goto out_overflow;
636 if (*p++) {
637 p = xdr_decode_fhandle_stream(xdr, entry->fh);
638 if (IS_ERR(p))
639 goto out_overflow_exit;
640 /* Ugh -- server reply was truncated */
641 if (p == NULL) {
642 dprintk("NFS: FH truncated\n");
643 *entry = old;
644 return ERR_PTR(-EAGAIN);
646 } else
647 memset((u8*)(entry->fh), 0, sizeof(*entry->fh));
650 p = xdr_inline_peek(xdr, 8);
651 if (p != NULL)
652 entry->eof = !p[0] && p[1];
653 else
654 entry->eof = 0;
656 return p;
658 out_overflow:
659 print_overflow_msg(__func__, xdr);
660 out_overflow_exit:
661 return ERR_PTR(-EAGAIN);
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_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 = xdr_adjust_iovec(req->rq_svec,
722 p + XDR_QUADLEN(args->len));
724 err = nfsacl_encode(buf, base, args->inode,
725 (args->mask & NFS_ACL) ?
726 args->acl_access : NULL, 1, 0);
727 if (err > 0)
728 err = nfsacl_encode(buf, base + err, args->inode,
729 (args->mask & NFS_DFACL) ?
730 args->acl_default : NULL, 1,
731 NFS_ACL_DEFAULT);
732 return (err > 0) ? 0 : err;
734 #endif /* CONFIG_NFS_V3_ACL */
737 * NFS XDR decode functions
741 * Decode attrstat reply.
743 static int
744 nfs3_xdr_attrstat(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
746 int status;
748 if ((status = ntohl(*p++)))
749 return nfs_stat_to_errno(status);
750 xdr_decode_fattr(p, fattr);
751 return 0;
755 * Decode status+wcc_data reply
756 * SATTR, REMOVE, RMDIR
758 static int
759 nfs3_xdr_wccstat(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
761 int status;
763 if ((status = ntohl(*p++)))
764 status = nfs_stat_to_errno(status);
765 xdr_decode_wcc_data(p, fattr);
766 return status;
769 static int
770 nfs3_xdr_removeres(struct rpc_rqst *req, __be32 *p, struct nfs_removeres *res)
772 return nfs3_xdr_wccstat(req, p, res->dir_attr);
776 * Decode LOOKUP reply
778 static int
779 nfs3_xdr_lookupres(struct rpc_rqst *req, __be32 *p, struct nfs3_diropres *res)
781 int status;
783 if ((status = ntohl(*p++))) {
784 status = nfs_stat_to_errno(status);
785 } else {
786 if (!(p = xdr_decode_fhandle(p, res->fh)))
787 return -errno_NFSERR_IO;
788 p = xdr_decode_post_op_attr(p, res->fattr);
790 xdr_decode_post_op_attr(p, res->dir_attr);
791 return status;
795 * Decode ACCESS reply
797 static int
798 nfs3_xdr_accessres(struct rpc_rqst *req, __be32 *p, struct nfs3_accessres *res)
800 int status = ntohl(*p++);
802 p = xdr_decode_post_op_attr(p, res->fattr);
803 if (status)
804 return nfs_stat_to_errno(status);
805 res->access = ntohl(*p++);
806 return 0;
809 static int
810 nfs3_xdr_readlinkargs(struct rpc_rqst *req, __be32 *p, struct nfs3_readlinkargs *args)
812 struct rpc_auth *auth = req->rq_cred->cr_auth;
813 unsigned int replen;
815 p = xdr_encode_fhandle(p, args->fh);
816 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
818 /* Inline the page array */
819 replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS3_readlinkres_sz) << 2;
820 xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, args->pgbase, args->pglen);
821 return 0;
825 * Decode READLINK reply
827 static int
828 nfs3_xdr_readlinkres(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
830 struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
831 struct kvec *iov = rcvbuf->head;
832 size_t hdrlen;
833 u32 len, recvd;
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 xdr_terminate_string(rcvbuf, len);
867 return 0;
871 * Decode READ reply
873 static int
874 nfs3_xdr_readres(struct rpc_rqst *req, __be32 *p, struct nfs_readres *res)
876 struct kvec *iov = req->rq_rcv_buf.head;
877 size_t hdrlen;
878 u32 count, ocount, recvd;
879 int status;
881 status = ntohl(*p++);
882 p = xdr_decode_post_op_attr(p, res->fattr);
884 if (status != 0)
885 return nfs_stat_to_errno(status);
887 /* Decode reply count and EOF flag. NFSv3 is somewhat redundant
888 * in that it puts the count both in the res struct and in the
889 * opaque data count. */
890 count = ntohl(*p++);
891 res->eof = ntohl(*p++);
892 ocount = ntohl(*p++);
894 if (ocount != count) {
895 dprintk("NFS: READ count doesn't match RPC opaque count.\n");
896 return -errno_NFSERR_IO;
899 hdrlen = (u8 *) p - (u8 *) iov->iov_base;
900 if (iov->iov_len < hdrlen) {
901 dprintk("NFS: READ reply header overflowed:"
902 "length %Zu > %Zu\n", hdrlen, iov->iov_len);
903 return -errno_NFSERR_IO;
904 } else if (iov->iov_len != hdrlen) {
905 dprintk("NFS: READ header is short. iovec will be shifted.\n");
906 xdr_shift_buf(&req->rq_rcv_buf, iov->iov_len - hdrlen);
909 recvd = req->rq_rcv_buf.len - hdrlen;
910 if (count > recvd) {
911 dprintk("NFS: server cheating in read reply: "
912 "count %u > recvd %u\n", count, recvd);
913 count = recvd;
914 res->eof = 0;
917 if (count < res->count)
918 res->count = count;
920 return count;
924 * Decode WRITE response
926 static int
927 nfs3_xdr_writeres(struct rpc_rqst *req, __be32 *p, struct nfs_writeres *res)
929 int status;
931 status = ntohl(*p++);
932 p = xdr_decode_wcc_data(p, res->fattr);
934 if (status != 0)
935 return nfs_stat_to_errno(status);
937 res->count = ntohl(*p++);
938 res->verf->committed = (enum nfs3_stable_how)ntohl(*p++);
939 res->verf->verifier[0] = *p++;
940 res->verf->verifier[1] = *p++;
942 return res->count;
946 * Decode a CREATE response
948 static int
949 nfs3_xdr_createres(struct rpc_rqst *req, __be32 *p, struct nfs3_diropres *res)
951 int status;
953 status = ntohl(*p++);
954 if (status == 0) {
955 if (*p++) {
956 if (!(p = xdr_decode_fhandle(p, res->fh)))
957 return -errno_NFSERR_IO;
958 p = xdr_decode_post_op_attr(p, res->fattr);
959 } else {
960 memset(res->fh, 0, sizeof(*res->fh));
961 /* Do decode post_op_attr but set it to NULL */
962 p = xdr_decode_post_op_attr(p, res->fattr);
963 res->fattr->valid = 0;
965 } else {
966 status = nfs_stat_to_errno(status);
968 p = xdr_decode_wcc_data(p, res->dir_attr);
969 return status;
973 * Decode RENAME reply
975 static int
976 nfs3_xdr_renameres(struct rpc_rqst *req, __be32 *p, struct nfs_renameres *res)
978 int status;
980 if ((status = ntohl(*p++)) != 0)
981 status = nfs_stat_to_errno(status);
982 p = xdr_decode_wcc_data(p, res->old_fattr);
983 p = xdr_decode_wcc_data(p, res->new_fattr);
984 return status;
988 * Decode LINK reply
990 static int
991 nfs3_xdr_linkres(struct rpc_rqst *req, __be32 *p, struct nfs3_linkres *res)
993 int status;
995 if ((status = ntohl(*p++)) != 0)
996 status = nfs_stat_to_errno(status);
997 p = xdr_decode_post_op_attr(p, res->fattr);
998 p = xdr_decode_wcc_data(p, res->dir_attr);
999 return status;
1003 * Decode FSSTAT reply
1005 static int
1006 nfs3_xdr_fsstatres(struct rpc_rqst *req, __be32 *p, struct nfs_fsstat *res)
1008 int status;
1010 status = ntohl(*p++);
1012 p = xdr_decode_post_op_attr(p, res->fattr);
1013 if (status != 0)
1014 return nfs_stat_to_errno(status);
1016 p = xdr_decode_hyper(p, &res->tbytes);
1017 p = xdr_decode_hyper(p, &res->fbytes);
1018 p = xdr_decode_hyper(p, &res->abytes);
1019 p = xdr_decode_hyper(p, &res->tfiles);
1020 p = xdr_decode_hyper(p, &res->ffiles);
1021 p = xdr_decode_hyper(p, &res->afiles);
1023 /* ignore invarsec */
1024 return 0;
1028 * Decode FSINFO reply
1030 static int
1031 nfs3_xdr_fsinfores(struct rpc_rqst *req, __be32 *p, struct nfs_fsinfo *res)
1033 int status;
1035 status = ntohl(*p++);
1037 p = xdr_decode_post_op_attr(p, res->fattr);
1038 if (status != 0)
1039 return nfs_stat_to_errno(status);
1041 res->rtmax = ntohl(*p++);
1042 res->rtpref = ntohl(*p++);
1043 res->rtmult = ntohl(*p++);
1044 res->wtmax = ntohl(*p++);
1045 res->wtpref = ntohl(*p++);
1046 res->wtmult = ntohl(*p++);
1047 res->dtpref = ntohl(*p++);
1048 p = xdr_decode_hyper(p, &res->maxfilesize);
1049 p = xdr_decode_time3(p, &res->time_delta);
1051 /* ignore properties */
1052 res->lease_time = 0;
1053 return 0;
1057 * Decode PATHCONF reply
1059 static int
1060 nfs3_xdr_pathconfres(struct rpc_rqst *req, __be32 *p, struct nfs_pathconf *res)
1062 int status;
1064 status = ntohl(*p++);
1066 p = xdr_decode_post_op_attr(p, res->fattr);
1067 if (status != 0)
1068 return nfs_stat_to_errno(status);
1069 res->max_link = ntohl(*p++);
1070 res->max_namelen = ntohl(*p++);
1072 /* ignore remaining fields */
1073 return 0;
1077 * Decode COMMIT reply
1079 static int
1080 nfs3_xdr_commitres(struct rpc_rqst *req, __be32 *p, struct nfs_writeres *res)
1082 int status;
1084 status = ntohl(*p++);
1085 p = xdr_decode_wcc_data(p, res->fattr);
1086 if (status != 0)
1087 return nfs_stat_to_errno(status);
1089 res->verf->verifier[0] = *p++;
1090 res->verf->verifier[1] = *p++;
1091 return 0;
1094 #ifdef CONFIG_NFS_V3_ACL
1096 * Decode GETACL reply
1098 static int
1099 nfs3_xdr_getaclres(struct rpc_rqst *req, __be32 *p,
1100 struct nfs3_getaclres *res)
1102 struct xdr_buf *buf = &req->rq_rcv_buf;
1103 int status = ntohl(*p++);
1104 struct posix_acl **acl;
1105 unsigned int *aclcnt;
1106 int err, base;
1108 if (status != 0)
1109 return nfs_stat_to_errno(status);
1110 p = xdr_decode_post_op_attr(p, res->fattr);
1111 res->mask = ntohl(*p++);
1112 if (res->mask & ~(NFS_ACL|NFS_ACLCNT|NFS_DFACL|NFS_DFACLCNT))
1113 return -EINVAL;
1114 base = (char *)p - (char *)req->rq_rcv_buf.head->iov_base;
1116 acl = (res->mask & NFS_ACL) ? &res->acl_access : NULL;
1117 aclcnt = (res->mask & NFS_ACLCNT) ? &res->acl_access_count : NULL;
1118 err = nfsacl_decode(buf, base, aclcnt, acl);
1120 acl = (res->mask & NFS_DFACL) ? &res->acl_default : NULL;
1121 aclcnt = (res->mask & NFS_DFACLCNT) ? &res->acl_default_count : NULL;
1122 if (err > 0)
1123 err = nfsacl_decode(buf, base + err, aclcnt, acl);
1124 return (err > 0) ? 0 : err;
1128 * Decode setacl reply.
1130 static int
1131 nfs3_xdr_setaclres(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
1133 int status = ntohl(*p++);
1135 if (status)
1136 return nfs_stat_to_errno(status);
1137 xdr_decode_post_op_attr(p, fattr);
1138 return 0;
1140 #endif /* CONFIG_NFS_V3_ACL */
1142 #define PROC(proc, argtype, restype, timer) \
1143 [NFS3PROC_##proc] = { \
1144 .p_proc = NFS3PROC_##proc, \
1145 .p_encode = (kxdrproc_t) nfs3_xdr_##argtype, \
1146 .p_decode = (kxdrproc_t) nfs3_xdr_##restype, \
1147 .p_arglen = NFS3_##argtype##_sz, \
1148 .p_replen = NFS3_##restype##_sz, \
1149 .p_timer = timer, \
1150 .p_statidx = NFS3PROC_##proc, \
1151 .p_name = #proc, \
1154 struct rpc_procinfo nfs3_procedures[] = {
1155 PROC(GETATTR, fhandle, attrstat, 1),
1156 PROC(SETATTR, sattrargs, wccstat, 0),
1157 PROC(LOOKUP, diropargs, lookupres, 2),
1158 PROC(ACCESS, accessargs, accessres, 1),
1159 PROC(READLINK, readlinkargs, readlinkres, 3),
1160 PROC(READ, readargs, readres, 3),
1161 PROC(WRITE, writeargs, writeres, 4),
1162 PROC(CREATE, createargs, createres, 0),
1163 PROC(MKDIR, mkdirargs, createres, 0),
1164 PROC(SYMLINK, symlinkargs, createres, 0),
1165 PROC(MKNOD, mknodargs, createres, 0),
1166 PROC(REMOVE, removeargs, removeres, 0),
1167 PROC(RMDIR, diropargs, wccstat, 0),
1168 PROC(RENAME, renameargs, renameres, 0),
1169 PROC(LINK, linkargs, linkres, 0),
1170 PROC(READDIR, readdirargs, readdirres, 3),
1171 PROC(READDIRPLUS, readdirargs, readdirres, 3),
1172 PROC(FSSTAT, fhandle, fsstatres, 0),
1173 PROC(FSINFO, fhandle, fsinfores, 0),
1174 PROC(PATHCONF, fhandle, pathconfres, 0),
1175 PROC(COMMIT, commitargs, commitres, 5),
1178 struct rpc_version nfs_version3 = {
1179 .number = 3,
1180 .nrprocs = ARRAY_SIZE(nfs3_procedures),
1181 .procs = nfs3_procedures
1184 #ifdef CONFIG_NFS_V3_ACL
1185 static struct rpc_procinfo nfs3_acl_procedures[] = {
1186 [ACLPROC3_GETACL] = {
1187 .p_proc = ACLPROC3_GETACL,
1188 .p_encode = (kxdrproc_t) nfs3_xdr_getaclargs,
1189 .p_decode = (kxdrproc_t) nfs3_xdr_getaclres,
1190 .p_arglen = ACL3_getaclargs_sz,
1191 .p_replen = ACL3_getaclres_sz,
1192 .p_timer = 1,
1193 .p_name = "GETACL",
1195 [ACLPROC3_SETACL] = {
1196 .p_proc = ACLPROC3_SETACL,
1197 .p_encode = (kxdrproc_t) nfs3_xdr_setaclargs,
1198 .p_decode = (kxdrproc_t) nfs3_xdr_setaclres,
1199 .p_arglen = ACL3_setaclargs_sz,
1200 .p_replen = ACL3_setaclres_sz,
1201 .p_timer = 0,
1202 .p_name = "SETACL",
1206 struct rpc_version nfsacl_version3 = {
1207 .number = 3,
1208 .nrprocs = sizeof(nfs3_acl_procedures)/
1209 sizeof(nfs3_acl_procedures[0]),
1210 .procs = nfs3_acl_procedures,
1212 #endif /* CONFIG_NFS_V3_ACL */