Btrfs: use a separate flag for search_start vs a hint in find_free_extent

Signed-off-by: Chris Mason <chris.mason@oracle.com>
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index b6dc020..85616b4 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -5,8 +5,9 @@
 #include "transaction.h"
 
 static int find_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root
-			    *orig_root, u64 num_blocks, u64 search_start, u64
-			    search_end, struct btrfs_key *ins, int data);
+			    *orig_root, u64 num_blocks, u64 search_start,
+			    u64 search_end, u64 hint_block,
+			    struct btrfs_key *ins, int data);
 static int finish_current_insert(struct btrfs_trans_handle *trans, struct
 				 btrfs_root *extent_root);
 static int del_pending_extents(struct btrfs_trans_handle *trans, struct
@@ -157,12 +158,6 @@
 		    block_group->key.objectid + block_group->key.offset)
 			return block_group;
 	}
-	WARN_ON(1);
-	printk("lookup_block_group fails for blocknr %Lu\n", blocknr);
-	printk("last ret was %d\n", ret);
-	if (ret) {
-		printk("last block group was %Lu %Lu\n", block_group->key.objectid, block_group->key.offset);
-	}
 	return NULL;
 }
 
@@ -378,7 +373,7 @@
 	struct btrfs_key ins;
 	u32 refs;
 
-	find_free_extent(trans, root->fs_info->extent_root, 0, 0, (u64)-1,
+	find_free_extent(trans, root->fs_info->extent_root, 0, 0, (u64)-1, 0,
 			 &ins, 0);
 	path = btrfs_alloc_path();
 	BUG_ON(!path);
@@ -495,7 +490,7 @@
 	struct btrfs_block_group_item *bi;
 	struct btrfs_key ins;
 
-	find_free_extent(trans, extent_root, 0, 0, (u64)-1, &ins, 0);
+	find_free_extent(trans, extent_root, 0, 0, (u64)-1, 0, &ins, 0);
 	ret = btrfs_search_slot(trans, extent_root, &cache->key, path, 0, 1);
 	BUG_ON(ret);
 	bi = btrfs_item_ptr(btrfs_buffer_leaf(path->nodes[0]), path->slots[0],
@@ -788,7 +783,7 @@
 	btrfs_set_key_type(&key, BTRFS_EXTENT_ITEM_KEY);
 	key.offset = num_blocks;
 
-	find_free_extent(trans, root, 0, 0, (u64)-1, &ins, 0);
+	find_free_extent(trans, root, 0, 0, (u64)-1, 0, &ins, 0);
 	path = btrfs_alloc_path();
 	BUG_ON(!path);
 	btrfs_init_path(path);
@@ -906,7 +901,8 @@
  */
 static int find_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root
 			    *orig_root, u64 num_blocks, u64 search_start, u64
-			    search_end, struct btrfs_key *ins, int data)
+			    search_end, u64 hint_block,
+			    struct btrfs_key *ins, int data)
 {
 	struct btrfs_path *path;
 	struct btrfs_key key;
@@ -926,6 +922,7 @@
 	int level;
 	struct btrfs_block_group_cache *block_group;
 	int full_scan = 0;
+	int wrapped = 0;
 	u64 limit;
 
 	path = btrfs_alloc_path();
@@ -940,10 +937,10 @@
 	}
 	if (search_end == (u64)-1)
 		search_end = btrfs_super_total_blocks(info->disk_super);
-	if (search_start) {
-		block_group = lookup_block_group(info, search_start);
+	if (hint_block) {
+		block_group = lookup_block_group(info, hint_block);
 		block_group = btrfs_find_block_group(root, block_group,
-						     search_start, data, 1);
+						     hint_block, data, 1);
 	} else {
 		block_group = btrfs_find_block_group(root,
 						     trans->block_group, 0,
@@ -954,7 +951,7 @@
 	if (!block_group->data)
 		search_start = find_search_start(root, &block_group,
 						 search_start, total_needed);
-	else
+	else if (!full_scan)
 		search_start = max(block_group->last_alloc, search_start);
 
 	btrfs_init_path(path);
@@ -1039,7 +1036,7 @@
 
 		start_found = 1;
 		last_block = key.objectid + key.offset;
-		if (last_block >= block_group->key.objectid +
+		if (!full_scan && last_block >= block_group->key.objectid +
 		    block_group->key.offset) {
 			btrfs_release_path(root, path);
 			search_start = block_group->key.objectid +
@@ -1059,10 +1056,15 @@
 	BUG_ON(ins->objectid < search_start);
 
 	if (ins->objectid + num_blocks >= search_end) {
-		if (full_scan)
-			return -ENOSPC;
+		if (full_scan) {
+			ret = -ENOSPC;
+			goto error;
+		}
 		search_start = orig_search_start;
-		full_scan = 1;
+		if (wrapped)
+			full_scan = 1;
+		else
+			wrapped = 1;
 		goto new_group;
 	}
 	for (test_block = ins->objectid;
@@ -1132,14 +1134,20 @@
 new_group:
 	if (search_start + num_blocks >= search_end) {
 		search_start = orig_search_start;
-printk("doing full scan!\n");
-		full_scan = 1;
+		if (full_scan) {
+			ret = -ENOSPC;
+			goto error;
+		}
+		if (wrapped)
+			full_scan = 1;
+		else
+			wrapped = 1;
 	}
 	block_group = lookup_block_group(info, search_start);
+	cond_resched();
 	if (!full_scan)
 		block_group = btrfs_find_block_group(root, block_group,
 						     search_start, data, 0);
-	cond_resched();
 	goto check_failed;
 
 error:
@@ -1156,12 +1164,13 @@
  */
 int btrfs_alloc_extent(struct btrfs_trans_handle *trans,
 		       struct btrfs_root *root, u64 owner,
-		       u64 num_blocks, u64 search_start,
+		       u64 num_blocks, u64 hint_block,
 		       u64 search_end, struct btrfs_key *ins, int data)
 {
 	int ret;
 	int pending_ret;
 	u64 super_blocks_used;
+	u64 search_start = 0;
 	struct btrfs_fs_info *info = root->fs_info;
 	struct btrfs_root *extent_root = info->extent_root;
 	struct btrfs_extent_item extent_item;
@@ -1193,7 +1202,7 @@
 	 */
 	if (data) {
 		ret = find_free_extent(trans, root, 0, 0,
-				       search_end, &prealloc_key, 0);
+				       search_end, 0, &prealloc_key, 0);
 		if (ret) {
 			return ret;
 		}
@@ -1204,9 +1213,11 @@
 			search_start = info->extent_tree_prealloc[0] + 1;
 		}
 	}
+	if (hint_block < search_start)
+		hint_block = search_start;
 	/* do the real allocation */
 	ret = find_free_extent(trans, root, num_blocks, search_start,
-			       search_end, ins, data);
+			       search_end, hint_block, ins, data);
 	if (ret) {
 		return ret;
 	}
@@ -1226,8 +1237,12 @@
 		else
 			search_start = ins->objectid + ins->offset;
 
+		if (hint_block < search_start)
+			hint_block = search_start;
+
 		ret = find_free_extent(trans, root, 0, search_start,
-				       search_end, &prealloc_key, 0);
+				       search_end, hint_block,
+				       &prealloc_key, 0);
 		if (ret) {
 			return ret;
 		}