1 /* 2 * linux/fs/nfs/nfs2xdr.c 3 * 4 * XDR functions to encode/decode NFS RPC arguments and results. 5 * 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 10 */ 11 12 #include <linux/param.h> 13 #include <linux/time.h> 14 #include <linux/mm.h> 15 #include <linux/slab.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.h> 24 #include <linux/nfs2.h> 25 #include <linux/nfs_fs.h> 26 27 #define NFSDBG_FACILITY NFSDBG_XDR 28 /* #define NFS_PARANOIA 1 */ 29 30 extern int nfs_stat_to_errno(int stat); 31 32 /* Mapping from NFS error code to "errno" error code. */ 33 #define errno_NFSERR_IO EIO 34 35 /* 36 * Declare the space requirements for NFS arguments and replies as 37 * number of 32bit-words 38 */ 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) 46 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) 57 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 (2) 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) 66 67 /* 68 * Common NFS XDR functions as inlines 69 */ 70 static inline u32 * 71 xdr_encode_fhandle(u32 *p, struct nfs_fh *fhandle) 72 { 73 memcpy(p, fhandle->data, NFS2_FHSIZE); 74 return p + XDR_QUADLEN(NFS2_FHSIZE); 75 } 76 77 static inline u32 * 78 xdr_decode_fhandle(u32 *p, struct nfs_fh *fhandle) 79 { 80 /* NFSv2 handles have a fixed length */ 81 fhandle->size = NFS2_FHSIZE; 82 memcpy(fhandle->data, p, NFS2_FHSIZE); 83 return p + XDR_QUADLEN(NFS2_FHSIZE); 84 } 85 86 static inline u32* 87 xdr_encode_time(u32 *p, struct timespec *timep) 88 { 89 *p++ = htonl(timep->tv_sec); 90 /* Convert nanoseconds into microseconds */ 91 *p++ = htonl(timep->tv_nsec ? timep->tv_nsec / 1000 : 0); 92 return p; 93 } 94 95 static inline u32* 96 xdr_encode_current_server_time(u32 *p, struct timespec *timep) 97 { 98 /* 99 * Passing the invalid value useconds=1000000 is a 100 * Sun convention for "set to current server time". 101 * It's needed to make permissions checks for the 102 * "touch" program across v2 mounts to Solaris and 103 * Irix boxes work correctly. See description of 104 * sattr in section 6.1 of "NFS Illustrated" by 105 * Brent Callaghan, Addison-Wesley, ISBN 0-201-32750-5 106 */ 107 *p++ = htonl(timep->tv_sec); 108 *p++ = htonl(1000000); 109 return p; 110 } 111 112 static inline u32* 113 xdr_decode_time(u32 *p, struct timespec *timep) 114 { 115 timep->tv_sec = ntohl(*p++); 116 /* Convert microseconds into nanoseconds */ 117 timep->tv_nsec = ntohl(*p++) * 1000; 118 return p; 119 } 120 121 static u32 * 122 xdr_decode_fattr(u32 *p, struct nfs_fattr *fattr) 123 { 124 u32 rdev; 125 fattr->type = (enum nfs_ftype) ntohl(*p++); 126 fattr->mode = ntohl(*p++); 127 fattr->nlink = ntohl(*p++); 128 fattr->uid = ntohl(*p++); 129 fattr->gid = ntohl(*p++); 130 fattr->size = ntohl(*p++); 131 fattr->du.nfs2.blocksize = ntohl(*p++); 132 rdev = ntohl(*p++); 133 fattr->du.nfs2.blocks = ntohl(*p++); 134 fattr->fsid_u.nfs3 = ntohl(*p++); 135 fattr->fileid = ntohl(*p++); 136 p = xdr_decode_time(p, &fattr->atime); 137 p = xdr_decode_time(p, &fattr->mtime); 138 p = xdr_decode_time(p, &fattr->ctime); 139 fattr->valid |= NFS_ATTR_FATTR; 140 fattr->rdev = new_decode_dev(rdev); 141 if (fattr->type == NFCHR && rdev == NFS2_FIFO_DEV) { 142 fattr->type = NFFIFO; 143 fattr->mode = (fattr->mode & ~S_IFMT) | S_IFIFO; 144 fattr->rdev = 0; 145 } 146 return p; 147 } 148 149 #define SATTR(p, attr, flag, field) \ 150 *p++ = (attr->ia_valid & flag) ? htonl(attr->field) : ~(u32) 0 151 static inline u32 * 152 xdr_encode_sattr(u32 *p, struct iattr *attr) 153 { 154 SATTR(p, attr, ATTR_MODE, ia_mode); 155 SATTR(p, attr, ATTR_UID, ia_uid); 156 SATTR(p, attr, ATTR_GID, ia_gid); 157 SATTR(p, attr, ATTR_SIZE, ia_size); 158 159 if (attr->ia_valid & ATTR_ATIME_SET) { 160 p = xdr_encode_time(p, &attr->ia_atime); 161 } else if (attr->ia_valid & ATTR_ATIME) { 162 p = xdr_encode_current_server_time(p, &attr->ia_atime); 163 } else { 164 *p++ = ~(u32) 0; 165 *p++ = ~(u32) 0; 166 } 167 168 if (attr->ia_valid & ATTR_MTIME_SET) { 169 p = xdr_encode_time(p, &attr->ia_mtime); 170 } else if (attr->ia_valid & ATTR_MTIME) { 171 p = xdr_encode_current_server_time(p, &attr->ia_mtime); 172 } else { 173 *p++ = ~(u32) 0; 174 *p++ = ~(u32) 0; 175 } 176 return p; 177 } 178 #undef SATTR 179 180 /* 181 * NFS encode functions 182 */ 183 /* 184 * Encode file handle argument 185 * GETATTR, READLINK, STATFS 186 */ 187 static int 188 nfs_xdr_fhandle(struct rpc_rqst *req, u32 *p, struct nfs_fh *fh) 189 { 190 p = xdr_encode_fhandle(p, fh); 191 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); 192 return 0; 193 } 194 195 /* 196 * Encode SETATTR arguments 197 */ 198 static int 199 nfs_xdr_sattrargs(struct rpc_rqst *req, u32 *p, struct nfs_sattrargs *args) 200 { 201 p = xdr_encode_fhandle(p, args->fh); 202 p = xdr_encode_sattr(p, args->sattr); 203 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); 204 return 0; 205 } 206 207 /* 208 * Encode directory ops argument 209 * LOOKUP, REMOVE, RMDIR 210 */ 211 static int 212 nfs_xdr_diropargs(struct rpc_rqst *req, u32 *p, struct nfs_diropargs *args) 213 { 214 p = xdr_encode_fhandle(p, args->fh); 215 p = xdr_encode_array(p, args->name, args->len); 216 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); 217 return 0; 218 } 219 220 /* 221 * Arguments to a READ call. Since we read data directly into the page 222 * cache, we also set up the reply iovec here so that iov[1] points 223 * exactly to the page we want to fetch. 224 */ 225 static int 226 nfs_xdr_readargs(struct rpc_rqst *req, u32 *p, struct nfs_readargs *args) 227 { 228 struct rpc_auth *auth = req->rq_task->tk_auth; 229 unsigned int replen; 230 u32 offset = (u32)args->offset; 231 u32 count = args->count; 232 233 p = xdr_encode_fhandle(p, args->fh); 234 *p++ = htonl(offset); 235 *p++ = htonl(count); 236 *p++ = htonl(count); 237 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); 238 239 /* Inline the page array */ 240 replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS_readres_sz) << 2; 241 xdr_inline_pages(&req->rq_rcv_buf, replen, 242 args->pages, args->pgbase, count); 243 return 0; 244 } 245 246 /* 247 * Decode READ reply 248 */ 249 static int 250 nfs_xdr_readres(struct rpc_rqst *req, u32 *p, struct nfs_readres *res) 251 { 252 struct kvec *iov = req->rq_rcv_buf.head; 253 int status, count, recvd, hdrlen; 254 255 if ((status = ntohl(*p++))) 256 return -nfs_stat_to_errno(status); 257 p = xdr_decode_fattr(p, res->fattr); 258 259 count = ntohl(*p++); 260 res->eof = 0; 261 hdrlen = (u8 *) p - (u8 *) iov->iov_base; 262 if (iov->iov_len < hdrlen) { 263 printk(KERN_WARNING "NFS: READ reply header overflowed:" 264 "length %d > %Zu\n", hdrlen, iov->iov_len); 265 return -errno_NFSERR_IO; 266 } else if (iov->iov_len != hdrlen) { 267 dprintk("NFS: READ header is short. iovec will be shifted.\n"); 268 xdr_shift_buf(&req->rq_rcv_buf, iov->iov_len - hdrlen); 269 } 270 271 recvd = req->rq_rcv_buf.len - hdrlen; 272 if (count > recvd) { 273 printk(KERN_WARNING "NFS: server cheating in read reply: " 274 "count %d > recvd %d\n", count, recvd); 275 count = recvd; 276 } 277 278 dprintk("RPC: readres OK count %d\n", count); 279 if (count < res->count) 280 res->count = count; 281 282 return count; 283 } 284 285 286 /* 287 * Write arguments. Splice the buffer to be written into the iovec. 288 */ 289 static int 290 nfs_xdr_writeargs(struct rpc_rqst *req, u32 *p, struct nfs_writeargs *args) 291 { 292 struct xdr_buf *sndbuf = &req->rq_snd_buf; 293 u32 offset = (u32)args->offset; 294 u32 count = args->count; 295 296 p = xdr_encode_fhandle(p, args->fh); 297 *p++ = htonl(offset); 298 *p++ = htonl(offset); 299 *p++ = htonl(count); 300 *p++ = htonl(count); 301 sndbuf->len = xdr_adjust_iovec(sndbuf->head, p); 302 303 /* Copy the page array */ 304 xdr_encode_pages(sndbuf, args->pages, args->pgbase, count); 305 return 0; 306 } 307 308 /* 309 * Encode create arguments 310 * CREATE, MKDIR 311 */ 312 static int 313 nfs_xdr_createargs(struct rpc_rqst *req, u32 *p, struct nfs_createargs *args) 314 { 315 p = xdr_encode_fhandle(p, args->fh); 316 p = xdr_encode_array(p, args->name, args->len); 317 p = xdr_encode_sattr(p, args->sattr); 318 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); 319 return 0; 320 } 321 322 /* 323 * Encode RENAME arguments 324 */ 325 static int 326 nfs_xdr_renameargs(struct rpc_rqst *req, u32 *p, struct nfs_renameargs *args) 327 { 328 p = xdr_encode_fhandle(p, args->fromfh); 329 p = xdr_encode_array(p, args->fromname, args->fromlen); 330 p = xdr_encode_fhandle(p, args->tofh); 331 p = xdr_encode_array(p, args->toname, args->tolen); 332 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); 333 return 0; 334 } 335 336 /* 337 * Encode LINK arguments 338 */ 339 static int 340 nfs_xdr_linkargs(struct rpc_rqst *req, u32 *p, struct nfs_linkargs *args) 341 { 342 p = xdr_encode_fhandle(p, args->fromfh); 343 p = xdr_encode_fhandle(p, args->tofh); 344 p = xdr_encode_array(p, args->toname, args->tolen); 345 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); 346 return 0; 347 } 348 349 /* 350 * Encode SYMLINK arguments 351 */ 352 static int 353 nfs_xdr_symlinkargs(struct rpc_rqst *req, u32 *p, struct nfs_symlinkargs *args) 354 { 355 p = xdr_encode_fhandle(p, args->fromfh); 356 p = xdr_encode_array(p, args->fromname, args->fromlen); 357 p = xdr_encode_array(p, args->topath, args->tolen); 358 p = xdr_encode_sattr(p, args->sattr); 359 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); 360 return 0; 361 } 362 363 /* 364 * Encode arguments to readdir call 365 */ 366 static int 367 nfs_xdr_readdirargs(struct rpc_rqst *req, u32 *p, struct nfs_readdirargs *args) 368 { 369 struct rpc_task *task = req->rq_task; 370 struct rpc_auth *auth = task->tk_auth; 371 unsigned int replen; 372 u32 count = args->count; 373 374 p = xdr_encode_fhandle(p, args->fh); 375 *p++ = htonl(args->cookie); 376 *p++ = htonl(count); /* see above */ 377 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); 378 379 /* Inline the page array */ 380 replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS_readdirres_sz) << 2; 381 xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, 0, count); 382 return 0; 383 } 384 385 /* 386 * Decode the result of a readdir call. 387 * We're not really decoding anymore, we just leave the buffer untouched 388 * and only check that it is syntactically correct. 389 * The real decoding happens in nfs_decode_entry below, called directly 390 * from nfs_readdir for each entry. 391 */ 392 static int 393 nfs_xdr_readdirres(struct rpc_rqst *req, u32 *p, void *dummy) 394 { 395 struct xdr_buf *rcvbuf = &req->rq_rcv_buf; 396 struct kvec *iov = rcvbuf->head; 397 struct page **page; 398 int hdrlen, recvd; 399 int status, nr; 400 unsigned int len, pglen; 401 u32 *end, *entry, *kaddr; 402 403 if ((status = ntohl(*p++))) 404 return -nfs_stat_to_errno(status); 405 406 hdrlen = (u8 *) p - (u8 *) iov->iov_base; 407 if (iov->iov_len < hdrlen) { 408 printk(KERN_WARNING "NFS: READDIR reply header overflowed:" 409 "length %d > %Zu\n", hdrlen, iov->iov_len); 410 return -errno_NFSERR_IO; 411 } else if (iov->iov_len != hdrlen) { 412 dprintk("NFS: READDIR header is short. iovec will be shifted.\n"); 413 xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen); 414 } 415 416 pglen = rcvbuf->page_len; 417 recvd = rcvbuf->len - hdrlen; 418 if (pglen > recvd) 419 pglen = recvd; 420 page = rcvbuf->pages; 421 kaddr = p = (u32 *)kmap_atomic(*page, KM_USER0); 422 end = (u32 *)((char *)p + pglen); 423 entry = p; 424 for (nr = 0; *p++; nr++) { 425 if (p + 2 > end) 426 goto short_pkt; 427 p++; /* fileid */ 428 len = ntohl(*p++); 429 p += XDR_QUADLEN(len) + 1; /* name plus cookie */ 430 if (len > NFS2_MAXNAMLEN) { 431 printk(KERN_WARNING "NFS: giant filename in readdir (len 0x%x)!\n", 432 len); 433 goto err_unmap; 434 } 435 if (p + 2 > end) 436 goto short_pkt; 437 entry = p; 438 } 439 if (!nr && (entry[0] != 0 || entry[1] == 0)) 440 goto short_pkt; 441 out: 442 kunmap_atomic(kaddr, KM_USER0); 443 return nr; 444 short_pkt: 445 entry[0] = entry[1] = 0; 446 /* truncate listing ? */ 447 if (!nr) { 448 printk(KERN_NOTICE "NFS: readdir reply truncated!\n"); 449 entry[1] = 1; 450 } 451 goto out; 452 err_unmap: 453 nr = -errno_NFSERR_IO; 454 goto out; 455 } 456 457 u32 * 458 nfs_decode_dirent(u32 *p, struct nfs_entry *entry, int plus) 459 { 460 if (!*p++) { 461 if (!*p) 462 return ERR_PTR(-EAGAIN); 463 entry->eof = 1; 464 return ERR_PTR(-EBADCOOKIE); 465 } 466 467 entry->ino = ntohl(*p++); 468 entry->len = ntohl(*p++); 469 entry->name = (const char *) p; 470 p += XDR_QUADLEN(entry->len); 471 entry->prev_cookie = entry->cookie; 472 entry->cookie = ntohl(*p++); 473 entry->eof = !p[0] && p[1]; 474 475 return p; 476 } 477 478 /* 479 * NFS XDR decode functions 480 */ 481 /* 482 * Decode simple status reply 483 */ 484 static int 485 nfs_xdr_stat(struct rpc_rqst *req, u32 *p, void *dummy) 486 { 487 int status; 488 489 if ((status = ntohl(*p++)) != 0) 490 status = -nfs_stat_to_errno(status); 491 return status; 492 } 493 494 /* 495 * Decode attrstat reply 496 * GETATTR, SETATTR, WRITE 497 */ 498 static int 499 nfs_xdr_attrstat(struct rpc_rqst *req, u32 *p, struct nfs_fattr *fattr) 500 { 501 int status; 502 503 if ((status = ntohl(*p++))) 504 return -nfs_stat_to_errno(status); 505 xdr_decode_fattr(p, fattr); 506 return 0; 507 } 508 509 /* 510 * Decode diropres reply 511 * LOOKUP, CREATE, MKDIR 512 */ 513 static int 514 nfs_xdr_diropres(struct rpc_rqst *req, u32 *p, struct nfs_diropok *res) 515 { 516 int status; 517 518 if ((status = ntohl(*p++))) 519 return -nfs_stat_to_errno(status); 520 p = xdr_decode_fhandle(p, res->fh); 521 xdr_decode_fattr(p, res->fattr); 522 return 0; 523 } 524 525 /* 526 * Encode READLINK args 527 */ 528 static int 529 nfs_xdr_readlinkargs(struct rpc_rqst *req, u32 *p, struct nfs_readlinkargs *args) 530 { 531 struct rpc_auth *auth = req->rq_task->tk_auth; 532 unsigned int replen; 533 534 p = xdr_encode_fhandle(p, args->fh); 535 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); 536 537 /* Inline the page array */ 538 replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS_readlinkres_sz) << 2; 539 xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, args->pgbase, args->pglen); 540 return 0; 541 } 542 543 /* 544 * Decode READLINK reply 545 */ 546 static int 547 nfs_xdr_readlinkres(struct rpc_rqst *req, u32 *p, void *dummy) 548 { 549 struct xdr_buf *rcvbuf = &req->rq_rcv_buf; 550 struct kvec *iov = rcvbuf->head; 551 int hdrlen, len, recvd; 552 char *kaddr; 553 int status; 554 555 if ((status = ntohl(*p++))) 556 return -nfs_stat_to_errno(status); 557 /* Convert length of symlink */ 558 len = ntohl(*p++); 559 if (len >= rcvbuf->page_len || len <= 0) { 560 dprintk(KERN_WARNING "nfs: server returned giant symlink!\n"); 561 return -ENAMETOOLONG; 562 } 563 hdrlen = (u8 *) p - (u8 *) iov->iov_base; 564 if (iov->iov_len < hdrlen) { 565 printk(KERN_WARNING "NFS: READLINK reply header overflowed:" 566 "length %d > %Zu\n", hdrlen, iov->iov_len); 567 return -errno_NFSERR_IO; 568 } else if (iov->iov_len != hdrlen) { 569 dprintk("NFS: READLINK header is short. iovec will be shifted.\n"); 570 xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen); 571 } 572 recvd = req->rq_rcv_buf.len - hdrlen; 573 if (recvd < len) { 574 printk(KERN_WARNING "NFS: server cheating in readlink reply: " 575 "count %u > recvd %u\n", len, recvd); 576 return -EIO; 577 } 578 579 /* NULL terminate the string we got */ 580 kaddr = (char *)kmap_atomic(rcvbuf->pages[0], KM_USER0); 581 kaddr[len+rcvbuf->page_base] = '\0'; 582 kunmap_atomic(kaddr, KM_USER0); 583 return 0; 584 } 585 586 /* 587 * Decode WRITE reply 588 */ 589 static int 590 nfs_xdr_writeres(struct rpc_rqst *req, u32 *p, struct nfs_writeres *res) 591 { 592 res->verf->committed = NFS_FILE_SYNC; 593 return nfs_xdr_attrstat(req, p, res->fattr); 594 } 595 596 /* 597 * Decode STATFS reply 598 */ 599 static int 600 nfs_xdr_statfsres(struct rpc_rqst *req, u32 *p, struct nfs2_fsstat *res) 601 { 602 int status; 603 604 if ((status = ntohl(*p++))) 605 return -nfs_stat_to_errno(status); 606 607 res->tsize = ntohl(*p++); 608 res->bsize = ntohl(*p++); 609 res->blocks = ntohl(*p++); 610 res->bfree = ntohl(*p++); 611 res->bavail = ntohl(*p++); 612 return 0; 613 } 614 615 /* 616 * We need to translate between nfs status return values and 617 * the local errno values which may not be the same. 618 */ 619 static struct { 620 int stat; 621 int errno; 622 } nfs_errtbl[] = { 623 { NFS_OK, 0 }, 624 { NFSERR_PERM, EPERM }, 625 { NFSERR_NOENT, ENOENT }, 626 { NFSERR_IO, errno_NFSERR_IO }, 627 { NFSERR_NXIO, ENXIO }, 628 /* { NFSERR_EAGAIN, EAGAIN }, */ 629 { NFSERR_ACCES, EACCES }, 630 { NFSERR_EXIST, EEXIST }, 631 { NFSERR_XDEV, EXDEV }, 632 { NFSERR_NODEV, ENODEV }, 633 { NFSERR_NOTDIR, ENOTDIR }, 634 { NFSERR_ISDIR, EISDIR }, 635 { NFSERR_INVAL, EINVAL }, 636 { NFSERR_FBIG, EFBIG }, 637 { NFSERR_NOSPC, ENOSPC }, 638 { NFSERR_ROFS, EROFS }, 639 { NFSERR_MLINK, EMLINK }, 640 { NFSERR_NAMETOOLONG, ENAMETOOLONG }, 641 { NFSERR_NOTEMPTY, ENOTEMPTY }, 642 { NFSERR_DQUOT, EDQUOT }, 643 { NFSERR_STALE, ESTALE }, 644 { NFSERR_REMOTE, EREMOTE }, 645 #ifdef EWFLUSH 646 { NFSERR_WFLUSH, EWFLUSH }, 647 #endif 648 { NFSERR_BADHANDLE, EBADHANDLE }, 649 { NFSERR_NOT_SYNC, ENOTSYNC }, 650 { NFSERR_BAD_COOKIE, EBADCOOKIE }, 651 { NFSERR_NOTSUPP, ENOTSUPP }, 652 { NFSERR_TOOSMALL, ETOOSMALL }, 653 { NFSERR_SERVERFAULT, ESERVERFAULT }, 654 { NFSERR_BADTYPE, EBADTYPE }, 655 { NFSERR_JUKEBOX, EJUKEBOX }, 656 { -1, EIO } 657 }; 658 659 /* 660 * Convert an NFS error code to a local one. 661 * This one is used jointly by NFSv2 and NFSv3. 662 */ 663 int 664 nfs_stat_to_errno(int stat) 665 { 666 int i; 667 668 for (i = 0; nfs_errtbl[i].stat != -1; i++) { 669 if (nfs_errtbl[i].stat == stat) 670 return nfs_errtbl[i].errno; 671 } 672 printk(KERN_ERR "nfs_stat_to_errno: bad nfs status return value: %d\n", stat); 673 return nfs_errtbl[i].errno; 674 } 675 676 #ifndef MAX 677 # define MAX(a, b) (((a) > (b))? (a) : (b)) 678 #endif 679 680 #define PROC(proc, argtype, restype, timer) \ 681 [NFSPROC_##proc] = { \ 682 .p_proc = NFSPROC_##proc, \ 683 .p_encode = (kxdrproc_t) nfs_xdr_##argtype, \ 684 .p_decode = (kxdrproc_t) nfs_xdr_##restype, \ 685 .p_bufsiz = MAX(NFS_##argtype##_sz,NFS_##restype##_sz) << 2, \ 686 .p_timer = timer \ 687 } 688 struct rpc_procinfo nfs_procedures[] = { 689 PROC(GETATTR, fhandle, attrstat, 1), 690 PROC(SETATTR, sattrargs, attrstat, 0), 691 PROC(LOOKUP, diropargs, diropres, 2), 692 PROC(READLINK, readlinkargs, readlinkres, 3), 693 PROC(READ, readargs, readres, 3), 694 PROC(WRITE, writeargs, writeres, 4), 695 PROC(CREATE, createargs, diropres, 0), 696 PROC(REMOVE, diropargs, stat, 0), 697 PROC(RENAME, renameargs, stat, 0), 698 PROC(LINK, linkargs, stat, 0), 699 PROC(SYMLINK, symlinkargs, stat, 0), 700 PROC(MKDIR, createargs, diropres, 0), 701 PROC(RMDIR, diropargs, stat, 0), 702 PROC(READDIR, readdirargs, readdirres, 3), 703 PROC(STATFS, fhandle, statfsres, 0), 704 }; 705 706 struct rpc_version nfs_version2 = { 707 .number = 2, 708 .nrprocs = sizeof(nfs_procedures)/sizeof(nfs_procedures[0]), 709 .procs = nfs_procedures 710 }; 711