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