Btrfs: Fold some btree readahead routines into something more generic.

Signed-off-by: Chris Mason <chris.mason@oracle.com>
diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c
index aa824e2..7a08491 100644
--- a/fs/btrfs/ctree.c
+++ b/fs/btrfs/ctree.c
@@ -640,6 +640,73 @@
 }
 
 /*
+ * readahead one full node of leaves
+ */
+static void reada_for_search(struct btrfs_root *root, struct btrfs_path *path,
+			     int slot)
+{
+	struct btrfs_node *node;
+	int i;
+	u32 nritems;
+	u64 item_objectid;
+	u64 blocknr;
+	u64 search;
+	u64 cluster_start;
+	int ret;
+	int nread = 0;
+	int direction = path->reada;
+	struct radix_tree_root found;
+	unsigned long gang[8];
+	struct buffer_head *bh;
+
+	if (!path->nodes[1])
+		return;
+
+	node = btrfs_buffer_node(path->nodes[1]);
+	search = btrfs_node_blockptr(node, slot);
+	bh = btrfs_find_tree_block(root, search);
+	if (bh) {
+		brelse(bh);
+		return;
+	}
+
+	init_bit_radix(&found);
+	nritems = btrfs_header_nritems(&node->header);
+	for (i = slot; i < nritems; i++) {
+		item_objectid = btrfs_disk_key_objectid(&node->ptrs[i].key);
+		blocknr = btrfs_node_blockptr(node, i);
+		set_radix_bit(&found, blocknr);
+	}
+	if (direction > 0) {
+		cluster_start = search - 4;
+		if (cluster_start > search)
+			cluster_start = 0;
+	} else
+		cluster_start = search + 4;
+	while(1) {
+		ret = find_first_radix_bit(&found, gang, 0, ARRAY_SIZE(gang));
+		if (!ret)
+			break;
+		for (i = 0; i < ret; i++) {
+			blocknr = gang[i];
+			clear_radix_bit(&found, blocknr);
+			if (nread > 64)
+				continue;
+			if (direction > 0 && cluster_start <= blocknr &&
+			    cluster_start + 8 > blocknr) {
+				cluster_start = blocknr;
+				readahead_tree_block(root, blocknr);
+				nread++;
+			} else if (direction < 0 && cluster_start >= blocknr &&
+				   blocknr + 8 > cluster_start) {
+				cluster_start = blocknr;
+				readahead_tree_block(root, blocknr);
+				nread++;
+			}
+		}
+	}
+}
+/*
  * look for key in the tree.  path is filled in with nodes along the way
  * if key is found, we return zero and you can find the item in the leaf
  * level of the path (level 0)
@@ -660,9 +727,11 @@
 	struct buffer_head *cow_buf;
 	struct btrfs_node *c;
 	struct btrfs_root_item *root_item = &root->root_item;
+	u64 blocknr;
 	int slot;
 	int ret;
 	int level;
+	int should_reada = p->reada;
 	u8 lowest_level = 0;
 
 	if (btrfs_root_refs(root_item) == 0 && root->ref_cows) {
@@ -728,7 +797,11 @@
 			/* this is only true while dropping a snapshot */
 			if (level == lowest_level)
 				break;
+			blocknr = btrfs_node_blockptr(c, slot);
+			if (level == 1 && should_reada)
+				reada_for_search(root, p, slot);
 			b = read_tree_block(root, btrfs_node_blockptr(c, slot));
+
 		} else {
 			struct btrfs_leaf *l = (struct btrfs_leaf *)c;
 			p->slots[level] = slot;
@@ -1915,6 +1988,8 @@
 		blocknr = btrfs_node_blockptr(c_node, slot);
 		if (next)
 			btrfs_block_release(root, next);
+		if (level == 1 && path->reada)
+			reada_for_search(root, path, slot);
 		next = read_tree_block(root, blocknr);
 		break;
 	}
@@ -1927,6 +2002,8 @@
 		path->slots[level] = 0;
 		if (!level)
 			break;
