|
|
1.1 ! root 1: /* ! 2: * primitives dealing in stream blocks ! 3: */ ! 4: ! 5: #include "sys/param.h" ! 6: #include "sys/stream.h" ! 7: #include "sys/mtpr.h" ! 8: #include "sys/buf.h" ! 9: ! 10: #define M_HIPRI 127 /* for use by putbq */ ! 11: ! 12: extern struct block cblock[]; ! 13: extern struct buf *cblkbuf[]; ! 14: extern struct queue queue[]; ! 15: extern int blkcnt, blkbcnt, queuecnt; ! 16: struct queue *qhead; /* head of queues to run */ ! 17: struct queue *qtail; /* last queue */ ! 18: ! 19: /* ! 20: * blocks are kept in handful of free lists, ! 21: * each containing blocks of a particular size. ! 22: * there are MAXLEVEL sizes, each SPLITSIZE times bigger than the last. ! 23: * the system starts out with blkbcnt blocks of the largest size ! 24: * (which are in fact buffers from bio) ! 25: * and blkcnt-blkbcnt blocks of the smallest size. ! 26: * if there are no blocks of the requested size, ! 27: * larger ones are split to make some. ! 28: * the smallest blocks (level 0) are a special case: ! 29: * the data lives in the block header, ! 30: * and there's no point splitting larger blocks to make more ! 31: * because there are no headers to use after splitting. ! 32: */ ! 33: ! 34: #define MAXLEVEL 6 ! 35: #define SPLITSIZE 4 ! 36: ! 37: int rbsize[MAXLEVEL] = { 4, 16, 64, 256, 1024, 4096 }; /* real block sizes */ ! 38: int bsize[MAXLEVEL] = { 4, 16, 64, 256, 256, 256 }; /* size for q limits */ ! 39: struct block *qfreelist[MAXLEVEL]; ! 40: short blkfree[MAXLEVEL]; ! 41: short blkall[MAXLEVEL]; ! 42: short blkmax[MAXLEVEL]; ! 43: ! 44: /* ! 45: * hooks for debugging ! 46: * turn this on only if you need it; ! 47: * it's quite slow ! 48: */ ! 49: #if STDEBUG ! 50: ! 51: static int qiniting; ! 52: #define BADBP(bp) ((bp)!=&cblock[(bp)-cblock]) ! 53: ! 54: static ! 55: badfreelist(lev) ! 56: register lev; ! 57: { ! 58: register i = 0; ! 59: register struct block *bp; ! 60: ! 61: /* look for block that is already on the free list */ ! 62: for(bp=qfreelist[lev];bp!=0;bp=bp->next) ! 63: i++; ! 64: if(i!=blkfree[lev]){ ! 65: printf("blkfree[%d]==%d i==%d\n", lev, blkfree[lev], i); ! 66: panic("bad free list 1"); ! 67: } ! 68: } ! 69: ! 70: static ! 71: duplicateblock(lev, bp) ! 72: register lev; ! 73: register struct block *bp; ! 74: { ! 75: register i = 0; ! 76: register struct block *nbp; ! 77: ! 78: /* look for block that is already on the free list */ ! 79: for(nbp=qfreelist[lev];nbp!=0;nbp=nbp->next) { ! 80: if(nbp==bp) ! 81: panic("duplicate free"); ! 82: i++; ! 83: } ! 84: if(i!=blkfree[lev]){ ! 85: printf("blkfree[%d]==%d i==%d\n", lev, blkfree[lev], i); ! 86: panic("bad free list 2"); ! 87: } ! 88: } ! 89: #endif ! 90: ! 91: /* ! 92: * more debugging: trace the owner of a block ! 93: * not so slow, but very VAX-dependent. ! 94: */ ! 95: #if BLKOWNER ! 96: #define MAXOWNER 2000 /* this many blocks will be traced */ ! 97: #define CALLER(x) *(&x+5) /* x is an int, and is first auto in function */ ! 98: int blkowner[MAXOWNER]; ! 99: #endif ! 100: ! 101: qinit() ! 102: { ! 103: register i; ! 104: register struct buf *bp; ! 105: ! 106: #if STDEBUG ! 107: qiniting=1; ! 108: #endif ! 109: for (i = 0; i<blkbcnt; i++) { ! 110: if ((bp = geteblk()) == NULL) ! 111: break; /* probably not best */ ! 112: cblock[i].class = MAXLEVEL-1; ! 113: cblock[i].base = (u_char *)&bp->b_un.b_addr[0]; ! 114: cblock[i].lim = (u_char *)&bp->b_un.b_addr[bp->b_bcount]; ! 115: cblock[i].rbufix = i; ! 116: cblkbuf[i] = bp; ! 117: freeb(&cblock[i]); ! 118: } ! 119: blkall[MAXLEVEL-1] = 0; ! 120: for ( ; i<blkcnt; i++) { ! 121: cblock[i].class = 0; ! 122: cblock[i].base = &cblock[i].data[0]; ! 123: cblock[i].lim = &cblock[i].data[sizeof(cblock[0].data)]; ! 124: cblock[i].rbufix = NOBUFIX; ! 125: freeb(&cblock[i]); ! 126: } ! 127: blkall[0] = 0; ! 128: #if STDEBUG ! 129: qiniting=0; ! 130: #endif ! 131: } ! 132: ! 133: static bsplit(); ! 134: ! 135: struct block * ! 136: allocb(size) ! 137: { ! 138: #if BLKOWNER ! 139: int x; ! 140: #endif ! 141: register struct block *bp; ! 142: register lev; ! 143: register s; ! 144: ! 145: for (lev = 0; lev < MAXLEVEL; lev++) { ! 146: if (size <= rbsize[lev]) ! 147: break; ! 148: } ! 149: if (lev >= MAXLEVEL) ! 150: panic("allocb bad size"); ! 151: s = spl6(); ! 152: #if STDEBUG ! 153: badfreelist(lev); ! 154: #endif ! 155: ! 156: /* check for free block of right size */ ! 157: if ((bp = qfreelist[lev]) == NULL) { ! 158: bsplit(lev+1); /* else try to split larger block */ ! 159: if ((bp = qfreelist[lev]) == NULL) { ! 160: if (size != QBSIZE) { ! 161: splx(s); ! 162: return (allocb(QBSIZE)); /* last chance */ ! 163: } ! 164: panic("allocb no block"); ! 165: } ! 166: } ! 167: qfreelist[lev] = bp->next; ! 168: blkall[lev]++; ! 169: if (blkall[lev] > blkmax[lev]) ! 170: blkmax[lev] = blkall[lev]; ! 171: blkfree[lev]--; ! 172: #if BLKOWNER ! 173: if ((x = bp-cblock) < MAXOWNER) ! 174: blkowner[x] = CALLER(x); ! 175: #endif ! 176: splx(s); ! 177: bp->type = M_DATA; ! 178: bp->next = NULL; ! 179: bp->rptr = bp->base; ! 180: bp->wptr = bp->base; ! 181: bp->bufix = bp->rbufix; ! 182: bp->class &= ~S_DELIM; ! 183: #if STDEBUG ! 184: if (BADBP(bp)) ! 185: panic("allocb"); ! 186: #endif ! 187: return(bp); ! 188: } ! 189: ! 190: static ! 191: bsplit(lev) ! 192: register lev; ! 193: { ! 194: register struct block *bp, *bp1; ! 195: register i, size; ! 196: ! 197: if (lev>=MAXLEVEL) ! 198: return; ! 199: if ((bp = qfreelist[lev]) == NULL) { ! 200: bsplit(lev+1); ! 201: if ((bp = qfreelist[lev]) == NULL) ! 202: return; ! 203: } ! 204: qfreelist[lev] = bp->next; ! 205: blkfree[lev]--; ! 206: size = (bp->lim - bp->base)/SPLITSIZE; ! 207: lev--; /* the blocks we're creating */ ! 208: for (i=1; i<SPLITSIZE; i++) { ! 209: if ((bp1 = qfreelist[0]) == NULL) ! 210: return; ! 211: qfreelist[0] = bp1->next; ! 212: blkfree[0]--; ! 213: bp1->base = bp->base; ! 214: bp->base += size; ! 215: bp1->lim = bp1->base+size; ! 216: bp1->class = lev; ! 217: bp1->rbufix = bp->rbufix; ! 218: bp1->next = qfreelist[lev]; ! 219: qfreelist[lev] = bp1; ! 220: blkfree[lev]++; ! 221: } ! 222: bp->class = lev; ! 223: bp->next = qfreelist[lev]; ! 224: qfreelist[lev] = bp; ! 225: blkfree[lev]++; ! 226: } ! 227: ! 228: /* ! 229: * if this is a large block and its data can be squeezed ! 230: * into a smaller block, do it. ! 231: */ ! 232: struct block * ! 233: cramb(bp) ! 234: register struct block *bp; ! 235: { ! 236: register struct block *nbp; ! 237: register int n; ! 238: ! 239: n = bp->wptr - bp->rptr; ! 240: if((bp->class&CL_MASK) < 3 || n > rbsize[(bp->class&CL_MASK)-1]) ! 241: return bp; ! 242: nbp = allocb(n); ! 243: if(nbp==NULL) ! 244: return bp; ! 245: if(nbp->lim-nbp->wptr < n) { ! 246: freeb(nbp); ! 247: return bp; ! 248: } ! 249: bcopy(bp->rptr, nbp->wptr, n); ! 250: nbp->wptr += n; ! 251: nbp->type = bp->type; ! 252: if (bp->class & S_DELIM) ! 253: nbp->class |= S_DELIM; ! 254: freeb(bp); ! 255: return nbp; ! 256: } ! 257: ! 258: /* ! 259: * make a block that points to the same data ! 260: * as some existing block ! 261: */ ! 262: struct block * ! 263: dupb(bp) ! 264: register struct block *bp; ! 265: { ! 266: #if BLKOWNER ! 267: int x; ! 268: #endif ! 269: register struct block *nbp; ! 270: ! 271: if ((nbp = allocb(0)) == NULL) ! 272: return (NULL); ! 273: nbp->type = bp->type; ! 274: nbp->rptr = bp->rptr; ! 275: nbp->wptr = bp->wptr; ! 276: nbp->bufix = bp->bufix; ! 277: nbp->class |= bp->class&S_DELIM; ! 278: #if BLKOWNER ! 279: if ((x = nbp-cblock) < MAXOWNER) ! 280: blkowner[x] = CALLER(x); ! 281: #endif ! 282: return (nbp); ! 283: } ! 284: ! 285: freeb(bp) ! 286: register struct block *bp; ! 287: { ! 288: register s = spl6(); ! 289: register lev; ! 290: ! 291: lev = bp->class&CL_MASK; ! 292: #if STDEBUG ! 293: if (BADBP(bp)) ! 294: panic("freeb"); ! 295: duplicateblock(lev, bp); ! 296: if (blkall[lev] <= 0 && !qiniting) ! 297: panic("freeb excess free"); ! 298: #endif ! 299: bp->next = qfreelist[lev]; ! 300: qfreelist[lev] = bp; ! 301: blkall[lev]--; ! 302: blkfree[lev]++; ! 303: splx(s); ! 304: } ! 305: ! 306: struct block * ! 307: getq(q) ! 308: register struct queue *q; ! 309: { ! 310: #if BLKOWNER ! 311: int x; ! 312: #endif ! 313: register struct block *bp; ! 314: register s = spl6(); ! 315: ! 316: if ((bp = q->first) == NULL) { ! 317: if ((q->flag&QENAB) == 0) ! 318: q->flag |= QWANTR; ! 319: } else { ! 320: if ((q->first = bp->next) == NULL) ! 321: q->last = NULL; ! 322: q->count -= bsize[bp->class&CL_MASK]; ! 323: if (q->count < q->qinfo->limit) ! 324: q->flag &= ~QFULL; ! 325: q->flag &= ~QWANTR; ! 326: #if BLKOWNER ! 327: if ((x = bp-cblock) < MAXOWNER) ! 328: blkowner[x] = CALLER(x); ! 329: #endif ! 330: } ! 331: if (q->count<=q->qinfo->lolimit && q->flag&QWANTW && OTHERQ(q)->next) { ! 332: register struct queue *bq = backq(q); ! 333: if (bq->qinfo->srvp) ! 334: qenable(bq); ! 335: q->flag &= ~QWANTW; ! 336: } ! 337: splx(s); ! 338: #if STDEBUG ! 339: if(bp && BADBP(bp)) ! 340: panic("getq"); ! 341: #endif ! 342: return(bp); ! 343: } ! 344: ! 345: putq(q, bp) ! 346: register struct queue *q; ! 347: register struct block *bp; ! 348: { ! 349: int s; ! 350: ! 351: #if STDEBUG ! 352: if (BADBP(bp)) ! 353: panic("putq"); ! 354: #endif ! 355: if (bp->type==M_FLUSH) ! 356: flushq(q, 0); ! 357: s = spl6(); ! 358: if (q->first==NULL) { /* empty, just tack on */ ! 359: q->first = bp; ! 360: q->last = bp; ! 361: bp->next = NULL; ! 362: } else if (bp->type<QPCTL || q->last->type>=QPCTL) { /* put at end */ ! 363: register struct block *lastp = q->last; ! 364: register n = bp->wptr - bp->rptr; ! 365: if (bp->type==M_DATA && lastp->type==M_DATA ! 366: && (lastp->class&S_DELIM)==0 ! 367: && n <= lastp->lim-lastp->wptr && lastp->wptr>=lastp->base) { ! 368: bcopy(bp->rptr, lastp->wptr, n); ! 369: lastp->wptr += n; ! 370: if (bp->class&S_DELIM) ! 371: lastp->class |= S_DELIM; ! 372: freeb(bp); ! 373: bp = NULL; ! 374: } else { ! 375: lastp->next = bp; ! 376: q->last = bp; ! 377: bp->next = NULL; ! 378: } ! 379: } else { /* pri, put after any others */ ! 380: register struct block *nbp = q->first; ! 381: if (nbp->type < QPCTL) { ! 382: bp->next = q->first; ! 383: q->first = bp; ! 384: } else { ! 385: while (nbp->next->type>=QPCTL) ! 386: nbp = nbp->next; ! 387: bp->next = nbp->next; ! 388: nbp->next = bp; ! 389: } ! 390: } ! 391: if (bp) { ! 392: q->count += bsize[bp->class&CL_MASK]; ! 393: if (bp->type >= QPCTL && bp->type!= M_HIPRI) ! 394: q->flag |= QWANTR; ! 395: } ! 396: if (q->count >= q->qinfo->limit) ! 397: q->flag |= QFULL|QWANTW; ! 398: if ((q->flag & (QWANTR|QENAB|QNOENB)) == QWANTR && q->qinfo->srvp) ! 399: qenable(q); ! 400: splx(s); ! 401: } ! 402: ! 403: /* ! 404: * Put stuff back at beginning of Q ! 405: * (but after any priority msgs) ! 406: */ ! 407: putbq(q, bp) ! 408: register struct queue *q; ! 409: register struct block *bp; ! 410: { ! 411: register savetype = bp->type; ! 412: register s = spl6(); ! 413: ! 414: bp->type = M_HIPRI; /* fake priority, to force to start */ ! 415: putq(q, bp); ! 416: bp->type = savetype; ! 417: splx(s); ! 418: } ! 419: ! 420: /* ! 421: * empty a queue. Leave any non-data messages, unless flag is 1. ! 422: */ ! 423: flushq(q, flag) ! 424: register struct queue *q; ! 425: { ! 426: register struct block *bp, *nbp; ! 427: register s = spl6(); ! 428: ! 429: bp = q->first; ! 430: q->first = NULL; ! 431: if (q->last) ! 432: q->last->next = NULL; ! 433: q->last = NULL; ! 434: q->count = 0; ! 435: q->flag &= ~QFULL; ! 436: while (bp) { ! 437: nbp = bp->next; ! 438: if (bp->type != M_DATA && bp->type != M_DELIM ! 439: && bp->type != M_CTL && bp->type != M_DELAY ! 440: && bp->type != M_FLUSH && !flag) ! 441: putq(q, bp); ! 442: else { ! 443: if (bp->type == M_PASS) ! 444: printf("flushing PASS %x\n",*(int *)(bp->rptr)); ! 445: freeb(bp); ! 446: } ! 447: bp = nbp; ! 448: } ! 449: if (q->flag&QWANTW && OTHERQ(q)->next) { ! 450: q->flag &= ~QWANTW; ! 451: qenable(backq(q)); ! 452: } ! 453: splx(s); ! 454: } ! 455: ! 456: /* ! 457: * allocate a pair of queues ! 458: */ ! 459: struct queue * ! 460: allocq() ! 461: { ! 462: register struct queue *qp; ! 463: static struct queue zeroR = ! 464: { NULL,NULL,NULL,NULL,NULL,NULL,0,QUSE|QREADR}; ! 465: static struct queue zeroW = ! 466: { NULL,NULL,NULL,NULL,NULL,NULL,0,QUSE}; ! 467: ! 468: for (qp = queue; qp < &queue[queuecnt]; qp += 2) { ! 469: if ((qp->flag & QUSE) == 0) { ! 470: *qp = zeroR; ! 471: *WR(qp) = zeroW; ! 472: return(qp); ! 473: } ! 474: } ! 475: return(NULL); ! 476: } ! 477: ! 478: /* ! 479: * put routine that shouldn't be called ! 480: */ ! 481: noput(q, c) ! 482: struct queue *q; ! 483: { ! 484: panic("noput"); ! 485: } ! 486: ! 487: /* ! 488: * Put one data char on a queue, using f ! 489: */ ! 490: putd(f, q, c) ! 491: int (*f)(); ! 492: register struct queue *q; ! 493: { ! 494: register struct block *bp; ! 495: register s = spl6(); ! 496: ! 497: if (f==putq && (bp = q->last) && bp->type==M_DATA && bp->wptr<bp->lim ! 498: && (bp->class&S_DELIM)==0) { ! 499: *bp->wptr++ = c; ! 500: splx(s); ! 501: } else { ! 502: splx(s); ! 503: if ((bp = allocb(16)) == NULL) ! 504: return(0); ! 505: *bp->wptr++ = c; ! 506: (*f)(q, bp); ! 507: } ! 508: return(1); ! 509: } ! 510: ! 511: /* ! 512: * Put a block of type c on queue ! 513: */ ! 514: putctl(q, c) ! 515: struct queue *q; ! 516: { ! 517: register struct block *bp; ! 518: ! 519: if ((bp = allocb(0)) == NULL) ! 520: return(0); ! 521: bp->type = c; ! 522: (*q->qinfo->putp)(q, bp); ! 523: return(1); ! 524: } ! 525: ! 526: /* ! 527: * Put a block of type c, delimited, on queue ! 528: */ ! 529: putctld(q, c) ! 530: struct queue *q; ! 531: { ! 532: register struct block *bp; ! 533: ! 534: if ((bp = allocb(0)) == NULL) ! 535: return(0); ! 536: bp->type = c; ! 537: bp->class |= S_DELIM; ! 538: (*q->qinfo->putp)(q, bp); ! 539: return(1); ! 540: } ! 541: ! 542: /* ! 543: * Block of type c, with one byte of data ! 544: */ ! 545: putctl1(q, c, p) ! 546: struct queue *q; ! 547: { ! 548: register struct block *bp; ! 549: ! 550: if ((bp = allocb(1)) == NULL) ! 551: return(0); ! 552: bp->type = c; ! 553: *bp->wptr++ = p; ! 554: (*q->qinfo->putp)(q, bp); ! 555: return(1); ! 556: } ! 557: ! 558: /* ! 559: * Block of type c, delimited, with one byte of data ! 560: */ ! 561: putctl1d(q, c, p) ! 562: struct queue *q; ! 563: { ! 564: register struct block *bp; ! 565: ! 566: if ((bp = allocb(1)) == NULL) ! 567: return(0); ! 568: bp->type = c; ! 569: bp->class |= S_DELIM; ! 570: *bp->wptr++ = p; ! 571: (*q->qinfo->putp)(q, bp); ! 572: return(1); ! 573: } ! 574: ! 575: /* ! 576: * block with two parameters ! 577: */ ! 578: putctl2(q, c, p1, p2) ! 579: struct queue *q; ! 580: { ! 581: register struct block *bp; ! 582: ! 583: if ((bp = allocb(2)) == NULL) ! 584: return(0); ! 585: bp->type = c; ! 586: *bp->wptr++ = p1; ! 587: *bp->wptr++ = p2; ! 588: (*q->qinfo->putp)(q, bp); ! 589: return(1); ! 590: } ! 591: ! 592: /* ! 593: * put control record, using putq instead of queue's putp ! 594: */ ! 595: qpctl(q, d) ! 596: register struct queue *q; ! 597: { ! 598: register struct block *bp = allocb(1); ! 599: ! 600: if (bp) { ! 601: bp->type = d; ! 602: putq(q, bp); ! 603: } ! 604: } ! 605: ! 606: qpctl1(q, c, d) ! 607: register struct queue *q; ! 608: { ! 609: register struct block *bp = allocb(1); ! 610: ! 611: if (bp) { ! 612: bp->type = c; ! 613: *bp->wptr++ = d; ! 614: putq(q, bp); ! 615: } ! 616: } ! 617: ! 618: qpctld(q, d) ! 619: register struct queue *q; ! 620: { ! 621: register struct block *bp = allocb(1); ! 622: ! 623: if (bp) { ! 624: bp->type = d; ! 625: bp->class |= S_DELIM; ! 626: putq(q, bp); ! 627: } ! 628: } ! 629: ! 630: /* ! 631: * Copy a literal record onto queue ! 632: */ ! 633: putcpy(q, cp, n) ! 634: register struct queue *q; ! 635: register char *cp; ! 636: { ! 637: register struct block *bp; ! 638: register nm; ! 639: ! 640: while (n) { ! 641: if ((bp = allocb(n)) == NULL) /* sorry */ ! 642: return; ! 643: bp->type = M_DATA; ! 644: nm = bp->lim - bp->wptr; ! 645: if (nm > n) ! 646: nm = n; ! 647: bcopy(cp, bp->wptr, nm); ! 648: cp += nm; ! 649: bp->wptr += nm; ! 650: n -= nm; ! 651: (*q->qinfo->putp)(q, bp); ! 652: } ! 653: } ! 654: ! 655: /* ! 656: * return the queue upstream from this one ! 657: */ ! 658: struct queue * ! 659: backq(q) ! 660: register struct queue *q; ! 661: { ! 662: q = OTHERQ(q); ! 663: if (q->next) { ! 664: q = q->next; ! 665: return(OTHERQ(q)); ! 666: } ! 667: q = OTHERQ(q); ! 668: printf("backq called with no back (Q %x)\n", q); ! 669: panic("backq"); ! 670: return(NULL); ! 671: } ! 672: ! 673: /* ! 674: * Send a block back up the queue in reverse from this ! 675: * one (e.g. to respond to ioctls) ! 676: */ ! 677: qreply(q, bp) ! 678: register struct queue *q; ! 679: struct block *bp; ! 680: { ! 681: q = OTHERQ(q); ! 682: (*q->next->qinfo->putp)(q->next, bp); ! 683: } ! 684: ! 685: /* ! 686: * Enable a queue: put it on list of those whose srvp's are ! 687: * ready to run. ! 688: */ ! 689: qenable(q) ! 690: register struct queue *q; ! 691: { ! 692: register s; ! 693: ! 694: s = spl6(); ! 695: if (q->flag & QENAB) { ! 696: splx(s); ! 697: return; ! 698: } ! 699: if (q->qinfo->srvp==NULL) { ! 700: splx(s); ! 701: return; ! 702: } ! 703: q->flag |= QENAB; ! 704: q->link = NULL; ! 705: if (qhead==NULL) ! 706: qhead = q; ! 707: else ! 708: qtail->link = q; ! 709: qtail = q; ! 710: setqsched(); ! 711: splx(s); ! 712: } ! 713: ! 714: /* ! 715: * Run the srvp's of each enabled queue ! 716: * -- Should not be reentered ! 717: */ ! 718: queuerun() ! 719: { ! 720: register struct queue *q; ! 721: register s; ! 722: extern int queueflag; ! 723: extern char *panicstr; ! 724: ! 725: if (panicstr) ! 726: return; /* to minimize destruction */ ! 727: s = spl6(); ! 728: queueflag++; ! 729: while (q = qhead) { ! 730: if ((qhead = q->link) == NULL) ! 731: qtail = NULL; ! 732: q->flag &= ~QENAB; ! 733: splx(s); ! 734: if (q->qinfo->srvp != NULL) ! 735: (*q->qinfo->srvp)(q); ! 736: else ! 737: printf("Q %x run with no srvp\n", q); ! 738: spl6(); ! 739: } ! 740: queueflag--; ! 741: splx(s); ! 742: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.