|
|
1.1 ! root 1: #include "sys/param.h" ! 2: #include "sys/user.h" ! 3: #include "sys/buf.h" ! 4: #include "sys/conf.h" ! 5: #include "sys/proc.h" ! 6: #include "sys/pte.h" ! 7: #include "sys/vm.h" ! 8: ! 9: /* ! 10: * The following several routines allocate and free ! 11: * buffers with various side effects. In general the ! 12: * arguments to an allocate routine are a device and ! 13: * a block number, and the value is a pointer to ! 14: * to the buffer header; the buffer is marked "busy" ! 15: * so that no one else can touch it. If the block was ! 16: * already in core, no I/O need be done; if it is ! 17: * already busy, the process waits until it becomes free. ! 18: * The following routines allocate a buffer: ! 19: * getblk ! 20: * bread ! 21: * breada ! 22: * baddr (if it is incore) ! 23: * Eventually the buffer must be released, possibly with the ! 24: * side effect of writing it out, by using one of ! 25: * bwrite ! 26: * bdwrite ! 27: * bawrite ! 28: * brelse ! 29: */ ! 30: ! 31: struct buf bfreelist[BQUEUES]; ! 32: struct buf bswlist, *bclnlist; ! 33: ! 34: extern int bufhcnt; ! 35: extern struct bufhd bufhash[]; ! 36: #define BUFHASH(dev, dblkno) \ ! 37: ((struct buf *)&bufhash[((int)(dev)+(int)(dblkno)) % bufhcnt]) ! 38: ! 39: /* ! 40: * Initialize hash links for buffers. ! 41: */ ! 42: bhinit() ! 43: { ! 44: register int i; ! 45: register struct bufhd *bp; ! 46: ! 47: for (bp = bufhash, i = 0; i < bufhcnt; i++, bp++) ! 48: bp->b_forw = bp->b_back = (struct buf *)bp; ! 49: } ! 50: ! 51: #define DISKMON 1 ! 52: ! 53: #ifdef DISKMON ! 54: struct { ! 55: long ndwrite; /* bdwrite, not real io */ ! 56: long nread; /* someone's waiting for this one */ ! 57: long nreada; /* readahead from disk */ ! 58: long ncache; /* blocks found in cache, so not read */ ! 59: long nwrite; /* acutally written */ ! 60: long bufcount[64]; ! 61: } io_info; ! 62: #endif ! 63: ! 64: #define CECMON 0 ! 65: ! 66: #define CFS 64 ! 67: ! 68: #ifdef CECMON ! 69: struct { ! 70: long cread; /* someone's waiting for this one */ ! 71: long creada; /* readahead from disk */ ! 72: long ccache; /* blocks found in cache, so not read */ ! 73: long cwrite; /* acutally written */ ! 74: } cec_info[CFS]; ! 75: #endif ! 76: ! 77: ! 78: /* ! 79: * Swap IO headers - ! 80: * They contain the necessary information for the swap I/O. ! 81: * At any given time, a swap header can be in three ! 82: * different lists. When free it is in the free list, ! 83: * when allocated and the I/O queued, it is on the swap ! 84: * device list, and finally, if the operation was a dirty ! 85: * page push, when the I/O completes, it is inserted ! 86: * in a list of cleaned pages to be processed by the pageout daemon. ! 87: */ ! 88: extern struct buf swapbuf[]; ! 89: extern struct swapinfo swapinfo[]; ! 90: ! 91: #ifndef UNFAST ! 92: #define notavail(bp) \ ! 93: { \ ! 94: int s = spl6(); \ ! 95: (bp)->av_back->av_forw = (bp)->av_forw; \ ! 96: (bp)->av_forw->av_back = (bp)->av_back; \ ! 97: (bp)->b_flags |= B_BUSY; \ ! 98: splx(s); \ ! 99: } ! 100: #endif ! 101: ! 102: /* ! 103: * Read in (if necessary) the block and return a buffer pointer. ! 104: */ ! 105: struct buf * ! 106: bread(dev, blkno) ! 107: dev_t dev; ! 108: daddr_t blkno; ! 109: { ! 110: register struct buf *bp; ! 111: #ifdef CECMON ! 112: register int sub; ! 113: #endif ! 114: ! 115: bp = getblk(dev, blkno); ! 116: if (bp->b_flags&B_DONE) { ! 117: #ifdef DISKMON ! 118: io_info.ncache++; ! 119: #endif ! 120: #ifdef CECMON ! 121: sub = minor(dev); ! 122: cec_info[(sub >= CFS)?(sub - CFS) : sub].ccache++; ! 123: #endif ! 124: return(bp); ! 125: } ! 126: bp->b_flags |= B_READ; ! 127: bp->b_bcount = BSIZE(dev); ! 128: (*bdevsw[major(dev)]->d_strategy)(bp); ! 129: #ifdef DISKMON ! 130: io_info.nread++; ! 131: #endif ! 132: #ifdef CECMON ! 133: sub = minor(dev); ! 134: cec_info[(sub >= CFS)?(sub - CFS) : sub].cread++; ! 135: #endif ! 136: u.u_vm.vm_inblk++; /* pay for read */ ! 137: iowait(bp); ! 138: return(bp); ! 139: } ! 140: ! 141: /* ! 142: * Read in the block, like bread, but also start I/O on the ! 143: * read-ahead block (which is not allocated to the caller) ! 144: */ ! 145: struct buf * ! 146: breada(dev, blkno, rablkno) ! 147: dev_t dev; ! 148: daddr_t blkno, rablkno; ! 149: { ! 150: register struct buf *bp, *rabp; ! 151: #ifdef CECMON ! 152: register int sub; ! 153: #endif ! 154: ! 155: bp = NULL; ! 156: if (!incore(dev, blkno)) { ! 157: bp = getblk(dev, blkno); ! 158: if ((bp->b_flags&B_DONE) == 0) { ! 159: bp->b_flags |= B_READ; ! 160: bp->b_bcount = BSIZE(dev); ! 161: (*bdevsw[major(dev)]->d_strategy)(bp); ! 162: #ifdef DISKMON ! 163: io_info.nread++; ! 164: #endif ! 165: #ifdef CECMON ! 166: sub = minor(dev); ! 167: cec_info[(sub >= CFS) ? (sub - CFS) : sub].cread++; ! 168: #endif ! 169: u.u_vm.vm_inblk++; /* pay for read */ ! 170: } ! 171: } ! 172: if (rablkno && !incore(dev, rablkno)) { ! 173: rabp = getblk(dev, rablkno); ! 174: if (rabp->b_flags & B_DONE) { ! 175: brelse(rabp); ! 176: } else { ! 177: rabp->b_flags |= B_READ|B_ASYNC; ! 178: rabp->b_bcount = BSIZE(dev); ! 179: (*bdevsw[major(dev)]->d_strategy)(rabp); ! 180: #ifdef DISKMON ! 181: io_info.nreada++; ! 182: #endif ! 183: #ifdef CECMON ! 184: sub = minor(dev); ! 185: cec_info[(sub >= CFS) ? (sub - CFS) : sub].creada++; ! 186: #endif ! 187: u.u_vm.vm_inblk++; /* pay in advance */ ! 188: } ! 189: } ! 190: if(bp == NULL) ! 191: return(bread(dev, blkno)); ! 192: iowait(bp); ! 193: return(bp); ! 194: } ! 195: ! 196: /* ! 197: * Write the buffer, waiting for completion. ! 198: * Then release the buffer. ! 199: */ ! 200: bwrite(bp) ! 201: register struct buf *bp; ! 202: { ! 203: register flag; ! 204: #ifdef CECMON ! 205: register int sub; ! 206: #endif ! 207: ! 208: flag = bp->b_flags; ! 209: bp->b_flags &= ~(B_READ | B_DONE | B_ERROR | B_DELWRI | B_AGE); ! 210: bp->b_bcount = BSIZE(bp->b_dev); ! 211: #ifdef DISKMON ! 212: io_info.nwrite++; ! 213: #endif ! 214: #ifdef CECMON ! 215: sub = minor(bp->b_dev); ! 216: cec_info[(sub >= CFS) ? (sub - CFS) : sub].cwrite++; ! 217: #endif ! 218: if ((flag&B_DELWRI) == 0) ! 219: u.u_vm.vm_oublk++; /* noone paid yet */ ! 220: (*bdevsw[major(bp->b_dev)]->d_strategy)(bp); ! 221: if ((flag&B_ASYNC) == 0) { ! 222: iowait(bp); ! 223: brelse(bp); ! 224: } else if (flag & B_DELWRI) ! 225: bp->b_flags |= B_AGE; ! 226: else ! 227: geterror(bp); ! 228: } ! 229: ! 230: /* ! 231: * Release the buffer, marking it so that if it is grabbed ! 232: * for another purpose it will be written out before being ! 233: * given up (e.g. when writing a partial block where it is ! 234: * assumed that another write for the same block will soon follow). ! 235: * This can't be done for magtape, since writes must be done ! 236: * in the same order as requested. ! 237: */ ! 238: bdwrite(bp) ! 239: register struct buf *bp; ! 240: { ! 241: ! 242: if ((bp->b_flags&B_DELWRI) == 0) ! 243: u.u_vm.vm_oublk++; /* noone paid yet */ ! 244: if(bdevsw[major(bp->b_dev)]->d_flags & B_TAPE) ! 245: bawrite(bp); ! 246: else { ! 247: #ifdef DISKMON ! 248: io_info.ndwrite++; ! 249: #endif ! 250: bp->b_flags |= B_DELWRI | B_DONE; ! 251: brelse(bp); ! 252: } ! 253: } ! 254: ! 255: /* ! 256: * Release the buffer, start I/O on it, but don't wait for completion. ! 257: */ ! 258: bawrite(bp) ! 259: register struct buf *bp; ! 260: { ! 261: ! 262: bp->b_flags |= B_ASYNC; ! 263: bwrite(bp); ! 264: } ! 265: ! 266: /* ! 267: * release the buffer, with no I/O implied. ! 268: */ ! 269: brelse(bp) ! 270: register struct buf *bp; ! 271: { ! 272: register struct buf *flist; ! 273: register s; ! 274: ! 275: if (bp->b_flags&B_WANTED) ! 276: wakeup((caddr_t)bp); ! 277: if (bfreelist[0].b_flags&B_WANTED) { ! 278: bfreelist[0].b_flags &= ~B_WANTED; ! 279: wakeup((caddr_t)bfreelist); ! 280: } ! 281: if (bp->b_flags&B_ERROR) ! 282: if (bp->b_flags & B_LOCKED) ! 283: bp->b_flags &= ~B_ERROR; /* try again later */ ! 284: else ! 285: bp->b_dev = NODEV; /* no assoc */ ! 286: s = spl6(); ! 287: if (bp->b_flags & (B_ERROR|B_INVAL)) { ! 288: /* block has no info ... put at front of most free list */ ! 289: flist = &bfreelist[BQUEUES-1]; ! 290: flist->av_forw->av_back = bp; ! 291: bp->av_forw = flist->av_forw; ! 292: flist->av_forw = bp; ! 293: bp->av_back = flist; ! 294: } else { ! 295: if (bp->b_flags & B_LOCKED) ! 296: flist = &bfreelist[BQ_LOCKED]; ! 297: else if (bp->b_flags & B_AGE) ! 298: flist = &bfreelist[BQ_AGE]; ! 299: else ! 300: flist = &bfreelist[BQ_LRU]; ! 301: flist->av_back->av_forw = bp; ! 302: bp->av_back = flist->av_back; ! 303: flist->av_back = bp; ! 304: bp->av_forw = flist; ! 305: } ! 306: bp->b_flags &= ~(B_WANTED|B_BUSY|B_ASYNC|B_AGE); ! 307: splx(s); ! 308: } ! 309: ! 310: /* ! 311: * See if the block is associated with some buffer ! 312: * (mainly to avoid getting hung up on a wait in breada) ! 313: */ ! 314: incore(dev, blkno) ! 315: dev_t dev; ! 316: daddr_t blkno; ! 317: { ! 318: register struct buf *bp; ! 319: register struct buf *dp; ! 320: register int dblkno = fsbtodb(dev, blkno); ! 321: ! 322: dp = BUFHASH(dev, dblkno); ! 323: for (bp = dp->b_forw; bp != dp; bp = bp->b_forw) ! 324: if (bp->b_blkno == dblkno && bp->b_dev == dev && ! 325: !(bp->b_flags & B_INVAL)) ! 326: return (1); ! 327: return (0); ! 328: } ! 329: ! 330: struct buf * ! 331: baddr(dev, blkno) ! 332: dev_t dev; ! 333: daddr_t blkno; ! 334: { ! 335: ! 336: if (incore(dev, blkno)) ! 337: return (bread(dev, blkno)); ! 338: return (0); ! 339: } ! 340: ! 341: /* ! 342: * Assign a buffer for the given block. If the appropriate ! 343: * block is already associated, return it; otherwise search ! 344: * for the oldest non-busy buffer and reassign it. ! 345: */ ! 346: struct buf * ! 347: getblk(dev, blkno) ! 348: dev_t dev; ! 349: daddr_t blkno; ! 350: { ! 351: register struct buf *bp, *dp, *ep; ! 352: register daddr_t dblkno; ! 353: #ifdef DISKMON ! 354: register int i; ! 355: #endif ! 356: ! 357: if ((unsigned)blkno >= 1 << (sizeof(int)*NBBY-PGSHIFT)) ! 358: blkno = 1 << ((sizeof(int)*NBBY-PGSHIFT) + 1); ! 359: dblkno = fsbtodb(dev, blkno); ! 360: dp = BUFHASH(dev, dblkno); ! 361: loop: ! 362: (void) spl0(); ! 363: for (bp = dp->b_forw; bp != dp; bp = bp->b_forw) { ! 364: if (bp->b_blkno != dblkno || bp->b_dev != dev || ! 365: bp->b_flags&B_INVAL) ! 366: continue; ! 367: (void) spl6(); ! 368: if (bp->b_flags&B_BUSY) { ! 369: bp->b_flags |= B_WANTED; ! 370: sleep((caddr_t)bp, PRIBIO+1); ! 371: goto loop; ! 372: } ! 373: (void) spl0(); ! 374: #ifdef DISKMON ! 375: i = 0; ! 376: dp = bp->av_forw; ! 377: while ((dp->b_flags & B_HEAD) == 0) { ! 378: i++; ! 379: dp = dp->av_forw; ! 380: } ! 381: if (i<64) ! 382: io_info.bufcount[i]++; ! 383: #endif ! 384: notavail(bp); ! 385: return(bp); ! 386: } ! 387: if (major(dev) >= nblkdev) ! 388: panic("blkdev"); ! 389: (void) spl6(); ! 390: for (ep = &bfreelist[BQUEUES-1]; ep > bfreelist; ep--) ! 391: if (ep->av_forw != ep) ! 392: break; ! 393: if (ep == bfreelist) { /* no free blocks at all */ ! 394: ep->b_flags |= B_WANTED; ! 395: sleep((caddr_t)ep, PRIBIO+1); ! 396: goto loop; ! 397: } ! 398: (void) spl0(); ! 399: bp = ep->av_forw; ! 400: notavail(bp); ! 401: if (bp->b_flags & B_DELWRI) { ! 402: bp->b_flags |= B_ASYNC; ! 403: bwrite(bp); ! 404: goto loop; ! 405: } ! 406: bp->b_flags = B_BUSY; ! 407: bp->b_back->b_forw = bp->b_forw; ! 408: bp->b_forw->b_back = bp->b_back; ! 409: bp->b_forw = dp->b_forw; ! 410: bp->b_back = dp; ! 411: dp->b_forw->b_back = bp; ! 412: dp->b_forw = bp; ! 413: bp->b_dev = dev; ! 414: bp->b_blkno = dblkno; ! 415: return(bp); ! 416: } ! 417: ! 418: /* ! 419: * get an empty block, ! 420: * not assigned to any particular device ! 421: */ ! 422: struct buf * ! 423: geteblk() ! 424: { ! 425: register struct buf *bp, *dp; ! 426: register int s; ! 427: ! 428: loop: ! 429: s = spl6(); ! 430: for (dp = &bfreelist[BQUEUES-1]; dp > bfreelist; dp--) ! 431: if (dp->av_forw != dp) ! 432: break; ! 433: if (dp == bfreelist) { /* no free blocks */ ! 434: dp->b_flags |= B_WANTED; ! 435: sleep((caddr_t)dp, PRIBIO+1); ! 436: goto loop; ! 437: } ! 438: (void) splx(s); ! 439: bp = dp->av_forw; ! 440: notavail(bp); ! 441: if (bp->b_flags & B_DELWRI) { ! 442: bp->b_flags |= B_ASYNC; ! 443: bwrite(bp); ! 444: goto loop; ! 445: } ! 446: bp->b_flags = B_BUSY|B_INVAL; ! 447: bp->b_back->b_forw = bp->b_forw; ! 448: bp->b_forw->b_back = bp->b_back; ! 449: bp->b_forw = dp->b_forw; ! 450: bp->b_back = dp; ! 451: dp->b_forw->b_back = bp; ! 452: dp->b_forw = bp; ! 453: bp->b_dev = (dev_t)NODEV; ! 454: bp->b_bcount = BUFSIZE; ! 455: return(bp); ! 456: } ! 457: ! 458: /* ! 459: * Wait for I/O completion on the buffer; return errors ! 460: * to the user. ! 461: */ ! 462: iowait(bp) ! 463: register struct buf *bp; ! 464: { ! 465: ! 466: (void) spl6(); ! 467: while ((bp->b_flags&B_DONE)==0) ! 468: sleep((caddr_t)bp, PRIBIO); ! 469: (void) spl0(); ! 470: geterror(bp); ! 471: } ! 472: ! 473: #ifdef UNFAST ! 474: /* ! 475: * Unlink a buffer from the available list and mark it busy. ! 476: * (internal interface) ! 477: */ ! 478: notavail(bp) ! 479: register struct buf *bp; ! 480: { ! 481: register s; ! 482: ! 483: s = spl6(); ! 484: bp->av_back->av_forw = bp->av_forw; ! 485: bp->av_forw->av_back = bp->av_back; ! 486: bp->b_flags |= B_BUSY; ! 487: splx(s); ! 488: } ! 489: #endif ! 490: ! 491: /* ! 492: * Mark I/O complete on a buffer. If the header ! 493: * indicates a dirty page push completion, the ! 494: * header is inserted into the ``cleaned'' list ! 495: * to be processed by the pageout daemon. Otherwise ! 496: * release it if I/O is asynchronous, and wake ! 497: * up anyone waiting for it. ! 498: */ ! 499: iodone(bp) ! 500: register struct buf *bp; ! 501: { ! 502: register int s; ! 503: ! 504: if (bp->b_flags & B_DONE) ! 505: panic("dup iodone"); ! 506: bp->b_flags |= B_DONE; ! 507: if (bp->b_flags & B_DIRTY) { ! 508: if (bp->b_flags & B_ERROR) ! 509: panic("IO err in push"); ! 510: s = spl6(); ! 511: bp->av_forw = bclnlist; ! 512: bp->b_bcount = swapinfo[bp - swapbuf].swsize; ! 513: bp->b_pfcent = swapinfo[bp - swapbuf].swpf; ! 514: cnt.v_pgout++; ! 515: cnt.v_pgpgout += bp->b_bcount / NBPG; ! 516: bclnlist = bp; ! 517: if (bswlist.b_flags & B_WANTED) ! 518: wakeup((caddr_t)&proc[PAGEPID]); ! 519: splx(s); ! 520: return; ! 521: } ! 522: if (bp->b_flags&B_ASYNC) ! 523: brelse(bp); ! 524: else { ! 525: bp->b_flags &= ~B_WANTED; ! 526: wakeup((caddr_t)bp); ! 527: } ! 528: } ! 529: ! 530: /* ! 531: * Zero the core associated with a buffer. ! 532: */ ! 533: clrbuf(bp) ! 534: struct buf *bp; ! 535: { ! 536: register *p; ! 537: register c; ! 538: ! 539: p = bp->b_un.b_words; ! 540: c = BUFSIZE/sizeof(int); ! 541: do ! 542: *p++ = 0; ! 543: while (--c); ! 544: bp->b_resid = 0; ! 545: } ! 546: ! 547: /* ! 548: * swap I/O - ! 549: * ! 550: * If the flag indicates a dirty page push initiated ! 551: * by the pageout daemon, we map the page into the i th ! 552: * virtual page of process 2 (the daemon itself) where i is ! 553: * the index of the swap header that has been allocated. ! 554: * We simply initialize the header and queue the I/O but ! 555: * do not wait for completion. When the I/O completes, ! 556: * iodone() will link the header to a list of cleaned ! 557: * pages to be processed by the pageout daemon. ! 558: */ ! 559: swap(p, dblkno, addr, nbytes, rdflg, flag, dev, pfcent) ! 560: struct proc *p; ! 561: swblk_t dblkno; ! 562: caddr_t addr; ! 563: int flag, nbytes; ! 564: dev_t dev; ! 565: unsigned pfcent; ! 566: { ! 567: register struct buf *bp; ! 568: register int c; ! 569: int p2dp; ! 570: register struct pte *dpte, *vpte; ! 571: ! 572: (void) spl6(); ! 573: while (bswlist.av_forw == NULL) { ! 574: bswlist.b_flags |= B_WANTED; ! 575: sleep((caddr_t)&bswlist, PSWP+1); ! 576: } ! 577: bp = bswlist.av_forw; ! 578: bswlist.av_forw = bp->av_forw; ! 579: (void) spl0(); ! 580: ! 581: bp->b_flags = B_BUSY | B_PHYS | rdflg | flag; ! 582: if ((bp->b_flags & (B_DIRTY|B_PGIN)) == 0) ! 583: if (rdflg == B_READ) ! 584: sum.v_pswpin += btoc(nbytes); ! 585: else ! 586: sum.v_pswpout += btoc(nbytes); ! 587: bp->b_proc = p; ! 588: if (flag & B_DIRTY) { ! 589: p2dp = ((bp - swapbuf) * CLSIZE) * KLMAX; ! 590: dpte = dptopte(&proc[PAGEPID], p2dp); ! 591: vpte = vtopte(p, btop(addr)); ! 592: for (c = 0; c < nbytes; c += NBPG) { ! 593: if (vpte->pg_pfnum == 0 || vpte->pg_fod) ! 594: panic("swap bad pte"); ! 595: *dpte++ = *vpte++; ! 596: } ! 597: bp->b_un.b_addr = (caddr_t)ctob(p2dp); ! 598: } else ! 599: bp->b_un.b_addr = addr; ! 600: while (nbytes > 0) { ! 601: c = imin(ctob(120), nbytes); ! 602: bp->b_bcount = c; ! 603: bp->b_blkno = dblkno; ! 604: bp->b_dev = dev; ! 605: if (flag & B_DIRTY) { ! 606: swapinfo[bp - swapbuf].swpf = pfcent; ! 607: swapinfo[bp - swapbuf].swsize = nbytes; ! 608: } ! 609: if (bdevsw[major(dev)] == NULL) ! 610: panic("swap"); ! 611: (*bdevsw[major(dev)]->d_strategy)(bp); ! 612: if (flag & B_DIRTY) { ! 613: if (c < nbytes) ! 614: panic("big push"); ! 615: return; ! 616: } ! 617: (void) spl6(); ! 618: while((bp->b_flags&B_DONE)==0) ! 619: sleep((caddr_t)bp, PSWP); ! 620: (void) spl0(); ! 621: bp->b_un.b_addr += c; ! 622: bp->b_flags &= ~B_DONE; ! 623: if (bp->b_flags & B_ERROR) { ! 624: if ((flag & (B_UAREA|B_PAGET)) || rdflg == B_WRITE) ! 625: panic("hard IO err in swap"); ! 626: swkill(p, (char *)0); ! 627: } ! 628: nbytes -= c; ! 629: dblkno += btoc(c); ! 630: } ! 631: (void) spl6(); ! 632: bp->b_flags &= ~(B_BUSY|B_WANTED|B_PHYS|B_PAGET|B_UAREA|B_DIRTY); ! 633: bp->av_forw = bswlist.av_forw; ! 634: bswlist.av_forw = bp; ! 635: if (bswlist.b_flags & B_WANTED) { ! 636: bswlist.b_flags &= ~B_WANTED; ! 637: wakeup((caddr_t)&bswlist); ! 638: wakeup((caddr_t)&proc[PAGEPID]); ! 639: } ! 640: (void) spl0(); ! 641: } ! 642: ! 643: /* ! 644: * Initialize linked list of free swap ! 645: * headers. These do not actually point ! 646: * to buffers, but rather to pages that ! 647: * are being swapped in and out. ! 648: */ ! 649: bswinit() ! 650: { ! 651: extern int swbufcnt; ! 652: register int i; ! 653: register struct buf *sp = swapbuf; ! 654: ! 655: bswlist.av_forw = sp; ! 656: for (i=0; i<swbufcnt-1; i++, sp++) ! 657: sp->av_forw = sp+1; ! 658: sp->av_forw = NULL; ! 659: } ! 660: ! 661: /* ! 662: * If rout == 0 then killed on swap error, else ! 663: * rout is the name of the routine where we ran out of ! 664: * swap space. ! 665: */ ! 666: swkill(p, rout) ! 667: struct proc *p; ! 668: char *rout; ! 669: { ! 670: ! 671: printf("pid %d: ", p->p_pid); ! 672: if (rout) ! 673: printf("killed due to no swap space\n"); ! 674: else ! 675: printf("killed on swap error\n"); ! 676: /* ! 677: * To be sure no looping (e.g. in vmsched trying to ! 678: * swap out) mark process locked in core (as though ! 679: * done by user) after killing it so noone will try ! 680: * to swap it out. ! 681: */ ! 682: psignal(p, SIGKILL); ! 683: p->p_flag |= SULOCK; ! 684: } ! 685: ! 686: /* ! 687: * make sure all write-behind blocks ! 688: * on dev (or NODEV for all) ! 689: * are flushed out. ! 690: * (from umount and update) ! 691: */ ! 692: bflush(dev) ! 693: dev_t dev; ! 694: { ! 695: register struct buf *bp; ! 696: register struct buf *flist; ! 697: register s; ! 698: ! 699: loop: ! 700: s = spl6(); ! 701: for (flist = bfreelist; flist < &bfreelist[BQUEUES]; flist++) ! 702: for (bp = flist->av_forw; bp != flist; bp = bp->av_forw) { ! 703: if (bp->b_flags&B_DELWRI && (dev == NODEV||dev==bp->b_dev)) { ! 704: bp->b_flags |= B_ASYNC; ! 705: notavail(bp); ! 706: splx(s); ! 707: bwrite(bp); ! 708: goto loop; ! 709: } ! 710: } ! 711: splx(s); ! 712: } ! 713: ! 714: /* ! 715: * Raw I/O. The arguments are ! 716: * The strategy routine for the device ! 717: * A buffer, which will always be a special buffer ! 718: * header owned exclusively by the device for this purpose ! 719: * The device number ! 720: * Read/write flag ! 721: * Essentially all the work is computing physical addresses and ! 722: * validating them. ! 723: * If the user has the proper access privilidges, the process is ! 724: * marked 'delayed unlock' and the pages involved in the I/O are ! 725: * faulted and locked. After the completion of the I/O, the above pages ! 726: * are unlocked. ! 727: */ ! 728: ! 729: physio(strat, bp, dev, rw, mincnt) ! 730: int (*strat)(); ! 731: register struct buf *bp; ! 732: unsigned (*mincnt)(); ! 733: { ! 734: register int c; ! 735: char *a; ! 736: register int s; ! 737: ! 738: if (useracc(u.u_base,u.u_count,rw==B_READ?B_WRITE:B_READ) == NULL) { ! 739: u.u_error = EFAULT; ! 740: return; ! 741: } ! 742: s = spl6(); ! 743: while (bp->b_flags&B_BUSY) { ! 744: bp->b_flags |= B_WANTED; ! 745: /*sleep((caddr_t)bp, PRIBIO+1);*/ ! 746: switch(tsleep((caddr_t)bp, PRIBIO+1, 20)) { ! 747: case TS_OK: ! 748: continue; ! 749: case TS_SIG: /* can't happen at PRIBIO+1*/ ! 750: continue; ! 751: case TS_TIME: ! 752: u.u_error = EIO; ! 753: (void) splx(s); ! 754: return; ! 755: } ! 756: } ! 757: (void) splx(s); ! 758: bp->b_error = 0; ! 759: bp->b_proc = u.u_procp; ! 760: bp->b_un.b_addr = u.u_base; ! 761: while (u.u_count != 0) { ! 762: bp->b_flags = B_BUSY | B_PHYS | rw; ! 763: bp->b_dev = dev; ! 764: bp->b_blkno = Lshift(u.u_offset, PGSHIFT); ! 765: bp->b_bcount = u.u_count; ! 766: (*mincnt)(bp); ! 767: c = bp->b_bcount; ! 768: u.u_procp->p_flag |= SPHYSIO; ! 769: vslock(a = bp->b_un.b_addr, c); ! 770: (*strat)(bp); ! 771: s = spl6(); ! 772: while ((bp->b_flags&B_DONE) == 0) ! 773: sleep((caddr_t)bp, PRIBIO); ! 774: vsunlock(a, c, rw); ! 775: u.u_procp->p_flag &= ~SPHYSIO; ! 776: if (bp->b_flags&B_WANTED) ! 777: wakeup((caddr_t)bp); ! 778: (void) splx(s); ! 779: bp->b_un.b_addr += c; ! 780: u.u_count -= c; ! 781: u.u_offset = Lladd(u.u_offset, c); ! 782: if (bp->b_flags&B_ERROR) ! 783: break; ! 784: } ! 785: bp->b_flags &= ~(B_BUSY|B_WANTED|B_PHYS); ! 786: u.u_count = bp->b_resid; ! 787: geterror(bp); ! 788: } ! 789: ! 790: /*ARGSUSED*/ ! 791: unsigned ! 792: minphys(bp) ! 793: struct buf *bp; ! 794: { ! 795: ! 796: if (bp->b_bcount > (64*1024)-512) ! 797: bp->b_bcount = (64*1024)-512; ! 798: } ! 799: ! 800: /* ! 801: * Pick up the device's error number and pass it to the user; ! 802: * if there is an error but the number is 0 set a generalized ! 803: * code. Actually the latter is always true because devices ! 804: * don't yet return specific errors. ! 805: */ ! 806: geterror(bp) ! 807: register struct buf *bp; ! 808: { ! 809: ! 810: if (bp->b_flags&B_ERROR) ! 811: if ((u.u_error = bp->b_error)==0) ! 812: u.u_error = EIO; ! 813: } ! 814: ! 815: /* ! 816: * Invalidate in core blocks belonging to closed or umounted filesystem ! 817: * ! 818: * This is not nicely done at all - the buffer ought to be removed from the ! 819: * hash chains & have its dev/blkno fields clobbered, but unfortunately we ! 820: * can't do that here, as it is quite possible that the block is still ! 821: * being used for i/o. Eventually, all disc drivers should be forced to ! 822: * have a close routine, which ought ensure that the queue is empty, then ! 823: * properly flush the queues. Until that happy day, this suffices for ! 824: * correctness. ... kre ! 825: */ ! 826: binval(dev) ! 827: dev_t dev; ! 828: { ! 829: register struct buf *bp; ! 830: register struct bufhd *hp; ! 831: #define dp ((struct buf *)hp) ! 832: ! 833: for (hp = &bufhash[bufhcnt-1]; hp >= bufhash; hp--) ! 834: for (bp = dp->b_forw; bp != dp; bp = bp->b_forw) ! 835: if (bp->b_dev == dev) ! 836: bp->b_flags |= B_INVAL; ! 837: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.