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 /* Uncomment this to support servers requiring longword lengths */
26 #define NFS_PAD_WRITES 1
28 #define NFSDBG_FACILITY NFSDBG_XDR
29 /* #define NFS_PARANOIA 1 */
31 #define QUADLEN(len) (((len) + 3) >> 2)
32 static int nfs_stat_to_errno(int stat
);
34 /* Mapping from NFS error code to "errno" error code. */
35 #define errno_NFSERR_IO EIO
38 * Declare the space requirements for NFS arguments and replies as
39 * number of 32bit-words
41 #define NFS_fhandle_sz 8
42 #define NFS_sattr_sz 8
43 #define NFS_filename_sz 1+(NFS_MAXNAMLEN>>2)
44 #define NFS_path_sz 1+(NFS_MAXPATHLEN>>2)
45 #define NFS_fattr_sz 17
47 #define NFS_entry_sz NFS_filename_sz+3
49 #define NFS_enc_void_sz 0
50 #define NFS_diropargs_sz NFS_fhandle_sz+NFS_filename_sz
51 #define NFS_sattrargs_sz NFS_fhandle_sz+NFS_sattr_sz
52 #define NFS_readargs_sz NFS_fhandle_sz+3
53 #define NFS_writeargs_sz NFS_fhandle_sz+4
54 #define NFS_createargs_sz NFS_diropargs_sz+NFS_sattr_sz
55 #define NFS_renameargs_sz NFS_diropargs_sz+NFS_diropargs_sz
56 #define NFS_linkargs_sz NFS_fhandle_sz+NFS_diropargs_sz
57 #define NFS_symlinkargs_sz NFS_diropargs_sz+NFS_path_sz+NFS_sattr_sz
58 #define NFS_readdirargs_sz NFS_fhandle_sz+2
60 #define NFS_dec_void_sz 0
61 #define NFS_attrstat_sz 1+NFS_fattr_sz
62 #define NFS_diropres_sz 1+NFS_fhandle_sz+NFS_fattr_sz
63 #define NFS_readlinkres_sz 1+NFS_path_sz
64 #define NFS_readres_sz 1+NFS_fattr_sz+1
66 #define NFS_readdirres_sz 1
67 #define NFS_statfsres_sz 1+NFS_info_sz
70 * Common NFS XDR functions as inlines
73 xdr_encode_fhandle(u32
*p
, struct nfs_fh
*fhandle
)
75 *((struct nfs_fh
*) p
) = *fhandle
;
76 return p
+ QUADLEN(sizeof(*fhandle
));
80 xdr_decode_fhandle(u32
*p
, struct nfs_fh
*fhandle
)
82 *fhandle
= *((struct nfs_fh
*) p
);
83 return p
+ QUADLEN(sizeof(*fhandle
));
87 xdr_decode_string2(u32
*p
, char **string
, unsigned int *len
,
94 return p
+ QUADLEN(*len
);
98 xdr_decode_fattr(u32
*p
, struct nfs_fattr
*fattr
)
100 fattr
->type
= (enum nfs_ftype
) ntohl(*p
++);
101 fattr
->mode
= ntohl(*p
++);
102 fattr
->nlink
= ntohl(*p
++);
103 fattr
->uid
= ntohl(*p
++);
104 fattr
->gid
= ntohl(*p
++);
105 fattr
->size
= ntohl(*p
++);
106 fattr
->blocksize
= ntohl(*p
++);
107 fattr
->rdev
= ntohl(*p
++);
108 fattr
->blocks
= ntohl(*p
++);
109 fattr
->fsid
= ntohl(*p
++);
110 fattr
->fileid
= ntohl(*p
++);
111 fattr
->atime
.seconds
= ntohl(*p
++);
112 fattr
->atime
.useconds
= ntohl(*p
++);
113 fattr
->mtime
.seconds
= ntohl(*p
++);
114 fattr
->mtime
.useconds
= ntohl(*p
++);
115 fattr
->ctime
.seconds
= ntohl(*p
++);
116 fattr
->ctime
.useconds
= ntohl(*p
++);
121 xdr_encode_sattr(u32
*p
, struct nfs_sattr
*sattr
)
123 *p
++ = htonl(sattr
->mode
);
124 *p
++ = htonl(sattr
->uid
);
125 *p
++ = htonl(sattr
->gid
);
126 *p
++ = htonl(sattr
->size
);
127 *p
++ = htonl(sattr
->atime
.seconds
);
128 *p
++ = htonl(sattr
->atime
.useconds
);
129 *p
++ = htonl(sattr
->mtime
.seconds
);
130 *p
++ = htonl(sattr
->mtime
.useconds
);
135 * NFS encode functions
138 * Encode void argument
141 nfs_xdr_enc_void(struct rpc_rqst
*req
, u32
*p
, void *dummy
)
143 req
->rq_slen
= xdr_adjust_iovec(req
->rq_svec
, p
);
148 * Encode file handle argument
149 * GETATTR, READLINK, STATFS
152 nfs_xdr_fhandle(struct rpc_rqst
*req
, u32
*p
, struct nfs_fh
*fh
)
154 p
= xdr_encode_fhandle(p
, fh
);
155 req
->rq_slen
= xdr_adjust_iovec(req
->rq_svec
, p
);
160 * Encode SETATTR arguments
163 nfs_xdr_sattrargs(struct rpc_rqst
*req
, u32
*p
, struct nfs_sattrargs
*args
)
165 p
= xdr_encode_fhandle(p
, args
->fh
);
166 p
= xdr_encode_sattr(p
, args
->sattr
);
167 req
->rq_slen
= xdr_adjust_iovec(req
->rq_svec
, p
);
172 * Encode directory ops argument
173 * LOOKUP, REMOVE, RMDIR
176 nfs_xdr_diropargs(struct rpc_rqst
*req
, u32
*p
, struct nfs_diropargs
*args
)
178 p
= xdr_encode_fhandle(p
, args
->fh
);
179 p
= xdr_encode_string(p
, args
->name
);
180 req
->rq_slen
= xdr_adjust_iovec(req
->rq_svec
, p
);
185 * Arguments to a READ call. Since we read data directly into the page
186 * cache, we also set up the reply iovec here so that iov[1] points
187 * exactly to the page we want to fetch.
190 nfs_xdr_readargs(struct rpc_rqst
*req
, u32
*p
, struct nfs_readargs
*args
)
192 struct rpc_auth
*auth
= req
->rq_task
->tk_auth
;
195 p
= xdr_encode_fhandle(p
, args
->fh
);
196 *p
++ = htonl(args
->offset
);
197 *p
++ = htonl(args
->count
);
198 *p
++ = htonl(args
->count
);
199 req
->rq_slen
= xdr_adjust_iovec(req
->rq_svec
, p
);
202 /* set up reply iovec */
203 replen
= (RPC_REPHDRSIZE
+ auth
->au_rslack
+ NFS_readres_sz
) << 2;
204 buflen
= req
->rq_rvec
[0].iov_len
;
205 req
->rq_rvec
[0].iov_len
= replen
;
206 req
->rq_rvec
[1].iov_base
= args
->buffer
;
207 req
->rq_rvec
[1].iov_len
= args
->count
;
208 req
->rq_rvec
[2].iov_base
= (u8
*) req
->rq_rvec
[0].iov_base
+ replen
;
209 req
->rq_rvec
[2].iov_len
= buflen
- replen
;
210 req
->rq_rlen
= args
->count
+ buflen
;
213 replen
= (RPC_REPHDRSIZE
+ auth
->au_rslack
+ NFS_readres_sz
) << 2;
214 req
->rq_rvec
[0].iov_len
= replen
;
224 nfs_xdr_readres(struct rpc_rqst
*req
, u32
*p
, struct nfs_readres
*res
)
226 struct iovec
*iov
= req
->rq_rvec
;
227 int status
, count
, recvd
, hdrlen
;
229 dprintk("RPC: readres OK status %lx\n", (long)ntohl(*p
));
230 if ((status
= ntohl(*p
++)))
231 return -nfs_stat_to_errno(status
);
232 p
= xdr_decode_fattr(p
, res
->fattr
);
235 hdrlen
= (u8
*) p
- (u8
*) iov
->iov_base
;
236 recvd
= req
->rq_rlen
- hdrlen
;
237 if (p
!= iov
[2].iov_base
) {
238 /* Unexpected reply header size. Punt.
239 * XXX: Move iovec contents to align data on page
240 * boundary and adjust RPC header size guess */
241 printk("NFS: Odd RPC header size in read reply: %d\n", hdrlen
);
242 return -errno_NFSERR_IO
;
245 printk("NFS: server cheating in read reply: "
246 "count %d > recvd %d\n", count
, recvd
);
250 dprintk("RPC: readres OK count %d\n", count
);
251 if (count
< res
->count
)
252 memset((u8
*)(iov
[1].iov_base
+count
), 0, res
->count
-count
);
259 * Write arguments. Splice the buffer to be written into the iovec.
262 nfs_xdr_writeargs(struct rpc_rqst
*req
, u32
*p
, struct nfs_writeargs
*args
)
264 u32 count
= args
->count
;
266 p
= xdr_encode_fhandle(p
, args
->fh
);
267 *p
++ = htonl(args
->offset
);
268 *p
++ = htonl(args
->offset
);
271 req
->rq_slen
= xdr_adjust_iovec(req
->rq_svec
, p
);
273 req
->rq_svec
[1].iov_base
= (void *) args
->buffer
;
274 req
->rq_svec
[1].iov_len
= count
;
275 req
->rq_slen
+= count
;
278 #ifdef NFS_PAD_WRITES
280 * Some old servers require that the message length
281 * be a multiple of 4, so we pad it here if needed.
283 count
= ((count
+ 3) & ~3) - count
;
286 printk("nfs_writeargs: padding write, len=%d, slen=%d, pad=%d\n",
287 req
->rq_svec
[1].iov_len
, req
->rq_slen
, count
);
289 req
->rq_svec
[2].iov_base
= (void *) "\0\0\0";
290 req
->rq_svec
[2].iov_len
= count
;
291 req
->rq_slen
+= count
;
300 * Encode create arguments
304 nfs_xdr_createargs(struct rpc_rqst
*req
, u32
*p
, struct nfs_createargs
*args
)
306 p
= xdr_encode_fhandle(p
, args
->fh
);
307 p
= xdr_encode_string(p
, args
->name
);
308 p
= xdr_encode_sattr(p
, args
->sattr
);
309 req
->rq_slen
= xdr_adjust_iovec(req
->rq_svec
, p
);
314 * Encode RENAME arguments
317 nfs_xdr_renameargs(struct rpc_rqst
*req
, u32
*p
, struct nfs_renameargs
*args
)
319 p
= xdr_encode_fhandle(p
, args
->fromfh
);
320 p
= xdr_encode_string(p
, args
->fromname
);
321 p
= xdr_encode_fhandle(p
, args
->tofh
);
322 p
= xdr_encode_string(p
, args
->toname
);
323 req
->rq_slen
= xdr_adjust_iovec(req
->rq_svec
, p
);
328 * Encode LINK arguments
331 nfs_xdr_linkargs(struct rpc_rqst
*req
, u32
*p
, struct nfs_linkargs
*args
)
333 p
= xdr_encode_fhandle(p
, args
->fromfh
);
334 p
= xdr_encode_fhandle(p
, args
->tofh
);
335 p
= xdr_encode_string(p
, args
->toname
);
336 req
->rq_slen
= xdr_adjust_iovec(req
->rq_svec
, p
);
341 * Encode SYMLINK arguments
344 nfs_xdr_symlinkargs(struct rpc_rqst
*req
, u32
*p
, struct nfs_symlinkargs
*args
)
346 p
= xdr_encode_fhandle(p
, args
->fromfh
);
347 p
= xdr_encode_string(p
, args
->fromname
);
348 p
= xdr_encode_string(p
, args
->topath
);
349 p
= xdr_encode_sattr(p
, args
->sattr
);
350 req
->rq_slen
= xdr_adjust_iovec(req
->rq_svec
, p
);
355 * Encode arguments to readdir call
358 nfs_xdr_readdirargs(struct rpc_rqst
*req
, u32
*p
, struct nfs_readdirargs
*args
)
360 struct rpc_task
*task
= req
->rq_task
;
361 struct rpc_auth
*auth
= task
->tk_auth
;
362 u32 bufsiz
= args
->bufsiz
;
366 * Some servers (e.g. HP OS 9.5) seem to expect the buffer size
367 * to be in longwords ... check whether to convert the size.
369 if (task
->tk_client
->cl_flags
& NFS_CLNTF_BUFSIZE
)
370 bufsiz
= bufsiz
>> 2;
372 p
= xdr_encode_fhandle(p
, args
->fh
);
373 *p
++ = htonl(args
->cookie
);
374 *p
++ = htonl(bufsiz
); /* see above */
375 req
->rq_slen
= xdr_adjust_iovec(req
->rq_svec
, p
);
377 /* set up reply iovec */
378 replen
= (RPC_REPHDRSIZE
+ auth
->au_rslack
+ NFS_readdirres_sz
) << 2;
380 dprintk("RPC: readdirargs: slack is 4 * (%d + %d + %d) = %d\n",
381 RPC_REPHDRSIZE, auth->au_rslack, NFS_readdirres_sz, replen);
383 req
->rq_rvec
[0].iov_len
= replen
;
384 req
->rq_rvec
[1].iov_base
= args
->buffer
;
385 req
->rq_rvec
[1].iov_len
= args
->bufsiz
;
386 req
->rq_rlen
= replen
+ args
->bufsiz
;
390 dprintk("RPC: readdirargs set up reply vec:\n");
391 dprintk(" rvec[0] = %p/%d\n",
392 req->rq_rvec[0].iov_base,
393 req->rq_rvec[0].iov_len);
394 dprintk(" rvec[1] = %p/%d\n",
395 req->rq_rvec[1].iov_base,
396 req->rq_rvec[1].iov_len);
403 * Decode the result of a readdir call. We decode the result in place
404 * to avoid a malloc of NFS_MAXNAMLEN+1 for each file name.
405 * After decoding, the layout in memory looks like this:
406 * entry1 entry2 ... entryN <space> stringN ... string2 string1
407 * Each entry consists of three __u32 values, the same space as NFS uses.
408 * Note that the strings are not null-terminated so that the entire number
409 * of entries returned by the server should fit into the buffer.
412 nfs_xdr_readdirres(struct rpc_rqst
*req
, u32
*p
, struct nfs_readdirres
*res
)
414 struct iovec
*iov
= req
->rq_rvec
;
416 char *string
, *start
;
417 u32
*end
, *entry
, len
, fileid
, cookie
;
419 if ((status
= ntohl(*p
++)))
420 return -nfs_stat_to_errno(status
);
421 if ((void *) p
!= ((u8
*) iov
->iov_base
+iov
->iov_len
)) {
422 /* Unexpected reply header size. Punt. */
423 printk("NFS: Odd RPC header size in readdirres reply\n");
424 return -errno_NFSERR_IO
;
427 /* Get start and end address of XDR data */
428 p
= (u32
*) iov
[1].iov_base
;
429 end
= (u32
*) ((u8
*) p
+ iov
[1].iov_len
);
431 /* Get start and end of dirent buffer */
432 entry
= (u32
*) res
->buffer
;
433 start
= (char *) res
->buffer
;
434 string
= (char *) res
->buffer
+ res
->bufsiz
;
435 for (nr
= 0; *p
++; nr
++) {
436 fileid
= ntohl(*p
++);
440 * Check whether the server has exceeded our reply buffer,
441 * and set a flag to convert the size to longwords.
443 if ((p
+ QUADLEN(len
) + 3) > end
) {
444 struct rpc_clnt
*clnt
= req
->rq_task
->tk_client
;
446 "NFS: server %s, readdir reply truncated\n",
448 printk(KERN_WARNING
"NFS: nr=%d, slots=%d, len=%d\n",
450 clnt
->cl_flags
|= NFS_CLNTF_BUFSIZE
;
453 if (len
> NFS_MAXNAMLEN
) {
454 printk("NFS: giant filename in readdir (len %x)!\n",
456 return -errno_NFSERR_IO
;
459 if ((void *) (entry
+3) > (void *) string
) {
461 * This error is impossible as long as the temp
462 * buffer is no larger than the user buffer. The
463 * current packing algorithm uses the same amount
464 * of space in the user buffer as in the XDR data,
465 * so it's guaranteed to fit.
467 printk("NFS: incorrect buffer size in %s!\n",
472 memmove(string
, p
, len
);
474 cookie
= ntohl(*p
++);
476 * To make everything fit, we encode the length, offset,
477 * and eof flag into 32 bits. This works for filenames
478 * up to 32K and PAGE_SIZE up to 64K.
480 status
= !p
[0] && p
[1] ? (1 << 15) : 0; /* eof flag */
483 *entry
++ = ((string
- start
) << 16) | status
| (len
& 0x7FFF);
486 printk("nfs_xdr_readdirres: %d entries, ent sp=%d, str sp=%d\n",
487 nr
, ((char *) entry
- start
), (start
+ res
->bufsiz
- string
));
493 * NFS XDR decode functions
499 nfs_xdr_dec_void(struct rpc_rqst
*req
, u32
*p
, void *dummy
)
505 * Decode simple status reply
508 nfs_xdr_stat(struct rpc_rqst
*req
, u32
*p
, void *dummy
)
512 if ((status
= ntohl(*p
++)) != 0)
513 status
= -nfs_stat_to_errno(status
);
518 * Decode attrstat reply
519 * GETATTR, SETATTR, WRITE
522 nfs_xdr_attrstat(struct rpc_rqst
*req
, u32
*p
, struct nfs_fattr
*fattr
)
526 dprintk("RPC: attrstat status %lx\n", (long)ntohl(*p
));
527 if ((status
= ntohl(*p
++)))
528 return -nfs_stat_to_errno(status
);
529 xdr_decode_fattr(p
, fattr
);
530 dprintk("RPC: attrstat OK type %d mode %o dev %x ino %x\n",
531 fattr
->type
, fattr
->mode
, fattr
->fsid
, fattr
->fileid
);
536 * Decode diropres reply
537 * LOOKUP, CREATE, MKDIR
540 nfs_xdr_diropres(struct rpc_rqst
*req
, u32
*p
, struct nfs_diropok
*res
)
544 dprintk("RPC: diropres status %lx\n", (long)ntohl(*p
));
545 if ((status
= ntohl(*p
++)))
546 return -nfs_stat_to_errno(status
);
547 p
= xdr_decode_fhandle(p
, res
->fh
);
548 xdr_decode_fattr(p
, res
->fattr
);
549 dprintk("RPC: diropres OK type %x mode %o dev %x ino %x\n",
550 res
->fattr
->type
, res
->fattr
->mode
,
551 res
->fattr
->fsid
, res
->fattr
->fileid
);
556 * Decode READLINK reply
559 nfs_xdr_readlinkres(struct rpc_rqst
*req
, u32
*p
, struct nfs_readlinkres
*res
)
563 if ((status
= ntohl(*p
++)))
564 return -nfs_stat_to_errno(status
);
565 xdr_decode_string2(p
, res
->string
, res
->lenp
, res
->maxlen
);
567 /* Caller takes over the buffer here to avoid extra copy */
568 res
->buffer
= req
->rq_task
->tk_buffer
;
569 req
->rq_task
->tk_buffer
= NULL
;
574 * Decode STATFS reply
577 nfs_xdr_statfsres(struct rpc_rqst
*req
, u32
*p
, struct nfs_fsinfo
*res
)
581 if ((status
= ntohl(*p
++)))
582 return -nfs_stat_to_errno(status
);
583 res
->tsize
= ntohl(*p
++);
584 res
->bsize
= ntohl(*p
++);
585 res
->blocks
= ntohl(*p
++);
586 res
->bfree
= ntohl(*p
++);
587 res
->bavail
= ntohl(*p
++);
592 * We need to translate between nfs status return values and
593 * the local errno values which may not be the same.
600 { NFSERR_PERM
, EPERM
},
601 { NFSERR_NOENT
, ENOENT
},
602 { NFSERR_IO
, errno_NFSERR_IO
},
603 { NFSERR_NXIO
, ENXIO
},
604 { NFSERR_EAGAIN
, EAGAIN
},
605 { NFSERR_ACCES
, EACCES
},
606 { NFSERR_EXIST
, EEXIST
},
607 { NFSERR_XDEV
, EXDEV
},
608 { NFSERR_NODEV
, ENODEV
},
609 { NFSERR_NOTDIR
, ENOTDIR
},
610 { NFSERR_ISDIR
, EISDIR
},
611 { NFSERR_INVAL
, EINVAL
},
612 { NFSERR_FBIG
, EFBIG
},
613 { NFSERR_NOSPC
, ENOSPC
},
614 { NFSERR_ROFS
, EROFS
},
615 { NFSERR_OPNOTSUPP
, EOPNOTSUPP
},
616 { NFSERR_NAMETOOLONG
, ENAMETOOLONG
},
617 { NFSERR_NOTEMPTY
, ENOTEMPTY
},
618 { NFSERR_DQUOT
, EDQUOT
},
619 { NFSERR_STALE
, ESTALE
},
621 { NFSERR_WFLUSH
, EWFLUSH
},
627 nfs_stat_to_errno(int stat
)
631 for (i
= 0; nfs_errtbl
[i
].stat
!= -1; i
++) {
632 if (nfs_errtbl
[i
].stat
== stat
)
633 return nfs_errtbl
[i
].errno
;
635 printk("nfs_stat_to_errno: bad nfs status return value: %d\n", stat
);
636 return nfs_errtbl
[i
].errno
;
640 # define MAX(a, b) (((a) > (b))? (a) : (b))
643 #define PROC(proc, argtype, restype) \
645 (kxdrproc_t) nfs_xdr_##argtype, \
646 (kxdrproc_t) nfs_xdr_##restype, \
647 MAX(NFS_##argtype##_sz,NFS_##restype##_sz) << 2 \
650 static struct rpc_procinfo nfs_procedures
[18] = {
651 PROC(null
, enc_void
, dec_void
),
652 PROC(getattr
, fhandle
, attrstat
),
653 PROC(setattr
, sattrargs
, attrstat
),
654 PROC(root
, enc_void
, dec_void
),
655 PROC(lookup
, diropargs
, diropres
),
656 PROC(readlink
, fhandle
, readlinkres
),
657 PROC(read
, readargs
, readres
),
658 PROC(writecache
, enc_void
, dec_void
),
659 PROC(write
, writeargs
, attrstat
),
660 PROC(create
, createargs
, diropres
),
661 PROC(remove
, diropargs
, stat
),
662 PROC(rename
, renameargs
, stat
),
663 PROC(link
, linkargs
, stat
),
664 PROC(symlink
, symlinkargs
, stat
),
665 PROC(mkdir
, createargs
, diropres
),
666 PROC(rmdir
, diropargs
, stat
),
667 PROC(readdir
, readdirargs
, readdirres
),
668 PROC(statfs
, fhandle
, statfsres
),
671 static struct rpc_version nfs_version2
= {
673 sizeof(nfs_procedures
)/sizeof(nfs_procedures
[0]),
677 static struct rpc_version
* nfs_version
[] = {
683 struct rpc_program nfs_program
= {
686 sizeof(nfs_version
) / sizeof(nfs_version
[0]),