mirror of https://gitee.com/openkylin/linux.git
bcache: Avoid deadlocking in garbage collection
Not a complete fix - we could still deadlock if btree_insert_node() has to split... Signed-off-by: Kent Overstreet <kmo@daterainc.com>
This commit is contained in:
parent
a1f0358b2b
commit
bc9389eefe
|
@ -1059,14 +1059,14 @@ static void btree_node_free(struct btree *b)
|
||||||
mutex_unlock(&b->c->bucket_lock);
|
mutex_unlock(&b->c->bucket_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct btree *bch_btree_node_alloc(struct cache_set *c, int level)
|
struct btree *bch_btree_node_alloc(struct cache_set *c, int level, bool wait)
|
||||||
{
|
{
|
||||||
BKEY_PADDED(key) k;
|
BKEY_PADDED(key) k;
|
||||||
struct btree *b = ERR_PTR(-EAGAIN);
|
struct btree *b = ERR_PTR(-EAGAIN);
|
||||||
|
|
||||||
mutex_lock(&c->bucket_lock);
|
mutex_lock(&c->bucket_lock);
|
||||||
retry:
|
retry:
|
||||||
if (__bch_bucket_alloc_set(c, WATERMARK_METADATA, &k.key, 1, true))
|
if (__bch_bucket_alloc_set(c, WATERMARK_METADATA, &k.key, 1, wait))
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
bkey_put(c, &k.key);
|
bkey_put(c, &k.key);
|
||||||
|
@ -1098,9 +1098,9 @@ struct btree *bch_btree_node_alloc(struct cache_set *c, int level)
|
||||||
return b;
|
return b;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct btree *btree_node_alloc_replacement(struct btree *b)
|
static struct btree *btree_node_alloc_replacement(struct btree *b, bool wait)
|
||||||
{
|
{
|
||||||
struct btree *n = bch_btree_node_alloc(b->c, b->level);
|
struct btree *n = bch_btree_node_alloc(b->c, b->level, wait);
|
||||||
if (!IS_ERR_OR_NULL(n))
|
if (!IS_ERR_OR_NULL(n))
|
||||||
bch_btree_sort_into(b, n);
|
bch_btree_sort_into(b, n);
|
||||||
|
|
||||||
|
@ -1250,7 +1250,7 @@ static int btree_gc_coalesce(struct btree *b, struct btree_op *op,
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
for (i = 0; i < nodes; i++) {
|
for (i = 0; i < nodes; i++) {
|
||||||
new_nodes[i] = btree_node_alloc_replacement(r[i].b);
|
new_nodes[i] = btree_node_alloc_replacement(r[i].b, false);
|
||||||
if (IS_ERR_OR_NULL(new_nodes[i]))
|
if (IS_ERR_OR_NULL(new_nodes[i]))
|
||||||
goto out_nocoalesce;
|
goto out_nocoalesce;
|
||||||
}
|
}
|
||||||
|
@ -1420,7 +1420,8 @@ static int btree_gc_recurse(struct btree *b, struct btree_op *op,
|
||||||
if (!IS_ERR(last->b)) {
|
if (!IS_ERR(last->b)) {
|
||||||
should_rewrite = btree_gc_mark_node(last->b, gc);
|
should_rewrite = btree_gc_mark_node(last->b, gc);
|
||||||
if (should_rewrite) {
|
if (should_rewrite) {
|
||||||
n = btree_node_alloc_replacement(last->b);
|
n = btree_node_alloc_replacement(last->b,
|
||||||
|
false);
|
||||||
|
|
||||||
if (!IS_ERR_OR_NULL(n)) {
|
if (!IS_ERR_OR_NULL(n)) {
|
||||||
bch_btree_node_write_sync(n);
|
bch_btree_node_write_sync(n);
|
||||||
|
@ -1492,7 +1493,7 @@ static int bch_btree_gc_root(struct btree *b, struct btree_op *op,
|
||||||
|
|
||||||
should_rewrite = btree_gc_mark_node(b, gc);
|
should_rewrite = btree_gc_mark_node(b, gc);
|
||||||
if (should_rewrite) {
|
if (should_rewrite) {
|
||||||
n = btree_node_alloc_replacement(b);
|
n = btree_node_alloc_replacement(b, false);
|
||||||
|
|
||||||
if (!IS_ERR_OR_NULL(n)) {
|
if (!IS_ERR_OR_NULL(n)) {
|
||||||
bch_btree_node_write_sync(n);
|
bch_btree_node_write_sync(n);
|
||||||
|
@ -2038,7 +2039,7 @@ static int btree_split(struct btree *b, struct btree_op *op,
|
||||||
|
|
||||||
closure_init_stack(&cl);
|
closure_init_stack(&cl);
|
||||||
|
|
||||||
n1 = btree_node_alloc_replacement(b);
|
n1 = btree_node_alloc_replacement(b, true);
|
||||||
if (IS_ERR(n1))
|
if (IS_ERR(n1))
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
|
@ -2049,12 +2050,12 @@ static int btree_split(struct btree *b, struct btree_op *op,
|
||||||
|
|
||||||
trace_bcache_btree_node_split(b, n1->sets[0].data->keys);
|
trace_bcache_btree_node_split(b, n1->sets[0].data->keys);
|
||||||
|
|
||||||
n2 = bch_btree_node_alloc(b->c, b->level);
|
n2 = bch_btree_node_alloc(b->c, b->level, true);
|
||||||
if (IS_ERR(n2))
|
if (IS_ERR(n2))
|
||||||
goto err_free1;
|
goto err_free1;
|
||||||
|
|
||||||
if (!b->parent) {
|
if (!b->parent) {
|
||||||
n3 = bch_btree_node_alloc(b->c, b->level + 1);
|
n3 = bch_btree_node_alloc(b->c, b->level + 1, true);
|
||||||
if (IS_ERR(n3))
|
if (IS_ERR(n3))
|
||||||
goto err_free2;
|
goto err_free2;
|
||||||
}
|
}
|
||||||
|
|
|
@ -271,7 +271,7 @@ void bch_btree_node_read(struct btree *);
|
||||||
void bch_btree_node_write(struct btree *, struct closure *);
|
void bch_btree_node_write(struct btree *, struct closure *);
|
||||||
|
|
||||||
void bch_btree_set_root(struct btree *);
|
void bch_btree_set_root(struct btree *);
|
||||||
struct btree *bch_btree_node_alloc(struct cache_set *, int);
|
struct btree *bch_btree_node_alloc(struct cache_set *, int, bool);
|
||||||
struct btree *bch_btree_node_get(struct cache_set *, struct bkey *, int, bool);
|
struct btree *bch_btree_node_get(struct cache_set *, struct bkey *, int, bool);
|
||||||
|
|
||||||
int bch_btree_insert_check_key(struct btree *, struct btree_op *,
|
int bch_btree_insert_check_key(struct btree *, struct btree_op *,
|
||||||
|
|
|
@ -1601,7 +1601,7 @@ static void run_cache_set(struct cache_set *c)
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
err = "cannot allocate new btree root";
|
err = "cannot allocate new btree root";
|
||||||
c->root = bch_btree_node_alloc(c, 0);
|
c->root = bch_btree_node_alloc(c, 0, true);
|
||||||
if (IS_ERR_OR_NULL(c->root))
|
if (IS_ERR_OR_NULL(c->root))
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue