summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKent Overstreet <kent.overstreet@gmail.com>2019-02-14 18:38:52 -0500
committerKent Overstreet <kent.overstreet@gmail.com>2019-04-03 12:44:07 -0400
commitae6a54ac0981953572b6c942cfe52de5cd5ada49 (patch)
tree38c4fec0a3da1cc0509c1b3b0cfe30dd52cd7b4c
parenta0a35b65ec7df3a21379014870894b57c258eade (diff)
bcachefs: Add a mechanism for blocking the journal
-rw-r--r--fs/bcachefs/journal.c44
-rw-r--r--fs/bcachefs/journal.h3
-rw-r--r--fs/bcachefs/journal_types.h3
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;