Example #1
0
/*
 * 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);
}
Example #2
0
/* 
 * 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);
}