diff options
Diffstat (limited to 'libbcachefs/btree_update_leaf.c')
-rw-r--r-- | libbcachefs/btree_update_leaf.c | 99 |
1 files changed, 84 insertions, 15 deletions
diff --git a/libbcachefs/btree_update_leaf.c b/libbcachefs/btree_update_leaf.c index 588a1997..a481b0d6 100644 --- a/libbcachefs/btree_update_leaf.c +++ b/libbcachefs/btree_update_leaf.c @@ -309,8 +309,10 @@ static inline int do_btree_insert_at(struct btree_insert *trans, unsigned u64s; int ret; - trans_for_each_entry(trans, i) + trans_for_each_entry(trans, i) { BUG_ON(i->done); + BUG_ON(i->iter->uptodate >= BTREE_ITER_NEED_RELOCK); + } u64s = 0; trans_for_each_entry(trans, i) @@ -330,6 +332,7 @@ static inline int do_btree_insert_at(struct btree_insert *trans, if (race_fault()) { ret = -EINTR; + trans_restart(" (race)"); goto out; } @@ -354,10 +357,14 @@ static inline int do_btree_insert_at(struct btree_insert *trans, } } - if (journal_seq_verify(c) && - !(trans->flags & BTREE_INSERT_JOURNAL_REPLAY)) - trans_for_each_entry(trans, i) - i->k->k.version.lo = trans->journal_res.seq; + if (!(trans->flags & BTREE_INSERT_JOURNAL_REPLAY)) { + if (journal_seq_verify(c)) + trans_for_each_entry(trans, i) + i->k->k.version.lo = trans->journal_res.seq; + else if (inject_invalid_keys(c)) + trans_for_each_entry(trans, i) + i->k->k.version = MAX_VERSION; + } trans_for_each_entry(trans, i) { switch (btree_insert_key_leaf(trans, i)) { @@ -398,6 +405,17 @@ out: return ret; } +static inline void btree_insert_entry_checks(struct bch_fs *c, + struct btree_insert_entry *i) +{ + BUG_ON(i->iter->level); + BUG_ON(bkey_cmp(bkey_start_pos(&i->k->k), i->iter->pos)); + BUG_ON(debug_check_bkeys(c) && + !bkey_deleted(&i->k->k) && + bch2_bkey_invalid(c, i->iter->btree_id, + bkey_i_to_s_c(i->k))); +} + /** * __bch_btree_insert_at - insert keys at given iterator positions * @@ -418,20 +436,16 @@ int __bch2_btree_insert_at(struct btree_insert *trans) unsigned flags; int ret; + BUG_ON(!trans->nr); + for_each_btree_iter(trans->entries[0].iter, linked) bch2_btree_iter_verify_locks(linked); /* for the sake of sanity: */ BUG_ON(trans->nr > 1 && !(trans->flags & BTREE_INSERT_ATOMIC)); - trans_for_each_entry(trans, i) { - BUG_ON(i->iter->level); - BUG_ON(bkey_cmp(bkey_start_pos(&i->k->k), i->iter->pos)); - BUG_ON(debug_check_bkeys(c) && - !bkey_deleted(&i->k->k) && - bch2_bkey_invalid(c, i->iter->btree_id, - bkey_i_to_s_c(i->k))); - } + trans_for_each_entry(trans, i) + btree_insert_entry_checks(c, i); bubble_sort(trans->entries, trans->nr, btree_trans_cmp); @@ -442,7 +456,12 @@ retry: cycle_gc_lock = false; trans_for_each_entry(trans, i) { + unsigned old_locks_want = i->iter->locks_want; + unsigned old_uptodate = i->iter->uptodate; + if (!bch2_btree_iter_upgrade(i->iter, 1, true)) { + trans_restart(" (failed upgrade, locks_want %u uptodate %u)", + old_locks_want, old_uptodate); ret = -EINTR; goto err; } @@ -515,8 +534,10 @@ err: * don't care if we got ENOSPC because we told split it * couldn't block: */ - if (!ret || (flags & BTREE_INSERT_NOUNLOCK)) + if (!ret || (flags & BTREE_INSERT_NOUNLOCK)) { + trans_restart(" (split)"); ret = -EINTR; + } } if (cycle_gc_lock) { @@ -531,13 +552,16 @@ err: } if (ret == -EINTR) { - if (flags & BTREE_INSERT_NOUNLOCK) + if (flags & BTREE_INSERT_NOUNLOCK) { + trans_restart(" (can't unlock)"); goto out; + } trans_for_each_entry(trans, i) { int ret2 = bch2_btree_iter_traverse(i->iter); if (ret2) { ret = ret2; + trans_restart(" (traverse)"); goto out; } @@ -550,11 +574,56 @@ err: */ if (!(flags & BTREE_INSERT_ATOMIC)) goto retry; + + trans_restart(" (atomic)"); } goto out; } +void bch2_trans_update(struct btree_trans *trans, + struct btree_iter *iter, + struct bkey_i *k, + unsigned extra_journal_res) +{ + struct btree_insert_entry *i; + + BUG_ON(trans->nr_updates >= ARRAY_SIZE(trans->updates)); + + i = &trans->updates[trans->nr_updates++]; + + *i = (struct btree_insert_entry) { + .iter = iter, + .k = k, + .extra_res = extra_journal_res, + }; + + btree_insert_entry_checks(trans->c, i); +} + +int bch2_trans_commit(struct btree_trans *trans, + struct disk_reservation *disk_res, + struct extent_insert_hook *hook, + u64 *journal_seq, + unsigned flags) +{ + struct btree_insert insert = { + .c = trans->c, + .disk_res = disk_res, + .journal_seq = journal_seq, + .flags = flags, + .nr = trans->nr_updates, + .entries = trans->updates, + }; + + if (!trans->nr_updates) + return 0; + + trans->nr_updates = 0; + + return __bch2_btree_insert_at(&insert); +} + int bch2_btree_delete_at(struct btree_iter *iter, unsigned flags) { struct bkey_i k; |