[BACK]Return to vfs_bio.c CVS log [TXT][DIR] Up to [local] / prex-old / usr / server / fs / vfs

Annotation of prex-old/usr/server/fs/vfs/vfs_bio.c, Revision 1.1.1.1.2.1

1.1       nbrk        1: /*
                      2:  * Copyright (c) 2005-2007, Kohsuke Ohtani
                      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. Neither the name of the author nor the names of any co-contributors
                     14:  *    may be used to endorse or promote products derived from this software
                     15:  *    without specific prior written permission.
                     16:  *
                     17:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
                     18:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     19:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     20:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
                     21:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     22:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     23:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     24:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     25:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     26:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     27:  * SUCH DAMAGE.
                     28:  */
                     29:
                     30: /*
                     31:  * bio.c - buffered I/O operations
                     32:  */
                     33:
                     34: /*
                     35:  * References:
                     36:  *     Bach: The Design of the UNIX Operating System (Prentice Hall, 1986)
                     37:  */
                     38:
                     39: #include <prex/prex.h>
                     40: #include <sys/list.h>
                     41: #include <sys/param.h>
                     42: #include <sys/buf.h>
                     43:
                     44: #include <limits.h>
                     45: #include <unistd.h>
                     46: #include <stdlib.h>
                     47: #include <string.h>
                     48:
                     49: #include "vfs.h"
                     50:
                     51: /* number of buffer cache */
1.1.1.1.2.1! nbrk       52: #define NBUFS          CONFIG_BUF_CACHE
1.1       nbrk       53:
                     54: /* macros to clear/set/test flags. */
                     55: #define        SET(t, f)       (t) |= (f)
                     56: #define        CLR(t, f)       (t) &= ~(f)
                     57: #define        ISSET(t, f)     ((t) & (f))
                     58:
                     59: /*
                     60:  * Global lock to access all buffer headers and lists.
                     61:  */
                     62: #if CONFIG_FS_THREADS > 1
                     63: static mutex_t bio_lock = MUTEX_INITIALIZER;
                     64: #define BIO_LOCK()     mutex_lock(&bio_lock)
                     65: #define BIO_UNLOCK()   mutex_unlock(&bio_lock)
                     66: #else
                     67: #define BIO_LOCK()
                     68: #define BIO_UNLOCK()
                     69: #endif
                     70:
                     71:
                     72: /* set of buffers */
1.1.1.1.2.1! nbrk       73: static char buffers[NBUFS][BSIZE];
1.1       nbrk       74:
1.1.1.1.2.1! nbrk       75: static struct buf buf_table[NBUFS];
1.1       nbrk       76: static struct list free_list = LIST_INIT(free_list);
                     77:
                     78: static sem_t free_sem;
                     79:
                     80:
                     81: /*
                     82:  * Insert buffer to the head of free list
                     83:  */
                     84: static void
1.1.1.1.2.1! nbrk       85: bio_insert_head(struct buf *bp)
1.1       nbrk       86: {
                     87:
                     88:        list_insert(&free_list, &bp->b_link);
                     89:        sem_post(&free_sem);
                     90: }
                     91:
                     92: /*
                     93:  * Insert buffer to the tail of free list
                     94:  */
                     95: static void
1.1.1.1.2.1! nbrk       96: bio_insert_tail(struct buf *bp)
1.1       nbrk       97: {
                     98:
                     99:        list_insert(list_prev(&free_list), &bp->b_link);
                    100:        sem_post(&free_sem);
                    101: }
                    102:
                    103: /*
                    104:  * Remove buffer from free list
                    105:  */
                    106: static void
1.1.1.1.2.1! nbrk      107: bio_remove(struct buf *bp)
1.1       nbrk      108: {
                    109:
                    110:        sem_wait(&free_sem, 0);
                    111:        ASSERT(!list_empty(&free_list));
                    112:        list_remove(&bp->b_link);
                    113: }
                    114:
                    115: /*
                    116:  * Remove buffer from the head of free list
                    117:  */
                    118: static struct buf *
