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 qid.type = 0; 360 putbuf(p); 361 return qid; 362 } 363 364 /* 365 * what are legal characters in a name? 366 * only disallow control characters. 367 * a) utf avoids control characters. 368 * b) '/' may not be the separator 369 */ 370 int 371 checkname(char *n) 372 { 373 int i, c; 374 375 for(i=0; i<NAMELEN; i++) { 376 c = *n & 0xff; 377 if(c == 0) { 378 if(i == 0) 379 return 1; 380 memset(n, 0, NAMELEN-i); 381 return 0; 382 } 383 if(c <= 040) 384 return 1; 385 n++; 386 } 387 return 1; /* too long */ 388 } 389 390 void 391 bfree(Device dev, long addr, int d) 392 { 393 Iobuf *p; 394 long a; 395 int i; 396 397 if(!addr) 398 return; 399 if(d > 0) { 400 d--; 401 p = getbuf(dev, addr, Bread); 402 if(p) { 403 for(i=INDPERBUF-1; i>=0; i--) { 404 a = ((long*)p->iobuf)[i]; 405 bfree(dev, a, d); 406 } 407 putbuf(p); 408 } 409 } 410 /* 411 * stop outstanding i/o 412 */ 413 p = getbuf(dev, addr, Bprobe); 414 if(p) { 415 p->flags &= ~(Bmod|Bimm); 416 putbuf(p); 417 } 418 /* 419 * dont put written worm 420 * blocks into free list 421 */ 422 if(nofree(dev, addr)) 423 return; 424 p = getbuf(dev, superaddr(dev), Bread|Bmod); 425 if(!p || checktag(p, Tsuper, QPSUPER)) 426 panic("bfree: super block"); 427 addfree(dev, addr, (Superb*)p->iobuf); 428 putbuf(p); 429 } 430 431 long 432 balloc(Device dev, int tag, long qid) 433 { 434 Iobuf *bp, *p; 435 Superb *sb; 436 long a; 437 int n; 438 439 p = getbuf(dev, superaddr(dev), Bread|Bmod); 440 if(!p || checktag(p, Tsuper, QPSUPER)) 441 panic("balloc: super block"); 442 sb = (Superb*)p->iobuf; 443 444 loop: 445 n = --sb->fbuf.nfree; 446 sb->tfree--; 447 if(n < 0 || n >= FEPERBUF) 448 panic("balloc: bad freelist"); 449 a = sb->fbuf.free[n]; 450 if(n <= 0) { 451 if(a == 0) { 452 sb->tfree = 0; 453 sb->fbuf.nfree = 1; 454 if(devgrow(dev, sb)) 455 goto loop; 456 putbuf(p); 457 return 0; 458 } 459 bp = getbuf(dev, a, Bread); 460 if(!bp || checktag(bp, Tfree, QPNONE)) { 461 if(bp) 462 putbuf(bp); 463 putbuf(p); 464 return 0; 465 } 466 memmove(&sb->fbuf, bp->iobuf, (FEPERBUF+1)*sizeof(long)); 467 putbuf(bp); 468 } 469 bp = getbuf(dev, a, Bmod); 470 memset(bp->iobuf, 0, RBUFSIZE); 471 settag(bp, tag, qid); 472 if(tag == Tind1 || tag == Tind2 || tag == Tdir) 473 bp->flags |= Bimm; 474 putbuf(bp); 475 putbuf(p); 476 return a; 477 } 478 479 void 480 addfree(Device dev, long addr, Superb *sb) 481 { 482 int n; 483 Iobuf *p; 484 485 if(addr >= sb->fsize){ 486 print("addfree: bad addr %lux\n", addr); 487 return; 488 } 489 n = sb->fbuf.nfree; 490 if(n < 0 || n > FEPERBUF) 491 panic("addfree: bad freelist"); 492 if(n >= FEPERBUF) { 493 p = getbuf(dev, addr, Bmod); 494 if(p == 0) 495 panic("addfree: getbuf"); 496 memmove(p->iobuf, &sb->fbuf, (FEPERBUF+1)*sizeof(long)); 497 settag(p, Tfree, QPNONE); 498 putbuf(p); 499 n = 0; 500 } 501 sb->fbuf.free[n++] = addr; 502 sb->fbuf.nfree = n; 503 sb->tfree++; 504 if(addr >= sb->fsize) 505 sb->fsize = addr+1; 506 } 507 508 int 509 Cfmt(Fmt *f1) 510 { 511 Chan *cp; 512 513 cp = va_arg(f1->args, Chan*); 514 return fmtprint(f1, "C%d.%.3d", cp->type, cp->chan); 515 } 516 517 int 518 Dfmt(Fmt *f1) 519 { 520 Device d; 521 522 d = va_arg(f1->args, Device); 523 return fmtprint(f1, "D%d.%d.%d.%d", d.type, d.ctrl, d.unit, d.part); 524 } 525 526 int 527 Afmt(Fmt *f1) 528 { 529 Filta a; 530 531 a = va_arg(f1->args, Filta); 532 return fmtprint(f1, "%6lud %6lud %6lud", 533 fdf(a.f->filter[0], a.scale*60), 534 fdf(a.f->filter[1], a.scale*600), 535 fdf(a.f->filter[2], a.scale*6000)); 536 } 537 538 int 539 Gfmt(Fmt *f1) 540 { 541 int t; 542 543 t = va_arg(f1->args, int); 544 if(t >= 0 && t < MAXTAG) 545 return fmtstrcpy(f1, tagnames[t]); 546 else 547 return fmtprint(f1, "<badtag %d>", t); 548 } 549 550 void 551 formatinit(void) 552 { 553 554 fmtinstall('C', Cfmt); /* print channels */ 555 fmtinstall('D', Dfmt); /* print devices */ 556 fmtinstall('A', Afmt); /* print filters */ 557 fmtinstall('G', Gfmt); /* print tags */ 558 fmtinstall('T', Tfmt); /* print times */ 559 fmtinstall('O', ofcallfmt); /* print old fcalls */ 560 } 561 int 562 devcmp(Device d1, Device d2) 563 { 564 565 if(d1.type == d2.type) 566 if(d1.ctrl == d2.ctrl) 567 if(d1.unit == d2.unit) 568 if(d1.part == d2.part) 569 return 0; 570 return 1; 571 } 572 573 void 574 rootream(Device dev, long addr) 575 { 576 Iobuf *p; 577 Dentry *d; 578 579 p = getbuf(dev, addr, Bmod|Bimm); 580 memset(p->iobuf, 0, RBUFSIZE); 581 settag(p, Tdir, QPROOT); 582 d = getdir(p, 0); 583 strcpy(d->name, "/"); 584 d->uid = -1; 585 d->gid = -1; 586 d->mode = DALLOC | DDIR | 587 ((DREAD|DWRITE|DEXEC) << 6) | 588 ((DREAD|DWRITE|DEXEC) << 3) | 589 ((DREAD|DWRITE|DEXEC) << 0); 590 d->qid = QID9P1(QPROOT|QPDIR,0); 591 d->atime = time(0); 592 d->mtime = d->atime; 593 putbuf(p); 594 } 595 596 int 597 superok(Device dev, long addr, int set) 598 { 599 Iobuf *p; 600 Superb *s; 601 int ok; 602 603 p = getbuf(dev, addr, Bread|Bmod|Bimm); 604 s = (Superb*)p->iobuf; 605 ok = s->fsok; 606 s->fsok = set; 607 putbuf(p); 608 return ok; 609 } 610 611 void 612 superream(Device dev, long addr) 613 { 614 Iobuf *p; 615 Superb *s; 616 long i; 617 618 p = getbuf(dev, addr, Bmod|Bimm); 619 memset(p->iobuf, 0, RBUFSIZE); 620 settag(p, Tsuper, QPSUPER); 621 622 s = (Superb*)p->iobuf; 623 s->fstart = 1; 624 s->fsize = devsize(dev); 625 s->fbuf.nfree = 1; 626 s->qidgen = 10; 627 for(i=s->fsize-1; i>=addr+2; i--) 628 addfree(dev, i, s); 629 putbuf(p); 630 } 631 632 /* 633 * returns 1 if n is prime 634 * used for adjusting lengths 635 * of hashing things. 636 * there is no need to be clever 637 */ 638 int 639 prime(long n) 640 { 641 long i; 642 643 if((n%2) == 0) 644 return 0; 645 for(i=3;; i+=2) { 646 if((n%i) == 0) 647 return 0; 648 if(i*i >= n) 649 return 1; 650 } 651 } 652 653 void 654 hexdump(void *a, int n) 655 { 656 char s1[30], s2[4]; 657 uchar *p; 658 int i; 659 660 p = a; 661 s1[0] = 0; 662 for(i=0; i<n; i++) { 663 sprint(s2, " %.2ux", p[i]); 664 strcat(s1, s2); 665 if((i&7) == 7) { 666 print("%s\n", s1); 667 s1[0] = 0; 668 } 669 } 670 if(s1[0]) 671 print("%s\n", s1); 672 } 673 674 long 675 qidpathgen(Device *dev) 676 { 677 Iobuf *p; 678 Superb *sb; 679 long path; 680 681 p = getbuf(*dev, superaddr((*dev)), Bread|Bmod); 682 if(!p || checktag(p, Tsuper, QPSUPER)) 683 panic("newqid: super block"); 684 sb = (Superb*)p->iobuf; 685 sb->qidgen++; 686 path = sb->qidgen; 687 putbuf(p); 688 return path; 689 } 690 691