srv.c (18737B)
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 558 respond(r, nil); 559 } 560 static void 561 rclunk(Req *r, char *msg) 562 { 563 USED(r); 564 USED(msg); 565 } 566 567 static void 568 sremove(Srv *srv, Req *r) 569 { 570 if((r->fid = removefid(srv->fpool, r->ifcall.fid)) == nil){ 571 respond(r, Eunknownfid); 572 return; 573 } 574 /* BUG RACE */ 575 if(r->fid->file && !hasperm(r->fid->file->parent, r->fid->uid, AWRITE)){ 576 respond(r, Eperm); 577 return; 578 } 579 if(srv->remove) 580 srv->remove(r); 581 else 582 respond(r, r->fid->file ? nil : Enoremove); 583 } 584 static void 585 rremove(Req *r, char *error, char *errbuf) 586 { 587 if(error) 588 return; 589 if(r->fid->file){ 590 if(removefile(r->fid->file) < 0){ 591 snprint(errbuf, ERRMAX, "remove %s: %r", 592 r->fid->file->dir.name); 593 r->error = errbuf; 594 } 595 r->fid->file = nil; 596 } 597 } 598 599 static void 600 sstat(Srv *srv, Req *r) 601 { 602 if((r->fid = lookupfid(srv->fpool, r->ifcall.fid)) == nil){ 603 respond(r, Eunknownfid); 604 return; 605 } 606 if(r->fid->file){ 607 r->d = r->fid->file->dir; 608 if(r->d.name) 609 r->d.name = estrdup9p(r->d.name); 610 if(r->d.uid) 611 r->d.uid = estrdup9p(r->d.uid); 612 if(r->d.gid) 613 r->d.gid = estrdup9p(r->d.gid); 614 if(r->d.muid) 615 r->d.muid = estrdup9p(r->d.muid); 616 } 617 if(srv->stat) 618 srv->stat(r); 619 else if(r->fid->file) 620 respond(r, nil); 621 else 622 respond(r, Enostat); 623 } 624 static void 625 rstat(Req *r, char *error) 626 { 627 int n; 628 uchar *statbuf; 629 uchar tmp[BIT16SZ]; 630 631 if(error) 632 return; 633 if(convD2M(&r->d, tmp, BIT16SZ) != BIT16SZ){ 634 r->error = "convD2M(_,_,BIT16SZ) did not return BIT16SZ"; 635 return; 636 } 637 n = GBIT16(tmp)+BIT16SZ; 638 statbuf = emalloc9p(n); 639 if(statbuf == nil){ 640 r->error = "out of memory"; 641 return; 642 } 643 r->ofcall.nstat = convD2M(&r->d, statbuf, n); 644 r->ofcall.stat = statbuf; /* freed in closereq */ 645 if(r->ofcall.nstat <= BIT16SZ){ 646 r->error = "convD2M fails"; 647 free(statbuf); 648 return; 649 } 650 } 651 652 static void 653 swstat(Srv *srv, Req *r) 654 { 655 if((r->fid = lookupfid(srv->fpool, r->ifcall.fid)) == nil){ 656 respond(r, Eunknownfid); 657 return; 658 } 659 if(srv->wstat == nil){ 660 respond(r, Enowstat); 661 return; 662 } 663 if(convM2D(r->ifcall.stat, r->ifcall.nstat, &r->d, (char*)r->ifcall.stat) != r->ifcall.nstat){ 664 respond(r, Ebaddir); 665 return; 666 } 667 if((ushort)~r->d.type){ 668 respond(r, "wstat -- attempt to change type"); 669 return; 670 } 671 if((uint)~r->d.dev){ 672 respond(r, "wstat -- attempt to change dev"); 673 return; 674 } 675 if((uchar)~r->d.qid.type || (ulong)~r->d.qid.vers || (uvlong)~r->d.qid.path){ 676 respond(r, "wstat -- attempt to change qid"); 677 return; 678 } 679 if(r->d.muid && r->d.muid[0]){ 680 respond(r, "wstat -- attempt to change muid"); 681 return; 682 } 683 if((ulong)~r->d.mode && ((r->d.mode&DMDIR)>>24) != (r->fid->qid.type&QTDIR)){ 684 respond(r, "wstat -- attempt to change DMDIR bit"); 685 return; 686 } 687 srv->wstat(r); 688 } 689 690 static void 691 rwstat(Req *r, char *msg) 692 { 693 USED(r); 694 USED(msg); 695 } 696 697 void 698 srv(Srv *srv) 699 { 700 Req *r; 701 702 fmtinstall('D', dirfmt); 703 fmtinstall('F', fcallfmt); 704 705 if(srv->fpool == nil) 706 srv->fpool = allocfidpool(srv->destroyfid); 707 if(srv->rpool == nil) 708 srv->rpool = allocreqpool(srv->destroyreq); 709 if(srv->msize == 0) 710 srv->msize = 8192+IOHDRSZ; 711 712 changemsize(srv, srv->msize); 713 714 srv->fpool->srv = srv; 715 srv->rpool->srv = srv; 716 717 if(srv->start) 718 srv->start(srv); 719 720 while(r = getreq(srv)){ 721 if(r->error){ 722 respond(r, r->error); 723 continue; 724 } 725 switch(r->ifcall.type){ 726 default: 727 respond(r, "unknown message"); 728 break; 729 case Tversion: sversion(srv, r); break; 730 case Tauth: sauth(srv, r); break; 731 case Tattach: sattach(srv, r); break; 732 case Tflush: sflush(srv, r); break; 733 case Twalk: swalk(srv, r); break; 734 case Topen: sopen(srv, r); break; 735 case Tcreate: screate(srv, r); break; 736 case Tread: sread(srv, r); break; 737 case Twrite: swrite(srv, r); break; 738 case Tclunk: sclunk(srv, r); break; 739 case Tremove: sremove(srv, r); break; 740 case Tstat: sstat(srv, r); break; 741 case Twstat: swstat(srv, r); break; 742 } 743 } 744 745 if(srv->end) 746 srv->end(srv); 747 } 748 749 void 750 respond(Req *r, char *error) 751 { 752 int i, m, n; 753 char errbuf[ERRMAX]; 754 Srv *srv; 755 756 srv = r->srv; 757 assert(srv != nil); 758 759 if(r->responded){ 760 assert(r->pool); 761 goto free; 762 } 763 764 assert(r->responded == 0); 765 r->error = error; 766 767 switch(r->ifcall.type){ 768 default: 769 assert(0); 770 /* 771 * Flush is special. If the handler says so, we return 772 * without further processing. Respond will be called 773 * again once it is safe. 774 */ 775 case Tflush: 776 if(rflush(r, error)<0) 777 return; 778 break; 779 case Tversion: rversion(r, error); break; 780 case Tauth: rauth(r, error); break; 781 case Tattach: rattach(r, error); break; 782 case Twalk: rwalk(r, error); break; 783 case Topen: ropen(r, error); break; 784 case Tcreate: rcreate(r, error); break; 785 case Tread: rread(r, error); break; 786 case Twrite: rwrite(r, error); break; 787 case Tclunk: rclunk(r, error); break; 788 case Tremove: rremove(r, error, errbuf); break; 789 case Tstat: rstat(r, error); break; 790 case Twstat: rwstat(r, error); break; 791 } 792 793 r->ofcall.tag = r->ifcall.tag; 794 r->ofcall.type = r->ifcall.type+1; 795 if(r->error) 796 setfcallerror(&r->ofcall, r->error); 797 798 if(srv->fake) 799 return; 800 801 if(chatty9p) 802 fprint(2, "-%d-> %F\n", srv->outfd, &r->ofcall); 803 804 qlock(&srv->wlock); 805 n = convS2M(&r->ofcall, srv->wbuf, srv->msize); 806 if(n <= 0){ 807 fprint(2, "n = %d %F\n", n, &r->ofcall); 808 abort(); 809 } 810 assert(n > 2); 811 /* 812 * There is a race here - we must remove the entry before 813 * the write, so that if the client is very fast and reuses the 814 * tag, the read loop won't think it is still in use. 815 * 816 * By removing the entry before the write, we open up a 817 * race with incoming Tflush messages. Specifically, an 818 * incoming Tflush might not see r even though it has not 819 * yet been responded to. It would then send an Rflush 820 * immediately, potentially before we do the write. This can't 821 * happen because we already old srv->wlock, so nothing 822 * is going out on the wire before this write. 823 */ 824 if(r->pool) /* not a fake */ 825 closereq(removereq(r->pool, r->ifcall.tag)); 826 827 qlock(&r->lk); 828 r->responded = 1; 829 if(r->pool) 830 if(r->ref.ref == 1+r->nflush) 831 if(r->fid){ 832 /* 833 * There are no references other than in our r->flush array, 834 * so no one else should be accessing r concurrently. 835 * Close the fid now, before responding to the message. 836 * 837 * If the client is behaving (there are no outstanding T-messages 838 * that reference r->fid) and the message is a Tclunk or Tremove, 839 * then this closefid will call destroyfid. 840 * 841 * This means destroyfid can't piddle around 842 * indefinitely (we're holding srv->wlock!), but it provides 843 * for tighter semantics as to when destroyfid is called. 844 * 845 * LANL has observed cases where waiting until after the write 846 * can delay a closefid on a Twrite for many 9P transactions, 847 * so that a handful of transactions can happen including a Tclunk 848 * and a Topen, and the original fid will still not be destroyed. 849 */ 850 closefid(r->fid); 851 r->fid = nil; 852 } 853 qunlock(&r->lk); 854 m = write(srv->outfd, srv->wbuf, n); 855 if(m != n) 856 sysfatal("lib9p srv: write %d returned %d on fd %d: %r", n, m, srv->outfd); 857 qunlock(&srv->wlock); 858 859 free: 860 qlock(&r->lk); /* no one will add flushes now */ 861 862 for(i=0; i<r->nflush; i++){ 863 r->flush[i]->oldreq = nil; /* so it doesn't try to lock us! */ 864 respond(r->flush[i], nil); 865 } 866 free(r->flush); 867 r->nflush = 0; 868 r->flush = nil; 869 qunlock(&r->lk); 870 871 if(r->pool) 872 closereq(r); 873 else 874 free(r); 875 } 876 877 int 878 postfd(char *name, int pfd) 879 { 880 int fd; 881 char buf[80]; 882 883 snprint(buf, sizeof buf, "/srv/%s", name); 884 if(chatty9p) 885 fprint(2, "postfd %s\n", buf); 886 fd = create(buf, OWRITE|ORCLOSE|OCEXEC, 0600); 887 if(fd < 0){ 888 if(chatty9p) 889 fprint(2, "create fails: %r\n"); 890 return -1; 891 } 892 if(fprint(fd, "%d", pfd) < 0){ 893 if(chatty9p) 894 fprint(2, "write fails: %r\n"); 895 close(fd); 896 return -1; 897 } 898 if(chatty9p) 899 fprint(2, "postfd successful\n"); 900 return 0; 901 }