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.

diff --git a/lib/ext2fs/unix_io.c b/lib/ext2fs/unix_io.c
index 1dcca4a..a76f9d8 100644
--- a/lib/ext2fs/unix_io.c
+++ b/lib/ext2fs/unix_io.c
@@ -55,7 +55,8 @@
 };
 
 #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 @@
 }
 
 /*
- * 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 @@
 	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 @@
 		    (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 @@
 			       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 @@
 	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 @@
 	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 @@
 		 * 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 @@
 		/* 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 @@
 				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 @@
 	 * 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 @@
 	
 	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;