summaryrefslogtreecommitdiffstats
path: root/sys/boot/common
diff options
context:
space:
mode:
authorjhb <jhb@FreeBSD.org>2001-12-11 00:10:00 +0000
committerjhb <jhb@FreeBSD.org>2001-12-11 00:10:00 +0000
commit356efe3c0b9c059153349979d7c80cd8b40c104c (patch)
tree82a0edc8e2cce97ce6e805e175ebe5ed7fb3fde3 /sys/boot/common
parentf4789ce28d2c2ddb2fcbfb10fb870c98d18cc6d7 (diff)
downloadFreeBSD-src-356efe3c0b9c059153349979d7c80cd8b40c104c.zip
FreeBSD-src-356efe3c0b9c059153349979d7c80cd8b40c104c.tar.gz
Add support for writing blocks to the loader's disk cache.
PR: kern/32389 Submitted by: Jonathan Mini <mini@haikugeek.com> Sponsored by: ClickArray, Inc.
Diffstat (limited to 'sys/boot/common')
-rw-r--r--sys/boot/common/bcache.c113
1 files changed, 92 insertions, 21 deletions
diff --git a/sys/boot/common/bcache.c b/sys/boot/common/bcache.c
index d4f4d7a..bc577f5 100644
--- a/sys/boot/common/bcache.c
+++ b/sys/boot/common/bcache.c
@@ -63,6 +63,7 @@ static u_int bcache_hits, bcache_misses, bcache_ops, bcache_bypasses;
static u_int bcache_flushes;
static u_int bcache_bcount;
+static void bcache_invalidate(daddr_t blkno);
static void bcache_insert(caddr_t buf, daddr_t blkno);
static int bcache_lookup(caddr_t buf, daddr_t blkno);
@@ -116,16 +117,45 @@ bcache_flush(void)
}
}
-/*
- * Handle a transfer request; fill in parts of the request that can
+/*
+ * Handle a write request; write directly to the disk, and populate the
+ * cache with the new values.
+ */
+static int
+write_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;
+ daddr_t i, nblk;
+ int err;
+
+ nblk = size / bcache_blksize;
+
+ /* Invalidate the blocks being written */
+ for (i = 0; i < nblk; i++) {
+ bcache_invalidate(blk + i);
+ }
+
+ /* Write the blocks */
+ err = dd->dv_strategy(dd->dv_devdata, rw, blk, size, buf, rsize);
+
+ /* Populate the block cache with the new data */
+ if (err == 0) {
+ for (i = 0; i < nblk; i++) {
+ bcache_insert(buf + (i * bcache_blksize),blk + i);
+ }
+ }
+
+ return err;
+}
+
+/*
+ * 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.
- *
- * 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 unit, int rw, daddr_t blk, size_t size,
+static int
+read_strategy(void *devdata, int unit, int rw, daddr_t blk, size_t size,
char *buf, size_t *rsize)
{
static int bcache_unit = -1;
@@ -134,20 +164,6 @@ bcache_strategy(void *devdata, int unit, int rw, daddr_t blk, size_t size,
daddr_t p_blk, i, j, nblk;
caddr_t p_buf;
- bcache_ops++;
-
- if(bcache_unit != unit) {
- bcache_flush();
- bcache_unit = unit;
- }
-
- /* 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;
@@ -201,6 +217,43 @@ bcache_strategy(void *devdata, int unit, int rw, daddr_t blk, size_t size,
return(result);
}
+/*
+ * 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 unit, int rw, daddr_t blk, size_t size,
+ char *buf, size_t *rsize)
+{
+ static int bcache_unit = -1;
+ struct bcache_devdata *dd = (struct bcache_devdata *)devdata;
+ int p_size, result;
+ daddr_t p_blk, i, j, nblk;
+ caddr_t p_buf;
+
+ bcache_ops++;
+
+ if(bcache_unit != unit) {
+ bcache_flush();
+ bcache_unit = unit;
+ }
+
+ /* 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));
+ }
+
+ switch (rw) {
+ case F_READ:
+ return read_strategy(devdata, unit, rw, blk, size, buf, rsize);
+ case F_WRITE:
+ return write_strategy(devdata, unit, rw, blk, size, buf, rsize);
+ }
+ return -1;
+}
+
/*
* Insert a block into the cache. Retire the oldest block to do so, if required.
@@ -261,6 +314,24 @@ bcache_lookup(caddr_t buf, daddr_t blkno)
return(ENOENT);
}
+/*
+ * Invalidate a block from the cache.
+ */
+static void
+bcache_invalidate(daddr_t blkno)
+{
+ u_int i;
+
+ for (i = 0; i < bcache_nblks; i++) {
+ if (bcache_ctl[i].bc_blkno == blkno) {
+ bcache_ctl[i].bc_count = -1;
+ bcache_ctl[i].bc_blkno = -1;
+ DEBUG("invalidate blk %d", blkno);
+ break;
+ }
+ }
+}
+
COMMAND_SET(bcachestat, "bcachestat", "get disk block cache stats", command_bcache);
static int
OpenPOWER on IntegriCloud