Skip to content

Commit f6033c5

Browse files
sherllykdave
authored andcommitted
btrfs: fix block group leak when removing fails
btrfs_remove_block_group() invokes btrfs_lookup_block_group(), which returns a local reference of the block group that contains the given bytenr to "block_group" with increased refcount. When btrfs_remove_block_group() returns, "block_group" becomes invalid, so the refcount should be decreased to keep refcount balanced. The reference counting issue happens in several exception handling paths of btrfs_remove_block_group(). When those error scenarios occur such as btrfs_alloc_path() returns NULL, the function forgets to decrease its refcnt increased by btrfs_lookup_block_group() and will cause a refcnt leak. Fix this issue by jumping to "out_put_group" label and calling btrfs_put_block_group() when those error scenarios occur. CC: [email protected] # 4.4+ Signed-off-by: Xiyu Yang <[email protected]> Signed-off-by: Xin Tan <[email protected]> Reviewed-by: David Sterba <[email protected]> Signed-off-by: David Sterba <[email protected]>
1 parent ef67963 commit f6033c5

File tree

1 file changed

+10
-6
lines changed

1 file changed

+10
-6
lines changed

fs/btrfs/block-group.c

+10-6
Original file line numberDiff line numberDiff line change
@@ -916,7 +916,7 @@ int btrfs_remove_block_group(struct btrfs_trans_handle *trans,
916916
path = btrfs_alloc_path();
917917
if (!path) {
918918
ret = -ENOMEM;
919-
goto out;
919+
goto out_put_group;
920920
}
921921

922922
/*
@@ -954,7 +954,7 @@ int btrfs_remove_block_group(struct btrfs_trans_handle *trans,
954954
ret = btrfs_orphan_add(trans, BTRFS_I(inode));
955955
if (ret) {
956956
btrfs_add_delayed_iput(inode);
957-
goto out;
957+
goto out_put_group;
958958
}
959959
clear_nlink(inode);
960960
/* One for the block groups ref */
@@ -977,13 +977,13 @@ int btrfs_remove_block_group(struct btrfs_trans_handle *trans,
977977

978978
ret = btrfs_search_slot(trans, tree_root, &key, path, -1, 1);
979979
if (ret < 0)
980-
goto out;
980+
goto out_put_group;
981981
if (ret > 0)
982982
btrfs_release_path(path);
983983
if (ret == 0) {
984984
ret = btrfs_del_item(trans, tree_root, path);
985985
if (ret)
986-
goto out;
986+
goto out_put_group;
987987
btrfs_release_path(path);
988988
}
989989

@@ -1102,9 +1102,9 @@ int btrfs_remove_block_group(struct btrfs_trans_handle *trans,
11021102

11031103
ret = remove_block_group_free_space(trans, block_group);
11041104
if (ret)
1105-
goto out;
1105+
goto out_put_group;
11061106

1107-
btrfs_put_block_group(block_group);
1107+
/* Once for the block groups rbtree */
11081108
btrfs_put_block_group(block_group);
11091109

11101110
ret = btrfs_search_slot(trans, root, &key, path, -1, 1);
@@ -1127,6 +1127,10 @@ int btrfs_remove_block_group(struct btrfs_trans_handle *trans,
11271127
/* once for the tree */
11281128
free_extent_map(em);
11291129
}
1130+
1131+
out_put_group:
1132+
/* Once for the lookup reference */
1133+
btrfs_put_block_group(block_group);
11301134
out:
11311135
if (remove_rsv)
11321136
btrfs_delayed_refs_rsv_release(fs_info, 1);

0 commit comments

Comments
 (0)