aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChris Mason <chris.mason@oracle.com>2008-10-30 11:23:27 -0400
committerChris Mason <chris.mason@oracle.com>2008-10-30 11:23:27 -0400
commit87ef2bb46bfc4be0b40799e68115cbe28d80a1bd (patch)
tree8060158d9adee7ad2fc591c47ad1354b07237020
parent09fde3c9ba360926ce021c184a1ee343f4d8fa19 (diff)
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>
-rw-r--r--fs/btrfs/extent-tree.c54
-rw-r--r--fs/btrfs/transaction.c12
2 files changed, 42 insertions, 24 deletions
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index 155c8dc56a22..fada9c22a021 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -45,9 +45,9 @@ struct pending_extent_op {
45}; 45};
46 46
47static int finish_current_insert(struct btrfs_trans_handle *trans, struct 47static int finish_current_insert(struct btrfs_trans_handle *trans, struct
48 btrfs_root *extent_root); 48 btrfs_root *extent_root, int all);
49static int del_pending_extents(struct btrfs_trans_handle *trans, struct 49static int del_pending_extents(struct btrfs_trans_handle *trans, struct
50 btrfs_root *extent_root); 50 btrfs_root *extent_root, int all);
51static struct btrfs_block_group_cache * 51static struct btrfs_block_group_cache *
52__btrfs_find_block_group(struct btrfs_root *root, 52__btrfs_find_block_group(struct btrfs_root *root,
53 struct btrfs_block_group_cache *hint, 53 struct btrfs_block_group_cache *hint,
@@ -711,8 +711,8 @@ static int __btrfs_update_extent_ref(struct btrfs_trans_handle *trans,
711 parent, ref_root, ref_generation, 711 parent, ref_root, ref_generation,
712 owner_objectid); 712 owner_objectid);
713 BUG_ON(ret); 713 BUG_ON(ret);
714 finish_current_insert(trans, extent_root); 714 finish_current_insert(trans, extent_root, 0);
715 del_pending_extents(trans, extent_root); 715 del_pending_extents(trans, extent_root, 0);
716out: 716out:
717 btrfs_free_path(path); 717 btrfs_free_path(path);
718 return ret; 718 return ret;
@@ -784,8 +784,8 @@ static int __btrfs_inc_extent_ref(struct btrfs_trans_handle *trans,
784 ref_root, ref_generation, 784 ref_root, ref_generation,
785 owner_objectid); 785 owner_objectid);
786 BUG_ON(ret); 786 BUG_ON(ret);
787 finish_current_insert(trans, root->fs_info->extent_root); 787 finish_current_insert(trans, root->fs_info->extent_root, 0);
788 del_pending_extents(trans, root->fs_info->extent_root); 788 del_pending_extents(trans, root->fs_info->extent_root, 0);
789 789
790 btrfs_free_path(path); 790 btrfs_free_path(path);
791 return 0; 791 return 0;
@@ -810,8 +810,8 @@ int btrfs_inc_extent_ref(struct btrfs_trans_handle *trans,
810int btrfs_extent_post_op(struct btrfs_trans_handle *trans, 810int btrfs_extent_post_op(struct btrfs_trans_handle *trans,
811 struct btrfs_root *root) 811 struct btrfs_root *root)
812{ 812{
813 finish_current_insert(trans, root->fs_info->extent_root); 813 finish_current_insert(trans, root->fs_info->extent_root, 1);
814 del_pending_extents(trans, root->fs_info->extent_root); 814 del_pending_extents(trans, root->fs_info->extent_root, 1);
815 return 0; 815 return 0;
816} 816}
817 817
@@ -1292,8 +1292,8 @@ static int write_one_cache_group(struct btrfs_trans_handle *trans,
1292 btrfs_mark_buffer_dirty(leaf); 1292 btrfs_mark_buffer_dirty(leaf);
1293 btrfs_release_path(extent_root, path); 1293 btrfs_release_path(extent_root, path);
1294fail: 1294fail:
1295 finish_current_insert(trans, extent_root); 1295 finish_current_insert(trans, extent_root, 0);
1296 pending_ret = del_pending_extents(trans, extent_root); 1296 pending_ret = del_pending_extents(trans, extent_root, 0);
1297 if (ret) 1297 if (ret)
1298 return ret; 1298 return ret;
1299 if (pending_ret) 1299 if (pending_ret)
@@ -1690,7 +1690,7 @@ int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans,
1690} 1690}
1691 1691
1692static int finish_current_insert(struct btrfs_trans_handle *trans, 1692static int finish_current_insert(struct btrfs_trans_handle *trans,
1693 struct btrfs_root *extent_root) 1693 struct btrfs_root *extent_root, int all)
1694{ 1694{
1695 u64 start; 1695 u64 start;
1696 u64 end; 1696 u64 end;
@@ -1714,7 +1714,7 @@ static int finish_current_insert(struct btrfs_trans_handle *trans,
1714 &end, EXTENT_WRITEBACK); 1714 &end, EXTENT_WRITEBACK);
1715 if (ret) { 1715 if (ret) {
1716 mutex_unlock(&info->extent_ins_mutex); 1716 mutex_unlock(&info->extent_ins_mutex);
1717 if (search) { 1717 if (search && all) {
1718 search = 0; 1718 search = 0;
1719 continue; 1719 continue;
1720 } 1720 }
@@ -1723,7 +1723,7 @@ static int finish_current_insert(struct btrfs_trans_handle *trans,
1723 1723
1724 ret = try_lock_extent(&info->extent_ins, start, end, GFP_NOFS); 1724 ret = try_lock_extent(&info->extent_ins, start, end, GFP_NOFS);
1725 if (!ret) { 1725 if (!ret) {
1726 search = end+1; 1726 search = end + 1;
1727 mutex_unlock(&info->extent_ins_mutex); 1727 mutex_unlock(&info->extent_ins_mutex);
1728 cond_resched(); 1728 cond_resched();
1729 continue; 1729 continue;
@@ -1785,7 +1785,10 @@ static int finish_current_insert(struct btrfs_trans_handle *trans,
1785 } 1785 }
1786 kfree(extent_op); 1786 kfree(extent_op);
1787 unlock_extent(&info->extent_ins, start, end, GFP_NOFS); 1787 unlock_extent(&info->extent_ins, start, end, GFP_NOFS);
1788 search = 0; 1788 if (all)
1789 search = 0;
1790 else
1791 search = end + 1;
1789 1792
1790 cond_resched(); 1793 cond_resched();
1791 } 1794 }
@@ -1992,7 +1995,7 @@ static int __free_extent(struct btrfs_trans_handle *trans,
1992#endif 1995#endif
1993 } 1996 }
1994 btrfs_free_path(path); 1997 btrfs_free_path(path);
1995 finish_current_insert(trans, extent_root); 1998 finish_current_insert(trans, extent_root, 0);
1996 return ret; 1999 return ret;
1997} 2000}
1998 2001
@@ -2001,7 +2004,7 @@ static int __free_extent(struct btrfs_trans_handle *trans,
2001 * them from the extent map 2004 * them from the extent map
2002 */ 2005 */
2003static int del_pending_extents(struct btrfs_trans_handle *trans, struct 2006static int del_pending_extents(struct btrfs_trans_handle *trans, struct
2004 btrfs_root *extent_root) 2007 btrfs_root *extent_root, int all)
2005{ 2008{
2006 int ret; 2009 int ret;
2007 int err = 0; 2010 int err = 0;
@@ -2023,7 +2026,7 @@ static int del_pending_extents(struct btrfs_trans_handle *trans, struct
2023 EXTENT_WRITEBACK); 2026 EXTENT_WRITEBACK);
2024 if (ret) { 2027 if (ret) {
2025 mutex_unlock(&info->extent_ins_mutex); 2028 mutex_unlock(&info->extent_ins_mutex);
2026 if (search) { 2029 if (all && search) {
2027 search = 0; 2030 search = 0;
2028 continue; 2031 continue;
2029 } 2032 }
@@ -2088,7 +2091,10 @@ free_extent:
2088 err = ret; 2091 err = ret;
2089 unlock_extent(extent_ins, start, end, GFP_NOFS); 2092 unlock_extent(extent_ins, start, end, GFP_NOFS);
2090 2093
2091 search = 0; 2094 if (all)
2095 search = 0;
2096 else
2097 search = end + 1;
2092 cond_resched(); 2098 cond_resched();
2093 } 2099 }
2094 return err; 2100 return err;
@@ -2155,8 +2161,8 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans,
2155 root_objectid, ref_generation, 2161 root_objectid, ref_generation,
2156 owner_objectid, pin, pin == 0); 2162 owner_objectid, pin, pin == 0);
2157 2163
2158 finish_current_insert(trans, root->fs_info->extent_root); 2164 finish_current_insert(trans, root->fs_info->extent_root, 0);
2159 pending_ret = del_pending_extents(trans, root->fs_info->extent_root); 2165 pending_ret = del_pending_extents(trans, root->fs_info->extent_root, 0);
2160 return ret ? ret : pending_ret; 2166 return ret ? ret : pending_ret;
2161} 2167}
2162 2168
@@ -2580,8 +2586,8 @@ static int __btrfs_alloc_reserved_extent(struct btrfs_trans_handle *trans,
2580 trans->alloc_exclude_start = 0; 2586 trans->alloc_exclude_start = 0;
2581 trans->alloc_exclude_nr = 0; 2587 trans->alloc_exclude_nr = 0;
2582 btrfs_free_path(path); 2588 btrfs_free_path(path);
2583 finish_current_insert(trans, extent_root); 2589 finish_current_insert(trans, extent_root, 0);
2584 pending_ret = del_pending_extents(trans, extent_root); 2590 pending_ret = del_pending_extents(trans, extent_root, 0);
2585 2591
2586 if (ret) 2592 if (ret)
2587 goto out; 2593 goto out;
@@ -5229,8 +5235,8 @@ int btrfs_make_block_group(struct btrfs_trans_handle *trans,
5229 sizeof(cache->item)); 5235 sizeof(cache->item));
5230 BUG_ON(ret); 5236 BUG_ON(ret);
5231 5237
5232 finish_current_insert(trans, extent_root); 5238 finish_current_insert(trans, extent_root, 0);
5233 ret = del_pending_extents(trans, extent_root); 5239 ret = del_pending_extents(trans, extent_root, 0);
5234 BUG_ON(ret); 5240 BUG_ON(ret);
5235 set_avail_alloc_bits(extent_root->fs_info, type); 5241 set_avail_alloc_bits(extent_root->fs_info, type);
5236 5242
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c
index 924af6f2aeac..968b84f17a19 100644
--- a/fs/btrfs/transaction.c
+++ b/fs/btrfs/transaction.c
@@ -430,7 +430,10 @@ static int update_cowonly_root(struct btrfs_trans_handle *trans,
430 u64 old_root_bytenr; 430 u64 old_root_bytenr;
431 struct btrfs_root *tree_root = root->fs_info->tree_root; 431 struct btrfs_root *tree_root = root->fs_info->tree_root;
432 432
433 btrfs_extent_post_op(trans, root);
433 btrfs_write_dirty_block_groups(trans, root); 434 btrfs_write_dirty_block_groups(trans, root);
435 btrfs_extent_post_op(trans, root);
436
434 while(1) { 437 while(1) {
435 old_root_bytenr = btrfs_root_bytenr(&root->root_item); 438 old_root_bytenr = btrfs_root_bytenr(&root->root_item);
436 if (old_root_bytenr == root->node->start) 439 if (old_root_bytenr == root->node->start)
@@ -440,11 +443,15 @@ static int update_cowonly_root(struct btrfs_trans_handle *trans,
440 btrfs_set_root_level(&root->root_item, 443 btrfs_set_root_level(&root->root_item,
441 btrfs_header_level(root->node)); 444 btrfs_header_level(root->node));
442 btrfs_set_root_generation(&root->root_item, trans->transid); 445 btrfs_set_root_generation(&root->root_item, trans->transid);
446
447 btrfs_extent_post_op(trans, root);
448
443 ret = btrfs_update_root(trans, tree_root, 449 ret = btrfs_update_root(trans, tree_root,
444 &root->root_key, 450 &root->root_key,
445 &root->root_item); 451 &root->root_item);
446 BUG_ON(ret); 452 BUG_ON(ret);
447 btrfs_write_dirty_block_groups(trans, root); 453 btrfs_write_dirty_block_groups(trans, root);
454 btrfs_extent_post_op(trans, root);
448 } 455 }
449 return 0; 456 return 0;
450} 457}
@@ -459,15 +466,20 @@ int btrfs_commit_tree_roots(struct btrfs_trans_handle *trans,
459 struct list_head *next; 466 struct list_head *next;
460 struct extent_buffer *eb; 467 struct extent_buffer *eb;
461 468
469 btrfs_extent_post_op(trans, fs_info->tree_root);
470
462 eb = btrfs_lock_root_node(fs_info->tree_root); 471 eb = btrfs_lock_root_node(fs_info->tree_root);
463 btrfs_cow_block(trans, fs_info->tree_root, eb, NULL, 0, &eb, 0); 472 btrfs_cow_block(trans, fs_info->tree_root, eb, NULL, 0, &eb, 0);
464 btrfs_tree_unlock(eb); 473 btrfs_tree_unlock(eb);
465 free_extent_buffer(eb); 474 free_extent_buffer(eb);
466 475
476 btrfs_extent_post_op(trans, fs_info->tree_root);
477
467 while(!list_empty(&fs_info->dirty_cowonly_roots)) { 478 while(!list_empty(&fs_info->dirty_cowonly_roots)) {
468 next = fs_info->dirty_cowonly_roots.next; 479 next = fs_info->dirty_cowonly_roots.next;
469 list_del_init(next); 480 list_del_init(next);
470 root = list_entry(next, struct btrfs_root, dirty_list); 481 root = list_entry(next, struct btrfs_root, dirty_list);
482
471 update_cowonly_root(trans, root); 483 update_cowonly_root(trans, root);
472 } 484 }
473 return 0; 485 return 0;