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