FAILED: patch "[PATCH] btrfs: fix block group leak when removing fails" failed to apply to 4.4-stable tree
Subsystems (2)
[email protected]
maintainerThe patch below does not apply to the 4.4-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From f6033c5e333238f299c3ae03fac8cc1365b23b77 Mon Sep 17 00:00:00 2001
From: Xiyu Yang <[email protected]>
Date: Tue, 21 Apr 2020 10:54:11 +0800
Subject: [PATCH] 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.
fs/btrfs/block-group.c +10 -6
@@ -916,7 +916,7 @@ int btrfs_remove_block_group(struct btrfs_trans_handle *trans, path =btrfs_alloc_path ();if (!path) { ret = -ENOMEM ; - goto out; + goto out_put_group; }/*
@@ -954,7 +954,7 @@ int btrfs_remove_block_group(struct btrfs_trans_handle *trans, ret =btrfs_orphan_add (trans,BTRFS_I (inode));if (ret) {btrfs_add_delayed_iput (inode); - goto out; + goto out_put_group; }clear_nlink (inode);/* One for the block groups ref */
@@ -977,13 +977,13 @@ int btrfs_remove_block_group(struct btrfs_trans_handle *trans, ret =btrfs_search_slot (trans, tree_root, &key, path,-1 ,1 );if (ret <0 ) - goto out; + goto out_put_group;if (ret >0 )btrfs_release_path (path);if (ret ==0 ) { ret =btrfs_del_item (trans, tree_root, path);if (ret) - goto out; + goto out_put_group;btrfs_release_path (path); }
@@ -1102,9 +1102,9 @@ int btrfs_remove_block_group(struct btrfs_trans_handle *trans, ret =remove_block_group_free_space (trans, block_group);if (ret) - goto out; + goto out_put_group; -btrfs_put_block_group (block_group); +/* Once for the block groups rbtree */ btrfs_put_block_group (block_group); ret =btrfs_search_slot (trans, root, &key, path,-1 ,1 );
@@ -1127,6 +1127,10 @@ int btrfs_remove_block_group(struct btrfs_trans_handle *trans,/* once for the tree */ free_extent_map (em); } + +out_put_group: +/* Once for the lookup reference */ +btrfs_put_block_group (block_group); out:if (remove_rsv)btrfs_delayed_refs_rsv_release (fs_info,1 );