diff options
authorSlava Pestov <>2015-02-08 23:39:33 -0800
committerKent Overstreet <>2015-02-12 23:43:58 -0800
commitbd0bc5d7d87c079dfa6a077fe84e90c547f6ed09 (patch)
parent42d1772174154381496c54aba21485e4a5bb597a (diff)
bcache: fix rare race on first startup of fresh cache set
On the very first startup of a cache set, we would set CACHE_SYNC to false and then initialize the first journal entry by calling bch_journal_next(). If the allocator thread calls bch_journal_meta() in between these two steps, bad things could happen: a) we could dereference a NULL pointer because c->journal.cur wasn't set yet b) if we were in between setting c->journal.cur and pushing the first entry onto c-> journal_reclaim_fast() would hang when trying to pop elements off c-> Change the order of these two steps so that bch_journal_meta() doesn't try to get a journal reservation before bch_journal_next() has been called, and change the FIFO reclaim loop to BUG_ON if the FIFO is empty instead of just looping. Change-Id: I1a13a81ca3779bced6e453158f4793e408ef9d57
2 files changed, 7 insertions, 2 deletions
diff --git a/drivers/md/bcache/journal.c b/drivers/md/bcache/journal.c
index ff903dc15ff6..da79166fe030 100644
--- a/drivers/md/bcache/journal.c
+++ b/drivers/md/bcache/journal.c
@@ -836,7 +836,7 @@ static bool journal_reclaim_fast(struct cache_set *c)
* all btree nodes got written out
while (!atomic_read(&fifo_front(&c->
- fifo_pop(&c->, p);
+ BUG_ON(!fifo_pop(&c->, p));
/* If less than 15% space free, kick off background reclaim */
if (fifo_free(&c-> <= (c-> >> 6))
diff --git a/drivers/md/bcache/super.c b/drivers/md/bcache/super.c
index 6ee7ebc87706..a7dd332b17d8 100644
--- a/drivers/md/bcache/super.c
+++ b/drivers/md/bcache/super.c
@@ -1171,6 +1171,12 @@ const char *bch_run_cache_set(struct cache_set *c)
bch_initial_gc(c, NULL);
+ /*
+ * journal_res_get() will crash if called before this has
+ * set up the FIFO and journal.cur pointer:
+ */
+ bch_journal_next(&c->journal);
for_each_cache(ca, c, i)
if (CACHE_STATE(&ca->mi) == CACHE_ACTIVE &&
(err = __bch_cache_read_write(ca))) {
@@ -1191,7 +1197,6 @@ const char *bch_run_cache_set(struct cache_set *c)
SET_CACHE_SYNC(&c->sb, true);
set_bit(JOURNAL_REPLAY_DONE, &c->journal.flags);
- bch_journal_next(&c->journal);
bch_journal_meta(c, &cl);