* [PATCH 1/3] bcachefs: opts.journal_rewind_no_extents
@ 2025-06-30 21:31 Kent Overstreet
2025-06-30 21:31 ` [PATCH 2/3] bcachefs: Before removing dangling dirents, check for contents Kent Overstreet
2025-06-30 21:31 ` [PATCH 3/3] bcachefs: check_key_has_inode() reconstructs more aggressively Kent Overstreet
0 siblings, 2 replies; 3+ messages in thread
From: Kent Overstreet @ 2025-06-30 21:31 UTC (permalink / raw)
To: linux-bcachefs; +Cc: Kent Overstreet
Add an option to skip rewinding extents when rewinding the journal.
If the only extents operatinos that have occurred are data move
operations, then this will give a higher probability of successful
recovery - until we implement the "buffer discards by a percentage of
device size" functionality.
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
---
fs/bcachefs/btree_journal_iter.c | 17 ++++++++++++++---
fs/bcachefs/opts.h | 5 +++++
2 files changed, 19 insertions(+), 3 deletions(-)
diff --git a/fs/bcachefs/btree_journal_iter.c b/fs/bcachefs/btree_journal_iter.c
index ea839560a136..341d31b3a1f1 100644
--- a/fs/bcachefs/btree_journal_iter.c
+++ b/fs/bcachefs/btree_journal_iter.c
@@ -717,6 +717,18 @@ static void __journal_keys_sort(struct journal_keys *keys)
keys->nr = dst - keys->data;
}
+static bool should_rewind_entry(struct bch_fs *c, struct jset_entry *entry)
+{
+ if (entry->level)
+ return false;
+ if (btree_id_is_alloc(entry->btree_id))
+ return false;
+ if (c->opts.journal_rewind_no_extents &&
+ entry->btree_id == BTREE_ID_extents)
+ return false;
+ return true;
+}
+
int bch2_journal_keys_sort(struct bch_fs *c)
{
struct genradix_iter iter;
@@ -735,9 +747,8 @@ int bch2_journal_keys_sort(struct bch_fs *c)
cond_resched();
vstruct_for_each(&i->j, entry) {
- bool rewind = !entry->level &&
- !btree_id_is_alloc(entry->btree_id) &&
- le64_to_cpu(i->j.seq) >= rewind_seq;
+ bool rewind = le64_to_cpu(i->j.seq) >= rewind_seq &&
+ should_rewind_entry(c, entry);
if (entry->type != (rewind
? BCH_JSET_ENTRY_overwrite
diff --git a/fs/bcachefs/opts.h b/fs/bcachefs/opts.h
index b0a76bd6d6f5..9301f318c4d4 100644
--- a/fs/bcachefs/opts.h
+++ b/fs/bcachefs/opts.h
@@ -384,6 +384,11 @@ enum fsck_err_opts {
OPT_UINT(0, U64_MAX), \
BCH2_NO_SB_OPT, 0, \
NULL, "Rewind journal") \
+ x(journal_rewind_no_extents, bool, \
+ OPT_FS|OPT_MOUNT, \
+ OPT_BOOL(), \
+ BCH2_NO_SB_OPT, 0, \
+ NULL, "Don't rewind extents when rewinding journal") \
x(recovery_passes, u64, \
OPT_FS|OPT_MOUNT, \
OPT_BITFIELD(bch2_recovery_passes), \
--
2.50.0
^ permalink raw reply related [flat|nested] 3+ messages in thread
* [PATCH 2/3] bcachefs: Before removing dangling dirents, check for contents
2025-06-30 21:31 [PATCH 1/3] bcachefs: opts.journal_rewind_no_extents Kent Overstreet
@ 2025-06-30 21:31 ` Kent Overstreet
2025-06-30 21:31 ` [PATCH 3/3] bcachefs: check_key_has_inode() reconstructs more aggressively Kent Overstreet
1 sibling, 0 replies; 3+ messages in thread
From: Kent Overstreet @ 2025-06-30 21:31 UTC (permalink / raw)
To: linux-bcachefs; +Cc: Kent Overstreet
If we find a dirent pointing to a missing inode, check for
dirents/extents assocatiated with that inode number: if present,
reconstruct the inode insead of deleting the dirent.
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
---
fs/bcachefs/fsck.c | 44 ++++++++++++++++++++++++++++++++++
fs/bcachefs/sb-errors_format.h | 3 ++-
2 files changed, 46 insertions(+), 1 deletion(-)
diff --git a/fs/bcachefs/fsck.c b/fs/bcachefs/fsck.c
index 453a5c3184ea..a94dea16e4cf 100644
--- a/fs/bcachefs/fsck.c
+++ b/fs/bcachefs/fsck.c
@@ -1572,6 +1572,43 @@ static int check_key_has_inode(struct btree_trans *trans,
goto out;
}
+static int maybe_reconstruct_inum_btree(struct btree_trans *trans,
+ u64 inum, u32 snapshot,
+ enum btree_id btree)
+{
+ struct btree_iter iter;
+ struct bkey_s_c k;
+ int ret = 0;
+
+ for_each_btree_key_max_norestart(trans, iter, btree,
+ SPOS(inum, 0, snapshot),
+ POS(inum, U64_MAX),
+ 0, k, ret) {
+ ret = 1;
+ break;
+ }
+ bch2_trans_iter_exit(trans, &iter);
+
+ if (ret <= 0)
+ return ret;
+
+ if (fsck_err(trans, missing_inode_with_contents,
+ "inode %llu:%u missing, but contents found: reconstruct?",
+ inum, snapshot))
+ return reconstruct_inode(trans, btree, snapshot, inum) ?:
+ bch2_trans_commit(trans, NULL, NULL, BCH_TRANS_COMMIT_no_enospc) ?:
+ bch_err_throw(trans->c, transaction_restart_commit);
+fsck_err:
+ return ret;
+}
+
+static int maybe_reconstruct_inum(struct btree_trans *trans,
+ u64 inum, u32 snapshot)
+{
+ return maybe_reconstruct_inum_btree(trans, inum, snapshot, BTREE_ID_extents) ?:
+ maybe_reconstruct_inum_btree(trans, inum, snapshot, BTREE_ID_dirents);
+}
+
static int check_i_sectors_notnested(struct btree_trans *trans, struct inode_walker *w)
{
struct bch_fs *c = trans->c;
@@ -2368,6 +2405,13 @@ static int check_dirent(struct btree_trans *trans, struct btree_iter *iter,
if (ret)
goto err;
+ if (!target->inodes.nr) {
+ ret = maybe_reconstruct_inum(trans, le64_to_cpu(d.v->d_inum),
+ d.k->p.snapshot);
+ if (ret)
+ return ret;
+ }
+
if (fsck_err_on(!target->inodes.nr,
trans, dirent_to_missing_inode,
"dirent points to missing inode:\n%s",
diff --git a/fs/bcachefs/sb-errors_format.h b/fs/bcachefs/sb-errors_format.h
index 3ecac2524118..02605976a114 100644
--- a/fs/bcachefs/sb-errors_format.h
+++ b/fs/bcachefs/sb-errors_format.h
@@ -291,6 +291,7 @@ enum bch_fsck_flags {
x(inode_points_to_missing_dirent, 249, FSCK_AUTOFIX) \
x(inode_points_to_wrong_dirent, 250, FSCK_AUTOFIX) \
x(inode_bi_parent_nonzero, 251, 0) \
+ x(missing_inode_with_contents, 321, FSCK_AUTOFIX) \
x(dirent_to_missing_parent_subvol, 252, 0) \
x(dirent_not_visible_in_parent_subvol, 253, 0) \
x(subvol_fs_path_parent_wrong, 254, 0) \
@@ -332,7 +333,7 @@ enum bch_fsck_flags {
x(dirent_stray_data_after_cf_name, 305, 0) \
x(rebalance_work_incorrectly_set, 309, FSCK_AUTOFIX) \
x(rebalance_work_incorrectly_unset, 310, FSCK_AUTOFIX) \
- x(MAX, 321, 0)
+ x(MAX, 322, 0)
enum bch_sb_error_id {
#define x(t, n, ...) BCH_FSCK_ERR_##t = n,
--
2.50.0
^ permalink raw reply related [flat|nested] 3+ messages in thread
* [PATCH 3/3] bcachefs: check_key_has_inode() reconstructs more aggressively
2025-06-30 21:31 [PATCH 1/3] bcachefs: opts.journal_rewind_no_extents Kent Overstreet
2025-06-30 21:31 ` [PATCH 2/3] bcachefs: Before removing dangling dirents, check for contents Kent Overstreet
@ 2025-06-30 21:31 ` Kent Overstreet
1 sibling, 0 replies; 3+ messages in thread
From: Kent Overstreet @ 2025-06-30 21:31 UTC (permalink / raw)
To: linux-bcachefs; +Cc: Kent Overstreet
For regular files: reconstruct if more than three extents are found
found
For directories: reconstruct if a single dirent is found.
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
---
fs/bcachefs/fsck.c | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/fs/bcachefs/fsck.c b/fs/bcachefs/fsck.c
index a94dea16e4cf..52f4dc7ba477 100644
--- a/fs/bcachefs/fsck.c
+++ b/fs/bcachefs/fsck.c
@@ -1500,6 +1500,10 @@ static int check_key_has_inode(struct btree_trans *trans,
SPOS(k.k->p.inode, 0, k.k->p.snapshot),
POS(k.k->p.inode, U64_MAX),
0, k2, ret) {
+ if (k.k->type == KEY_TYPE_error ||
+ k.k->type == KEY_TYPE_hash_whiteout)
+ continue;
+
nr_keys++;
if (nr_keys <= 10) {
bch2_bkey_val_to_text(&buf, c, k2);
@@ -1512,9 +1516,11 @@ static int check_key_has_inode(struct btree_trans *trans,
if (ret)
goto err;
+ unsigned reconstruct_limit = iter->btree_id == BTREE_ID_extents ? 3 : 0;
+
if (nr_keys > 100)
prt_printf(&buf, "found > %u keys for this missing inode\n", nr_keys);
- else if (nr_keys > 10)
+ else if (nr_keys > reconstruct_limit)
prt_printf(&buf, "found %u keys for this missing inode\n", nr_keys);
if (!have_inode) {
--
2.50.0
^ permalink raw reply related [flat|nested] 3+ messages in thread
end of thread, other threads:[~2025-06-30 21:31 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-06-30 21:31 [PATCH 1/3] bcachefs: opts.journal_rewind_no_extents Kent Overstreet
2025-06-30 21:31 ` [PATCH 2/3] bcachefs: Before removing dangling dirents, check for contents Kent Overstreet
2025-06-30 21:31 ` [PATCH 3/3] bcachefs: check_key_has_inode() reconstructs more aggressively Kent Overstreet
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).