Skip to content

Commit 507dd52

Browse files
SaltyKitkatkdave
authored andcommitted
btrfs: factor out root promotion logic into promote_child_to_root()
The balance_level() function is overly long and contains a cold code path that handles promoting a child node to root when the root has only one item. This code has distinct logic that is clearer and more maintainable when isolated in its own function. Signed-off-by: Sun YangKai <sunk67188@gmail.com> Reviewed-by: David Sterba <dsterba@suse.com> Signed-off-by: David Sterba <dsterba@suse.com>
1 parent 251ab1a commit 507dd52

File tree

1 file changed

+70
-46
lines changed

1 file changed

+70
-46
lines changed

fs/btrfs/ctree.c

Lines changed: 70 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -861,6 +861,75 @@ struct extent_buffer *btrfs_read_node_slot(struct extent_buffer *parent,
861861
return eb;
862862
}
863863

864+
/*
865+
* Promote a child node to become the new tree root.
866+
*
867+
* @trans: Transaction handle
868+
* @root: Tree root structure to update
869+
* @path: Path holding nodes and locks
870+
* @level: Level of the parent (old root)
871+
* @parent: The parent (old root) with exactly one item
872+
*
873+
* This helper is called during rebalancing when the root node contains only
874+
* a single item (nritems == 1). We can reduce the tree height by promoting
875+
* that child to become the new root and freeing the old root node. The path
876+
* locks and references are updated accordingly.
877+
*
878+
* Return: 0 on success, negative errno on failure. The transaction is aborted
879+
* on critical errors.
880+
*/
881+
static int promote_child_to_root(struct btrfs_trans_handle *trans,
882+
struct btrfs_root *root, struct btrfs_path *path,
883+
int level, struct extent_buffer *parent)
884+
{
885+
struct extent_buffer *child;
886+
int ret;
887+
888+
ASSERT(btrfs_header_nritems(parent) == 1);
889+
890+
child = btrfs_read_node_slot(parent, 0);
891+
if (IS_ERR(child))
892+
return PTR_ERR(child);
893+
894+
btrfs_tree_lock(child);
895+
ret = btrfs_cow_block(trans, root, child, parent, 0, &child, BTRFS_NESTING_COW);
896+
if (ret) {
897+
btrfs_tree_unlock(child);
898+
free_extent_buffer(child);
899+
return ret;
900+
}
901+
902+
ret = btrfs_tree_mod_log_insert_root(root->node, child, true);
903+
if (unlikely(ret < 0)) {
904+
btrfs_tree_unlock(child);
905+
free_extent_buffer(child);
906+
btrfs_abort_transaction(trans, ret);
907+
return ret;
908+
}
909+
rcu_assign_pointer(root->node, child);
910+
911+
add_root_to_dirty_list(root);
912+
btrfs_tree_unlock(child);
913+
914+
path->locks[level] = 0;
915+
path->nodes[level] = NULL;
916+
btrfs_clear_buffer_dirty(trans, parent);
917+
btrfs_tree_unlock(parent);
918+
/* Once for the path. */
919+
free_extent_buffer(parent);
920+
921+
root_sub_used_bytes(root);
922+
ret = btrfs_free_tree_block(trans, btrfs_root_id(root), parent, 0, 1);
923+
/* Once for the root ptr. */
924+
free_extent_buffer_stale(parent);
925+
if (unlikely(ret < 0)) {
926+
btrfs_abort_transaction(trans, ret);
927+
return ret;
928+
}
929+
930+
return 0;
931+
}
932+
864933
/*
865934
* node level balancing, used to make sure nodes are in proper order for
866935
* item deletion. We balance from the top down, so we have to make sure
@@ -900,55 +969,10 @@ static noinline int balance_level(struct btrfs_trans_handle *trans,
900969
* by promoting the node below to a root
901970
*/
902971
if (!parent) {
903-
struct extent_buffer *child;
904-
905972
if (btrfs_header_nritems(mid) != 1)
906973
return 0;
907974

908-
/* promote the child to a root */
909-
child = btrfs_read_node_slot(mid, 0);
910-
if (IS_ERR(child)) {
911-
ret = PTR_ERR(child);
912-
goto out;
913-
}
914-
915-
btrfs_tree_lock(child);
916-
ret = btrfs_cow_block(trans, root, child, mid, 0, &child,
917-
BTRFS_NESTING_COW);
918-
if (ret) {
919-
btrfs_tree_unlock(child);
920-
free_extent_buffer(child);
921-
goto out;
922-
}
923-
924-
ret = btrfs_tree_mod_log_insert_root(root->node, child, true);
925-
if (unlikely(ret < 0)) {
926-
btrfs_tree_unlock(child);
927-
free_extent_buffer(child);
928-
btrfs_abort_transaction(trans, ret);
929-
goto out;
930-
}
931-
rcu_assign_pointer(root->node, child);
932-
933-
add_root_to_dirty_list(root);
934-
btrfs_tree_unlock(child);
935-
936-
path->locks[level] = 0;
937-
path->nodes[level] = NULL;
938-
btrfs_clear_buffer_dirty(trans, mid);
939-
btrfs_tree_unlock(mid);
940-
/* once for the path */
941-
free_extent_buffer(mid);
942-
943-
root_sub_used_bytes(root);
944-
ret = btrfs_free_tree_block(trans, btrfs_root_id(root), mid, 0, 1);
945-
/* once for the root ptr */
946-
free_extent_buffer_stale(mid);
947-
if (unlikely(ret < 0)) {
948-
btrfs_abort_transaction(trans, ret);
949-
goto out;
950-
}
951-
return 0;
975+
return promote_child_to_root(trans, root, path, level, mid);
952976
}
953977
if (btrfs_header_nritems(mid) >
954978
BTRFS_NODEPTRS_PER_BLOCK(fs_info) / 4)

0 commit comments

Comments
 (0)