* Parent node must be locked, else we could read in a btree node that's
* been freed:
*/
- if (iter && !bch2_btree_node_relock(iter, level + 1))
+ if (iter && !bch2_btree_node_relock(iter, level + 1)) {
+ btree_trans_restart(iter->trans);
return ERR_PTR(-EINTR);
+ }
b = bch2_btree_node_mem_alloc(c);
if (IS_ERR(b))
if (iter &&
(!bch2_trans_relock(iter->trans) ||
- !bch2_btree_iter_relock_intent(iter)))
+ !bch2_btree_iter_relock_intent(iter))) {
+ BUG_ON(!iter->trans->restarted);
return ERR_PTR(-EINTR);
+ }
- if (!six_relock_type(&b->c.lock, lock_type, seq))
+ if (!six_relock_type(&b->c.lock, lock_type, seq)) {
+ btree_trans_restart(iter->trans);
return ERR_PTR(-EINTR);
+ }
return b;
}
if (!btree_node_lock(b, k->k.p, level, iter, lock_type,
lock_node_check_fn, (void *) k, trace_ip)) {
- if (b->hash_val != btree_ptr_hash_val(k))
+ if (!trans->restarted)
goto retry;
return ERR_PTR(-EINTR);
}
trace_ip,
iter->btree_id,
&iter->real_pos);
+ btree_trans_restart(trans);
return ERR_PTR(-EINTR);
}
}
*/
if (iter &&
(!bch2_trans_relock(trans) ||
- !bch2_btree_iter_relock_intent(iter)))
+ !bch2_btree_iter_relock_intent(iter))) {
+ BUG_ON(!trans->restarted);
return ERR_PTR(-EINTR);
+ }
if (!six_relock_type(&b->c.lock, lock_type, seq))
goto retry;
BTREE_ITER_NOT_EXTENTS|
BTREE_ITER_ALL_SNAPSHOTS);
- while ((k = bch2_btree_iter_peek(iter)).k &&
+ while ((bch2_trans_begin(&trans),
+ k = bch2_btree_iter_peek(iter)).k &&
!(ret = bkey_err(k))) {
c->gc_gens_pos = iter->pos;
}
if (unlikely(deadlock_iter)) {
- trace_trans_restart_would_deadlock(iter->trans->ip, ip,
+ trace_trans_restart_would_deadlock(trans->ip, ip,
trans->in_traverse_all, reason,
deadlock_iter->btree_id,
btree_iter_type(deadlock_iter),
iter->btree_id,
btree_iter_type(iter),
&pos);
+ btree_trans_restart(trans);
return false;
}
? iter->l[l].b->c.lock.state.seq
: 0);
btree_iter_set_dirty(iter, BTREE_ITER_NEED_TRAVERSE);
+ btree_trans_restart(iter->trans);
return false;
}
}
__flatten
bool bch2_btree_iter_relock(struct btree_iter *iter, unsigned long trace_ip)
{
- return btree_iter_get_locks(iter, false, trace_ip);
+ bool ret = btree_iter_get_locks(iter, false, trace_ip);
+
+ if (!ret)
+ btree_trans_restart(iter->trans);
+ return ret;
}
bool __bch2_btree_iter_upgrade(struct btree_iter *iter,
btree_iter_get_locks(linked, true, _THIS_IP_);
}
+ if (iter->should_be_locked)
+ btree_trans_restart(iter->trans);
return false;
}
{
struct btree_iter *iter;
+ if (unlikely(trans->restarted))
+ return false;
+
trans_for_each_iter(trans, iter)
if (btree_iter_should_be_locked(iter) &&
!bch2_btree_iter_relock(iter, _RET_IP_)) {
trace_trans_restart_relock(trans->ip, _RET_IP_,
iter->btree_id, &iter->real_pos);
+ BUG_ON(!trans->restarted);
return false;
}
return true;
return b == *rootp ? 0 : -1;
}
-static inline int btree_iter_lock_root(struct btree_iter *iter,
+static inline int btree_iter_lock_root(struct btree_trans *trans,
+ struct btree_iter *iter,
unsigned depth_want,
unsigned long trace_ip)
{
- struct bch_fs *c = iter->trans->c;
+ struct bch_fs *c = trans->c;
struct btree *b, **rootp = &c->btree_roots[iter->btree_id].b;
enum six_lock_type lock_type;
unsigned i;
if (unlikely(!btree_node_lock(b, SPOS_MAX, iter->level,
iter, lock_type,
lock_root_check_fn, rootp,
- trace_ip)))
- return -EINTR;
+ trace_ip))) {
+ if (trans->restarted)
+ return -EINTR;
+ continue;
+ }
if (likely(b == READ_ONCE(*rootp) &&
b->c.level == iter->level &&
btree_node_unlock(iter, plevel);
}
-static __always_inline int btree_iter_down(struct btree_iter *iter,
+static __always_inline int btree_iter_down(struct btree_trans *trans,
+ struct btree_iter *iter,
unsigned long trace_ip)
{
- struct btree_trans *trans = iter->trans;
struct bch_fs *c = trans->c;
struct btree_iter_level *l = &iter->l[iter->level];
struct btree *b;
trans->in_traverse_all = true;
retry_all:
+ trans->restarted = false;
+
nr_sorted = 0;
trans_for_each_iter(trans, iter) {
}
if (hweight64(trans->iters_live) > 1)
- ret = -EINTR;
+ ret = btree_trans_restart(trans);
else
trans_for_each_iter(trans, iter)
if (iter->flags & BTREE_ITER_KEEP_UNTIL_COMMIT) {
- ret = -EINTR;
+ ret = btree_trans_restart(trans);
break;
}
out:
*/
while (iter->level > depth_want) {
ret = btree_iter_node(iter, iter->level)
- ? btree_iter_down(iter, trace_ip)
- : btree_iter_lock_root(iter, depth_want, trace_ip);
+ ? btree_iter_down(trans, iter, trace_ip)
+ : btree_iter_lock_root(trans, iter, depth_want, trace_ip);
if (unlikely(ret)) {
if (ret == 1) {
/*
iter->uptodate = BTREE_ITER_NEED_PEEK;
out:
+ BUG_ON((ret == -EINTR) != !!trans->restarted);
trace_iter_traverse(trans->ip, trace_ip,
btree_iter_type(iter) == BTREE_ITER_CACHED,
iter->btree_id, &iter->real_pos, ret);
int cmp = bpos_cmp(new_pos, iter->real_pos);
unsigned l = iter->level;
+ EBUG_ON(iter->trans->restarted);
+
if (!cmp)
goto out;
struct btree_iter *iter, *best = NULL;
struct bpos real_pos, pos_min = POS_MIN;
+ EBUG_ON(trans->restarted);
+
if ((flags & BTREE_ITER_TYPE) != BTREE_ITER_NODES &&
btree_node_type_is_extents(btree_id) &&
!(flags & BTREE_ITER_NOT_EXTENTS) &&
if (old_bytes) {
trace_trans_restart_mem_realloced(trans->ip, _RET_IP_, new_bytes);
+ btree_trans_restart(trans);
return ERR_PTR(-EINTR);
}
}
if (!(flags & TRANS_RESET_NOTRAVERSE) &&
trans->iters_linked)
bch2_btree_iter_traverse_all(trans);
+
+ trans->restarted = false;
}
static void bch2_trans_alloc_iters(struct btree_trans *trans, struct bch_fs *c)
bool bch2_trans_relock(struct btree_trans *);
void bch2_trans_unlock(struct btree_trans *);
+__always_inline
+static inline int btree_trans_restart(struct btree_trans *trans)
+{
+ trans->restarted = true;
+ bch2_trans_unlock(trans);
+ return -EINTR;
+}
+
bool __bch2_btree_iter_upgrade(struct btree_iter *, unsigned);
static inline bool bch2_btree_iter_upgrade(struct btree_iter *iter,
if (!bch2_btree_node_relock(ck_iter, 0)) {
trace_transaction_restart_ip(trans->ip, _THIS_IP_);
- ret = -EINTR;
+ ret = btree_trans_restart(trans);
goto err;
}
}
}
+ /*
+ * XXX: not allowed to be holding read locks when we take a write lock,
+ * currently
+ */
bch2_btree_node_lock_write(ck_iter->l[0].b, ck_iter);
if (new_k) {
kfree(ck->k);
if (!btree_node_lock((void *) ck, iter->pos, 0, iter, lock_want,
bkey_cached_check_fn, iter, _THIS_IP_)) {
- if (ck->key.btree_id != iter->btree_id ||
- bpos_cmp(ck->key.pos, iter->pos)) {
+ if (!trans->restarted)
goto retry;
- }
trace_transaction_restart_ip(trans->ip, _THIS_IP_);
ret = -EINTR;
iter->l[0].b = (void *) ck;
fill:
if (!ck->valid && !(iter->flags & BTREE_ITER_CACHED_NOFILL)) {
- if (!btree_node_intent_locked(iter, 0))
- bch2_btree_iter_upgrade(iter, 1);
- if (!btree_node_intent_locked(iter, 0)) {
+ if (!iter->locks_want &&
+ !!__bch2_btree_iter_upgrade(iter, 1)) {
trace_transaction_restart_ip(trans->ip, _THIS_IP_);
+ BUG_ON(!trans->restarted);
ret = -EINTR;
goto err;
}
iter->uptodate = BTREE_ITER_NEED_PEEK;
if ((iter->flags & BTREE_ITER_INTENT) &&
- !iter->locks_want &&
- __bch2_btree_iter_upgrade(iter, 1))
+ !bch2_btree_iter_upgrade(iter, 1)) {
+ BUG_ON(!trans->restarted);
ret = -EINTR;
+ }
+
+ BUG_ON(!ret && !btree_node_locked(iter, 0));
return ret;
err:
int srcu_idx;
u8 nr_updates;
- unsigned used_mempool:1;
- unsigned error:1;
- unsigned in_traverse_all:1;
+ bool used_mempool:1;
+ bool error:1;
+ bool in_traverse_all:1;
+ bool restarted:1;
/*
* For when bch2_trans_update notices we'll be splitting a compressed
* extent:
if (flags & BTREE_INSERT_JOURNAL_RECLAIM) {
bch2_btree_update_free(as);
+ btree_trans_restart(trans);
return ERR_PTR(ret);
}
if (race_fault()) {
trace_trans_restart_fault_inject(trans->ip, trace_ip);
+ trans->restarted = true;
return -EINTR;
}
u64s_delta -= !bkey_deleted(old.k) ? old.k->u64s : 0;
}
- return u64s_delta <= 0
- ? (bch2_foreground_maybe_merge(trans, iter, iter->level,
- trans->flags & ~BTREE_INSERT_NOUNLOCK) ?: -EINTR)
- : 0;
+ if (u64s_delta > 0)
+ return 0;
+
+ ret = bch2_foreground_maybe_merge(trans, iter, iter->level,
+ trans->flags & ~BTREE_INSERT_NOUNLOCK);
+ if (!ret) {
+ ret = -EINTR;
+ trans->restarted = true;
+ }
+
+ return ret;
}
/*
trace_trans_restart_upgrade(trans->ip, trace_ip,
iter->btree_id,
&iter->real_pos);
+ trans->restarted = true;
return -EINTR;
}
} else {
trace_trans_restart_btree_node_split(trans->ip, trace_ip,
i->iter->btree_id,
&i->iter->real_pos);
+ trans->restarted = true;
ret = -EINTR;
}
break;
ret = bch2_replicas_delta_list_mark(c, trans->fs_usage_deltas);
if (ret)
- return ret;
+ break;
if (bch2_trans_relock(trans))
return 0;
bch2_trans_unlock(trans);
if ((trans->flags & BTREE_INSERT_JOURNAL_RECLAIM) &&
- !(trans->flags & BTREE_INSERT_JOURNAL_RESERVED))
- return -EAGAIN;
+ !(trans->flags & BTREE_INSERT_JOURNAL_RESERVED)) {
+ trans->restarted = true;
+ ret = -EAGAIN;
+ break;
+ }
ret = bch2_trans_journal_res_get(trans, JOURNAL_RES_GET_CHECK);
if (ret)
- return ret;
+ break;
if (bch2_trans_relock(trans))
return 0;
wait_event_freezable(c->journal.reclaim_wait,
(ret = journal_reclaim_wait_done(c)));
if (ret < 0)
- return ret;
+ break;
if (bch2_trans_relock(trans))
return 0;
break;
}
+ BUG_ON((ret == EINTR || ret == -EAGAIN) && !trans->restarted);
BUG_ON(ret == -ENOSPC && (flags & BTREE_INSERT_NOFAIL));
return ret;
trace_trans_restart_upgrade(trans->ip, _RET_IP_,
i->iter->btree_id,
&i->iter->pos);
+ trans->restarted = true;
ret = -EINTR;
goto out;
}
goto err;
}
retry:
+ BUG_ON(trans->restarted);
memset(&trans->journal_res, 0, sizeof(trans->journal_res));
ret = do_bch2_trans_commit(trans, &i, _RET_IP_);