summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFilipe Manana <fdmanana@suse.com>2026-06-12 12:02:14 +0100
committerDavid Sterba <dsterba@suse.com>2026-08-07 19:16:27 +0200
commit6f1c97695a6e230ee15c9e052e1933bdccfd5fa3 (patch)
treeaf4469f3cb84babb4ad814c9429bad2dde33caa7
parent15f7c86215e8d5f14b24127fa88af6c79363d50e (diff)
downloadlinux-6f1c97695a6e230ee15c9e052e1933bdccfd5fa3.tar.gz
linux-6f1c97695a6e230ee15c9e052e1933bdccfd5fa3.zip
btrfs: fix memory barrier order in reloc_root_is_dead()
When we set a root's reloc_root to NULL, we do it like this: static void clear_reloc_root(struct btrfs_root *root) { root->reloc_root = NULL; /* * Need barrier to ensure clear_bit() only happens after * root->reloc_root = NULL. Pairs with have_reloc_root(). */ smp_wmb(); clear_bit(BTRFS_ROOT_DEAD_RELOC_TREE, &root->state); } So that a NULL reloc_root is always seen before seeing that the bit BTRFS_ROOT_DEAD_RELOC_TREE was cleared. But on the read side we have: static bool reloc_root_is_dead(const struct btrfs_root *root) { smp_rmb(); if (test_bit(BTRFS_ROOT_DEAD_RELOC_TREE, &root->state)) return true; return false; } And then callers of reloc_root_is_dead() access root->reloc_root. Because the read memory barrier is placed before testing the bit, the CPU is completely free to speculatively reorder those two loads. It can read root->reloc_root before it actually checks the dead tree bit. Sashiko reported this as an existing problem in another patch review, see the link in the Link tag below. Fix this by moving the read memory barrier to happen after testing the bit and update the comment to reflect current reality. Link: https://sashiko.dev/#/patchset/cf84f1a217c719e25b6b69e4298dd7afd36c9427.1781194426.git.fdmanana%40suse.com Reviewed-by: Boris Burkov <boris@bur.io> Signed-off-by: Filipe Manana <fdmanana@suse.com> Signed-off-by: David Sterba <dsterba@suse.com>
-rw-r--r--fs/btrfs/relocation.c11
1 files changed, 6 insertions, 5 deletions
diff --git a/fs/btrfs/relocation.c b/fs/btrfs/relocation.c
index fc5c14b5adad..4f83415ee8f8 100644
--- a/fs/btrfs/relocation.c
+++ b/fs/btrfs/relocation.c
@@ -339,14 +339,15 @@ static struct btrfs_backref_node *walk_down_backref(
static bool reloc_root_is_dead(const struct btrfs_root *root)
{
+ if (test_bit(BTRFS_ROOT_DEAD_RELOC_TREE, &root->state))
+ return true;
/*
- * Pair with set_bit/clear_bit in clean_dirty_subvols and
- * btrfs_update_reloc_root. We need to see the updated bit before
- * trying to access reloc_root
+ * Pairs with set_bit/clear_bit in clear_reloc_root() and
+ * btrfs_update_reloc_root(). We need to see the updated bit before
+ * trying to access root->reloc_root in our callers.
*/
smp_rmb();
- if (test_bit(BTRFS_ROOT_DEAD_RELOC_TREE, &root->state))
- return true;
+
return false;
}