Skip to content

Commit 87ef2bb

Browse files
committed
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 <[email protected]>
1 parent 09fde3c commit 87ef2bb

File tree

2 files changed

+42
-24
lines changed

2 files changed

+42
-24
lines changed

fs/btrfs/extent-tree.c

Lines changed: 30 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,9 @@ struct pending_extent_op {
4545
};
4646

4747
static int finish_current_insert(struct btrfs_trans_handle *trans, struct
48-
btrfs_root *extent_root);
48+
btrfs_root *extent_root, int all);
4949
static int del_pending_extents(struct btrfs_trans_handle *trans, struct
50-
btrfs_root *extent_root);
50+
btrfs_root *extent_root, int all);
5151
static struct btrfs_block_group_cache *
5252
__btrfs_find_block_group(struct btrfs_root *root,
5353
struct btrfs_block_group_cache *hint,
@@ -711,8 +711,8 @@ static int __btrfs_update_extent_ref(struct btrfs_trans_handle *trans,
711711
parent, ref_root, ref_generation,
712712
owner_objectid);
713713
BUG_ON(ret);
714-
finish_current_insert(trans, extent_root);
715-
del_pending_extents(trans, extent_root);
714+
finish_current_insert(trans, extent_root, 0);
715+
del_pending_extents(trans, extent_root, 0);
716716
out:
717717
btrfs_free_path(path);
718718
return ret;
@@ -784,8 +784,8 @@ static int __btrfs_inc_extent_ref(struct btrfs_trans_handle *trans,
784784
ref_root, ref_generation,
785785
owner_objectid);
786786
BUG_ON(ret);
787-
finish_current_insert(trans, root->fs_info->extent_root);
788-
del_pending_extents(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, 0);
789789

790790
btrfs_free_path(path);
791791
return 0;
@@ -810,8 +810,8 @@ int btrfs_inc_extent_ref(struct btrfs_trans_handle *trans,
810810
int btrfs_extent_post_op(struct btrfs_trans_handle *trans,
811811
struct btrfs_root *root)
812812
{
813-
finish_current_insert(trans, root->fs_info->extent_root);
814-
del_pending_extents(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, 1);
815815
return 0;
816816
}
817817

@@ -1292,8 +1292,8 @@ static int write_one_cache_group(struct btrfs_trans_handle *trans,
12921292
btrfs_mark_buffer_dirty(leaf);
12931293
btrfs_release_path(extent_root, path);
12941294
fail:
1295-
finish_current_insert(trans, extent_root);
1296-
pending_ret = del_pending_extents(trans, extent_root);
1295+
finish_current_insert(trans, extent_root, 0);
1296+
pending_ret = del_pending_extents(trans, extent_root, 0);
12971297
if (ret)
12981298
return ret;
12991299
if (pending_ret)
@@ -1690,7 +1690,7 @@ int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans,
16901690
}
16911691

16921692
static int finish_current_insert(struct btrfs_trans_handle *trans,
1693-
struct btrfs_root *extent_root)
1693+
struct btrfs_root *extent_root, int all)
16941694
{
16951695
u64 start;
16961696
u64 end;
@@ -1714,7 +1714,7 @@ static int finish_current_insert(struct btrfs_trans_handle *trans,
17141714
&end, EXTENT_WRITEBACK);
17151715
if (ret) {
17161716
mutex_unlock(&info->extent_ins_mutex);
1717-
if (search) {
1717+
if (search && all) {
17181718
search = 0;
17191719
continue;
17201720
}
@@ -1723,7 +1723,7 @@ static int finish_current_insert(struct btrfs_trans_handle *trans,
17231723

17241724
ret = try_lock_extent(&info->extent_ins, start, end, GFP_NOFS);
17251725
if (!ret) {
1726-
search = end+1;
1726+
search = end + 1;
17271727
mutex_unlock(&info->extent_ins_mutex);
17281728
cond_resched();
17291729
continue;
@@ -1785,7 +1785,10 @@ static int finish_current_insert(struct btrfs_trans_handle *trans,
17851785
}
17861786
kfree(extent_op);
17871787
unlock_extent(&info->extent_ins, start, end, GFP_NOFS);
1788-
search = 0;
1788+
if (all)
1789+
search = 0;
1790+
else
1791+
search = end + 1;
17891792

17901793
cond_resched();
17911794
}
@@ -1992,7 +1995,7 @@ static int __free_extent(struct btrfs_trans_handle *trans,
19921995
#endif
19931996
}
19941997
btrfs_free_path(path);
1995-
finish_current_insert(trans, extent_root);
1998+
finish_current_insert(trans, extent_root, 0);
19961999
return ret;
19972000
}
19982001

@@ -2001,7 +2004,7 @@ static int __free_extent(struct btrfs_trans_handle *trans,
20012004
* them from the extent map
20022005
*/
20032006
static int del_pending_extents(struct btrfs_trans_handle *trans, struct
2004-
btrfs_root *extent_root)
2007+
btrfs_root *extent_root, int all)
20052008
{
20062009
int ret;
20072010
int err = 0;
@@ -2023,7 +2026,7 @@ static int del_pending_extents(struct btrfs_trans_handle *trans, struct
20232026
EXTENT_WRITEBACK);
20242027
if (ret) {
20252028
mutex_unlock(&info->extent_ins_mutex);
2026-
if (search) {
2029+
if (all && search) {
20272030
search = 0;
20282031
continue;
20292032
}
@@ -2088,7 +2091,10 @@ static int del_pending_extents(struct btrfs_trans_handle *trans, struct
20882091
err = ret;
20892092
unlock_extent(extent_ins, start, end, GFP_NOFS);
20902093

2091-
search = 0;
2094+
if (all)
2095+
search = 0;
2096+
else
2097+
search = end + 1;
20922098
cond_resched();
20932099
}
20942100
return err;
@@ -2155,8 +2161,8 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans,
21552161
root_objectid, ref_generation,
21562162
owner_objectid, pin, pin == 0);
21572163

2158-
finish_current_insert(trans, root->fs_info->extent_root);
2159-
pending_ret = del_pending_extents(trans, root->fs_info->extent_root);
2164+
finish_current_insert(trans, root->fs_info->extent_root, 0);
2165+
pending_ret = del_pending_extents(trans, root->fs_info->extent_root, 0);
21602166
return ret ? ret : pending_ret;
21612167
}
21622168

@@ -2580,8 +2586,8 @@ static int __btrfs_alloc_reserved_extent(struct btrfs_trans_handle *trans,
25802586
trans->alloc_exclude_start = 0;
25812587
trans->alloc_exclude_nr = 0;
25822588
btrfs_free_path(path);
2583-
finish_current_insert(trans, extent_root);
2584-
pending_ret = del_pending_extents(trans, extent_root);
2589+
finish_current_insert(trans, extent_root, 0);
2590+
pending_ret = del_pending_extents(trans, extent_root, 0);
25852591

25862592
if (ret)
25872593
goto out;
@@ -5229,8 +5235,8 @@ int btrfs_make_block_group(struct btrfs_trans_handle *trans,
52295235
sizeof(cache->item));
52305236
BUG_ON(ret);
52315237

5232-
finish_current_insert(trans, extent_root);
5233-
ret = del_pending_extents(trans, extent_root);
5238+
finish_current_insert(trans, extent_root, 0);
5239+
ret = del_pending_extents(trans, extent_root, 0);
52345240
BUG_ON(ret);
52355241
set_avail_alloc_bits(extent_root->fs_info, type);
52365242

fs/btrfs/transaction.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -430,7 +430,10 @@ static int update_cowonly_root(struct btrfs_trans_handle *trans,
430430
u64 old_root_bytenr;
431431
struct btrfs_root *tree_root = root->fs_info->tree_root;
432432

433+
btrfs_extent_post_op(trans, root);
433434
btrfs_write_dirty_block_groups(trans, root);
435+
btrfs_extent_post_op(trans, root);
436+
434437
while(1) {
435438
old_root_bytenr = btrfs_root_bytenr(&root->root_item);
436439
if (old_root_bytenr == root->node->start)
@@ -440,11 +443,15 @@ static int update_cowonly_root(struct btrfs_trans_handle *trans,
440443
btrfs_set_root_level(&root->root_item,
441444
btrfs_header_level(root->node));
442445
btrfs_set_root_generation(&root->root_item, trans->transid);
446+
447+
btrfs_extent_post_op(trans, root);
448+
443449
ret = btrfs_update_root(trans, tree_root,
444450
&root->root_key,
445451
&root->root_item);
446452
BUG_ON(ret);
447453
btrfs_write_dirty_block_groups(trans, root);
454+
btrfs_extent_post_op(trans, root);
448455
}
449456
return 0;
450457
}
@@ -459,15 +466,20 @@ int btrfs_commit_tree_roots(struct btrfs_trans_handle *trans,
459466
struct list_head *next;
460467
struct extent_buffer *eb;
461468

469+
btrfs_extent_post_op(trans, fs_info->tree_root);
470+
462471
eb = btrfs_lock_root_node(fs_info->tree_root);
463472
btrfs_cow_block(trans, fs_info->tree_root, eb, NULL, 0, &eb, 0);
464473
btrfs_tree_unlock(eb);
465474
free_extent_buffer(eb);
466475

476+
btrfs_extent_post_op(trans, fs_info->tree_root);
477+
467478
while(!list_empty(&fs_info->dirty_cowonly_roots)) {
468479
next = fs_info->dirty_cowonly_roots.next;
469480
list_del_init(next);
470481
root = list_entry(next, struct btrfs_root, dirty_list);
482+
471483
update_cowonly_root(trans, root);
472484
}
473485
return 0;

0 commit comments

Comments
 (0)