@@ -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