|
|||
Prex Home / Browse Source - Prex Version: 0.9.0 |
|||
root/usr/server/fs/vfs/vfs_bio.c/* [<][>][^][v][top][bottom][index][help] */DEFINITIONSThis source file includes following definitions.
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 * vfs_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 <sys/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 */ 52 #define NBUFS CONFIG_BUF_CACHE 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 */ 73 static char buffers[NBUFS][BSIZE]; 74 75 static struct buf buf_table[NBUFS]; 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 85 bio_insert_head(struct buf *bp) 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 96 bio_insert_tail(struct buf *bp) 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 107 bio_remove(struct buf *bp) 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 * 119 bio_remove_head(void) 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 139 for (i = 0; i < NBUFS; i++) { 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 * 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. 155 */ 156 struct buf * 157 getblk(dev_t dev, int blkno) 158 { 159 struct buf *bp; 160 161 DPRINTF(VFSDB_BIO, ("getblk: dev=%x blkno=%d\n", dev, blkno)); 162 start: 163 BIO_LOCK(); 164 bp = incore(dev, blkno); 165 if (bp != NULL) { 166 /* Block found in cache. */ 167 if (ISSET(bp->b_flags, B_BUSY)) { 168 /* 169 * Wait buffer ready. 170 */ 171 BIO_UNLOCK(); 172 mutex_lock(&bp->b_lock); 173 mutex_unlock(&bp->b_lock); 174 /* Scan again if it's busy */ 175 goto start; 176 } 177 bio_remove(bp); 178 SET(bp->b_flags, B_BUSY); 179 } else { 180 bp = bio_remove_head(); 181 if (ISSET(bp->b_flags, B_DELWRI)) { 182 BIO_UNLOCK(); 183 bwrite(bp); 184 goto start; 185 } 186 bp->b_flags = B_BUSY; 187 bp->b_dev = dev; 188 bp->b_blkno = blkno; 189 } 190 mutex_lock(&bp->b_lock); 191 BIO_UNLOCK(); 192 DPRINTF(VFSDB_BIO, ("getblk: done bp=%x\n", bp)); 193 return bp; 194 } 195 196 /* 197 * Release a buffer, with no I/O implied. 198 */ 199 void 200 brelse(struct buf *bp) 201 { 202 ASSERT(ISSET(bp->b_flags, B_BUSY)); 203 DPRINTF(VFSDB_BIO, ("brelse: bp=%x dev=%x blkno=%d\n", 204 bp, bp->b_dev, bp->b_blkno)); 205 206 BIO_LOCK(); 207 CLR(bp->b_flags, B_BUSY); 208 mutex_unlock(&bp->b_lock); 209 if (ISSET(bp->b_flags, B_INVAL)) 210 bio_insert_head(bp); 211 else 212 bio_insert_tail(bp); 213 BIO_UNLOCK(); 214 } 215 216 /* 217 * Block read with cache. 218 * @dev: device id to read from. 219 * @blkno: block number. 220 * @buf: buffer pointer to be returned. 221 * 222 * An actual read operation is done only when the cached 223 * buffer is dirty. 224 */ 225 int 226 bread(dev_t dev, int blkno, struct buf **bpp) 227 { 228 struct buf *bp; 229 size_t size; 230 int error; 231 232 DPRINTF(VFSDB_BIO, ("bread: dev=%x blkno=%d\n", dev, blkno)); 233 bp = getblk(dev, blkno); 234 235 if (!ISSET(bp->b_flags, (B_DONE | B_DELWRI))) { 236 size = BSIZE; 237 error = device_read((device_t)dev, bp->b_data, &size, blkno); 238 if (error) { 239 DPRINTF(VFSDB_BIO, ("bread: i/o error\n")); 240 brelse(bp); 241 return error; 242 } 243 } 244 CLR(bp->b_flags, B_INVAL); 245 SET(bp->b_flags, (B_READ | B_DONE)); 246 DPRINTF(VFSDB_BIO, ("bread: done bp=%x\n\n", bp)); 247 *bpp = bp; 248 return 0; 249 } 250 251 /* 252 * Block write with cache. 253 * @buf: buffer to write. 254 * 255 * The data is copied to the buffer. 256 * Then release the buffer. 257 */ 258 int 259 bwrite(struct buf *bp) 260 { 261 size_t size; 262 int error; 263 264 ASSERT(ISSET(bp->b_flags, B_BUSY)); 265 DPRINTF(VFSDB_BIO, ("bwrite: dev=%x blkno=%d\n", bp->b_dev, 266 bp->b_blkno)); 267 268 BIO_LOCK(); 269 CLR(bp->b_flags, (B_READ | B_DONE | B_DELWRI)); 270 BIO_UNLOCK(); 271 272 size = BSIZE; 273 error = device_write((device_t)bp->b_dev, bp->b_data, &size, 274 bp->b_blkno); 275 if (error) 276 return error; 277 BIO_LOCK(); 278 SET(bp->b_flags, B_DONE); 279 BIO_UNLOCK(); 280 brelse(bp); 281 return 0; 282 } 283 284 /* 285 * Delayed write. 286 * 287 * The buffer is marked dirty, but an actual I/O is not 288 * performed. This routine should be used when the buffer 289 * is expected to be modified again soon. 290 */ 291 void 292 bdwrite(struct buf *bp) 293 { 294 295 BIO_LOCK(); 296 SET(bp->b_flags, B_DELWRI); 297 CLR(bp->b_flags, B_DONE); 298 BIO_UNLOCK(); 299 brelse(bp); 300 } 301 302 /* 303 * Flush write-behind block 304 */ 305 void 306 bflush(struct buf *bp) 307 { 308 309 BIO_LOCK(); 310 if (ISSET(bp->b_flags, B_DELWRI)) 311 bwrite(bp); 312 BIO_UNLOCK(); 313 } 314 315 /* 316 * Invalidate buffer for specified device. 317 * This is called when unmount. 318 */ 319 void 320 binval(dev_t dev) 321 { 322 struct buf *bp; 323 int i; 324 325 BIO_LOCK(); 326 for (i = 0; i < NBUFS; i++) { 327 bp = &buf_table[i]; 328 if (bp->b_dev == dev) { 329 if (ISSET(bp->b_flags, B_DELWRI)) 330 bwrite(bp); 331 else if (ISSET(bp->b_flags, B_BUSY)) 332 brelse(bp); 333 bp->b_flags = B_INVAL; 334 } 335 } 336 BIO_UNLOCK(); 337 } 338 339 /* 340 * Invalidate all buffers. 341 * This is called when unmount. 342 */ 343 void 344 bio_sync(void) 345 { 346 struct buf *bp; 347 int i; 348 349 start: 350 BIO_LOCK(); 351 for (i = 0; i < NBUFS; i++) { 352 bp = &buf_table[i]; 353 if (ISSET(bp->b_flags, B_BUSY)) { 354 BIO_UNLOCK(); 355 mutex_lock(&bp->b_lock); 356 mutex_unlock(&bp->b_lock); 357 goto start; 358 } 359 if (ISSET(bp->b_flags, B_DELWRI)) 360 bwrite(bp); 361 } 362 BIO_UNLOCK(); 363 } 364 365 /* 366 * Initialize the buffer I/O system. 367 */ 368 void 369 bio_init(void) 370 { 371 struct buf *bp; 372 int i; 373 374 for (i = 0; i < NBUFS; i++) { 375 bp = &buf_table[i]; 376 bp->b_flags = B_INVAL; 377 bp->b_data = buffers[i]; 378 mutex_init(&bp->b_lock); 379 list_insert(&free_list, &bp->b_link); 380 } 381 sem_init(&free_sem, NBUFS); 382 383 DPRINTF(VFSDB_BIO, ("bio: Buffer cache size %dK bytes\n", 384 BSIZE * NBUFS / 1024)); 385 } /* [<][>][^][v][top][bottom][index][help] */ | |||
Copyright© 2005-2009 Kohsuke Ohtani |