srv.c (18775B)
1 #include <u.h> 2 #include <libc.h> 3 #include <fcall.h> 4 #include <thread.h> 5 #include <9p.h> 6 7 int chatty9p; 8 9 /* static char Ebadattach[] = "unknown specifier in attach"; */ 10 static char Ebadoffset[] = "bad offset"; 11 /* static char Ebadcount[] = "bad count"; */ 12 static char Ebotch[] = "9P protocol botch"; 13 static char Ecreatenondir[] = "create in non-directory"; 14 static char Edupfid[] = "duplicate fid"; 15 static char Eduptag[] = "duplicate tag"; 16 static char Eisdir[] = "is a directory"; 17 static char Enocreate[] = "create prohibited"; 18 /* static char Enomem[] = "out of memory"; */ 19 static char Enoremove[] = "remove prohibited"; 20 static char Enostat[] = "stat prohibited"; 21 static char Enotfound[] = "file not found"; 22 /* static char Enowrite[] = "write prohibited"; */ 23 /*static char Enowstat[] = "wstat prohibited";*/ 24 static char Eperm[] = "permission denied"; 25 static char Eunknownfid[] = "unknown fid"; 26 static char Ebaddir[] = "bad directory in wstat"; 27 static char Ewalknodir[] = "walk in non-directory"; 28 29 static void 30 setfcallerror(Fcall *f, char *err) 31 { 32 f->ename = err; 33 f->type = Rerror; 34 } 35 36 static void 37 changemsize(Srv *srv, int msize) 38 { 39 if(srv->rbuf && srv->wbuf && srv->msize == msize) 40 return; 41 qlock(&srv->rlock); 42 qlock(&srv->wlock); 43 srv->msize = msize; 44 free(srv->rbuf); 45 free(srv->wbuf); 46 srv->rbuf = emalloc9p(msize); 47 srv->wbuf = emalloc9p(msize); 48 qunlock(&srv->rlock); 49 qunlock(&srv->wlock); 50 } 51 52 static Req* 53 getreq(Srv *s) 54 { 55 long n; 56 uchar *buf; 57 Fcall f; 58 Req *r; 59 60 qlock(&s->rlock); 61 if((n = read9pmsg(s->infd, s->rbuf, s->msize)) <= 0){ 62 qunlock(&s->rlock); 63 return nil; 64 } 65 66 buf = emalloc9p(n+1); /* +1 for NUL in swrite */ 67 memmove(buf, s->rbuf, n); 68 qunlock(&s->rlock); 69 70 if(convM2S(buf, n, &f) != n){ 71 free(buf); 72 return nil; 73 } 74 75 if((r=allocreq(s->rpool, f.tag)) == nil){ /* duplicate tag: cons up a fake Req */ 76 r = emalloc9p(sizeof *r); 77 incref(&r->ref); 78 r->tag = f.tag; 79 r->ifcall = f; 80 r->error = Eduptag; 81 r->buf = buf; 82 r->responded = 0; 83 r->type = 0; 84 r->srv = s; 85 r->pool = nil; 86 if(chatty9p) 87 fprint(2, "<-%d- %F: dup tag\n", s->infd, &f); 88 return r; 89 } 90 91 r->srv = s; 92 r->responded = 0; 93 r->buf = buf; 94 r->ifcall = f; 95 memset(&r->ofcall, 0, sizeof r->ofcall); 96 r->type = r->ifcall.type; 97 98 if(chatty9p) 99 if(r->error) 100 fprint(2, "<-%d- %F: %s\n", s->infd, &r->ifcall, r->error); 101 else 102 fprint(2, "<-%d- %F\n", s->infd, &r->ifcall); 103 104 return r; 105 } 106 107 static void 108 filewalk(Req *r) 109 { 110 int i; 111 File *f; 112 113 f = r->fid->file; 114 assert(f != nil); 115 116 incref(&f->ref); 117 for(i=0; i<r->ifcall.nwname; i++) 118 if(f = walkfile(f, r->ifcall.wname[i])) 119 r->ofcall.wqid[i] = f->dir.qid; 120 else 121 break; 122 123 r->ofcall.nwqid = i; 124 if(f){ 125 r->newfid->file = f; 126 r->newfid->qid = r->newfid->file->dir.qid; 127 } 128 respond(r, nil); 129 } 130 131 void 132 walkandclone(Req *r, char *(*walk1)(Fid*, char*, void*), char *(*clone)(Fid*, Fid*, void*), void *arg) 133 { 134 int i; 135 char *e; 136 137 if(r->fid == r->newfid && r->ifcall.nwname > 1){ 138 respond(r, "lib9p: unused documented feature not implemented"); 139 return; 140 } 141 142 if(r->fid != r->newfid){ 143 r->newfid->qid = r->fid->qid; 144 if(clone && (e = clone(r->fid, r->newfid, arg))){ 145 respond(r, e); 146 return; 147 } 148 } 149 150 e = nil; 151 for(i=0; i<r->ifcall.nwname; i++){ 152 if(e = walk1(r->newfid, r->ifcall.wname[i], arg)) 153 break; 154 r->ofcall.wqid[i] = r->newfid->qid; 155 } 156 157 r->ofcall.nwqid = i; 158 if(e && i==0) 159 respond(r, e); 160 else 161 respond(r, nil); 162 } 163 164 static void 165 sversion(Srv *srv, Req *r) 166 { 167 USED(srv); 168 169 if(strncmp(r->ifcall.version, "9P2000", 6) != 0){ 170 r->ofcall.version = "unknown"; 171 respond(r, nil); 172 return; 173 } 174 r->ofcall.version = "9P2000"; 175 r->ofcall.msize = r->ifcall.msize; 176 respond(r, nil); 177 } 178 179 static void 180 rversion(Req *r, char *error) 181 { 182 assert(error == nil); 183 changemsize(r->srv, r->ofcall.msize); 184 } 185 186 static void 187 sauth(Srv *srv, Req *r) 188 { 189 char e[ERRMAX]; 190 191 if((r->afid = allocfid(srv->fpool, r->ifcall.afid)) == nil){ 192 respond(r, Edupfid); 193 return; 194 } 195 if(srv->auth) 196 srv->auth(r); 197 else{ 198 snprint(e, sizeof e, "%s: authentication not required", argv0); 199 respond(r, e); 200 } 201 } 202 203 static void 204 rauth(Req *r, char *error) 205 { 206 if(error && r->afid) 207 closefid(removefid(r->srv->fpool, r->afid->fid)); 208 } 209 210 static void 211 sattach(Srv *srv, Req *r) 212 { 213 if((r->fid = allocfid(srv->fpool, r->ifcall.fid)) == nil){ 214 respond(r, Edupfid); 215 return; 216 } 217 r->afid = nil; 218 if(r->ifcall.afid != NOFID && (r->afid = lookupfid(srv->fpool, r->ifcall.afid)) == nil){ 219 respond(r, Eunknownfid); 220 return; 221 } 222 r->fid->uid = estrdup9p(r->ifcall.uname); 223 if(srv->tree){ 224 r->fid->file = srv->tree->root; 225 incref(&r->fid->file->ref); 226 r->ofcall.qid = r->fid->file->dir.qid; 227 r->fid->qid = r->ofcall.qid; 228 } 229 if(srv->attach) 230 srv->attach(r); 231 else 232 respond(r, nil); 233 return; 234 } 235 236 static void 237 rattach(Req *r, char *error) 238 { 239 if(error && r->fid) 240 closefid(removefid(r->srv->fpool, r->fid->fid)); 241 } 242 243 static void 244 sflush(Srv *srv, Req *r) 245 { 246 r->oldreq = lookupreq(srv->rpool, r->ifcall.oldtag); 247 if(r->oldreq == nil || r->oldreq == r) 248 respond(r, nil); 249 else if(srv->flush) 250 srv->flush(r); 251 else 252 respond(r, nil); 253 } 254 255 static int 256 rflush(Req *r, char *error) 257 { 258 Req *or; 259 260 assert(error == nil); 261 or = r->oldreq; 262 if(or){ 263 qlock(&or->lk); 264 if(or->responded == 0){ 265 or->flush = erealloc9p(or->flush, (or->nflush+1)*sizeof(or->flush[0])); 266 or->flush[or->nflush++] = r; 267 qunlock(&or->lk); 268 return -1; /* delay response until or is responded */ 269 } 270 qunlock(&or->lk); 271 closereq(or); 272 } 273 r->oldreq = nil; 274 return 0; 275 } 276 277 static char* 278 oldwalk1(Fid *fid, char *name, void *arg) 279 { 280 char *e; 281 Qid qid; 282 Srv *srv; 283 284 srv = arg; 285 e = srv->walk1(fid, name, &qid); 286 if(e) 287 return e; 288 fid->qid = qid; 289 return nil; 290 } 291 292 static char* 293 oldclone(Fid *fid, Fid *newfid, void *arg) 294 { 295 Srv *srv; 296 297 srv = arg; 298 if(srv->clone == nil) 299 return nil; 300 return srv->clone(fid, newfid); 301 } 302 303 static void 304 swalk(Srv *srv, Req *r) 305 { 306 if((r->fid = lookupfid(srv->fpool, r->ifcall.fid)) == nil){ 307 respond(r, Eunknownfid); 308 return; 309 } 310 if(r->fid->omode != -1){ 311 respond(r, "cannot clone open fid"); 312 return; 313 } 314 if(r->ifcall.nwname && !(r->fid->qid.type&QTDIR)){ 315 respond(r, Ewalknodir); 316 return; 317 } 318 if(r->ifcall.fid != r->ifcall.newfid){ 319 if((r->newfid = allocfid(srv->fpool, r->ifcall.newfid)) == nil){ 320 respond(r, Edupfid); 321 return; 322 } 323 r->newfid->uid = estrdup9p(r->fid->uid); 324 }else{ 325 incref(&r->fid->ref); 326 r->newfid = r->fid; 327 } 328 if(r->fid->file){ 329 filewalk(r); 330 }else if(srv->walk1) 331 walkandclone(r, oldwalk1, oldclone, srv); 332 else if(srv->walk) 333 srv->walk(r); 334 else 335 sysfatal("no walk function, no file trees"); 336 } 337 static void 338 rwalk(Req *r, char *error) 339 { 340 if(error || r->ofcall.nwqid < r->ifcall.nwname){ 341 if(r->ifcall.fid != r->ifcall.newfid && r->newfid) 342 closefid(removefid(r->srv->fpool, r->newfid->fid)); 343 if (r->ofcall.nwqid==0){ 344 if(error==nil && r->ifcall.nwname!=0) 345 r->error = Enotfound; 346 }else 347 r->error = nil; /* No error on partial walks */ 348 }else{ 349 if(r->ofcall.nwqid == 0){ 350 /* Just a clone */ 351 r->newfid->qid = r->fid->qid; 352 }else{ 353 /* if file trees are in use, filewalk took care of the rest */ 354 r->newfid->qid = r->ofcall.wqid[r->ofcall.nwqid-1]; 355 } 356 } 357 } 358 359 static void 360 sopen(Srv *srv, Req *r) 361 { 362 int p; 363 364 if((r->fid = lookupfid(srv->fpool, r->ifcall.fid)) == nil){ 365 respond(r, Eunknownfid); 366 return; 367 } 368 if(r->fid->omode != -1){ 369 respond(r, Ebotch); 370 return; 371 } 372 if((r->fid->qid.type&QTDIR) && (r->ifcall.mode&~ORCLOSE) != OREAD){ 373 respond(r, Eisdir); 374 return; 375 } 376 r->ofcall.qid = r->fid->qid; 377 switch(r->ifcall.mode&3){ 378 default: 379 assert(0); 380 case OREAD: 381 p = AREAD; 382 break; 383 case OWRITE: 384 p = AWRITE; 385 break; 386 case ORDWR: 387 p = AREAD|AWRITE; 388 break; 389 case OEXEC: 390 p = AEXEC; 391 break; 392 } 393 if(r->ifcall.mode&OTRUNC) 394 p |= AWRITE; 395 if((r->fid->qid.type&QTDIR) && p!=AREAD){ 396 respond(r, Eperm); 397 return; 398 } 399 if(r->fid->file){ 400 if(!hasperm(r->fid->file, r->fid->uid, p)){ 401 respond(r, Eperm); 402 return; 403 } 404 /* BUG RACE */ 405 if((r->ifcall.mode&ORCLOSE) 406 && !hasperm(r->fid->file->parent, r->fid->uid, AWRITE)){ 407 respond(r, Eperm); 408 return; 409 } 410 r->ofcall.qid = r->fid->file->dir.qid; 411 if((r->ofcall.qid.type&QTDIR) 412 && (r->fid->rdir = opendirfile(r->fid->file)) == nil){ 413 respond(r, "opendirfile failed"); 414 return; 415 } 416 } 417 if(srv->open) 418 srv->open(r); 419 else 420 respond(r, nil); 421 } 422 423 static void 424 ropen(Req *r, char *error) 425 { 426 char errbuf[ERRMAX]; 427 if(error) 428 return; 429 if(chatty9p){ 430 snprint(errbuf, sizeof errbuf, "fid mode is 0x%ux\n", r->ifcall.mode); 431 write(2, errbuf, strlen(errbuf)); 432 } 433 r->fid->omode = r->ifcall.mode; 434 r->fid->qid = r->ofcall.qid; 435 if(r->ofcall.qid.type&QTDIR) 436 r->fid->diroffset = 0; 437 } 438 439 static void 440 screate(Srv *srv, Req *r) 441 { 442 if((r->fid = lookupfid(srv->fpool, r->ifcall.fid)) == nil) 443 respond(r, Eunknownfid); 444 else if(r->fid->omode != -1) 445 respond(r, Ebotch); 446 else if(!(r->fid->qid.type&QTDIR)) 447 respond(r, Ecreatenondir); 448 else if(r->fid->file && !hasperm(r->fid->file, r->fid->uid, AWRITE)) 449 respond(r, Eperm); 450 else if(srv->create) 451 srv->create(r); 452 else 453 respond(r, Enocreate); 454 } 455 456 static void 457 rcreate(Req *r, char *error) 458 { 459 if(error) 460 return; 461 r->fid->omode = r->ifcall.mode; 462 r->fid->qid = r->ofcall.qid; 463 } 464 465 static void 466 sread(Srv *srv, Req *r) 467 { 468 int o; 469 470 if((r->fid = lookupfid(srv->fpool, r->ifcall.fid)) == nil){ 471 respond(r, Eunknownfid); 472 return; 473 } 474 if((int32)r->ifcall.count < 0){ 475 respond(r, Ebotch); 476 return; 477 } 478 if(r->ifcall.offset < 0 479 || ((r->fid->qid.type&QTDIR) && r->ifcall.offset != 0 && r->ifcall.offset != r->fid->diroffset)){ 480 respond(r, Ebadoffset); 481 return; 482 } 483 484 if(r->ifcall.count > srv->msize - IOHDRSZ) 485 r->ifcall.count = srv->msize - IOHDRSZ; 486 r->rbuf = emalloc9p(r->ifcall.count); 487 r->ofcall.data = r->rbuf; 488 o = r->fid->omode & 3; 489 if(o != OREAD && o != ORDWR && o != OEXEC){ 490 respond(r, Ebotch); 491 return; 492 } 493 if((r->fid->qid.type&QTDIR) && r->fid->file){ 494 r->ofcall.count = readdirfile(r->fid->rdir, r->rbuf, r->ifcall.count); 495 respond(r, nil); 496 return; 497 } 498 if(srv->read) 499 srv->read(r); 500 else 501 respond(r, "no srv->read"); 502 } 503 504 static void 505 rread(Req *r, char *error) 506 { 507 if(error==nil && (r->fid->qid.type&QTDIR)) 508 r->fid->diroffset = r->ifcall.offset + r->ofcall.count; 509 } 510 511 static void 512 swrite(Srv *srv, Req *r) 513 { 514 int o; 515 char e[ERRMAX]; 516 517 if((r->fid = lookupfid(srv->fpool, r->ifcall.fid)) == nil){ 518 respond(r, Eunknownfid); 519 return; 520 } 521 if((int32)r->ifcall.count < 0){ 522 respond(r, Ebotch); 523 return; 524 } 525 if(r->ifcall.offset < 0){ 526 respond(r, Ebotch); 527 return; 528 } 529 if(r->ifcall.count > srv->msize - IOHDRSZ) 530 r->ifcall.count = srv->msize - IOHDRSZ; 531 o = r->fid->omode & 3; 532 if(o != OWRITE && o != ORDWR){ 533 snprint(e, sizeof e, "write on fid with open mode 0x%ux", r->fid->omode); 534 respond(r, e); 535 return; 536 } 537 if(srv->write){ 538 r->ifcall.data[r->ifcall.count] = 0; /* enough room - see getreq */ 539 srv->write(r); 540 }else 541 respond(r, "no srv->write"); 542 } 543 static void 544 rwrite(Req *r, char *error) 545 { 546 if(error) 547 return; 548 if(r->fid->file) 549 r->fid->file->dir.qid.vers++; 550 } 551 552 static void 553 sclunk(Srv *srv, Req *r) 554 { 555 if((r->fid = removefid(srv->fpool, r->ifcall.fid)) == nil) 556 respond(r, Eunknownfid); 557 else if (srv->clunk) 558 srv->clunk(r); 559 else 560 respond(r, nil); 561 } 562 static void 563 rclunk(Req *r, char *msg) 564 { 565 USED(r); 566 USED(msg); 567 } 568 569 static void 570 sremove(Srv *srv, Req *r) 571 { 572 if((r->fid = removefid(srv->fpool, r->ifcall.fid)) == nil){ 573 respond(r, Eunknownfid); 574 return; 575 } 576 /* BUG RACE */ 577 if(r->fid->file && !hasperm(r->fid->file->parent, r->fid->uid, AWRITE)){ 578 respond(r, Eperm); 579 return; 580 } 581 if(srv->remove) 582 srv->remove(r); 583 else 584 respond(r, r->fid->file ? nil : Enoremove); 585 } 586 static void 587 rremove(Req *r, char *error, char *errbuf) 588 { 589 if(error) 590 return; 591 if(r->fid->file){ 592 if(removefile(r->fid->file) < 0){ 593 snprint(errbuf, ERRMAX, "remove %s: %r", 594 r->fid->file->dir.name); 595 r->error = errbuf; 596 } 597 r->fid->file = nil; 598 } 599 } 600 601 static void 602 sstat(Srv *srv, Req *r) 603 { 604 if((r->fid = lookupfid(srv->fpool, r->ifcall.fid)) == nil){ 605 respond(r, Eunknownfid); 606 return; 607 } 608 if(r->fid->file){ 609 r->d = r->fid->file->dir; 610 if(r->d.name) 611 r->d.name = estrdup9p(r->d.name); 612 if(r->d.uid) 613 r->d.uid = estrdup9p(r->d.uid); 614 if(r->d.gid) 615 r->d.gid = estrdup9p(r->d.gid); 616 if(r->d.muid) 617 r->d.muid = estrdup9p(r->d.muid); 618 } 619 if(srv->stat) 620 srv->stat(r); 621 else if(r->fid->file) 622 respond(r, nil); 623 else 624 respond(r, Enostat); 625 } 626 static void 627 rstat(Req *r, char *error) 628 { 629 int n; 630 uchar *statbuf; 631 uchar tmp[BIT16SZ]; 632 633 if(error) 634 return; 635 if(convD2M(&r->d, tmp, BIT16SZ) != BIT16SZ){ 636 r->error = "convD2M(_,_,BIT16SZ) did not return BIT16SZ"; 637 return; 638 } 639 n = GBIT16(tmp)+BIT16SZ; 640 statbuf = emalloc9p(n); 641 if(statbuf == nil){ 642 r->error = "out of memory"; 643 return; 644 } 645 r->ofcall.nstat = convD2M(&r->d, statbuf, n); 646 r->ofcall.stat = statbuf; /* freed in closereq */ 647 if(r->ofcall.nstat <= BIT16SZ){ 648 r->error = "convD2M fails"; 649 free(statbuf); 650 return; 651 } 652 } 653 654 static void 655 swstat(Srv *srv, Req *r) 656 { 657 if((r->fid = lookupfid(srv->fpool, r->ifcall.fid)) == nil){ 658 respond(r, Eunknownfid); 659 return; 660 } 661 if(srv->wstat == nil){ 662 respond(r, nil); 663 return; 664 } 665 if(convM2D(r->ifcall.stat, r->ifcall.nstat, &r->d, (char*)r->ifcall.stat) != r->ifcall.nstat){ 666 respond(r, Ebaddir); 667 return; 668 } 669 if((ushort)~r->d.type){ 670 respond(r, "wstat -- attempt to change type"); 671 return; 672 } 673 if((uint)~r->d.dev){ 674 respond(r, "wstat -- attempt to change dev"); 675 return; 676 } 677 if((uchar)~r->d.qid.type || (ulong)~r->d.qid.vers || (uvlong)~r->d.qid.path){ 678 respond(r, "wstat -- attempt to change qid"); 679 return; 680 } 681 if(r->d.muid && r->d.muid[0]){ 682 respond(r, "wstat -- attempt to change muid"); 683 return; 684 } 685 if((ulong)~r->d.mode && ((r->d.mode&DMDIR)>>24) != (r->fid->qid.type&QTDIR)){ 686 respond(r, "wstat -- attempt to change DMDIR bit"); 687 return; 688 } 689 srv->wstat(r); 690 } 691 692 static void 693 rwstat(Req *r, char *msg) 694 { 695 USED(r); 696 USED(msg); 697 } 698 699 void 700 srv(Srv *srv) 701 { 702 Req *r; 703 704 fmtinstall('D', dirfmt); 705 fmtinstall('F', fcallfmt); 706 707 if(srv->fpool == nil) 708 srv->fpool = allocfidpool(srv->destroyfid); 709 if(srv->rpool == nil) 710 srv->rpool = allocreqpool(srv->destroyreq); 711 if(srv->msize == 0) 712 srv->msize = 8192+IOHDRSZ; 713 714 changemsize(srv, srv->msize); 715 716 srv->fpool->srv = srv; 717 srv->rpool->srv = srv; 718 719 if(srv->start) 720 srv->start(srv); 721 722 while(r = getreq(srv)){ 723 if(r->error){ 724 respond(r, r->error); 725 continue; 726 } 727 switch(r->ifcall.type){ 728 default: 729 respond(r, "unknown message"); 730 break; 731 case Tversion: sversion(srv, r); break; 732 case Tauth: sauth(srv, r); break; 733 case Tattach: sattach(srv, r); break; 734 case Tflush: sflush(srv, r); break; 735 case Twalk: swalk(srv, r); break; 736 case Topen: sopen(srv, r); break; 737 case Tcreate: screate(srv, r); break; 738 case Tread: sread(srv, r); break; 739 case Twrite: swrite(srv, r); break; 740 case Tclunk: sclunk(srv, r); break; 741 case Tremove: sremove(srv, r); break; 742 case Tstat: sstat(srv, r); break; 743 case Twstat: swstat(srv, r); break; 744 } 745 } 746 747 if(srv->end) 748 srv->end(srv); 749 } 750 751 void 752 respond(Req *r, char *error) 753 { 754 int i, m, n; 755 char errbuf[ERRMAX]; 756 Srv *srv; 757 758 srv = r->srv; 759 assert(srv != nil); 760 761 if(r->responded){ 762 assert(r->pool); 763 goto free; 764 } 765 766 assert(r->responded == 0); 767 r->error = error; 768 769 switch(r->ifcall.type){ 770 default: 771 assert(0); 772 /* 773 * Flush is special. If the handler says so, we return 774 * without further processing. Respond will be called 775 * again once it is safe. 776 */ 777 case Tflush: 778 if(rflush(r, error)<0) 779 return; 780 break; 781 case Tversion: rversion(r, error); break; 782 case Tauth: rauth(r, error); break; 783 case Tattach: rattach(r, error); break; 784 case Twalk: rwalk(r, error); break; 785 case Topen: ropen(r, error); break; 786 case Tcreate: rcreate(r, error); break; 787 case Tread: rread(r, error); break; 788 case Twrite: rwrite(r, error); break; 789 case Tclunk: rclunk(r, error); break; 790 case Tremove: rremove(r, error, errbuf); break; 791 case Tstat: rstat(r, error); break; 792 case Twstat: rwstat(r, error); break; 793 } 794 795 r->ofcall.tag = r->ifcall.tag; 796 r->ofcall.type = r->ifcall.type+1; 797 if(r->error) 798 setfcallerror(&r->ofcall, r->error); 799 800 if(srv->fake) 801 return; 802 803 if(chatty9p) 804 fprint(2, "-%d-> %F\n", srv->outfd, &r->ofcall); 805 806 qlock(&srv->wlock); 807 n = convS2M(&r->ofcall, srv->wbuf, srv->msize); 808 if(n <= 0){ 809 fprint(2, "n = %d %F\n", n, &r->ofcall); 810 abort(); 811 } 812 assert(n > 2); 813 /* 814 * There is a race here - we must remove the entry before 815 * the write, so that if the client is very fast and reuses the 816 * tag, the read loop won't think it is still in use. 817 * 818 * By removing the entry before the write, we open up a 819 * race with incoming Tflush messages. Specifically, an 820 * incoming Tflush might not see r even though it has not 821 * yet been responded to. It would then send an Rflush 822 * immediately, potentially before we do the write. This can't 823 * happen because we already old srv->wlock, so nothing 824 * is going out on the wire before this write. 825 */ 826 if(r->pool) /* not a fake */ 827 closereq(removereq(r->pool, r->ifcall.tag)); 828 829 qlock(&r->lk); 830 r->responded = 1; 831 if(r->pool) 832 if(r->ref.ref == 1+r->nflush) 833 if(r->fid){ 834 /* 835 * There are no references other than in our r->flush array, 836 * so no one else should be accessing r concurrently. 837 * Close the fid now, before responding to the message. 838 * 839 * If the client is behaving (there are no outstanding T-messages 840 * that reference r->fid) and the message is a Tclunk or Tremove, 841 * then this closefid will call destroyfid. 842 * 843 * This means destroyfid can't piddle around 844 * indefinitely (we're holding srv->wlock!), but it provides 845 * for tighter semantics as to when destroyfid is called. 846 * 847 * LANL has observed cases where waiting until after the write 848 * can delay a closefid on a Twrite for many 9P transactions, 849 * so that a handful of transactions can happen including a Tclunk 850 * and a Topen, and the original fid will still not be destroyed. 851 */ 852 closefid(r->fid); 853 r->fid = nil; 854 } 855 qunlock(&r->lk); 856 m = write(srv->outfd, srv->wbuf, n); 857 if(m != n) 858 sysfatal("lib9p srv: write %d returned %d on fd %d: %r", n, m, srv->outfd); 859 qunlock(&srv->wlock); 860 861 free: 862 qlock(&r->lk); /* no one will add flushes now */ 863 864 for(i=0; i<r->nflush; i++){ 865 r->flush[i]->oldreq = nil; /* so it doesn't try to lock us! */ 866 respond(r->flush[i], nil); 867 } 868 free(r->flush); 869 r->nflush = 0; 870 r->flush = nil; 871 qunlock(&r->lk); 872 873 if(r->pool) 874 closereq(r); 875 else 876 free(r); 877 } 878 879 int 880 postfd(char *name, int pfd) 881 { 882 int fd; 883 char buf[80]; 884 885 snprint(buf, sizeof buf, "/srv/%s", name); 886 if(chatty9p) 887 fprint(2, "postfd %s\n", buf); 888 fd = create(buf, OWRITE|ORCLOSE|OCEXEC, 0600); 889 if(fd < 0){ 890 if(chatty9p) 891 fprint(2, "create fails: %r\n"); 892 return -1; 893 } 894 if(fprint(fd, "%d", pfd) < 0){ 895 if(chatty9p) 896 fprint(2, "write fails: %r\n"); 897 close(fd); 898 return -1; 899 } 900 if(chatty9p) 901 fprint(2, "postfd successful\n"); 902 return 0; 903 }