1.1.1.1.2.1! nbrk      119: bio_remove_head(void)
1.1       nbrk      120: {
                    121:        struct buf *bp;
                    122:
                    123:        sem_wait(&free_sem, 0);
                    124:        ASSERT(!list_empty(&free_list));
                    125:        bp = list_entry(list_first(&free_list), struct buf, b_link);
                    126:        list_remove(&bp->b_link);
                    127:        return bp;
                    128: }
                    129:
                    130: /*
                    131:  * Determine if a block is in the cache.
                    132:  */
                    133: static struct buf *
                    134: incore(dev_t dev, int blkno)
                    135: {
                    136:        struct buf *bp;
                    137:        int i;
                    138:
1.1.1.1.2.1! nbrk      139:        for (i = 0; i < NBUFS; i++) {
1.1       nbrk      140:                bp = &buf_table[i];
                    141:                if (bp->b_blkno == blkno && bp->b_dev == dev &&
                    142:                    !ISSET(bp->b_flags, B_INVAL))
                    143:                        return bp;
                    144:        }
                    145:        return NULL;
                    146: }
                    147:
                    148: /*
                    149:  * Assign a buffer for the given block.
                    150:  *
1.1.1.1.2.1! nbrk      151:  * The block is selected from the buffer list with LRU
        !           152:  * algorithm.  If the appropriate block already exists in the
        !           153:  * block list, return it.  Otherwise, the least recently used
        !           154:  * block is used.
1.1       nbrk      155:  */
                    156: struct buf *
                    157: getblk(dev_t dev, int blkno)
                    158: {
                    159:        struct buf *bp;
                    160:
1.1.1.1.2.1! nbrk      161:        DPRINTF(VFSDB_BIO, ("getblk: dev=%x blkno=%d\n", dev, blkno));
1.1       nbrk      162:  start:
                    163:        BIO_LOCK();
                    164:        bp = incore(dev, blkno);
                    165:        if (bp != NULL) {
1.1.1.1.2.1! nbrk      166:                /* Block found in cache. */
1.1       nbrk      167:                if (ISSET(bp->b_flags, B_BUSY)) {
                    168:                        BIO_UNLOCK();
                    169:                        mutex_lock(&bp->b_lock);
                    170:                        mutex_unlock(&bp->b_lock);
1.1.1.1.2.1! nbrk      171:                        /* Scan again if it's busy */
1.1       nbrk      172:                        goto start;
                    173:                }
1.1.1.1.2.1! nbrk      174:                bio_remove(bp);
1.1       nbrk      175:                SET(bp->b_flags, B_BUSY);
                    176:        } else {
1.1.1.1.2.1! nbrk      177:                bp = bio_remove_head();
1.1       nbrk      178:                if (ISSET(bp->b_flags, B_DELWRI)) {
                    179:                        BIO_UNLOCK();
                    180:                        bwrite(bp);
                    181:                        goto start;
                    182:                }
                    183:                bp->b_flags = B_BUSY;
                    184:                bp->b_dev = dev;
                    185:                bp->b_blkno = blkno;
                    186:        }
                    187:        mutex_lock(&bp->b_lock);
                    188:        BIO_UNLOCK();
1.1.1.1.2.1! nbrk      189:        DPRINTF(VFSDB_BIO, ("getblk: done bp=%x\n", bp));
1.1       nbrk      190:        return bp;
                    191: }
                    192:
                    193: /*
                    194:  * Release a buffer, with no I/O implied.
                    195:  */
                    196: void
                    197: brelse(struct buf *bp)
                    198: {
                    199:        ASSERT(ISSET(bp->b_flags, B_BUSY));
1.1.1.1.2.1! nbrk      200:        DPRINTF(VFSDB_BIO, ("brelse: bp=%x dev=%x blkno=%d\n",
        !           201:                                bp, bp->b_dev, bp->b_blkno));
1.1       nbrk      202:
                    203:        BIO_LOCK();
                    204:        CLR(bp->b_flags, B_BUSY);
                    205:        mutex_unlock(&bp->b_lock);
                    206:        if (ISSET(bp->b_flags, B_INVAL))
1.1.1.1.2.1! nbrk      207:                bio_insert_head(bp);
1.1       nbrk      208:        else
1.1.1.1.2.1! nbrk      209:                bio_insert_tail(bp);
1.1       nbrk      210:        BIO_UNLOCK();
                    211: }
                    212:
                    213: /*
                    214:  * Block read with cache.
                    215:  * @dev:   device id to read from.
                    216:  * @blkno: block number.
                    217:  * @buf:   buffer pointer to be returned.
                    218:  *
1.1.1.1.2.1! nbrk      219:  * An actual read operation is done only when the cached
        !           220:  * buffer is dirty.
1.1       nbrk      221:  */
                    222: int
                    223: bread(dev_t dev, int blkno, struct buf **bpp)
                    224: {
                    225:        struct buf *bp;
                    226:        size_t size;
                    227:        int err;
                    228:
1.1.1.1.2.1! nbrk      229:        DPRINTF(VFSDB_BIO, ("bread: dev=%x blkno=%d\n", dev, blkno));
1.1       nbrk      230:        bp = getblk(dev, blkno);
                    231:
                    232:        if (!ISSET(bp->b_flags, (B_DONE | B_DELWRI))) {
                    233:                size = BSIZE;
                    234:                err = device_read((device_t)dev, bp->b_data, &size, blkno);
                    235:                if (err) {
1.1.1.1.2.1! nbrk      236:                        DPRINTF(VFSDB_BIO, ("bread: i/o error\n"));
1.1       nbrk      237:                        brelse(bp);
                    238:                        return err;
                    239:                }
                    240:        }
                    241:        CLR(bp->b_flags, B_INVAL);
                    242:        SET(bp->b_flags, (B_READ | B_DONE));
1.1.1.1.2.1! nbrk      243:        DPRINTF(VFSDB_BIO, ("bread: done bp=%x\n\n", bp));
1.1       nbrk      244:        *bpp = bp;
                    245:        return 0;
                    246: }
                    247:
                    248: /*
                    249:  * Block write with cache.
                    250:  * @buf:   buffer to write.
                    251:  *
1.1.1.1.2.1! nbrk      252:  * The data is copied to the buffer.
        !           253:  * Then release the buffer.
1.1       nbrk      254:  */
                    255: int
                    256: bwrite(struct buf *bp)
                    257: {
                    258:        size_t size;
                    259:        int err;
                    260:
                    261:        ASSERT(ISSET(bp->b_flags, B_BUSY));
1.1.1.1.2.1! nbrk      262:        DPRINTF(VFSDB_BIO, ("bwrite: dev=%x blkno=%d\n", bp->b_dev,
        !           263:                            bp->b_blkno));
1.1       nbrk      264:
                    265:        BIO_LOCK();
                    266:        CLR(bp->b_flags, (B_READ | B_DONE | B_DELWRI));
                    267:        BIO_UNLOCK();
                    268:
                    269:        size = BSIZE;
                    270:        err = device_write((device_t)bp->b_dev, bp->b_data, &size,
                    271:                           bp->b_blkno);
                    272:        if (err)
                    273:                return err;
                    274:        BIO_LOCK();
                    275:        SET(bp->b_flags, B_DONE);
                    276:        BIO_UNLOCK();
                    277:        brelse(bp);
                    278:        return 0;
                    279: }
                    280:
                    281: /*
                    282:  * Delayed write.
                    283:  *
1.1.1.1.2.1! nbrk      284:  * The buffer is marked dirty, but an actual I/O is not
        !           285:  * performed.  This routine should be used when the buffer
        !           286:  * is expected to be modified again soon.
1.1       nbrk      287:  */
                    288: void
                    289: bdwrite(struct buf *bp)
                    290: {
                    291:
                    292:        BIO_LOCK();
                    293:        SET(bp->b_flags, B_DELWRI);
                    294:        CLR(bp->b_flags, B_DONE);
                    295:        BIO_UNLOCK();
                    296:        brelse(bp);
                    297: }
                    298:
                    299: /*
                    300:  * Flush write-behind block
                    301:  */
                    302: void
                    303: bflush(struct buf *bp)
                    304: {
                    305:
                    306:        BIO_LOCK();
                    307:        if (ISSET(bp->b_flags, B_DELWRI))
                    308:                bwrite(bp);
                    309:        BIO_UNLOCK();
                    310: }
                    311:
                    312: /*
                    313:  * Invalidate buffer for specified device.
                    314:  * This is called when unmount.
                    315:  */
                    316: void
                    317: binval(dev_t dev)
                    318: {
                    319:        struct buf *bp;
                    320:        int i;
                    321:
                    322:        BIO_LOCK();
1.1.1.1.2.1! nbrk      323:        for (i = 0; i < NBUFS; i++) {
1.1       nbrk      324:                bp = &buf_table[i];
                    325:                if (bp->b_dev == dev) {
                    326:                        if (ISSET(bp->b_flags, B_DELWRI))
                    327:                                bwrite(bp);
                    328:                        else if (ISSET(bp->b_flags, B_BUSY))
                    329:                                brelse(bp);
                    330:                        bp->b_flags = B_INVAL;
                    331:                }
                    332:        }
                    333:        BIO_UNLOCK();
                    334: }
                    335:
                    336: /*
1.1.1.1.2.1! nbrk      337:  * Invalidate all buffers.
1.1       nbrk      338:  * This is called when unmount.
                    339:  */
                    340: void
                    341: bio_sync(void)
                    342: {
                    343:        struct buf *bp;
                    344:        int i;
                    345:
                    346:  start:
                    347:        BIO_LOCK();
1.1.1.1.2.1! nbrk      348:        for (i = 0; i < NBUFS; i++) {
1.1       nbrk      349:                bp = &buf_table[i];
                    350:                if (ISSET(bp->b_flags, B_BUSY)) {
                    351:                        BIO_UNLOCK();
                    352:                        mutex_lock(&bp->b_lock);
                    353:                        mutex_unlock(&bp->b_lock);
                    354:                        goto start;
                    355:                }
                    356:                if (ISSET(bp->b_flags, B_DELWRI))
                    357:                        bwrite(bp);
                    358:        }
                    359:        BIO_UNLOCK();
                    360: }
                    361:
                    362: /*
1.1.1.1.2.1! nbrk      363:  * Initialize the buffer I/O system.
1.1       nbrk      364:  */
                    365: void
                    366: bio_init(void)
                    367: {
                    368:        struct buf *bp;
                    369:        int i;
                    370:
1.1.1.1.2.1! nbrk      371:        for (i = 0; i < NBUFS; i++) {
1.1       nbrk      372:                bp = &buf_table[i];
                    373:                bp->b_flags = B_INVAL;
1.1.1.1.2.1! nbrk      374:                bp->b_data = buffers[i];
1.1       nbrk      375:                mutex_init(&bp->b_lock);
                    376:                list_insert(&free_list, &bp->b_link);
                    377:        }
1.1.1.1.2.1! nbrk      378:        sem_init(&free_sem, NBUFS);
        !           379:        DPRINTF(VFSDB_BIO, ("bio: Buffer cache size %dK bytes\n",
        !           380:                            BSIZE * NBUFS / 1024));
1.1       nbrk      381: }

CVSweb