diff options
author | Kent Overstreet <kent.overstreet@gmail.com> | 2016-02-12 17:46:17 -0900 |
---|---|---|
committer | Kent Overstreet <kent.overstreet@gmail.com> | 2016-10-07 12:35:29 -0800 |
commit | 545395b2cc66d36c0b3056ea53474552cd3b1446 (patch) | |
tree | 85aaded54717d9b7968a73ba016f923e52c252c8 | |
parent | 250a52ce9837d34d503aabe9f4708168689cca8d (diff) |
bcache: fix a really obnoxious gc/btree split deadlock
-rw-r--r-- | drivers/md/bcache/btree_update.c | 27 |
1 files changed, 17 insertions, 10 deletions
diff --git a/drivers/md/bcache/btree_update.c b/drivers/md/bcache/btree_update.c index f95465384eb6..9146d7409baa 100644 --- a/drivers/md/bcache/btree_update.c +++ b/drivers/md/bcache/btree_update.c @@ -1558,7 +1558,13 @@ static int bch_btree_split_leaf(struct btree_iter *iter, unsigned flags) struct btree *b = iter->nodes[0]; struct btree_reserve *reserve; struct async_split *as; - int ret; + int ret = -EINTR; + + /* Hack, because gc and splitting nodes doesn't mix yet: */ + if (!down_read_trylock(&c->gc_lock)) { + bch_btree_iter_unlock(iter); + down_read(&c->gc_lock); + } /* * XXX: figure out how far we might need to split, @@ -1566,26 +1572,27 @@ static int bch_btree_split_leaf(struct btree_iter *iter, unsigned flags) */ iter->locks_want = BTREE_MAX_DEPTH; if (!bch_btree_iter_upgrade(iter)) - return -EINTR; + goto out_unlock; reserve = bch_btree_reserve_get(c, b, iter, 0, !(flags & BTREE_INSERT_NOFAIL)); - if (IS_ERR(reserve)) - return PTR_ERR(reserve); + if (IS_ERR(reserve)) { + ret = PTR_ERR(reserve); + goto out_unlock; + } as = bch_async_split_alloc(b, iter); if (!as) { - bch_btree_reserve_put(c, reserve); - return -EIO; + ret = -EIO; + goto out_put_reserve; } - /* Hack, because gc and splitting nodes doesn't mix yet: */ - down_read(&c->gc_lock); ret = btree_split(b, iter, NULL, reserve, as); - up_read(&c->gc_lock); +out_put_reserve: bch_btree_reserve_put(c, reserve); - +out_unlock: + up_read(&c->gc_lock); return ret; } |