Annotation of Net2/kern/vfs__bio.c, revision 1.1.1.1

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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.