Annotation of prex-old/usr/server/fs/vfs/vfs_bio.c, Revision 1.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/syslog.h>
! 42: #include <sys/param.h>
! 43: #include <sys/buf.h>
! 44:
! 45: #include <limits.h>
! 46: #include <unistd.h>
! 47: #include <stdlib.h>
! 48: #include <string.h>
! 49:
! 50: #include "vfs.h"
! 51:
! 52: /* number of buffer cache */
! 53: #define NR_BUFS CONFIG_BUF_CACHE
! 54:
! 55: /* macros to clear/set/test flags. */
! 56: #define SET(t, f) (t) |= (f)
! 57: #define CLR(t, f) (t) &= ~(f)
! 58: #define ISSET(t, f) ((t) & (f))
! 59:
! 60: /*
! 61: * Global lock to access all buffer headers and lists.
! 62: */
! 63: #if CONFIG_FS_THREADS > 1
! 64: static mutex_t bio_lock = MUTEX_INITIALIZER;
! 65: #define BIO_LOCK() mutex_lock(&bio_lock)
! 66: #define BIO_UNLOCK() mutex_unlock(&bio_lock)
! 67: #else
! 68: #define BIO_LOCK()
! 69: #define BIO_UNLOCK()
! 70: #endif
! 71:
! 72:
! 73: /* set of buffers */
! 74: static char buf_base[NR_BUFS][BSIZE];
! 75:
! 76: static struct buf buf_table[NR_BUFS];
! 77: static struct list free_list = LIST_INIT(free_list);
! 78:
! 79: static int nr_free;
! 80: static sem_t free_sem;
! 81:
! 82:
! 83: /*
! 84: * Insert buffer to the head of free list
! 85: */
! 86: static void
! 87: binsfree_head(struct buf *bp)
! 88: {
! 89:
! 90: list_insert(&free_list, &bp->b_link);
! 91: nr_free++;
! 92: sem_post(&free_sem);
! 93:
! 94: bio_printf("binsfree_head: free=%d\n", nr_free);
! 95: }
! 96:
! 97: /*
! 98: * Insert buffer to the tail of free list
! 99: */
! 100: static void
! 101: binsfree_tail(struct buf *bp)
! 102: {
! 103:
! 104: list_insert(list_prev(&free_list), &bp->b_link);
! 105: nr_free++;
! 106: sem_post(&free_sem);
! 107:
! 108: bio_printf("binsfree_tail: free=%d\n", nr_free);
! 109: }
! 110:
! 111: /*
! 112: * Remove buffer from free list
! 113: */
! 114: static void
! 115: bremfree(struct buf *bp)
! 116: {
! 117: bio_printf("bremfree: free=%d\n", nr_free);
! 118:
! 119: sem_wait(&free_sem, 0);
! 120: ASSERT(!list_empty(&free_list));
! 121: list_remove(&bp->b_link);
! 122: nr_free--;
! 123: }
! 124:
! 125: /*
! 126: * Remove buffer from the head of free list
! 127: */
! 128: static struct buf *
! 129: bremfree_head(void)
! 130: {
! 131: struct buf *bp;
! 132:
! 133: bio_printf("bremfree_head: free=%d\n", nr_free);
! 134: sem_wait(&free_sem, 0);
! 135: ASSERT(!list_empty(&free_list));
! 136:
! 137: bp = list_entry(list_first(&free_list), struct buf, b_link);
! 138: list_remove(&bp->b_link);
! 139: nr_free--;
! 140: return bp;
! 141: }
! 142:
! 143: /*
! 144: * Determine if a block is in the cache.
! 145: */
! 146: static struct buf *
! 147: incore(dev_t dev, int blkno)
! 148: {
! 149: struct buf *bp;
! 150: int i;
! 151:
! 152: for (i = 0; i < NR_BUFS; i++) {
! 153: bp = &buf_table[i];
! 154: if (bp->b_blkno == blkno && bp->b_dev == dev &&
! 155: !ISSET(bp->b_flags, B_INVAL))
! 156: return bp;
! 157: }
! 158: return NULL;
! 159: }
! 160:
! 161: /*
! 162: * Assign a buffer for the given block.
! 163: *
! 164: * The block is selected from the buffer list with LRU algorithm.
! 165: * If the appropriate block already exists in the block list, return it.
! 166: * Otherwise, the least recently used block is used.
! 167: */
! 168: struct buf *
! 169: getblk(dev_t dev, int blkno)
! 170: {
! 171: struct buf *bp;
! 172:
! 173: bio_printf("getblk: dev=%x blkno=%d\n", dev, blkno);
! 174: start:
! 175: BIO_LOCK();
! 176: bp = incore(dev, blkno);
! 177: if (bp != NULL) {
! 178: bio_printf("getblk: found in cache! bp=%x\n", bp);
! 179:
! 180: /* Block exists in cache */
! 181: if (ISSET(bp->b_flags, B_BUSY)) {
! 182: bio_printf("getblk: but busy...\n");
! 183: BIO_UNLOCK();
! 184: mutex_lock(&bp->b_lock);
! 185: mutex_unlock(&bp->b_lock);
! 186: bio_printf("getblk: scan again...\n");
! 187: goto start;
! 188: }
! 189: bremfree(bp);
! 190: SET(bp->b_flags, B_BUSY);
! 191: } else {
! 192: bio_printf("getblk: find new buf\n");
! 193:
! 194: bp = bremfree_head();
! 195: if (ISSET(bp->b_flags, B_DELWRI)) {
! 196: BIO_UNLOCK();
! 197: bwrite(bp);
! 198: goto start;
! 199: }
! 200: bp->b_flags = B_BUSY;
! 201: bp->b_dev = dev;
! 202: bp->b_blkno = blkno;
! 203: }
! 204: mutex_lock(&bp->b_lock);
! 205: BIO_UNLOCK();
! 206: bio_printf("getblk: done bp=%x\n", bp);
! 207: return bp;
! 208: }
! 209:
! 210: /*
! 211: * Release a buffer, with no I/O implied.
! 212: */
! 213: void
! 214: brelse(struct buf *bp)
! 215: {
! 216: ASSERT(ISSET(bp->b_flags, B_BUSY));
! 217: bio_printf("brelse: bp=%x dev=%x blkno=%d\n",
! 218: bp, bp->b_dev, bp->b_blkno);
! 219:
! 220: BIO_LOCK();
! 221: CLR(bp->b_flags, B_BUSY);
! 222: mutex_unlock(&bp->b_lock);
! 223: if (ISSET(bp->b_flags, B_INVAL))
! 224: binsfree_head(bp);
! 225: else
! 226: binsfree_tail(bp);
! 227: BIO_UNLOCK();
! 228: }
! 229:
! 230: /*
! 231: * Block read with cache.
! 232: * @dev: device id to read from.
! 233: * @blkno: block number.
! 234: * @buf: buffer pointer to be returned.
! 235: *
! 236: * An actual read operation is done only when the cached buffer
! 237: * is dirty.
! 238: */
! 239: int
! 240: bread(dev_t dev, int blkno, struct buf **bpp)
! 241: {
! 242: struct buf *bp;
! 243: size_t size;
! 244: int err;
! 245:
! 246: bio_printf("bread: dev=%x blkno=%d\n", dev, blkno);
! 247: bp = getblk(dev, blkno);
! 248:
! 249: if (!ISSET(bp->b_flags, (B_DONE | B_DELWRI))) {
! 250: bio_printf("bread: i/o read\n");
! 251: size = BSIZE;
! 252: err = device_read((device_t)dev, bp->b_data, &size, blkno);
! 253: if (err) {
! 254: bio_printf("bread: i/o error\n");
! 255: brelse(bp);
! 256: return err;
! 257: }
! 258: }
! 259: CLR(bp->b_flags, B_INVAL);
! 260: SET(bp->b_flags, (B_READ | B_DONE));
! 261: bio_printf("bread: done bp=%x\n\n", bp);
! 262: *bpp = bp;
! 263: return 0;
! 264: }
! 265:
! 266: /*
! 267: * Block write with cache.
! 268: * @buf: buffer to write.
! 269: *
! 270: * The data is copied to cache block.
! 271: */
! 272: int
! 273: bwrite(struct buf *bp)
! 274: {
! 275: size_t size;
! 276: int err;
! 277:
! 278: ASSERT(ISSET(bp->b_flags, B_BUSY));
! 279: bio_printf("bwrite: dev=%x blkno=%d\n", bp->b_dev, bp->b_blkno);
! 280:
! 281: BIO_LOCK();
! 282: CLR(bp->b_flags, (B_READ | B_DONE | B_DELWRI));
! 283: BIO_UNLOCK();
! 284:
! 285: size = BSIZE;
! 286: err = device_write((device_t)bp->b_dev, bp->b_data, &size,
! 287: bp->b_blkno);
! 288: if (err)
! 289: return err;
! 290: BIO_LOCK();
! 291: SET(bp->b_flags, B_DONE);
! 292: BIO_UNLOCK();
! 293: brelse(bp);
! 294: return 0;
! 295: }
! 296:
! 297: /*
! 298: * Delayed write.
! 299: *
! 300: * The buffer is marked dirty, but an actial I/O is not performed.
! 301: * This routine should be used when the buffer is expected to be
! 302: * modified again soon.
! 303: */
! 304: void
! 305: bdwrite(struct buf *bp)
! 306: {
! 307:
! 308: BIO_LOCK();
! 309: SET(bp->b_flags, B_DELWRI);
! 310: CLR(bp->b_flags, B_DONE);
! 311: BIO_UNLOCK();
! 312: brelse(bp);
! 313: }
! 314:
! 315: /*
! 316: * Flush write-behind block
! 317: */
! 318: void
! 319: bflush(struct buf *bp)
! 320: {
! 321:
! 322: BIO_LOCK();
! 323: if (ISSET(bp->b_flags, B_DELWRI))
! 324: bwrite(bp);
! 325: BIO_UNLOCK();
! 326: }
! 327:
! 328: /*
! 329: * Invalidate buffer for specified device.
! 330: * This is called when unmount.
! 331: */
! 332: void
! 333: binval(dev_t dev)
! 334: {
! 335: struct buf *bp;
! 336: int i;
! 337:
! 338: BIO_LOCK();
! 339: for (i = 0; i < NR_BUFS; i++) {
! 340: bp = &buf_table[i];
! 341: if (bp->b_dev == dev) {
! 342: if (ISSET(bp->b_flags, B_DELWRI))
! 343: bwrite(bp);
! 344: else if (ISSET(bp->b_flags, B_BUSY))
! 345: brelse(bp);
! 346: bp->b_flags = B_INVAL;
! 347: }
! 348: }
! 349: BIO_UNLOCK();
! 350: }
! 351:
! 352: /*
! 353: * Invalidate buffer for specified device.
! 354: * This is called when unmount.
! 355: */
! 356: void
! 357: bio_sync(void)
! 358: {
! 359: struct buf *bp;
! 360: int i;
! 361:
! 362: start:
! 363: BIO_LOCK();
! 364: for (i = 0; i < NR_BUFS; i++) {
! 365: bp = &buf_table[i];
! 366: if (ISSET(bp->b_flags, B_BUSY)) {
! 367: BIO_UNLOCK();
! 368: mutex_lock(&bp->b_lock);
! 369: mutex_unlock(&bp->b_lock);
! 370: goto start;
! 371: }
! 372: if (ISSET(bp->b_flags, B_DELWRI))
! 373: bwrite(bp);
! 374: }
! 375: BIO_UNLOCK();
! 376: }
! 377:
! 378: /*
! 379: * Initialize
! 380: */
! 381: void
! 382: bio_init(void)
! 383: {
! 384: struct buf *bp;
! 385: int i;
! 386:
! 387: for (i = 0; i < NR_BUFS; i++) {
! 388: bp = &buf_table[i];
! 389: bp->b_flags = B_INVAL;
! 390: bp->b_data = buf_base[i];
! 391: mutex_init(&bp->b_lock);
! 392: list_insert(&free_list, &bp->b_link);
! 393: }
! 394: sem_init(&free_sem, NR_BUFS);
! 395: nr_free = NR_BUFS;
! 396: bio_printf("bio: Buffer cache size %dK bytes\n",
! 397: BSIZE * NR_BUFS / 1024);
! 398: }
CVSweb