bcachefs: Fix another deadlock in btree_update_nodes_written()

We also can't be blocking on btree node write locks while holding
btree_interior_update_lock.

Signed-off-by: Kent Overstreet <kent.overstreet@gmail.com>
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
This commit is contained in:
Kent Overstreet 2020-05-01 19:56:31 -04:00 committed by Kent Overstreet
parent 1e1a31c4b0
commit 5b6d505a77

View file

@ -609,6 +609,19 @@ static void bch2_btree_update_free(struct btree_update *as)
mutex_unlock(&c->btree_interior_update_lock);
}
static inline bool six_trylock_intentwrite(struct six_lock *lock)
{
if (!six_trylock_intent(lock))
return false;
if (!six_trylock_write(lock)) {
six_unlock_intent(lock);
return false;
}
return true;
}
static void btree_update_nodes_written(struct closure *cl)
{
struct btree_update *as = container_of(cl, struct btree_update, cl);
@ -637,10 +650,15 @@ static void btree_update_nodes_written(struct closure *cl)
}
b = as->b;
if (b && !six_trylock_intent(&b->c.lock)) {
if (b && !six_trylock_intentwrite(&b->c.lock)) {
mutex_unlock(&c->btree_interior_update_lock);
btree_node_lock_type(c, b, SIX_LOCK_intent);
six_lock_write(&b->c.lock, NULL, NULL);
six_unlock_write(&b->c.lock);
six_unlock_intent(&b->c.lock);
mutex_lock(&c->btree_interior_update_lock);
goto again;
}
@ -648,7 +666,25 @@ static void btree_update_nodes_written(struct closure *cl)
list_del(&as->unwritten_list);
ret = bch2_journal_res_get(&c->journal, &res, as->journal_u64s,
JOURNAL_RES_GET_NONBLOCK|
JOURNAL_RES_GET_RESERVED);
if (ret == -EAGAIN) {
unsigned u64s = as->journal_u64s;
six_unlock_write(&b->c.lock);
six_unlock_intent(&b->c.lock);
mutex_unlock(&c->btree_interior_update_lock);
ret = bch2_journal_res_get(&c->journal, &res, u64s,
JOURNAL_RES_GET_CHECK|
JOURNAL_RES_GET_RESERVED);
if (!ret) {
mutex_lock(&c->btree_interior_update_lock);
goto again;
}
}
if (ret) {
BUG_ON(!bch2_journal_error(&c->journal));
/* can't unblock btree writes */
@ -671,7 +707,6 @@ static void btree_update_nodes_written(struct closure *cl)
/* @b is the node we did the final insert into: */
BUG_ON(!res.ref);
six_lock_write(&b->c.lock, NULL, NULL);
list_del(&as->write_blocked_list);
i = btree_bset_last(b);
@ -680,7 +715,6 @@ static void btree_update_nodes_written(struct closure *cl)
le64_to_cpu(i->journal_seq)));
bch2_btree_add_journal_pin(c, b, res.seq);
six_unlock_write(&b->c.lock);
break;
case BTREE_INTERIOR_UPDATING_AS:
@ -709,6 +743,7 @@ static void btree_update_nodes_written(struct closure *cl)
free_update:
/* Do btree write after dropping journal res: */
if (b) {
six_unlock_write(&b->c.lock);
/*
* b->write_blocked prevented it from being written, so
* write it now if it needs to be written: