mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-15 08:14:15 +08:00
bcachefs: Don't reexecute triggers when retrying transaction commit
This was causing a bug with transaction iterators overflowing; now, if triggers have to be reexecuted we always return -EINTR and retry from the start of the transaction. Signed-off-by: Kent Overstreet <kent.overstreet@gmail.com> Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
This commit is contained in:
parent
58e2388f9e
commit
8b3bbe2c34
@ -281,6 +281,7 @@ struct btree_trans {
|
|||||||
struct disk_reservation *disk_res;
|
struct disk_reservation *disk_res;
|
||||||
unsigned flags;
|
unsigned flags;
|
||||||
unsigned journal_u64s;
|
unsigned journal_u64s;
|
||||||
|
unsigned journal_preres_u64s;
|
||||||
struct replicas_delta_list *fs_usage_deltas;
|
struct replicas_delta_list *fs_usage_deltas;
|
||||||
|
|
||||||
struct btree_iter iters_onstack[2];
|
struct btree_iter iters_onstack[2];
|
||||||
|
@ -26,7 +26,6 @@ enum {
|
|||||||
__BTREE_INSERT_JOURNAL_RESERVED,
|
__BTREE_INSERT_JOURNAL_RESERVED,
|
||||||
__BTREE_INSERT_NOMARK_OVERWRITES,
|
__BTREE_INSERT_NOMARK_OVERWRITES,
|
||||||
__BTREE_INSERT_NOMARK,
|
__BTREE_INSERT_NOMARK,
|
||||||
__BTREE_INSERT_NO_CLEAR_REPLICAS,
|
|
||||||
__BTREE_INSERT_BUCKET_INVALIDATE,
|
__BTREE_INSERT_BUCKET_INVALIDATE,
|
||||||
__BTREE_INSERT_NOWAIT,
|
__BTREE_INSERT_NOWAIT,
|
||||||
__BTREE_INSERT_GC_LOCK_HELD,
|
__BTREE_INSERT_GC_LOCK_HELD,
|
||||||
@ -60,8 +59,6 @@ enum {
|
|||||||
/* Don't call mark new key at all: */
|
/* Don't call mark new key at all: */
|
||||||
#define BTREE_INSERT_NOMARK (1 << __BTREE_INSERT_NOMARK)
|
#define BTREE_INSERT_NOMARK (1 << __BTREE_INSERT_NOMARK)
|
||||||
|
|
||||||
#define BTREE_INSERT_NO_CLEAR_REPLICAS (1 << __BTREE_INSERT_NO_CLEAR_REPLICAS)
|
|
||||||
|
|
||||||
#define BTREE_INSERT_BUCKET_INVALIDATE (1 << __BTREE_INSERT_BUCKET_INVALIDATE)
|
#define BTREE_INSERT_BUCKET_INVALIDATE (1 << __BTREE_INSERT_BUCKET_INVALIDATE)
|
||||||
|
|
||||||
/* Don't block on allocation failure (for new btree nodes: */
|
/* Don't block on allocation failure (for new btree nodes: */
|
||||||
|
@ -515,44 +515,18 @@ static inline int do_bch2_trans_commit(struct btree_trans *trans,
|
|||||||
{
|
{
|
||||||
struct btree_insert_entry *i;
|
struct btree_insert_entry *i;
|
||||||
struct btree_iter *iter;
|
struct btree_iter *iter;
|
||||||
unsigned idx, u64s, journal_preres_u64s = 0;
|
unsigned idx;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
/*
|
trans_for_each_update(trans, i)
|
||||||
* note: running triggers will append more updates to the list of
|
BUG_ON(!btree_node_intent_locked(i->iter, 0));
|
||||||
* updates as we're walking it:
|
|
||||||
*/
|
|
||||||
trans_for_each_update(trans, i) {
|
|
||||||
/* we know trans->nounlock won't be set here: */
|
|
||||||
if (unlikely(!(i->iter->locks_want < 1
|
|
||||||
? __bch2_btree_iter_upgrade(i->iter, 1)
|
|
||||||
: i->iter->uptodate <= BTREE_ITER_NEED_PEEK))) {
|
|
||||||
trace_trans_restart_upgrade(trans->ip);
|
|
||||||
return -EINTR;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (likely(!(trans->flags & BTREE_INSERT_NOMARK)) &&
|
|
||||||
update_has_trans_triggers(i)) {
|
|
||||||
ret = bch2_trans_mark_update(trans, i->iter, i->k);
|
|
||||||
if (unlikely(ret)) {
|
|
||||||
if (ret == -EINTR)
|
|
||||||
trace_trans_restart_mark(trans->ip);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
u64s = jset_u64s(i->k->k.u64s);
|
|
||||||
if (0)
|
|
||||||
journal_preres_u64s += u64s;
|
|
||||||
trans->journal_u64s += u64s;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = bch2_journal_preres_get(&trans->c->journal,
|
ret = bch2_journal_preres_get(&trans->c->journal,
|
||||||
&trans->journal_preres, journal_preres_u64s,
|
&trans->journal_preres, trans->journal_preres_u64s,
|
||||||
JOURNAL_RES_GET_NONBLOCK);
|
JOURNAL_RES_GET_NONBLOCK);
|
||||||
if (unlikely(ret == -EAGAIN))
|
if (unlikely(ret == -EAGAIN))
|
||||||
ret = bch2_trans_journal_preres_get_cold(trans,
|
ret = bch2_trans_journal_preres_get_cold(trans,
|
||||||
journal_preres_u64s);
|
trans->journal_preres_u64s);
|
||||||
if (unlikely(ret))
|
if (unlikely(ret))
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
@ -740,8 +714,7 @@ int __bch2_trans_commit(struct btree_trans *trans)
|
|||||||
{
|
{
|
||||||
struct btree_insert_entry *i = NULL;
|
struct btree_insert_entry *i = NULL;
|
||||||
struct btree_iter *iter;
|
struct btree_iter *iter;
|
||||||
unsigned orig_nr_updates = trans->nr_updates;
|
unsigned u64s;
|
||||||
unsigned orig_mem_top = trans->mem_top;
|
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
if (!trans->nr_updates)
|
if (!trans->nr_updates)
|
||||||
@ -752,26 +725,50 @@ int __bch2_trans_commit(struct btree_trans *trans)
|
|||||||
|
|
||||||
memset(&trans->journal_preres, 0, sizeof(trans->journal_preres));
|
memset(&trans->journal_preres, 0, sizeof(trans->journal_preres));
|
||||||
|
|
||||||
|
trans->journal_u64s = 0;
|
||||||
|
trans->journal_preres_u64s = 0;
|
||||||
|
|
||||||
if (!(trans->flags & BTREE_INSERT_NOCHECK_RW) &&
|
if (!(trans->flags & BTREE_INSERT_NOCHECK_RW) &&
|
||||||
unlikely(!percpu_ref_tryget(&trans->c->writes))) {
|
unlikely(!percpu_ref_tryget(&trans->c->writes))) {
|
||||||
ret = bch2_trans_commit_get_rw_cold(trans);
|
ret = bch2_trans_commit_get_rw_cold(trans);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* note: running triggers will append more updates to the list of
|
||||||
|
* updates as we're walking it:
|
||||||
|
*/
|
||||||
|
trans_for_each_update(trans, i) {
|
||||||
|
/* we know trans->nounlock won't be set here: */
|
||||||
|
if (unlikely(!(i->iter->locks_want < 1
|
||||||
|
? __bch2_btree_iter_upgrade(i->iter, 1)
|
||||||
|
: i->iter->uptodate <= BTREE_ITER_NEED_PEEK))) {
|
||||||
|
trace_trans_restart_upgrade(trans->ip);
|
||||||
|
ret = -EINTR;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (likely(!(trans->flags & BTREE_INSERT_NOMARK)) &&
|
||||||
|
update_has_trans_triggers(i)) {
|
||||||
|
ret = bch2_trans_mark_update(trans, i->iter, i->k);
|
||||||
|
if (unlikely(ret)) {
|
||||||
|
if (ret == -EINTR)
|
||||||
|
trace_trans_restart_mark(trans->ip);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
u64s = jset_u64s(i->k->k.u64s);
|
||||||
|
if (0)
|
||||||
|
trans->journal_preres_u64s += u64s;
|
||||||
|
trans->journal_u64s += u64s;
|
||||||
|
}
|
||||||
retry:
|
retry:
|
||||||
memset(&trans->journal_res, 0, sizeof(trans->journal_res));
|
memset(&trans->journal_res, 0, sizeof(trans->journal_res));
|
||||||
trans->journal_u64s = 0;
|
|
||||||
|
|
||||||
ret = do_bch2_trans_commit(trans, &i);
|
ret = do_bch2_trans_commit(trans, &i);
|
||||||
|
|
||||||
if (trans->fs_usage_deltas) {
|
|
||||||
trans->fs_usage_deltas->used = 0;
|
|
||||||
memset((void *) trans->fs_usage_deltas +
|
|
||||||
offsetof(struct replicas_delta_list, memset_start), 0,
|
|
||||||
(void *) &trans->fs_usage_deltas->memset_end -
|
|
||||||
(void *) &trans->fs_usage_deltas->memset_start);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* make sure we didn't drop or screw up locks: */
|
/* make sure we didn't drop or screw up locks: */
|
||||||
bch2_btree_trans_verify_locks(trans);
|
bch2_btree_trans_verify_locks(trans);
|
||||||
|
|
||||||
@ -793,19 +790,20 @@ out_noupdates:
|
|||||||
trans->nr_updates = 0;
|
trans->nr_updates = 0;
|
||||||
trans->mem_top = 0;
|
trans->mem_top = 0;
|
||||||
|
|
||||||
|
if (trans->fs_usage_deltas) {
|
||||||
|
trans->fs_usage_deltas->used = 0;
|
||||||
|
memset((void *) trans->fs_usage_deltas +
|
||||||
|
offsetof(struct replicas_delta_list, memset_start), 0,
|
||||||
|
(void *) &trans->fs_usage_deltas->memset_end -
|
||||||
|
(void *) &trans->fs_usage_deltas->memset_start);
|
||||||
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
err:
|
err:
|
||||||
ret = bch2_trans_commit_error(trans, i, ret);
|
ret = bch2_trans_commit_error(trans, i, 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)
|
if (ret)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
/* free updates and memory used by triggers, they'll be reexecuted: */
|
|
||||||
trans->nr_updates = orig_nr_updates;
|
|
||||||
trans->mem_top = orig_mem_top;
|
|
||||||
goto retry;
|
goto retry;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -311,8 +311,7 @@ retry:
|
|||||||
bch2_trans_commit(&trans, &disk_res, NULL,
|
bch2_trans_commit(&trans, &disk_res, NULL,
|
||||||
BTREE_INSERT_NOFAIL|
|
BTREE_INSERT_NOFAIL|
|
||||||
BTREE_INSERT_LAZY_RW|
|
BTREE_INSERT_LAZY_RW|
|
||||||
BTREE_INSERT_NOMARK_OVERWRITES|
|
BTREE_INSERT_NOMARK_OVERWRITES);
|
||||||
BTREE_INSERT_NO_CLEAR_REPLICAS);
|
|
||||||
} else {
|
} else {
|
||||||
ret = bch2_trans_commit(&trans, &disk_res, NULL,
|
ret = bch2_trans_commit(&trans, &disk_res, NULL,
|
||||||
BTREE_INSERT_NOFAIL|
|
BTREE_INSERT_NOFAIL|
|
||||||
|
Loading…
Reference in New Issue
Block a user