bcachefs: Ensure we don't use a blacklisted journal seq
authorKent Overstreet <kent.overstreet@linux.dev>
Fri, 23 May 2025 18:03:06 +0000 (14:03 -0400)
committerKent Overstreet <kent.overstreet@linux.dev>
Fri, 23 May 2025 23:52:31 +0000 (19:52 -0400)
Different versions differ on the size of the blacklist range; it is
theoretically possible that we could end up with blacklisted journal
sequence numbers newer than the newest seq we find in the journal, and
pick a new start seq that's blacklisted.

Explicitly check for this in bch2_fs_journal_start().

Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
fs/bcachefs/journal.c
fs/bcachefs/journal_seq_blacklist.c
fs/bcachefs/journal_seq_blacklist.h

index f2963a6cca8876e2fbdcf216cca99c6e74cac0a7..09b70fd140a104eb46fc47131da43fa88c664eef 100644 (file)
@@ -415,7 +415,7 @@ static int journal_entry_open(struct journal *j)
        if (atomic64_read(&j->seq) - j->seq_write_started == JOURNAL_STATE_BUF_NR)
                return -BCH_ERR_journal_max_open;
 
-       if (journal_cur_seq(j) >= JOURNAL_SEQ_MAX) {
+       if (unlikely(journal_cur_seq(j) >= JOURNAL_SEQ_MAX)) {
                bch_err(c, "cannot start: journal seq overflow");
                if (bch2_fs_emergency_read_only_locked(c))
                        bch_err(c, "fatal error - emergency read only");
@@ -459,6 +459,14 @@ static int journal_entry_open(struct journal *j)
        atomic64_inc(&j->seq);
        journal_pin_list_init(fifo_push_ref(&j->pin), 1);
 
+       if (unlikely(bch2_journal_seq_is_blacklisted(c, journal_cur_seq(j), false))) {
+               bch_err(c, "attempting to open blacklisted journal seq %llu",
+                       journal_cur_seq(j));
+               if (bch2_fs_emergency_read_only_locked(c))
+                       bch_err(c, "fatal error - emergency read only");
+               return -BCH_ERR_journal_shutdown;
+       }
+
        BUG_ON(j->pin.back - 1 != atomic64_read(&j->seq));
 
        BUG_ON(j->buf + (journal_cur_seq(j) & JOURNAL_BUF_MASK) != buf);
@@ -1415,6 +1423,13 @@ int bch2_fs_journal_start(struct journal *j, u64 cur_seq)
        bool had_entries = false;
        u64 last_seq = cur_seq, nr, seq;
 
+       /*
+        *
+        * XXX pick most recent non blacklisted sequence number
+        */
+
+       cur_seq = max(cur_seq, bch2_journal_last_blacklisted_seq(c));
+
        if (cur_seq >= JOURNAL_SEQ_MAX) {
                bch_err(c, "cannot start: journal seq overflow");
                return -EINVAL;
index e463d2d95359589a5a97f01723e9630c0900bdc6..c5a7d800a0f54ef3626707c386a35a5ecc077f72 100644 (file)
@@ -130,6 +130,16 @@ bool bch2_journal_seq_is_blacklisted(struct bch_fs *c, u64 seq,
        return true;
 }
 
+u64 bch2_journal_last_blacklisted_seq(struct bch_fs *c)
+{
+       struct journal_seq_blacklist_table *t = c->journal_seq_blacklist_table;
+
+       if (!t || !t->nr)
+               return 0;
+
+       return t->entries[eytzinger0_last(t->nr)].end - 1;
+}
+
 int bch2_blacklist_table_initialize(struct bch_fs *c)
 {
        struct bch_sb_field_journal_seq_blacklist *bl =
index d47636f96fdc61f74b6aba5e7116e61c524c953f..f06942ccfcddaa8488d444163613070542954e1d 100644 (file)
@@ -12,6 +12,7 @@ blacklist_nr_entries(struct bch_sb_field_journal_seq_blacklist *bl)
 }
 
 bool bch2_journal_seq_is_blacklisted(struct bch_fs *, u64, bool);
+u64 bch2_journal_last_blacklisted_seq(struct bch_fs *);
 int bch2_journal_seq_blacklist_add(struct bch_fs *c, u64, u64);
 int bch2_blacklist_table_initialize(struct bch_fs *);