diff mbox series

[v2,1/2] Btrfs: fix memory leak of transaction when deleting unused block group

Message ID 20200417153615.23832-1-fdmanana@kernel.org (mailing list archive)
State New, archived
Headers show
Series [v2,1/2] Btrfs: fix memory leak of transaction when deleting unused block group | expand

Commit Message

Filipe Manana April 17, 2020, 3:36 p.m. UTC
From: Filipe Manana <fdmanana@suse.com>

When cleaning pinned extents right before deleting an unused block group,
we check if there's still a previous transaction running and if so we
increment its reference count before using it for cleaning pinned ranges
in its pinned extents iotree. However we ended up never decrementing the
reference count after using the transaction, resulting in a memory leak.

Fix it by decrementing the reference count.

Signed-off-by: Filipe Manana <fdmanana@suse.com>
---

V2: Use btrfs_put_transaction() and not refcount_dec(), otherwise we are
    not really releasing the memory used by the transaction in case its
    refcount is 1. Stupid mistake.

 fs/btrfs/block-group.c | 4 ++++
 1 file changed, 4 insertions(+)

Comments

David Sterba April 17, 2020, 4:41 p.m. UTC | #1
On Fri, Apr 17, 2020 at 04:36:15PM +0100, fdmanana@kernel.org wrote:
> From: Filipe Manana <fdmanana@suse.com>
> 
> When cleaning pinned extents right before deleting an unused block group,
> we check if there's still a previous transaction running and if so we
> increment its reference count before using it for cleaning pinned ranges
> in its pinned extents iotree. However we ended up never decrementing the
> reference count after using the transaction, resulting in a memory leak.
> 
> Fix it by decrementing the reference count.
> 
> Signed-off-by: Filipe Manana <fdmanana@suse.com>
> ---
> 
> V2: Use btrfs_put_transaction() and not refcount_dec(), otherwise we are
>     not really releasing the memory used by the transaction in case its
>     refcount is 1. Stupid mistake.

I missed it too. As Nik pointed out on IRC, the API should be consistent
so that for put there's a get, or refcount_inc/refcount_dec. In this
case there's non-trivial work on the put side, so the wrappers make
sense.

A good example may be btrfs_get_block_group/btrfs_put_block_group, same
as for the transaction.

Trivial wrappers around plain _inc/_dec wouldn't be so great, but in
case there's eg refcount_dec_and_test + kfree, then I think this can be
considered a good pattern.
Filipe Manana April 21, 2020, 8:05 a.m. UTC | #2
On Fri, Apr 17, 2020 at 4:38 PM <fdmanana@kernel.org> wrote:
>
> From: Filipe Manana <fdmanana@suse.com>
>
> When cleaning pinned extents right before deleting an unused block group,
> we check if there's still a previous transaction running and if so we
> increment its reference count before using it for cleaning pinned ranges
> in its pinned extents iotree. However we ended up never decrementing the
> reference count after using the transaction, resulting in a memory leak.
>
> Fix it by decrementing the reference count.
>
> Signed-off-by: Filipe Manana <fdmanana@suse.com>

Fixes: fe119a6eeb6705 ("btrfs: switch to per-transaction pinned extents")

And missed that in v2, but had it in v1.

> ---
>
> V2: Use btrfs_put_transaction() and not refcount_dec(), otherwise we are
>     not really releasing the memory used by the transaction in case its
>     refcount is 1. Stupid mistake.
>
>  fs/btrfs/block-group.c | 4 ++++
>  1 file changed, 4 insertions(+)
>
> diff --git a/fs/btrfs/block-group.c b/fs/btrfs/block-group.c
> index 47f66c6a7d7f..af9e9a008724 100644
> --- a/fs/btrfs/block-group.c
> +++ b/fs/btrfs/block-group.c
> @@ -1288,11 +1288,15 @@ static bool clean_pinned_extents(struct btrfs_trans_handle *trans,
>         if (ret)
>                 goto err;
>         mutex_unlock(&fs_info->unused_bg_unpin_mutex);
> +       if (prev_trans)
> +               btrfs_put_transaction(prev_trans);
>
>         return true;
>
>  err:
>         mutex_unlock(&fs_info->unused_bg_unpin_mutex);
> +       if (prev_trans)
> +               btrfs_put_transaction(prev_trans);
>         btrfs_dec_block_group_ro(bg);
>         return false;
>  }
> --
> 2.11.0
>
David Sterba April 22, 2020, 10:57 p.m. UTC | #3
On Tue, Apr 21, 2020 at 09:05:33AM +0100, Filipe Manana wrote:
> On Fri, Apr 17, 2020 at 4:38 PM <fdmanana@kernel.org> wrote:
> >
> > From: Filipe Manana <fdmanana@suse.com>
> >
> > When cleaning pinned extents right before deleting an unused block group,
> > we check if there's still a previous transaction running and if so we
> > increment its reference count before using it for cleaning pinned ranges
> > in its pinned extents iotree. However we ended up never decrementing the
> > reference count after using the transaction, resulting in a memory leak.
> >
> > Fix it by decrementing the reference count.
> >
> > Signed-off-by: Filipe Manana <fdmanana@suse.com>
> 
> Fixes: fe119a6eeb6705 ("btrfs: switch to per-transaction pinned extents")
> 
> And missed that in v2, but had it in v1.

Patch updated, thanks.
diff mbox series

Patch

diff --git a/fs/btrfs/block-group.c b/fs/btrfs/block-group.c
index 47f66c6a7d7f..af9e9a008724 100644
--- a/fs/btrfs/block-group.c
+++ b/fs/btrfs/block-group.c
@@ -1288,11 +1288,15 @@  static bool clean_pinned_extents(struct btrfs_trans_handle *trans,
 	if (ret)
 		goto err;
 	mutex_unlock(&fs_info->unused_bg_unpin_mutex);
+	if (prev_trans)
+		btrfs_put_transaction(prev_trans);
 
 	return true;
 
 err:
 	mutex_unlock(&fs_info->unused_bg_unpin_mutex);
+	if (prev_trans)
+		btrfs_put_transaction(prev_trans);
 	btrfs_dec_block_group_ro(bg);
 	return false;
 }