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