diff options
author | Kent Overstreet <kent.overstreet@linux.dev> | 2022-10-24 11:24:22 -0400 |
---|---|---|
committer | Kent Overstreet <kent.overstreet@linux.dev> | 2022-10-25 00:22:24 -0400 |
commit | cf6c9fae912e78f65c564a06613f8601ffbe3596 (patch) | |
tree | fe508463917b2ab93fc2cc5dd3714c2eefe42d24 | |
parent | 18dd24526abd2e14cc4228805520aad41ec339a7 (diff) |
bcachefs: Fix for allocating before backpointers have been checked
Before the backpointers phase of fsck completes - which runs while we're
RW - we could have free buckets (dirty_sectors = 0) with backpointers in
them - invalid backpointers that will be removed later.
We don't want to allocate from these buckets, we'll get "overlapping
backpointer" errors. This patch fixes this issue by explicitly checking
if there's any backpointers in the candidate bucket if backpointers
haven't been checked yet.
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
-rw-r--r-- | fs/bcachefs/alloc_foreground.c | 24 | ||||
-rw-r--r-- | fs/bcachefs/btree_update_interior.c | 3 | ||||
-rw-r--r-- | fs/bcachefs/recovery.c | 3 | ||||
-rw-r--r-- | include/trace/events/bcachefs.h | 12 |
4 files changed, 37 insertions, 5 deletions
diff --git a/fs/bcachefs/alloc_foreground.c b/fs/bcachefs/alloc_foreground.c index a9e0c7397292..58368b04f257 100644 --- a/fs/bcachefs/alloc_foreground.c +++ b/fs/bcachefs/alloc_foreground.c @@ -14,6 +14,7 @@ #include "bcachefs.h" #include "alloc_background.h" #include "alloc_foreground.h" +#include "backpointers.h" #include "btree_iter.h" #include "btree_update.h" #include "btree_gc.h" @@ -333,6 +334,29 @@ static struct open_bucket *try_alloc_bucket(struct btree_trans *trans, struct bc goto err; } + if (!test_bit(BCH_FS_CHECK_BACKPOINTERS_DONE, &c->flags)) { + struct bch_backpointer bp; + u64 bp_offset = 0; + + ret = bch2_get_next_backpointer(trans, POS(ca->dev_idx, b), -1, + &bp_offset, &bp, + BTREE_ITER_NOPRESERVE); + if (ret) { + ob = ERR_PTR(ret); + goto err; + } + + if (bp_offset != U64_MAX) { + /* + * Bucket may have data in it - we don't call + * bc2h_trans_inconnsistent() because fsck hasn't + * finished yet + */ + ob = NULL; + goto err; + } + } + ob = __try_alloc_bucket(c, ca, b, reserve, &a, skipped_open, skipped_need_journal_commit, diff --git a/fs/bcachefs/btree_update_interior.c b/fs/bcachefs/btree_update_interior.c index 5ce91ae6a69e..39298f0246b4 100644 --- a/fs/bcachefs/btree_update_interior.c +++ b/fs/bcachefs/btree_update_interior.c @@ -1178,7 +1178,8 @@ bch2_btree_update_start(struct btree_trans *trans, struct btree_path *path, } if (ret) { - trace_and_count(c, btree_reserve_get_fail, trans->fn, _RET_IP_, nr_nodes[0] + nr_nodes[1]); + trace_and_count(c, btree_reserve_get_fail, trans->fn, + _RET_IP_, nr_nodes[0] + nr_nodes[1], ret); goto err; } diff --git a/fs/bcachefs/recovery.c b/fs/bcachefs/recovery.c index 6968f934594f..2bb078749b9a 100644 --- a/fs/bcachefs/recovery.c +++ b/fs/bcachefs/recovery.c @@ -1486,6 +1486,9 @@ int bch2_fs_initialize(struct bch_fs *c) mutex_unlock(&c->sb_lock); set_bit(BCH_FS_INITIAL_GC_DONE, &c->flags); + set_bit(BCH_FS_CHECK_LRUS_DONE, &c->flags); + set_bit(BCH_FS_CHECK_BACKPOINTERS_DONE, &c->flags); + set_bit(BCH_FS_CHECK_ALLOC_TO_LRU_REFS_DONE, &c->flags); set_bit(BCH_FS_MAY_GO_RW, &c->flags); set_bit(BCH_FS_FSCK_DONE, &c->flags); diff --git a/include/trace/events/bcachefs.h b/include/trace/events/bcachefs.h index 444f43f0474d..6bc361ae7d7a 100644 --- a/include/trace/events/bcachefs.h +++ b/include/trace/events/bcachefs.h @@ -344,25 +344,29 @@ DEFINE_EVENT(btree_node, btree_node_free, TRACE_EVENT(btree_reserve_get_fail, TP_PROTO(const char *trans_fn, unsigned long caller_ip, - size_t required), - TP_ARGS(trans_fn, caller_ip, required), + size_t required, + int ret), + TP_ARGS(trans_fn, caller_ip, required, ret), TP_STRUCT__entry( __array(char, trans_fn, 32 ) __field(unsigned long, caller_ip ) __field(size_t, required ) + __array(char, ret, 32 ) ), TP_fast_assign( strscpy(__entry->trans_fn, trans_fn, sizeof(__entry->trans_fn)); __entry->caller_ip = caller_ip; __entry->required = required; + strscpy(__entry->ret, bch2_err_str(ret), sizeof(__entry->ret)); ), - TP_printk("%s %pS required %zu", + TP_printk("%s %pS required %zu ret %s", __entry->trans_fn, (void *) __entry->caller_ip, - __entry->required) + __entry->required, + __entry->ret) ); DEFINE_EVENT(btree_node, btree_node_compact, |