bcachefs: More btree iterator fixes

- check for getting to the end of the btree in bch2_path_verify_locks
   and __btree_path_traverse_all(), this fixes an infinite loop in
   __btree_path_traverse_all().
 - relax requirement in bch2_btree_node_upgrade() that we must want an
   intent lock, this fixes bugs with paths that point to interior nodes
   (nonzero level).
 - bch2_btree_node_update_key(): fix it to upgrade the path to an intent
   lock, if necessary

Signed-off-by: Kent Overstreet <kent.overstreet@gmail.com>
This commit is contained in:
Kent Overstreet 2021-10-07 14:56:56 -04:00 committed by Kent Overstreet
parent 502027a8b2
commit d697b9abba
2 changed files with 24 additions and 4 deletions

View File

@ -170,11 +170,20 @@ static bool bch2_btree_node_upgrade(struct btree_trans *trans,
{
struct btree *b = path->l[level].b;
EBUG_ON(btree_lock_want(path, level) != BTREE_NODE_INTENT_LOCKED);
if (!is_btree_node(path, level))
return false;
switch (btree_lock_want(path, level)) {
case BTREE_NODE_UNLOCKED:
BUG_ON(btree_node_locked(path, level));
return true;
case BTREE_NODE_READ_LOCKED:
BUG_ON(btree_node_intent_locked(path, level));
return bch2_btree_node_relock(trans, path, level);
case BTREE_NODE_INTENT_LOCKED:
break;
}
if (btree_node_intent_locked(path, level))
return true;
@ -368,7 +377,8 @@ static void bch2_btree_path_verify_locks(struct btree_path *path)
unsigned l;
if (!path->nodes_locked) {
BUG_ON(path->uptodate == BTREE_ITER_UPTODATE);
BUG_ON(path->uptodate == BTREE_ITER_UPTODATE &&
btree_path_node(path, path->level));
return;
}
@ -1356,7 +1366,8 @@ retry_all:
EBUG_ON(!(trans->paths_allocated & (1ULL << path->idx)));
if (path->nodes_locked)
if (path->nodes_locked ||
!btree_path_node(path, path->level))
i++;
}

View File

@ -1945,9 +1945,16 @@ int bch2_btree_node_update_key(struct btree_trans *trans, struct btree_iter *ite
{
struct bch_fs *c = trans->c;
struct btree *new_hash = NULL;
struct btree_path *path = iter->path;
struct closure cl;
int ret = 0;
if (!btree_node_intent_locked(path, b->c.level) &&
!bch2_btree_path_upgrade(trans, path, b->c.level + 1)) {
btree_trans_restart(trans);
return -EINTR;
}
closure_init_stack(&cl);
/*
@ -1966,8 +1973,10 @@ int bch2_btree_node_update_key(struct btree_trans *trans, struct btree_iter *ite
new_hash = bch2_btree_node_mem_alloc(c);
}
path->intent_ref++;
ret = __bch2_btree_node_update_key(trans, iter, b, new_hash,
new_key, skip_triggers);
--path->intent_ref;
if (new_hash) {
mutex_lock(&c->btree_cache.lock);