Btrfs: prevent looping forever in finish_current_insert and del_pending_extents

finish_current_insert and del_pending_extents process extent tree modifications
that build up while we are changing the extent tree.  It is a confusing
bit of code that prevents recursion.

Both functions run through a list of pending operations and both funcs
add to the list of pending operations.  If you have two procs in either
one of them, they can end up looping forever making more work for each other.

This patch makes them walk forward through the list of pending changes instead
of always trying to process the entire list.  At transaction commit
time, we catch any changes that were left over.

Signed-off-by: Chris Mason <chris.mason@oracle.com>

diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index 155c8dc..fada9c2 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -45,9 +45,9 @@
 };
 
 static int finish_current_insert(struct btrfs_trans_handle *trans, struct
-				 btrfs_root *extent_root);
+				 btrfs_root *extent_root, int all);
 static int del_pending_extents(struct btrfs_trans_handle *trans, struct
-			       btrfs_root *extent_root);
+			       btrfs_root *extent_root, int all);
 static struct btrfs_block_group_cache *
 __btrfs_find_block_group(struct btrfs_root *root,
 			 struct btrfs_block_group_cache *hint,
@@ -711,8 +711,8 @@
 				    parent, ref_root, ref_generation,
 				    owner_objectid);
 	BUG_ON(ret);
-	finish_current_insert(trans, extent_root);
-	del_pending_extents(trans, extent_root);
+	finish_current_insert(trans, extent_root, 0);
+	del_pending_extents(trans, extent_root, 0);
 out:
 	btrfs_free_path(path);
 	return ret;
@@ -784,8 +784,8 @@
 				    ref_root, ref_generation,
 				    owner_objectid);
 	BUG_ON(ret);
-	finish_current_insert(trans, root->fs_info->extent_root);
-	del_pending_extents(trans, root->fs_info->extent_root);
+	finish_current_insert(trans, root->fs_info->extent_root, 0);
+	del_pending_extents(trans, root->fs_info->extent_root, 0);
 
 	btrfs_free_path(path);
 	return 0;
@@ -810,8 +810,8 @@
 int btrfs_extent_post_op(struct btrfs_trans_handle *trans,
 			 struct btrfs_root *root)
 {
-	finish_current_insert(trans, root->fs_info->extent_root);
-	del_pending_extents(trans, root->fs_info->extent_root);
+	finish_current_insert(trans, root->fs_info->extent_root, 1);
+	del_pending_extents(trans, root->fs_info->extent_root, 1);
 	return 0;
 }
 
@@ -1292,8 +1292,8 @@
 	btrfs_mark_buffer_dirty(leaf);
 	btrfs_release_path(extent_root, path);
 fail:
-	finish_current_insert(trans, extent_root);
-	pending_ret = del_pending_extents(trans, extent_root);
+	finish_current_insert(trans, extent_root, 0);
+	pending_ret = del_pending_extents(trans, extent_root, 0);
 	if (ret)
 		return ret;
 	if (pending_ret)
@@ -1690,7 +1690,7 @@
 }
 
 static int finish_current_insert(struct btrfs_trans_handle *trans,
-				 struct btrfs_root *extent_root)
+				 struct btrfs_root *extent_root, int all)
 {
 	u64 start;
 	u64 end;
@@ -1714,7 +1714,7 @@
 					    &end, EXTENT_WRITEBACK);
 		if (ret) {
 			mutex_unlock(&info->extent_ins_mutex);
-			if (search) {
+			if (search && all) {
 				search = 0;
 				continue;
 			}
@@ -1723,7 +1723,7 @@
 
 		ret = try_lock_extent(&info->extent_ins, start, end, GFP_NOFS);
 		if (!ret) {
-			search = end+1;
+			search = end + 1;
 			mutex_unlock(&info->extent_ins_mutex);
 			cond_resched();
 			continue;
@@ -1785,7 +1785,10 @@
 		}
 		kfree(extent_op);
 		unlock_extent(&info->extent_ins, start, end, GFP_NOFS);
-		search = 0;
+		if (all)
+			search = 0;
+		else
+			search = end + 1;
 
 		cond_resched();
 	}
@@ -1992,7 +1995,7 @@
 #endif
 	}
 	btrfs_free_path(path);
-	finish_current_insert(trans, extent_root);
+	finish_current_insert(trans, extent_root, 0);
 	return ret;
 }
 
