diff --git a/.bcachefs_revision b/.bcachefs_revision index a0684850..e086bdcf 100644 --- a/.bcachefs_revision +++ b/.bcachefs_revision @@ -1 +1 @@ -9d28e4a535cac3b88104a4525dd39fc16175f38c +42284b8b2bb980c80140b640de7cb12bc1e4541c diff --git a/libbcachefs/bcachefs.h b/libbcachefs/bcachefs.h index b21151ea..696c7c93 100644 --- a/libbcachefs/bcachefs.h +++ b/libbcachefs/bcachefs.h @@ -561,6 +561,7 @@ struct journal_keys { enum btree_id btree_id:8; unsigned level:8; bool allocated; + bool overwritten; struct bkey_i *k; u32 journal_seq; u32 journal_offset; diff --git a/libbcachefs/btree_update_leaf.c b/libbcachefs/btree_update_leaf.c index 05e11983..09dc585b 100644 --- a/libbcachefs/btree_update_leaf.c +++ b/libbcachefs/btree_update_leaf.c @@ -15,6 +15,7 @@ #include "journal.h" #include "journal_reclaim.h" #include "keylist.h" +#include "recovery.h" #include "subvolume.h" #include "replicas.h" @@ -624,6 +625,14 @@ fail: return btree_trans_restart(trans); } +static noinline void bch2_drop_overwrites_from_journal(struct btree_trans *trans) +{ + struct btree_insert_entry *i; + + trans_for_each_update(trans, i) + bch2_journal_key_overwritten(trans->c, i->btree_id, i->level, i->k->k.p); +} + /* * Get journal reservation, take write locks, and attempt to do btree update(s): */ @@ -701,6 +710,9 @@ static inline int do_bch2_trans_commit(struct btree_trans *trans, ret = bch2_trans_commit_write_locked(trans, stopped_at, trace_ip); + if (!ret && unlikely(!test_bit(JOURNAL_REPLAY_DONE, &c->journal.flags))) + bch2_drop_overwrites_from_journal(trans); + trans_for_each_update(trans, i) if (!same_leaf_as_prev(trans, i)) bch2_btree_node_unlock_write_inlined(trans, i->path, diff --git a/libbcachefs/buckets.c b/libbcachefs/buckets.c index 94aa81e7..78d43997 100644 --- a/libbcachefs/buckets.c +++ b/libbcachefs/buckets.c @@ -531,20 +531,6 @@ void bch2_mark_alloc_bucket(struct bch_fs *c, struct bch_dev *ca, BUG_ON(owned_by_allocator == old.owned_by_allocator); } -static inline u8 bkey_alloc_gen(struct bkey_s_c k) -{ - switch (k.k->type) { - case KEY_TYPE_alloc: - return bkey_s_c_to_alloc(k).v->gen; - case KEY_TYPE_alloc_v2: - return bkey_s_c_to_alloc_v2(k).v->gen; - case KEY_TYPE_alloc_v3: - return bkey_s_c_to_alloc_v3(k).v->gen; - default: - return 0; - } -} - static int bch2_mark_alloc(struct btree_trans *trans, struct bkey_s_c old, struct bkey_s_c new, unsigned flags) @@ -589,7 +575,7 @@ static int bch2_mark_alloc(struct btree_trans *trans, return 0; percpu_down_read(&c->mark_lock); - if (!gc && new_u.gen != bkey_alloc_gen(old)) + if (!gc && new_u.gen != old_u.gen) *bucket_gen(ca, new.k->p.offset) = new_u.gen; g = __bucket(ca, new.k->p.offset, gc); diff --git a/libbcachefs/journal_io.c b/libbcachefs/journal_io.c index 0d5bdbaa..faf82bb4 100644 --- a/libbcachefs/journal_io.c +++ b/libbcachefs/journal_io.c @@ -558,20 +558,20 @@ static void journal_entry_dev_usage_to_text(struct printbuf *out, struct bch_fs container_of(entry, struct jset_entry_dev_usage, entry); unsigned i, nr_types = jset_entry_dev_usage_nr_types(u); - pr_buf(out, "dev=%u ", le32_to_cpu(u->dev)); + pr_buf(out, "dev=%u", le32_to_cpu(u->dev)); for (i = 0; i < nr_types; i++) { if (i < BCH_DATA_NR) - pr_buf(out, "%s", bch2_data_types[i]); + pr_buf(out, " %s", bch2_data_types[i]); else - pr_buf(out, "(unknown data type %u)", i); + pr_buf(out, " (unknown data type %u)", i); pr_buf(out, ": buckets=%llu sectors=%llu fragmented=%llu", le64_to_cpu(u->d[i].buckets), le64_to_cpu(u->d[i].sectors), le64_to_cpu(u->d[i].fragmented)); } - pr_buf(out, "buckets_ec: %llu buckets_unavailable: %llu", + pr_buf(out, " buckets_ec: %llu buckets_unavailable: %llu", le64_to_cpu(u->buckets_ec), le64_to_cpu(u->buckets_unavailable)); } diff --git a/libbcachefs/recovery.c b/libbcachefs/recovery.c index d332fd16..40e1e991 100644 --- a/libbcachefs/recovery.c +++ b/libbcachefs/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 @@ -533,6 +546,10 @@ static int __bch2_journal_replay_key(struct btree_trans *trans, BTREE_ITER_NOT_EXTENTS; int ret; + /* Must be checked with btree locked: */ + if (k->overwritten) + return 0; + if (!k->level && k->btree_id == BTREE_ID_alloc) iter_flags |= BTREE_ITER_CACHED|BTREE_ITER_CACHED_NOFILL; diff --git a/libbcachefs/recovery.h b/libbcachefs/recovery.h index 1504e0bd..a7a9496a 100644 --- a/libbcachefs/recovery.h +++ b/libbcachefs/recovery.h @@ -37,6 +37,8 @@ int bch2_journal_key_insert(struct bch_fs *, enum btree_id, unsigned, struct bkey_i *); int bch2_journal_key_delete(struct bch_fs *, enum btree_id, unsigned, struct bpos); +void bch2_journal_key_overwritten(struct bch_fs *, enum btree_id, + unsigned, struct bpos); void bch2_btree_and_journal_iter_advance(struct btree_and_journal_iter *); struct bkey_s_c bch2_btree_and_journal_iter_peek(struct btree_and_journal_iter *);