summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSlava Pestov <sp@daterainc.com>2015-01-31 17:06:45 -0800
committerKent Overstreet <kmo@daterainc.com>2015-02-12 23:43:34 -0800
commit77f78518c17583dee6d5dc41b30531d103c037d1 (patch)
tree6751ecf3934a4d5b04984a5138e3d280d5b24682
parent8532765526ca17b856051a4c8e5a6fab87e8b50f (diff)
bcache: fix faulty logic in bch_journal_res_get()
If current journal entry was completely full, we should try to write it before doing a journal reclaim. Otherwise we might do a reclaim for nothing and just sit there waiting 10ms for the timer to write the entry. This fixes a very old regression from "journal reservations". Change-Id: Ia083999130dcd6180b074efd0ba7a7fdc98d8c3a
-rw-r--r--drivers/md/bcache/journal.c71
1 files changed, 39 insertions, 32 deletions
diff --git a/drivers/md/bcache/journal.c b/drivers/md/bcache/journal.c
index 2cf768c43d6a..37f9861b986f 100644
--- a/drivers/md/bcache/journal.c
+++ b/drivers/md/bcache/journal.c
@@ -1137,6 +1137,7 @@ static bool __journal_res_get(struct cache_set *c, struct journal_res *res,
spin_lock(&c->journal.lock);
while (1) {
+ /* Check if there is still room in the current journal entry */
if (nkeys_min < c->journal.u64s_remaining) {
res->nkeys = min_t(unsigned, nkeys_max,
c->journal.u64s_remaining - 1);
@@ -1157,49 +1158,55 @@ static bool __journal_res_get(struct cache_set *c, struct journal_res *res,
if (*start_time == 0)
*start_time = local_clock();
- if (!c->journal.u64s_remaining) {
- oldest_seq = 0;
- write_oldest = journal_reclaim(c, &oldest_seq);
-
- /* Waiting for discards, or active cache devices gone */
- if (!write_oldest && !c->journal.u64s_remaining) {
- spin_unlock(&c->journal.lock);
- trace_bcache_journal_discard_wait(c);
+ /* If the current journal entry is not empty, write it */
+ if (c->journal.cur->data->u64s) {
+ /*
+ * If the previous journal entry is still being written, we
+ * have to wait
+ */
+ if (!journal_try_write(c)) {
+ trace_bcache_journal_entry_full(c);
return false;
}
- if (write_oldest) {
- BUG_ON(c->journal.u64s_remaining);
- BUG_ON(oldest_seq == 0);
- oldest_seq -= last_seq(&c->journal);
- spin_unlock(&c->journal.lock);
- /*
- * If we didn't write any nodes, wake us up
- * again so we don't wait forever
- */
- bch_btree_write_oldest(c, oldest_seq);
- return false;
- }
- } else {
+ spin_lock(&c->journal.lock);
+ continue;
+ }
+
+ if (c->journal.u64s_remaining) {
/*
* Not much room for this journal entry (near the end of
* a journal bucket) but there's nothing in this journal
* entry yet - skip it and allocate a new journal entry
*/
- if (!c->journal.cur->data->u64s) {
- BUG_ON(test_bit(JOURNAL_DIRTY, &c->journal.flags)
- && !test_bit(JOURNAL_NEED_WRITE, &c->journal.flags));
+ BUG_ON(test_bit(JOURNAL_DIRTY, &c->journal.flags)
+ && !test_bit(JOURNAL_NEED_WRITE, &c->journal.flags));
- journal_entry_no_room(c);
- continue;
- }
+ journal_entry_no_room(c);
+ continue;
+ }
- if (!journal_try_write(c)) {
- trace_bcache_journal_entry_full(c);
- return false;
- }
+ oldest_seq = 0;
+ write_oldest = journal_reclaim(c, &oldest_seq);
- spin_lock(&c->journal.lock);
+ /* Waiting for discards, or active cache devices gone */
+ if (!write_oldest && !c->journal.u64s_remaining) {
+ spin_unlock(&c->journal.lock);
+ trace_bcache_journal_discard_wait(c);
+ return false;
+ }
+
+ if (write_oldest) {
+ BUG_ON(c->journal.u64s_remaining);
+ BUG_ON(oldest_seq == 0);
+ oldest_seq -= last_seq(&c->journal);
+ spin_unlock(&c->journal.lock);
+ /*
+ * If we didn't write any nodes, wake us up
+ * again so we don't wait forever
+ */
+ bch_btree_write_oldest(c, oldest_seq);
+ return false;
}
}
}