FreeBSD/sys/boot/common/bcache.c
/*
 * 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. 
 */
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.
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 rw, daddr_t blk, size_t offset,
    size_t size, char *buf, size_t *rsize)
{
    struct bcache_devdata	*dd = (struct bcache_devdata *)devdata;
    struct bcache		*bc = dd->dv_cache;
    size_t			i, nblk, p_size, r_size, complete, ra;
    int				result;
    daddr_t			p_blk;
    caddr_t			p_buf;
    if (bc == NULL) {
	errno = ENODEV;
	return (-1);
    }
    if (rsize != NULL)
	*rsize = 0;
    nblk = size / bcache_blksize;
    if ((nblk == 0 && size != 0) || offset != 0)
	nblk++;
    result = 0;
    complete = 1;
    for (i = 0; i < nblk; i++) {
	if (BCACHE_LOOKUP(bc, (daddr_t)(blk + i))) {
	    bcache_misses += (nblk - i);
	    complete = 0;
	    if (nblk - i > BCACHE_MINREADAHEAD && bc->ra > BCACHE_MINREADAHEAD)
		bc->ra >>= 1;	
	    break;
	} else {
	    bcache_hits++;
	}
    }
   if (complete) {	
	if (bc->ra < BCACHE_READAHEAD)
		bc->ra <<= 1;	
	bcopy(bc->bcache_data + (bcache_blksize * BHASH(bc, blk)) + offset,
	    buf, size);
	goto done;
   }
    p_blk = blk + i;
    p_buf = bc->bcache_data + (bcache_blksize * BHASH(bc, p_blk));
    r_size = bc->bcache_nblks - BHASH(bc, p_blk); 
    p_size = MIN(r_size, nblk - i);	
    ra = bc->bcache_nblks - BHASH(bc, p_blk + p_size);
    if (ra != bc->bcache_nblks) { 
	ra = MIN(bc->ra, ra);
	p_size += ra;
    }
    for (i = 0; i < p_size; i++) {
	bcache_invalidate(bc, p_blk + i);
    }
    r_size = 0;
    result = dd->dv_strategy(dd->dv_devdata, rw, p_blk, 0,
	p_size * bcache_blksize, p_buf, &r_size);
    r_size /= bcache_blksize;
    for (i = 0; i < r_size; i++)
	bcache_insert(bc, p_blk + i);
    if (r_size != 0) {
	if (r_size < p_size)
	    bcache_rablks += (p_size - r_size);
	else
	    bcache_rablks += ra;
    }
    for (i = 0; i < nblk; i++) {
	if (BCACHE_LOOKUP(bc, (daddr_t)(blk + i)))
	    break;
    }
    size = i * bcache_blksize;
    if (size != 0) {
	bcopy(bc->bcache_data + (bcache_blksize * BHASH(bc, blk)) + offset,
	    buf, size);
	result = 0;
    }
 done:
    if ((result == 0) && (rsize != NULL))
	*rsize = size;
    return(result);
}
static int read_strategy ( void * devdata , int rw , daddr_t blk , size_t offset , size_t size , char * buf , size_t * rsize ) { struct bcache_devdata * dd = ( struct bcache_devdata * ) devdata ; struct bcache * bc = dd -> dv_cache ; size_t i , nblk , p_size , r_size , complete , ra ; int result ; daddr_t p_blk ; caddr_t p_buf ; if ( bc == NULL ) { errno = ENODEV ; return ( -1 ) ; } if ( rsize != NULL ) * rsize = 0 ; nblk = size / bcache_blksize ; if ( ( nblk == 0 && size != 0 ) || offset != 0 ) nblk ++ ; result = 0 ; complete = 1 ; for ( i = 0 ; i < nblk ; i ++ ) { if ( BCACHE_LOOKUP ( bc , ( daddr_t ) ( blk + i ) ) ) { bcache_misses += ( nblk - i ) ; complete = 0 ; if ( nblk - i > BCACHE_MINREADAHEAD && bc -> ra > BCACHE_MINREADAHEAD ) bc -> ra >>= 1 ; break ; } else { bcache_hits ++ ; } } if ( complete ) { if ( bc -> ra < BCACHE_READAHEAD ) bc -> ra <<= 1 ; bcopy ( bc -> bcache_data + ( bcache_blksize * BHASH ( bc , blk ) ) + offset , buf , size ) ; goto done ; } p_blk = blk + i ; p_buf = bc -> bcache_data + ( bcache_blksize * BHASH ( bc , p_blk ) ) ; r_size = bc -> bcache_nblks - BHASH ( bc , p_blk ) ; p_size = MIN ( r_size , nblk - i ) ; ra = bc -> bcache_nblks - BHASH ( bc , p_blk + p_size ) ; if ( ra != bc -> bcache_nblks ) { ra = MIN ( bc -> ra , ra ) ; p_size += ra ; } for ( i = 0 ; i < p_size ; i ++ ) { bcache_invalidate ( bc , p_blk + i ) ; } r_size = 0 ; result = dd -> dv_strategy ( dd -> dv_devdata , rw , p_blk , 0 , p_size * bcache_blksize , p_buf , & r_size ) ; r_size /= bcache_blksize ; for ( i = 0 ; i < r_size ; i ++ ) bcache_insert ( bc , p_blk + i ) ; if ( r_size != 0 ) { if ( r_size < p_size ) bcache_rablks += ( p_size - r_size ) ; else bcache_rablks += ra ; } for ( i = 0 ; i < nblk ; i ++ ) { if ( BCACHE_LOOKUP ( bc , ( daddr_t ) ( blk + i ) ) ) break ; } size = i * bcache_blksize ; if ( size != 0 ) { bcopy ( bc -> bcache_data + ( bcache_blksize * BHASH ( bc , blk ) ) + offset , buf , size ) ; result = 0 ; } done : if ( ( result == 0 ) && ( rsize != NULL ) ) * rsize = size ; return ( result ) ; }
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.
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 .
/* Satisfy any cache hits up front, break on first miss */ /* reduce read ahead */ /* whole set was in cache, return it */ /* increase read ahead */ /*
     * Fill in any misses. From check we have i pointing to first missing
     * block, read in all remaining blocks + readahead.
     * We have space at least for nblk - i before bcache wraps.
     */ /* remaining blocks */ /* read at least those blocks */ /* do we have RA space? */ /* invalidate bcache */ /*
     * with read-ahead, it may happen we are attempting to read past
     * disk end, as bcache has no information about disk size.
     * in such case we should get partial read if some blocks can be
     * read or error, if no blocks can be read.
     * in either case we should return the data in bcache and only
     * return error if there is no data.
     */ /* update ra statistics */ /* check how much data can we copy */