linux-bcachefs.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [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).