diff options
author | Kent Overstreet <kent.overstreet@gmail.com> | 2022-02-28 19:29:19 -0500 |
---|---|---|
committer | Kent Overstreet <kent.overstreet@linux.dev> | 2023-10-22 17:09:26 -0400 |
commit | 24a3d53b28398d2edd4dc717bede21eaf4a3b874 (patch) | |
tree | 9ba1e8bf729fb88bd3c4027f370422c8eb5b6f97 /fs | |
parent | 30ef633a0b46e06860f46bf7df0f5a313e6e1a19 (diff) |
bcachefs: __journal_entry_close() never fails
Previous patch just moved responsibility for incrementing the journal
sequence number and initializing the new journal entry from
__journal_entry_close() to journal_entry_open(); this patch makes the
analagous change for journal reservation state, incrementing the index
into array of journal_bufs at open time.
This means that __journal_entry_close() never fails to close an open
journal entry, which is important for the next patch that will change
our emergency shutdown behaviour.
Signed-off-by: Kent Overstreet <kent.overstreet@gmail.com>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/bcachefs/journal.c | 50 | ||||
-rw-r--r-- | fs/bcachefs/journal.h | 3 | ||||
-rw-r--r-- | fs/bcachefs/journal_io.c | 18 | ||||
-rw-r--r-- | fs/bcachefs/journal_types.h | 1 |
4 files changed, 36 insertions, 36 deletions
diff --git a/fs/bcachefs/journal.c b/fs/bcachefs/journal.c index 3de1a7488d5e..b427e252ec8e 100644 --- a/fs/bcachefs/journal.c +++ b/fs/bcachefs/journal.c @@ -106,7 +106,7 @@ void __bch2_journal_buf_put(struct journal *j) * We don't close a journal_buf until the next journal_buf is finished writing, * and can be opened again - this also initializes the next journal_buf: */ -static bool __journal_entry_close(struct journal *j) +static void __journal_entry_close(struct journal *j) { struct bch_fs *c = container_of(j, struct bch_fs, journal); struct journal_buf *buf = journal_cur_buf(j); @@ -119,21 +119,15 @@ static bool __journal_entry_close(struct journal *j) do { old.v = new.v = v; if (old.cur_entry_offset == JOURNAL_ENTRY_CLOSED_VAL) - return true; + return; if (old.cur_entry_offset == JOURNAL_ENTRY_ERROR_VAL) { /* this entry will never be written: */ closure_wake_up(&buf->wait); - return true; + return; } new.cur_entry_offset = JOURNAL_ENTRY_CLOSED_VAL; - new.idx++; - - if (new.idx == new.unwritten_idx) - return false; - - BUG_ON(journal_state_count(new, new.idx)); } while ((v = atomic64_cmpxchg(&j->reservations.counter, old.v, new.v)) != old.v); @@ -175,17 +169,17 @@ static bool __journal_entry_close(struct journal *j) bch2_journal_space_available(j); bch2_journal_buf_put(j, old.idx); - return true; } static bool journal_entry_want_write(struct journal *j) { bool ret = !journal_entry_is_open(j) || - (journal_cur_seq(j) == journal_last_unwritten_seq(j) && - __journal_entry_close(j)); + journal_cur_seq(j) == journal_last_unwritten_seq(j); /* Don't close it yet if we already have a write in flight: */ - if (!ret && nr_unwritten_journal_entries(j)) { + if (ret) + __journal_entry_close(j); + else if (nr_unwritten_journal_entries(j)) { struct journal_buf *buf = journal_cur_buf(j); if (!buf->flush_time) { @@ -221,15 +215,15 @@ static bool journal_entry_close(struct journal *j) static int journal_entry_open(struct journal *j) { struct bch_fs *c = container_of(j, struct bch_fs, journal); - struct journal_buf *buf = journal_cur_buf(j); + struct journal_buf *buf = j->buf + + ((journal_cur_seq(j) + 1) & JOURNAL_BUF_MASK); union journal_res_state old, new; int u64s; u64 v; - BUG_ON(BCH_SB_CLEAN(c->disk_sb.sb)); - lockdep_assert_held(&j->lock); BUG_ON(journal_entry_is_open(j)); + BUG_ON(BCH_SB_CLEAN(c->disk_sb.sb)); if (j->blocked) return cur_entry_blocked; @@ -243,6 +237,9 @@ static int journal_entry_open(struct journal *j) if (!fifo_free(&j->pin)) return cur_entry_journal_pin_full; + if (nr_unwritten_journal_entries(j) == ARRAY_SIZE(j->buf)) + return cur_entry_max_in_flight; + BUG_ON(!j->cur_entry_sectors); buf->expires = @@ -291,7 +288,10 @@ static int journal_entry_open(struct journal *j) old.v = new.v = v; BUG_ON(old.cur_entry_offset == JOURNAL_ENTRY_ERROR_VAL); + + new.idx++; BUG_ON(journal_state_count(new, new.idx)); + BUG_ON(new.idx != (journal_cur_seq(j) & JOURNAL_BUF_MASK)); journal_state_inc(&new); new.cur_entry_offset = 0; @@ -390,18 +390,11 @@ retry: buf->buf_size < JOURNAL_ENTRY_SIZE_MAX) j->buf_size_want = max(j->buf_size_want, buf->buf_size << 1); - if (journal_entry_is_open(j) && - !__journal_entry_close(j)) { - /* - * We failed to get a reservation on the current open journal - * entry because it's full, and we can't close it because - * there's still a previous one in flight: - */ + __journal_entry_close(j); + ret = journal_entry_open(j); + + if (ret == cur_entry_max_in_flight) trace_journal_entry_full(c); - ret = cur_entry_blocked; - } else { - ret = journal_entry_open(j); - } unlock: if ((ret && ret != cur_entry_insufficient_devices) && !j->res_get_blocked_start) { @@ -1051,7 +1044,8 @@ int bch2_fs_journal_start(struct journal *j, u64 cur_seq, set_bit(JOURNAL_STARTED, &j->flags); j->last_flush_write = jiffies; - j->reservations.idx = j->reservations.unwritten_idx = journal_cur_seq(j) + 1; + j->reservations.idx = j->reservations.unwritten_idx = journal_cur_seq(j); + j->reservations.unwritten_idx++; c->last_bucket_seq_cleanup = journal_cur_seq(j); diff --git a/fs/bcachefs/journal.h b/fs/bcachefs/journal.h index 409d32b784d2..948e8b53dffd 100644 --- a/fs/bcachefs/journal.h +++ b/fs/bcachefs/journal.h @@ -264,9 +264,6 @@ static inline void bch2_journal_buf_put(struct journal *j, unsigned idx) .buf3_count = idx == 3, }).v, &j->reservations.counter); - EBUG_ON(((s.idx - idx) & 3) > - ((s.idx - s.unwritten_idx) & 3)); - if (!journal_state_count(s, idx) && idx == s.unwritten_idx) __bch2_journal_buf_put(j); } diff --git a/fs/bcachefs/journal_io.c b/fs/bcachefs/journal_io.c index 7c8298ddad25..90743fa13ff4 100644 --- a/fs/bcachefs/journal_io.c +++ b/fs/bcachefs/journal_io.c @@ -1392,7 +1392,7 @@ static void journal_write_done(struct closure *cl) v = atomic64_read(&j->reservations.counter); do { old.v = new.v = v; - BUG_ON(new.idx == new.unwritten_idx); + BUG_ON(journal_state_count(new, new.unwritten_idx)); new.unwritten_idx++; } while ((v = atomic64_cmpxchg(&j->reservations.counter, @@ -1403,14 +1403,22 @@ static void journal_write_done(struct closure *cl) closure_wake_up(&w->wait); journal_wake(j); - if (journal_last_unwritten_seq(j) == journal_cur_seq(j)) { + if (!journal_state_count(new, new.unwritten_idx) && + journal_last_unwritten_seq(j) <= journal_cur_seq(j)) { + closure_call(&j->io, bch2_journal_write, c->io_complete_wq, NULL); + } else if (journal_last_unwritten_seq(j) == journal_cur_seq(j) && + new.cur_entry_offset < JOURNAL_ENTRY_CLOSED_VAL) { struct journal_buf *buf = journal_cur_buf(j); long delta = buf->expires - jiffies; + /* + * We don't close a journal entry to write it while there's + * previous entries still in flight - the current journal entry + * might want to be written now: + */ + mod_delayed_work(c->io_complete_wq, &j->write_work, max(0L, delta)); - } else if (journal_last_unwritten_seq(j) < journal_cur_seq(j) && - !journal_state_count(new, new.unwritten_idx)) - closure_call(&j->io, bch2_journal_write, c->io_complete_wq, NULL); + } spin_unlock(&j->lock); } diff --git a/fs/bcachefs/journal_types.h b/fs/bcachefs/journal_types.h index 3d9810e48e9d..330c5d79e645 100644 --- a/fs/bcachefs/journal_types.h +++ b/fs/bcachefs/journal_types.h @@ -176,6 +176,7 @@ struct journal { enum { cur_entry_ok, cur_entry_blocked, + cur_entry_max_in_flight, cur_entry_journal_full, cur_entry_journal_pin_full, cur_entry_journal_stuck, |