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