1 /* 2 * Process version 2 NFS requests. 3 * 4 * Copyright (C) 1995-1997 Olaf Kirch <okir@monad.swb.de> 5 */ 6 7 #include <linux/namei.h> 8 9 #include "cache.h" 10 #include "xdr.h" 11 #include "vfs.h" 12 13 typedef struct svc_rqst svc_rqst; 14 typedef struct svc_buf svc_buf; 15 16 #define NFSDDBG_FACILITY NFSDDBG_PROC 17 18 19 static __be32 20 nfsd_proc_null(struct svc_rqst *rqstp, void *argp, void *resp) 21 { 22 return nfs_ok; 23 } 24 25 static __be32 26 nfsd_return_attrs(__be32 err, struct nfsd_attrstat *resp) 27 { 28 if (err) return err; 29 return fh_getattr(&resp->fh, &resp->stat); 30 } 31 static __be32 32 nfsd_return_dirop(__be32 err, struct nfsd_diropres *resp) 33 { 34 if (err) return err; 35 return fh_getattr(&resp->fh, &resp->stat); 36 } 37 /* 38 * Get a file's attributes 39 * N.B. After this call resp->fh needs an fh_put 40 */ 41 static __be32 42 nfsd_proc_getattr(struct svc_rqst *rqstp, struct nfsd_fhandle *argp, 43 struct nfsd_attrstat *resp) 44 { 45 __be32 nfserr; 46 dprintk("nfsd: GETATTR %s\n", SVCFH_fmt(&argp->fh)); 47 48 fh_copy(&resp->fh, &argp->fh); 49 nfserr = fh_verify(rqstp, &resp->fh, 0, 50 NFSD_MAY_NOP | NFSD_MAY_BYPASS_GSS_ON_ROOT); 51 return nfsd_return_attrs(nfserr, resp); 52 } 53 54 /* 55 * Set a file's attributes 56 * N.B. After this call resp->fh needs an fh_put 57 */ 58 static __be32 59 nfsd_proc_setattr(struct svc_rqst *rqstp, struct nfsd_sattrargs *argp, 60 struct nfsd_attrstat *resp) 61 { 62 __be32 nfserr; 63 dprintk("nfsd: SETATTR %s, valid=%x, size=%ld\n", 64 SVCFH_fmt(&argp->fh), 65 argp->attrs.ia_valid, (long) argp->attrs.ia_size); 66 67 fh_copy(&resp->fh, &argp->fh); 68 nfserr = nfsd_setattr(rqstp, &resp->fh, &argp->attrs,0, (time_t)0); 69 return nfsd_return_attrs(nfserr, resp); 70 } 71 72 /* 73 * Look up a path name component 74 * Note: the dentry in the resp->fh may be negative if the file 75 * doesn't exist yet. 76 * N.B. After this call resp->fh needs an fh_put 77 */ 78 static __be32 79 nfsd_proc_lookup(struct svc_rqst *rqstp, struct nfsd_diropargs *argp, 80 struct nfsd_diropres *resp) 81 { 82 __be32 nfserr; 83 84 dprintk("nfsd: LOOKUP %s %.*s\n", 85 SVCFH_fmt(&argp->fh), argp->len, argp->name); 86 87 fh_init(&resp->fh, NFS_FHSIZE); 88 nfserr = nfsd_lookup(rqstp, &argp->fh, argp->name, argp->len, 89 &resp->fh); 90 91 fh_put(&argp->fh); 92 return nfsd_return_dirop(nfserr, resp); 93 } 94 95 /* 96 * Read a symlink. 97 */ 98 static __be32 99 nfsd_proc_readlink(struct svc_rqst *rqstp, struct nfsd_readlinkargs *argp, 100 struct nfsd_readlinkres *resp) 101 { 102 __be32 nfserr; 103 104 dprintk("nfsd: READLINK %s\n", SVCFH_fmt(&argp->fh)); 105 106 /* Read the symlink. */ 107 resp->len = NFS_MAXPATHLEN; 108 nfserr = nfsd_readlink(rqstp, &argp->fh, argp->buffer, &resp->len); 109 110 fh_put(&argp->fh); 111 return nfserr; 112 } 113 114 /* 115 * Read a portion of a file. 116 * N.B. After this call resp->fh needs an fh_put 117 */ 118 static __be32 119 nfsd_proc_read(struct svc_rqst *rqstp, struct nfsd_readargs *argp, 120 struct nfsd_readres *resp) 121 { 122 __be32 nfserr; 123 124 dprintk("nfsd: READ %s %d bytes at %d\n", 125 SVCFH_fmt(&argp->fh), 126 argp->count, argp->offset); 127 128 /* Obtain buffer pointer for payload. 19 is 1 word for 129 * status, 17 words for fattr, and 1 word for the byte count. 130 */ 131 132 if (NFSSVC_MAXBLKSIZE_V2 < argp->count) { 133 char buf[RPC_MAX_ADDRBUFLEN]; 134 printk(KERN_NOTICE 135 "oversized read request from %s (%d bytes)\n", 136 svc_print_addr(rqstp, buf, sizeof(buf)), 137 argp->count); 138 argp->count = NFSSVC_MAXBLKSIZE_V2; 139 } 140 svc_reserve_auth(rqstp, (19<<2) + argp->count + 4); 141 142 resp->count = argp->count; 143 nfserr = nfsd_read(rqstp, fh_copy(&resp->fh, &argp->fh), 144 argp->offset, 145 rqstp->rq_vec, argp->vlen, 146 &resp->count); 147 148 if (nfserr) return nfserr; 149 return fh_getattr(&resp->fh, &resp->stat); 150 } 151 152 /* 153 * Write data to a file 154 * N.B. After this call resp->fh needs an fh_put 155 */ 156 static __be32 157 nfsd_proc_write(struct svc_rqst *rqstp, struct nfsd_writeargs *argp, 158 struct nfsd_attrstat *resp) 159 { 160 __be32 nfserr; 161 int stable = 1; 162 unsigned long cnt = argp->len; 163 164 dprintk("nfsd: WRITE %s %d bytes at %d\n", 165 SVCFH_fmt(&argp->fh), 166 argp->len, argp->offset); 167 168 nfserr = nfsd_write(rqstp, fh_copy(&resp->fh, &argp->fh), NULL, 169 argp->offset, 170 rqstp->rq_vec, argp->vlen, 171 &cnt, 172 &stable); 173 return nfsd_return_attrs(nfserr, resp); 174 } 175 176 /* 177 * CREATE processing is complicated. The keyword here is `overloaded.' 178 * The parent directory is kept locked between the check for existence 179 * and the actual create() call in compliance with VFS protocols. 180 * N.B. After this call _both_ argp->fh and resp->fh need an fh_put 181 */ 182 static __be32 183 nfsd_proc_create(struct svc_rqst *rqstp, struct nfsd_createargs *argp, 184 struct nfsd_diropres *resp) 185 { 186 svc_fh *dirfhp = &argp->fh; 187 svc_fh *newfhp = &resp->fh; 188 struct iattr *attr = &argp->attrs; 189 struct inode *inode; 190 struct dentry *dchild; 191 int type, mode; 192 __be32 nfserr; 193 int hosterr; 194 dev_t rdev = 0, wanted = new_decode_dev(attr->ia_size); 195 196 dprintk("nfsd: CREATE %s %.*s\n", 197 SVCFH_fmt(dirfhp), argp->len, argp->name); 198 199 /* First verify the parent file handle */ 200 nfserr = fh_verify(rqstp, dirfhp, S_IFDIR, NFSD_MAY_EXEC); 201 if (nfserr) 202 goto done; /* must fh_put dirfhp even on error */ 203 204 /* Check for NFSD_MAY_WRITE in nfsd_create if necessary */ 205 206 nfserr = nfserr_acces; 207 if (!argp->len) 208 goto done; 209 nfserr = nfserr_exist; 210 if (isdotent(argp->name, argp->len)) 211 goto done; 212 hosterr = fh_want_write(dirfhp); 213 if (hosterr) { 214 nfserr = nfserrno(hosterr); 215 goto done; 216 } 217 218 fh_lock_nested(dirfhp, I_MUTEX_PARENT); 219 dchild = lookup_one_len(argp->name, dirfhp->fh_dentry, argp->len); 220 if (IS_ERR(dchild)) { 221 nfserr = nfserrno(PTR_ERR(dchild)); 222 goto out_unlock; 223 } 224 fh_init(newfhp, NFS_FHSIZE); 225 nfserr = fh_compose(newfhp, dirfhp->fh_export, dchild, dirfhp); 226 if (!nfserr && !dchild->d_inode) 227 nfserr = nfserr_noent; 228 dput(dchild); 229 if (nfserr) { 230 if (nfserr != nfserr_noent) 231 goto out_unlock; 232 /* 233 * If the new file handle wasn't verified, we can't tell 234 * whether the file exists or not. Time to bail ... 235 */ 236 nfserr = nfserr_acces; 237 if (!newfhp->fh_dentry) { 238 printk(KERN_WARNING 239 "nfsd_proc_create: file handle not verified\n"); 240 goto out_unlock; 241 } 242 } 243 244 inode = newfhp->fh_dentry->d_inode; 245 246 /* Unfudge the mode bits */ 247 if (attr->ia_valid & ATTR_MODE) { 248 type = attr->ia_mode & S_IFMT; 249 mode = attr->ia_mode & ~S_IFMT; 250 if (!type) { 251 /* no type, so if target exists, assume same as that, 252 * else assume a file */ 253 if (inode) { 254 type = inode->i_mode & S_IFMT; 255 switch(type) { 256 case S_IFCHR: 257 case S_IFBLK: 258 /* reserve rdev for later checking */ 259 rdev = inode->i_rdev; 260 attr->ia_valid |= ATTR_SIZE; 261 262 /* FALLTHROUGH */ 263 case S_IFIFO: 264 /* this is probably a permission check.. 265 * at least IRIX implements perm checking on 266 * echo thing > device-special-file-or-pipe 267 * by doing a CREATE with type==0 268 */ 269 nfserr = nfsd_permission(rqstp, 270 newfhp->fh_export, 271 newfhp->fh_dentry, 272 NFSD_MAY_WRITE|NFSD_MAY_LOCAL_ACCESS); 273 if (nfserr && nfserr != nfserr_rofs) 274 goto out_unlock; 275 } 276 } else 277 type = S_IFREG; 278 } 279 } else if (inode) { 280 type = inode->i_mode & S_IFMT; 281 mode = inode->i_mode & ~S_IFMT; 282 } else { 283 type = S_IFREG; 284 mode = 0; /* ??? */ 285 } 286 287 attr->ia_valid |= ATTR_MODE; 288 attr->ia_mode = mode; 289 290 /* Special treatment for non-regular files according to the 291 * gospel of sun micro 292 */ 293 if (type != S_IFREG) { 294 if (type != S_IFBLK && type != S_IFCHR) { 295 rdev = 0; 296 } else if (type == S_IFCHR && !(attr->ia_valid & ATTR_SIZE)) { 297 /* If you think you've seen the worst, grok this. */ 298 type = S_IFIFO; 299 } else { 300 /* Okay, char or block special */ 301 if (!rdev) 302 rdev = wanted; 303 } 304 305 /* we've used the SIZE information, so discard it */ 306 attr->ia_valid &= ~ATTR_SIZE; 307 308 /* Make sure the type and device matches */ 309 nfserr = nfserr_exist; 310 if (inode && type != (inode->i_mode & S_IFMT)) 311 goto out_unlock; 312 } 313 314 nfserr = 0; 315 if (!inode) { 316 /* File doesn't exist. Create it and set attrs */ 317 nfserr = nfsd_create(rqstp, dirfhp, argp->name, argp->len, 318 attr, type, rdev, newfhp); 319 } else if (type == S_IFREG) { 320 dprintk("nfsd: existing %s, valid=%x, size=%ld\n", 321 argp->name, attr->ia_valid, (long) attr->ia_size); 322 /* File already exists. We ignore all attributes except 323 * size, so that creat() behaves exactly like 324 * open(..., O_CREAT|O_TRUNC|O_WRONLY). 325 */ 326 attr->ia_valid &= ATTR_SIZE; 327 if (attr->ia_valid) 328 nfserr = nfsd_setattr(rqstp, newfhp, attr, 0, (time_t)0); 329 } 330 331 out_unlock: 332 /* We don't really need to unlock, as fh_put does it. */ 333 fh_unlock(dirfhp); 334 fh_drop_write(dirfhp); 335 done: 336 fh_put(dirfhp); 337 return nfsd_return_dirop(nfserr, resp); 338 } 339 340 static __be32 341 nfsd_proc_remove(struct svc_rqst *rqstp, struct nfsd_diropargs *argp, 342 void *resp) 343 { 344 __be32 nfserr; 345 346 dprintk("nfsd: REMOVE %s %.*s\n", SVCFH_fmt(&argp->fh), 347 argp->len, argp->name); 348 349 /* Unlink. -SIFDIR means file must not be a directory */ 350 nfserr = nfsd_unlink(rqstp, &argp->fh, -S_IFDIR, argp->name, argp->len); 351 fh_put(&argp->fh); 352 return nfserr; 353 } 354 355 static __be32 356 nfsd_proc_rename(struct svc_rqst *rqstp, struct nfsd_renameargs *argp, 357 void *resp) 358 { 359 __be32 nfserr; 360 361 dprintk("nfsd: RENAME %s %.*s -> \n", 362 SVCFH_fmt(&argp->ffh), argp->flen, argp->fname); 363 dprintk("nfsd: -> %s %.*s\n", 364 SVCFH_fmt(&argp->tfh), argp->tlen, argp->tname); 365 366 nfserr = nfsd_rename(rqstp, &argp->ffh, argp->fname, argp->flen, 367 &argp->tfh, argp->tname, argp->tlen); 368 fh_put(&argp->ffh); 369 fh_put(&argp->tfh); 370 return nfserr; 371 } 372 373 static __be32 374 nfsd_proc_link(struct svc_rqst *rqstp, struct nfsd_linkargs *argp, 375 void *resp) 376 { 377 __be32 nfserr; 378 379 dprintk("nfsd: LINK %s ->\n", 380 SVCFH_fmt(&argp->ffh)); 381 dprintk("nfsd: %s %.*s\n", 382 SVCFH_fmt(&argp->tfh), 383 argp->tlen, 384 argp->tname); 385 386 nfserr = nfsd_link(rqstp, &argp->tfh, argp->tname, argp->tlen, 387 &argp->ffh); 388 fh_put(&argp->ffh); 389 fh_put(&argp->tfh); 390 return nfserr; 391 } 392 393 static __be32 394 nfsd_proc_symlink(struct svc_rqst *rqstp, struct nfsd_symlinkargs *argp, 395 void *resp) 396 { 397 struct svc_fh newfh; 398 __be32 nfserr; 399 400 dprintk("nfsd: SYMLINK %s %.*s -> %.*s\n", 401 SVCFH_fmt(&argp->ffh), argp->flen, argp->fname, 402 argp->tlen, argp->tname); 403 404 fh_init(&newfh, NFS_FHSIZE); 405 /* 406 * Create the link, look up new file and set attrs. 407 */ 408 nfserr = nfsd_symlink(rqstp, &argp->ffh, argp->fname, argp->flen, 409 argp->tname, argp->tlen, 410 &newfh, &argp->attrs); 411 412 413 fh_put(&argp->ffh); 414 fh_put(&newfh); 415 return nfserr; 416 } 417 418 /* 419 * Make directory. This operation is not idempotent. 420 * N.B. After this call resp->fh needs an fh_put 421 */ 422 static __be32 423 nfsd_proc_mkdir(struct svc_rqst *rqstp, struct nfsd_createargs *argp, 424 struct nfsd_diropres *resp) 425 { 426 __be32 nfserr; 427 428 dprintk("nfsd: MKDIR %s %.*s\n", SVCFH_fmt(&argp->fh), argp->len, argp->name); 429 430 if (resp->fh.fh_dentry) { 431 printk(KERN_WARNING 432 "nfsd_proc_mkdir: response already verified??\n"); 433 } 434 435 argp->attrs.ia_valid &= ~ATTR_SIZE; 436 fh_init(&resp->fh, NFS_FHSIZE); 437 nfserr = nfsd_create(rqstp, &argp->fh, argp->name, argp->len, 438 &argp->attrs, S_IFDIR, 0, &resp->fh); 439 fh_put(&argp->fh); 440 return nfsd_return_dirop(nfserr, resp); 441 } 442 443 /* 444 * Remove a directory 445 */ 446 static __be32 447 nfsd_proc_rmdir(struct svc_rqst *rqstp, struct nfsd_diropargs *argp, 448 void *resp) 449 { 450 __be32 nfserr; 451 452 dprintk("nfsd: RMDIR %s %.*s\n", SVCFH_fmt(&argp->fh), argp->len, argp->name); 453 454 nfserr = nfsd_unlink(rqstp, &argp->fh, S_IFDIR, argp->name, argp->len); 455 fh_put(&argp->fh); 456 return nfserr; 457 } 458 459 /* 460 * Read a portion of a directory. 461 */ 462 static __be32 463 nfsd_proc_readdir(struct svc_rqst *rqstp, struct nfsd_readdirargs *argp, 464 struct nfsd_readdirres *resp) 465 { 466 int count; 467 __be32 nfserr; 468 loff_t offset; 469 470 dprintk("nfsd: READDIR %s %d bytes at %d\n", 471 SVCFH_fmt(&argp->fh), 472 argp->count, argp->cookie); 473 474 /* Shrink to the client read size */ 475 count = (argp->count >> 2) - 2; 476 477 /* Make sure we've room for the NULL ptr & eof flag */ 478 count -= 2; 479 if (count < 0) 480 count = 0; 481 482 resp->buffer = argp->buffer; 483 resp->offset = NULL; 484 resp->buflen = count; 485 resp->common.err = nfs_ok; 486 /* Read directory and encode entries on the fly */ 487 offset = argp->cookie; 488 nfserr = nfsd_readdir(rqstp, &argp->fh, &offset, 489 &resp->common, nfssvc_encode_entry); 490 491 resp->count = resp->buffer - argp->buffer; 492 if (resp->offset) 493 *resp->offset = htonl(offset); 494 495 fh_put(&argp->fh); 496 return nfserr; 497 } 498 499 /* 500 * Get file system info 501 */ 502 static __be32 503 nfsd_proc_statfs(struct svc_rqst * rqstp, struct nfsd_fhandle *argp, 504 struct nfsd_statfsres *resp) 505 { 506 __be32 nfserr; 507 508 dprintk("nfsd: STATFS %s\n", SVCFH_fmt(&argp->fh)); 509 510 nfserr = nfsd_statfs(rqstp, &argp->fh, &resp->stats, 511 NFSD_MAY_BYPASS_GSS_ON_ROOT); 512 fh_put(&argp->fh); 513 return nfserr; 514 } 515 516 /* 517 * NFSv2 Server procedures. 518 * Only the results of non-idempotent operations are cached. 519 */ 520 struct nfsd_void { int dummy; }; 521 522 #define ST 1 /* status */ 523 #define FH 8 /* filehandle */ 524 #define AT 18 /* attributes */ 525 526 static struct svc_procedure nfsd_procedures2[18] = { 527 [NFSPROC_NULL] = { 528 .pc_func = (svc_procfunc) nfsd_proc_null, 529 .pc_decode = (kxdrproc_t) nfssvc_decode_void, 530 .pc_encode = (kxdrproc_t) nfssvc_encode_void, 531 .pc_argsize = sizeof(struct nfsd_void), 532 .pc_ressize = sizeof(struct nfsd_void), 533 .pc_cachetype = RC_NOCACHE, 534 .pc_xdrressize = ST, 535 }, 536 [NFSPROC_GETATTR] = { 537 .pc_func = (svc_procfunc) nfsd_proc_getattr, 538 .pc_decode = (kxdrproc_t) nfssvc_decode_fhandle, 539 .pc_encode = (kxdrproc_t) nfssvc_encode_attrstat, 540 .pc_release = (kxdrproc_t) nfssvc_release_fhandle, 541 .pc_argsize = sizeof(struct nfsd_fhandle), 542 .pc_ressize = sizeof(struct nfsd_attrstat), 543 .pc_cachetype = RC_NOCACHE, 544 .pc_xdrressize = ST+AT, 545 }, 546 [NFSPROC_SETATTR] = { 547 .pc_func = (svc_procfunc) nfsd_proc_setattr, 548 .pc_decode = (kxdrproc_t) nfssvc_decode_sattrargs, 549 .pc_encode = (kxdrproc_t) nfssvc_encode_attrstat, 550 .pc_release = (kxdrproc_t) nfssvc_release_fhandle, 551 .pc_argsize = sizeof(struct nfsd_sattrargs), 552 .pc_ressize = sizeof(struct nfsd_attrstat), 553 .pc_cachetype = RC_REPLBUFF, 554 .pc_xdrressize = ST+AT, 555 }, 556 [NFSPROC_ROOT] = { 557 .pc_decode = (kxdrproc_t) nfssvc_decode_void, 558 .pc_encode = (kxdrproc_t) nfssvc_encode_void, 559 .pc_argsize = sizeof(struct nfsd_void), 560 .pc_ressize = sizeof(struct nfsd_void), 561 .pc_cachetype = RC_NOCACHE, 562 .pc_xdrressize = ST, 563 }, 564 [NFSPROC_LOOKUP] = { 565 .pc_func = (svc_procfunc) nfsd_proc_lookup, 566 .pc_decode = (kxdrproc_t) nfssvc_decode_diropargs, 567 .pc_encode = (kxdrproc_t) nfssvc_encode_diropres, 568 .pc_release = (kxdrproc_t) nfssvc_release_fhandle, 569 .pc_argsize = sizeof(struct nfsd_diropargs), 570 .pc_ressize = sizeof(struct nfsd_diropres), 571 .pc_cachetype = RC_NOCACHE, 572 .pc_xdrressize = ST+FH+AT, 573 }, 574 [NFSPROC_READLINK] = { 575 .pc_func = (svc_procfunc) nfsd_proc_readlink, 576 .pc_decode = (kxdrproc_t) nfssvc_decode_readlinkargs, 577 .pc_encode = (kxdrproc_t) nfssvc_encode_readlinkres, 578 .pc_argsize = sizeof(struct nfsd_readlinkargs), 579 .pc_ressize = sizeof(struct nfsd_readlinkres), 580 .pc_cachetype = RC_NOCACHE, 581 .pc_xdrressize = ST+1+NFS_MAXPATHLEN/4, 582 }, 583 [NFSPROC_READ] = { 584 .pc_func = (svc_procfunc) nfsd_proc_read, 585 .pc_decode = (kxdrproc_t) nfssvc_decode_readargs, 586 .pc_encode = (kxdrproc_t) nfssvc_encode_readres, 587 .pc_release = (kxdrproc_t) nfssvc_release_fhandle, 588 .pc_argsize = sizeof(struct nfsd_readargs), 589 .pc_ressize = sizeof(struct nfsd_readres), 590 .pc_cachetype = RC_NOCACHE, 591 .pc_xdrressize = ST+AT+1+NFSSVC_MAXBLKSIZE_V2/4, 592 }, 593 [NFSPROC_WRITECACHE] = { 594 .pc_decode = (kxdrproc_t) nfssvc_decode_void, 595 .pc_encode = (kxdrproc_t) nfssvc_encode_void, 596 .pc_argsize = sizeof(struct nfsd_void), 597 .pc_ressize = sizeof(struct nfsd_void), 598 .pc_cachetype = RC_NOCACHE, 599 .pc_xdrressize = ST, 600 }, 601 [NFSPROC_WRITE] = { 602 .pc_func = (svc_procfunc) nfsd_proc_write, 603 .pc_decode = (kxdrproc_t) nfssvc_decode_writeargs, 604 .pc_encode = (kxdrproc_t) nfssvc_encode_attrstat, 605 .pc_release = (kxdrproc_t) nfssvc_release_fhandle, 606 .pc_argsize = sizeof(struct nfsd_writeargs), 607 .pc_ressize = sizeof(struct nfsd_attrstat), 608 .pc_cachetype = RC_REPLBUFF, 609 .pc_xdrressize = ST+AT, 610 }, 611 [NFSPROC_CREATE] = { 612 .pc_func = (svc_procfunc) nfsd_proc_create, 613 .pc_decode = (kxdrproc_t) nfssvc_decode_createargs, 614 .pc_encode = (kxdrproc_t) nfssvc_encode_diropres, 615 .pc_release = (kxdrproc_t) nfssvc_release_fhandle, 616 .pc_argsize = sizeof(struct nfsd_createargs), 617 .pc_ressize = sizeof(struct nfsd_diropres), 618 .pc_cachetype = RC_REPLBUFF, 619 .pc_xdrressize = ST+FH+AT, 620 }, 621 [NFSPROC_REMOVE] = { 622 .pc_func = (svc_procfunc) nfsd_proc_remove, 623 .pc_decode = (kxdrproc_t) nfssvc_decode_diropargs, 624 .pc_encode = (kxdrproc_t) nfssvc_encode_void, 625 .pc_argsize = sizeof(struct nfsd_diropargs), 626 .pc_ressize = sizeof(struct nfsd_void), 627 .pc_cachetype = RC_REPLSTAT, 628 .pc_xdrressize = ST, 629 }, 630 [NFSPROC_RENAME] = { 631 .pc_func = (svc_procfunc) nfsd_proc_rename, 632 .pc_decode = (kxdrproc_t) nfssvc_decode_renameargs, 633 .pc_encode = (kxdrproc_t) nfssvc_encode_void, 634 .pc_argsize = sizeof(struct nfsd_renameargs), 635 .pc_ressize = sizeof(struct nfsd_void), 636 .pc_cachetype = RC_REPLSTAT, 637 .pc_xdrressize = ST, 638 }, 639 [NFSPROC_LINK] = { 640 .pc_func = (svc_procfunc) nfsd_proc_link, 641 .pc_decode = (kxdrproc_t) nfssvc_decode_linkargs, 642 .pc_encode = (kxdrproc_t) nfssvc_encode_void, 643 .pc_argsize = sizeof(struct nfsd_linkargs), 644 .pc_ressize = sizeof(struct nfsd_void), 645 .pc_cachetype = RC_REPLSTAT, 646 .pc_xdrressize = ST, 647 }, 648 [NFSPROC_SYMLINK] = { 649 .pc_func = (svc_procfunc) nfsd_proc_symlink, 650 .pc_decode = (kxdrproc_t) nfssvc_decode_symlinkargs, 651 .pc_encode = (kxdrproc_t) nfssvc_encode_void, 652 .pc_argsize = sizeof(struct nfsd_symlinkargs), 653 .pc_ressize = sizeof(struct nfsd_void), 654 .pc_cachetype = RC_REPLSTAT, 655 .pc_xdrressize = ST, 656 }, 657 [NFSPROC_MKDIR] = { 658 .pc_func = (svc_procfunc) nfsd_proc_mkdir, 659 .pc_decode = (kxdrproc_t) nfssvc_decode_createargs, 660 .pc_encode = (kxdrproc_t) nfssvc_encode_diropres, 661 .pc_release = (kxdrproc_t) nfssvc_release_fhandle, 662 .pc_argsize = sizeof(struct nfsd_createargs), 663 .pc_ressize = sizeof(struct nfsd_diropres), 664 .pc_cachetype = RC_REPLBUFF, 665 .pc_xdrressize = ST+FH+AT, 666 }, 667 [NFSPROC_RMDIR] = { 668 .pc_func = (svc_procfunc) nfsd_proc_rmdir, 669 .pc_decode = (kxdrproc_t) nfssvc_decode_diropargs, 670 .pc_encode = (kxdrproc_t) nfssvc_encode_void, 671 .pc_argsize = sizeof(struct nfsd_diropargs), 672 .pc_ressize = sizeof(struct nfsd_void), 673 .pc_cachetype = RC_REPLSTAT, 674 .pc_xdrressize = ST, 675 }, 676 [NFSPROC_READDIR] = { 677 .pc_func = (svc_procfunc) nfsd_proc_readdir, 678 .pc_decode = (kxdrproc_t) nfssvc_decode_readdirargs, 679 .pc_encode = (kxdrproc_t) nfssvc_encode_readdirres, 680 .pc_argsize = sizeof(struct nfsd_readdirargs), 681 .pc_ressize = sizeof(struct nfsd_readdirres), 682 .pc_cachetype = RC_NOCACHE, 683 }, 684 [NFSPROC_STATFS] = { 685 .pc_func = (svc_procfunc) nfsd_proc_statfs, 686 .pc_decode = (kxdrproc_t) nfssvc_decode_fhandle, 687 .pc_encode = (kxdrproc_t) nfssvc_encode_statfsres, 688 .pc_argsize = sizeof(struct nfsd_fhandle), 689 .pc_ressize = sizeof(struct nfsd_statfsres), 690 .pc_cachetype = RC_NOCACHE, 691 .pc_xdrressize = ST+5, 692 }, 693 }; 694 695 696 struct svc_version nfsd_version2 = { 697 .vs_vers = 2, 698 .vs_nproc = 18, 699 .vs_proc = nfsd_procedures2, 700 .vs_dispatch = nfsd_dispatch, 701 .vs_xdrsize = NFS2_SVC_XDRSIZE, 702 }; 703 704 /* 705 * Map errnos to NFS errnos. 706 */ 707 __be32 708 nfserrno (int errno) 709 { 710 static struct { 711 __be32 nfserr; 712 int syserr; 713 } nfs_errtbl[] = { 714 { nfs_ok, 0 }, 715 { nfserr_perm, -EPERM }, 716 { nfserr_noent, -ENOENT }, 717 { nfserr_io, -EIO }, 718 { nfserr_nxio, -ENXIO }, 719 { nfserr_acces, -EACCES }, 720 { nfserr_exist, -EEXIST }, 721 { nfserr_xdev, -EXDEV }, 722 { nfserr_mlink, -EMLINK }, 723 { nfserr_nodev, -ENODEV }, 724 { nfserr_notdir, -ENOTDIR }, 725 { nfserr_isdir, -EISDIR }, 726 { nfserr_inval, -EINVAL }, 727 { nfserr_fbig, -EFBIG }, 728 { nfserr_nospc, -ENOSPC }, 729 { nfserr_rofs, -EROFS }, 730 { nfserr_mlink, -EMLINK }, 731 { nfserr_nametoolong, -ENAMETOOLONG }, 732 { nfserr_notempty, -ENOTEMPTY }, 733 #ifdef EDQUOT 734 { nfserr_dquot, -EDQUOT }, 735 #endif 736 { nfserr_stale, -ESTALE }, 737 { nfserr_jukebox, -ETIMEDOUT }, 738 { nfserr_jukebox, -ERESTARTSYS }, 739 { nfserr_jukebox, -EAGAIN }, 740 { nfserr_jukebox, -EWOULDBLOCK }, 741 { nfserr_jukebox, -ENOMEM }, 742 { nfserr_io, -ETXTBSY }, 743 { nfserr_notsupp, -EOPNOTSUPP }, 744 { nfserr_toosmall, -ETOOSMALL }, 745 { nfserr_serverfault, -ESERVERFAULT }, 746 }; 747 int i; 748 749 for (i = 0; i < ARRAY_SIZE(nfs_errtbl); i++) { 750 if (nfs_errtbl[i].syserr == errno) 751 return nfs_errtbl[i].nfserr; 752 } 753 printk (KERN_INFO "nfsd: non-standard errno: %d\n", errno); 754 return nfserr_io; 755 } 756 757