Patch "btrfs: fix a block group ref counter leak after failure to remove block group" has been added to the 4.19-stable tree

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This is a note to let you know that I've just added the patch titled

    btrfs: fix a block group ref counter leak after failure to remove block group

to the 4.19-stable tree which can be found at:
    http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary

The filename of the patch is:
     btrfs-fix-a-block-group-ref-counter-leak-after-failu.patch
and it can be found in the queue-4.19 subdirectory.

If you, or anyone else, feels it should not be added to the stable tree,
please let <stable@xxxxxxxxxxxxxxx> know about it.



commit 9edbe6592ec77d0c1137399e3137141d79ea1c65
Author: Filipe Manana <fdmanana@xxxxxxxx>
Date:   Mon Jun 1 19:12:06 2020 +0100

    btrfs: fix a block group ref counter leak after failure to remove block group
    
    [ Upstream commit 9fecd13202f520f3f25d5b1c313adb740fe19773 ]
    
    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: f6033c5e333238 ("btrfs: fix block group leak when removing fails")
    CC: stable@xxxxxxxxxxxxxxx # 4.4+
    Reviewed-by: Nikolay Borisov <nborisov@xxxxxxxx>
    Reviewed-by: Anand Jain <anand.jain@xxxxxxxxxx>
    Signed-off-by: Filipe Manana <fdmanana@xxxxxxxx>
    Reviewed-by: David Sterba <dsterba@xxxxxxxx>
    Signed-off-by: David Sterba <dsterba@xxxxxxxx>
    Signed-off-by: Sasha Levin <sashal@xxxxxxxxxx>

diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index 271e70c45d5bd..ec3aa76d19b7f 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -10286,7 +10286,7 @@ int btrfs_remove_block_group(struct btrfs_trans_handle *trans,
 	path = btrfs_alloc_path();
 	if (!path) {
 		ret = -ENOMEM;
-		goto out_put_group;
+		goto out;
 	}
 
 	/*
@@ -10323,7 +10323,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_put_group;
+			goto out;
 		}
 		clear_nlink(inode);
 		/* One for the block groups ref */
@@ -10346,13 +10346,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_put_group;
+		goto out;
 	if (ret > 0)
 		btrfs_release_path(path);
 	if (ret == 0) {
 		ret = btrfs_del_item(trans, tree_root, path);
 		if (ret)
-			goto out_put_group;
+			goto out;
 		btrfs_release_path(path);
 	}
 
@@ -10361,6 +10361,9 @@ int btrfs_remove_block_group(struct btrfs_trans_handle *trans,
 		 &fs_info->block_group_cache_tree);
 	RB_CLEAR_NODE(&block_group->cache_node);
 
+	/* Once for the block groups rbtree */
+	btrfs_put_block_group(block_group);
+
 	if (fs_info->first_logical_byte == block_group->key.objectid)
 		fs_info->first_logical_byte = (u64)-1;
 	spin_unlock(&fs_info->block_group_cache_lock);
@@ -10494,10 +10497,7 @@ int btrfs_remove_block_group(struct btrfs_trans_handle *trans,
 
 	ret = remove_block_group_free_space(trans, block_group);
 	if (ret)
-		goto out_put_group;
-
-	/* Once for the block groups rbtree */
-	btrfs_put_block_group(block_group);
+		goto out;
 
 	ret = btrfs_search_slot(trans, root, &key, path, -1, 1);
 	if (ret > 0)
@@ -10525,10 +10525,9 @@ int btrfs_remove_block_group(struct btrfs_trans_handle *trans,
 		free_extent_map(em);
 	}
 
-out_put_group:
+out:
 	/* Once for the lookup reference */
 	btrfs_put_block_group(block_group);
-out:
 	btrfs_free_path(path);
 	return ret;
 }



[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux