| From 0d68eefaee4ab5908c73b86de4a9ec369ea322d4 Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Thu, 8 Jun 2023 11:27:41 +0100 |
| Subject: btrfs: do not BUG_ON() on tree mod log failure at balance_level() |
| |
| From: Filipe Manana <fdmanana@suse.com> |
| |
| [ Upstream commit 39020d8abc7ec62c4de9b260e3d10d4a1c2478ce ] |
| |
| At balance_level(), instead of doing a BUG_ON() in case we fail to record |
| tree mod log operations, do a transaction abort and return the error to |
| the callers. There's really no need for the BUG_ON() as we can release |
| all resources in this context, and we have to abort because other future |
| tree searches that use the tree mod log (btrfs_search_old_slot()) may get |
| inconsistent results if other operations modify the tree after that |
| failure and before the tree mod log based search. |
| |
| CC: stable@vger.kernel.org # 5.4+ |
| Reviewed-by: Qu Wenruo <wqu@suse.com> |
| Signed-off-by: Filipe Manana <fdmanana@suse.com> |
| Reviewed-by: David Sterba <dsterba@suse.com> |
| Signed-off-by: David Sterba <dsterba@suse.com> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| fs/btrfs/ctree.c | 17 ++++++++++++++--- |
| 1 file changed, 14 insertions(+), 3 deletions(-) |
| |
| --- a/fs/btrfs/ctree.c |
| +++ b/fs/btrfs/ctree.c |
| @@ -935,7 +935,12 @@ static noinline int balance_level(struct |
| } |
| |
| ret = btrfs_tree_mod_log_insert_root(root->node, child, true); |
| - BUG_ON(ret < 0); |
| + if (ret < 0) { |
| + btrfs_tree_unlock(child); |
| + free_extent_buffer(child); |
| + btrfs_abort_transaction(trans, ret); |
| + goto enospc; |
| + } |
| rcu_assign_pointer(root->node, child); |
| |
| add_root_to_dirty_list(root); |
| @@ -1017,7 +1022,10 @@ static noinline int balance_level(struct |
| btrfs_node_key(right, &right_key, 0); |
| ret = btrfs_tree_mod_log_insert_key(parent, pslot + 1, |
| BTRFS_MOD_LOG_KEY_REPLACE, GFP_NOFS); |
| - BUG_ON(ret < 0); |
| + if (ret < 0) { |
| + btrfs_abort_transaction(trans, ret); |
| + goto enospc; |
| + } |
| btrfs_set_node_key(parent, &right_key, pslot + 1); |
| btrfs_mark_buffer_dirty(parent); |
| } |
| @@ -1063,7 +1071,10 @@ static noinline int balance_level(struct |
| btrfs_node_key(mid, &mid_key, 0); |
| ret = btrfs_tree_mod_log_insert_key(parent, pslot, |
| BTRFS_MOD_LOG_KEY_REPLACE, GFP_NOFS); |
| - BUG_ON(ret < 0); |
| + if (ret < 0) { |
| + btrfs_abort_transaction(trans, ret); |
| + goto enospc; |
| + } |
| btrfs_set_node_key(parent, &mid_key, pslot); |
| btrfs_mark_buffer_dirty(parent); |
| } |