diff options
author | Kent Overstreet <kent.overstreet@gmail.com> | 2019-02-14 18:38:52 -0500 |
---|---|---|
committer | Kent Overstreet <kent.overstreet@gmail.com> | 2019-04-03 12:44:07 -0400 |
commit | ae6a54ac0981953572b6c942cfe52de5cd5ada49 (patch) | |
tree | 38c4fec0a3da1cc0509c1b3b0cfe30dd52cd7b4c | |
parent | a0a35b65ec7df3a21379014870894b57c258eade (diff) |
bcachefs: Add a mechanism for blocking the journal
-rw-r--r-- | fs/bcachefs/journal.c | 44 | ||||
-rw-r--r-- | fs/bcachefs/journal.h | 3 | ||||
-rw-r--r-- | fs/bcachefs/journal_types.h | 3 |
3 files changed, 47 insertions, 3 deletions
diff --git a/fs/bcachefs/journal.c b/fs/bcachefs/journal.c index 8ff8cfa8bf76..0acfbfe0ef77 100644 --- a/fs/bcachefs/journal.c +++ b/fs/bcachefs/journal.c @@ -212,6 +212,9 @@ static int journal_entry_open(struct journal *j) lockdep_assert_held(&j->lock); BUG_ON(journal_entry_is_open(j)); + if (j->blocked) + return -EAGAIN; + if (!fifo_free(&j->pin)) return 0; @@ -286,7 +289,7 @@ static bool __journal_entry_close(struct journal *j) default: spin_unlock(&j->lock); case JOURNAL_UNLOCKED: - return true; + return false; } } @@ -296,6 +299,22 @@ static bool journal_entry_close(struct journal *j) return __journal_entry_close(j); } +static bool journal_quiesced(struct journal *j) +{ + bool ret; + + spin_lock(&j->lock); + ret = !j->reservations.prev_buf_unwritten && + !journal_entry_is_open(j); + __journal_entry_close(j); + return ret; +} + +static void journal_quiesce(struct journal *j) +{ + wait_event(j->wait, journal_quiesced(j)); +} + static void journal_write_work(struct work_struct *work) { struct journal *j = container_of(work, struct journal, write_work.work); @@ -721,6 +740,26 @@ int bch2_journal_flush(struct journal *j) return bch2_journal_flush_seq(j, seq); } +/* block/unlock the journal: */ + +void bch2_journal_unblock(struct journal *j) +{ + spin_lock(&j->lock); + j->blocked--; + spin_unlock(&j->lock); + + journal_wake(j); +} + +void bch2_journal_block(struct journal *j) +{ + spin_lock(&j->lock); + j->blocked++; + spin_unlock(&j->lock); + + journal_quiesce(j); +} + /* allocate journal on a device: */ static int __bch2_set_nr_journal_buckets(struct bch_dev *ca, unsigned nr, @@ -930,8 +969,7 @@ void bch2_fs_journal_stop(struct journal *j) c->btree_roots_dirty) bch2_journal_meta(j); - BUG_ON(journal_entry_is_open(j) || - j->reservations.prev_buf_unwritten); + journal_quiesce(j); BUG_ON(!bch2_journal_error(j) && test_bit(JOURNAL_NOT_EMPTY, &j->flags)); diff --git a/fs/bcachefs/journal.h b/fs/bcachefs/journal.h index 50d864a3cae3..9c395fd041f0 100644 --- a/fs/bcachefs/journal.h +++ b/fs/bcachefs/journal.h @@ -367,6 +367,9 @@ static inline void bch2_journal_set_replay_done(struct journal *j) set_bit(JOURNAL_REPLAY_DONE, &j->flags); } +void bch2_journal_unblock(struct journal *); +void bch2_journal_block(struct journal *); + ssize_t bch2_journal_print_debug(struct journal *, char *); ssize_t bch2_journal_print_pins(struct journal *, char *); diff --git a/fs/bcachefs/journal_types.h b/fs/bcachefs/journal_types.h index a91662f6a61b..bbf1aa727a30 100644 --- a/fs/bcachefs/journal_types.h +++ b/fs/bcachefs/journal_types.h @@ -141,6 +141,9 @@ struct journal { spinlock_t lock; + /* if nonzero, we may not open a new journal entry: */ + unsigned blocked; + /* Used when waiting because the journal was full */ wait_queue_head_t wait; struct closure_waitlist async_wait; |