| From b9203cd86debefd718d325a4b85e0e918e264c90 Mon Sep 17 00:00:00 2001 |
| From: Jeff Mahoney <jeffm@suse.com> |
| Date: Tue, 11 Feb 2020 15:25:37 +0800 |
| Subject: [PATCH] btrfs: destroy qgroup extent records on transaction abort |
| |
| commit 81f7eb00ff5bb8326e82503a32809421d14abb8a upstream. |
| |
| We clean up the delayed references when we abort a transaction but we |
| leave the pending qgroup extent records behind, leaking memory. |
| |
| This patch destroys the extent records when we destroy the delayed refs |
| and makes sure ensure they're gone before releasing the transaction. |
| |
| Fixes: 3368d001ba5d ("btrfs: qgroup: Record possible quota-related extent for qgroup.") |
| CC: stable@vger.kernel.org # 4.4+ |
| Reviewed-by: Josef Bacik <josef@toxicpanda.com> |
| Signed-off-by: Jeff Mahoney <jeffm@suse.com> |
| [ Rebased to latest upstream, remove to_qgroup() helper, use |
| rbtree_postorder_for_each_entry_safe() wrapper ] |
| Signed-off-by: Qu Wenruo <wqu@suse.com> |
| Reviewed-by: David Sterba <dsterba@suse.com> |
| Signed-off-by: David Sterba <dsterba@suse.com> |
| Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> |
| |
| diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c |
| index e1ce2c00a1fe..88e4c579cb4d 100644 |
| --- a/fs/btrfs/disk-io.c |
| +++ b/fs/btrfs/disk-io.c |
| @@ -4280,6 +4280,7 @@ static int btrfs_destroy_delayed_refs(struct btrfs_transaction *trans, |
| cond_resched(); |
| spin_lock(&delayed_refs->lock); |
| } |
| + btrfs_qgroup_destroy_extent_records(trans); |
| |
| spin_unlock(&delayed_refs->lock); |
| |
| diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c |
| index 522fecbc26c8..8c70208aa785 100644 |
| --- a/fs/btrfs/qgroup.c |
| +++ b/fs/btrfs/qgroup.c |
| @@ -4006,3 +4006,16 @@ int btrfs_qgroup_trace_subtree_after_cow(struct btrfs_trans_handle *trans, |
| } |
| return ret; |
| } |
| + |
| +void btrfs_qgroup_destroy_extent_records(struct btrfs_transaction *trans) |
| +{ |
| + struct btrfs_qgroup_extent_record *entry; |
| + struct btrfs_qgroup_extent_record *next; |
| + struct rb_root *root; |
| + |
| + root = &trans->delayed_refs.dirty_extent_root; |
| + rbtree_postorder_for_each_entry_safe(entry, next, root, node) { |
| + ulist_free(entry->old_roots); |
| + kfree(entry); |
| + } |
| +} |
| diff --git a/fs/btrfs/qgroup.h b/fs/btrfs/qgroup.h |
| index 46ba7bd2961c..17e8ac992c50 100644 |
| --- a/fs/btrfs/qgroup.h |
| +++ b/fs/btrfs/qgroup.h |
| @@ -414,5 +414,6 @@ int btrfs_qgroup_add_swapped_blocks(struct btrfs_trans_handle *trans, |
| u64 last_snapshot); |
| int btrfs_qgroup_trace_subtree_after_cow(struct btrfs_trans_handle *trans, |
| struct btrfs_root *root, struct extent_buffer *eb); |
| +void btrfs_qgroup_destroy_extent_records(struct btrfs_transaction *trans); |
| |
| #endif |
| diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c |
| index f48b8e91949f..4e71c51dd650 100644 |
| --- a/fs/btrfs/transaction.c |
| +++ b/fs/btrfs/transaction.c |
| @@ -49,6 +49,8 @@ void btrfs_put_transaction(struct btrfs_transaction *transaction) |
| BUG_ON(!list_empty(&transaction->list)); |
| WARN_ON(!RB_EMPTY_ROOT( |
| &transaction->delayed_refs.href_root.rb_root)); |
| + WARN_ON(!RB_EMPTY_ROOT( |
| + &transaction->delayed_refs.dirty_extent_root)); |
| if (transaction->delayed_refs.pending_csums) |
| btrfs_err(transaction->fs_info, |
| "pending csums is %llu", |
| -- |
| 2.7.4 |
| |