2 * linux/fs/nfs/nfs2xdr.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 * 04 Aug 1998 Ion Badulescu <ionut@cs.columbia.edu>
9 * FIFO's need special handling in NFSv2
12 #include <linux/param.h>
13 #include <linux/time.h>
15 #include <linux/slab.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.h>
24 #include <linux/nfs2.h>
25 #include <linux/nfs_fs.h>
27 #define NFSDBG_FACILITY NFSDBG_XDR
28 /* #define NFS_PARANOIA 1 */
30 extern 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 (8)
40 #define NFS_sattr_sz (8)
41 #define NFS_filename_sz (1+(NFS2_MAXNAMLEN>>2))
42 #define NFS_path_sz (1+(NFS2_MAXPATHLEN>>2))
43 #define NFS_fattr_sz (17)
44 #define NFS_info_sz (5)
45 #define NFS_entry_sz (NFS_filename_sz+3)
47 #define NFS_diropargs_sz (NFS_fhandle_sz+NFS_filename_sz)
48 #define NFS_sattrargs_sz (NFS_fhandle_sz+NFS_sattr_sz)
49 #define NFS_readlinkargs_sz (NFS_fhandle_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_attrstat_sz (1+NFS_fattr_sz)
59 #define NFS_diropres_sz (1+NFS_fhandle_sz+NFS_fattr_sz)
60 #define NFS_readlinkres_sz (1)
61 #define NFS_readres_sz (1+NFS_fattr_sz+1)
62 #define NFS_writeres_sz (NFS_attrstat_sz)
63 #define NFS_stat_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 nfs_fh *fhandle)
73 memcpy(p, fhandle->data, NFS2_FHSIZE);
74 return p + XDR_QUADLEN(NFS2_FHSIZE);
78 xdr_decode_fhandle(u32 *p, struct nfs_fh *fhandle)
80 /* Zero handle first to allow comparisons */
81 memset(fhandle, 0, sizeof(*fhandle));
82 /* NFSv2 handles have a fixed length */
83 fhandle->size = NFS2_FHSIZE;
84 memcpy(fhandle->data, p, NFS2_FHSIZE);
85 return p + XDR_QUADLEN(NFS2_FHSIZE);
89 xdr_encode_time(u32 *p, struct timespec *timep)
91 *p++ = htonl(timep->tv_sec);
92 /* Convert nanoseconds into microseconds */
93 *p++ = htonl(timep->tv_nsec ? timep->tv_nsec / 1000 : 0);
98 xdr_decode_time(u32 *p, struct timespec *timep)
100 timep->tv_sec = ntohl(*p++);
101 /* Convert microseconds into nanoseconds */
102 timep->tv_nsec = ntohl(*p++) * 1000;
107 xdr_decode_fattr(u32 *p, struct nfs_fattr *fattr)
110 fattr->type = (enum nfs_ftype) ntohl(*p++);
111 fattr->mode = ntohl(*p++);
112 fattr->nlink = ntohl(*p++);
113 fattr->uid = ntohl(*p++);
114 fattr->gid = ntohl(*p++);
115 fattr->size = ntohl(*p++);
116 fattr->du.nfs2.blocksize = ntohl(*p++);
118 fattr->du.nfs2.blocks = ntohl(*p++);
119 fattr->fsid_u.nfs3 = ntohl(*p++);
120 fattr->fileid = ntohl(*p++);
121 p = xdr_decode_time(p, &fattr->atime);
122 p = xdr_decode_time(p, &fattr->mtime);
123 p = xdr_decode_time(p, &fattr->ctime);
124 fattr->valid |= NFS_ATTR_FATTR;
125 fattr->rdev = new_decode_dev(rdev);
126 if (fattr->type == NFCHR && rdev == NFS2_FIFO_DEV) {
127 fattr->type = NFFIFO;
128 fattr->mode = (fattr->mode & ~S_IFMT) | S_IFIFO;
131 fattr->timestamp = jiffies;
135 #define SATTR(p, attr, flag, field) \
136 *p++ = (attr->ia_valid & flag) ? htonl(attr->field) : ~(u32) 0
138 xdr_encode_sattr(u32 *p, struct iattr *attr)
140 SATTR(p, attr, ATTR_MODE, ia_mode);
141 SATTR(p, attr, ATTR_UID, ia_uid);
142 SATTR(p, attr, ATTR_GID, ia_gid);
143 SATTR(p, attr, ATTR_SIZE, ia_size);
145 if (attr->ia_valid & (ATTR_ATIME|ATTR_ATIME_SET)) {
146 p = xdr_encode_time(p, &attr->ia_atime);
152 if (attr->ia_valid & (ATTR_MTIME|ATTR_MTIME_SET)) {
153 p = xdr_encode_time(p, &attr->ia_mtime);
163 * NFS encode functions
166 * Encode file handle argument
167 * GETATTR, READLINK, STATFS
170 nfs_xdr_fhandle(struct rpc_rqst *req, u32 *p, struct nfs_fh *fh)
172 p = xdr_encode_fhandle(p, fh);
173 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
178 * Encode SETATTR arguments
181 nfs_xdr_sattrargs(struct rpc_rqst *req, u32 *p, struct nfs_sattrargs *args)
183 p = xdr_encode_fhandle(p, args->fh);
184 p = xdr_encode_sattr(p, args->sattr);
185 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
190 * Encode directory ops argument
191 * LOOKUP, REMOVE, RMDIR
194 nfs_xdr_diropargs(struct rpc_rqst *req, u32 *p, struct nfs_diropargs *args)
196 p = xdr_encode_fhandle(p, args->fh);
197 p = xdr_encode_array(p, args->name, args->len);
198 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
203 * Arguments to a READ call. Since we read data directly into the page
204 * cache, we also set up the reply iovec here so that iov[1] points
205 * exactly to the page we want to fetch.
208 nfs_xdr_readargs(struct rpc_rqst *req, u32 *p, struct nfs_readargs *args)
210 struct rpc_auth *auth = req->rq_task->tk_auth;
212 u32 offset = (u32)args->offset;
213 u32 count = args->count;
215 p = xdr_encode_fhandle(p, args->fh);
216 *p++ = htonl(offset);
219 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
221 /* Inline the page array */
222 replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS_readres_sz) << 2;
223 xdr_inline_pages(&req->rq_rcv_buf, replen,
224 args->pages, args->pgbase, count);
232 nfs_xdr_readres(struct rpc_rqst *req, u32 *p, struct nfs_readres *res)
234 struct iovec *iov = req->rq_rcv_buf.head;
235 int status, count, recvd, hdrlen;
237 if ((status = ntohl(*p++)))
238 return -nfs_stat_to_errno(status);
239 p = xdr_decode_fattr(p, res->fattr);
243 hdrlen = (u8 *) p - (u8 *) iov->iov_base;
244 if (iov->iov_len < hdrlen) {
245 printk(KERN_WARNING "NFS: READ reply header overflowed:"
246 "length %d > %Zu\n", hdrlen, iov->iov_len);
247 return -errno_NFSERR_IO;
248 } else if (iov->iov_len != hdrlen) {
249 dprintk("NFS: READ header is short. iovec will be shifted.\n");
250 xdr_shift_buf(&req->rq_rcv_buf, iov->iov_len - hdrlen);
253 recvd = req->rq_rcv_buf.len - hdrlen;
255 printk(KERN_WARNING "NFS: server cheating in read reply: "
256 "count %d > recvd %d\n", count, recvd);
260 dprintk("RPC: readres OK count %d\n", count);
261 if (count < res->count)
269 * Write arguments. Splice the buffer to be written into the iovec.
272 nfs_xdr_writeargs(struct rpc_rqst *req, u32 *p, struct nfs_writeargs *args)
274 struct xdr_buf *sndbuf = &req->rq_snd_buf;
275 u32 offset = (u32)args->offset;
276 u32 count = args->count;
278 p = xdr_encode_fhandle(p, args->fh);
279 *p++ = htonl(offset);
280 *p++ = htonl(offset);
283 sndbuf->len = xdr_adjust_iovec(sndbuf->head, p);
285 /* Copy the page array */
286 xdr_encode_pages(sndbuf, args->pages, args->pgbase, count);
291 * Encode create arguments
295 nfs_xdr_createargs(struct rpc_rqst *req, u32 *p, struct nfs_createargs *args)
297 p = xdr_encode_fhandle(p, args->fh);
298 p = xdr_encode_array(p, args->name, args->len);
299 p = xdr_encode_sattr(p, args->sattr);
300 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
305 * Encode RENAME arguments
308 nfs_xdr_renameargs(struct rpc_rqst *req, u32 *p, struct nfs_renameargs *args)
310 p = xdr_encode_fhandle(p, args->fromfh);
311 p = xdr_encode_array(p, args->fromname, args->fromlen);
312 p = xdr_encode_fhandle(p, args->tofh);
313 p = xdr_encode_array(p, args->toname, args->tolen);
314 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
319 * Encode LINK arguments
322 nfs_xdr_linkargs(struct rpc_rqst *req, u32 *p, struct nfs_linkargs *args)
324 p = xdr_encode_fhandle(p, args->fromfh);
325 p = xdr_encode_fhandle(p, args->tofh);
326 p = xdr_encode_array(p, args->toname, args->tolen);
327 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
332 * Encode SYMLINK arguments
335 nfs_xdr_symlinkargs(struct rpc_rqst *req, u32 *p, struct nfs_symlinkargs *args)
337 p = xdr_encode_fhandle(p, args->fromfh);
338 p = xdr_encode_array(p, args->fromname, args->fromlen);
339 p = xdr_encode_array(p, args->topath, args->tolen);
340 p = xdr_encode_sattr(p, args->sattr);
341 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
346 * Encode arguments to readdir call
349 nfs_xdr_readdirargs(struct rpc_rqst *req, u32 *p, struct nfs_readdirargs *args)
351 struct rpc_task *task = req->rq_task;
352 struct rpc_auth *auth = task->tk_auth;
354 u32 count = args->count;
356 p = xdr_encode_fhandle(p, args->fh);
357 *p++ = htonl(args->cookie);
358 *p++ = htonl(count); /* see above */
359 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
361 /* Inline the page array */
362 replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS_readdirres_sz) << 2;
363 xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, 0, count);
368 * Decode the result of a readdir call.
369 * We're not really decoding anymore, we just leave the buffer untouched
370 * and only check that it is syntactically correct.
371 * The real decoding happens in nfs_decode_entry below, called directly
372 * from nfs_readdir for each entry.
375 nfs_xdr_readdirres(struct rpc_rqst *req, u32 *p, void *dummy)
377 struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
378 struct iovec *iov = rcvbuf->head;
382 unsigned int len, pglen;
383 u32 *end, *entry, *kaddr;
385 if ((status = ntohl(*p++)))
386 return -nfs_stat_to_errno(status);
388 hdrlen = (u8 *) p - (u8 *) iov->iov_base;
389 if (iov->iov_len < hdrlen) {
390 printk(KERN_WARNING "NFS: READDIR reply header overflowed:"
391 "length %d > %Zu\n", hdrlen, iov->iov_len);
392 return -errno_NFSERR_IO;
393 } else if (iov->iov_len != hdrlen) {
394 dprintk("NFS: READDIR header is short. iovec will be shifted.\n");
395 xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen);
398 pglen = rcvbuf->page_len;
399 recvd = rcvbuf->len - hdrlen;
402 page = rcvbuf->pages;
403 kaddr = p = (u32 *)kmap_atomic(*page, KM_USER0);
404 end = (u32 *)((char *)p + pglen);
406 for (nr = 0; *p++; nr++) {
411 p += XDR_QUADLEN(len) + 1; /* name plus cookie */
412 if (len > NFS2_MAXNAMLEN) {
413 printk(KERN_WARNING "NFS: giant filename in readdir (len 0x%x)!\n",
421 if (!nr && (entry[0] != 0 || entry[1] == 0))
424 kunmap_atomic(kaddr, KM_USER0);
427 entry[0] = entry[1] = 0;
428 /* truncate listing ? */
430 printk(KERN_NOTICE "NFS: readdir reply truncated!\n");
435 nr = -errno_NFSERR_IO;
440 nfs_decode_dirent(u32 *p, struct nfs_entry *entry, int plus)
444 return ERR_PTR(-EAGAIN);
446 return ERR_PTR(-EBADCOOKIE);
449 entry->ino = ntohl(*p++);
450 entry->len = ntohl(*p++);
451 entry->name = (const char *) p;
452 p += XDR_QUADLEN(entry->len);
453 entry->prev_cookie = entry->cookie;
454 entry->cookie = ntohl(*p++);
455 entry->eof = !p[0] && p[1];
461 * NFS XDR decode functions
464 * Decode simple status reply
467 nfs_xdr_stat(struct rpc_rqst *req, u32 *p, void *dummy)
471 if ((status = ntohl(*p++)) != 0)
472 status = -nfs_stat_to_errno(status);
477 * Decode attrstat reply
478 * GETATTR, SETATTR, WRITE
481 nfs_xdr_attrstat(struct rpc_rqst *req, u32 *p, struct nfs_fattr *fattr)
485 if ((status = ntohl(*p++)))
486 return -nfs_stat_to_errno(status);
487 xdr_decode_fattr(p, fattr);
492 * Decode diropres reply
493 * LOOKUP, CREATE, MKDIR
496 nfs_xdr_diropres(struct rpc_rqst *req, u32 *p, struct nfs_diropok *res)
500 if ((status = ntohl(*p++)))
501 return -nfs_stat_to_errno(status);
502 p = xdr_decode_fhandle(p, res->fh);
503 xdr_decode_fattr(p, res->fattr);
508 * Encode READLINK args
511 nfs_xdr_readlinkargs(struct rpc_rqst *req, u32 *p, struct nfs_readlinkargs *args)
513 struct rpc_auth *auth = req->rq_task->tk_auth;
515 u32 count = args->count - 4;
517 p = xdr_encode_fhandle(p, args->fh);
518 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
520 /* Inline the page array */
521 replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS_readlinkres_sz) << 2;
522 xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, 0, count);
527 * Decode READLINK reply
530 nfs_xdr_readlinkres(struct rpc_rqst *req, u32 *p, void *dummy)
532 struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
533 struct iovec *iov = rcvbuf->head;
539 if ((status = ntohl(*p++)))
540 return -nfs_stat_to_errno(status);
541 hdrlen = (u8 *) p - (u8 *) iov->iov_base;
542 if (iov->iov_len > hdrlen) {
543 dprintk("NFS: READLINK header is short. iovec will be shifted.\n");
544 xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen);
547 strlen = (u32*)kmap_atomic(rcvbuf->pages[0], KM_USER0);
548 /* Convert length of symlink */
549 len = ntohl(*strlen);
550 if (len > rcvbuf->page_len)
551 len = rcvbuf->page_len;
553 /* NULL terminate the string we got */
554 string = (char *)(strlen + 1);
556 kunmap_atomic(strlen, KM_USER0);
564 nfs_xdr_writeres(struct rpc_rqst *req, u32 *p, struct nfs_writeres *res)
566 res->verf->committed = NFS_FILE_SYNC;
567 return nfs_xdr_attrstat(req, p, res->fattr);
571 * Decode STATFS reply
574 nfs_xdr_statfsres(struct rpc_rqst *req, u32 *p, struct nfs2_fsstat *res)
578 if ((status = ntohl(*p++)))
579 return -nfs_stat_to_errno(status);
581 res->tsize = ntohl(*p++);
582 res->bsize = ntohl(*p++);
583 res->blocks = ntohl(*p++);
584 res->bfree = ntohl(*p++);
585 res->bavail = ntohl(*p++);
590 * We need to translate between nfs status return values and
591 * the local errno values which may not be the same.
598 { NFSERR_PERM, EPERM },
599 { NFSERR_NOENT, ENOENT },
600 { NFSERR_IO, errno_NFSERR_IO },
601 { NFSERR_NXIO, ENXIO },
602 /* { NFSERR_EAGAIN, EAGAIN }, */
603 { NFSERR_ACCES, EACCES },
604 { NFSERR_EXIST, EEXIST },
605 { NFSERR_XDEV, EXDEV },
606 { NFSERR_NODEV, ENODEV },
607 { NFSERR_NOTDIR, ENOTDIR },
608 { NFSERR_ISDIR, EISDIR },
609 { NFSERR_INVAL, EINVAL },
610 { NFSERR_FBIG, EFBIG },
611 { NFSERR_NOSPC, ENOSPC },
612 { NFSERR_ROFS, EROFS },
613 { NFSERR_MLINK, EMLINK },
614 { NFSERR_NAMETOOLONG, ENAMETOOLONG },
615 { NFSERR_NOTEMPTY, ENOTEMPTY },
616 { NFSERR_DQUOT, EDQUOT },
617 { NFSERR_STALE, ESTALE },
618 { NFSERR_REMOTE, EREMOTE },
620 { NFSERR_WFLUSH, EWFLUSH },
622 { NFSERR_BADHANDLE, EBADHANDLE },
623 { NFSERR_NOT_SYNC, ENOTSYNC },
624 { NFSERR_BAD_COOKIE, EBADCOOKIE },
625 { NFSERR_NOTSUPP, ENOTSUPP },
626 { NFSERR_TOOSMALL, ETOOSMALL },
627 { NFSERR_SERVERFAULT, ESERVERFAULT },
628 { NFSERR_BADTYPE, EBADTYPE },
629 { NFSERR_JUKEBOX, EJUKEBOX },
634 * Convert an NFS error code to a local one.
635 * This one is used jointly by NFSv2 and NFSv3.
638 nfs_stat_to_errno(int stat)
642 for (i = 0; nfs_errtbl[i].stat != -1; i++) {
643 if (nfs_errtbl[i].stat == stat)
644 return nfs_errtbl[i].errno;
646 printk(KERN_ERR "nfs_stat_to_errno: bad nfs status return value: %d\n", stat);
647 return nfs_errtbl[i].errno;
651 # define MAX(a, b) (((a) > (b))? (a) : (b))
654 #define PROC(proc, argtype, restype, timer) \
655 [NFSPROC_##proc] = { \
656 .p_proc = NFSPROC_##proc, \
657 .p_encode = (kxdrproc_t) nfs_xdr_##argtype, \
658 .p_decode = (kxdrproc_t) nfs_xdr_##restype, \
659 .p_bufsiz = MAX(NFS_##argtype##_sz,NFS_##restype##_sz) << 2, \
662 struct rpc_procinfo nfs_procedures[] = {
663 PROC(GETATTR, fhandle, attrstat, 1),
664 PROC(SETATTR, sattrargs, attrstat, 0),
665 PROC(LOOKUP, diropargs, diropres, 2),
666 PROC(READLINK, readlinkargs, readlinkres, 3),
667 PROC(READ, readargs, readres, 3),
668 PROC(WRITE, writeargs, writeres, 4),
669 PROC(CREATE, createargs, diropres, 0),
670 PROC(REMOVE, diropargs, stat, 0),
671 PROC(RENAME, renameargs, stat, 0),
672 PROC(LINK, linkargs, stat, 0),
673 PROC(SYMLINK, symlinkargs, stat, 0),
674 PROC(MKDIR, createargs, diropres, 0),
675 PROC(RMDIR, diropargs, stat, 0),
676 PROC(READDIR, readdirargs, readdirres, 3),
677 PROC(STATFS, fhandle, statfsres, 0),
680 struct rpc_version nfs_version2 = {
682 .nrprocs = sizeof(nfs_procedures)/sizeof(nfs_procedures[0]),
683 .procs = nfs_procedures