diff options
| author | Kent Overstreet <kent.overstreet@linux.dev> | 2024-10-24 22:12:37 -0400 |
|---|---|---|
| committer | Kent Overstreet <kent.overstreet@linux.dev> | 2024-12-21 01:36:18 -0500 |
| commit | 7e5b8e00e2631ee1fa72edeb420e7393ad078ab3 (patch) | |
| tree | 0b33351328ad05ca3531055a7364181fa86e0d28 /fs/bcachefs/btree_journal_iter.c | |
| parent | bcachefs: discard_one_bucket() now uses need_discard_or_freespace_err() (diff) | |
| download | linux-7e5b8e00e2631ee1fa72edeb420e7393ad078ab3.tar.gz linux-7e5b8e00e2631ee1fa72edeb420e7393ad078ab3.zip | |
bcachefs: Implement bch2_btree_iter_prev_min()
A user contributed a filessytem dump, where the dump was actually
corrupted (due to being taken while the filesystem was online), but
which exposed an interesting bug in fsck - reconstruct_inode().
When itearting in BTREE_ITER_filter_snapshots mode, it's required to
give an end position for the iteration and it can't span inode numbers;
continuing into the next inode might mean we start seeing keys from a
different snapshot tree, that the is_ancestor() checks always filter,
thus we're never able to return a key and stop iterating.
Backwards iteration never implemented the end position because nothing
else needed it - except for reconstuct_inode().
Additionally, backwards iteration is now able to overlay keys from the
journal, which will be useful if we ever decide to start doing journal
replay in the background.
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
Diffstat (limited to 'fs/bcachefs/btree_journal_iter.c')
| -rw-r--r-- | fs/bcachefs/btree_journal_iter.c | 46 |
1 files changed, 46 insertions, 0 deletions
diff --git a/fs/bcachefs/btree_journal_iter.c b/fs/bcachefs/btree_journal_iter.c index c9dee4b4627a..c44889ef9817 100644 --- a/fs/bcachefs/btree_journal_iter.c +++ b/fs/bcachefs/btree_journal_iter.c @@ -107,6 +107,52 @@ search: return NULL; } +struct bkey_i *bch2_journal_keys_peek_prev_min(struct bch_fs *c, enum btree_id btree_id, + unsigned level, struct bpos pos, + struct bpos end_pos, size_t *idx) +{ + struct journal_keys *keys = &c->journal_keys; + unsigned iters = 0; + struct journal_key *k; + + BUG_ON(*idx > keys->nr); +search: + if (!*idx) + *idx = __bch2_journal_key_search(keys, btree_id, level, pos); + + while (*idx && + __journal_key_cmp(btree_id, level, end_pos, idx_to_key(keys, *idx - 1)) <= 0) { + (*idx)++; + iters++; + if (iters == 10) { + *idx = 0; + goto search; + } + } + + while ((k = *idx < keys->nr ? idx_to_key(keys, *idx) : NULL)) { + if (__journal_key_cmp(btree_id, level, end_pos, k) > 0) + return NULL; + + if (k->overwritten) { + --(*idx); + continue; + } + + if (__journal_key_cmp(btree_id, level, pos, k) >= 0) + return k->k; + + --(*idx); + iters++; + if (iters == 10) { + *idx = 0; + goto search; + } + } + + return NULL; +} + struct bkey_i *bch2_journal_keys_peek_slot(struct bch_fs *c, enum btree_id btree_id, unsigned level, struct bpos pos) { |
