From 0388b5bd3a6eb8bcb20208c3b6dbee96fd30bbe0 Mon Sep 17 00:00:00 2001 From: Filipe Manana Date: Thu, 1 Oct 2026 17:21:22 +0100 Subject: [PATCH] btrfs: qgroup: fix swapped blocks existence check when tracing after COW In btrfs_qgroup_trace_subtree_after_cow(), after we erase the swapped block, iterate over all possible tree levels to check if we sill have other swapped blocks. However the check is wrong, it considers that there are other swapped blocks if any rbtree for any level is empty, instead of not empty. As a consequence we set blocks->swapped to true basically every time since we always find an empty rbtree at least at level 7, since in practice it's nearly impossible to find such a huge btree. This makes every future call to btrfs_qgroup_trace_subtree_after_cow() do an unnecessary rbtree search instead of returning immediately. Fix this by updating the condition to set swapped to true if we find an rbtree that is not empty. Fixes: f616f5cd9da7 ("btrfs: qgroup: Use delayed subtree rescan for balance") Reviewed-by: Qu Wenruo Signed-off-by: Filipe Manana Signed-off-by: David Sterba --- fs/btrfs/ctree.h | 2 +- fs/btrfs/qgroup.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 22ba2b4505b3..00d4c4184e76 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -160,7 +160,7 @@ enum { */ struct btrfs_qgroup_swapped_blocks { spinlock_t lock; - /* RM_EMPTY_ROOT() of above blocks[] */ + /* True if any of the rbtrees in the blocks array below is not empty. */ bool swapped; struct rb_root blocks[BTRFS_MAX_LEVEL]; }; diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c index 46de0a5e80d5..798f21608de5 100644 --- a/fs/btrfs/qgroup.c +++ b/fs/btrfs/qgroup.c @@ -4913,7 +4913,7 @@ int btrfs_qgroup_trace_subtree_after_cow(struct btrfs_trans_handle *trans, /* Found one, remove it from @blocks first and update blocks->swapped */ rb_erase(&block->node, &blocks->blocks[level]); for (i = 0; i < BTRFS_MAX_LEVEL; i++) { - if (RB_EMPTY_ROOT(&blocks->blocks[i])) { + if (!RB_EMPTY_ROOT(&blocks->blocks[i])) { swapped = true; break; }