1 #include <u.h> 2 #include <libc.h> 3 #include <auth.h> 4 #include <fcall.h> 5 #define Extern extern 6 #include "statfs.h" 7 8 char *e[] = 9 { 10 [Ebadfid] "Bad fid", 11 [Enotdir] "Not a directory", 12 [Edupfid] "Fid already in use", 13 [Eopen] "Fid already opened", 14 [Exmnt] "Cannot .. past mount point", 15 [Enoauth] "Authentication failed", 16 }; 17 18 void 19 Xnop(Fsrpc *r) 20 { 21 Fcall thdr; 22 23 reply(&r->work, &thdr, 0); 24 r->busy = 0; 25 } 26 27 void 28 Xsession(Fsrpc *r) 29 { 30 Fcall thdr; 31 32 memset(thdr.authid, 0, sizeof(thdr.authid)); 33 memset(thdr.authdom, 0, sizeof(thdr.authdom)); 34 memset(thdr.chal, 0, sizeof(thdr.chal)); 35 reply(&r->work, &thdr, 0); 36 r->busy = 0; 37 } 38 39 void 40 Xflush(Fsrpc *r) 41 { 42 Fsrpc *t, *e; 43 Fcall thdr; 44 45 e = &Workq[Nr_workbufs]; 46 47 for(t = Workq; t < e; t++) { 48 if(t->work.tag == r->work.oldtag) { 49 DEBUG(2, "\tQ busy %d pid %d can %d\n", t->busy, t->pid, t->canint); 50 if(t->busy && t->pid) { 51 t->flushtag = r->work.tag; 52 DEBUG(2, "\tset flushtag %d\n", r->work.tag); 53 if(t->canint) 54 postnote(PNPROC, t->pid, "flush"); 55 r->busy = 0; 56 return; 57 } 58 } 59 } 60 61 reply(&r->work, &thdr, 0); 62 DEBUG(2, "\tflush reply\n"); 63 r->busy = 0; 64 } 65 66 void 67 Xattach(Fsrpc *r) 68 { 69 Fcall thdr; 70 Fid *f; 71 Rpc *rpc; 72 ulong t; 73 74 t = msec(); 75 76 f = newfid(r->work.fid); 77 if(f == 0) { 78 reply(&r->work, &thdr, e[Ebadfid]); 79 r->busy = 0; 80 return; 81 } 82 83 f->f = root; 84 thdr.qid = f->f->qid; 85 reply(&r->work, &thdr, 0); 86 r->busy = 0; 87 88 t = msec()-t; 89 rpc = &stats->rpc[Tattach]; 90 rpc->time += t; 91 if(t < rpc->loms) 92 rpc->loms = t; 93 if(t > rpc->hims) 94 rpc->hims = t; 95 } 96 97 void 98 Xclone(Fsrpc *r) 99 { 100 Fcall thdr; 101 Fid *f, *n; 102 ulong t; 103 Rpc *rpc; 104 105 t = msec(); 106 107 f = getfid(r->work.fid); 108 if(f == 0) { 109 reply(&r->work, &thdr, e[Ebadfid]); 110 r->busy = 0; 111 return; 112 } 113 n = newfid(r->work.newfid); 114 if(n == 0) { 115 reply(&r->work, &thdr, e[Edupfid]); 116 r->busy = 0; 117 return; 118 } 119 n->f = f->f; 120 reply(&r->work, &thdr, 0); 121 r->busy = 0; 122 123 t = msec()-t; 124 rpc = &stats->rpc[Tclone]; 125 rpc->time += t; 126 if(t < rpc->loms) 127 rpc->loms = t; 128 if(t > rpc->hims) 129 rpc->hims = t; 130 } 131 132 void 133 Xwalk(Fsrpc *r) 134 { 135 char err[ERRLEN]; 136 Fcall thdr; 137 Fid *f; 138 File *nf; 139 Rpc *rpc; 140 ulong t; 141 142 t = msec(); 143 144 f = getfid(r->work.fid); 145 if(f == 0) { 146 reply(&r->work, &thdr, e[Ebadfid]); 147 r->busy = 0; 148 return; 149 } 150 151 if(strcmp(r->work.name, "..") == 0) { 152 if(f->f->parent == 0) { 153 reply(&r->work, &thdr, e[Exmnt]); 154 r->busy = 0; 155 return; 156 } 157 f->f = f->f->parent; 158 thdr.qid = f->f->qid; 159 reply(&r->work, &thdr, 0); 160 r->busy = 0; 161 return; 162 } 163 164 nf = file(f->f, r->work.name); 165 if(nf == 0) { 166 errstr(err); 167 reply(&r->work, &thdr, err); 168 r->busy = 0; 169 return; 170 } 171 172 f->f = nf; 173 thdr.qid = nf->qid; 174 reply(&r->work, &thdr, 0); 175 r->busy = 0; 176 177 t = msec()-t; 178 rpc = &stats->rpc[Twalk]; 179 rpc->time += t; 180 if(t < rpc->loms) 181 rpc->loms = t; 182 if(t > rpc->hims) 183 rpc->hims = t; 184 } 185 186 void 187 Xclunk(Fsrpc *r) 188 { 189 Fcall thdr; 190 Fid *f; 191 Rpc *rpc; 192 ulong t; 193 int fid; 194 195 t = msec(); 196 197 f = getfid(r->work.fid); 198 if(f == 0) { 199 reply(&r->work, &thdr, e[Ebadfid]); 200 r->busy = 0; 201 return; 202 } 203 204 if(f->fid >= 0) 205 close(f->fid); 206 207 fid = r->work.fid; 208 reply(&r->work, &thdr, 0); 209 r->busy = 0; 210 211 t = msec()-t; 212 rpc = &stats->rpc[Tclunk]; 213 rpc->time += t; 214 if(t < rpc->loms) 215 rpc->loms = t; 216 if(t > rpc->hims) 217 rpc->hims = t; 218 219 if(f->nread || f->nwrite) 220 fidreport(f); 221 222 freefid(fid); 223 } 224 225 void 226 Xstat(Fsrpc *r) 227 { 228 char err[ERRLEN], path[128]; 229 Fcall thdr; 230 Fid *f; 231 int s; 232 Rpc *rpc; 233 ulong t; 234 235 t = msec(); 236 237 f = getfid(r->work.fid); 238 if(f == 0) { 239 reply(&r->work, &thdr, e[Ebadfid]); 240 r->busy = 0; 241 return; 242 } 243 if(f->fid >= 0) 244 s = fstat(f->fid, thdr.stat); 245 else { 246 makepath(path, f->f, ""); 247 s = stat(path, thdr.stat); 248 } 249 250 if(s < 0) { 251 errstr(err); 252 reply(&r->work, &thdr, err); 253 r->busy = 0; 254 return; 255 } 256 reply(&r->work, &thdr, 0); 257 r->busy = 0; 258 259 t = msec()-t; 260 rpc = &stats->rpc[Tstat]; 261 rpc->time += t; 262 if(t < rpc->loms) 263 rpc->loms = t; 264 if(t > rpc->hims) 265 rpc->hims = t; 266 } 267 268 void 269 Xcreate(Fsrpc *r) 270 { 271 char err[ERRLEN], path[128]; 272 Fcall thdr; 273 Fid *f; 274 File *nf; 275 Rpc *rpc; 276 ulong t; 277 278 t = msec(); 279 280 f = getfid(r->work.fid); 281 if(f == 0) { 282 reply(&r->work, &thdr, e[Ebadfid]); 283 r->busy = 0; 284 return; 285 } 286 287 288 makepath(path, f->f, r->work.name); 289 f->fid = create(path, r->work.mode, r->work.perm); 290 if(f->fid < 0) { 291 errstr(err); 292 reply(&r->work, &thdr, err); 293 r->busy = 0; 294 return; 295 } 296 297 nf = file(f->f, r->work.name); 298 if(nf == 0) { 299 errstr(err); 300 reply(&r->work, &thdr, err); 301 r->busy = 0; 302 return; 303 } 304 305 f->mode = r->work.mode; 306 f->f = nf; 307 f->offset = 0; 308 thdr.qid = f->f->qid; 309 reply(&r->work, &thdr, 0); 310 r->busy = 0; 311 312 t = msec()-t; 313 rpc = &stats->rpc[Tcreate]; 314 rpc->time += t; 315 if(t < rpc->loms) 316 rpc->loms = t; 317 if(t > rpc->hims) 318 rpc->hims = t; 319 } 320 321 322 void 323 Xremove(Fsrpc *r) 324 { 325 char err[ERRLEN], path[128]; 326 Fcall thdr; 327 Fid *f; 328 ulong t; 329 Rpc *rpc; 330 331 t = msec(); 332 333 f = getfid(r->work.fid); 334 if(f == 0) { 335 reply(&r->work, &thdr, e[Ebadfid]); 336 r->busy = 0; 337 return; 338 } 339 340 makepath(path, f->f, ""); 341 DEBUG(2, "\tremove: %s\n", path); 342 if(remove(path) < 0) { 343 errstr(err); 344 reply(&r->work, &thdr, err); 345 freefid(r->work.fid); 346 r->busy = 0; 347 return; 348 } 349 350 if(f->fid >= 0) 351 close(f->fid); 352 freefid(r->work.fid); 353 354 reply(&r->work, &thdr, 0); 355 r->busy = 0; 356 357 t = msec()-t; 358 rpc = &stats->rpc[Tremove]; 359 rpc->time += t; 360 if(t < rpc->loms) 361 rpc->loms = t; 362 if(t > rpc->hims) 363 rpc->hims = t; 364 } 365 366 void 367 Xwstat(Fsrpc *r) 368 { 369 char err[ERRLEN], path[128]; 370 Fcall thdr; 371 Fid *f; 372 int s; 373 ulong t; 374 Rpc *rpc; 375 376 t = msec(); 377 378 f = getfid(r->work.fid); 379 if(f == 0) { 380 reply(&r->work, &thdr, e[Ebadfid]); 381 r->busy = 0; 382 return; 383 } 384 if(f->fid >= 0) 385 s = fwstat(f->fid, r->work.stat); 386 else { 387 makepath(path, f->f, ""); 388 s = wstat(path, r->work.stat); 389 } 390 if(s < 0) { 391 errstr(err); 392 reply(&r->work, &thdr, err); 393 } 394 else 395 reply(&r->work, &thdr, 0); 396 397 r->busy = 0; 398 t = msec()-t; 399 rpc = &stats->rpc[Twstat]; 400 rpc->time += t; 401 if(t < rpc->loms) 402 rpc->loms = t; 403 if(t > rpc->hims) 404 rpc->hims = t; 405 } 406 407 void 408 Xclwalk(Fsrpc *r) 409 { 410 Fcall thdr; 411 412 reply(&r->work, &thdr, "exportfs: no Tclwalk"); 413 r->busy = 0; 414 } 415 416 void 417 slave(Fsrpc *f) 418 { 419 Proc *p; 420 int pid; 421 static int nproc; 422 423 for(;;) { 424 for(p = Proclist; p; p = p->next) { 425 if(p->busy == 0) { 426 f->pid = p->pid; 427 p->busy = 1; 428 pid = rendezvous(p->pid, (ulong)f); 429 if(pid != p->pid) 430 fatal("rendezvous sync fail"); 431 return; 432 } 433 } 434 435 if(++nproc > MAXPROC) 436 fatal("too many procs"); 437 438 pid = rfork(RFPROC|RFMEM); 439 if(pid < 0) 440 fatal("rfork"); 441 442 if(pid == 0) 443 blockingslave(); 444 445 p = malloc(sizeof(Proc)); 446 if(p == 0) 447 fatal("out of memory"); 448 449 p->busy = 0; 450 p->pid = pid; 451 p->next = Proclist; 452 Proclist = p; 453 454 rendezvous(pid, (ulong)p); 455 } 456 } 457 458 void 459 blockingslave(void) 460 { 461 Proc *m; 462 int pid; 463 Fsrpc *p; 464 Fcall thdr; 465 466 notify(flushaction); 467 468 pid = getpid(); 469 470 m = (Proc*)rendezvous(pid, 0); 471 472 for(;;) { 473 p = (Fsrpc*)rendezvous(pid, pid); 474 if((int)p == ~0) /* Interrupted */ 475 continue; 476 477 DEBUG(2, "\tslave: %d %F b %d p %d\n", pid, &p->work, p->busy, p->pid); 478 if(p->flushtag != NOTAG) 479 return; 480 481 switch(p->work.type) { 482 case Tread: 483 slaveread(p); 484 break; 485 case Twrite: 486 slavewrite(p); 487 break; 488 case Topen: 489 slaveopen(p); 490 break; 491 default: 492 reply(&p->work, &thdr, "exportfs: slave type error"); 493 } 494 if(p->flushtag != NOTAG) { 495 p->work.type = Tflush; 496 p->work.tag = p->flushtag; 497 reply(&p->work, &thdr, 0); 498 } 499 p->busy = 0; 500 m->busy = 0; 501 } 502 } 503 504 void 505 slaveopen(Fsrpc *p) 506 { 507 char err[ERRLEN], path[128]; 508 Fcall *work, thdr; 509 Fid *f; 510 ulong t; 511 Rpc *rpc; 512 513 work = &p->work; 514 515 t = msec(); 516 517 f = getfid(work->fid); 518 if(f == 0) { 519 reply(work, &thdr, e[Ebadfid]); 520 return; 521 } 522 if(f->fid >= 0) { 523 close(f->fid); 524 f->fid = -1; 525 } 526 527 makepath(path, f->f, ""); 528 DEBUG(2, "\topen: %s %d\n", path, work->mode); 529 530 p->canint = 1; 531 if(p->flushtag != NOTAG) 532 return; 533 /* There is a race here I ignore because there are no locks */ 534 f->fid = open(path, work->mode); 535 p->canint = 0; 536 if(f->fid < 0) { 537 errstr(err); 538 reply(work, &thdr, err); 539 return; 540 } 541 542 DEBUG(2, "\topen: fd %d\n", f->fid); 543 f->mode = work->mode; 544 f->offset = 0; 545 thdr.qid = f->f->qid; 546 reply(work, &thdr, 0); 547 548 t = msec()-t; 549 rpc = &stats->rpc[Topen]; 550 rpc->time += t; 551 if(t < rpc->loms) 552 rpc->loms = t; 553 if(t > rpc->hims) 554 rpc->hims = t; 555 } 556 557 void 558 slaveread(Fsrpc *p) 559 { 560 char data[MAXFDATA], err[ERRLEN]; 561 Fcall *work, thdr; 562 Fid *f; 563 int n, r; 564 ulong t; 565 Rpc *rpc; 566 567 work = &p->work; 568 569 t = msec(); 570 571 f = getfid(work->fid); 572 if(f == 0) { 573 reply(work, &thdr, e[Ebadfid]); 574 return; 575 } 576 577 if(work->offset != f->offset) 578 fileseek(f, work->offset); 579 580 n = (work->count > MAXFDATA) ? MAXFDATA : work->count; 581 p->canint = 1; 582 if(p->flushtag != NOTAG) 583 return; 584 r = read(f->fid, data, n); 585 p->canint = 0; 586 if(r < 0) { 587 errstr(err); 588 reply(work, &thdr, err); 589 return; 590 } 591 592 DEBUG(2, "\tread: fd=%d %d bytes\n", f->fid, r); 593 594 f->offset += r; 595 thdr.data = data; 596 thdr.count = r; 597 stats->totread += r; 598 f->nread++; 599 f->bread += r; 600 reply(work, &thdr, 0); 601 602 t = msec()-t; 603 rpc = &stats->rpc[Tread]; 604 rpc->time += t; 605 if(t < rpc->loms) 606 rpc->loms = t; 607 if(t > rpc->hims) 608 rpc->hims = t; 609 } 610 611 void 612 slavewrite(Fsrpc *p) 613 { 614 char err[ERRLEN]; 615 Fcall *work, thdr; 616 Fid *f; 617 int n; 618 ulong t; 619 Rpc *rpc; 620 621 work = &p->work; 622 623 t = msec(); 624 625 f = getfid(work->fid); 626 if(f == 0) { 627 reply(work, &thdr, e[Ebadfid]); 628 return; 629 } 630 631 if(work->offset != f->offset) 632 fileseek(f, work->offset); 633 634 n = (work->count > MAXFDATA) ? MAXFDATA : work->count; 635 p->canint = 1; 636 if(p->flushtag != NOTAG) 637 return; 638 n = write(f->fid, work->data, n); 639 p->canint = 0; 640 if(n < 0) { 641 errstr(err); 642 reply(work, &thdr, err); 643 return; 644 } 645 646 DEBUG(2, "\twrite: %d bytes fd=%d\n", n, f->fid); 647 648 f->offset += n; 649 thdr.count = n; 650 f->nwrite++; 651 f->bwrite += n; 652 stats->totwrite += n; 653 reply(work, &thdr, 0); 654 655 t = msec()-t; 656 rpc = &stats->rpc[Twrite]; 657 rpc->time += t; 658 if(t < rpc->loms) 659 rpc->loms = t; 660 if(t > rpc->hims) 661 rpc->hims = t; 662 } 663 664 void 665 fileseek(Fid *f, ulong offset) 666 { 667 char chunk[DIRCHUNK]; 668 int n, nbytes, r; 669 ulong to; 670 671 if(f->f->qid.path&CHDIR) { 672 if(offset < f->offset) 673 reopen(f); 674 675 for(nbytes = offset - f->offset; nbytes; nbytes -= r) { 676 n = (nbytes > DIRCHUNK) ? DIRCHUNK : nbytes; 677 r = read(f->fid, chunk, n); 678 if(r <= 0) { 679 DEBUG(2,"\tdir seek error\n"); 680 return; 681 } 682 f->offset += r; 683 } 684 } 685 else 686 f->offset = seek(f->fid, offset, 0); 687 } 688 689 void 690 reopen(Fid *f) 691 { 692 USED(f); 693 fatal("reopen"); 694 } 695 696 void 697 flushaction(void *a, char *cause) 698 { 699 USED(a); 700 if(strncmp(cause, "kill", 4) == 0) 701 noted(NDFLT); 702 703 noted(NCONT); 704 } 705