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 * Crazy hack: the request fits in a page, and already-decoded 407 * attributes follow argp->tname, so it's safe to just write a 408 * null to ensure it's null-terminated: 409 */ 410 argp->tname[argp->tlen] = '\0'; 411 nfserr = nfsd_symlink(rqstp, &argp->ffh, argp->fname, argp->flen, 412 argp->tname, &newfh); 413 414 fh_put(&argp->ffh); 415 fh_put(&newfh); 416 return nfserr; 417 } 418 419 /* 420 * Make directory. This operation is not idempotent. 421 * N.B. After this call resp->fh needs an fh_put 422 */ 423 static __be32 424 nfsd_proc_mkdir(struct svc_rqst *rqstp, struct nfsd_createargs *argp, 425 struct nfsd_diropres *resp) 426 { 427 __be32 nfserr; 428 429 dprintk("nfsd: MKDIR %s %.*s\n", SVCFH_fmt(&argp->fh), argp->len, argp->name); 430 431 if (resp->fh.fh_dentry) { 432 printk(KERN_WARNING 433 "nfsd_proc_mkdir: response already verified??\n"); 434 } 435 436 argp->attrs.ia_valid &= ~ATTR_SIZE; 437 fh_init(&resp->fh, NFS_FHSIZE); 438 nfserr = nfsd_create(rqstp, &argp->fh, argp->name, argp->len, 439 &argp->attrs, S_IFDIR, 0, &resp->fh); 440 fh_put(&argp->fh); 441 return nfsd_return_dirop(nfserr, resp); 442 } 443 444 /* 445 * Remove a directory 446 */ 447 static __be32 448 nfsd_proc_rmdir(struct svc_rqst *rqstp, struct nfsd_diropargs *argp, 449 void *resp) 450 { 451 __be32 nfserr; 452 453 dprintk("nfsd: RMDIR %s %.*s\n", SVCFH_fmt(&argp->fh), argp->len, argp->name); 454 455 nfserr = nfsd_unlink(rqstp, &argp->fh, S_IFDIR, argp->name, argp->len); 456 fh_put(&argp->fh); 457 return nfserr; 458 } 459 460 /* 461 * Read a portion of a directory. 462 */ 463 static __be32 464 nfsd_proc_readdir(struct svc_rqst *rqstp, struct nfsd_readdirargs *argp, 465 struct nfsd_readdirres *resp) 466 { 467 int count; 468 __be32 nfserr; 469 loff_t offset; 470 471 dprintk("nfsd: READDIR %s %d bytes at %d\n", 472 SVCFH_fmt(&argp->fh), 473 argp->count, argp->cookie); 474 475 /* Shrink to the client read size */ 476 count = (argp->count >> 2) - 2; 477 478 /* Make sure we've room for the NULL ptr & eof flag */ 479 count -= 2; 480 if (count < 0) 481 count = 0; 482 483 resp->buffer = argp->buffer; 484 resp->offset = NULL; 485 resp->buflen = count; 486 resp->common.err = nfs_ok; 487 /* Read directory and encode entries on the fly */ 488 offset = argp->cookie; 489 nfserr = nfsd_readdir(rqstp, &argp->fh, &offset, 490 &resp->common, nfssvc_encode_entry); 491 492 resp->count = resp->buffer - argp->buffer; 493 if (resp->offset) 494 *resp->offset = htonl(offset); 495 496 fh_put(&argp->fh); 497 return nfserr; 498 } 499 500 /* 501 * Get file system info 502 */ 503 static __be32 504 nfsd_proc_statfs(struct svc_rqst * rqstp, struct nfsd_fhandle *argp, 505 struct nfsd_statfsres *resp) 506 { 507 __be32 nfserr; 508 509 dprintk("nfsd: STATFS %s\n", SVCFH_fmt(&argp->fh)); 510 511 nfserr = nfsd_statfs(rqstp, &argp->fh, &resp->stats, 512 NFSD_MAY_BYPASS_GSS_ON_ROOT); 513 fh_put(&argp->fh); 514 return nfserr; 515 } 516 517 /* 518 * NFSv2 Server procedures. 519 * Only the results of non-idempotent operations are cached. 520 */ 521 struct nfsd_void { int dummy; }; 522 523 #define ST 1 /* status */ 524 #define FH 8 /* filehandle */ 525 #define AT 18 /* attributes */ 526 527 static struct svc_procedure nfsd_procedures2[18] = { 528 [NFSPROC_NULL] = { 529 .pc_func = (svc_procfunc) nfsd_proc_null, 530 .pc_decode = (kxdrproc_t) nfssvc_decode_void, 531 .pc_encode = (kxdrproc_t) nfssvc_encode_void, 532 .pc_argsize = sizeof(struct nfsd_void), 533 .pc_ressize = sizeof(struct nfsd_void), 534 .pc_cachetype = RC_NOCACHE, 535 .pc_xdrressize = ST, 536 }, 537 [NFSPROC_GETATTR] = { 538 .pc_func = (svc_procfunc) nfsd_proc_getattr, 539 .pc_decode = (kxdrproc_t) nfssvc_decode_fhandle, 540 .pc_encode = (kxdrproc_t) nfssvc_encode_attrstat, 541 .pc_release = (kxdrproc_t) nfssvc_release_fhandle, 542 .pc_argsize = sizeof(struct nfsd_fhandle), 543 .pc_ressize = sizeof(struct nfsd_attrstat), 544 .pc_cachetype = RC_NOCACHE, 545 .pc_xdrressize = ST+AT, 546 }, 547 [NFSPROC_SETATTR] = { 548 .pc_func = (svc_procfunc) nfsd_proc_setattr, 549 .pc_decode = (kxdrproc_t) nfssvc_decode_sattrargs, 550 .pc_encode = (kxdrproc_t) nfssvc_encode_attrstat, 551 .pc_release = (kxdrproc_t) nfssvc_release_fhandle, 552 .pc_argsize = sizeof(struct nfsd_sattrargs), 553 .pc_ressize = sizeof(struct nfsd_attrstat), 554 .pc_cachetype = RC_REPLBUFF, 555 .pc_xdrressize = ST+AT, 556 }, 557 [NFSPROC_ROOT] = { 558 .pc_decode = (kxdrproc_t) nfssvc_decode_void, 559 .pc_encode = (kxdrproc_t) nfssvc_encode_void, 560 .pc_argsize = sizeof(struct nfsd_void), 561 .pc_ressize = sizeof(struct nfsd_void), 562 .pc_cachetype = RC_NOCACHE, 563 .pc_xdrressize = ST, 564 }, 565 [NFSPROC_LOOKUP] = { 566 .pc_func = (svc_procfunc) nfsd_proc_lookup, 567 .pc_decode = (kxdrproc_t) nfssvc_decode_diropargs, 568 .pc_encode = (kxdrproc_t) nfssvc_encode_diropres, 569 .pc_release = (kxdrproc_t) nfssvc_release_fhandle, 570 .pc_argsize = sizeof(struct nfsd_diropargs), 571 .pc_ressize = sizeof(struct nfsd_diropres), 572 .pc_cachetype = RC_NOCACHE, 573 .pc_xdrressize = ST+FH+AT, 574 }, 575 [NFSPROC_READLINK] = { 576 .pc_func = (svc_procfunc) nfsd_proc_readlink, 577 .pc_decode = (kxdrproc_t) nfssvc_decode_readlinkargs, 578 .pc_encode = (kxdrproc_t) nfssvc_encode_readlinkres, 579 .pc_argsize = sizeof(struct nfsd_readlinkargs), 580 .pc_ressize = sizeof(struct nfsd_readlinkres), 581 .pc_cachetype = RC_NOCACHE, 582 .pc_xdrressize = ST+1+NFS_MAXPATHLEN/4, 583 }, 584 [NFSPROC_READ] = { 585 .pc_func = (svc_procfunc) nfsd_proc_read, 586 .pc_decode = (kxdrproc_t) nfssvc_decode_readargs, 587 .pc_encode = (kxdrproc_t) nfssvc_encode_readres, 588 .pc_release = (kxdrproc_t) nfssvc_release_fhandle, 589 .pc_argsize = sizeof(struct nfsd_readargs), 590 .pc_ressize = sizeof(struct nfsd_readres), 591 .pc_cachetype = RC_NOCACHE, 592 .pc_xdrressize = ST+AT+1+NFSSVC_MAXBLKSIZE_V2/4, 593 }, 594 [NFSPROC_WRITECACHE] = { 595 .pc_decode = (kxdrproc_t) nfssvc_decode_void, 596 .pc_encode = (kxdrproc_t) nfssvc_encode_void, 597 .pc_argsize = sizeof(struct nfsd_void), 598 .pc_ressize = sizeof(struct nfsd_void), 599 .pc_cachetype = RC_NOCACHE, 600 .pc_xdrressize = ST, 601 }, 602 [NFSPROC_WRITE] = { 603 .pc_func = (svc_procfunc) nfsd_proc_write, 604 .pc_decode = (kxdrproc_t) nfssvc_decode_writeargs, 605 .pc_encode = (kxdrproc_t) nfssvc_encode_attrstat, 606 .pc_release = (kxdrproc_t) nfssvc_release_fhandle, 607 .pc_argsize = sizeof(struct nfsd_writeargs), 608 .pc_ressize = sizeof(struct nfsd_attrstat), 609 .pc_cachetype = RC_REPLBUFF, 610 .pc_xdrressize = ST+AT, 611 }, 612 [NFSPROC_CREATE] = { 613 .pc_func = (svc_procfunc) nfsd_proc_create, 614 .pc_decode = (kxdrproc_t) nfssvc_decode_createargs, 615 .pc_encode = (kxdrproc_t) nfssvc_encode_diropres, 616 .pc_release = (kxdrproc_t) nfssvc_release_fhandle, 617 .pc_argsize = sizeof(struct nfsd_createargs), 618 .pc_ressize = sizeof(struct nfsd_diropres), 619 .pc_cachetype = RC_REPLBUFF, 620 .pc_xdrressize = ST+FH+AT, 621 }, 622 [NFSPROC_REMOVE] = { 623 .pc_func = (svc_procfunc) nfsd_proc_remove, 624 .pc_decode = (kxdrproc_t) nfssvc_decode_diropargs, 625 .pc_encode = (kxdrproc_t) nfssvc_encode_void, 626 .pc_argsize = sizeof(struct nfsd_diropargs), 627 .pc_ressize = sizeof(struct nfsd_void), 628 .pc_cachetype = RC_REPLSTAT, 629 .pc_xdrressize = ST, 630 }, 631 [NFSPROC_RENAME] = { 632 .pc_func = (svc_procfunc) nfsd_proc_rename, 633 .pc_decode = (kxdrproc_t) nfssvc_decode_renameargs, 634 .pc_encode = (kxdrproc_t) nfssvc_encode_void, 635 .pc_argsize = sizeof(struct nfsd_renameargs), 636 .pc_ressize = sizeof(struct nfsd_void), 637 .pc_cachetype = RC_REPLSTAT, 638 .pc_xdrressize = ST, 639 }, 640 [NFSPROC_LINK] = { 641 .pc_func = (svc_procfunc) nfsd_proc_link, 642 .pc_decode = (kxdrproc_t) nfssvc_decode_linkargs, 643 .pc_encode = (kxdrproc_t) nfssvc_encode_void, 644 .pc_argsize = sizeof(struct nfsd_linkargs), 645 .pc_ressize = sizeof(struct nfsd_void), 646 .pc_cachetype = RC_REPLSTAT, 647 .pc_xdrressize = ST, 648 }, 649 [NFSPROC_SYMLINK] = { 650 .pc_func = (svc_procfunc) nfsd_proc_symlink, 651 .pc_decode = (kxdrproc_t) nfssvc_decode_symlinkargs, 652 .pc_encode = (kxdrproc_t) nfssvc_encode_void, 653 .pc_argsize = sizeof(struct nfsd_symlinkargs), 654 .pc_ressize = sizeof(struct nfsd_void), 655 .pc_cachetype = RC_REPLSTAT, 656 .pc_xdrressize = ST, 657 }, 658 [NFSPROC_MKDIR] = { 659 .pc_func = (svc_procfunc) nfsd_proc_mkdir, 660 .pc_decode = (kxdrproc_t) nfssvc_decode_createargs, 661 .pc_encode = (kxdrproc_t) nfssvc_encode_diropres, 662 .pc_release = (kxdrproc_t) nfssvc_release_fhandle, 663 .pc_argsize = sizeof(struct nfsd_createargs), 664 .pc_ressize = sizeof(struct nfsd_diropres), 665 .pc_cachetype = RC_REPLBUFF, 666 .pc_xdrressize = ST+FH+AT, 667 }, 668 [NFSPROC_RMDIR] = { 669 .pc_func = (svc_procfunc) nfsd_proc_rmdir, 670 .pc_decode = (kxdrproc_t) nfssvc_decode_diropargs, 671 .pc_encode = (kxdrproc_t) nfssvc_encode_void, 672 .pc_argsize = sizeof(struct nfsd_diropargs), 673 .pc_ressize = sizeof(struct nfsd_void), 674 .pc_cachetype = RC_REPLSTAT, 675 .pc_xdrressize = ST, 676 }, 677 [NFSPROC_READDIR] = { 678 .pc_func = (svc_procfunc) nfsd_proc_readdir, 679 .pc_decode = (kxdrproc_t) nfssvc_decode_readdirargs, 680 .pc_encode = (kxdrproc_t) nfssvc_encode_readdirres, 681 .pc_argsize = sizeof(struct nfsd_readdirargs), 682 .pc_ressize = sizeof(struct nfsd_readdirres), 683 .pc_cachetype = RC_NOCACHE, 684 }, 685 [NFSPROC_STATFS] = { 686 .pc_func = (svc_procfunc) nfsd_proc_statfs, 687 .pc_decode = (kxdrproc_t) nfssvc_decode_fhandle, 688 .pc_encode = (kxdrproc_t) nfssvc_encode_statfsres, 689 .pc_argsize = sizeof(struct nfsd_fhandle), 690 .pc_ressize = sizeof(struct nfsd_statfsres), 691 .pc_cachetype = RC_NOCACHE, 692 .pc_xdrressize = ST+5, 693 }, 694 }; 695 696 697 struct svc_version nfsd_version2 = { 698 .vs_vers = 2, 699 .vs_nproc = 18, 700 .vs_proc = nfsd_procedures2, 701 .vs_dispatch = nfsd_dispatch, 702 .vs_xdrsize = NFS2_SVC_XDRSIZE, 703 }; 704 705 /* 706 * Map errnos to NFS errnos. 707 */ 708 __be32 709 nfserrno (int errno) 710 { 711 static struct { 712 __be32 nfserr; 713 int syserr; 714 } nfs_errtbl[] = { 715 { nfs_ok, 0 }, 716 { nfserr_perm, -EPERM }, 717 { nfserr_noent, -ENOENT }, 718 { nfserr_io, -EIO }, 719 { nfserr_nxio, -ENXIO }, 720 { nfserr_fbig, -E2BIG }, 721 { nfserr_acces, -EACCES }, 722 { nfserr_exist, -EEXIST }, 723 { nfserr_xdev, -EXDEV }, 724 { nfserr_mlink, -EMLINK }, 725 { nfserr_nodev, -ENODEV }, 726 { nfserr_notdir, -ENOTDIR }, 727 { nfserr_isdir, -EISDIR }, 728 { nfserr_inval, -EINVAL }, 729 { nfserr_fbig, -EFBIG }, 730 { nfserr_nospc, -ENOSPC }, 731 { nfserr_rofs, -EROFS }, 732 { nfserr_mlink, -EMLINK }, 733 { nfserr_nametoolong, -ENAMETOOLONG }, 734 { nfserr_notempty, -ENOTEMPTY }, 735 #ifdef EDQUOT 736 { nfserr_dquot, -EDQUOT }, 737 #endif 738 { nfserr_stale, -ESTALE }, 739 { nfserr_jukebox, -ETIMEDOUT }, 740 { nfserr_jukebox, -ERESTARTSYS }, 741 { nfserr_jukebox, -EAGAIN }, 742 { nfserr_jukebox, -EWOULDBLOCK }, 743 { nfserr_jukebox, -ENOMEM }, 744 { nfserr_io, -ETXTBSY }, 745 { nfserr_notsupp, -EOPNOTSUPP }, 746 { nfserr_toosmall, -ETOOSMALL }, 747 { nfserr_serverfault, -ESERVERFAULT }, 748 { nfserr_serverfault, -ENFILE }, 749 }; 750 int i; 751 752 for (i = 0; i < ARRAY_SIZE(nfs_errtbl); i++) { 753 if (nfs_errtbl[i].syserr == errno) 754 return nfs_errtbl[i].nfserr; 755 } 756 WARN(1, "nfsd: non-standard errno: %d\n", errno); 757 return nfserr_io; 758 } 759 760