aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTheodore Ts'o <tytso@mit.edu>2002-11-09 14:56:17 -0500
committerTheodore Ts'o <tytso@mit.edu>2002-11-09 14:56:17 -0500
commit82c4660c756fba5eae289e6fbf03fab55393e3e2 (patch)
tree330b6a300a5ec4835947acafd378796e8e48b5a8
parent0c897a9012efb7d65244e25245c4b7318201d961 (diff)
downloade2fsprogs-82c4660c756fba5eae289e6fbf03fab55393e3e2.tar.gz
unix_io.c (find_cached_block, reuse_cache, unix_read_blk,
unix_write_blk): Optimize routines so that we don't end up searching the cache twice when a block isn't in the cache. If reads are larger than READ_DIRECT_SIZE, don't let them go through the cache.
-rw-r--r--lib/ext2fs/ChangeLog8
-rw-r--r--lib/ext2fs/unix_io.c83
2 files changed, 47 insertions, 44 deletions
diff --git a/lib/ext2fs/ChangeLog b/lib/ext2fs/ChangeLog
index 3e265c50..8ee700bd 100644
--- a/lib/ext2fs/ChangeLog
+++ b/lib/ext2fs/ChangeLog
@@ -1,4 +1,10 @@
-2002-11-09 <tytso@snap.thunk.org>
+2002-11-09 Theodore Ts'o <tytso@mit.edu>
+
+ * unix_io.c (find_cached_block, reuse_cache, unix_read_blk,
+ unix_write_blk): Optimize routines so that we don't end up
+ searching the cache twice when a block isn't in the
+ cache. If reads are larger than READ_DIRECT_SIZE, don't
+ let them go through the cache.
* unix_io.c (find_cached_block): Fixed bug which caused some clean
blocks to be erroneously marked as dirty, so they would
diff --git a/lib/ext2fs/unix_io.c b/lib/ext2fs/unix_io.c
index 1dcca4ad..a76f9d81 100644
--- a/lib/ext2fs/unix_io.c
+++ b/lib/ext2fs/unix_io.c
@@ -55,7 +55,8 @@ struct unix_cache {
};
#define CACHE_SIZE 8
-#define WRITE_VIA_CACHE_SIZE 4 /* Must be smaller than CACHE_SIZE */
+#define WRITE_DIRECT_SIZE 4 /* Must be smaller than CACHE_SIZE */
+#define READ_DIRECT_SIZE 4 /* Should be smaller than CACHE_SIZE */
struct unix_private_data {
int magic;
@@ -211,14 +212,14 @@ static void free_cache(io_channel channel,
}
/*
- * Try to find a block in the cache. If get_cache is non-zero, then
- * if the block isn't in the cache, evict the oldest block in the
- * cache and create a new cache entry for the requested block.
+ * Try to find a block in the cache. If the block is not found, and
+ * eldest is a non-zero pointer, then fill in eldest with the cache
+ * entry to that should be reused.
*/
static struct unix_cache *find_cached_block(io_channel channel,
struct unix_private_data *data,
unsigned long block,
- int get_cache)
+ struct unix_cache **eldest)
{
struct unix_cache *cache, *unused_cache, *oldest_cache;
int i;
@@ -226,7 +227,8 @@ static struct unix_cache *find_cached_block(io_channel channel,
unused_cache = oldest_cache = 0;
for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) {
if (!cache->in_use) {
- unused_cache = cache;
+ if (!unused_cache)
+ unused_cache = cache;
continue;
}
if (cache->block == block) {
@@ -237,25 +239,24 @@ static struct unix_cache *find_cached_block(io_channel channel,
(cache->access_time < oldest_cache->access_time))
oldest_cache = cache;
}
- if (!get_cache)
- return 0;
-
- /*
- * Try to allocate cache slot.
- */
- if (unused_cache)
- cache = unused_cache;
- else {
- cache = oldest_cache;
- if (cache->dirty)
- raw_write_blk(channel, data,
- cache->block, 1, cache->buf);
- }
+ if (eldest)
+ *eldest = (unused_cache) ? unused_cache : oldest_cache;
+ return 0;
+}
+
+/*
+ * Reuse a particular cache entry for another block.
+ */
+void reuse_cache(io_channel channel, struct unix_private_data *data,
+ struct unix_cache *cache, unsigned long block)
+{
+ if (cache->dirty && cache->in_use)
+ raw_write_blk(channel, data, cache->block, 1, cache->buf);
+
cache->in_use = 1;
cache->dirty = 0;
cache->block = block;
cache->access_time = ++data->access_time;
- return cache;
}
/*
@@ -444,7 +445,7 @@ static errcode_t unix_read_blk(io_channel channel, unsigned long block,
int count, void *buf)
{
struct unix_private_data *data;
- struct unix_cache *cache;
+ struct unix_cache *cache, *reuse[READ_DIRECT_SIZE];
errcode_t retval;
char *cp;
int i, j;
@@ -454,10 +455,10 @@ static errcode_t unix_read_blk(io_channel channel, unsigned long block,
EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
/*
- * If we're doing an odd-sized read, flush out the cache and
- * then do a direct read.
+ * If we're doing an odd-sized read or a very large read,
+ * flush out the cache and then do a direct read.
*/
- if (count < 0) {
+ if (count < 0 || count > WRITE_DIRECT_SIZE) {
if ((retval = flush_cached_blocks(channel, data, 0)))
return retval;
return raw_read_blk(channel, data, block, count, buf);
@@ -466,7 +467,8 @@ static errcode_t unix_read_blk(io_channel channel, unsigned long block,
cp = buf;
while (count > 0) {
/* If it's in the cache, use it! */
- if ((cache = find_cached_block(channel, data, block, 0))) {
+ if ((cache = find_cached_block(channel, data, block,
+ &reuse[0]))) {
#ifdef DEBUG
printf("Using cached block %d\n", block);
#endif
@@ -481,7 +483,8 @@ static errcode_t unix_read_blk(io_channel channel, unsigned long block,
* single read request
*/
for (i=1; i < count; i++)
- if (find_cached_block(channel, data, block+i, 0))
+ if (find_cached_block(channel, data, block+i,
+ &reuse[i]))
break;
#ifdef DEBUG
printf("Reading %d blocks starting at %d\n", i, block);
@@ -492,9 +495,9 @@ static errcode_t unix_read_blk(io_channel channel, unsigned long block,
/* Save the results in the cache */
for (j=0; j < i; j++) {
count--;
- cache = find_cached_block(channel, data, block++, 1);
- if (cache)
- memcpy(cache->buf, cp, channel->block_size);
+ cache = reuse[j];
+ reuse_cache(channel, data, cache, block++);
+ memcpy(cache->buf, cp, channel->block_size);
cp += channel->block_size;
}
}
@@ -505,7 +508,7 @@ static errcode_t unix_write_blk(io_channel channel, unsigned long block,
int count, const void *buf)
{
struct unix_private_data *data;
- struct unix_cache *cache;
+ struct unix_cache *cache, *reuse;
errcode_t retval = 0, retval2;
const char *cp;
int writethrough;
@@ -518,7 +521,7 @@ static errcode_t unix_write_blk(io_channel channel, unsigned long block,
* If we're doing an odd-sized write or a very large write,
* flush out the cache completely and then do a direct write.
*/
- if (count < 0 || count > WRITE_VIA_CACHE_SIZE) {
+ if (count < 0 || count > WRITE_DIRECT_SIZE) {
if ((retval = flush_cached_blocks(channel, data, 1)))
return retval;
return raw_write_blk(channel, data, block, count, buf);
@@ -535,19 +538,13 @@ static errcode_t unix_write_blk(io_channel channel, unsigned long block,
cp = buf;
while (count > 0) {
- cache = find_cached_block(channel, data, block, 1);
+ cache = find_cached_block(channel, data, block, &reuse);
if (!cache) {
- /*
- * Oh shit, we couldn't get cache descriptor.
- * Force the write directly.
- */
- if ((retval2 = raw_write_blk(channel, data, block,
- 1, cp)))
- retval = retval2;
- } else {
- memcpy(cache->buf, cp, channel->block_size);
- cache->dirty = !writethrough;
+ cache = reuse;
+ reuse_cache(channel, data, cache, block);
}
+ memcpy(cache->buf, cp, channel->block_size);
+ cache->dirty = !writethrough;
count--;
block++;
cp += channel->block_size;