4 * XDR functions to encode/decode NFS RPC arguments and results.
6 * Copyright (C) 1992, 1993, 1994 Rick Sladkey
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/utsname.h>
17 #include <linux/errno.h>
18 #include <linux/string.h>
20 #include <linux/pagemap.h>
21 #include <linux/proc_fs.h>
22 #include <linux/sunrpc/clnt.h>
23 #include <linux/nfs_fs.h>
25 #define NFSDBG_FACILITY NFSDBG_XDR
27 #define QUADLEN(len) (((len) + 3) >> 2)
28 static int nfs_stat_to_errno(int stat
);
30 /* Mapping from NFS error code to "errno" error code. */
31 #define errno_NFSERR_IO EIO
34 * Declare the space requirements for NFS arguments and replies as
35 * number of 32bit-words
37 #define NFS_fhandle_sz 8
38 #define NFS_sattr_sz 8
39 #define NFS_filename_sz 1+(NFS_MAXNAMLEN>>2)
40 #define NFS_path_sz 1+(NFS_MAXPATHLEN>>2)
41 #define NFS_fattr_sz 17
43 #define NFS_entry_sz NFS_filename_sz+3
45 #define NFS_enc_void_sz 0
46 #define NFS_diropargs_sz NFS_fhandle_sz+NFS_filename_sz
47 #define NFS_sattrargs_sz NFS_fhandle_sz+NFS_sattr_sz
48 #define NFS_readargs_sz NFS_fhandle_sz+3
49 #define NFS_writeargs_sz NFS_fhandle_sz+4
50 #define NFS_createargs_sz NFS_diropargs_sz+NFS_sattr_sz
51 #define NFS_renameargs_sz NFS_diropargs_sz+NFS_diropargs_sz
52 #define NFS_linkargs_sz NFS_fhandle_sz+NFS_diropargs_sz
53 #define NFS_symlinkargs_sz NFS_diropargs_sz+NFS_path_sz+NFS_sattr_sz
54 #define NFS_readdirargs_sz NFS_fhandle_sz+2
56 #define NFS_dec_void_sz 0
57 #define NFS_attrstat_sz 1+NFS_fattr_sz
58 #define NFS_diropres_sz 1+NFS_fhandle_sz+NFS_fattr_sz
59 #define NFS_readlinkres_sz 1+NFS_path_sz
60 #define NFS_readres_sz 1+NFS_fattr_sz+1
62 #define NFS_readdirres_sz 1
63 #define NFS_statfsres_sz 1+NFS_info_sz
66 * Common NFS XDR functions as inlines
69 xdr_encode_fhandle(u32
*p
, struct nfs_fh
*fhandle
)
71 *((struct nfs_fh
*) p
) = *fhandle
;
72 return p
+ QUADLEN(sizeof(*fhandle
));
76 xdr_decode_fhandle(u32
*p
, struct nfs_fh
*fhandle
)
78 *fhandle
= *((struct nfs_fh
*) p
);
79 return p
+ QUADLEN(sizeof(*fhandle
));
83 xdr_decode_string2(u32
*p
, char **string
, unsigned int *len
,
90 return p
+ QUADLEN(*len
);
94 xdr_decode_fattr(u32
*p
, struct nfs_fattr
*fattr
)
96 fattr
->type
= (enum nfs_ftype
) ntohl(*p
++);
97 fattr
->mode
= ntohl(*p
++);
98 fattr
->nlink
= ntohl(*p
++);
99 fattr
->uid
= ntohl(*p
++);
100 fattr
->gid
= ntohl(*p
++);
101 fattr
->size
= ntohl(*p
++);
102 fattr
->blocksize
= ntohl(*p
++);
103 fattr
->rdev
= ntohl(*p
++);
104 fattr
->blocks
= ntohl(*p
++);
105 fattr
->fsid
= ntohl(*p
++);
106 fattr
->fileid
= ntohl(*p
++);
107 fattr
->atime
.seconds
= ntohl(*p
++);
108 fattr
->atime
.useconds
= ntohl(*p
++);
109 fattr
->mtime
.seconds
= ntohl(*p
++);
110 fattr
->mtime
.useconds
= ntohl(*p
++);
111 fattr
->ctime
.seconds
= ntohl(*p
++);
112 fattr
->ctime
.useconds
= ntohl(*p
++);
117 xdr_encode_sattr(u32
*p
, struct nfs_sattr
*sattr
)
119 *p
++ = htonl(sattr
->mode
);
120 *p
++ = htonl(sattr
->uid
);
121 *p
++ = htonl(sattr
->gid
);
122 *p
++ = htonl(sattr
->size
);
123 *p
++ = htonl(sattr
->atime
.seconds
);
124 *p
++ = htonl(sattr
->atime
.useconds
);
125 *p
++ = htonl(sattr
->mtime
.seconds
);
126 *p
++ = htonl(sattr
->mtime
.useconds
);
131 * NFS encode functions
134 * Encode void argument
137 nfs_xdr_enc_void(struct rpc_rqst
*req
, u32
*p
, void *dummy
)
139 req
->rq_slen
= xdr_adjust_iovec(req
->rq_svec
, p
);
144 * Encode file handle argument
145 * GETATTR, READLINK, STATFS
148 nfs_xdr_fhandle(struct rpc_rqst
*req
, u32
*p
, struct nfs_fh
*fh
)
150 p
= xdr_encode_fhandle(p
, fh
);
151 req
->rq_slen
= xdr_adjust_iovec(req
->rq_svec
, p
);
156 * Encode SETATTR arguments
159 nfs_xdr_sattrargs(struct rpc_rqst
*req
, u32
*p
, struct nfs_sattrargs
*args
)
161 p
= xdr_encode_fhandle(p
, args
->fh
);
162 p
= xdr_encode_sattr(p
, args
->sattr
);
163 req
->rq_slen
= xdr_adjust_iovec(req
->rq_svec
, p
);
168 * Encode directory ops argument
169 * LOOKUP, REMOVE, RMDIR
172 nfs_xdr_diropargs(struct rpc_rqst
*req
, u32
*p
, struct nfs_diropargs
*args
)
174 p
= xdr_encode_fhandle(p
, args
->fh
);
175 p
= xdr_encode_string(p
, args
->name
);
176 req
->rq_slen
= xdr_adjust_iovec(req
->rq_svec
, p
);
181 * Arguments to a READ call. Since we read data directly into the page
182 * cache, we also set up the reply iovec here so that iov[1] points
183 * exactly to the page wewant to fetch.
186 nfs_xdr_readargs(struct rpc_rqst
*req
, u32
*p
, struct nfs_readargs
*args
)
188 struct rpc_auth
*auth
= req
->rq_task
->tk_auth
;
191 p
= xdr_encode_fhandle(p
, args
->fh
);
192 *p
++ = htonl(args
->offset
);
193 *p
++ = htonl(args
->count
);
194 *p
++ = htonl(args
->count
);
195 req
->rq_slen
= xdr_adjust_iovec(req
->rq_svec
, p
);
198 /* set up reply iovec */
199 replen
= (RPC_REPHDRSIZE
+ auth
->au_rslack
+ NFS_readres_sz
) << 2;
200 buflen
= req
->rq_rvec
[0].iov_len
;
201 req
->rq_rvec
[0].iov_len
= replen
;
202 req
->rq_rvec
[1].iov_base
= args
->buffer
;
203 req
->rq_rvec
[1].iov_len
= args
->count
;
204 req
->rq_rvec
[2].iov_base
= (u8
*) req
->rq_rvec
[0].iov_base
+ replen
;
205 req
->rq_rvec
[2].iov_len
= buflen
- replen
;
206 req
->rq_rlen
= args
->count
+ buflen
;
209 replen
= (RPC_REPHDRSIZE
+ auth
->au_rslack
+ NFS_readres_sz
) << 2;
210 req
->rq_rvec
[0].iov_len
= replen
;
220 nfs_xdr_readres(struct rpc_rqst
*req
, u32
*p
, struct nfs_readres
*res
)
222 struct iovec
*iov
= req
->rq_rvec
;
223 int status
, count
, recvd
, hdrlen
;
225 dprintk("RPC: readres OK status %lx\n", (long)ntohl(*p
));
226 if ((status
= ntohl(*p
++)))
227 return -nfs_stat_to_errno(status
);
228 p
= xdr_decode_fattr(p
, res
->fattr
);
231 hdrlen
= (u8
*) p
- (u8
*) iov
->iov_base
;
232 recvd
= req
->rq_rlen
- hdrlen
;
233 if (p
!= iov
[2].iov_base
) {
234 /* Unexpected reply header size. Punt.
235 * XXX: Move iovec contents to align data on page
236 * boundary and adjust RPC header size guess */
237 printk("NFS: Odd RPC header size in read reply: %d\n", hdrlen
);
238 return -errno_NFSERR_IO
;
241 printk("NFS: server cheating in read reply: "
242 "count %d > recvd %d\n", count
, recvd
);
246 dprintk("RPC: readres OK count %d\n", count
);
247 if (count
< res
->count
)
248 memset((u8
*)(iov
[1].iov_base
+count
), 0, res
->count
-count
);
255 * Write arguments. Splice the buffer to be written into the iovec.
258 nfs_xdr_writeargs(struct rpc_rqst
*req
, u32
*p
, struct nfs_writeargs
*args
)
260 p
= xdr_encode_fhandle(p
, args
->fh
);
261 *p
++ = htonl(args
->offset
);
262 *p
++ = htonl(args
->offset
);
263 *p
++ = htonl(args
->count
);
264 *p
++ = htonl(args
->count
);
265 req
->rq_slen
= xdr_adjust_iovec(req
->rq_svec
, p
);
267 req
->rq_svec
[1].iov_base
= (void *) args
->buffer
;
268 req
->rq_svec
[1].iov_len
= args
->count
;
269 req
->rq_slen
+= args
->count
;
276 * Encode create arguments
280 nfs_xdr_createargs(struct rpc_rqst
*req
, u32
*p
, struct nfs_createargs
*args
)
282 p
= xdr_encode_fhandle(p
, args
->fh
);
283 p
= xdr_encode_string(p
, args
->name
);
284 p
= xdr_encode_sattr(p
, args
->sattr
);
285 req
->rq_slen
= xdr_adjust_iovec(req
->rq_svec
, p
);
290 * Encode RENAME arguments
293 nfs_xdr_renameargs(struct rpc_rqst
*req
, u32
*p
, struct nfs_renameargs
*args
)
295 p
= xdr_encode_fhandle(p
, args
->fromfh
);
296 p
= xdr_encode_string(p
, args
->fromname
);
297 p
= xdr_encode_fhandle(p
, args
->tofh
);
298 p
= xdr_encode_string(p
, args
->toname
);
299 req
->rq_slen
= xdr_adjust_iovec(req
->rq_svec
, p
);
304 * Encode LINK arguments
307 nfs_xdr_linkargs(struct rpc_rqst
*req
, u32
*p
, struct nfs_linkargs
*args
)
309 p
= xdr_encode_fhandle(p
, args
->fromfh
);
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 SYMLINK arguments
320 nfs_xdr_symlinkargs(struct rpc_rqst
*req
, u32
*p
, struct nfs_symlinkargs
*args
)
322 p
= xdr_encode_fhandle(p
, args
->fromfh
);
323 p
= xdr_encode_string(p
, args
->fromname
);
324 p
= xdr_encode_string(p
, args
->topath
);
325 p
= xdr_encode_sattr(p
, args
->sattr
);
326 req
->rq_slen
= xdr_adjust_iovec(req
->rq_svec
, p
);
331 * Encode arguments to readdir call
334 nfs_xdr_readdirargs(struct rpc_rqst
*req
, u32
*p
, struct nfs_readdirargs
*args
)
336 struct rpc_auth
*auth
= req
->rq_task
->tk_auth
;
339 p
= xdr_encode_fhandle(p
, args
->fh
);
340 *p
++ = htonl(args
->cookie
);
341 *p
++ = htonl(args
->bufsiz
);
342 req
->rq_slen
= xdr_adjust_iovec(req
->rq_svec
, p
);
344 /* set up reply iovec */
345 replen
= (RPC_REPHDRSIZE
+ auth
->au_rslack
+ NFS_readdirres_sz
) << 2;
347 dprintk("RPC: readdirargs: slack is 4 * (%d + %d + %d) = %d\n",
348 RPC_REPHDRSIZE, auth->au_rslack, NFS_readdirres_sz, replen);
350 req
->rq_rvec
[0].iov_len
= replen
;
351 req
->rq_rvec
[1].iov_base
= args
->buffer
;
352 req
->rq_rvec
[1].iov_len
= args
->bufsiz
;
353 req
->rq_rlen
= replen
+ args
->bufsiz
;
357 dprintk("RPC: readdirargs set up reply vec:\n");
358 dprintk(" rvec[0] = %p/%d\n",
359 req->rq_rvec[0].iov_base,
360 req->rq_rvec[0].iov_len);
361 dprintk(" rvec[1] = %p/%d\n",
362 req->rq_rvec[1].iov_base,
363 req->rq_rvec[1].iov_len);
370 * Decode the result of a readdir call. We decode the result in place
371 * to avoid a malloc of NFS_MAXNAMLEN+1 for each file name.
372 * After decoding, the layout in memory looks like this:
373 * entry1 entry2 ... entryN <space> stringN ... string2 string1
374 * Note that the strings are not null-terminated so that the entire number
375 * of entries returned by the server should fit into the buffer.
378 nfs_xdr_readdirres(struct rpc_rqst
*req
, u32
*p
, struct nfs_readdirres
*res
)
380 struct nfs_entry
*entry
;
381 struct iovec
*iov
= req
->rq_rvec
;
386 if ((status
= ntohl(*p
++)))
387 return -nfs_stat_to_errno(status
);
388 if ((void *) p
!= ((u8
*) iov
->iov_base
+iov
->iov_len
)) {
389 /* Unexpected reply header size. Punt. */
390 printk("NFS: Odd RPC header size in readdirres reply\n");
391 return -errno_NFSERR_IO
;
394 /* Get start and end address of XDR data */
395 p
= (u32
*) iov
[1].iov_base
;
396 end
= (u32
*) ((u8
*) p
+ iov
[1].iov_len
);
398 /* Get start and end of dirent buffer */
399 entry
= (struct nfs_entry
*) res
->buffer
;
400 string
= (char *) res
->buffer
+ res
->bufsiz
;
401 for (nr
= 0; *p
++; nr
++, entry
++) {
402 entry
->fileid
= ntohl(*p
++);
405 if ((p
+ QUADLEN(len
) + 3) > end
) {
407 "NFS: short packet in readdir reply!\n");
410 if (len
> NFS_MAXNAMLEN
) {
411 printk("NFS: giant filename in readdir (len %x)!\n",
413 return -errno_NFSERR_IO
;
416 if ((void *) (entry
+1) > (void *) string
) {
417 /* This may actually happen because an nfs_entry
418 * will take up more space than the XDR data. On
419 * 32bit machines that's due to 8byte alignment,
420 * on 64bit machines that's because the char * takes
425 printk(KERN_NOTICE
"NFS: should not happen in %s!\n",
430 entry
->name
= string
;
432 memmove(string
, p
, len
);
434 entry
->cookie
= ntohl(*p
++);
435 entry
->eof
= !p
[0] && p
[1];
441 * NFS XDR decode functions
447 nfs_xdr_dec_void(struct rpc_rqst
*req
, u32
*p
, void *dummy
)
453 * Decode simple status reply
456 nfs_xdr_stat(struct rpc_rqst
*req
, u32
*p
, void *dummy
)
460 if ((status
= ntohl(*p
++)) != 0)
461 status
= -nfs_stat_to_errno(status
);
466 * Decode attrstat reply
467 * GETATTR, SETATTR, WRITE
470 nfs_xdr_attrstat(struct rpc_rqst
*req
, u32
*p
, struct nfs_fattr
*fattr
)
474 dprintk("RPC: attrstat status %lx\n", (long)ntohl(*p
));
475 if ((status
= ntohl(*p
++)))
476 return -nfs_stat_to_errno(status
);
477 xdr_decode_fattr(p
, fattr
);
478 dprintk("RPC: attrstat OK type %d mode %o dev %x ino %x\n",
479 fattr
->type
, fattr
->mode
, fattr
->fsid
, fattr
->fileid
);
484 * Decode diropres reply
485 * LOOKUP, CREATE, MKDIR
488 nfs_xdr_diropres(struct rpc_rqst
*req
, u32
*p
, struct nfs_diropok
*res
)
492 dprintk("RPC: diropres status %lx\n", (long)ntohl(*p
));
493 if ((status
= ntohl(*p
++)))
494 return -nfs_stat_to_errno(status
);
495 p
= xdr_decode_fhandle(p
, res
->fh
);
496 xdr_decode_fattr(p
, res
->fattr
);
497 dprintk("RPC: diropres OK type %x mode %o dev %x ino %x\n",
498 res
->fattr
->type
, res
->fattr
->mode
,
499 res
->fattr
->fsid
, res
->fattr
->fileid
);
504 * Decode READLINK reply
507 nfs_xdr_readlinkres(struct rpc_rqst
*req
, u32
*p
, struct nfs_readlinkres
*res
)
511 if ((status
= ntohl(*p
++)))
512 return -nfs_stat_to_errno(status
);
513 xdr_decode_string2(p
, res
->string
, res
->lenp
, res
->maxlen
);
515 /* Caller takes over the buffer here to avoid extra copy */
516 res
->buffer
= req
->rq_task
->tk_buffer
;
517 req
->rq_task
->tk_buffer
= NULL
;
522 * Decode STATFS reply
525 nfs_xdr_statfsres(struct rpc_rqst
*req
, u32
*p
, struct nfs_fsinfo
*res
)
529 if ((status
= ntohl(*p
++)))
530 return -nfs_stat_to_errno(status
);
531 res
->tsize
= ntohl(*p
++);
532 res
->bsize
= ntohl(*p
++);
533 res
->blocks
= ntohl(*p
++);
534 res
->bfree
= ntohl(*p
++);
535 res
->bavail
= ntohl(*p
++);
540 * We need to translate between nfs status return values and
541 * the local errno values which may not be the same.
548 { NFSERR_PERM
, EPERM
},
549 { NFSERR_NOENT
, ENOENT
},
550 { NFSERR_IO
, errno_NFSERR_IO
},
551 { NFSERR_NXIO
, ENXIO
},
552 { NFSERR_EAGAIN
, EAGAIN
},
553 { NFSERR_ACCES
, EACCES
},
554 { NFSERR_EXIST
, EEXIST
},
555 { NFSERR_NODEV
, ENODEV
},
556 { NFSERR_NOTDIR
, ENOTDIR
},
557 { NFSERR_ISDIR
, EISDIR
},
558 { NFSERR_INVAL
, EINVAL
},
559 { NFSERR_FBIG
, EFBIG
},
560 { NFSERR_NOSPC
, ENOSPC
},
561 { NFSERR_ROFS
, EROFS
},
562 { NFSERR_NAMETOOLONG
, ENAMETOOLONG
},
563 { NFSERR_NOTEMPTY
, ENOTEMPTY
},
564 { NFSERR_DQUOT
, EDQUOT
},
565 { NFSERR_STALE
, ESTALE
},
567 { NFSERR_WFLUSH
, EWFLUSH
},
573 nfs_stat_to_errno(int stat
)
577 for (i
= 0; nfs_errtbl
[i
].stat
!= -1; i
++) {
578 if (nfs_errtbl
[i
].stat
== stat
)
579 return nfs_errtbl
[i
].errno
;
581 printk("nfs_stat_to_errno: bad nfs status return value: %d\n", stat
);
582 return nfs_errtbl
[i
].errno
;
586 # define MAX(a, b) (((a) > (b))? (a) : (b))
589 #define PROC(proc, argtype, restype) \
591 (kxdrproc_t) nfs_xdr_##argtype, \
592 (kxdrproc_t) nfs_xdr_##restype, \
593 MAX(NFS_##argtype##_sz,NFS_##restype##_sz) << 2 \
596 static struct rpc_procinfo nfs_procedures
[18] = {
597 PROC(null
, enc_void
, dec_void
),
598 PROC(getattr
, fhandle
, attrstat
),
599 PROC(setattr
, sattrargs
, attrstat
),
600 PROC(root
, enc_void
, dec_void
),
601 PROC(lookup
, diropargs
, diropres
),
602 PROC(readlink
, fhandle
, readlinkres
),
603 PROC(read
, readargs
, readres
),
604 PROC(writecache
, enc_void
, dec_void
),
605 PROC(write
, writeargs
, attrstat
),
606 PROC(create
, createargs
, diropres
),
607 PROC(remove
, diropargs
, stat
),
608 PROC(rename
, renameargs
, stat
),
609 PROC(link
, linkargs
, stat
),
610 PROC(symlink
, symlinkargs
, stat
),
611 PROC(mkdir
, createargs
, diropres
),
612 PROC(rmdir
, diropargs
, stat
),
613 PROC(readdir
, readdirargs
, readdirres
),
614 PROC(statfs
, fhandle
, statfsres
),
617 static struct rpc_version nfs_version2
= {
619 sizeof(nfs_procedures
)/sizeof(nfs_procedures
[0]),
623 static struct rpc_version
* nfs_version
[] = {
629 struct rpc_program nfs_program
= {
632 sizeof(nfs_version
) / sizeof(nfs_version
[0]),