2 * linux/fs/nfs/nfs3xdr.c
4 * XDR functions to encode/decode NFSv3 RPC arguments and results.
6 * Copyright (C) 1996, 1997 Olaf Kirch
9 #include <linux/param.h>
10 #include <linux/time.h>
12 #include <linux/slab.h>
13 #include <linux/utsname.h>
14 #include <linux/errno.h>
15 #include <linux/string.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>
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
94 unsigned int nfs2type
;
102 { S_IFSOCK
, NFSOCK
},
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
);
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
);
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
++);
146 xdr_decode_fattr(__be32
*p
, struct nfs_fattr
*fattr
)
148 unsigned int type
, major
, minor
;
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 */
166 fattr
->rdev
= MKDEV(major
, minor
);
167 if (MAJOR(fattr
->rdev
) != major
|| MINOR(fattr
->rdev
) != minor
)
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
);
182 static inline __be32
*
183 xdr_encode_sattr(__be32
*p
, struct iattr
*attr
)
185 if (attr
->ia_valid
& ATTR_MODE
) {
187 *p
++ = htonl(attr
->ia_mode
& S_IALLUGO
);
191 if (attr
->ia_valid
& ATTR_UID
) {
193 *p
++ = htonl(attr
->ia_uid
);
197 if (attr
->ia_valid
& ATTR_GID
) {
199 *p
++ = htonl(attr
->ia_gid
);
203 if (attr
->ia_valid
& ATTR_SIZE
) {
205 p
= xdr_encode_hyper(p
, (__u64
) attr
->ia_size
);
209 if (attr
->ia_valid
& ATTR_ATIME_SET
) {
211 p
= xdr_encode_time3(p
, &attr
->ia_atime
);
212 } else if (attr
->ia_valid
& ATTR_ATIME
) {
217 if (attr
->ia_valid
& ATTR_MTIME_SET
) {
219 p
= xdr_encode_time3(p
, &attr
->ia_mtime
);
220 } else if (attr
->ia_valid
& ATTR_MTIME
) {
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
;
238 static inline __be32
*
239 xdr_decode_post_op_attr(__be32
*p
, struct nfs_fattr
*fattr
)
242 p
= xdr_decode_fattr(p
, fattr
);
246 static inline __be32
*
247 xdr_decode_pre_op_attr(__be32
*p
, struct nfs_fattr
*fattr
)
250 return xdr_decode_wcc_attr(p
, fattr
);
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
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
);
278 * Encode SETATTR arguments
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
);
287 p
= xdr_encode_time3(p
, &args
->guardtime
);
288 req
->rq_slen
= xdr_adjust_iovec(req
->rq_svec
, p
);
293 * Encode directory ops argument
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
);
305 * Encode REMOVE argument
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
);
317 * Encode access() argument
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
);
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.
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
;
338 u32 count
= args
->count
;
340 p
= xdr_encode_fhandle(p
, args
->fh
);
341 p
= xdr_encode_hyper(p
, args
->offset
);
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
;
354 * Write arguments. Splice the buffer to be written into the iovec.
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
);
365 *p
++ = htonl(args
->stable
);
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
;
376 * Encode CREATE arguments
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];
389 p
= xdr_encode_sattr(p
, args
->sattr
);
391 req
->rq_slen
= xdr_adjust_iovec(req
->rq_svec
, p
);
396 * Encode MKDIR arguments
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
);
409 * Encode SYMLINK arguments
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
);
421 xdr_encode_pages(&req
->rq_snd_buf
, args
->pages
, 0, args
->pathlen
);
426 * Encode MKNOD arguments
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
);
445 * Encode RENAME arguments
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
);
459 * Encode LINK arguments
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
);
472 * Encode arguments to readdir call
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
;
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];
486 /* readdirplus: need dircount + buffer size.
487 * We just make sure we make dircount big enough */
488 *p
++ = htonl(count
>> 3);
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
);
500 * Decode the result of a readdir call.
501 * We just check for syntactical correctness.
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
;
510 u32 len
, recvd
, 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
);
518 return -nfs_stat_to_errno(status
);
519 /* Decode verifier cookie */
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
;
541 page
= rcvbuf
->pages
;
542 kaddr
= p
= kmap_atomic(*page
, KM_USER0
);
543 end
= (__be32
*)((char *)p
+ pglen
);
546 /* Make sure the packet actually has a value_follows and EOF entry */
547 if ((entry
+ 1) > end
)
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",
576 if (len
> NFS3_FHSIZE
) {
577 dprintk("NFS: giant filehandle in "
578 "readdir (len 0x%x)!\n", len
);
581 p
+= XDR_QUADLEN(len
);
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");
600 kunmap_atomic(kaddr
, KM_USER0
);
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;
614 nr
= -errno_NFSERR_IO
;
617 nr
= -errno_NFSERR_IO
;
622 nfs3_decode_dirent(__be32
*p
, struct nfs_entry
*entry
, int plus
)
624 struct nfs_entry old
= *entry
;
628 return ERR_PTR(-EAGAIN
);
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
);
641 entry
->fattr
->valid
= 0;
642 p
= xdr_decode_post_op_attr(p
, entry
->fattr
);
643 /* In fact, a post_op_fh3: */
645 p
= xdr_decode_fhandle(p
, entry
->fh
);
646 /* Ugh -- server reply was truncated */
648 dprintk("NFS: FH truncated\n");
650 return ERR_PTR(-EAGAIN
);
653 memset((u8
*)(entry
->fh
), 0, sizeof(*entry
->fh
));
656 entry
->eof
= !p
[0] && p
[1];
661 * Encode COMMIT arguments
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
);
673 #ifdef CONFIG_NFS_V3_ACL
675 * Encode GETACL arguments
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
;
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
);
699 * Encode SETACL arguments
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
);
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
);
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
]) {
723 __free_page(args
->pages
[--count
]);
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);
733 err
= nfsacl_encode(buf
, base
+ err
, args
->inode
,
734 (args
->mask
& NFS_DFACL
) ?
735 args
->acl_default
: NULL
, 1,
737 return (err
> 0) ? 0 : err
;
739 #endif /* CONFIG_NFS_V3_ACL */
742 * NFS XDR decode functions
746 * Decode attrstat reply.
749 nfs3_xdr_attrstat(struct rpc_rqst
*req
, __be32
*p
, struct nfs_fattr
*fattr
)
753 if ((status
= ntohl(*p
++)))
754 return -nfs_stat_to_errno(status
);
755 xdr_decode_fattr(p
, fattr
);
760 * Decode status+wcc_data reply
761 * SATTR, REMOVE, RMDIR
764 nfs3_xdr_wccstat(struct rpc_rqst
*req
, __be32
*p
, struct nfs_fattr
*fattr
)
768 if ((status
= ntohl(*p
++)))
769 status
= -nfs_stat_to_errno(status
);
770 xdr_decode_wcc_data(p
, fattr
);
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
784 nfs3_xdr_lookupres(struct rpc_rqst
*req
, __be32
*p
, struct nfs3_diropres
*res
)
788 if ((status
= ntohl(*p
++))) {
789 status
= -nfs_stat_to_errno(status
);
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
);
800 * Decode ACCESS reply
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
);
809 return -nfs_stat_to_errno(status
);
810 res
->access
= ntohl(*p
++);
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
;
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
);
830 * Decode READLINK reply
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
;
842 status
= ntohl(*p
++);
843 p
= xdr_decode_post_op_attr(p
, fattr
);
846 return -nfs_stat_to_errno(status
);
848 /* Convert length of symlink */
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
;
867 dprintk("NFS: server cheating in readlink reply: "
868 "count %u > recvd %u\n", len
, recvd
);
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
);
883 nfs3_xdr_readres(struct rpc_rqst
*req
, __be32
*p
, struct nfs_readres
*res
)
885 struct kvec
*iov
= req
->rq_rcv_buf
.head
;
887 u32 count
, ocount
, recvd
;
890 status
= ntohl(*p
++);
891 p
= xdr_decode_post_op_attr(p
, res
->fattr
);
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. */
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
;
920 dprintk("NFS: server cheating in read reply: "
921 "count %u > recvd %u\n", count
, recvd
);
926 if (count
< res
->count
)
933 * Decode WRITE response
936 nfs3_xdr_writeres(struct rpc_rqst
*req
, __be32
*p
, struct nfs_writeres
*res
)
940 status
= ntohl(*p
++);
941 p
= xdr_decode_wcc_data(p
, res
->fattr
);
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
++;
955 * Decode a CREATE response
958 nfs3_xdr_createres(struct rpc_rqst
*req
, __be32
*p
, struct nfs3_diropres
*res
)
962 status
= ntohl(*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
);
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;
975 status
= -nfs_stat_to_errno(status
);
977 p
= xdr_decode_wcc_data(p
, res
->dir_attr
);
982 * Decode RENAME reply
985 nfs3_xdr_renameres(struct rpc_rqst
*req
, __be32
*p
, struct nfs3_renameres
*res
)
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
);
1000 nfs3_xdr_linkres(struct rpc_rqst
*req
, __be32
*p
, struct nfs3_linkres
*res
)
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
);
1012 * Decode FSSTAT reply
1015 nfs3_xdr_fsstatres(struct rpc_rqst
*req
, __be32
*p
, struct nfs_fsstat
*res
)
1019 status
= ntohl(*p
++);
1021 p
= xdr_decode_post_op_attr(p
, res
->fattr
);
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 */
1037 * Decode FSINFO reply
1040 nfs3_xdr_fsinfores(struct rpc_rqst
*req
, __be32
*p
, struct nfs_fsinfo
*res
)
1044 status
= ntohl(*p
++);
1046 p
= xdr_decode_post_op_attr(p
, res
->fattr
);
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;
1065 * Decode PATHCONF reply
1068 nfs3_xdr_pathconfres(struct rpc_rqst
*req
, __be32
*p
, struct nfs_pathconf
*res
)
1072 status
= ntohl(*p
++);
1074 p
= xdr_decode_post_op_attr(p
, res
->fattr
);
1076 return -nfs_stat_to_errno(status
);
1077 res
->max_link
= ntohl(*p
++);
1078 res
->max_namelen
= ntohl(*p
++);
1080 /* ignore remaining fields */
1085 * Decode COMMIT reply
1088 nfs3_xdr_commitres(struct rpc_rqst
*req
, __be32
*p
, struct nfs_writeres
*res
)
1092 status
= ntohl(*p
++);
1093 p
= xdr_decode_wcc_data(p
, res
->fattr
);
1095 return -nfs_stat_to_errno(status
);
1097 res
->verf
->verifier
[0] = *p
++;
1098 res
->verf
->verifier
[1] = *p
++;
1102 #ifdef CONFIG_NFS_V3_ACL
1104 * Decode GETACL reply
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
;
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
))
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
;
1131 err
= nfsacl_decode(buf
, base
+ err
, aclcnt
, acl
);
1132 return (err
> 0) ? 0 : err
;
1136 * Decode setacl reply.
1139 nfs3_xdr_setaclres(struct rpc_rqst
*req
, __be32
*p
, struct nfs_fattr
*fattr
)
1141 int status
= ntohl(*p
++);
1144 return -nfs_stat_to_errno(status
);
1145 xdr_decode_post_op_attr(p
, fattr
);
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, \
1158 .p_statidx = NFS3PROC_##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
= {
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
,
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
,
1214 struct rpc_version nfsacl_version3
= {
1216 .nrprocs
= sizeof(nfs3_acl_procedures
)/
1217 sizeof(nfs3_acl_procedures
[0]),
1218 .procs
= nfs3_acl_procedures
,
1220 #endif /* CONFIG_NFS_V3_ACL */