Btrfs: Fixup last found extent caching

Signed-off-by: Chris Mason <chris.mason@oracle.com>
diff --git a/fs/btrfs/Makefile b/fs/btrfs/Makefile
index d92d08d..ae7f4c0 100644
--- a/fs/btrfs/Makefile
+++ b/fs/btrfs/Makefile
@@ -1,6 +1,6 @@
 
 CC=gcc
-CFLAGS = -Wall
+CFLAGS = -g -Wall
 headers = radix-tree.h ctree.h disk-io.h kerncompat.h print-tree.h list.h
 objects = ctree.o disk-io.o radix-tree.o mkfs.o extent-tree.o print-tree.o
 
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
index 4a7bc4e..518326f 100644
--- a/fs/btrfs/ctree.h
+++ b/fs/btrfs/ctree.h
@@ -54,6 +54,7 @@
 	struct tree_buffer *commit_root;
 	struct ctree_root *extent_root;
 	struct key current_insert;
+	struct key last_insert;
 	int fp;
 	struct radix_tree_root cache_radix;
 	struct radix_tree_root pinned_radix;
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index 2fe31c3..997cc57 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -186,6 +186,7 @@
 	root->commit_root = NULL;
 	root->node = read_tree_block(root, info->tree_root);
 	memset(&root->current_insert, 0, sizeof(root->current_insert));
+	memset(&root->last_insert, 0, sizeof(root->last_insert));
 	return 0;
 }
 
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index 8a2b8aa..dd11532 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -102,9 +102,12 @@
 						 ARRAY_SIZE(gang));
 		if (!ret)
 			break;
-		for (i = 0; i < ret; i++)
+		for (i = 0; i < ret; i++) {
 			radix_tree_delete(&extent_root->pinned_radix, gang[i]);
+		}
 	}
+	extent_root->last_insert.objectid = 0;
+	extent_root->last_insert.offset = 0;
 	return 0;
 }
 
@@ -170,6 +173,9 @@
 			radix_tree_preload_end();
 		}
 		ret = del_item(extent_root, &path);
+		if (root != extent_root &&
+		    extent_root->last_insert.objectid < blocknr)
+			extent_root->last_insert.objectid = blocknr;
 		if (ret)
 			BUG();
 	}
@@ -261,8 +267,11 @@
 	int start_found;
 	struct leaf *l;
 	struct ctree_root * root = orig_root->extent_root;
-	int total_needed = num_blocks + MAX_LEVEL * 3;
+	int total_needed = num_blocks;
 
+	total_needed += (node_level(root->node->node.header.flags) + 1) * 3;
+	if (root->last_insert.objectid > search_start)
+		search_start = root->last_insert.objectid;
 check_failed:
 	init_path(&path);
 	ins->objectid = search_start;
@@ -273,6 +282,9 @@
 	if (ret < 0)
 		goto error;
 
+	if (path.slots[0] > 0)
+		path.slots[0]--;
+
 	while (1) {
 		l = &path.nodes[0]->leaf;
 		slot = path.slots[0];
@@ -293,31 +305,21 @@
 			ins->offset = (u64)-1;
 			goto check_pending;
 		}
-		if (slot == 0) {
-			int last_slot = l->header.nritems - 1;
-			u64 span = l->items[last_slot].key.objectid;
-			span -= l->items[slot].key.objectid;
-			if (span + total_needed > last_slot - slot) {
-				path.slots[0] = last_slot + 1;
-				key = &l->items[last_slot].key;
-				last_block = key->objectid + key->offset;
-				start_found = 1;
-				continue;
-			}
-		}
 		key = &l->items[slot].key;
 		if (key->objectid >= search_start) {
 			if (start_found) {
+				if (last_block < search_start)
+					last_block = search_start;
 				hole_size = key->objectid - last_block;
 				if (hole_size > total_needed) {
 					ins->objectid = last_block;
 					ins->offset = hole_size;
 					goto check_pending;
 				}
-			} else
-				start_found = 1;
-			last_block = key->objectid + key->offset;
+			}
 		}
+		start_found = 1;
+		last_block = key->objectid + key->offset;
 		path.slots[0]++;
 	}
 	// FIXME -ENOSPC
@@ -335,9 +337,10 @@
 		}
 	}
 	BUG_ON(root->current_insert.offset);
-	root->current_insert.offset = total_needed;
+	root->current_insert.offset = total_needed - num_blocks;
 	root->current_insert.objectid = ins->objectid + num_blocks;
 	root->current_insert.flags = 0;
+	root->last_insert.objectid = ins->objectid;
 	ins->offset = num_blocks;
 	return 0;
 error: