diff options
Diffstat (limited to 'libbcachefs/btree_update_leaf.c')
-rw-r--r-- | libbcachefs/btree_update_leaf.c | 105 |
1 files changed, 83 insertions, 22 deletions
diff --git a/libbcachefs/btree_update_leaf.c b/libbcachefs/btree_update_leaf.c index ce1fc29d..d052ca54 100644 --- a/libbcachefs/btree_update_leaf.c +++ b/libbcachefs/btree_update_leaf.c @@ -54,7 +54,7 @@ static void btree_trans_unlock_write(struct btree_trans *trans) static inline int btree_trans_cmp(struct btree_insert_entry l, struct btree_insert_entry r) { - return (l.deferred > r.deferred) - (l.deferred < r.deferred) ?: + return cmp_int(l.deferred, r.deferred) ?: btree_iter_cmp(l.iter, r.iter); } @@ -524,6 +524,22 @@ static inline void do_btree_insert_one(struct btree_trans *trans, btree_insert_key_deferred(trans, insert); } +static inline bool update_triggers_transactional(struct btree_trans *trans, + struct btree_insert_entry *i) +{ + return likely(!(trans->flags & BTREE_INSERT_MARK_INMEM)) && + (i->iter->btree_id == BTREE_ID_EXTENTS || + i->iter->btree_id == BTREE_ID_INODES); +} + +static inline bool update_has_triggers(struct btree_trans *trans, + struct btree_insert_entry *i) +{ + return likely(!(trans->flags & BTREE_INSERT_NOMARK)) && + !i->deferred && + btree_node_type_needs_gc(i->iter->btree_id); +} + /* * Get journal reservation, take write locks, and attempt to do btree update(s): */ @@ -536,27 +552,25 @@ static inline int do_btree_insert_at(struct btree_trans *trans, struct btree_iter *linked; int ret; + if (likely(!(trans->flags & BTREE_INSERT_NO_CLEAR_REPLICAS))) { + memset(&trans->fs_usage_deltas.fs_usage, 0, + sizeof(trans->fs_usage_deltas.fs_usage)); + trans->fs_usage_deltas.top = trans->fs_usage_deltas.d; + } + trans_for_each_update_iter(trans, i) BUG_ON(i->iter->uptodate >= BTREE_ITER_NEED_RELOCK); - btree_trans_lock_write(c, trans); - - trans_for_each_update_iter(trans, i) { - if (i->deferred || - !btree_node_type_needs_gc(i->iter->btree_id)) - continue; - - if (!fs_usage) { - percpu_down_read(&c->mark_lock); - fs_usage = bch2_fs_usage_scratch_get(c); + trans_for_each_update_iter(trans, i) + if (update_has_triggers(trans, i) && + update_triggers_transactional(trans, i)) { + ret = bch2_trans_mark_update(trans, i, + &trans->fs_usage_deltas); + if (ret) + return ret; } - if (!bch2_bkey_replicas_marked_locked(c, - bkey_i_to_s_c(i->k), true)) { - ret = BTREE_INSERT_NEED_MARK_REPLICAS; - goto out; - } - } + btree_trans_lock_write(c, trans); if (race_fault()) { ret = -EINTR; @@ -573,6 +587,23 @@ static inline int do_btree_insert_at(struct btree_trans *trans, if (ret) goto out; + trans_for_each_update_iter(trans, i) { + if (i->deferred || + !btree_node_type_needs_gc(i->iter->btree_id)) + continue; + + if (!fs_usage) { + percpu_down_read(&c->mark_lock); + fs_usage = bch2_fs_usage_scratch_get(c); + } + + if (!bch2_bkey_replicas_marked_locked(c, + bkey_i_to_s_c(i->k), true)) { + ret = BTREE_INSERT_NEED_MARK_REPLICAS; + goto out; + } + } + /* * Don't get journal reservation until after we know insert will * succeed: @@ -602,16 +633,22 @@ static inline int do_btree_insert_at(struct btree_trans *trans, } trans_for_each_update_iter(trans, i) - bch2_mark_update(trans, i, fs_usage, 0); - if (fs_usage) + if (update_has_triggers(trans, i) && + !update_triggers_transactional(trans, i)) + bch2_mark_update(trans, i, fs_usage, 0); + + if (fs_usage) { + bch2_replicas_delta_list_apply(c, fs_usage, + &trans->fs_usage_deltas); bch2_trans_fs_usage_apply(trans, fs_usage); + } - if (unlikely(c->gc_pos.phase)) { + if (likely(!(trans->flags & BTREE_INSERT_NOMARK)) && + unlikely(c->gc_pos.phase)) trans_for_each_update_iter(trans, i) if (gc_visited(c, gc_pos_btree_node(i->iter->l[0].b))) bch2_mark_update(trans, i, NULL, BCH_BUCKET_MARK_GC); - } trans_for_each_update(trans, i) do_btree_insert_one(trans, i); @@ -639,6 +676,19 @@ int bch2_trans_commit_error(struct btree_trans *trans, { struct bch_fs *c = trans->c; unsigned flags = trans->flags; + struct btree_insert_entry *src, *dst; + + src = dst = trans->updates; + + while (src < trans->updates + trans->nr_updates) { + if (!src->triggered) { + *dst = *src; + dst++; + } + src++; + } + + trans->nr_updates = dst - trans->updates; /* * BTREE_INSERT_NOUNLOCK means don't unlock _after_ successful btree @@ -796,6 +846,7 @@ int bch2_trans_commit(struct btree_trans *trans, { struct bch_fs *c = trans->c; struct btree_insert_entry *i; + unsigned orig_mem_top = trans->mem_top; int ret = 0; if (!trans->nr_updates) @@ -873,8 +924,16 @@ out_noupdates: return ret; err: ret = bch2_trans_commit_error(trans, i, ret); - if (!ret) + + /* can't loop if it was passed in and we changed it: */ + if (unlikely(trans->flags & BTREE_INSERT_NO_CLEAR_REPLICAS) && !ret) + ret = -EINTR; + + if (!ret) { + /* free memory used by triggers, they'll be reexecuted: */ + trans->mem_top = orig_mem_top; goto retry; + } goto out; } @@ -957,6 +1016,7 @@ int bch2_btree_delete_range(struct bch_fs *c, enum btree_id id, int ret = 0; bch2_trans_init(&trans, c); + bch2_trans_preload_iters(&trans); iter = bch2_trans_get_iter(&trans, id, start, BTREE_ITER_INTENT); @@ -1002,5 +1062,6 @@ int bch2_btree_delete_range(struct bch_fs *c, enum btree_id id, } bch2_trans_exit(&trans); + BUG_ON(ret == -EINTR); return ret; } |