| From 6a4d9103df92f178d9be9ed4165a29659b75b246 Mon Sep 17 00:00:00 2001 |
| From: Filipe Manana <fdmanana@suse.com> |
| Date: Tue, 15 Oct 2019 10:54:39 +0100 |
| Subject: [PATCH] Btrfs: fix qgroup double free after failure to reserve |
| metadata for delalloc |
| |
| commit c7967fc1499beb9b70bb9d33525fb0b384af8883 upstream. |
| |
| If we fail to reserve metadata for delalloc operations we end up releasing |
| the previously reserved qgroup amount twice, once explicitly under the |
| 'out_qgroup' label by calling btrfs_qgroup_free_meta_prealloc() and once |
| again, under label 'out_fail', by calling btrfs_inode_rsv_release() with a |
| value of 'true' for its 'qgroup_free' argument, which results in |
| btrfs_qgroup_free_meta_prealloc() being called again, so we end up having |
| a double free. |
| |
| Also if we fail to reserve the necessary qgroup amount, we jump to the |
| label 'out_fail', which calls btrfs_inode_rsv_release() and that in turns |
| calls btrfs_qgroup_free_meta_prealloc(), even though we weren't able to |
| reserve any qgroup amount. So we freed some amount we never reserved. |
| |
| So fix this by removing the call to btrfs_inode_rsv_release() in the |
| failure path, since it's not necessary at all as we haven't changed the |
| inode's block reserve in any way at this point. |
| |
| Fixes: c8eaeac7b73434 ("btrfs: reserve delalloc metadata differently") |
| CC: stable@vger.kernel.org # 5.2+ |
| Signed-off-by: Filipe Manana <fdmanana@suse.com> |
| Reviewed-by: David Sterba <dsterba@suse.com> |
| Signed-off-by: David Sterba <dsterba@suse.com> |
| [PG: adapt for different file name in older code base.] |
| Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> |
| |
| diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c |
| index 6c1b7ec3b9ff..75e2f5d1e31d 100644 |
| --- a/fs/btrfs/extent-tree.c |
| +++ b/fs/btrfs/extent-tree.c |
| @@ -6111,7 +6111,6 @@ int btrfs_delalloc_reserve_metadata(struct btrfs_inode *inode, u64 num_bytes) |
| out_qgroup: |
| btrfs_qgroup_free_meta_prealloc(root, qgroup_reserve); |
| out_fail: |
| - btrfs_inode_rsv_release(inode, true); |
| if (delalloc_lock) |
| mutex_unlock(&inode->delalloc_mutex); |
| return ret; |
| -- |
| 2.7.4 |
| |