summaryrefslogtreecommitdiff
path: root/libbcachefs/btree_update_leaf.c
diff options
context:
space:
mode:
Diffstat (limited to 'libbcachefs/btree_update_leaf.c')
-rw-r--r--libbcachefs/btree_update_leaf.c105
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;
}