bcachefs; Don't use btree write buffer until journal replay is finished
authorKent Overstreet <kent.overstreet@linux.dev>
Sat, 2 Dec 2023 03:31:23 +0000 (22:31 -0500)
committerKent Overstreet <kent.overstreet@linux.dev>
Mon, 4 Dec 2023 20:46:31 +0000 (15:46 -0500)
The keys being replayed by journal replay have to be synchronized with
updates by other threads that overwrite them. We rely on btree node
locks for synchronizing - but since btree write buffer updates take no
btree locks, that won't work.

Instead, simply disable using the btree write buffer until journal
replay is finished.

This fixes a rare backpointers error in the merge_torture_flakey test.

Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
fs/bcachefs/btree_update.c

index 324767c0ddccd7457004a34e8ed6e49da8c54b85..25fdca00bf7bdeed69f9e114332746ccb1de0d23 100644 (file)
@@ -554,6 +554,19 @@ int __must_check bch2_trans_update_seq(struct btree_trans *trans, u64 seq,
                                                 BTREE_UPDATE_PREJOURNAL);
 }
 
+static noinline int bch2_btree_insert_clone_trans(struct btree_trans *trans,
+                                                 enum btree_id btree,
+                                                 struct bkey_i *k)
+{
+       struct bkey_i *n = bch2_trans_kmalloc(trans, bkey_bytes(&k->k));
+       int ret = PTR_ERR_OR_ZERO(n);
+       if (ret)
+               return ret;
+
+       bkey_copy(n, k);
+       return bch2_btree_insert_trans(trans, btree, n, 0);
+}
+
 int __must_check bch2_trans_update_buffered(struct btree_trans *trans,
                                            enum btree_id btree,
                                            struct bkey_i *k)
@@ -564,6 +577,9 @@ int __must_check bch2_trans_update_buffered(struct btree_trans *trans,
        EBUG_ON(trans->nr_wb_updates > trans->wb_updates_size);
        EBUG_ON(k->k.u64s > BTREE_WRITE_BUFERED_U64s_MAX);
 
+       if (unlikely(trans->journal_replay_not_finished))
+               return bch2_btree_insert_clone_trans(trans, btree, k);
+
        trans_for_each_wb_update(trans, i) {
                if (i->btree == btree && bpos_eq(i->k.k.p, k->k.p)) {
                        bkey_copy(&i->k, k);