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/sched.h>
12 #include <linux/malloc.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>
25 /* Uncomment this to support servers requiring longword lengths */
26 #define NFS_PAD_WRITES 1
28 #define NFSDBG_FACILITY NFSDBG_XDR
30 /* Mapping from NFS error code to "errno" error code. */
31 #define errno_NFSERR_IO EIO
33 extern int nfs_stat_to_errno(int);
36 * Declare the space requirements for NFS arguments and replies as
37 * number of 32bit-words
39 #define NFS3_fhandle_sz 1+16
40 #define NFS3_fh_sz NFS3_fhandle_sz /* shorthand */
41 #define NFS3_sattr_sz 15
42 #define NFS3_filename_sz 1+(NFS3_MAXNAMLEN>>2)
43 #define NFS3_path_sz 1+(NFS3_MAXPATHLEN>>2)
44 #define NFS3_fattr_sz 21
45 #define NFS3_wcc_attr_sz 6
46 #define NFS3_pre_op_attr_sz 1+NFS3_wcc_attr_sz
47 #define NFS3_post_op_attr_sz 1+NFS3_fattr_sz
48 #define NFS3_wcc_data_sz NFS3_pre_op_attr_sz+NFS3_post_op_attr_sz
49 #define NFS3_fsstat_sz
50 #define NFS3_fsinfo_sz
51 #define NFS3_pathconf_sz
52 #define NFS3_entry_sz NFS3_filename_sz+3
54 #define NFS3_enc_void_sz 0
55 #define NFS3_sattrargs_sz NFS3_fh_sz+NFS3_sattr_sz+3
56 #define NFS3_diropargs_sz NFS3_fh_sz+NFS3_filename_sz
57 #define NFS3_accessargs_sz NFS3_fh_sz+1
58 #define NFS3_readlinkargs_sz NFS3_fh_sz
59 #define NFS3_readargs_sz NFS3_fh_sz+3
60 #define NFS3_writeargs_sz NFS3_fh_sz+5
61 #define NFS3_createargs_sz NFS3_diropargs_sz+NFS3_sattr_sz
62 #define NFS3_mkdirargs_sz NFS3_diropargs_sz+NFS3_sattr_sz
63 #define NFS3_symlinkargs_sz NFS3_diropargs_sz+NFS3_path_sz+NFS3_sattr_sz
64 #define NFS3_mknodargs_sz NFS3_diropargs_sz+2+NFS3_sattr_sz
65 #define NFS3_renameargs_sz NFS3_diropargs_sz+NFS3_diropargs_sz
66 #define NFS3_linkargs_sz NFS3_fh_sz+NFS3_diropargs_sz
67 #define NFS3_readdirargs_sz NFS3_fh_sz+2
68 #define NFS3_commitargs_sz NFS3_fh_sz+3
70 #define NFS3_dec_void_sz 0
71 #define NFS3_attrstat_sz 1+NFS3_fattr_sz
72 #define NFS3_wccstat_sz 1+NFS3_wcc_data_sz
73 #define NFS3_lookupres_sz 1+NFS3_fh_sz+(2 * NFS3_post_op_attr_sz)
74 #define NFS3_accessres_sz 1+NFS3_post_op_attr_sz+1
75 #define NFS3_readlinkres_sz 1+NFS3_post_op_attr_sz
76 #define NFS3_readres_sz 1+NFS3_post_op_attr_sz+3
77 #define NFS3_writeres_sz 1+NFS3_wcc_data_sz+4
78 #define NFS3_createres_sz 1+NFS3_fh_sz+NFS3_post_op_attr_sz+NFS3_wcc_data_sz
79 #define NFS3_renameres_sz 1+(2 * NFS3_wcc_data_sz)
80 #define NFS3_linkres_sz 1+NFS3_post_op_attr_sz+NFS3_wcc_data_sz
81 #define NFS3_readdirres_sz 1+NFS3_post_op_attr_sz+2
82 #define NFS3_fsstatres_sz 1+NFS3_post_op_attr_sz+13
83 #define NFS3_fsinfores_sz 1+NFS3_post_op_attr_sz+12
84 #define NFS3_pathconfres_sz 1+NFS3_post_op_attr_sz+6
85 #define NFS3_commitres_sz 1+NFS3_wcc_data_sz+2
88 * Map file type to S_IFMT bits
92 unsigned int nfs2type
;
100 { S_IFSOCK
, NFSOCK
},
106 * Common NFS XDR functions as inlines
109 xdr_encode_fhandle(u32
*p
, struct nfs_fh
*fh
)
111 *p
++ = htonl(fh
->size
);
112 memcpy(p
, fh
->data
, fh
->size
);
113 return p
+ XDR_QUADLEN(fh
->size
);
117 xdr_decode_fhandle(u32
*p
, struct nfs_fh
*fh
)
120 * Zero all nonused bytes
122 memset((u8
*)fh
, 0, sizeof(*fh
));
123 if ((fh
->size
= ntohl(*p
++)) <= NFS3_FHSIZE
) {
124 memcpy(fh
->data
, p
, fh
->size
);
125 return p
+ XDR_QUADLEN(fh
->size
);
131 * Encode/decode time.
132 * Since the VFS doesn't care for fractional times, we ignore the
136 xdr_encode_time(u32
*p
, time_t time
)
144 xdr_decode_time3(u32
*p
, u64
*timep
)
146 u64 tmp
= (u64
)ntohl(*p
++) << 32;
147 *timep
= tmp
+ (u64
)ntohl(*p
++);
152 xdr_encode_time3(u32
*p
, u64 time
)
154 *p
++ = htonl(time
>> 32);
155 *p
++ = htonl(time
& 0xFFFFFFFF);
160 xdr_decode_string2(u32
*p
, char **string
, unsigned int *len
,
166 *string
= (char *) p
;
167 return p
+ XDR_QUADLEN(*len
);
171 xdr_decode_fattr(u32
*p
, struct nfs_fattr
*fattr
)
179 fmode
= nfs_type2fmt
[type
].mode
;
180 fattr
->type
= nfs_type2fmt
[type
].nfs2type
;
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
);
187 /* Turn remote device info into Linux-specific dev_t */
188 fattr
->rdev
= ntohl(*p
++) << MINORBITS
;
189 fattr
->rdev
|= ntohl(*p
++) & MINORMASK
;
190 p
= xdr_decode_hyper(p
, &fattr
->fsid
);
191 p
= xdr_decode_hyper(p
, &fattr
->fileid
);
192 p
= xdr_decode_time3(p
, &fattr
->atime
);
193 p
= xdr_decode_time3(p
, &fattr
->mtime
);
194 p
= xdr_decode_time3(p
, &fattr
->ctime
);
196 /* Update the mode bits */
197 fattr
->valid
|= (NFS_ATTR_FATTR
| NFS_ATTR_FATTR_V3
);
202 xdr_encode_sattr(u32
*p
, struct iattr
*attr
)
204 if (attr
->ia_valid
& ATTR_MODE
) {
206 *p
++ = htonl(attr
->ia_mode
);
210 if (attr
->ia_valid
& ATTR_UID
) {
212 *p
++ = htonl(attr
->ia_uid
);
216 if (attr
->ia_valid
& ATTR_GID
) {
218 *p
++ = htonl(attr
->ia_gid
);
222 if (attr
->ia_valid
& ATTR_SIZE
) {
224 p
= xdr_encode_hyper(p
, (__u64
) attr
->ia_size
);
228 if (attr
->ia_valid
& ATTR_ATIME_SET
) {
230 p
= xdr_encode_time(p
, attr
->ia_atime
);
231 } else if (attr
->ia_valid
& ATTR_ATIME
) {
236 if (attr
->ia_valid
& ATTR_MTIME_SET
) {
238 p
= xdr_encode_time(p
, attr
->ia_mtime
);
239 } else if (attr
->ia_valid
& ATTR_MTIME
) {
248 xdr_decode_wcc_attr(u32
*p
, struct nfs_fattr
*fattr
)
250 p
= xdr_decode_hyper(p
, &fattr
->pre_size
);
251 p
= xdr_decode_time3(p
, &fattr
->pre_mtime
);
252 p
= xdr_decode_time3(p
, &fattr
->pre_ctime
);
253 fattr
->valid
|= NFS_ATTR_WCC
;
258 xdr_decode_post_op_attr(u32
*p
, struct nfs_fattr
*fattr
)
261 p
= xdr_decode_fattr(p
, fattr
);
266 xdr_decode_pre_op_attr(u32
*p
, struct nfs_fattr
*fattr
)
269 return xdr_decode_wcc_attr(p
, fattr
);
275 xdr_decode_wcc_data(u32
*p
, struct nfs_fattr
*fattr
)
277 p
= xdr_decode_pre_op_attr(p
, fattr
);
278 return xdr_decode_post_op_attr(p
, fattr
);
282 * NFS encode functions
285 * Encode void argument
288 nfs3_xdr_enc_void(struct rpc_rqst
*req
, u32
*p
, void *dummy
)
290 req
->rq_slen
= xdr_adjust_iovec(req
->rq_svec
, p
);
295 * Encode file handle argument
298 nfs3_xdr_fhandle(struct rpc_rqst
*req
, u32
*p
, struct nfs_fh
*fh
)
300 p
= xdr_encode_fhandle(p
, fh
);
301 req
->rq_slen
= xdr_adjust_iovec(req
->rq_svec
, p
);
306 * Encode SETATTR arguments
309 nfs3_xdr_sattrargs(struct rpc_rqst
*req
, u32
*p
, struct nfs3_sattrargs
*args
)
311 p
= xdr_encode_fhandle(p
, args
->fh
);
312 p
= xdr_encode_sattr(p
, args
->sattr
);
313 *p
++ = htonl(args
->guard
);
315 p
= xdr_encode_time3(p
, args
->guardtime
);
316 req
->rq_slen
= xdr_adjust_iovec(req
->rq_svec
, p
);
321 * Encode directory ops argument
324 nfs3_xdr_diropargs(struct rpc_rqst
*req
, u32
*p
, struct nfs3_diropargs
*args
)
326 p
= xdr_encode_fhandle(p
, args
->fh
);
327 p
= xdr_encode_array(p
, args
->name
, args
->len
);
328 req
->rq_slen
= xdr_adjust_iovec(req
->rq_svec
, p
);
333 * Encode access() argument
336 nfs3_xdr_accessargs(struct rpc_rqst
*req
, u32
*p
, struct nfs3_accessargs
*args
)
338 p
= xdr_encode_fhandle(p
, args
->fh
);
339 *p
++ = htonl(args
->access
);
340 req
->rq_slen
= xdr_adjust_iovec(req
->rq_svec
, p
);
345 * Arguments to a READ call. Since we read data directly into the page
346 * cache, we also set up the reply iovec here so that iov[1] points
347 * exactly to the page we want to fetch.
350 nfs3_xdr_readargs(struct rpc_rqst
*req
, u32
*p
, struct nfs_readargs
*args
)
352 struct rpc_auth
*auth
= req
->rq_task
->tk_auth
;
356 p
= xdr_encode_fhandle(p
, args
->fh
);
357 p
= xdr_encode_hyper(p
, args
->offset
);
358 *p
++ = htonl(args
->count
);
359 req
->rq_slen
= xdr_adjust_iovec(req
->rq_svec
, p
);
361 /* Get the number of buffers in the receive iovec */
364 if (nr
+2 > MAX_IOVEC
) {
365 printk(KERN_ERR
"NFS: Bad number of iov's in xdr_readargs\n");
369 /* set up reply iovec */
370 replen
= (RPC_REPHDRSIZE
+ auth
->au_rslack
+ NFS3_readres_sz
) << 2;
371 buflen
= req
->rq_rvec
[0].iov_len
;
372 req
->rq_rvec
[0].iov_len
= replen
;
375 memcpy(req
->rq_rvec
+ 1, args
->iov
, nr
* sizeof(struct iovec
));
377 req
->rq_rvec
[nr
+1].iov_base
= (u8
*) req
->rq_rvec
[0].iov_base
+ replen
;
378 req
->rq_rvec
[nr
+1].iov_len
= buflen
- replen
;
379 req
->rq_rlen
= args
->count
+ buflen
;
386 * Write arguments. Splice the buffer to be written into the iovec.
389 nfs3_xdr_writeargs(struct rpc_rqst
*req
, u32
*p
, struct nfs_writeargs
*args
)
392 u32 count
= args
->count
;
394 p
= xdr_encode_fhandle(p
, args
->fh
);
395 p
= xdr_encode_hyper(p
, args
->offset
);
397 *p
++ = htonl(args
->stable
);
399 req
->rq_slen
= xdr_adjust_iovec(req
->rq_svec
, p
);
401 /* Get the number of buffers in the send iovec */
404 if (nr
+2 > MAX_IOVEC
) {
405 printk(KERN_ERR
"NFS: Bad number of iov's in xdr_writeargs\n");
410 memcpy(req
->rq_svec
+ 1, args
->iov
, nr
* sizeof(struct iovec
));
412 #ifdef NFS_PAD_WRITES
414 * Some old servers require that the message length
415 * be a multiple of 4, so we pad it here if needed.
418 struct iovec
*iov
= req
->rq_svec
+ nr
+ 1;
419 int pad
= 4 - (count
& 3);
421 iov
->iov_base
= (void *) "\0\0\0";
427 req
->rq_slen
+= count
;
434 * Encode CREATE arguments
437 nfs3_xdr_createargs(struct rpc_rqst
*req
, u32
*p
, struct nfs3_createargs
*args
)
439 p
= xdr_encode_fhandle(p
, args
->fh
);
440 p
= xdr_encode_array(p
, args
->name
, args
->len
);
442 *p
++ = htonl(args
->createmode
);
443 if (args
->createmode
== NFS3_CREATE_EXCLUSIVE
) {
444 *p
++ = args
->verifier
[0];
445 *p
++ = args
->verifier
[1];
447 p
= xdr_encode_sattr(p
, args
->sattr
);
449 req
->rq_slen
= xdr_adjust_iovec(req
->rq_svec
, p
);
454 * Encode MKDIR arguments
457 nfs3_xdr_mkdirargs(struct rpc_rqst
*req
, u32
*p
, struct nfs3_mkdirargs
*args
)
459 p
= xdr_encode_fhandle(p
, args
->fh
);
460 p
= xdr_encode_array(p
, args
->name
, args
->len
);
461 p
= xdr_encode_sattr(p
, args
->sattr
);
462 req
->rq_slen
= xdr_adjust_iovec(req
->rq_svec
, p
);
467 * Encode SYMLINK arguments
470 nfs3_xdr_symlinkargs(struct rpc_rqst
*req
, u32
*p
, struct nfs3_symlinkargs
*args
)
472 p
= xdr_encode_fhandle(p
, args
->fromfh
);
473 p
= xdr_encode_array(p
, args
->fromname
, args
->fromlen
);
474 p
= xdr_encode_sattr(p
, args
->sattr
);
475 p
= xdr_encode_array(p
, args
->topath
, args
->tolen
);
476 req
->rq_slen
= xdr_adjust_iovec(req
->rq_svec
, p
);
481 * Encode MKNOD arguments
484 nfs3_xdr_mknodargs(struct rpc_rqst
*req
, u32
*p
, struct nfs3_mknodargs
*args
)
486 p
= xdr_encode_fhandle(p
, args
->fh
);
487 p
= xdr_encode_array(p
, args
->name
, args
->len
);
488 *p
++ = htonl(args
->type
);
489 p
= xdr_encode_sattr(p
, args
->sattr
);
490 if (args
->type
== NF3CHR
|| args
->type
== NF3BLK
) {
491 *p
++ = htonl(args
->rdev
>> MINORBITS
);
492 *p
++ = htonl(args
->rdev
& MINORMASK
);
495 req
->rq_slen
= xdr_adjust_iovec(req
->rq_svec
, p
);
500 * Encode RENAME arguments
503 nfs3_xdr_renameargs(struct rpc_rqst
*req
, u32
*p
, struct nfs3_renameargs
*args
)
505 p
= xdr_encode_fhandle(p
, args
->fromfh
);
506 p
= xdr_encode_array(p
, args
->fromname
, args
->fromlen
);
507 p
= xdr_encode_fhandle(p
, args
->tofh
);
508 p
= xdr_encode_array(p
, args
->toname
, args
->tolen
);
509 req
->rq_slen
= xdr_adjust_iovec(req
->rq_svec
, p
);
514 * Encode LINK arguments
517 nfs3_xdr_linkargs(struct rpc_rqst
*req
, u32
*p
, struct nfs3_linkargs
*args
)
519 p
= xdr_encode_fhandle(p
, args
->fromfh
);
520 p
= xdr_encode_fhandle(p
, args
->tofh
);
521 p
= xdr_encode_array(p
, args
->toname
, args
->tolen
);
522 req
->rq_slen
= xdr_adjust_iovec(req
->rq_svec
, p
);
527 * Encode arguments to readdir call
530 nfs3_xdr_readdirargs(struct rpc_rqst
*req
, u32
*p
, struct nfs3_readdirargs
*args
)
532 struct rpc_auth
*auth
= req
->rq_task
->tk_auth
;
535 p
= xdr_encode_fhandle(p
, args
->fh
);
536 p
= xdr_encode_hyper(p
, args
->cookie
);
537 *p
++ = args
->verf
[0];
538 *p
++ = args
->verf
[1];
540 /* readdirplus: need dircount + buffer size.
541 * We just make sure we make dircount big enough */
542 *p
++ = htonl(args
->bufsiz
>> 3);
544 *p
++ = htonl(args
->bufsiz
);
545 req
->rq_slen
= xdr_adjust_iovec(req
->rq_svec
, p
);
547 /* set up reply iovec */
548 replen
= (RPC_REPHDRSIZE
+ auth
->au_rslack
+ NFS3_readdirres_sz
) << 2;
549 buflen
= req
->rq_rvec
[0].iov_len
;
550 req
->rq_rvec
[0].iov_len
= replen
;
551 req
->rq_rvec
[1].iov_base
= args
->buffer
;
552 req
->rq_rvec
[1].iov_len
= args
->bufsiz
;
553 req
->rq_rvec
[2].iov_base
= (u8
*) req
->rq_rvec
[0].iov_base
+ replen
;
554 req
->rq_rvec
[2].iov_len
= buflen
- replen
;
555 req
->rq_rlen
= buflen
+ args
->bufsiz
;
562 * Decode the result of a readdir call.
563 * We just check for syntactical correctness.
566 nfs3_xdr_readdirres(struct rpc_rqst
*req
, u32
*p
, struct nfs3_readdirres
*res
)
568 struct iovec
*iov
= req
->rq_rvec
;
574 status
= ntohl(*p
++);
575 /* Decode post_op_attrs */
576 p
= xdr_decode_post_op_attr(p
, res
->dir_attr
);
578 return -nfs_stat_to_errno(status
);
579 /* Decode verifier cookie */
587 hdrlen
= (u8
*) p
- (u8
*) iov
->iov_base
;
588 if (iov
->iov_len
> hdrlen
) {
589 dprintk("NFS: READDIR header is short. iovec will be shifted.\n");
590 xdr_shift_iovec(iov
, req
->rq_rnr
, iov
->iov_len
- hdrlen
);
593 p
= (u32
*) iov
[1].iov_base
;
594 end
= (u32
*) ((u8
*) p
+ iov
[1].iov_len
);
595 for (nr
= 0; *p
++; nr
++) {
597 p
+= 2; /* inode # */
598 len
= ntohl(*p
++); /* string length */
599 p
+= XDR_QUADLEN(len
) + 2; /* name + cookie */
600 if (len
> NFS3_MAXNAMLEN
) {
601 printk(KERN_WARNING
"NFS: giant filename in readdir (len %x)!\n",
603 return -errno_NFSERR_IO
;
613 if (len
> NFS3_FHSIZE
) {
614 printk(KERN_WARNING
"NFS: giant filehandle in "
615 "readdir (len %x)!\n", len
);
616 return -errno_NFSERR_IO
;
618 p
+= XDR_QUADLEN(len
);
624 "NFS: short packet in readdir reply!\n");
625 /* truncate listing */
626 entry
[0] = entry
[1] = 0;
635 nfs3_decode_dirent(u32
*p
, struct nfs_entry
*entry
, int plus
)
637 struct nfs_entry old
= *entry
;
641 return ERR_PTR(-EAGAIN
);
643 return ERR_PTR(-EBADCOOKIE
);
646 p
= xdr_decode_hyper(p
, &entry
->ino
);
647 entry
->len
= ntohl(*p
++);
648 entry
->name
= (const char *) p
;
649 p
+= XDR_QUADLEN(entry
->len
);
650 entry
->prev_cookie
= entry
->cookie
;
651 p
= xdr_decode_hyper(p
, &entry
->cookie
);
654 p
= xdr_decode_post_op_attr(p
, &entry
->fattr
);
655 /* In fact, a post_op_fh3: */
657 p
= xdr_decode_fhandle(p
, &entry
->fh
);
658 /* Ugh -- server reply was truncated */
660 dprintk("NFS: FH truncated\n");
662 return ERR_PTR(-EAGAIN
);
665 /* If we don't get a file handle, the attrs
666 * aren't worth a lot. */
667 entry
->fattr
.valid
= 0;
671 entry
->eof
= !p
[0] && p
[1];
676 * Encode COMMIT arguments
679 nfs3_xdr_commitargs(struct rpc_rqst
*req
, u32
*p
, struct nfs_writeargs
*args
)
681 p
= xdr_encode_fhandle(p
, args
->fh
);
682 p
= xdr_encode_hyper(p
, args
->offset
);
683 *p
++ = htonl(args
->count
);
684 req
->rq_slen
= xdr_adjust_iovec(req
->rq_svec
, p
);
689 * NFS XDR decode functions
695 nfs3_xdr_dec_void(struct rpc_rqst
*req
, u32
*p
, void *dummy
)
701 * Decode attrstat reply.
704 nfs3_xdr_attrstat(struct rpc_rqst
*req
, u32
*p
, struct nfs_fattr
*fattr
)
708 if ((status
= ntohl(*p
++)))
709 return -nfs_stat_to_errno(status
);
710 xdr_decode_fattr(p
, fattr
);
715 * Decode status+wcc_data reply
716 * SATTR, REMOVE, RMDIR
719 nfs3_xdr_wccstat(struct rpc_rqst
*req
, u32
*p
, struct nfs_fattr
*fattr
)
723 if ((status
= ntohl(*p
++)))
724 status
= -nfs_stat_to_errno(status
);
725 xdr_decode_wcc_data(p
, fattr
);
730 * Decode LOOKUP reply
733 nfs3_xdr_lookupres(struct rpc_rqst
*req
, u32
*p
, struct nfs3_diropres
*res
)
737 if ((status
= ntohl(*p
++))) {
738 status
= -nfs_stat_to_errno(status
);
740 if (!(p
= xdr_decode_fhandle(p
, res
->fh
)))
741 return -errno_NFSERR_IO
;
742 p
= xdr_decode_post_op_attr(p
, res
->fattr
);
744 xdr_decode_post_op_attr(p
, res
->dir_attr
);
749 * Decode ACCESS reply
752 nfs3_xdr_accessres(struct rpc_rqst
*req
, u32
*p
, struct nfs3_accessres
*res
)
754 int status
= ntohl(*p
++);
756 p
= xdr_decode_post_op_attr(p
, res
->fattr
);
758 return -nfs_stat_to_errno(status
);
759 res
->access
= ntohl(*p
++);
764 nfs3_xdr_readlinkargs(struct rpc_rqst
*req
, u32
*p
, struct nfs3_readlinkargs
*args
)
766 struct rpc_task
*task
= req
->rq_task
;
767 struct rpc_auth
*auth
= task
->tk_auth
;
770 p
= xdr_encode_fhandle(p
, args
->fh
);
771 req
->rq_slen
= xdr_adjust_iovec(req
->rq_svec
, p
);
772 replen
= (RPC_REPHDRSIZE
+ auth
->au_rslack
+ NFS3_readlinkres_sz
) << 2;
773 buflen
= req
->rq_rvec
[0].iov_len
;
774 req
->rq_rvec
[0].iov_len
= replen
;
775 req
->rq_rvec
[1].iov_base
= args
->buffer
;
776 req
->rq_rvec
[1].iov_len
= args
->bufsiz
;
777 req
->rq_rvec
[2].iov_base
= (u8
*) req
->rq_rvec
[0].iov_base
+ replen
;
778 req
->rq_rvec
[2].iov_len
= buflen
- replen
;
779 req
->rq_rlen
= buflen
+ args
->bufsiz
;
785 * Decode READLINK reply
788 nfs3_xdr_readlinkres(struct rpc_rqst
*req
, u32
*p
, struct nfs3_readlinkres
*res
)
790 struct iovec
*iov
= req
->rq_rvec
;
797 status
= ntohl(*p
++);
798 p
= xdr_decode_post_op_attr(p
, res
->fattr
);
801 return -nfs_stat_to_errno(status
);
803 hdrlen
= (u8
*) p
- (u8
*) iov
->iov_base
;
804 if (iov
->iov_len
> hdrlen
) {
805 dprintk("NFS: READLINK header is short. iovec will be shifted.\n");
806 xdr_shift_iovec(iov
, req
->rq_rnr
, iov
->iov_len
- hdrlen
);
809 strlen
= (u32
*)res
->buffer
;
810 /* Convert length of symlink */
811 len
= ntohl(*strlen
);
812 if (len
> res
->bufsiz
- 5)
813 len
= res
->bufsiz
- 5;
815 /* NULL terminate the string we got */
816 string
= (char *)(strlen
+ 1);
825 nfs3_xdr_readres(struct rpc_rqst
*req
, u32
*p
, struct nfs_readres
*res
)
827 struct iovec
*iov
= req
->rq_rvec
;
828 int status
, count
, ocount
, recvd
, hdrlen
;
830 status
= ntohl(*p
++);
831 p
= xdr_decode_post_op_attr(p
, res
->fattr
);
834 return -nfs_stat_to_errno(status
);
836 /* Decode reply could and EOF flag. NFSv3 is somewhat redundant
837 * in that it puts the count both in the res struct and in the
838 * opaque data count. */
840 res
->eof
= ntohl(*p
++);
841 ocount
= ntohl(*p
++);
843 if (ocount
!= count
) {
844 printk(KERN_WARNING
"NFS: READ count doesn't match RPC opaque count.\n");
845 return -errno_NFSERR_IO
;
848 hdrlen
= (u8
*) p
- (u8
*) iov
->iov_base
;
849 if (iov
->iov_len
> hdrlen
) {
850 dprintk("NFS: READ header is short. iovec will be shifted.\n");
851 xdr_shift_iovec(iov
, req
->rq_rnr
, iov
->iov_len
- hdrlen
);
854 recvd
= req
->rq_rlen
- hdrlen
;
856 printk(KERN_WARNING
"NFS: server cheating in read reply: "
857 "count %d > recvd %d\n", count
, recvd
);
861 if (count
< res
->count
) {
862 xdr_zero_iovec(iov
+1, req
->rq_rnr
-2, res
->count
- count
);
870 * Decode WRITE response
873 nfs3_xdr_writeres(struct rpc_rqst
*req
, u32
*p
, struct nfs_writeres
*res
)
877 status
= ntohl(*p
++);
878 p
= xdr_decode_wcc_data(p
, res
->fattr
);
881 return -nfs_stat_to_errno(status
);
883 res
->count
= ntohl(*p
++);
884 res
->verf
->committed
= (enum nfs3_stable_how
)ntohl(*p
++);
885 res
->verf
->verifier
[0] = *p
++;
886 res
->verf
->verifier
[1] = *p
++;
892 * Decode a CREATE response
895 nfs3_xdr_createres(struct rpc_rqst
*req
, u32
*p
, struct nfs3_diropres
*res
)
899 status
= ntohl(*p
++);
902 if (!(p
= xdr_decode_fhandle(p
, res
->fh
)))
903 return -errno_NFSERR_IO
;
904 p
= xdr_decode_post_op_attr(p
, res
->fattr
);
906 memset(res
->fh
, 0, sizeof(*res
->fh
));
907 /* Do decode post_op_attr but set it to NULL */
908 p
= xdr_decode_post_op_attr(p
, res
->fattr
);
909 res
->fattr
->valid
= 0;
912 status
= -nfs_stat_to_errno(status
);
914 p
= xdr_decode_wcc_data(p
, res
->dir_attr
);
919 * Decode RENAME reply
922 nfs3_xdr_renameres(struct rpc_rqst
*req
, u32
*p
, struct nfs3_renameres
*res
)
926 if ((status
= ntohl(*p
++)) != 0)
927 status
= -nfs_stat_to_errno(status
);
928 p
= xdr_decode_wcc_data(p
, res
->fromattr
);
929 p
= xdr_decode_wcc_data(p
, res
->toattr
);
937 nfs3_xdr_linkres(struct rpc_rqst
*req
, u32
*p
, struct nfs3_linkres
*res
)
941 if ((status
= ntohl(*p
++)) != 0)
942 status
= -nfs_stat_to_errno(status
);
943 p
= xdr_decode_post_op_attr(p
, res
->fattr
);
944 p
= xdr_decode_wcc_data(p
, res
->dir_attr
);
949 * Decode FSSTAT reply
952 nfs3_xdr_fsstatres(struct rpc_rqst
*req
, u32
*p
, struct nfs_fsinfo
*res
)
954 struct nfs_fattr dummy
;
957 status
= ntohl(*p
++);
959 p
= xdr_decode_post_op_attr(p
, &dummy
);
961 return -nfs_stat_to_errno(status
);
963 p
= xdr_decode_hyper(p
, &res
->tbytes
);
964 p
= xdr_decode_hyper(p
, &res
->fbytes
);
965 p
= xdr_decode_hyper(p
, &res
->abytes
);
966 p
= xdr_decode_hyper(p
, &res
->tfiles
);
967 p
= xdr_decode_hyper(p
, &res
->ffiles
);
968 p
= xdr_decode_hyper(p
, &res
->afiles
);
970 /* ignore invarsec */
975 * Decode FSINFO reply
978 nfs3_xdr_fsinfores(struct rpc_rqst
*req
, u32
*p
, struct nfs_fsinfo
*res
)
980 struct nfs_fattr dummy
;
983 status
= ntohl(*p
++);
985 p
= xdr_decode_post_op_attr(p
, &dummy
);
987 return -nfs_stat_to_errno(status
);
989 res
->rtmax
= ntohl(*p
++);
990 res
->rtpref
= ntohl(*p
++);
991 res
->rtmult
= ntohl(*p
++);
992 res
->wtmax
= ntohl(*p
++);
993 res
->wtpref
= ntohl(*p
++);
994 res
->wtmult
= ntohl(*p
++);
995 res
->dtpref
= ntohl(*p
++);
996 p
= xdr_decode_hyper(p
, &res
->maxfilesize
);
998 /* ignore time_delta and properties */
1003 * Decode PATHCONF reply
1006 nfs3_xdr_pathconfres(struct rpc_rqst
*req
, u32
*p
, struct nfs_fsinfo
*res
)
1008 struct nfs_fattr dummy
;
1011 status
= ntohl(*p
++);
1013 p
= xdr_decode_post_op_attr(p
, &dummy
);
1015 return -nfs_stat_to_errno(status
);
1016 res
->linkmax
= ntohl(*p
++);
1017 res
->namelen
= ntohl(*p
++);
1019 /* ignore remaining fields */
1024 * Decode COMMIT reply
1027 nfs3_xdr_commitres(struct rpc_rqst
*req
, u32
*p
, struct nfs_writeres
*res
)
1031 status
= ntohl(*p
++);
1032 p
= xdr_decode_wcc_data(p
, res
->fattr
);
1034 return -nfs_stat_to_errno(status
);
1036 res
->verf
->verifier
[0] = *p
++;
1037 res
->verf
->verifier
[1] = *p
++;
1042 # define MAX(a, b) (((a) > (b))? (a) : (b))
1045 #define PROC(proc, argtype, restype) \
1047 (kxdrproc_t) nfs3_xdr_##argtype, \
1048 (kxdrproc_t) nfs3_xdr_##restype, \
1049 MAX(NFS3_##argtype##_sz,NFS3_##restype##_sz) << 2, \
1053 static struct rpc_procinfo nfs3_procedures
[22] = {
1054 PROC(null
, enc_void
, dec_void
),
1055 PROC(getattr
, fhandle
, attrstat
),
1056 PROC(setattr
, sattrargs
, wccstat
),
1057 PROC(lookup
, diropargs
, lookupres
),
1058 PROC(access
, accessargs
, accessres
),
1059 PROC(readlink
, readlinkargs
, readlinkres
),
1060 PROC(read
, readargs
, readres
),
1061 PROC(write
, writeargs
, writeres
),
1062 PROC(create
, createargs
, createres
),
1063 PROC(mkdir
, mkdirargs
, createres
),
1064 PROC(symlink
, symlinkargs
, createres
),
1065 PROC(mknod
, mknodargs
, createres
),
1066 PROC(remove
, diropargs
, wccstat
),
1067 PROC(rmdir
, diropargs
, wccstat
),
1068 PROC(rename
, renameargs
, renameres
),
1069 PROC(link
, linkargs
, linkres
),
1070 PROC(readdir
, readdirargs
, readdirres
),
1071 PROC(readdirplus
, readdirargs
, readdirres
),
1072 PROC(fsstat
, fhandle
, fsstatres
),
1073 PROC(fsinfo
, fhandle
, fsinfores
),
1074 PROC(pathconf
, fhandle
, pathconfres
),
1075 PROC(commit
, commitargs
, commitres
),
1078 struct rpc_version nfs_version3
= {
1080 sizeof(nfs3_procedures
)/sizeof(nfs3_procedures
[0]),