|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1989, 1990, 1991, 1992 William F. Jolitz, TeleMuse ! 3: * All rights reserved. ! 4: * ! 5: * Redistribution and use in source and binary forms, with or without ! 6: * modification, are permitted provided that the following conditions ! 7: * are met: ! 8: * 1. Redistributions of source code must retain the above copyright ! 9: * notice, this list of conditions and the following disclaimer. ! 10: * 2. Redistributions in binary form must reproduce the above copyright ! 11: * notice, this list of conditions and the following disclaimer in the ! 12: * documentation and/or other materials provided with the distribution. ! 13: * 3. All advertising materials mentioning features or use of this software ! 14: * must display the following acknowledgement: ! 15: * This software is a component of "386BSD" developed by ! 16: William F. Jolitz, TeleMuse. ! 17: * 4. Neither the name of the developer nor the name "386BSD" ! 18: * may be used to endorse or promote products derived from this software ! 19: * without specific prior written permission. ! 20: * ! 21: * THIS SOFTWARE IS A COMPONENT OF 386BSD DEVELOPED BY WILLIAM F. JOLITZ ! 22: * AND IS INTENDED FOR RESEARCH AND EDUCATIONAL PURPOSES ONLY. THIS ! 23: * SOFTWARE SHOULD NOT BE CONSIDERED TO BE A COMMERCIAL PRODUCT. ! 24: * THE DEVELOPER URGES THAT USERS WHO REQUIRE A COMMERCIAL PRODUCT ! 25: * NOT MAKE USE THIS WORK. ! 26: * ! 27: * FOR USERS WHO WISH TO UNDERSTAND THE 386BSD SYSTEM DEVELOPED ! 28: * BY WILLIAM F. JOLITZ, WE RECOMMEND THE USER STUDY WRITTEN ! 29: * REFERENCES SUCH AS THE "PORTING UNIX TO THE 386" SERIES ! 30: * (BEGINNING JANUARY 1991 "DR. DOBBS JOURNAL", USA AND BEGINNING ! 31: * JUNE 1991 "UNIX MAGAZIN", GERMANY) BY WILLIAM F. JOLITZ AND ! 32: * LYNNE GREER JOLITZ, AS WELL AS OTHER BOOKS ON UNIX AND THE ! 33: * ON-LINE 386BSD USER MANUAL BEFORE USE. A BOOK DISCUSSING THE INTERNALS ! 34: * OF 386BSD ENTITLED "386BSD FROM THE INSIDE OUT" WILL BE AVAILABLE LATE 1992. ! 35: * ! 36: * THIS SOFTWARE IS PROVIDED BY THE DEVELOPER ``AS IS'' AND ! 37: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ! 38: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ! 39: * ARE DISCLAIMED. IN NO EVENT SHALL THE DEVELOPER BE LIABLE ! 40: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ! 41: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ! 42: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ! 43: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ! 44: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ! 45: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ! 46: * SUCH DAMAGE. ! 47: * ! 48: */ ! 49: static char rcsid[] = "$Header: /usr/bill/working/sys/kern/RCS/vfs__bio.c,v 1.2 92/01/21 21:30:08 william Exp $"; ! 50: ! 51: #include "param.h" ! 52: #include "proc.h" ! 53: #include "vnode.h" ! 54: #include "buf.h" ! 55: #include "specdev.h" ! 56: #include "mount.h" ! 57: #include "malloc.h" ! 58: #include "resourcevar.h" ! 59: ! 60: /* ! 61: * Initialize buffer headers and related structures. ! 62: */ ! 63: void bufinit() ! 64: { ! 65: struct bufhd *bh; ! 66: struct buf *bp; ! 67: ! 68: /* first, make a null hash table */ ! 69: for(bh = bufhash; bh < bufhash + BUFHSZ; bh++) { ! 70: bh->b_flags = 0; ! 71: bh->b_forw = (struct buf *)bh; ! 72: bh->b_back = (struct buf *)bh; ! 73: } ! 74: ! 75: /* next, make a null set of free lists */ ! 76: for(bp = bfreelist; bp < bfreelist + BQUEUES; bp++) { ! 77: bp->b_flags = 0; ! 78: bp->av_forw = bp; ! 79: bp->av_back = bp; ! 80: bp->b_forw = bp; ! 81: bp->b_back = bp; ! 82: } ! 83: ! 84: /* finally, initialize each buffer header and stick on empty q */ ! 85: for(bp = buf; bp < buf + nbuf ; bp++) { ! 86: bp->b_flags = B_HEAD | B_INVAL; /* we're just an empty header */ ! 87: bp->b_dev = NODEV; ! 88: bp->b_vp = 0; ! 89: binstailfree(bp, bfreelist + BQ_EMPTY); ! 90: binshash(bp, bfreelist + BQ_EMPTY); ! 91: } ! 92: } ! 93: ! 94: /* ! 95: * Find the block in the buffer pool. ! 96: * If the buffer is not present, allocate a new buffer and load ! 97: * its contents according to the filesystem fill routine. ! 98: */ ! 99: bread(vp, blkno, size, cred, bpp) ! 100: struct vnode *vp; ! 101: daddr_t blkno; ! 102: int size; ! 103: struct ucred *cred; ! 104: struct buf **bpp; ! 105: { ! 106: struct buf *bp; ! 107: int rv = 0; ! 108: ! 109: bp = getblk (vp, blkno, size); ! 110: ! 111: /* if not found in cache, do some I/O */ ! 112: if ((bp->b_flags & B_CACHE) == 0 || (bp->b_flags & B_INVAL) != 0) { ! 113: bp->b_flags |= B_READ; ! 114: bp->b_flags &= ~(B_DONE|B_ERROR|B_INVAL); ! 115: VOP_STRATEGY(bp); ! 116: rv = biowait (bp); ! 117: } ! 118: *bpp = bp; ! 119: ! 120: return (rv); ! 121: } ! 122: ! 123: /* ! 124: * Operates like bread, but also starts I/O on the specified ! 125: * read-ahead block. [See page 55 of Bach's Book] ! 126: */ ! 127: breada(vp, blkno, size, rablkno, rabsize, cred, bpp) ! 128: struct vnode *vp; ! 129: daddr_t blkno; int size; ! 130: daddr_t rablkno; int rabsize; ! 131: struct ucred *cred; ! 132: struct buf **bpp; ! 133: { ! 134: struct buf *bp, *rabp; ! 135: int rv = 0, needwait = 0; ! 136: ! 137: bp = getblk (vp, blkno, size); ! 138: ! 139: /* if not found in cache, do some I/O */ ! 140: if ((bp->b_flags & B_CACHE) == 0 || (bp->b_flags & B_INVAL) != 0) { ! 141: bp->b_flags |= B_READ; ! 142: bp->b_flags &= ~(B_DONE|B_ERROR|B_INVAL); ! 143: VOP_STRATEGY(bp); ! 144: needwait++; ! 145: } ! 146: ! 147: rabp = getblk (vp, rablkno, rabsize); ! 148: ! 149: /* if not found in cache, do some I/O (overlapped with first) */ ! 150: if ((rabp->b_flags & B_CACHE) == 0 || (rabp->b_flags & B_INVAL) != 0) { ! 151: rabp->b_flags |= B_READ | B_ASYNC; ! 152: rabp->b_flags &= ~(B_DONE|B_ERROR|B_INVAL); ! 153: VOP_STRATEGY(rabp); ! 154: } else ! 155: brelse(rabp); ! 156: ! 157: /* wait for original I/O */ ! 158: if (needwait) ! 159: rv = biowait (bp); ! 160: ! 161: *bpp = bp; ! 162: return (rv); ! 163: } ! 164: ! 165: /* ! 166: * Synchronous write. ! 167: * Release buffer on completion. ! 168: */ ! 169: bwrite(bp) ! 170: register struct buf *bp; ! 171: { ! 172: int rv; ! 173: ! 174: if(bp->b_flags & B_INVAL) { ! 175: brelse(bp); ! 176: return (0); ! 177: } else { ! 178: int wasdelayed; ! 179: ! 180: if(!(bp->b_flags & B_BUSY))panic("bwrite: not busy"); ! 181: wasdelayed = bp->b_flags & B_DELWRI; ! 182: bp->b_flags &= ~(B_READ|B_DONE|B_ERROR|B_ASYNC|B_DELWRI); ! 183: if(wasdelayed) reassignbuf(bp, bp->b_vp); ! 184: bp->b_flags |= B_DIRTY; ! 185: VOP_STRATEGY(bp); ! 186: rv = biowait(bp); ! 187: if (!rv) ! 188: bp->b_flags &= ~B_DIRTY; ! 189: brelse(bp); ! 190: return (rv); ! 191: } ! 192: } ! 193: ! 194: /* ! 195: * Delayed write. ! 196: * ! 197: * The buffer is marked dirty, but is not queued for I/O. ! 198: * This routine should be used when the buffer is expected ! 199: * to be modified again soon, typically a small write that ! 200: * partially fills a buffer. ! 201: * ! 202: * NB: magnetic tapes cannot be delayed; they must be ! 203: * written in the order that the writes are requested. ! 204: */ ! 205: void bdwrite(bp) ! 206: register struct buf *bp; ! 207: { ! 208: ! 209: if(!(bp->b_flags & B_BUSY))panic("bdwrite: not busy"); ! 210: if(bp->b_flags & B_INVAL) { ! 211: brelse(bp); ! 212: } ! 213: if(bp->b_flags & B_TAPE) { ! 214: bwrite(bp); ! 215: return; ! 216: } ! 217: bp->b_flags &= ~(B_READ|B_DONE); ! 218: bp->b_flags |= B_DIRTY|B_DELWRI; ! 219: reassignbuf(bp, bp->b_vp); ! 220: brelse(bp); ! 221: return; ! 222: } ! 223: ! 224: /* ! 225: * Asynchronous write. ! 226: * Start I/O on a buffer, but do not wait for it to complete. ! 227: * The buffer is released when the I/O completes. ! 228: */ ! 229: bawrite(bp) ! 230: register struct buf *bp; ! 231: { ! 232: ! 233: if(!(bp->b_flags & B_BUSY))panic("bawrite: not busy"); ! 234: if(bp->b_flags & B_INVAL) ! 235: brelse(bp); ! 236: else { ! 237: int wasdelayed; ! 238: ! 239: wasdelayed = bp->b_flags & B_DELWRI; ! 240: bp->b_flags &= ~(B_READ|B_DONE|B_ERROR|B_DELWRI); ! 241: if(wasdelayed) reassignbuf(bp, bp->b_vp); ! 242: ! 243: bp->b_flags |= B_DIRTY | B_ASYNC; ! 244: VOP_STRATEGY(bp); ! 245: } ! 246: } ! 247: ! 248: /* ! 249: * Release a buffer. ! 250: * Even if the buffer is dirty, no I/O is started. ! 251: */ ! 252: brelse(bp) ! 253: register struct buf *bp; ! 254: { ! 255: int x; ! 256: ! 257: /* anyone need a "free" block? */ ! 258: x=splbio(); ! 259: if ((bfreelist + BQ_AGE)->b_flags & B_WANTED) { ! 260: (bfreelist + BQ_AGE) ->b_flags &= ~B_WANTED; ! 261: wakeup(bfreelist); ! 262: } ! 263: /* anyone need this very block? */ ! 264: if (bp->b_flags & B_WANTED) { ! 265: bp->b_flags &= ~B_WANTED; ! 266: wakeup(bp); ! 267: } ! 268: ! 269: if (bp->b_flags & (B_INVAL|B_ERROR)) { ! 270: bp->b_flags |= B_INVAL; ! 271: bp->b_flags &= ~(B_DELWRI|B_CACHE); ! 272: if(bp->b_vp) ! 273: brelvp(bp); ! 274: } ! 275: ! 276: /* enqueue */ ! 277: /* just an empty buffer head ... */ ! 278: /*if(bp->b_flags & B_HEAD) ! 279: binsheadfree(bp, bfreelist + BQ_EMPTY)*/ ! 280: /* buffers with junk contents */ ! 281: /*else*/ if(bp->b_flags & (B_ERROR|B_INVAL|B_NOCACHE)) ! 282: binsheadfree(bp, bfreelist + BQ_AGE) ! 283: /* buffers with stale but valid contents */ ! 284: else if(bp->b_flags & B_AGE) ! 285: binstailfree(bp, bfreelist + BQ_AGE) ! 286: /* buffers with valid and quite potentially reuseable contents */ ! 287: else ! 288: binstailfree(bp, bfreelist + BQ_LRU) ! 289: ! 290: /* unlock */ ! 291: bp->b_flags &= ~B_BUSY; ! 292: splx(x); ! 293: ! 294: return; ! 295: } ! 296: ! 297: int freebufspace = 20*NBPG; ! 298: int allocbufspace; ! 299: ! 300: /* ! 301: * Find a buffer which is available for use. ! 302: * If free memory for buffer space and an empty header from the empty list, ! 303: * use that. Otherwise, select something from a free list. ! 304: * Preference is to AGE list, then LRU list. ! 305: */ ! 306: struct buf * ! 307: getnewbuf(sz) ! 308: { ! 309: struct buf *bp; ! 310: int x; ! 311: ! 312: x = splbio(); ! 313: start: ! 314: /* can we constitute a new buffer? */ ! 315: if (freebufspace > sz ! 316: && bfreelist[BQ_EMPTY].av_forw != (struct buf *)bfreelist+BQ_EMPTY) { ! 317: caddr_t addr; ! 318: ! 319: if ((addr = malloc (sz, M_TEMP, M_NOWAIT)) == 0) goto tryfree; ! 320: freebufspace -= sz; ! 321: allocbufspace += sz; ! 322: ! 323: bp = bfreelist[BQ_EMPTY].av_forw; ! 324: bp->b_flags = B_BUSY | B_INVAL; ! 325: bremfree(bp); ! 326: bp->b_un.b_addr = (caddr_t) addr; ! 327: goto fillin; ! 328: } ! 329: ! 330: tryfree: ! 331: if (bfreelist[BQ_AGE].av_forw != (struct buf *)bfreelist+BQ_AGE) { ! 332: bp = bfreelist[BQ_AGE].av_forw; ! 333: bremfree(bp); ! 334: } else if (bfreelist[BQ_LRU].av_forw != (struct buf *)bfreelist+BQ_LRU) { ! 335: bp = bfreelist[BQ_LRU].av_forw; ! 336: bremfree(bp); ! 337: } else { ! 338: /* wait for a free buffer of any kind */ ! 339: (bfreelist + BQ_AGE)->b_flags |= B_WANTED; ! 340: sleep(bfreelist, PRIBIO); ! 341: splx(x); ! 342: return (0); ! 343: } ! 344: ! 345: /* if we are a delayed write, convert to an async write! */ ! 346: if (bp->b_flags & B_DELWRI) { ! 347: /*bp->b_flags &= ~B_DELWRI;*/ ! 348: bp->b_flags |= B_BUSY; ! 349: bawrite (bp); ! 350: goto start; ! 351: } ! 352: ! 353: /*if (bp->b_flags & (B_INVAL|B_ERROR) == 0) { ! 354: bremhash(bp); ! 355: }*/ ! 356: ! 357: if(bp->b_vp) ! 358: brelvp(bp); ! 359: ! 360: /* we are not free, nor do we contain interesting data */ ! 361: bp->b_flags = B_BUSY; ! 362: fillin: ! 363: bremhash(bp); ! 364: splx(x); ! 365: bp->b_dev = NODEV; ! 366: bp->b_vp = NULL; ! 367: bp->b_blkno = bp->b_lblkno = 0; ! 368: bp->b_iodone = 0; ! 369: bp->b_error = 0; ! 370: bp->b_wcred = bp->b_rcred = NOCRED; ! 371: if (bp->b_bufsize != sz) allocbuf(bp, sz); ! 372: bp->b_bcount = bp->b_bufsize = sz; ! 373: bp->b_dirtyoff = bp->b_dirtyend = 0; ! 374: return (bp); ! 375: } ! 376: ! 377: /* ! 378: * Check to see if a block is currently memory resident. ! 379: */ ! 380: struct buf *incore(vp, blkno) ! 381: struct vnode *vp; ! 382: daddr_t blkno; ! 383: { ! 384: struct buf *bh; ! 385: struct buf *bp; ! 386: ! 387: bh = BUFHASH(vp, blkno); ! 388: ! 389: /* Search hash chain */ ! 390: bp = bh->b_forw; ! 391: while (bp != (struct buf *) bh) { ! 392: /* hit */ ! 393: if (bp->b_lblkno == blkno && bp->b_vp == vp ! 394: && (bp->b_flags & B_INVAL) == 0) ! 395: return (bp); ! 396: bp = bp->b_forw; ! 397: } ! 398: ! 399: return(0); ! 400: } ! 401: ! 402: /* ! 403: * Get a block of requested size that is associated with ! 404: * a given vnode and block offset. If it is found in the ! 405: * block cache, mark it as having been found, make it busy ! 406: * and return it. Otherwise, return an empty block of the ! 407: * correct size. It is up to the caller to insure that the ! 408: * cached blocks be of the correct size. ! 409: */ ! 410: struct buf * ! 411: getblk(vp, blkno, size) ! 412: register struct vnode *vp; ! 413: daddr_t blkno; ! 414: int size; ! 415: { ! 416: struct buf *bp, *bh; ! 417: int x; ! 418: ! 419: for (;;) { ! 420: if (bp = incore(vp, blkno)) { ! 421: x = splbio(); ! 422: if (bp->b_flags & B_BUSY) { ! 423: bp->b_flags |= B_WANTED; ! 424: sleep (bp, PRIBIO); ! 425: continue; ! 426: } ! 427: bp->b_flags |= B_BUSY | B_CACHE; ! 428: bremfree(bp); ! 429: if (size > bp->b_bufsize) ! 430: panic("now what do we do?"); ! 431: /* if (bp->b_bufsize != size) allocbuf(bp, size); */ ! 432: } else { ! 433: ! 434: if((bp = getnewbuf(size)) == 0) continue; ! 435: bp->b_blkno = bp->b_lblkno = blkno; ! 436: bgetvp(vp, bp); ! 437: x = splbio(); ! 438: bh = BUFHASH(vp, blkno); ! 439: binshash(bp, bh); ! 440: bp->b_flags = B_BUSY; ! 441: } ! 442: splx(x); ! 443: return (bp); ! 444: } ! 445: } ! 446: ! 447: /* ! 448: * Get an empty, disassociated buffer of given size. ! 449: */ ! 450: struct buf * ! 451: geteblk(size) ! 452: int size; ! 453: { ! 454: struct buf *bp; ! 455: int x; ! 456: ! 457: while ((bp = getnewbuf(size)) == 0) ! 458: ; ! 459: x = splbio(); ! 460: binshash(bp, bfreelist + BQ_AGE); ! 461: splx(x); ! 462: ! 463: return (bp); ! 464: } ! 465: ! 466: /* ! 467: * Exchange a buffer's underlying buffer storage for one of different ! 468: * size, taking care to maintain contents appropriately. When buffer ! 469: * increases in size, caller is responsible for filling out additional ! 470: * contents. When buffer shrinks in size, data is lost, so caller must ! 471: * first return it to backing store before shrinking the buffer, as ! 472: * no implied I/O will be done. ! 473: * ! 474: * Expanded buffer is returned as value. ! 475: */ ! 476: struct buf * ! 477: allocbuf(bp, size) ! 478: register struct buf *bp; ! 479: int size; ! 480: { ! 481: caddr_t newcontents; ! 482: ! 483: /* get new memory buffer */ ! 484: newcontents = (caddr_t) malloc (size, M_TEMP, M_WAITOK); ! 485: ! 486: /* copy the old into the new, up to the maximum that will fit */ ! 487: bcopy (bp->b_un.b_addr, newcontents, min(bp->b_bufsize, size)); ! 488: ! 489: /* return old contents to free heap */ ! 490: free (bp->b_un.b_addr, M_TEMP); ! 491: ! 492: /* adjust buffer cache's idea of memory allocated to buffer contents */ ! 493: freebufspace -= size - bp->b_bufsize; ! 494: allocbufspace += size - bp->b_bufsize; ! 495: ! 496: /* update buffer header */ ! 497: bp->b_un.b_addr = newcontents; ! 498: bp->b_bcount = bp->b_bufsize = size; ! 499: ! 500: return(bp); ! 501: } ! 502: ! 503: /* ! 504: * Patiently await operations to complete on this buffer. ! 505: * When they do, extract error value and return it. ! 506: * Extract and return any errors associated with the I/O. ! 507: * If an invalid block, force it off the lookup hash chains. ! 508: */ ! 509: biowait(bp) ! 510: register struct buf *bp; ! 511: { ! 512: int x; ! 513: ! 514: x = splbio(); ! 515: while ((bp->b_flags & B_DONE) == 0) ! 516: sleep((caddr_t)bp, PRIBIO); ! 517: if((bp->b_flags & B_ERROR) || bp->b_error) { ! 518: if ((bp->b_flags & B_INVAL) == 0) { ! 519: bp->b_flags |= B_INVAL; ! 520: bremhash(bp); ! 521: binshash(bp, bfreelist + BQ_AGE); ! 522: } ! 523: if (!bp->b_error) ! 524: bp->b_error = EIO; ! 525: else ! 526: bp->b_flags |= B_ERROR; ! 527: splx(x); ! 528: return (bp->b_error); ! 529: } else { ! 530: splx(x); ! 531: return (0); ! 532: } ! 533: } ! 534: ! 535: /* ! 536: * Finish up operations on a buffer, calling an optional ! 537: * function (if requested), and releasing the buffer if ! 538: * marked asynchronous. Then mark this buffer done so that ! 539: * others biowait()'ing for it will notice when they are ! 540: * woken up from sleep(). ! 541: */ ! 542: biodone(bp) ! 543: register struct buf *bp; ! 544: { ! 545: int x; ! 546: ! 547: x = splbio(); ! 548: if (bp->b_flags & B_CALL) (*bp->b_iodone)(bp); ! 549: bp->b_flags &= ~B_CALL; ! 550: if (bp->b_flags & B_ASYNC) brelse(bp); ! 551: bp->b_flags &= ~B_ASYNC; ! 552: bp->b_flags |= B_DONE; ! 553: wakeup(bp); ! 554: splx(x); ! 555: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.