1 #include "all.h" 2 3 Lock wpathlock; 4 5 struct { 6 Lock flock; 7 File* ffree; /* free file structures */ 8 Wpath* wfree; 9 } suballoc; 10 11 enum{ 12 Finc= 128, /* allocation chunksize for files */ 13 Fmax= 10000, /* maximum file structures to be allocated */ 14 15 Winc= 8*128, /* allocation chunksize for wpath */ 16 Wmax= 8*10000, /* maximum wpath structures to be allocated */ 17 }; 18 19 20 Filsys* 21 fsstr(char *p) 22 { 23 Filsys *fs; 24 25 for(fs=filesys; fs->name; fs++) 26 if(strcmp(fs->name, p) == 0) 27 return fs; 28 return 0; 29 } 30 31 void 32 fileinit(Chan *cp) 33 { 34 File *f; 35 Tlock *t; 36 37 loop: 38 lock(&cp->flock); 39 f = cp->flist; 40 if(!f) { 41 unlock(&cp->flock); 42 return; 43 } 44 cp->flist = f->next; 45 unlock(&cp->flock); 46 47 qlock(f); 48 if(t = f->tlock) { 49 t->time = 0; 50 f->tlock = 0; 51 } 52 if(f->open & FREMOV) 53 doremove(f, 0); 54 freewp(f->wpath); 55 f->open = 0; 56 f->cp = 0; 57 qunlock(f); 58 59 goto loop; 60 } 61 62 /* 63 * returns a locked file structure 64 */ 65 File* 66 filep(Chan *cp, int fid, int flag) 67 { 68 File *f, *prev; 69 70 if(fid == NOF) 71 return 0; 72 73 loop: 74 lock(&cp->flock); 75 for(prev=0,f=cp->flist; f; prev=f,f=f->next) { 76 if(f->fid != fid) 77 continue; 78 if(prev) { 79 prev->next = f->next; 80 f->next = cp->flist; 81 cp->flist = f; 82 } 83 goto out; 84 } 85 if(flag) { 86 f = newfp(cp); 87 if(f) { 88 f->fid = fid; 89 goto out; 90 } 91 } 92 else print("cannot find %p.%d (list=%p)\n", cp, fid, cp->flist); 93 unlock(&cp->flock); 94 return 0; 95 96 out: 97 unlock(&cp->flock); 98 qlock(f); 99 if(f->fid != fid) { 100 qunlock(f); 101 goto loop; 102 } 103 return f; 104 } 105 106 void 107 sublockinit(void) 108 { 109 lock(&suballoc.flock); 110 lock(&wpathlock); 111 conf.nfile = 0; 112 conf.nwpath = 0; 113 unlock(&suballoc.flock); 114 unlock(&wpathlock); 115 } 116 117 /* 118 * always called with cp->flock locked 119 */ 120 File* 121 newfp(Chan *cp) 122 { 123 File *f, *e; 124 125 retry: 126 lock(&suballoc.flock); 127 f = suballoc.ffree; 128 if(f != nil){ 129 suballoc.ffree = f->list; 130 unlock(&suballoc.flock); 131 f->list = 0; 132 f->cp = cp; 133 f->next = cp->flist; 134 f->wpath = 0; 135 f->tlock = 0; 136 f->dslot = 0; 137 f->doffset = 0; 138 f->uid = 0; 139 f->cuid = 0; 140 cp->flist = f; 141 return f; 142 } 143 unlock(&suballoc.flock); 144 145 if(conf.nfile > Fmax){ 146 print("%d: out of files\n", cp->chan); 147 return 0; 148 } 149 150 /* 151 * create a few new files 152 */ 153 f = malloc(Finc*sizeof(*f)); 154 memset(f, 0, Finc*sizeof(*f)); 155 lock(&suballoc.flock); 156 for(e = f+Finc; f < e; f++){ 157 qlock(f); 158 qunlock(f); 159 f->list = suballoc.ffree; 160 suballoc.ffree = f; 161 } 162 conf.nfile += Finc; 163 unlock(&suballoc.flock); 164 goto retry; 165 } 166 167 void 168 freefp(File *fp) 169 { 170 Chan *cp; 171 File *f, *prev; 172 173 if(!fp || !(cp = fp->cp)) 174 return; 175 authfree(fp); 176 lock(&cp->flock); 177 for(prev=0,f=cp->flist; f; prev=f,f=f->next) { 178 if(f != fp) 179 continue; 180 if(prev) 181 prev->next = f->next; 182 else 183 cp->flist = f->next; 184 f->cp = 0; 185 lock(&suballoc.flock); 186 f->list = suballoc.ffree; 187 suballoc.ffree = f; 188 unlock(&suballoc.flock); 189 break; 190 } 191 unlock(&cp->flock); 192 } 193 194 Wpath* 195 newwp(void) 196 { 197 Wpath *w, *e; 198 199 retry: 200 lock(&wpathlock); 201 w = suballoc.wfree; 202 if(w != nil){ 203 suballoc.wfree = w->list; 204 unlock(&wpathlock); 205 memset(w, 0, sizeof(*w)); 206 w->refs = 1; 207 w->up = 0; 208 return w; 209 } 210 unlock(&wpathlock); 211 212 if(conf.nwpath > Wmax){ 213 print("out of wpaths\n"); 214 return 0; 215 } 216 217 /* 218 * create a few new wpaths 219 */ 220 w = malloc(Winc*sizeof(*w)); 221 memset(w, 0, Winc*sizeof(*w)); 222 lock(&wpathlock); 223 for(e = w+Winc; w < e; w++){ 224 w->list = suballoc.wfree; 225 suballoc.wfree = w; 226 } 227 conf.nwpath += Winc; 228 unlock(&wpathlock); 229 goto retry; 230 } 231 232 /* 233 * increment the references for the whole path 234 */ 235 Wpath* 236 getwp(Wpath *w) 237 { 238 Wpath *nw; 239 240 lock(&wpathlock); 241 for(nw = w; nw; nw=nw->up) 242 nw->refs++; 243 unlock(&wpathlock); 244 return w; 245 } 246 247 /* 248 * decrement the reference for each element of the path 249 */ 250 void 251 freewp(Wpath *w) 252 { 253 lock(&wpathlock); 254 for(; w; w=w->up){ 255 w->refs--; 256 if(w->refs == 0){ 257 w->list = suballoc.wfree; 258 suballoc.wfree = w; 259 } 260 } 261 unlock(&wpathlock); 262 } 263 264 /* 265 * decrement the reference for just this element 266 */ 267 void 268 putwp(Wpath *w) 269 { 270 lock(&wpathlock); 271 w->refs--; 272 if(w->refs == 0){ 273 w->list = suballoc.wfree; 274 suballoc.wfree = w; 275 } 276 unlock(&wpathlock); 277 } 278 279 int 280 iaccess(File *f, Dentry *d, int m) 281 { 282 if(wstatallow) 283 return 0; 284 285 /* 286 * owner is next 287 */ 288 if(f->uid == d->uid) 289 if((m<<6) & d->mode) 290 return 0; 291 /* 292 * group membership is hard 293 */ 294 if(ingroup(f->uid, d->gid)) 295 if((m<<3) & d->mode) 296 return 0; 297 /* 298 * other access for everyone except members of group 9999 299 */ 300 if(m & d->mode){ 301 /* 302 * walk directories regardless. 303 * otherwise its impossible to get 304 * from the root to noworld's directories. 305 */ 306 if((d->mode & DDIR) && (m == DEXEC)) 307 return 0; 308 if(!ingroup(f->uid, 9999)) 309 return 0; 310 } 311 return 1; 312 } 313 314 Tlock* 315 tlocked(Iobuf *p, Dentry *d) 316 { 317 Tlock *t, *t1; 318 long qpath, tim; 319 Device dev; 320 321 tim = time(0); 322 qpath = d->qid.path; 323 dev = p->dev; 324 t1 = 0; 325 for(t=tlocks+NTLOCK-1; t>=tlocks; t--) { 326 if(t->qpath == qpath) 327 if(t->time >= tim) 328 if(devcmp(t->dev, dev) == 0) 329 return 0; /* its locked */ 330 if(!t1 && t->time < tim) 331 t1 = t; /* steal first lock */ 332 } 333 if(t1) { 334 t1->dev = dev; 335 t1->qpath = qpath; 336 t1->time = tim + TLOCK; 337 } 338 /* botch 339 * out of tlock nodes simulates 340 * a locked file 341 */ 342 return t1; 343 } 344 345 Qid 346 newqid(Device dev) 347 { 348 Iobuf *p; 349 Superb *sb; 350 Qid qid; 351 352 p = getbuf(dev, superaddr(dev), Bread|Bmod); 353 if(!p || checktag(p, Tsuper, QPSUPER)) 354 panic("newqid: super block"); 355 sb = (Superb*)p->iobuf; 356 sb->qidgen++; 357 qid.path = sb->qidgen; 358 qid.vers = 0; 359 putbuf(p); 360 return qid; 361 } 362 363 /* 364 * what are legal characters in a name? 365 * only disallow control characters. 366 * a) utf avoids control characters. 367 * b) '/' may not be the separator 368 */ 369 int 370 checkname(char *n) 371 { 372 int i, c; 373 374 for(i=0; i<NAMELEN; i++) { 375 c = *n & 0xff; 376 if(c == 0) { 377 if(i == 0) 378 return 1; 379 memset(n, 0, NAMELEN-i); 380 return 0; 381 } 382 if(c <= 040) 383 return 1; 384 n++; 385 } 386 return 1; /* too long */ 387 } 388 389 void 390 bfree(Device dev, long addr, int d) 391 { 392 Iobuf *p; 393 long a; 394 int i; 395 396 if(!addr) 397 return; 398 if(d > 0) { 399 d--; 400 p = getbuf(dev, addr, Bread); 401 if(p) { 402 for(i=INDPERBUF-1; i>=0; i--) { 403 a = ((long*)p->iobuf)[i]; 404 bfree(dev, a, d); 405 } 406 putbuf(p); 407 } 408 } 409 /* 410 * stop outstanding i/o 411 */ 412 p = getbuf(dev, addr, Bprobe); 413 if(p) { 414 p->flags &= ~(Bmod|Bimm); 415 putbuf(p); 416 } 417 /* 418 * dont put written worm 419 * blocks into free list 420 */ 421 if(nofree(dev, addr)) 422 return; 423 p = getbuf(dev, superaddr(dev), Bread|Bmod); 424 if(!p || checktag(p, Tsuper, QPSUPER)) 425 panic("bfree: super block"); 426 addfree(dev, addr, (Superb*)p->iobuf); 427 putbuf(p); 428 } 429 430 long 431 balloc(Device dev, int tag, long qid) 432 { 433 Iobuf *bp, *p; 434 Superb *sb; 435 long a; 436 int n; 437 438 p = getbuf(dev, superaddr(dev), Bread|Bmod); 439 if(!p || checktag(p, Tsuper, QPSUPER)) 440 panic("balloc: super block"); 441 sb = (Superb*)p->iobuf; 442 443 loop: 444 n = --sb->fbuf.nfree; 445 sb->tfree--; 446 if(n < 0 || n >= FEPERBUF) 447 panic("balloc: bad freelist"); 448 a = sb->fbuf.free[n]; 449 if(n <= 0) { 450 if(a == 0) { 451 sb->tfree = 0; 452 sb->fbuf.nfree = 1; 453 if(devgrow(dev, sb)) 454 goto loop; 455 putbuf(p); 456 return 0; 457 } 458 bp = getbuf(dev, a, Bread); 459 if(!bp || checktag(bp, Tfree, QPNONE)) { 460 if(bp) 461 putbuf(bp); 462 putbuf(p); 463 return 0; 464 } 465 memmove(&sb->fbuf, bp->iobuf, (FEPERBUF+1)*sizeof(long)); 466 putbuf(bp); 467 } 468 bp = getbuf(dev, a, Bmod); 469 memset(bp->iobuf, 0, RBUFSIZE); 470 settag(bp, tag, qid); 471 if(tag == Tind1 || tag == Tind2 || tag == Tdir) 472 bp->flags |= Bimm; 473 putbuf(bp); 474 putbuf(p); 475 return a; 476 } 477 478 void 479 addfree(Device dev, long addr, Superb *sb) 480 { 481 int n; 482 Iobuf *p; 483 484 if(addr >= sb->fsize){ 485 print("addfree: bad addr %lux\n", addr); 486 return; 487 } 488 n = sb->fbuf.nfree; 489 if(n < 0 || n > FEPERBUF) 490 panic("addfree: bad freelist"); 491 if(n >= FEPERBUF) { 492 p = getbuf(dev, addr, Bmod); 493 if(p == 0) 494 panic("addfree: getbuf"); 495 memmove(p->iobuf, &sb->fbuf, (FEPERBUF+1)*sizeof(long)); 496 settag(p, Tfree, QPNONE); 497 putbuf(p); 498 n = 0; 499 } 500 sb->fbuf.free[n++] = addr; 501 sb->fbuf.nfree = n; 502 sb->tfree++; 503 if(addr >= sb->fsize) 504 sb->fsize = addr+1; 505 } 506 507 int 508 Cfmt(Fmt *f1) 509 { 510 Chan *cp; 511 512 cp = va_arg(f1->args, Chan*); 513 return fmtprint(f1, "C%d.%.3d", cp->type, cp->chan); 514 } 515 516 int 517 Dfmt(Fmt *f1) 518 { 519 Device d; 520 521 d = va_arg(f1->args, Device); 522 return fmtprint(f1, "D%d.%d.%d.%d", d.type, d.ctrl, d.unit, d.part); 523 } 524 525 int 526 Afmt(Fmt *f1) 527 { 528 Filta a; 529 530 a = va_arg(f1->args, Filta); 531 return fmtprint(f1, "%6lud %6lud %6lud", 532 fdf(a.f->filter[0], a.scale*60), 533 fdf(a.f->filter[1], a.scale*600), 534 fdf(a.f->filter[2], a.scale*6000)); 535 } 536 537 int 538 Gfmt(Fmt *f1) 539 { 540 int t; 541 542 t = va_arg(f1->args, int); 543 if(t >= 0 && t < MAXTAG) 544 return fmtstrcpy(f1, tagnames[t]); 545 else 546 return fmtprint(f1, "<badtag %d>", t); 547 } 548 549 void 550 formatinit(void) 551 { 552 553 fmtinstall('C', Cfmt); /* print channels */ 554 fmtinstall('D', Dfmt); /* print devices */ 555 fmtinstall('A', Afmt); /* print filters */ 556 fmtinstall('G', Gfmt); /* print tags */ 557 fmtinstall('T', Tfmt); /* print times */ 558 fmtinstall('O', ofcallfmt); /* print old fcalls */ 559 } 560 int 561 devcmp(Device d1, Device d2) 562 { 563 564 if(d1.type == d2.type) 565 if(d1.ctrl == d2.ctrl) 566 if(d1.unit == d2.unit) 567 if(d1.part == d2.part) 568 return 0; 569 return 1; 570 } 571 572 void 573 rootream(Device dev, long addr) 574 { 575 Iobuf *p; 576 Dentry *d; 577 578 p = getbuf(dev, addr, Bmod|Bimm); 579 memset(p->iobuf, 0, RBUFSIZE); 580 settag(p, Tdir, QPROOT); 581 d = getdir(p, 0); 582 strcpy(d->name, "/"); 583 d->uid = -1; 584 d->gid = -1; 585 d->mode = DALLOC | DDIR | 586 ((DREAD|DWRITE|DEXEC) << 6) | 587 ((DREAD|DWRITE|DEXEC) << 3) | 588 ((DREAD|DWRITE|DEXEC) << 0); 589 d->qid = QID9P1(QPROOT|QPDIR,0); 590 d->atime = time(0); 591 d->mtime = d->atime; 592 putbuf(p); 593 } 594 595 int 596 superok(Device dev, long addr, int set) 597 { 598 Iobuf *p; 599 Superb *s; 600 int ok; 601 602 p = getbuf(dev, addr, Bread|Bmod|Bimm); 603 s = (Superb*)p->iobuf; 604 ok = s->fsok; 605 s->fsok = set; 606 putbuf(p); 607 return ok; 608 } 609 610 void 611 superream(Device dev, long addr) 612 { 613 Iobuf *p; 614 Superb *s; 615 long i; 616 617 p = getbuf(dev, addr, Bmod|Bimm); 618 memset(p->iobuf, 0, RBUFSIZE); 619 settag(p, Tsuper, QPSUPER); 620 621 s = (Superb*)p->iobuf; 622 s->fstart = 1; 623 s->fsize = devsize(dev); 624 s->fbuf.nfree = 1; 625 s->qidgen = 10; 626 for(i=s->fsize-1; i>=addr+2; i--) 627 addfree(dev, i, s); 628 putbuf(p); 629 } 630 631 /* 632 * returns 1 if n is prime 633 * used for adjusting lengths 634 * of hashing things. 635 * there is no need to be clever 636 */ 637 int 638 prime(long n) 639 { 640 long i; 641 642 if((n%2) == 0) 643 return 0; 644 for(i=3;; i+=2) { 645 if((n%i) == 0) 646 return 0; 647 if(i*i >= n) 648 return 1; 649 } 650 } 651 652 void 653 hexdump(void *a, int n) 654 { 655 char s1[30], s2[4]; 656 uchar *p; 657 int i; 658 659 p = a; 660 s1[0] = 0; 661 for(i=0; i<n; i++) { 662 sprint(s2, " %.2ux", p[i]); 663 strcat(s1, s2); 664 if((i&7) == 7) { 665 print("%s\n", s1); 666 s1[0] = 0; 667 } 668 } 669 if(s1[0]) 670 print("%s\n", s1); 671 } 672 673 long 674 qidpathgen(Device *dev) 675 { 676 Iobuf *p; 677 Superb *sb; 678 long path; 679 680 p = getbuf(*dev, superaddr((*dev)), Bread|Bmod); 681 if(!p || checktag(p, Tsuper, QPSUPER)) 682 panic("newqid: super block"); 683 sb = (Superb*)p->iobuf; 684 sb->qidgen++; 685 path = sb->qidgen; 686 putbuf(p); 687 return path; 688 } 689 690