Annotation of prex-old/usr/server/fs/vfs/vfs_bio.c, Revision 1.1.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