2 * linux/fs/nfs/nfs2xdr.c
4 * XDR functions to encode/decode NFSv3 RPC arguments and results.
5 * Note: this is incomplete!
7 * Copyright (C) 1996 Olaf Kirch
10 #define NFS_NEED_XDR_TYPES
12 #include <linux/param.h>
13 #include <linux/sched.h>
15 #include <linux/malloc.h>
16 #include <linux/nfs_fs.h>
17 #include <linux/utsname.h>
18 #include <linux/errno.h>
19 #include <linux/string.h>
21 #include <linux/pagemap.h>
22 #include <linux/proc_fs.h>
23 #include <linux/sunrpc/clnt.h>
26 # define RPC_FACILITY RPCDBG_NFS
29 #define QUADLEN(len) (((len) + 3) >> 2)
30 static int nfs_stat_to_errno(int stat
);
32 /* Mapping from NFS error code to "errno" error code. */
33 #define errno_NFSERR_IO EIO
36 * Declare the space requirements for NFS arguments and replies as
37 * number of 32bit-words
39 #define NFS_fhandle_sz (1+16)
40 #define NFS_sattr_sz 8
41 #define NFS_filename_sz 1+(NFS_MAXNAMLEN>>2)
42 #define NFS_path_sz 1+(NFS_MAXPATHLEN>>2)
43 #define NFS_fattr_sz 17
45 #define NFS_entry_sz NFS_filename_sz+3
47 #define NFS_enc_void_sz 0
48 #define NFS_diropargs_sz NFS_fhandle_sz+NFS_filename_sz
49 #define NFS_sattrargs_sz NFS_fhandle_sz+NFS_sattr_sz
50 #define NFS_readargs_sz NFS_fhandle_sz+3
51 #define NFS_writeargs_sz NFS_fhandle_sz+4
52 #define NFS_createargs_sz NFS_diropargs_sz+NFS_sattr_sz
53 #define NFS_renameargs_sz NFS_diropargs_sz+NFS_diropargs_sz
54 #define NFS_linkargs_sz NFS_fhandle_sz+NFS_diropargs_sz
55 #define NFS_symlinkargs_sz NFS_diropargs_sz+NFS_path_sz+NFS_sattr_sz
56 #define NFS_readdirargs_sz NFS_fhandle_sz+2
58 #define NFS_dec_void_sz 0
59 #define NFS_attrstat_sz 1+NFS_fattr_sz
60 #define NFS_diropres_sz 1+NFS_fhandle_sz+NFS_fattr_sz
61 #define NFS_readlinkres_sz 1+NFS_path_sz
62 #define NFS_readres_sz 1+NFS_fattr_sz+1
64 #define NFS_readdirres_sz 1
65 #define NFS_statfsres_sz 1+NFS_info_sz
68 * Common NFS XDR functions as inlines
71 xdr_encode_fhandle(u32
*p
, struct nfs3_fh
*fh
)
73 *p
++ = htonl(fh
->size
);
74 memcpy(p
, fh
->data
, fh
->size
);
75 return p
+ QUADLEN(fh
->size
);
79 xdr_decode_fhandle(u32
*p
, struct nfs3_fh
*fh
)
81 if ((fh
->size
= ntohl(*p
++)) <= NFS3_FHSIZE
) {
82 memcpy(fh
->data
, p
, fh
->size
);
83 return p
+ QUADLEN(fh
->size
);
88 static inline enum nfs_ftype
89 xdr_decode_ftype(u32 type
)
91 return (type
== NF3FIFO
)? NFFIFO
: (enum nfs_ftype
) type
;
95 xdr_decode_string2(u32
*p
, char **string
, unsigned int *len
,
101 *string
= (char *) p
;
102 return p
+ QUADLEN(*len
);
106 xdr_decode_fattr(u32
*p
, struct nfs3_fattr
*fattr
)
108 fattr
->type
= xdr_decode_ftype(ntohl(*p
++));
109 fattr
->mode
= ntohl(*p
++);
110 fattr
->nlink
= ntohl(*p
++);
111 fattr
->uid
= ntohl(*p
++);
112 fattr
->gid
= ntohl(*p
++);
113 fattr
->size
= ((u64
) ntohl(*p
++) << 32) | ntohl(*p
++);
114 fattr
->used
= ((u64
) ntohl(*p
++) << 32) | ntohl(*p
++);
115 fattr
->rdev_maj
= ntohl(*p
++);
116 fattr
->rdev_min
= ntohl(*p
++);
117 fattr
->fsid
= ntohl(*p
++);
118 fattr
->fileid
= ntohl(*p
++);
119 fattr
->atime
.seconds
= ntohl(*p
++);
120 fattr
->atime
.useconds
= ntohl(*p
++);
121 fattr
->mtime
.seconds
= ntohl(*p
++);
122 fattr
->mtime
.useconds
= ntohl(*p
++);
123 fattr
->ctime
.seconds
= ntohl(*p
++);
124 fattr
->ctime
.useconds
= ntohl(*p
++);
129 xdr_encode_sattr(u32
*p
, struct nfs_sattr
*sattr
)
131 *p
++ = htonl(sattr
->mode
);
132 *p
++ = htonl(sattr
->uid
);
133 *p
++ = htonl(sattr
->gid
);
134 *p
++ = htonl(sattr
->size
>> 32);
135 *p
++ = htonl(sattr
->size
& 0xFFFFFFFF);
136 *p
++ = htonl(sattr
->atime
.seconds
);
137 *p
++ = htonl(sattr
->atime
.useconds
);
138 *p
++ = htonl(sattr
->mtime
.seconds
);
139 *p
++ = htonl(sattr
->mtime
.useconds
);
144 * NFS encode functions
147 * Encode void argument
150 nfs_xdr_enc_void(struct rpc_rqst
*req
, u32
*p
, void *dummy
)
152 req
->rq_slen
= xdr_adjust_iovec(req
->rq_svec
, p
);
157 * Encode file handle argument
158 * GETATTR, READLINK, STATFS
161 nfs_xdr_fhandle(struct rpc_rqst
*req
, u32
*p
, struct nfs3_fh
*fh
)
163 p
= xdr_encode_fhandle(p
, fh
);
164 req
->rq_slen
= xdr_adjust_iovec(req
->rq_svec
, p
);
169 * Encode SETATTR arguments
172 nfs_xdr_sattrargs(struct rpc_rqst
*req
, u32
*p
, struct nfs_sattrargs
*args
)
174 p
= xdr_encode_fhandle(p
, args
->fh
);
175 p
= xdr_encode_sattr(p
, args
->sattr
);
176 req
->rq_slen
= xdr_adjust_iovec(req
->rq_svec
, p
);
181 * Encode directory ops argument
182 * LOOKUP, REMOVE, RMDIR
185 nfs_xdr_diropargs(struct rpc_rqst
*req
, u32
*p
, struct nfs_diropargs
*args
)
187 p
= xdr_encode_fhandle(p
, args
->fh
);
188 p
= xdr_encode_string(p
, args
->name
);
189 req
->rq_slen
= xdr_adjust_iovec(req
->rq_svec
, p
);
194 * Arguments to a READ call. Since we read data directly into the page
195 * cache, we also set up the reply iovec here so that iov[1] points
196 * exactly to the page wewant to fetch.
199 nfs_xdr_readargs(struct rpc_rqst
*req
, u32
*p
, struct nfs_readargs
*args
)
201 struct rpc_auth
*auth
= req
->rq_task
->tk_auth
;
204 p
= xdr_encode_fhandle(p
, args
->fh
);
205 *p
++ = htonl(args
->offset
);
206 *p
++ = htonl(args
->count
);
207 *p
++ = htonl(args
->count
);
208 req
->rq_slen
= xdr_adjust_iovec(req
->rq_svec
, p
);
211 /* set up reply iovec */
212 replen
= (RPC_REPHDRSIZE
+ auth
->au_rslack
+ NFS_readres_sz
) << 2;
213 buflen
= req
->rq_rvec
[0].iov_len
;
214 req
->rq_rvec
[0].iov_len
= replen
;
215 req
->rq_rvec
[1].iov_base
= args
->buffer
;
216 req
->rq_rvec
[1].iov_len
= args
->count
;
217 req
->rq_rvec
[2].iov_base
= (u8
*) req
->rq_rvec
[0].iov_base
+ replen
;
218 req
->rq_rvec
[2].iov_len
= buflen
- replen
;
219 req
->rq_rlen
= args
->count
+ buflen
;
222 replen
= (RPC_REPHDRSIZE
+ auth
->au_rslack
+ NFS_readres_sz
) << 2;
223 req
->rq_rvec
[0].iov_len
= replen
;
233 nfs_xdr_readres(struct rpc_rqst
*req
, u32
*p
, struct nfs_readres
*res
)
235 struct iovec
*iov
= req
->rq_rvec
;
236 int status
, count
, recvd
, hdrlen
;
238 dprintk("RPC: readres OK status %lx\n", ntohl(*p
));
239 if ((status
= ntohl(*p
++)))
240 return -nfs_stat_to_errno(status
);
241 p
= xdr_decode_fattr(p
, res
->fattr
);
244 hdrlen
= (u8
*) p
- (u8
*) iov
->iov_base
;
245 recvd
= req
->rq_rlen
- hdrlen
;
246 if (p
!= iov
[2].iov_base
) {
247 /* Unexpected reply header size. Punt.
248 * XXX: Move iovec contents to align data on page
249 * boundary and adjust RPC header size guess */
250 printk("NFS: Odd RPC header size in read reply: %d\n", hdrlen
);
251 return -errno_NFSERR_IO
;
254 printk("NFS: server cheating in read reply: "
255 "count %d > recvd %d\n", count
, recvd
);
259 dprintk("RPC: readres OK count %d\n", count
);
260 if (count
< res
->count
)
261 memset((u8
*)(iov
[1].iov_base
+count
), 0, res
->count
-count
);
268 * Write arguments. Splice the buffer to be written into the iovec.
271 nfs_xdr_writeargs(struct rpc_rqst
*req
, u32
*p
, struct nfs_writeargs
*args
)
273 p
= xdr_encode_fhandle(p
, args
->fh
);
274 *p
++ = htonl(args
->offset
);
275 *p
++ = htonl(args
->offset
);
276 *p
++ = htonl(args
->count
);
277 *p
++ = htonl(args
->count
);
278 req
->rq_slen
= xdr_adjust_iovec(req
->rq_svec
, p
);
280 req
->rq_svec
[1].iov_base
= (void *) args
->buffer
;
281 req
->rq_svec
[1].iov_len
= args
->count
;
282 req
->rq_slen
+= args
->count
;
289 * Encode create arguments
293 nfs_xdr_createargs(struct rpc_rqst
*req
, u32
*p
, struct nfs_createargs
*args
)
295 p
= xdr_encode_fhandle(p
, args
->fh
);
296 p
= xdr_encode_string(p
, args
->name
);
297 p
= xdr_encode_sattr(p
, args
->sattr
);
298 req
->rq_slen
= xdr_adjust_iovec(req
->rq_svec
, p
);
303 * Encode RENAME arguments
306 nfs_xdr_renameargs(struct rpc_rqst
*req
, u32
*p
, struct nfs_renameargs
*args
)
308 p
= xdr_encode_fhandle(p
, args
->fromfh
);
309 p
= xdr_encode_string(p
, args
->fromname
);
310 p
= xdr_encode_fhandle(p
, args
->tofh
);
311 p
= xdr_encode_string(p
, args
->toname
);
312 req
->rq_slen
= xdr_adjust_iovec(req
->rq_svec
, p
);
317 * Encode LINK arguments
320 nfs_xdr_linkargs(struct rpc_rqst
*req
, u32
*p
, struct nfs_linkargs
*args
)
322 p
= xdr_encode_fhandle(p
, args
->fromfh
);
323 p
= xdr_encode_fhandle(p
, args
->tofh
);
324 p
= xdr_encode_string(p
, args
->toname
);
325 req
->rq_slen
= xdr_adjust_iovec(req
->rq_svec
, p
);
330 * Encode SYMLINK arguments
333 nfs_xdr_symlinkargs(struct rpc_rqst
*req
, u32
*p
, struct nfs_symlinkargs
*args
)
335 p
= xdr_encode_fhandle(p
, args
->fromfh
);
336 p
= xdr_encode_string(p
, args
->fromname
);
337 p
= xdr_encode_string(p
, args
->topath
);
338 p
= xdr_encode_sattr(p
, args
->sattr
);
339 req
->rq_slen
= xdr_adjust_iovec(req
->rq_svec
, p
);
344 * Encode arguments to readdir call
347 nfs_xdr_readdirargs(struct rpc_rqst
*req
, u32
*p
, struct nfs_readdirargs
*args
)
349 struct rpc_auth
*auth
= req
->rq_task
->tk_auth
;
352 p
= xdr_encode_fhandle(p
, args
->fh
);
353 *p
++ = htonl(args
->cookie
);
354 *p
++ = htonl(args
->bufsiz
);
355 req
->rq_slen
= xdr_adjust_iovec(req
->rq_svec
, p
);
357 /* set up reply iovec */
358 replen
= (RPC_REPHDRSIZE
+ auth
->au_rslack
+ NFS_readdirres_sz
) << 2;
360 dprintk("RPC: readdirargs: slack is 4 * (%d + %d + %d) = %d\n",
361 RPC_REPHDRSIZE, auth->au_rslack, NFS_readdirres_sz, replen);
363 req
->rq_rvec
[0].iov_len
= replen
;
364 req
->rq_rvec
[1].iov_base
= args
->buffer
;
365 req
->rq_rvec
[1].iov_len
= args
->bufsiz
;
366 req
->rq_rlen
= replen
+ args
->bufsiz
;
370 dprintk("RPC: readdirargs set up reply vec:\n");
371 dprintk(" rvec[0] = %p/%d\n",
372 req->rq_rvec[0].iov_base,
373 req->rq_rvec[0].iov_len);
374 dprintk(" rvec[1] = %p/%d\n",
375 req->rq_rvec[1].iov_base,
376 req->rq_rvec[1].iov_len);
383 * Decode the result of a readdir call. We decode the result in place
384 * to avoid a malloc of NFS_MAXNAMLEN+1 for each file name.
385 * After decoding, the layout in memory looks like this:
386 * entry1 entry2 ... entryN <space> stringN ... string2 string1
387 * Each entry consists of three __u32 values, the same space as NFS uses.
388 * Note that the strings are not null-terminated so that the entire number
389 * of entries returned by the server should fit into the buffer.
392 nfs_xdr_readdirres(struct rpc_rqst
*req
, u32
*p
, struct nfs_readdirres
*res
)
394 struct iovec
*iov
= req
->rq_rvec
;
396 char *string
, *start
;
398 __u32 fileid
, cookie
, *entry
;
400 if ((status
= ntohl(*p
++)))
401 return -nfs_stat_to_errno(status
);
402 if ((void *) p
!= ((u8
*) iov
->iov_base
+iov
->iov_len
)) {
403 /* Unexpected reply header size. Punt. */
404 printk("NFS: Odd RPC header size in readdirres reply\n");
405 return -errno_NFSERR_IO
;
408 p
= (u32
*) iov
[1].iov_base
;
409 end
= (u32
*) ((u8
*) p
+ iov
[1].iov_len
);
411 if (p
!= res
->buffer
) {
412 printk("NFS: p != res->buffer in %s:%d!!!\n",
414 return -errno_NFSERR_IO
;
417 entry
= (__u32
*) res
->buffer
;
418 start
= (char *) res
->buffer
;
419 string
= start
+ res
->bufsiz
;
420 for (nr
= 0; *p
++; nr
++) {
421 fileid
= ntohl(*p
++);
424 if ((p
+ QUADLEN(len
) + 3) > end
) {
426 "NFS: short packet in readdir reply!\n");
429 if (len
> NFS_MAXNAMLEN
) {
430 printk("NFS: giant filename in readdir (len %x)!\n",
432 return -errno_NFSERR_IO
;
435 if ((void *) (entry
+3) > (void *) string
) {
437 * This error is impossible as long as the temp
438 * buffer is no larger than the user buffer. The
439 * current packing algorithm uses the same amount
440 * of space in the user buffer as in the XDR data,
441 * so it's guaranteed to fit.
443 printk("NFS: incorrect buffer size in %s!\n",
448 memmove(string
, p
, len
);
450 cookie
= ntohl(*p
++);
452 * To make everything fit, we encode the length, offset,
453 * and eof flag into 32 bits. This works for filenames
454 * up to 32K and PAGE_SIZE up to 64K.
456 status
= !p
[0] && p
[1] ? (1 << 15) : 0; /* eof flag */
459 *entry
++ = ((string
- start
) << 16) | status
| (len
& 0x7FFF);
461 dprintk("NFS: decoded dirent %.*s cookie %d eof %d\n",
462 len, string, cookie, status);
466 printk("nfs_xdr_readdirres: %d entries, ent sp=%d, str sp=%d\n",
467 nr
, ((char *) entry
- start
), (start
+ res
->bufsiz
- string
));
473 * NFS XDR decode functions
479 nfs_xdr_dec_void(struct rpc_rqst
*req
, u32
*p
, void *dummy
)
485 * Decode simple status reply
488 nfs_xdr_stat(struct rpc_rqst
*req
, u32
*p
, void *dummy
)
492 if ((status
= ntohl(*p
++)) != 0)
493 status
= -nfs_stat_to_errno(status
);
498 * Decode attrstat reply
499 * GETATTR, SETATTR, WRITE
502 nfs_xdr_attrstat(struct rpc_rqst
*req
, u32
*p
, struct nfs_fattr
*fattr
)
506 dprintk("RPC: attrstat status %lx\n", ntohl(*p
));
507 if ((status
= ntohl(*p
++)))
508 return -nfs_stat_to_errno(status
);
509 xdr_decode_fattr(p
, fattr
);
510 dprintk("RPC: attrstat OK type %d mode %o dev %x ino %x\n",
511 fattr
->type
, fattr
->mode
, fattr
->fsid
, fattr
->fileid
);
516 * Decode diropres reply
517 * LOOKUP, CREATE, MKDIR
520 nfs_xdr_diropres(struct rpc_rqst
*req
, u32
*p
, struct nfs_diropok
*res
)
524 dprintk("RPC: diropres status %lx\n", ntohl(*p
));
525 if ((status
= ntohl(*p
++)))
526 return -nfs_stat_to_errno(status
);
527 p
= xdr_decode_fhandle(p
, res
->fh
);
528 xdr_decode_fattr(p
, res
->fattr
);
529 dprintk("RPC: diropres OK type %x mode %o dev %x ino %x\n",
530 res
->fattr
->type
, res
->fattr
->mode
,
531 res
->fattr
->fsid
, res
->fattr
->fileid
);
536 * Decode READLINK reply
539 nfs_xdr_readlinkres(struct rpc_rqst
*req
, u32
*p
, struct nfs_readlinkres
*res
)
543 if ((status
= ntohl(*p
++)))
544 return -nfs_stat_to_errno(status
);
545 xdr_decode_string2(p
, res
->string
, res
->lenp
, res
->maxlen
);
547 /* Caller takes over the buffer here to avoid extra copy */
548 res
->buffer
= req
->rq_task
->tk_buffer
;
549 req
->rq_task
->tk_buffer
= NULL
;
554 * Decode STATFS reply
557 nfs_xdr_statfsres(struct rpc_rqst
*req
, u32
*p
, struct nfs_fsinfo
*res
)
561 if ((status
= ntohl(*p
++)))
562 return -nfs_stat_to_errno(status
);
563 res
->tsize
= ntohl(*p
++);
564 res
->bsize
= ntohl(*p
++);
565 res
->blocks
= ntohl(*p
++);
566 res
->bfree
= ntohl(*p
++);
567 res
->bavail
= ntohl(*p
++);
572 * We need to translate between nfs status return values and
573 * the local errno values which may not be the same.
580 { NFSERR_PERM
, EPERM
},
581 { NFSERR_NOENT
, ENOENT
},
582 { NFSERR_IO
, errno_NFSERR_IO
},
583 { NFSERR_NXIO
, ENXIO
},
584 { NFSERR_EAGAIN
, EAGAIN
},
585 { NFSERR_ACCES
, EACCES
},
586 { NFSERR_EXIST
, EEXIST
},
587 { NFSERR_XDEV
, EXDEV
},
588 { NFSERR_NODEV
, ENODEV
},
589 { NFSERR_NOTDIR
, ENOTDIR
},
590 { NFSERR_ISDIR
, EISDIR
},
591 { NFSERR_INVAL
, EINVAL
},
592 { NFSERR_FBIG
, EFBIG
},
593 { NFSERR_NOSPC
, ENOSPC
},
594 { NFSERR_ROFS
, EROFS
},
595 { NFSERR_NAMETOOLONG
, ENAMETOOLONG
},
596 { NFSERR_NOTEMPTY
, ENOTEMPTY
},
597 { NFSERR_DQUOT
, EDQUOT
},
598 { NFSERR_STALE
, ESTALE
},
600 { NFSERR_WFLUSH
, EWFLUSH
},
606 nfs_stat_to_errno(int stat
)
610 for (i
= 0; nfs_errtbl
[i
].stat
!= -1; i
++) {
611 if (nfs_errtbl
[i
].stat
== stat
)
612 return nfs_errtbl
[i
].errno
;
614 printk("nfs_stat_to_errno: bad nfs status return value: %d\n", stat
);
615 return nfs_errtbl
[i
].errno
;
619 # define MAX(a, b) (((a) > (b))? (a) : (b))
622 #define PROC(proc, argtype, restype) \
624 (kxdrproc_t) nfs_xdr_##argtype, \
625 (kxdrproc_t) nfs_xdr_##restype, \
626 MAX(NFS_##argtype##_sz,NFS_##restype##_sz) << 2 \
629 static struct rpc_procinfo nfs_procedures
[18] = {
630 PROC(null
, enc_void
, dec_void
),
631 PROC(getattr
, fhandle
, attrstat
),
632 PROC(setattr
, sattrargs
, attrstat
),
633 PROC(root
, enc_void
, dec_void
),
634 PROC(lookup
, diropargs
, diropres
),
635 PROC(readlink
, fhandle
, readlinkres
),
636 PROC(read
, readargs
, readres
),
637 PROC(writecache
, enc_void
, dec_void
),
638 PROC(write
, writeargs
, attrstat
),
639 PROC(create
, createargs
, diropres
),
640 PROC(remove
, diropargs
, stat
),
641 PROC(rename
, renameargs
, stat
),
642 PROC(link
, linkargs
, stat
),
643 PROC(symlink
, symlinkargs
, stat
),
644 PROC(mkdir
, createargs
, diropres
),
645 PROC(rmdir
, diropargs
, stat
),
646 PROC(readdir
, readdirargs
, readdirres
),
647 PROC(statfs
, fhandle
, statfsres
),
650 static struct rpc_version nfs_version2
= {
652 sizeof(nfs_procedures
)/sizeof(nfs_procedures
[0]),
656 static struct rpc_version
* nfs_version
[] = {
662 struct rpc_program nfs_program
= {
665 sizeof(nfs_version
) / sizeof(nfs_version
[0]),
674 nfs_get_info(char *buffer
, char **start
, off_t offset
, int length
, int dummy
)
676 return rpcstat_get_info(&nfs_rpcstat
, buffer
, start
, offset
, length
);
679 static struct proc_dir_entry proc_nfsclnt
= {
681 S_IFREG
| S_IRUGO
, 1, 0, 0,
686 struct rpc_stat nfs_rpcstat
= {
688 &proc_nfsclnt
, /* /proc/net directory entry */
689 &nfs_program
, /* RPC program */