diff mbox series

btrfs: qgroup: fix quota root leak after quota disable failure

Message ID d4186215561658577a9622bf111c79909f0521c6.1718883560.git.fdmanana@suse.com (mailing list archive)
State New, archived
Headers show
Series btrfs: qgroup: fix quota root leak after quota disable failure | expand

Commit Message

Filipe Manana June 20, 2024, 11:41 a.m. UTC
From: Filipe Manana <fdmanana@suse.com>

If during the quota disable we fail when cleaning the quota tree or when
deleting the root from the root tree, we jump to the 'out' label without
ever dropping the reference on the quota root, resulting in a leak of the
root since fs_info->quota_root is no longer pointing to the root (we have
set it to NULL just before those steps).

Fix this by always doing a btrfs_put_root() call under the 'out' label.
This is a problem that exists since qgroups were first added in 2012 by
commit bed92eae26cc ("Btrfs: qgroup implementation and prototypes"), but
back then we missed a kfree on the quota root and free_extent_buffer()
calls on its root and commit root nodes, since back then roots were not
yet reference counted.

Signed-off-by: Filipe Manana <fdmanana@suse.com>
---
 fs/btrfs/qgroup.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

Comments

Boris Burkov June 20, 2024, 9:06 p.m. UTC | #1
On Thu, Jun 20, 2024 at 12:41:09PM +0100, fdmanana@kernel.org wrote:
> From: Filipe Manana <fdmanana@suse.com>
> 
> If during the quota disable we fail when cleaning the quota tree or when
> deleting the root from the root tree, we jump to the 'out' label without
> ever dropping the reference on the quota root, resulting in a leak of the
> root since fs_info->quota_root is no longer pointing to the root (we have
> set it to NULL just before those steps).
> 
> Fix this by always doing a btrfs_put_root() call under the 'out' label.
> This is a problem that exists since qgroups were first added in 2012 by
> commit bed92eae26cc ("Btrfs: qgroup implementation and prototypes"), but
> back then we missed a kfree on the quota root and free_extent_buffer()
> calls on its root and commit root nodes, since back then roots were not
> yet reference counted.
> 
Reviewed-by: Boris Burkov <boris@bur.io>
> Signed-off-by: Filipe Manana <fdmanana@suse.com>
> ---
>  fs/btrfs/qgroup.c | 4 ++--
>  1 file changed, 2 insertions(+), 2 deletions(-)
> 
> diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c
> index 3edbe5bb19c6..d89240512796 100644
> --- a/fs/btrfs/qgroup.c
> +++ b/fs/btrfs/qgroup.c
> @@ -1346,7 +1346,7 @@ static int flush_reservations(struct btrfs_fs_info *fs_info)
>  
>  int btrfs_quota_disable(struct btrfs_fs_info *fs_info)
>  {
> -	struct btrfs_root *quota_root;
> +	struct btrfs_root *quota_root = NULL;
>  	struct btrfs_trans_handle *trans = NULL;
>  	int ret = 0;
>  
> @@ -1445,9 +1445,9 @@ int btrfs_quota_disable(struct btrfs_fs_info *fs_info)
>  				    quota_root->node, 0, 1);
>  	if (ret < 0)
>  		btrfs_abort_transaction(trans, ret);
> -	btrfs_put_root(quota_root);
>  
>  out:
> +	btrfs_put_root(quota_root);
>  	mutex_unlock(&fs_info->qgroup_ioctl_lock);
>  	if (ret && trans)
>  		btrfs_end_transaction(trans);
> -- 
> 2.43.0
>
Qu Wenruo June 20, 2024, 10:27 p.m. UTC | #2
在 2024/6/20 21:11, fdmanana@kernel.org 写道:
> From: Filipe Manana <fdmanana@suse.com>
>
> If during the quota disable we fail when cleaning the quota tree or when
> deleting the root from the root tree, we jump to the 'out' label without
> ever dropping the reference on the quota root, resulting in a leak of the
> root since fs_info->quota_root is no longer pointing to the root (we have
> set it to NULL just before those steps).
>
> Fix this by always doing a btrfs_put_root() call under the 'out' label.
> This is a problem that exists since qgroups were first added in 2012 by
> commit bed92eae26cc ("Btrfs: qgroup implementation and prototypes"), but
> back then we missed a kfree on the quota root and free_extent_buffer()
> calls on its root and commit root nodes, since back then roots were not
> yet reference counted.
>
> Signed-off-by: Filipe Manana <fdmanana@suse.com>

Reviewed-by: Qu Wenruo <wqu@suse.com>

Thanks,
Qu
> ---
>   fs/btrfs/qgroup.c | 4 ++--
>   1 file changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c
> index 3edbe5bb19c6..d89240512796 100644
> --- a/fs/btrfs/qgroup.c
> +++ b/fs/btrfs/qgroup.c
> @@ -1346,7 +1346,7 @@ static int flush_reservations(struct btrfs_fs_info *fs_info)
>
>   int btrfs_quota_disable(struct btrfs_fs_info *fs_info)
>   {
> -	struct btrfs_root *quota_root;
> +	struct btrfs_root *quota_root = NULL;
>   	struct btrfs_trans_handle *trans = NULL;
>   	int ret = 0;
>
> @@ -1445,9 +1445,9 @@ int btrfs_quota_disable(struct btrfs_fs_info *fs_info)
>   				    quota_root->node, 0, 1);
>   	if (ret < 0)
>   		btrfs_abort_transaction(trans, ret);
> -	btrfs_put_root(quota_root);
>
>   out:
> +	btrfs_put_root(quota_root);
>   	mutex_unlock(&fs_info->qgroup_ioctl_lock);
>   	if (ret && trans)
>   		btrfs_end_transaction(trans);
diff mbox series

Patch

diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c
index 3edbe5bb19c6..d89240512796 100644
--- a/fs/btrfs/qgroup.c
+++ b/fs/btrfs/qgroup.c
@@ -1346,7 +1346,7 @@  static int flush_reservations(struct btrfs_fs_info *fs_info)
 
 int btrfs_quota_disable(struct btrfs_fs_info *fs_info)
 {
-	struct btrfs_root *quota_root;
+	struct btrfs_root *quota_root = NULL;
 	struct btrfs_trans_handle *trans = NULL;
 	int ret = 0;
 
@@ -1445,9 +1445,9 @@  int btrfs_quota_disable(struct btrfs_fs_info *fs_info)
 				    quota_root->node, 0, 1);
 	if (ret < 0)
 		btrfs_abort_transaction(trans, ret);
-	btrfs_put_root(quota_root);
 
 out:
+	btrfs_put_root(quota_root);
 	mutex_unlock(&fs_info->qgroup_ioctl_lock);
 	if (ret && trans)
 		btrfs_end_transaction(trans);