diff options
author | Kent Overstreet <kent.overstreet@linux.dev> | 2024-04-10 18:53:28 +0200 |
---|---|---|
committer | Kent Overstreet <kent.overstreet@linux.dev> | 2024-04-11 04:28:36 +0200 |
commit | beccf29114886f1604e26f739cd108f048878ca8 (patch) | |
tree | c19ba70cae534c4c88cc8c746472a4c00ac138fd /fs/bcachefs | |
parent | bcachefs: btree_node_scan: Respect member.data_allowed (diff) | |
download | linux-beccf29114886f1604e26f739cd108f048878ca8.tar.xz linux-beccf29114886f1604e26f739cd108f048878ca8.zip |
bcachefs: Fix a race in btree_update_nodes_written()
One btree update might have terminated in a node update, and then while
it is in flight another btree update might free that original node.
This race has to be handled in btree_update_nodes_written() - we were
missing a READ_ONCE().
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
Diffstat (limited to 'fs/bcachefs')
-rw-r--r-- | fs/bcachefs/btree_update_interior.c | 10 |
1 files changed, 7 insertions, 3 deletions
diff --git a/fs/bcachefs/btree_update_interior.c b/fs/bcachefs/btree_update_interior.c index a4a63e363047..c4a5e83a56a4 100644 --- a/fs/bcachefs/btree_update_interior.c +++ b/fs/bcachefs/btree_update_interior.c @@ -704,9 +704,13 @@ static void btree_update_nodes_written(struct btree_update *as) bch2_fs_fatal_err_on(ret && !bch2_journal_error(&c->journal), c, "%s", bch2_err_str(ret)); err: - if (as->b) { - - b = as->b; + /* + * We have to be careful because another thread might be getting ready + * to free as->b and calling btree_update_reparent() on us - we'll + * recheck under btree_update_lock below: + */ + b = READ_ONCE(as->b); + if (b) { btree_path_idx_t path_idx = get_unlocked_mut_path(trans, as->btree_id, b->c.level, b->key.k.p); struct btree_path *path = trans->paths + path_idx; |