Skip to content

Commit 9fecd13

Browse files
fdmananakdave
authored andcommitted
btrfs: fix a block group ref counter leak after failure to remove block group
When removing a block group, if we fail to delete the block group's item from the extent tree, we jump to the 'out' label and end up decrementing the block group's reference count once only (by 1), resulting in a counter leak because the block group at that point was already removed from the block group cache rbtree - so we have to decrement the reference count twice, once for the rbtree and once for our lookup at the start of the function. There is a second bug where if removing the free space tree entries (the call to remove_block_group_free_space()) fails we end up jumping to the 'out_put_group' label but end up decrementing the reference count only once, when we should have done it twice, since we have already removed the block group from the block group cache rbtree. This happens because the reference count decrement for the rbtree reference happens after attempting to remove the free space tree entries, which is far away from the place where we remove the block group from the rbtree. To make things less error prone, decrement the reference count for the rbtree immediately after removing the block group from it. This also eleminates the need for two different exit labels on error, renaming 'out_put_label' to just 'out' and removing the old 'out'. Fixes: f6033c5 ("btrfs: fix block group leak when removing fails") CC: [email protected] # 4.4+ Reviewed-by: Nikolay Borisov <[email protected]> Reviewed-by: Anand Jain <[email protected]> Signed-off-by: Filipe Manana <[email protected]> Reviewed-by: David Sterba <[email protected]> Signed-off-by: David Sterba <[email protected]>
1 parent 55e20bd commit 9fecd13

File tree

1 file changed

+9
-10
lines changed

1 file changed

+9
-10
lines changed

fs/btrfs/block-group.c

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -940,7 +940,7 @@ int btrfs_remove_block_group(struct btrfs_trans_handle *trans,
940940
path = btrfs_alloc_path();
941941
if (!path) {
942942
ret = -ENOMEM;
943-
goto out_put_group;
943+
goto out;
944944
}
945945

946946
/*
@@ -978,7 +978,7 @@ int btrfs_remove_block_group(struct btrfs_trans_handle *trans,
978978
ret = btrfs_orphan_add(trans, BTRFS_I(inode));
979979
if (ret) {
980980
btrfs_add_delayed_iput(inode);
981-
goto out_put_group;
981+
goto out;
982982
}
983983
clear_nlink(inode);
984984
/* One for the block groups ref */
@@ -1001,13 +1001,13 @@ int btrfs_remove_block_group(struct btrfs_trans_handle *trans,
10011001

10021002
ret = btrfs_search_slot(trans, tree_root, &key, path, -1, 1);
10031003
if (ret < 0)
1004-
goto out_put_group;
1004+
goto out;
10051005
if (ret > 0)
10061006
btrfs_release_path(path);
10071007
if (ret == 0) {
10081008
ret = btrfs_del_item(trans, tree_root, path);
10091009
if (ret)
1010-
goto out_put_group;
1010+
goto out;
10111011
btrfs_release_path(path);
10121012
}
10131013

@@ -1016,6 +1016,9 @@ int btrfs_remove_block_group(struct btrfs_trans_handle *trans,
10161016
&fs_info->block_group_cache_tree);
10171017
RB_CLEAR_NODE(&block_group->cache_node);
10181018

1019+
/* Once for the block groups rbtree */
1020+
btrfs_put_block_group(block_group);
1021+
10191022
if (fs_info->first_logical_byte == block_group->start)
10201023
fs_info->first_logical_byte = (u64)-1;
10211024
spin_unlock(&fs_info->block_group_cache_lock);
@@ -1125,10 +1128,7 @@ int btrfs_remove_block_group(struct btrfs_trans_handle *trans,
11251128

11261129
ret = remove_block_group_free_space(trans, block_group);
11271130
if (ret)
1128-
goto out_put_group;
1129-
1130-
/* Once for the block groups rbtree */
1131-
btrfs_put_block_group(block_group);
1131+
goto out;
11321132

11331133
ret = remove_block_group_item(trans, path, block_group);
11341134
if (ret < 0)
@@ -1145,10 +1145,9 @@ int btrfs_remove_block_group(struct btrfs_trans_handle *trans,
11451145
free_extent_map(em);
11461146
}
11471147

1148-
out_put_group:
1148+
out:
11491149
/* Once for the lookup reference */
11501150
btrfs_put_block_group(block_group);
1151-
out:
11521151
if (remove_rsv)
11531152
btrfs_delayed_refs_rsv_release(fs_info, 1);
11541153
btrfs_free_path(path);

0 commit comments

Comments
 (0)