/* * Handle a read request; fill in parts of the request that can * be satisfied by the cache, use the supplied strategy routine to do * device I/O and then use the I/O results to populate the cache. */ static int read_strategy(void *devdata, int unit, int rw, daddr_t blk, size_t size, char *buf, size_t *rsize) { struct bcache_devdata *dd = (struct bcache_devdata *)devdata; int p_size, result; daddr_t p_blk, i, j, nblk; caddr_t p_buf; nblk = size / bcache_blksize; result = 0; /* Satisfy any cache hits up front */ for (i = 0; i < nblk; i++) { if (bcache_lookup(buf + (bcache_blksize * i), blk + i)) { bit_set(bcache_miss, i); /* cache miss */ bcache_misses++; } else { bit_clear(bcache_miss, i); /* cache hit */ bcache_hits++; } } /* Go back and fill in any misses XXX optimise */ p_blk = -1; p_buf = NULL; p_size = 0; for (i = 0; i < nblk; i++) { if (bit_test(bcache_miss, i)) { /* miss, add to pending transfer */ if (p_blk == -1) { p_blk = blk + i; p_buf = buf + (bcache_blksize * i); p_size = 1; } else { p_size++; } } else if (p_blk != -1) { /* hit, complete pending transfer */ result = dd->dv_strategy(dd->dv_devdata, rw, p_blk, p_size * bcache_blksize, p_buf, NULL); if (result != 0) goto done; for (j = 0; j < p_size; j++) bcache_insert(p_buf + (j * bcache_blksize), p_blk + j); p_blk = -1; } } if (p_blk != -1) { /* pending transfer left */ result = dd->dv_strategy(dd->dv_devdata, rw, p_blk, p_size * bcache_blksize, p_buf, NULL); if (result != 0) goto done; for (j = 0; j < p_size; j++) bcache_insert(p_buf + (j * bcache_blksize), p_blk + j); } done: if ((result == 0) && (rsize != NULL)) *rsize = size; return(result); }
/* * Handle a transfer request; fill in parts of the request that can * be satisfied by the cache, use the supplied strategy routine to do * device I/O and then use the I/O results to populate the cache. * * Requests larger than 1/2 the cache size will be bypassed and go * directly to the disk. XXX tune this. */ int bcache_strategy(void *devdata, int rw, daddr_t blk, size_t size, void *buf, size_t *rsize) { struct bcache_devdata *dd = (struct bcache_devdata *)devdata; int nblk, p_size; daddr_t p_blk; caddr_t p_buf; int i, j, result; bcache_ops++; /* bypass large requests, or when the cache is inactive */ if ((bcache_data == NULL) || ((size * 2 / bcache_blksize) > bcache_nblks)) { DEBUG("bypass %d from %d", size / bcache_blksize, blk); bcache_bypasses++; return(dd->dv_strategy(dd->dv_devdata, rw, blk, size, buf, rsize)); } nblk = size / bcache_blksize; result = 0; /* Satisfy any cache hits up front */ for (i = 0; i < nblk; i++) { if (bcache_lookup(buf + (bcache_blksize * i), blk + i)) { bit_set(bcache_miss, i); /* cache miss */ bcache_misses++; } else { bit_clear(bcache_miss, i); /* cache hit */ bcache_hits++; } } /* Go back and fill in any misses XXX optimise */ p_blk = -1; p_buf = NULL; p_size = 0; for (i = 0; i < nblk; i++) { if (bit_test(bcache_miss, i)) { /* miss, add to pending transfer */ if (p_blk == -1) { p_blk = blk + i; p_buf = buf + (bcache_blksize * i); p_size = 1; } else { p_size++; } } else if (p_blk != -1) { /* hit, complete pending transfer */ result = dd->dv_strategy(dd->dv_devdata, rw, p_blk, p_size * bcache_blksize, p_buf, NULL); if (result != 0) goto done; for (j = 0; j < p_size; j++) bcache_insert(p_buf + (j * bcache_blksize), p_blk + j); p_blk = -1; } } if (p_blk != -1) { /* pending transfer left */ result = dd->dv_strategy(dd->dv_devdata, rw, p_blk, p_size * bcache_blksize, p_buf, NULL); if (result != 0) goto done; for (j = 0; j < p_size; j++) bcache_insert(p_buf + (j * bcache_blksize), p_blk + j); } done: if ((result == 0) && (rsize != NULL)) *rsize = size; return(result); }