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