|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights ! 7: * Reserved. This file contains Original Code and/or Modifications of ! 8: * Original Code as defined in and that are subject to the Apple Public ! 9: * Source License Version 1.1 (the "License"). You may not use this file ! 10: * except in compliance with the License. Please obtain a copy of the ! 11: * License at http://www.apple.com/publicsource and read it before using ! 12: * this file. ! 13: * ! 14: * The Original Code and all software distributed under the License are ! 15: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 16: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 17: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 18: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ! 19: * License for the specific language governing rights and limitations ! 20: * under the License. ! 21: * ! 22: * @APPLE_LICENSE_HEADER_END@ ! 23: */ ! 24: ! 25: /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */ ! 26: /*- ! 27: * Copyright (c) 1982, 1986, 1989, 1993 ! 28: * The Regents of the University of California. All rights reserved. ! 29: * (c) UNIX System Laboratories, Inc. ! 30: * All or some portions of this file are derived from material licensed ! 31: * to the University of California by American Telephone and Telegraph ! 32: * Co. or Unix System Laboratories, Inc. and are reproduced herein with ! 33: * the permission of UNIX System Laboratories, Inc. ! 34: * ! 35: * Redistribution and use in source and binary forms, with or without ! 36: * modification, are permitted provided that the following conditions ! 37: * are met: ! 38: * 1. Redistributions of source code must retain the above copyright ! 39: * notice, this list of conditions and the following disclaimer. ! 40: * 2. Redistributions in binary form must reproduce the above copyright ! 41: * notice, this list of conditions and the following disclaimer in the ! 42: * documentation and/or other materials provided with the distribution. ! 43: * 3. All advertising materials mentioning features or use of this software ! 44: * must display the following acknowledgement: ! 45: * This product includes software developed by the University of ! 46: * California, Berkeley and its contributors. ! 47: * 4. Neither the name of the University nor the names of its contributors ! 48: * may be used to endorse or promote products derived from this software ! 49: * without specific prior written permission. ! 50: * ! 51: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ! 52: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ! 53: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ! 54: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE ! 55: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ! 56: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ! 57: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ! 58: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ! 59: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ! 60: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ! 61: * SUCH DAMAGE. ! 62: * ! 63: * The NEXTSTEP Software License Agreement specifies the terms ! 64: * and conditions for redistribution. ! 65: * ! 66: * @(#)vfs_bio.c 8.6 (Berkeley) 1/11/94 ! 67: */ ! 68: ! 69: /* ! 70: * Some references: ! 71: * Bach: The Design of the UNIX Operating System (Prentice Hall, 1986) ! 72: * Leffler, et al.: The Design and Implementation of the 4.3BSD ! 73: * UNIX Operating System (Addison Welley, 1989) ! 74: */ ! 75: /* ! 76: * HISTORY ! 77: * 17-July-97 Umesh Vaishampayan ([email protected]) ! 78: * Eliminated multiple definition of buffers and buf which are defined in ! 79: * conf/param.c. ! 80: * Eliminated multiple definition of nbuf and bufpages which are defined ! 81: * in machdep/XXX/unix_startup.c ! 82: * ! 83: * 11-July-97 Umesh Vaishampayan ([email protected]) ! 84: * Defined global variables for use when tracing is turned on. ! 85: */ ! 86: ! 87: #include <mach_nbc.h> ! 88: #include <sys/param.h> ! 89: #include <sys/systm.h> ! 90: #include <sys/proc.h> ! 91: #include <sys/buf.h> ! 92: #include <sys/vnode.h> ! 93: #include <sys/mount.h> ! 94: #include <sys/trace.h> ! 95: #include <sys/malloc.h> ! 96: #include <sys/resourcevar.h> ! 97: #include <miscfs/specfs/specdev.h> ! 98: ! 99: extern void reassignbuf(struct buf *, struct vnode *); ! 100: ! 101: extern int nbuf; /* The number of buffer headers */ ! 102: extern int niobuf; ! 103: extern struct buf *buf; /* The buffer headers. */ ! 104: extern char *buffers; /* The buffer contents. */ ! 105: extern int bufpages; /* Number of memory pages in the buffer pool. */ ! 106: struct buf *swbuf; /* Swap I/O buffer headers. */ ! 107: int nswbuf; /* Number of swap I/O buffer headers. */ ! 108: struct buf bswlist; /* Head of swap I/O buffer headers free list. */ ! 109: struct buf *bclnlist;/* Head of cleaned page list. */ ! 110: ! 111: #if TRACE ! 112: struct proc *traceproc; ! 113: int tracewhich, tracebuf[TRCSIZ]; ! 114: u_int tracex; ! 115: char traceflags[TR_NFLAGS]; ! 116: #endif /* TRACE */ ! 117: ! 118: /* Macros to clear/set/test flags. */ ! 119: #define SET(t, f) (t) |= (f) ! 120: #define CLR(t, f) (t) &= ~(f) ! 121: #define ISSET(t, f) ((t) & (f)) ! 122: ! 123: /* ! 124: * Definitions for the buffer hash lists. ! 125: */ ! 126: #define BUFHASH(dvp, lbn) \ ! 127: (&bufhashtbl[((long)(dvp) / sizeof(*(dvp)) + (int)(lbn)) & bufhash]) ! 128: LIST_HEAD(bufhashhdr, buf) *bufhashtbl, invalhash; ! 129: u_long bufhash; ! 130: ! 131: /* ! 132: * Insq/Remq for the buffer hash lists. ! 133: */ ! 134: #define binshash(bp, dp) LIST_INSERT_HEAD(dp, bp, b_hash) ! 135: #define bremhash(bp) LIST_REMOVE(bp, b_hash) ! 136: ! 137: /* ! 138: * Definitions for the buffer free lists. ! 139: */ ! 140: #define BQUEUES 4 /* number of free buffer queues */ ! 141: ! 142: #define BQ_LOCKED 0 /* super-blocks &c */ ! 143: #define BQ_LRU 1 /* lru, useful buffers */ ! 144: #define BQ_AGE 2 /* rubbish */ ! 145: #define BQ_EMPTY 3 /* buffer headers with no memory */ ! 146: ! 147: TAILQ_HEAD(ioqueue, buf) iobufqueue; ! 148: TAILQ_HEAD(bqueues, buf) bufqueues[BQUEUES]; ! 149: int needbuffer; ! 150: ! 151: /* ! 152: * Insq/Remq for the buffer free lists. ! 153: */ ! 154: #define binsheadfree(bp, dp) TAILQ_INSERT_HEAD(dp, bp, b_freelist) ! 155: #define binstailfree(bp, dp) TAILQ_INSERT_TAIL(dp, bp, b_freelist) ! 156: ! 157: void ! 158: bremfree(bp) ! 159: struct buf *bp; ! 160: { ! 161: struct bqueues *dp = NULL; ! 162: ! 163: /* ! 164: * We only calculate the head of the freelist when removing ! 165: * the last element of the list as that is the only time that ! 166: * it is needed (e.g. to reset the tail pointer). ! 167: * ! 168: * NB: This makes an assumption about how tailq's are implemented. ! 169: */ ! 170: if (bp->b_freelist.tqe_next == NULL) { ! 171: for (dp = bufqueues; dp < &bufqueues[BQUEUES]; dp++) ! 172: if (dp->tqh_last == &bp->b_freelist.tqe_next) ! 173: break; ! 174: if (dp == &bufqueues[BQUEUES]) ! 175: panic("bremfree: lost tail"); ! 176: } ! 177: TAILQ_REMOVE(dp, bp, b_freelist); ! 178: } ! 179: ! 180: /* ! 181: * Initialize buffers and hash links for buffers. ! 182: */ ! 183: void ! 184: bufinit() ! 185: { ! 186: register struct buf *bp; ! 187: struct bqueues *dp; ! 188: register int i; ! 189: int base, residual; ! 190: ! 191: for (dp = bufqueues; dp < &bufqueues[BQUEUES]; dp++) ! 192: TAILQ_INIT(dp); ! 193: bufhashtbl = hashinit(nbuf, M_CACHE, &bufhash); ! 194: base = bufpages / nbuf; ! 195: residual = bufpages % nbuf; ! 196: for (i = 0; i < nbuf; i++) { ! 197: bp = &buf[i]; ! 198: bzero((char *)bp, sizeof *bp); ! 199: bp->b_dev = NODEV; ! 200: bp->b_rcred = NOCRED; ! 201: bp->b_wcred = NOCRED; ! 202: bp->b_vnbufs.le_next = NOLIST; ! 203: bp->b_data = buffers + i * MAXBSIZE; ! 204: if (i < residual) ! 205: bp->b_bufsize = (base + 1) * CLBYTES; ! 206: else ! 207: bp->b_bufsize = base * CLBYTES; ! 208: bp->b_flags = B_INVAL; ! 209: dp = bp->b_bufsize ? &bufqueues[BQ_AGE] : &bufqueues[BQ_EMPTY]; ! 210: binsheadfree(bp, dp); ! 211: binshash(bp, &invalhash); ! 212: } ! 213: base = (int )(buffers + (i * MAXBSIZE)); ! 214: ! 215: for (; i < nbuf + niobuf; i++) { ! 216: bp = &buf[i]; ! 217: bzero((char *)bp, sizeof *bp); ! 218: bp->b_dev = NODEV; ! 219: bp->b_rcred = NOCRED; ! 220: bp->b_wcred = NOCRED; ! 221: bp->b_vnbufs.le_next = NOLIST; ! 222: bp->b_data = (char *)base; ! 223: bp->b_bufsize = 0; ! 224: bp->b_flags = B_INVAL; ! 225: binsheadfree(bp, &iobufqueue); ! 226: ! 227: base += MAXPHYSIO; ! 228: } ! 229: } ! 230: ! 231: __inline struct buf * ! 232: bio_doread(vp, blkno, size, cred, async) ! 233: struct vnode *vp; ! 234: daddr_t blkno; ! 235: int size; ! 236: struct ucred *cred; ! 237: int async; ! 238: { ! 239: register struct buf *bp; ! 240: struct proc *p = current_proc(); ! 241: ! 242: bp = getblk(vp, blkno, size, 0, 0); ! 243: ! 244: /* ! 245: * If buffer does not have data valid, start a read. ! 246: * Note that if buffer is B_INVAL, getblk() won't return it. ! 247: * Therefore, it's valid if it's I/O has completed or been delayed. ! 248: */ ! 249: if (!ISSET(bp->b_flags, (B_DONE | B_DELWRI))) { ! 250: /* Start I/O for the buffer (keeping credentials). */ ! 251: SET(bp->b_flags, B_READ | async); ! 252: if (cred != NOCRED && bp->b_rcred == NOCRED) { ! 253: crhold(cred); ! 254: bp->b_rcred = cred; ! 255: } ! 256: VOP_STRATEGY(bp); ! 257: ! 258: trace(TR_BREADMISS, pack(vp, size), blkno); ! 259: ! 260: /* Pay for the read. */ ! 261: if (p && p->p_stats) ! 262: p->p_stats->p_ru.ru_inblock++; /* XXX */ ! 263: } else if (async) { ! 264: brelse(bp); ! 265: } ! 266: ! 267: trace(TR_BREADHIT, pack(vp, size), blkno); ! 268: ! 269: return (bp); ! 270: } ! 271: ! 272: /* ! 273: * Read a disk block. ! 274: * This algorithm described in Bach (p.54). ! 275: */ ! 276: int ! 277: bread(vp, blkno, size, cred, bpp) ! 278: struct vnode *vp; ! 279: daddr_t blkno; ! 280: int size; ! 281: struct ucred *cred; ! 282: struct buf **bpp; ! 283: { ! 284: register struct buf *bp; ! 285: ! 286: /* Get buffer for block. */ ! 287: bp = *bpp = bio_doread(vp, blkno, size, cred, 0); ! 288: ! 289: /* Wait for the read to complete, and return result. */ ! 290: return (biowait(bp)); ! 291: } ! 292: ! 293: /* ! 294: * Read-ahead multiple disk blocks. The first is sync, the rest async. ! 295: * Trivial modification to the breada algorithm presented in Bach (p.55). ! 296: */ ! 297: int ! 298: breadn(vp, blkno, size, rablks, rasizes, nrablks, cred, bpp) ! 299: struct vnode *vp; ! 300: daddr_t blkno; int size; ! 301: daddr_t rablks[]; int rasizes[]; ! 302: int nrablks; ! 303: struct ucred *cred; ! 304: struct buf **bpp; ! 305: { ! 306: register struct buf *bp; ! 307: int i; ! 308: ! 309: bp = *bpp = bio_doread(vp, blkno, size, cred, 0); ! 310: ! 311: /* ! 312: * For each of the read-ahead blocks, start a read, if necessary. ! 313: */ ! 314: for (i = 0; i < nrablks; i++) { ! 315: /* If it's in the cache, just go on to next one. */ ! 316: if (incore(vp, rablks[i])) ! 317: continue; ! 318: ! 319: /* Get a buffer for the read-ahead block */ ! 320: (void) bio_doread(vp, rablks[i], rasizes[i], cred, B_ASYNC); ! 321: } ! 322: ! 323: /* Otherwise, we had to start a read for it; wait until it's valid. */ ! 324: return (biowait(bp)); ! 325: } ! 326: ! 327: /* ! 328: * Read with single-block read-ahead. Defined in Bach (p.55), but ! 329: * implemented as a call to breadn(). ! 330: * XXX for compatibility with old file systems. ! 331: */ ! 332: int ! 333: breada(vp, blkno, size, rablkno, rabsize, cred, bpp) ! 334: struct vnode *vp; ! 335: daddr_t blkno; int size; ! 336: daddr_t rablkno; int rabsize; ! 337: struct ucred *cred; ! 338: struct buf **bpp; ! 339: { ! 340: ! 341: return (breadn(vp, blkno, size, &rablkno, &rabsize, 1, cred, bpp)); ! 342: } ! 343: ! 344: /* ! 345: * Block write. Described in Bach (p.56) ! 346: */ ! 347: int ! 348: bwrite(bp) ! 349: struct buf *bp; ! 350: { ! 351: int rv, sync, wasdelayed; ! 352: struct proc *p = current_proc(); ! 353: ! 354: /* Remember buffer type, to switch on it later. */ ! 355: sync = !ISSET(bp->b_flags, B_ASYNC); ! 356: wasdelayed = ISSET(bp->b_flags, B_DELWRI); ! 357: CLR(bp->b_flags, (B_READ | B_DONE | B_ERROR | B_DELWRI)); ! 358: ! 359: if (!sync) { ! 360: /* ! 361: * If not synchronous, pay for the I/O operation and make ! 362: * sure the buf is on the correct vnode queue. We have ! 363: * to do this now, because if we don't, the vnode may not ! 364: * be properly notified that its I/O has completed. ! 365: */ ! 366: if (wasdelayed) ! 367: reassignbuf(bp, bp->b_vp); ! 368: else ! 369: if (p && p->p_stats) ! 370: p->p_stats->p_ru.ru_oublock++; /* XXX */ ! 371: } ! 372: ! 373: trace(TR_BWRITE, pack(bp->b_vp, bp->b_bcount), bp->b_lblkno); ! 374: ! 375: /* Initiate disk write. Make sure the appropriate party is charged. */ ! 376: SET(bp->b_flags, B_WRITEINPROG); ! 377: bp->b_vp->v_numoutput++; ! 378: VOP_STRATEGY(bp); ! 379: ! 380: if (sync) { ! 381: /* ! 382: * If I/O was synchronous, wait for it to complete. ! 383: */ ! 384: rv = biowait(bp); ! 385: ! 386: /* ! 387: * Pay for the I/O operation, if it's not been paid for, and ! 388: * make sure it's on the correct vnode queue. (async operatings ! 389: * were payed for above.) ! 390: */ ! 391: if (wasdelayed) ! 392: reassignbuf(bp, bp->b_vp); ! 393: else ! 394: if (p && p->p_stats) ! 395: p->p_stats->p_ru.ru_oublock++; /* XXX */ ! 396: ! 397: /* Release the buffer. */ ! 398: brelse(bp); ! 399: ! 400: return (rv); ! 401: } else { ! 402: return (0); ! 403: } ! 404: } ! 405: ! 406: int ! 407: vn_bwrite(ap) ! 408: struct vop_bwrite_args *ap; ! 409: { ! 410: ! 411: return (bwrite(ap->a_bp)); ! 412: } ! 413: ! 414: /* ! 415: * Delayed write. ! 416: * ! 417: * The buffer is marked dirty, but is not queued for I/O. ! 418: * This routine should be used when the buffer is expected ! 419: * to be modified again soon, typically a small write that ! 420: * partially fills a buffer. ! 421: * ! 422: * NB: magnetic tapes cannot be delayed; they must be ! 423: * written in the order that the writes are requested. ! 424: * ! 425: * Described in Leffler, et al. (pp. 208-213). ! 426: */ ! 427: void ! 428: bdwrite(bp) ! 429: struct buf *bp; ! 430: { ! 431: struct proc *p = current_proc(); ! 432: ! 433: /* ! 434: * If the block hasn't been seen before: ! 435: * (1) Mark it as having been seen, ! 436: * (2) Charge for the write. ! 437: * (3) Make sure it's on its vnode's correct block list, ! 438: */ ! 439: if (!ISSET(bp->b_flags, B_DELWRI)) { ! 440: SET(bp->b_flags, B_DELWRI); ! 441: if (p && p->p_stats) ! 442: p->p_stats->p_ru.ru_oublock++; /* XXX */ ! 443: reassignbuf(bp, bp->b_vp); ! 444: } ! 445: ! 446: /* If this is a tape block, write it the block now. */ ! 447: if (ISSET(bp->b_flags, B_TAPE)) { ! 448: bwrite(bp); ! 449: return; ! 450: } ! 451: ! 452: /* Otherwise, the "write" is done, so mark and release the buffer. */ ! 453: SET(bp->b_flags, B_DONE); ! 454: brelse(bp); ! 455: } ! 456: ! 457: /* ! 458: * Asynchronous block write; just an asynchronous bwrite(). ! 459: */ ! 460: void ! 461: bawrite(bp) ! 462: struct buf *bp; ! 463: { ! 464: ! 465: SET(bp->b_flags, B_ASYNC); ! 466: VOP_BWRITE(bp); ! 467: } ! 468: ! 469: /* ! 470: * Release a buffer on to the free lists. ! 471: * Described in Bach (p. 46). ! 472: */ ! 473: void ! 474: brelse(bp) ! 475: struct buf *bp; ! 476: { ! 477: struct bqueues *bufq; ! 478: int s; ! 479: ! 480: trace(TR_BRELSE, pack(bp->b_vp, bp->b_bufsize), bp->b_lblkno); ! 481: ! 482: /* Wake up any processes waiting for any buffer to become free. */ ! 483: if (needbuffer) { ! 484: needbuffer = 0; ! 485: wakeup(&needbuffer); ! 486: } ! 487: ! 488: /* Wake up any proceeses waiting for _this_ buffer to become free. */ ! 489: if (ISSET(bp->b_flags, B_WANTED)) { ! 490: CLR(bp->b_flags, B_WANTED); ! 491: wakeup(bp); ! 492: } ! 493: ! 494: /* Block disk interrupts. */ ! 495: s = splbio(); ! 496: ! 497: /* ! 498: * Determine which queue the buffer should be on, then put it there. ! 499: */ ! 500: ! 501: /* If it's locked, don't report an error; try again later. */ ! 502: if (ISSET(bp->b_flags, (B_LOCKED|B_ERROR)) == (B_LOCKED|B_ERROR)) ! 503: CLR(bp->b_flags, B_ERROR); ! 504: ! 505: /* If it's not cacheable, or an error, mark it invalid. */ ! 506: if (ISSET(bp->b_flags, (B_NOCACHE|B_ERROR))) ! 507: SET(bp->b_flags, B_INVAL); ! 508: ! 509: if ((bp->b_bufsize <= 0) || ISSET(bp->b_flags, B_INVAL)) { ! 510: /* ! 511: * If it's invalid or empty, dissociate it from its vnode ! 512: * and put on the head of the appropriate queue. ! 513: */ ! 514: if (bp->b_vp) ! 515: brelvp(bp); ! 516: CLR(bp->b_flags, B_DELWRI); ! 517: if (bp->b_bufsize <= 0) ! 518: /* no data */ ! 519: bufq = &bufqueues[BQ_EMPTY]; ! 520: else ! 521: /* invalid data */ ! 522: bufq = &bufqueues[BQ_AGE]; ! 523: binsheadfree(bp, bufq); ! 524: } else { ! 525: /* ! 526: * It has valid data. Put it on the end of the appropriate ! 527: * queue, so that it'll stick around for as long as possible. ! 528: */ ! 529: if (ISSET(bp->b_flags, B_LOCKED)) ! 530: /* locked in core */ ! 531: bufq = &bufqueues[BQ_LOCKED]; ! 532: else if (ISSET(bp->b_flags, B_AGE)) ! 533: /* stale but valid data */ ! 534: bufq = &bufqueues[BQ_AGE]; ! 535: else ! 536: /* valid data */ ! 537: bufq = &bufqueues[BQ_LRU]; ! 538: binstailfree(bp, bufq); ! 539: } ! 540: ! 541: /* Unlock the buffer. */ ! 542: CLR(bp->b_flags, (B_AGE | B_ASYNC | B_BUSY | B_NOCACHE)); ! 543: ! 544: /* Allow disk interrupts. */ ! 545: splx(s); ! 546: } ! 547: ! 548: /* ! 549: * Determine if a block is in the cache. ! 550: * Just look on what would be its hash chain. If it's there, return ! 551: * a pointer to it, unless it's marked invalid. If it's marked invalid, ! 552: * we normally don't return the buffer, unless the caller explicitly ! 553: * wants us to. ! 554: */ ! 555: struct buf * ! 556: incore(vp, blkno) ! 557: struct vnode *vp; ! 558: daddr_t blkno; ! 559: { ! 560: struct buf *bp; ! 561: ! 562: bp = BUFHASH(vp, blkno)->lh_first; ! 563: ! 564: /* Search hash chain */ ! 565: for (; bp != NULL; bp = bp->b_hash.le_next) { ! 566: if (bp->b_lblkno == blkno && bp->b_vp == vp && ! 567: !ISSET(bp->b_flags, B_INVAL)) ! 568: return (bp); ! 569: } ! 570: ! 571: return (0); ! 572: } ! 573: ! 574: /* ! 575: * Get a block of requested size that is associated with ! 576: * a given vnode and block offset. If it is found in the ! 577: * block cache, mark it as having been found, make it busy ! 578: * and return it. Otherwise, return an empty block of the ! 579: * correct size. It is up to the caller to insure that the ! 580: * cached blocks be of the correct size. ! 581: */ ! 582: struct buf * ! 583: getblk(vp, blkno, size, slpflag, slptimeo) ! 584: register struct vnode *vp; ! 585: daddr_t blkno; ! 586: int size, slpflag, slptimeo; ! 587: { ! 588: struct buf *bp; ! 589: int s, err; ! 590: ! 591: start: ! 592: s = splbio(); ! 593: if (bp = incore(vp, blkno)) { /* XXX NFS VOP_BWRITE foolishness */ ! 594: if (ISSET(bp->b_flags, B_BUSY)) { ! 595: SET(bp->b_flags, B_WANTED); ! 596: err = tsleep(bp, slpflag | (PRIBIO + 1), "getblk", ! 597: slptimeo); ! 598: splx(s); ! 599: if (err) ! 600: return (NULL); ! 601: goto start; ! 602: } ! 603: SET(bp->b_flags, (B_BUSY | B_CACHE)); ! 604: bremfree(bp); ! 605: splx(s); ! 606: allocbuf(bp, size); ! 607: } else { ! 608: splx(s); ! 609: if ((bp = getnewbuf(slpflag, slptimeo)) == NULL) ! 610: goto start; ! 611: binshash(bp, BUFHASH(vp, blkno)); ! 612: allocbuf(bp, size); ! 613: bp->b_blkno = bp->b_lblkno = blkno; ! 614: s = splbio(); ! 615: bgetvp(vp, bp); ! 616: splx(s); ! 617: } ! 618: return (bp); ! 619: } ! 620: ! 621: /* ! 622: * Get an empty, disassociated buffer of given size. ! 623: */ ! 624: struct buf * ! 625: geteblk(size) ! 626: int size; ! 627: { ! 628: struct buf *bp; ! 629: ! 630: while ((bp = getnewbuf(0, 0)) == 0) ! 631: ; ! 632: SET(bp->b_flags, B_INVAL); ! 633: binshash(bp, &invalhash); ! 634: allocbuf(bp, size); ! 635: ! 636: return (bp); ! 637: } ! 638: ! 639: /* ! 640: * Expand or contract the actual memory allocated to a buffer. ! 641: * ! 642: * If the buffer shrinks, data is lost, so it's up to the ! 643: * caller to have written it out *first*; this routine will not ! 644: * start a write. If the buffer grows, it's the callers ! 645: * responsibility to fill out the buffer's additional contents. ! 646: */ ! 647: int ! 648: allocbuf(bp, size) ! 649: struct buf *bp; ! 650: int size; ! 651: { ! 652: struct buf *nbp; ! 653: vm_size_t desired_size; ! 654: int s; ! 655: ! 656: desired_size = roundup(size, CLBYTES); ! 657: if (desired_size > MAXBSIZE) ! 658: panic("allocbuf: buffer larger than MAXBSIZE requested"); ! 659: ! 660: if (bp->b_bufsize == desired_size) ! 661: goto out; ! 662: ! 663: /* ! 664: * If the buffer is smaller than the desired size, we need to snarf ! 665: * it from other buffers. Get buffers (via getnewbuf()), and ! 666: * steal their pages. ! 667: */ ! 668: while (bp->b_bufsize < desired_size) { ! 669: int amt; ! 670: ! 671: /* find a buffer */ ! 672: while ((nbp = getnewbuf(0, 0)) == NULL) ! 673: ; ! 674: SET(nbp->b_flags, B_INVAL); ! 675: binshash(nbp, &invalhash); ! 676: ! 677: /* and steal its pages, up to the amount we need */ ! 678: amt = min(nbp->b_bufsize, (desired_size - bp->b_bufsize)); ! 679: pagemove((nbp->b_data + nbp->b_bufsize - amt), ! 680: bp->b_data + bp->b_bufsize, amt); ! 681: bp->b_bufsize += amt; ! 682: nbp->b_bufsize -= amt; ! 683: ! 684: /* reduce transfer count if we stole some data */ ! 685: if (nbp->b_bcount > nbp->b_bufsize) ! 686: nbp->b_bcount = nbp->b_bufsize; ! 687: ! 688: #if DIAGNOSTIC ! 689: if (nbp->b_bufsize < 0) ! 690: panic("allocbuf: negative bufsize"); ! 691: #endif ! 692: ! 693: brelse(nbp); ! 694: } ! 695: ! 696: /* ! 697: * If we want a buffer smaller than the current size, ! 698: * shrink this buffer. Grab a buf head from the EMPTY queue, ! 699: * move a page onto it, and put it on front of the AGE queue. ! 700: * If there are no free buffer headers, leave the buffer alone. ! 701: */ ! 702: if (bp->b_bufsize > desired_size) { ! 703: s = splbio(); ! 704: if ((nbp = bufqueues[BQ_EMPTY].tqh_first) == NULL) { ! 705: /* No free buffer head */ ! 706: splx(s); ! 707: goto out; ! 708: } ! 709: bremfree(nbp); ! 710: SET(nbp->b_flags, B_BUSY); ! 711: splx(s); ! 712: ! 713: /* move the page to it and note this change */ ! 714: pagemove(bp->b_data + desired_size, ! 715: nbp->b_data, bp->b_bufsize - desired_size); ! 716: nbp->b_bufsize = bp->b_bufsize - desired_size; ! 717: bp->b_bufsize = desired_size; ! 718: nbp->b_bcount = 0; ! 719: SET(nbp->b_flags, B_INVAL); ! 720: ! 721: /* release the newly-filled buffer and leave */ ! 722: brelse(nbp); ! 723: } ! 724: ! 725: out: ! 726: bp->b_bcount = size; ! 727: } ! 728: ! 729: /* ! 730: * Find a buffer which is available for use. ! 731: * Select something from a free list. ! 732: * Preference is to AGE list, then LRU list. ! 733: */ ! 734: struct buf * ! 735: getnewbuf(slpflag, slptimeo) ! 736: int slpflag, slptimeo; ! 737: { ! 738: register struct buf *bp; ! 739: int s; ! 740: struct ucred *cred; ! 741: ! 742: start: ! 743: s = splbio(); ! 744: if ((bp = bufqueues[BQ_AGE].tqh_first) != NULL || ! 745: (bp = bufqueues[BQ_LRU].tqh_first) != NULL) { ! 746: bremfree(bp); ! 747: } else { ! 748: /* wait for a free buffer of any kind */ ! 749: needbuffer = 1; ! 750: tsleep(&needbuffer, slpflag|(PRIBIO+1), "getnewbuf", slptimeo); ! 751: splx(s); ! 752: return (0); ! 753: } ! 754: ! 755: /* Buffer is no longer on free lists. */ ! 756: SET(bp->b_flags, B_BUSY); ! 757: splx(s); ! 758: ! 759: /* If buffer was a delayed write, start it, and go back to the top. */ ! 760: if (ISSET(bp->b_flags, B_DELWRI)) { ! 761: bawrite (bp); ! 762: goto start; ! 763: } ! 764: ! 765: trace(TR_BRELSE, pack(bp->b_vp, bp->b_bufsize), bp->b_lblkno); ! 766: ! 767: /* disassociate us from our vnode, if we had one... */ ! 768: s = splbio(); ! 769: if (bp->b_vp) ! 770: brelvp(bp); ! 771: splx(s); ! 772: ! 773: /* clear out various other fields */ ! 774: bp->b_flags = B_BUSY; ! 775: bp->b_dev = NODEV; ! 776: bp->b_blkno = bp->b_lblkno = 0; ! 777: bp->b_iodone = 0; ! 778: bp->b_error = 0; ! 779: bp->b_resid = 0; ! 780: bp->b_bcount = 0; ! 781: bp->b_dirtyoff = bp->b_dirtyend = 0; ! 782: bp->b_validoff = bp->b_validend = 0; ! 783: ! 784: /* nuke any credentials we were holding */ ! 785: cred = bp->b_rcred; ! 786: if (cred != NOCRED) { ! 787: bp->b_rcred = NOCRED; ! 788: crfree(cred); ! 789: } ! 790: cred = bp->b_wcred; ! 791: if (cred != NOCRED) { ! 792: bp->b_wcred = NOCRED; ! 793: crfree(cred); ! 794: } ! 795: ! 796: bremhash(bp); ! 797: return (bp); ! 798: } ! 799: ! 800: /* ! 801: * Wait for operations on the buffer to complete. ! 802: * When they do, extract and return the I/O's error value. ! 803: */ ! 804: int ! 805: biowait(bp) ! 806: struct buf *bp; ! 807: { ! 808: int s; ! 809: ! 810: s = splbio(); ! 811: while (!ISSET(bp->b_flags, B_DONE)) ! 812: tsleep(bp, PRIBIO + 1, "biowait", 0); ! 813: splx(s); ! 814: ! 815: /* check for interruption of I/O (e.g. via NFS), then errors. */ ! 816: if (ISSET(bp->b_flags, B_EINTR)) { ! 817: CLR(bp->b_flags, B_EINTR); ! 818: return (EINTR); ! 819: } else if (ISSET(bp->b_flags, B_ERROR)) ! 820: return (bp->b_error ? bp->b_error : EIO); ! 821: else ! 822: return (0); ! 823: } ! 824: ! 825: /* ! 826: * Mark I/O complete on a buffer. ! 827: * ! 828: * If a callback has been requested, e.g. the pageout ! 829: * daemon, do so. Otherwise, awaken waiting processes. ! 830: * ! 831: * [ Leffler, et al., says on p.247: ! 832: * "This routine wakes up the blocked process, frees the buffer ! 833: * for an asynchronous write, or, for a request by the pagedaemon ! 834: * process, invokes a procedure specified in the buffer structure" ] ! 835: * ! 836: * In real life, the pagedaemon (or other system processes) wants ! 837: * to do async stuff to, and doesn't want the buffer brelse()'d. ! 838: * (for swap pager, that puts swap buffers on the free lists (!!!), ! 839: * for the vn device, that puts malloc'd buffers on the free lists!) ! 840: */ ! 841: void ! 842: biodone(bp) ! 843: struct buf *bp; ! 844: { ! 845: if (ISSET(bp->b_flags, B_DONE)) ! 846: panic("biodone already"); ! 847: SET(bp->b_flags, B_DONE); /* note that it's done */ ! 848: ! 849: if (!ISSET(bp->b_flags, B_READ) && !ISSET(bp->b_flags, B_RAW)) /* wake up reader */ ! 850: vwakeup(bp); ! 851: ! 852: if (ISSET(bp->b_flags, B_CALL)) { /* if necessary, call out */ ! 853: CLR(bp->b_flags, B_CALL); /* but note callout done */ ! 854: (*bp->b_iodone)(bp); ! 855: } else if (ISSET(bp->b_flags, B_ASYNC)) /* if async, release it */ ! 856: brelse(bp); ! 857: else { /* or just wakeup the buffer */ ! 858: CLR(bp->b_flags, B_WANTED); ! 859: wakeup(bp); ! 860: } ! 861: } ! 862: ! 863: /* ! 864: * Return a count of buffers on the "locked" queue. ! 865: */ ! 866: int ! 867: count_lock_queue() ! 868: { ! 869: register struct buf *bp; ! 870: register int n = 0; ! 871: ! 872: for (bp = bufqueues[BQ_LOCKED].tqh_first; bp; ! 873: bp = bp->b_freelist.tqe_next) ! 874: n++; ! 875: return (n); ! 876: } ! 877: ! 878: #if MACH_NBC ! 879: #include <ufs/ufs/quota.h> ! 880: #include <ufs/ufs/inode.h> ! 881: ! 882: #define btodevblk(b) ((b) / devBlocksize) ! 883: void ! 884: blkflush(struct vnode *vp, daddr_t blkno, vm_size_t size) ! 885: { ! 886: register struct buf *ep, *nbp; ! 887: daddr_t start, last; ! 888: int s,err; ! 889: struct inode *ip= VTOI(vp); ! 890: int devBlocksize=1024; ! 891: ! 892: #if 1 ! 893: VOP_DEVBLOCKSIZE(ip->i_devvp, &devBlocksize); ! 894: #endif ! 895: ! 896: ! 897: start = blkno; ! 898: last = start + btodb(size, devBlocksize) - 1; ! 899: loop: ! 900: for(ep = vp->v_dirtyblkhd.lh_first; ep; ep = nbp) { ! 901: nbp = ep->b_vnbufs.le_next; ! 902: if (ep->b_vp != vp || ISSET(ep->b_flags, B_INVAL)) ! 903: continue; ! 904: /* look for overlap */ ! 905: if (ep->b_bcount == 0 || ep->b_blkno > last || ! 906: ep->b_blkno + btodevblk(ep->b_bcount) <= start) ! 907: continue; ! 908: s = splbio(); ! 909: if (ISSET(ep->b_flags, B_BUSY)) { ! 910: SET(ep->b_flags, B_WANTED); ! 911: err = tsleep(ep, (PRIBIO + 1), "blkflush", ! 912: 0); ! 913: splx(s); ! 914: goto loop; ! 915: } ! 916: if(ISSET(ep->b_flags, B_DELWRI)) { ! 917: bremfree(ep); ! 918: SET(ep->b_flags, B_BUSY); ! 919: (void) splx(s); ! 920: bwrite(ep); ! 921: goto loop; ! 922: } ! 923: (void) splx(s); ! 924: } ! 925: ! 926: } ! 927: #endif /* MACH_NBC */ ! 928: #if DIAGNOSTIC ! 929: /* ! 930: * Print out statistics on the current allocation of the buffer pool. ! 931: * Can be enabled to print out on every ``sync'' by setting "syncprt" ! 932: * in vfs_syscalls.c using sysctl. ! 933: */ ! 934: void ! 935: vfs_bufstats() ! 936: { ! 937: int s, i, j, count; ! 938: register struct buf *bp; ! 939: register struct bqueues *dp; ! 940: int counts[MAXBSIZE/CLBYTES+1]; ! 941: static char *bname[BQUEUES] = { "LOCKED", "LRU", "AGE", "EMPTY" }; ! 942: ! 943: for (dp = bufqueues, i = 0; dp < &bufqueues[BQUEUES]; dp++, i++) { ! 944: count = 0; ! 945: for (j = 0; j <= MAXBSIZE/CLBYTES; j++) ! 946: counts[j] = 0; ! 947: s = splbio(); ! 948: for (bp = dp->tqh_first; bp; bp = bp->b_freelist.tqe_next) { ! 949: counts[bp->b_bufsize/CLBYTES]++; ! 950: count++; ! 951: } ! 952: splx(s); ! 953: printf("%s: total-%d", bname[i], count); ! 954: for (j = 0; j <= MAXBSIZE/CLBYTES; j++) ! 955: if (counts[j] != 0) ! 956: printf(", %d-%d", j * CLBYTES, counts[j]); ! 957: printf("\n"); ! 958: } ! 959: } ! 960: #endif /* DIAGNOSTIC */ ! 961: ! 962: ! 963: struct buf * ! 964: alloc_io_buf(vp) ! 965: struct vnode *vp; ! 966: { register struct buf *bp; ! 967: int s; ! 968: ! 969: s = splbio(); ! 970: ! 971: if ((bp = iobufqueue.tqh_first) == NULL) { ! 972: splx(s); ! 973: return (NULL); ! 974: } ! 975: TAILQ_REMOVE(&iobufqueue, bp, b_freelist); ! 976: ! 977: /* clear out various fields */ ! 978: bp->b_flags = (B_BUSY | B_RAW); ! 979: bp->b_blkno = bp->b_lblkno = 0; ! 980: bp->b_iodone = 0; ! 981: bp->b_error = 0; ! 982: bp->b_resid = 0; ! 983: bp->b_bcount = 0; ! 984: bp->b_bufsize = 0; ! 985: bp->b_vp = vp; ! 986: ! 987: if (vp->v_type == VBLK || vp->v_type == VCHR) ! 988: bp->b_dev = vp->v_rdev; ! 989: else ! 990: bp->b_dev = NODEV; ! 991: splx(s); ! 992: ! 993: return (bp); ! 994: } ! 995: ! 996: void ! 997: free_io_buf(bp) ! 998: struct buf *bp; ! 999: { ! 1000: int s; ! 1001: ! 1002: s = splbio(); ! 1003: /* ! 1004: * put buffer back on the head of the iobufqueue ! 1005: */ ! 1006: bp->b_vp = NULL; ! 1007: bp->b_flags = B_INVAL; ! 1008: ! 1009: binsheadfree(bp, &iobufqueue); ! 1010: ! 1011: splx(s); ! 1012: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.