elf2coff isn't a generic tool for all linux ports
[linux-2.6/linux-mips.git] / fs / nfs / nfs2xdr.c
blob5eec5eb65e0d9f76e8fd2027b0bd33748942cf1c
1 /*
2 * linux/fs/nfs/xdr.c
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
8 */
10 #define NFS_NEED_XDR_TYPES
12 #include <linux/param.h>
13 #include <linux/sched.h>
14 #include <linux/mm.h>
15 #include <linux/malloc.h>
16 #include <linux/utsname.h>
17 #include <linux/errno.h>
18 #include <linux/string.h>
19 #include <linux/in.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
42 #define NFS_info_sz 5
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
61 #define NFS_stat_sz 1
62 #define NFS_readdirres_sz 1
63 #define NFS_statfsres_sz 1+NFS_info_sz
66 * Common NFS XDR functions as inlines
68 static inline u32 *
69 xdr_encode_fhandle(u32 *p, struct nfs_fh *fhandle)
71 *((struct nfs_fh *) p) = *fhandle;
72 return p + QUADLEN(sizeof(*fhandle));
75 static inline u32 *
76 xdr_decode_fhandle(u32 *p, struct nfs_fh *fhandle)
78 *fhandle = *((struct nfs_fh *) p);
79 return p + QUADLEN(sizeof(*fhandle));
82 static inline u32 *
83 xdr_decode_string2(u32 *p, char **string, unsigned int *len,
84 unsigned int maxlen)
86 *len = ntohl(*p++);
87 if (*len > maxlen)
88 return NULL;
89 *string = (char *) p;
90 return p + QUADLEN(*len);
93 static inline u32 *
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++);
113 return p;
116 static inline u32 *
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);
127 return p;
131 * NFS encode functions
134 * Encode void argument
136 static int
137 nfs_xdr_enc_void(struct rpc_rqst *req, u32 *p, void *dummy)
139 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
140 return 0;
144 * Encode file handle argument
145 * GETATTR, READLINK, STATFS
147 static int
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);
152 return 0;
156 * Encode SETATTR arguments
158 static int
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);
164 return 0;
168 * Encode directory ops argument
169 * LOOKUP, REMOVE, RMDIR
171 static int
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);
177 return 0;
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.
185 static int
186 nfs_xdr_readargs(struct rpc_rqst *req, u32 *p, struct nfs_readargs *args)
188 struct rpc_auth *auth = req->rq_task->tk_auth;
189 int replen, buflen;
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);
197 #if 1
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;
207 req->rq_rnr = 3;
208 #else
209 replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS_readres_sz) << 2;
210 req->rq_rvec[0].iov_len = replen;
211 #endif
213 return 0;
217 * Decode READ reply
219 static int
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);
230 count = ntohl(*p++);
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;
240 if (count > recvd) {
241 printk("NFS: server cheating in read reply: "
242 "count %d > recvd %d\n", count, recvd);
243 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);
250 return count;
255 * Write arguments. Splice the buffer to be written into the iovec.
257 static int
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;
270 req->rq_snr = 2;
272 return 0;
276 * Encode create arguments
277 * CREATE, MKDIR
279 static int
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);
286 return 0;
290 * Encode RENAME arguments
292 static int
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);
300 return 0;
304 * Encode LINK arguments
306 static int
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);
313 return 0;
317 * Encode SYMLINK arguments
319 static int
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);
327 return 0;
331 * Encode arguments to readdir call
333 static int
334 nfs_xdr_readdirargs(struct rpc_rqst *req, u32 *p, struct nfs_readdirargs *args)
336 struct rpc_auth *auth = req->rq_task->tk_auth;
337 int replen;
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;
354 req->rq_rnr = 2;
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);
366 return 0;
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.
377 static int
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;
382 int status, nr, len;
383 char *string;
384 u32 *end;
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++);
404 len = ntohl(*p++);
405 if ((p + QUADLEN(len) + 3) > end) {
406 printk(KERN_NOTICE
407 "NFS: short packet in readdir reply!\n");
408 break;
410 if (len > NFS_MAXNAMLEN) {
411 printk("NFS: giant filename in readdir (len %x)!\n",
412 len);
413 return -errno_NFSERR_IO;
415 string -= len;
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
421 * up 2 longs.
423 * THIS IS BAD!
425 printk(KERN_NOTICE "NFS: should not happen in %s!\n",
426 __FUNCTION__);
427 break;
430 entry->name = string;
431 entry->length = len;
432 memmove(string, p, len);
433 p += QUADLEN(len);
434 entry->cookie = ntohl(*p++);
435 entry->eof = !p[0] && p[1];
437 return nr;
441 * NFS XDR decode functions
444 * Decode void reply
446 static int
447 nfs_xdr_dec_void(struct rpc_rqst *req, u32 *p, void *dummy)
449 return 0;
453 * Decode simple status reply
455 static int
456 nfs_xdr_stat(struct rpc_rqst *req, u32 *p, void *dummy)
458 int status;
460 if ((status = ntohl(*p++)) != 0)
461 status = -nfs_stat_to_errno(status);
462 return status;
466 * Decode attrstat reply
467 * GETATTR, SETATTR, WRITE
469 static int
470 nfs_xdr_attrstat(struct rpc_rqst *req, u32 *p, struct nfs_fattr *fattr)
472 int status;
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);
480 return 0;
484 * Decode diropres reply
485 * LOOKUP, CREATE, MKDIR
487 static int
488 nfs_xdr_diropres(struct rpc_rqst *req, u32 *p, struct nfs_diropok *res)
490 int status;
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);
500 return 0;
504 * Decode READLINK reply
506 static int
507 nfs_xdr_readlinkres(struct rpc_rqst *req, u32 *p, struct nfs_readlinkres *res)
509 int status;
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;
518 return 0;
522 * Decode STATFS reply
524 static int
525 nfs_xdr_statfsres(struct rpc_rqst *req, u32 *p, struct nfs_fsinfo *res)
527 int status;
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++);
536 return 0;
540 * We need to translate between nfs status return values and
541 * the local errno values which may not be the same.
543 static struct {
544 int stat;
545 int errno;
546 } nfs_errtbl[] = {
547 { NFS_OK, 0 },
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 },
566 #ifdef EWFLUSH
567 { NFSERR_WFLUSH, EWFLUSH },
568 #endif
569 { -1, EIO }
572 static int
573 nfs_stat_to_errno(int stat)
575 int i;
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;
585 #ifndef MAX
586 # define MAX(a, b) (((a) > (b))? (a) : (b))
587 #endif
589 #define PROC(proc, argtype, restype) \
590 { "nfs_" #proc, \
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]),
620 nfs_procedures
623 static struct rpc_version * nfs_version[] = {
624 NULL,
625 NULL,
626 &nfs_version2
629 struct rpc_program nfs_program = {
630 "nfs",
631 NFS_PROGRAM,
632 sizeof(nfs_version) / sizeof(nfs_version[0]),
633 nfs_version,
634 &nfs_rpcstat,