btrfs: do not BUG_ON() on tree mod log failure at balance_level()
authorFilipe Manana <fdmanana@suse.com>
Thu, 8 Jun 2023 10:27:41 +0000 (11:27 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 19 Jul 2023 14:22:08 +0000 (16:22 +0200)
[ 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

index ab9f8d6..9a20b9e 100644 (file)
@@ -935,7 +935,12 @@ static noinline int balance_level(struct btrfs_trans_handle *trans,
                }
 
                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_trans_handle *trans,
                        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_trans_handle *trans,
                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);
        }