bcache: fixup btree_cache_wait list damage
[sfrench/cifs-2.6.git] / drivers / md / bcache / btree.c
index 0ddf91204782ded045403bf79ef0f6af5c30c834..68b9d7ca864e23ad9051d880e501f89d45b55654 100644 (file)
@@ -885,7 +885,7 @@ static struct btree *mca_cannibalize(struct cache_set *c, struct btree_op *op,
  * cannibalize_bucket() will take. This means every time we unlock the root of
  * the btree, we need to release this lock if we have it held.
  */
-static void bch_cannibalize_unlock(struct cache_set *c)
+void bch_cannibalize_unlock(struct cache_set *c)
 {
        spin_lock(&c->btree_cannibalize_lock);
        if (c->btree_cache_alloc_lock == current) {
@@ -1970,6 +1970,15 @@ static int bch_btree_check_thread(void *arg)
                        c->gc_stats.nodes++;
                        bch_btree_op_init(&op, 0);
                        ret = bcache_btree(check_recurse, p, c->root, &op);
+                       /*
+                        * The op may be added to cache_set's btree_cache_wait
+                        * in mca_cannibalize(), must ensure it is removed from
+                        * the list and release btree_cache_alloc_lock before
+                        * free op memory.
+                        * Otherwise, the btree_cache_wait will be damaged.
+                        */
+                       bch_cannibalize_unlock(c);
+                       finish_wait(&c->btree_cache_wait, &(&op)->wait);
                        if (ret)
                                goto out;
                }