/*-
* Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
* Copyright 2015 Toomas Soome <tsoome@me.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
__FBSDID("$FreeBSD$");
/*
* Simple hashed block cache
*/
#include <stand.h>
#include <string.h>
#include <strings.h>
#include "bootstrap.h"
/* #define BCACHE_DEBUG */
#ifdef BCACHE_DEBUG
#else
#endif
struct bcachectl
{
int bc_count;
};
/*
* bcache per device node. cache is allocated on device first open and freed
* on last close, to save memory. The issue there is the size; biosdisk
* supports up to 31 (0x1f) devices. Classic setup would use single disk
* to boot from, but this has changed with zfs.
*/
struct bcache {
};
/* statistics */
/*
* Initialise the cache for (nblks) of (bsize).
*/
void
{
/* set up control data */
}
/*
* add number of devices to bcache. we have to divide cache space
* between the devices, so bcache_add_dev() can be used to set up the
* number. The issue is, we need to get the number before actual allocations.
* bcache_add_dev() is supposed to be called from device init() call, so the
* assumption is, devsw dv_init is called for plain devices first, and
* for zfs, last.
*/
void
{
bcache_numdev += devices;
}
void *
bcache_allocate(void)
{
u_int i;
if (disks == 0)
return (bc);
}
/*
* the bcache block count must be power of 2 for hash function
*/
i++;
/* dont error out yet. fall back to 32 blocks and try again */
}
return(NULL);
}
/* Flush the cache */
for (i = 0; i < bc->bcache_nblks; i++) {
}
bcache_units++;
return (bc);
}
void
{
return;
bcache_units--;
}
/*
* Handle a write request; write directly to the disk, and populate the
* cache with the new values.
*/
static int
{
/* Invalidate the blocks being written */
for (i = 0; i < nblk; i++) {
}
/* Write the blocks */
}
/*
* 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
{
int result;
return (-1);
}
*rsize = 0;
nblk++;
result = 0;
complete = 1;
/* Satisfy any cache hits up front, break on first miss */
for (i = 0; i < nblk; i++) {
bcache_misses += (nblk - i);
complete = 0;
break;
} else {
bcache_hits++;
}
}
if (complete) { /* whole set was in cache, return it */
goto done;
}
/*
* 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.
*/
}
/* invalidate bcache */
for (i = 0; i < p_size; i++) {
}
r_size = 0;
/*
* 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.
*/
r_size /= bcache_blksize;
for (i = 0; i < r_size; i++)
/* update ra statistics */
if (r_size != 0) {
else
bcache_rablks += ra;
}
/* check how much data can we copy */
for (i = 0; i < nblk; i++) {
break;
}
if (size > i * bcache_blksize)
size = i * bcache_blksize;
if (size != 0) {
result = 0;
}
done:
return(result);
}
/*
* Requests larger than 1/2 cache size will be bypassed and go
* directly to the disk. XXX tune this.
*/
int
{
bcache_ops++;
/* bypass large requests, or when the cache is inactive */
rsize));
}
/* normalize offset */
while (offset >= bcache_blksize) {
blk++;
offset -= bcache_blksize;
}
switch (rw) {
case F_READ:
nblk++; /* read at least one block */
ret = 0;
total = 0;
while(size) {
if (size <= bcache_blksize)
else {
if (offset)
}
/*
* we may have error from read ahead, if we have read some data
* return partial read.
*/
if (total != 0)
ret = 0;
break;
}
offset = 0;
}
if (rsize)
return (ret);
case F_WRITE:
}
return -1;
}
/*
* Free allocated bcache instance
*/
static void
{
if (bc->bcache_ctl)
if (bc->bcache_data)
}
}
/*
* Insert a block into the cache.
*/
static void
{
}
/*
* Invalidate a block from the cache.
*/
static void
{
u_int i;
}
}
#ifndef BOOT2
static int
{
if (argc != 1) {
command_errmsg = "wrong number of arguments";
return(CMD_ERROR);
}
return(CMD_OK);
}
#endif