@@ -2001,7 +2004,7 @@
  * them from the extent map
  */
 static int del_pending_extents(struct btrfs_trans_handle *trans, struct
-			       btrfs_root *extent_root)
+			       btrfs_root *extent_root, int all)
 {
 	int ret;
 	int err = 0;
@@ -2023,7 +2026,7 @@
 					    EXTENT_WRITEBACK);
 		if (ret) {
 			mutex_unlock(&info->extent_ins_mutex);
-			if (search) {
+			if (all && search) {
 				search = 0;
 				continue;
 			}
@@ -2088,7 +2091,10 @@
 			err = ret;
 		unlock_extent(extent_ins, start, end, GFP_NOFS);
 
-		search = 0;
+		if (all)
+			search = 0;
+		else
+			search = end + 1;
 		cond_resched();
 	}
 	return err;
@@ -2155,8 +2161,8 @@
 			    root_objectid, ref_generation,
 			    owner_objectid, pin, pin == 0);
 
-	finish_current_insert(trans, root->fs_info->extent_root);
-	pending_ret = del_pending_extents(trans, root->fs_info->extent_root);
+	finish_current_insert(trans, root->fs_info->extent_root, 0);
+	pending_ret = del_pending_extents(trans, root->fs_info->extent_root, 0);
 	return ret ? ret : pending_ret;
 }
 
@@ -2580,8 +2586,8 @@
 	trans->alloc_exclude_start = 0;
 	trans->alloc_exclude_nr = 0;
 	btrfs_free_path(path);
-	finish_current_insert(trans, extent_root);
-	pending_ret = del_pending_extents(trans, extent_root);
+	finish_current_insert(trans, extent_root, 0);
+	pending_ret = del_pending_extents(trans, extent_root, 0);
 
 	if (ret)
 		goto out;
@@ -5229,8 +5235,8 @@
 				sizeof(cache->item));
 	BUG_ON(ret);
 
-	finish_current_insert(trans, extent_root);
-	ret = del_pending_extents(trans, extent_root);
+	finish_current_insert(trans, extent_root, 0);
+	ret = del_pending_extents(trans, extent_root, 0);
 	BUG_ON(ret);
 	set_avail_alloc_bits(extent_root->fs_info, type);
 
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c
index 924af6f..968b84f 100644
--- a/fs/btrfs/transaction.c
+++ b/fs/btrfs/transaction.c
@@ -430,7 +430,10 @@
 	u64 old_root_bytenr;
 	struct btrfs_root *tree_root = root->fs_info->tree_root;
 
+	btrfs_extent_post_op(trans, root);
 	btrfs_write_dirty_block_groups(trans, root);
+	btrfs_extent_post_op(trans, root);
+
 	while(1) {
 		old_root_bytenr = btrfs_root_bytenr(&root->root_item);
 		if (old_root_bytenr == root->node->start)
@@ -440,11 +443,15 @@
 		btrfs_set_root_level(&root->root_item,
 				     btrfs_header_level(root->node));
 		btrfs_set_root_generation(&root->root_item, trans->transid);
+
+		btrfs_extent_post_op(trans, root);
+
 		ret = btrfs_update_root(trans, tree_root,
 					&root->root_key,
 					&root->root_item);
 		BUG_ON(ret);
 		btrfs_write_dirty_block_groups(trans, root);
+		btrfs_extent_post_op(trans, root);
 	}
 	return 0;
 }
@@ -459,15 +466,20 @@
 	struct list_head *next;
 	struct extent_buffer *eb;
 
+	btrfs_extent_post_op(trans, fs_info->tree_root);
+
 	eb = btrfs_lock_root_node(fs_info->tree_root);
 	btrfs_cow_block(trans, fs_info->tree_root, eb, NULL, 0, &eb, 0);
 	btrfs_tree_unlock(eb);
 	free_extent_buffer(eb);
 
+	btrfs_extent_post_op(trans, fs_info->tree_root);
+
 	while(!list_empty(&fs_info->dirty_cowonly_roots)) {
 		next = fs_info->dirty_cowonly_roots.next;
 		list_del_init(next);
 		root = list_entry(next, struct btrfs_root, dirty_list);
+
 		update_cowonly_root(trans, root);
 	}
 	return 0;