diff options
author | Sverker Eriksson <[email protected]> | 2018-06-07 20:15:07 +0200 |
---|---|---|
committer | Sverker Eriksson <[email protected]> | 2018-06-07 20:15:07 +0200 |
commit | 6ccf40d1b46a3e880134994bd71836f15a3358d4 (patch) | |
tree | 006f5fa90b8ee49ef2a146c1e40ad1fa646f0368 | |
parent | a113f6117fd696ea6f84ed754055b4ec97a7ccb2 (diff) | |
download | otp-6ccf40d1b46a3e880134994bd71836f15a3358d4.tar.gz otp-6ccf40d1b46a3e880134994bd71836f15a3358d4.tar.bz2 otp-6ccf40d1b46a3e880134994bd71836f15a3358d4.zip |
erts: Fix race between ets table deletion and auto-unfix
Bug exists since ets-refs were introduced in 20.0
0d6dc895744c34c9c52fd42f4801a8a941864ae3.
Problem:
1. Process A fixates table T.
2. Process B starts deleting table T (either by ets:delete or exit)
and does tid_clear().
3. Process A exits and does proc_cleanup_fixed_table()
and get NULL from btid2tab() and deallocates DbFixation.
4. Process B continues deleting table in free_fixations_locked()
and finds the deallocated DbFixation in the fixing_procs tree.
Solution:
Wait with tid_clear() until after free_fixations_locked()
has traversed the fixing_procs tree.
-rw-r--r-- | erts/emulator/beam/erl_db.c | 7 |
1 files changed, 3 insertions, 4 deletions
diff --git a/erts/emulator/beam/erl_db.c b/erts/emulator/beam/erl_db.c index 6d4a895ef6..68d984014f 100644 --- a/erts/emulator/beam/erl_db.c +++ b/erts/emulator/beam/erl_db.c @@ -1948,8 +1948,6 @@ BIF_RETTYPE ets_delete_1(BIF_ALIST_1) save_owned_table(BIF_P, tb); } - tid_clear(BIF_P, tb); - if (is_table_named(tb)) remove_named_tab(tb, 0); @@ -1958,6 +1956,7 @@ BIF_RETTYPE ets_delete_1(BIF_ALIST_1) tb->common.heir = am_none; reds -= free_fixations_locked(BIF_P, tb); + tid_clear(BIF_P, tb); db_unlock(tb, LCK_WRITE); if (free_table_continue(BIF_P, tb, reds) < 0) { @@ -3680,7 +3679,6 @@ erts_db_process_exiting(Process *c_p, ErtsProcLocks c_p_locks) && give_away_to_heir(c_p, tb)) { break; } - tid_clear(c_p, tb); /* Clear all access bits. */ tb->common.status &= ~(DB_PROTECTED | DB_PUBLIC | DB_PRIVATE); tb->common.status |= DB_DELETE; @@ -3690,6 +3688,7 @@ erts_db_process_exiting(Process *c_p, ErtsProcLocks c_p_locks) free_heir_data(tb); reds -= free_fixations_locked(c_p, tb); + tid_clear(c_p, tb); db_unlock(tb, LCK_WRITE); state->op = FREE_OWNED_TABLE; break; @@ -3850,7 +3849,7 @@ static void free_fixations_op(DbFixation* fix, void* vctx) struct free_fixations_ctx* ctx = (struct free_fixations_ctx*) vctx; erts_aint_t diff; - ASSERT(!btid2tab(fix->tabs.btid)); + ASSERT(btid2tab(fix->tabs.btid) == ctx->tb); ASSERT(fix->counter > 0); ASSERT(ctx->tb->common.status & DB_DELETE); |