+		if (level == 1 && path->reada)
+			reada_for_search(root, path, slot);
 		next = read_tree_block(root,
 		       btrfs_node_blockptr(btrfs_buffer_node(next), 0));
 	}
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
index 73c2e75..c5a18d5 100644
--- a/fs/btrfs/ctree.h
+++ b/fs/btrfs/ctree.h
@@ -177,6 +177,7 @@
 struct btrfs_path {
 	struct buffer_head *nodes[BTRFS_MAX_LEVEL];
 	int slots[BTRFS_MAX_LEVEL];
+	int reada;
 };
 
 /*
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index 9455974..5d4d5d8 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -32,33 +32,6 @@
 static int del_pending_extents(struct btrfs_trans_handle *trans, struct
 			       btrfs_root *extent_root);
 
-static void reada_extent_leaves(struct btrfs_root *root,
-				struct btrfs_path *path, u64 limit)
-{
-	struct btrfs_node *node;
-	int i;
-	int nritems;
-	u64 item_objectid;
-	u64 blocknr;
-	int slot;
-	int ret;
-
-	if (!path->nodes[1])
-		return;
-	node = btrfs_buffer_node(path->nodes[1]);
-	slot = path->slots[1] + 1;
-	nritems = btrfs_header_nritems(&node->header);
-	for (i = slot; i < nritems && i < slot + 8; i++) {
-		item_objectid = btrfs_disk_key_objectid(&node->ptrs[i].key);
-		if (item_objectid > limit)
-			break;
-		blocknr = btrfs_node_blockptr(node, i);
-		ret = readahead_tree_block(root, blocknr);
-		if (ret)
-			break;
-	}
-}
-
 static int cache_block_group(struct btrfs_root *root,
 			     struct btrfs_block_group_cache *block_group)
 {
@@ -84,6 +57,7 @@
 	path = btrfs_alloc_path();
 	if (!path)
 		return -ENOMEM;
+	path->reada = 1;
 	key.objectid = block_group->key.objectid;
 	key.flags = 0;
 	key.offset = 0;
@@ -94,12 +68,10 @@
 	if (ret && path->slots[0] > 0)
 		path->slots[0]--;
 	limit = block_group->key.objectid + block_group->key.offset;
-	reada_extent_leaves(root, path, limit);
 	while(1) {
 		leaf = btrfs_buffer_leaf(path->nodes[0]);
 		slot = path->slots[0];
 		if (slot >= btrfs_header_nritems(&leaf->header)) {
-			reada_extent_leaves(root, path, limit);
 			ret = btrfs_next_leaf(root, path);
 			if (ret < 0)
 				goto err;
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index fa9c531..3889032 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -375,40 +375,6 @@
 }
 
 /*
- * truncates go from a high offset to a low offset.  So, walk
- * from hi to lo in the node and issue readas.  Stop when you find
- * keys from a different objectid
- */
-static void reada_truncate(struct btrfs_root *root, struct btrfs_path *path,
-			   u64 objectid)
-{
-	struct btrfs_node *node;
-	int i;
-	int nritems;
-	u64 item_objectid;
-	u64 blocknr;
-	int slot;
-	int ret;
-
-	if (!path->nodes[1])
-		return;
-	node = btrfs_buffer_node(path->nodes[1]);
-	slot = path->slots[1];
-	if (slot == 0)
-		return;
-	nritems = btrfs_header_nritems(&node->header);
-	for (i = slot - 1; i >= 0; i--) {
-		item_objectid = btrfs_disk_key_objectid(&node->ptrs[i].key);
-		if (item_objectid != objectid)
-			break;
-		blocknr = btrfs_node_blockptr(node, i);
-		ret = readahead_tree_block(root, blocknr);
-		if (ret)
-			break;
-	}
-}
-
-/*
  * this can truncate away extent items, csum items and directory items.
  * It starts at a high offset and removes keys until it can't find
  * any higher than i_size.
@@ -434,6 +400,7 @@
 	int del_item;
 
 	path = btrfs_alloc_path();
+	path->reada = -1;
 	BUG_ON(!path);
 	/* FIXME, add redo link to tree so we don't leak on crash */
 	key.objectid = inode->i_ino;
@@ -450,7 +417,6 @@
 			BUG_ON(path->slots[0] == 0);
 			path->slots[0]--;
 		}
-		reada_truncate(root, path, inode->i_ino);
 		leaf = btrfs_buffer_leaf(path->nodes[0]);
 		found_key = &leaf->items[path->slots[0]].key;
 		found_type = btrfs_disk_key_type(found_key);
@@ -827,36 +793,6 @@
 	return d_splice_alias(inode, dentry);
 }
 
-/*
- * readahead one full node of leaves as long as their keys include
- * the objectid supplied
- */
-static void reada_leaves(struct btrfs_root *root, struct btrfs_path *path,
-			 u64 objectid)
-{
-	struct btrfs_node *node;
-	int i;
-	u32 nritems;
-	u64 item_objectid;
-	u64 blocknr;
-	int slot;
-	int ret;
-
-	if (!path->nodes[1])
-		return;
-	node = btrfs_buffer_node(path->nodes[1]);
-	slot = path->slots[1];
-	nritems = btrfs_header_nritems(&node->header);
-	for (i = slot + 1; i < nritems; i++) {
-		item_objectid = btrfs_disk_key_objectid(&node->ptrs[i].key);
-		if (item_objectid != objectid)
-			break;
-		blocknr = btrfs_node_blockptr(node, i);
-		ret = readahead_tree_block(root, blocknr);
-		if (ret)
-			break;
-	}
-}
 static unsigned char btrfs_filetype_table[] = {
 	DT_UNKNOWN, DT_REG, DT_DIR, DT_CHR, DT_BLK, DT_FIFO, DT_SOCK, DT_LNK
 };
@@ -890,18 +826,17 @@
 	btrfs_set_key_type(&key, key_type);
 	key.offset = filp->f_pos;
 	path = btrfs_alloc_path();
+	path->reada = 1;
 	ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
 	if (ret < 0)
 		goto err;
 	advance = 0;
-	reada_leaves(root, path, inode->i_ino);
 	while(1) {
 		leaf = btrfs_buffer_leaf(path->nodes[0]);
 		nritems = btrfs_header_nritems(&leaf->header);
 		slot = path->slots[0];
 		if (advance || slot >= nritems) {
 			if (slot >= nritems -1) {
-				reada_leaves(root, path, inode->i_ino);
 				ret = btrfs_next_leaf(root, path);
 				if (ret)
 					break;