summaryrefslogtreecommitdiff
path: root/fs/bcachefs/recovery.c
diff options
context:
space:
mode:
authorKent Overstreet <kent.overstreet@gmail.com>2021-12-31 17:54:13 -0500
committerKent Overstreet <kent.overstreet@linux.dev>2023-10-22 17:09:21 -0400
commitdfd41fb9f24699393a042f9c34bd46496da1174d (patch)
treec92bb60a1514fcec6067b65ed9ac0450c3ac4c96 /fs/bcachefs/recovery.c
parent528b18e6d1c67ccf4ab01cdee94299f3ac61e1ec (diff)
downloadlwn-dfd41fb9f24699393a042f9c34bd46496da1174d.tar.gz
lwn-dfd41fb9f24699393a042f9c34bd46496da1174d.zip
bcachefs: Fix race between btree updates & journal replay
Add a flag to indicate whether a journal replay key has been overwritten, and set/test it with appropriate btree locks held. This fixes a race between the allocator - invalidating buckets, and doing btree updates - and journal replay, which before this patch could clobber the allocator thread's update with an older version of the key from the journal. Signed-off-by: Kent Overstreet <kent.overstreet@gmail.com>
Diffstat (limited to 'fs/bcachefs/recovery.c')
-rw-r--r--fs/bcachefs/recovery.c25
1 files changed, 23 insertions, 2 deletions
diff --git a/fs/bcachefs/recovery.c b/fs/bcachefs/recovery.c
index d332fd16517b..fcacf166f900 100644
--- a/fs/bcachefs/recovery.c
+++ b/fs/bcachefs/recovery.c
@@ -185,6 +185,19 @@ int bch2_journal_key_delete(struct bch_fs *c, enum btree_id id,
return bch2_journal_key_insert(c, id, level, &whiteout);
}
+void bch2_journal_key_overwritten(struct bch_fs *c, enum btree_id btree,
+ unsigned level, struct bpos pos)
+{
+ struct journal_keys *keys = &c->journal_keys;
+ size_t idx = journal_key_search(keys, btree, level, pos);
+
+ if (idx < keys->nr &&
+ keys->d[idx].btree_id == btree &&
+ keys->d[idx].level == level &&
+ !bpos_cmp(keys->d[idx].k->k.p, pos))
+ keys->d[idx].overwritten = true;
+}
+
static struct bkey_i *bch2_journal_iter_peek(struct journal_iter *iter)
{
struct journal_key *k = iter->idx - iter->keys->nr
@@ -539,8 +552,16 @@ static int __bch2_journal_replay_key(struct btree_trans *trans,
bch2_trans_node_iter_init(trans, &iter, k->btree_id, k->k->k.p,
BTREE_MAX_DEPTH, k->level,
iter_flags);
- ret = bch2_btree_iter_traverse(&iter) ?:
- bch2_trans_update(trans, &iter, k->k, BTREE_TRIGGER_NORUN);
+ ret = bch2_btree_iter_traverse(&iter);
+ if (ret)
+ goto out;
+
+ /* Must be checked with btree locked: */
+ if (k->overwritten)
+ goto out;
+
+ ret = bch2_trans_update(trans, &iter, k->k, BTREE_TRIGGER_NORUN);
+out:
bch2_trans_iter_exit(trans, &iter);
return ret;
}