summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/md/bcache/btree_update.c16
1 files changed, 15 insertions, 1 deletions
diff --git a/drivers/md/bcache/btree_update.c b/drivers/md/bcache/btree_update.c
index a8df0fab3e5f..ae3f97bc3fa0 100644
--- a/drivers/md/bcache/btree_update.c
+++ b/drivers/md/bcache/btree_update.c
@@ -695,7 +695,21 @@ static void btree_node_flush(struct journal *j, struct journal_entry_pin *pin)
struct btree *b = container_of(w, struct btree, writes[w->index]);
six_lock_read(&b->lock);
- __bch_btree_node_write(b, NULL, w->index);
+ /*
+ * Reusing a btree node can race with the journal reclaim code calling
+ * the journal pin flush fn, and there's no good fix for this: we don't
+ * really want journal_pin_drop() to block until the flush fn is no
+ * longer running, because journal_pin_drop() is called from the btree
+ * node write endio function, and we can't wait on the flush fn to
+ * finish running in mca_reap() - where we make reused btree nodes ready
+ * to use again - because there, we're holding the lock this function
+ * needs - deadlock.
+ *
+ * So, the b->level check is a hack so we don't try to write nodes we
+ * shouldn't:
+ */
+ if (!b->level)
+ __bch_btree_node_write(b, NULL, w->index);
six_unlock_read(&b->lock);
}