From dab1e24867f0e694c8ab73c075d10676c2699d85 Mon Sep 17 00:00:00 2001 From: Kent Overstreet Date: Sat, 19 Nov 2022 21:40:35 -0500 Subject: [PATCH] bcachefs: Handle last journal write being torn If the last journal write didn't complete sucessfully due to a torn write, we'll detect it as a checksum error. In that case, we should just pretend that journal entry was never written. Signed-off-by: Kent Overstreet --- fs/bcachefs/journal_io.c | 39 +++++++++++++++++++++++++-------------- 1 file changed, 25 insertions(+), 14 deletions(-) diff --git a/fs/bcachefs/journal_io.c b/fs/bcachefs/journal_io.c index 485fd6f3003bf..d1deb0573ffd2 100644 --- a/fs/bcachefs/journal_io.c +++ b/fs/bcachefs/journal_io.c @@ -1106,7 +1106,7 @@ int bch2_journal_read(struct bch_fs *c, u64 *blacklist_seq, u64 *start_seq) struct bch_dev *ca; unsigned iter; struct printbuf buf = PRINTBUF; - bool degraded = false; + bool degraded = false, last_write_torn = false; u64 seq, last_seq = 0; int ret = 0; @@ -1142,8 +1142,13 @@ int bch2_journal_read(struct bch_fs *c, u64 *blacklist_seq, u64 *start_seq) /* * Find most recent flush entry, and ignore newer non flush entries - * those entries will be blacklisted: + * + * + * XXX check for torn write on last journal entry */ genradix_for_each_reverse(&c->journal_entries, radix_iter, _i) { + int write = READ; + i = *_i; if (!i || i->ignore) @@ -1152,21 +1157,27 @@ int bch2_journal_read(struct bch_fs *c, u64 *blacklist_seq, u64 *start_seq) if (!*start_seq) *blacklist_seq = *start_seq = le64_to_cpu(i->j.seq) + 1; - if (!JSET_NO_FLUSH(&i->j)) { - int write = READ; - if (journal_entry_err_on(le64_to_cpu(i->j.last_seq) > le64_to_cpu(i->j.seq), - c, &i->j, NULL, - "invalid journal entry: last_seq > seq (%llu > %llu)", - le64_to_cpu(i->j.last_seq), - le64_to_cpu(i->j.seq))) - i->j.last_seq = i->j.seq; - - last_seq = le64_to_cpu(i->j.last_seq); - *blacklist_seq = le64_to_cpu(i->j.seq) + 1; - break; + if (JSET_NO_FLUSH(&i->j)) { + journal_replay_free(c, i); + continue; } - journal_replay_free(c, i); + if (!last_write_torn && !i->csum_good) { + last_write_torn = true; + journal_replay_free(c, i); + continue; + } + + if (journal_entry_err_on(le64_to_cpu(i->j.last_seq) > le64_to_cpu(i->j.seq), + c, &i->j, NULL, + "invalid journal entry: last_seq > seq (%llu > %llu)", + le64_to_cpu(i->j.last_seq), + le64_to_cpu(i->j.seq))) + i->j.last_seq = i->j.seq; + + last_seq = le64_to_cpu(i->j.last_seq); + *blacklist_seq = le64_to_cpu(i->j.seq) + 1; + break; } if (!*start_seq) { -- 2.30.2