[9] | 1 | /* Second level block cache to supplement the file system cache. The block
|
---|
| 2 | * cache of a 16-bit Minix system is very small, too small to prevent trashing.
|
---|
| 3 | * A generic 32-bit system also doesn't have a very large cache to allow it
|
---|
| 4 | * to run on systems with little memory. On a system with lots of memory one
|
---|
| 5 | * can use the RAM disk as a read-only second level cache. Any blocks pushed
|
---|
| 6 | * out of the primary cache are cached on the RAM disk. This code manages the
|
---|
| 7 | * second level cache. The cache is a simple FIFO where old blocks are put
|
---|
| 8 | * into and drop out at the other end. Must be searched backwards.
|
---|
| 9 | *
|
---|
| 10 | * The entry points into this file are:
|
---|
| 11 | * init_cache2: initialize the second level cache
|
---|
| 12 | * get_block2: get a block from the 2nd level cache
|
---|
| 13 | * put_block2: store a block in the 2nd level cache
|
---|
| 14 | * invalidate2: remove all the cache blocks on some device
|
---|
| 15 | */
|
---|
| 16 |
|
---|
| 17 | #include "fs.h"
|
---|
| 18 | #include <minix/com.h>
|
---|
| 19 | #include "buf.h"
|
---|
| 20 |
|
---|
| 21 | #if ENABLE_CACHE2
|
---|
| 22 |
|
---|
| 23 | #define MAX_BUF2 (256 * sizeof(char *))
|
---|
| 24 |
|
---|
| 25 | PRIVATE struct buf2 { /* 2nd level cache per block administration */
|
---|
| 26 | block_t b2_blocknr; /* block number */
|
---|
| 27 | dev_t b2_dev; /* device number */
|
---|
| 28 | u16_t b2_count; /* count of in-cache block groups */
|
---|
| 29 | } buf2[MAX_BUF2];
|
---|
| 30 |
|
---|
| 31 | PRIVATE unsigned nr_buf2; /* actual cache size */
|
---|
| 32 | PRIVATE unsigned buf2_idx; /* round-robin reuse index */
|
---|
| 33 |
|
---|
| 34 | #define hash2(block) ((unsigned) ((block) & (MAX_BUF2 - 1)))
|
---|
| 35 |
|
---|
| 36 | /*===========================================================================*
|
---|
| 37 | * init_cache2 *
|
---|
| 38 | *===========================================================================*/
|
---|
| 39 | PUBLIC void init_cache2(size)
|
---|
| 40 | unsigned long size;
|
---|
| 41 | {
|
---|
| 42 | /* Initialize the second level disk buffer cache of 'size' blocks. */
|
---|
| 43 |
|
---|
| 44 | nr_buf2 = size > MAX_BUF2 ? MAX_BUF2 : (unsigned) size;
|
---|
| 45 | }
|
---|
| 46 |
|
---|
| 47 | /*===========================================================================*
|
---|
| 48 | * get_block2 *
|
---|
| 49 | *===========================================================================*/
|
---|
| 50 | PUBLIC int get_block2(bp, only_search)
|
---|
| 51 | struct buf *bp; /* buffer to get from the 2nd level cache */
|
---|
| 52 | int only_search; /* if NO_READ, do nothing, else act normal */
|
---|
| 53 | {
|
---|
| 54 | /* Fill a buffer from the 2nd level cache. Return true iff block acquired. */
|
---|
| 55 | unsigned b;
|
---|
| 56 | struct buf2 *bp2;
|
---|
| 57 |
|
---|
| 58 | /* If the block wanted is in the RAM disk then our game is over. */
|
---|
| 59 | if (bp->b_dev == DEV_RAM) nr_buf2 = 0;
|
---|
| 60 |
|
---|
| 61 | /* Cache enabled? NO_READ? Any blocks with the same hash key? */
|
---|
| 62 | if (nr_buf2 == 0 || only_search == NO_READ
|
---|
| 63 | || buf2[hash2(bp->b_blocknr)].b2_count == 0) return(0);
|
---|
| 64 |
|
---|
| 65 | /* Search backwards (there may be older versions). */
|
---|
| 66 | b = buf2_idx;
|
---|
| 67 | for (;;) {
|
---|
| 68 | if (b == 0) b = nr_buf2;
|
---|
| 69 | bp2 = &buf2[--b];
|
---|
| 70 | if (bp2->b2_blocknr == bp->b_blocknr && bp2->b2_dev == bp->b_dev) break;
|
---|
| 71 | if (b == buf2_idx) return(0);
|
---|
| 72 | }
|
---|
| 73 |
|
---|
| 74 | /* Block is in the cache, get it. */
|
---|
| 75 | if (dev_io(DEV_READ, DEV_RAM, FS_PROC_NR, bp->b_data,
|
---|
| 76 | (off_t) b * BLOCK_SIZE, BLOCK_SIZE, 0) == BLOCK_SIZE) {
|
---|
| 77 | return(1);
|
---|
| 78 | }
|
---|
| 79 | return(0);
|
---|
| 80 | }
|
---|
| 81 |
|
---|
| 82 | /*===========================================================================*
|
---|
| 83 | * put_block2 *
|
---|
| 84 | *===========================================================================*/
|
---|
| 85 | PUBLIC void put_block2(bp)
|
---|
| 86 | struct buf *bp; /* buffer to store in the 2nd level cache */
|
---|
| 87 | {
|
---|
| 88 | /* Store a buffer into the 2nd level cache. */
|
---|
| 89 | unsigned b;
|
---|
| 90 | struct buf2 *bp2;
|
---|
| 91 |
|
---|
| 92 | if (nr_buf2 == 0) return; /* no 2nd level cache */
|
---|
| 93 |
|
---|
| 94 | b = buf2_idx++;
|
---|
| 95 | if (buf2_idx == nr_buf2) buf2_idx = 0;
|
---|
| 96 |
|
---|
| 97 | bp2 = &buf2[b];
|
---|
| 98 |
|
---|
| 99 | if (dev_io(DEV_WRITE, DEV_RAM, FS_PROC_NR, bp->b_data,
|
---|
| 100 | (off_t) b * BLOCK_SIZE, BLOCK_SIZE, 0) == BLOCK_SIZE) {
|
---|
| 101 | if (bp2->b2_dev != NO_DEV) buf2[hash2(bp2->b2_blocknr)].b2_count--;
|
---|
| 102 | bp2->b2_dev = bp->b_dev;
|
---|
| 103 | bp2->b2_blocknr = bp->b_blocknr;
|
---|
| 104 | buf2[hash2(bp2->b2_blocknr)].b2_count++;
|
---|
| 105 | }
|
---|
| 106 | }
|
---|
| 107 |
|
---|
| 108 | /*===========================================================================*
|
---|
| 109 | * invalidate2 *
|
---|
| 110 | *===========================================================================*/
|
---|
| 111 | PUBLIC void invalidate2(device)
|
---|
| 112 | dev_t device;
|
---|
| 113 | {
|
---|
| 114 | /* Invalidate all blocks from a given device in the 2nd level cache. */
|
---|
| 115 | unsigned b;
|
---|
| 116 | struct buf2 *bp2;
|
---|
| 117 |
|
---|
| 118 | for (b = 0; b < nr_buf2; b++) {
|
---|
| 119 | bp2 = &buf2[b];
|
---|
| 120 | if (bp2->b2_dev == device) {
|
---|
| 121 | bp2->b2_dev = NO_DEV;
|
---|
| 122 | buf2[hash2(bp2->b2_blocknr)].b2_count--;
|
---|
| 123 | }
|
---|
| 124 | }
|
---|
| 125 | }
|
---|
| 126 | #endif /* ENABLE_CACHE2 */
|
---|