/* new transactional stuff: */
-int bch2_trans_iter_put(struct btree_trans *trans,
- struct btree_iter *iter)
-{
- int ret = btree_iter_err(iter);
-
- trans->iters_live &= ~(1ULL << iter->idx);
- return ret;
-}
-
static inline void __bch2_trans_iter_free(struct btree_trans *trans,
unsigned idx)
{
trans->iters_linked &= ~(1ULL << idx);
trans->iters_live &= ~(1ULL << idx);
trans->iters_touched &= ~(1ULL << idx);
- trans->iters_unlink_on_restart &= ~(1ULL << idx);
- trans->iters_unlink_on_commit &= ~(1ULL << idx);
}
-int bch2_trans_iter_free(struct btree_trans *trans,
- struct btree_iter *iter)
+int bch2_trans_iter_put(struct btree_trans *trans,
+ struct btree_iter *iter)
{
int ret = btree_iter_err(iter);
- __bch2_trans_iter_free(trans, iter->idx);
+ if (!(trans->iters_touched & (1ULL << iter->idx)) &&
+ !(iter->flags & BTREE_ITER_KEEP_UNTIL_COMMIT))
+ __bch2_trans_iter_free(trans, iter->idx);
+
+ trans->iters_live &= ~(1ULL << iter->idx);
return ret;
}
-int bch2_trans_iter_free_on_commit(struct btree_trans *trans,
- struct btree_iter *iter)
+int bch2_trans_iter_free(struct btree_trans *trans,
+ struct btree_iter *iter)
{
- int ret = btree_iter_err(iter);
+ trans->iters_touched &= ~(1ULL << iter->idx);
- trans->iters_unlink_on_commit |= 1ULL << iter->idx;
- return ret;
+ return bch2_trans_iter_put(trans, iter);
}
static int bch2_trans_realloc_iters(struct btree_trans *trans,
goto got_slot;
if (trans->nr_iters == trans->size) {
- int ret = bch2_trans_realloc_iters(trans, trans->size * 2);
+ int ret;
+
+ if (trans->nr_iters >= BTREE_ITER_MAX) {
+ struct btree_iter *iter;
+
+ trans_for_each_iter(trans, iter) {
+ pr_err("iter: btree %s pos %llu:%llu%s%s%s",
+ bch2_btree_ids[iter->btree_id],
+ iter->pos.inode,
+ iter->pos.offset,
+ (trans->iters_live & (1ULL << iter->idx)) ? " live" : "",
+ (trans->iters_touched & (1ULL << iter->idx)) ? " touched" : "",
+ iter->flags & BTREE_ITER_KEEP_UNTIL_COMMIT ? " keep" : "");
+ }
+
+ panic("trans iter oveflow\n");
+ }
+
+ ret = bch2_trans_realloc_iters(trans, trans->size * 2);
if (ret)
return ERR_PTR(ret);
}
return &trans->iters[idx];
}
+static inline void btree_iter_copy(struct btree_iter *dst,
+ struct btree_iter *src)
+{
+ unsigned i, idx = dst->idx;
+
+ *dst = *src;
+ dst->idx = idx;
+
+ for (i = 0; i < BTREE_MAX_DEPTH; i++)
+ if (btree_node_locked(dst, i))
+ six_lock_increment(&dst->l[i].b->c.lock,
+ __btree_lock_want(dst, i));
+}
+
+static inline struct bpos bpos_diff(struct bpos l, struct bpos r)
+{
+ if (bkey_cmp(l, r) > 0)
+ swap(l, r);
+
+ return POS(r.inode - l.inode, r.offset - l.offset);
+}
+
static struct btree_iter *__btree_trans_get_iter(struct btree_trans *trans,
unsigned btree_id, struct bpos pos,
- unsigned flags, u64 iter_id)
+ unsigned flags)
{
- struct btree_iter *iter;
+ struct btree_iter *iter, *best = NULL;
BUG_ON(trans->nr_iters > BTREE_ITER_MAX);
- trans_for_each_iter(trans, iter)
- if (iter_id
- ? iter->id == iter_id
- : (iter->btree_id == btree_id &&
- !bkey_cmp(iter->pos, pos)))
- goto found;
+ trans_for_each_iter(trans, iter) {
+ if (btree_iter_type(iter) != (flags & BTREE_ITER_TYPE))
+ continue;
- iter = NULL;
-found:
- if (!iter) {
+ if (iter->btree_id != btree_id)
+ continue;
+
+ if (best &&
+ bkey_cmp(bpos_diff(best->pos, pos),
+ bpos_diff(iter->pos, pos)) < 0)
+ continue;
+
+ best = iter;
+ }
+
+ if (!best) {
iter = btree_trans_iter_alloc(trans);
if (IS_ERR(iter))
return iter;
- iter->id = iter_id;
-
bch2_btree_iter_init(trans, iter, btree_id, pos, flags);
- } else {
- iter->flags &= ~(BTREE_ITER_SLOTS|BTREE_ITER_INTENT|BTREE_ITER_PREFETCH);
- iter->flags |= flags & (BTREE_ITER_SLOTS|BTREE_ITER_INTENT|BTREE_ITER_PREFETCH);
+ } else if ((trans->iters_live & (1ULL << best->idx)) ||
+ (best->flags & BTREE_ITER_KEEP_UNTIL_COMMIT)) {
+ iter = btree_trans_iter_alloc(trans);
+ if (IS_ERR(iter))
+ return iter;
- if ((iter->flags & BTREE_ITER_INTENT) &&
- !bch2_btree_iter_upgrade(iter, 1)) {
- trace_trans_restart_upgrade(trans->ip);
- return ERR_PTR(-EINTR);
- }
+ btree_iter_copy(iter, best);
+ } else {
+ iter = best;
}
+ iter->flags &= ~BTREE_ITER_KEEP_UNTIL_COMMIT;
+ iter->flags &= ~(BTREE_ITER_SLOTS|BTREE_ITER_INTENT|BTREE_ITER_PREFETCH);
+ iter->flags |= flags & (BTREE_ITER_SLOTS|BTREE_ITER_INTENT|BTREE_ITER_PREFETCH);
+
+ if (iter->flags & BTREE_ITER_INTENT)
+ bch2_btree_iter_upgrade(iter, 1);
+ else
+ bch2_btree_iter_downgrade(iter);
+
BUG_ON(iter->btree_id != btree_id);
+ BUG_ON((iter->flags ^ flags) & BTREE_ITER_TYPE);
+ BUG_ON(iter->flags & BTREE_ITER_KEEP_UNTIL_COMMIT);
BUG_ON(trans->iters_live & (1ULL << iter->idx));
+
trans->iters_live |= 1ULL << iter->idx;
trans->iters_touched |= 1ULL << iter->idx;
- BUG_ON(iter->btree_id != btree_id);
- BUG_ON((iter->flags ^ flags) & BTREE_ITER_TYPE);
-
return iter;
}
-struct btree_iter *__bch2_trans_get_iter(struct btree_trans *trans,
- enum btree_id btree_id,
- struct bpos pos, unsigned flags,
- u64 iter_id)
+struct btree_iter *bch2_trans_get_iter(struct btree_trans *trans,
+ enum btree_id btree_id,
+ struct bpos pos, unsigned flags)
{
struct btree_iter *iter =
- __btree_trans_get_iter(trans, btree_id, pos, flags, iter_id);
+ __btree_trans_get_iter(trans, btree_id, pos, flags);
if (!IS_ERR(iter))
bch2_btree_iter_set_pos(iter, pos);
{
struct btree_iter *iter =
__btree_trans_get_iter(trans, btree_id, pos,
- flags|BTREE_ITER_NODES, 0);
+ flags|BTREE_ITER_NODES);
unsigned i;
BUG_ON(IS_ERR(iter));
struct btree_iter *src)
{
struct btree_iter *iter;
- int idx, i;
iter = btree_trans_iter_alloc(trans);
if (IS_ERR(iter))
return iter;
- idx = iter->idx;
- *iter = *src;
- iter->idx = idx;
+ btree_iter_copy(iter, src);
- trans->iters_live |= 1ULL << idx;
- trans->iters_touched |= 1ULL << idx;
- trans->iters_unlink_on_restart |= 1ULL << idx;
-
- for (i = 0; i < BTREE_MAX_DEPTH; i++)
- if (btree_node_locked(iter, i))
- six_lock_increment(&iter->l[i].b->c.lock,
- __btree_lock_want(iter, i));
+ trans->iters_live |= 1ULL << iter->idx;
+ /*
+ * Don't mark it as touched, we don't need to preserve this iter since
+ * it's cheap to copy it again:
+ */
+ trans->iters_touched &= ~(1ULL << iter->idx);
+ iter->flags &= ~BTREE_ITER_KEEP_UNTIL_COMMIT;
return iter;
}
return p;
}
-inline void bch2_trans_unlink_iters(struct btree_trans *trans, u64 iters)
+inline void bch2_trans_unlink_iters(struct btree_trans *trans)
{
- iters &= trans->iters_linked;
- iters &= ~trans->iters_live;
+ u64 iters = trans->iters_linked &
+ ~trans->iters_touched &
+ ~trans->iters_live;
while (iters) {
unsigned idx = __ffs64(iters);
}
}
-void bch2_trans_begin(struct btree_trans *trans)
+void bch2_trans_reset(struct btree_trans *trans, unsigned flags)
{
- u64 iters_to_unlink;
+ struct btree_iter *iter;
- /*
- * On transaction restart, the transaction isn't required to allocate
- * all the same iterators it on the last iteration:
- *
- * Unlink any iterators it didn't use this iteration, assuming it got
- * further (allocated an iter with a higher idx) than where the iter
- * was originally allocated:
- */
- iters_to_unlink = ~trans->iters_live &
- ((1ULL << fls64(trans->iters_live)) - 1);
+ trans_for_each_iter(trans, iter)
+ iter->flags &= ~BTREE_ITER_KEEP_UNTIL_COMMIT;
- iters_to_unlink |= trans->iters_unlink_on_restart;
- iters_to_unlink |= trans->iters_unlink_on_commit;
+ bch2_trans_unlink_iters(trans);
- trans->iters_live = 0;
+ if (flags & TRANS_RESET_ITERS)
+ trans->iters_live = 0;
- bch2_trans_unlink_iters(trans, iters_to_unlink);
+ trans->iters_touched &= trans->iters_live;
- trans->iters_touched = 0;
- trans->iters_unlink_on_restart = 0;
- trans->iters_unlink_on_commit = 0;
trans->nr_updates = 0;
- trans->mem_top = 0;
+
+ if (flags & TRANS_RESET_MEM)
+ trans->mem_top = 0;
bch2_btree_iter_traverse_all(trans);
}
int bch2_trans_iter_put(struct btree_trans *, struct btree_iter *);
int bch2_trans_iter_free(struct btree_trans *, struct btree_iter *);
-int bch2_trans_iter_free_on_commit(struct btree_trans *, struct btree_iter *);
-void bch2_trans_unlink_iters(struct btree_trans *, u64);
+void bch2_trans_unlink_iters(struct btree_trans *);
-struct btree_iter *__bch2_trans_get_iter(struct btree_trans *, enum btree_id,
- struct bpos, unsigned, u64);
+struct btree_iter *bch2_trans_get_iter(struct btree_trans *, enum btree_id,
+ struct bpos, unsigned);
struct btree_iter *bch2_trans_copy_iter(struct btree_trans *,
struct btree_iter *);
+struct btree_iter *bch2_trans_get_node_iter(struct btree_trans *,
+ enum btree_id, struct bpos,
+ unsigned, unsigned, unsigned);
-static __always_inline u64 __btree_iter_id(void)
-{
- u64 ret = 0;
+#define TRANS_RESET_ITERS (1 << 0)
+#define TRANS_RESET_MEM (1 << 1)
- ret <<= 32;
- ret |= _RET_IP_ & U32_MAX;
- ret <<= 32;
- ret |= _THIS_IP_ & U32_MAX;
- return ret;
-}
+void bch2_trans_reset(struct btree_trans *, unsigned);
-static __always_inline struct btree_iter *
-bch2_trans_get_iter(struct btree_trans *trans, enum btree_id btree_id,
- struct bpos pos, unsigned flags)
+static inline void bch2_trans_begin(struct btree_trans *trans)
{
- return __bch2_trans_get_iter(trans, btree_id, pos, flags,
- __btree_iter_id());
+ return bch2_trans_reset(trans, TRANS_RESET_ITERS|TRANS_RESET_MEM);
}
-struct btree_iter *bch2_trans_get_node_iter(struct btree_trans *,
- enum btree_id, struct bpos,
- unsigned, unsigned, unsigned);
-
-void bch2_trans_begin(struct btree_trans *);
-
static inline void bch2_trans_begin_updates(struct btree_trans *trans)
{
- trans->nr_updates = 0;
+ return bch2_trans_reset(trans, TRANS_RESET_MEM);
}
void *bch2_trans_kmalloc(struct btree_trans *, size_t);