summaryrefslogtreecommitdiffstats
path: root/database/engine
diff options
context:
space:
mode:
authorMarkos Fountoulakis <44345837+mfundul@users.noreply.github.com>2019-12-09 17:01:49 +0200
committerGitHub <noreply@github.com>2019-12-09 17:01:49 +0200
commitc177a4a8fc5ae37be0e28e1680d08399b3969258 (patch)
tree21aaa544f5c22b24b3ab54c2994086414e6f1bf5 /database/engine
parentf19f0ded353b00ca90c4f1f2ef1583ba0c390435 (diff)
Fix race condition with page cache descriptors (#7478)
Diffstat (limited to 'database/engine')
-rw-r--r--database/engine/pagecache.c4
-rw-r--r--database/engine/rrdenglocking.c16
2 files changed, 13 insertions, 7 deletions
diff --git a/database/engine/pagecache.c b/database/engine/pagecache.c
index 449138b4de..7ac4512d69 100644
--- a/database/engine/pagecache.c
+++ b/database/engine/pagecache.c
@@ -429,8 +429,8 @@ void pg_cache_punch_hole(struct rrdengine_instance *ctx, struct rrdeng_page_desc
uv_rwlock_wrunlock(&pg_cache->pg_cache_rwlock);
}
pg_cache_put(ctx, descr);
-
- rrdeng_destroy_pg_cache_descr(ctx, pg_cache_descr);
+ if (descr->pg_cache_descr_state & PG_CACHE_DESCR_ALLOCATED)
+ rrdeng_try_deallocate_pg_cache_descr(ctx, descr);
destroy:
freez(descr);
pg_cache_update_metric_times(page_index);
diff --git a/database/engine/rrdenglocking.c b/database/engine/rrdenglocking.c
index 0eb9019b47..754d802a23 100644
--- a/database/engine/rrdenglocking.c
+++ b/database/engine/rrdenglocking.c
@@ -20,7 +20,12 @@ struct page_cache_descr *rrdeng_create_pg_cache_descr(struct rrdengine_instance
void rrdeng_destroy_pg_cache_descr(struct rrdengine_instance *ctx, struct page_cache_descr *pg_cache_descr)
{
+ /* Flush any lock and condition variable users */
+ uv_mutex_lock(&pg_cache_descr->mutex);
+ uv_mutex_unlock(&pg_cache_descr->mutex);
+
uv_cond_destroy(&pg_cache_descr->cond);
+
uv_mutex_destroy(&pg_cache_descr->mutex);
freez(pg_cache_descr);
rrd_stat_atomic_add(&ctx->stats.page_cache_descriptors, -1);
@@ -71,8 +76,9 @@ void rrdeng_page_descr_mutex_lock(struct rrdengine_instance *ctx, struct rrdeng_
continue; /* spin */
}
/* page cache descriptor is already allocated */
- assert(old_state & PG_CACHE_DESCR_ALLOCATED);
-
+ if (unlikely(!(old_state & PG_CACHE_DESCR_ALLOCATED))) {
+ fatal("Invalid page cache descriptor locking state:%#lX", old_state);
+ }
new_state = (old_users + 1) << PG_CACHE_DESCR_SHIFT;
new_state |= old_state & PG_CACHE_DESCR_FLAGS_MASK;
@@ -122,7 +128,7 @@ void rrdeng_page_descr_mutex_unlock(struct rrdengine_instance *ctx, struct rrden
pg_cache_descr = descr->pg_cache_descr;
/* caller is the only page cache descriptor user and there are no pending references on the page */
if ((old_state & PG_CACHE_DESCR_DESTROY) && (1 == old_users) &&
- !pg_cache_descr->flags && !pg_cache_descr->refcnt) {
+ !pg_cache_descr->flags && !pg_cache_descr->refcnt && !pg_cache_descr->waiters) {
new_state = PG_CACHE_DESCR_LOCKED;
ret_state = ulong_compare_and_swap(&descr->pg_cache_descr_state, old_state, new_state);
if (old_state == ret_state) {
@@ -171,7 +177,7 @@ void rrdeng_try_deallocate_pg_cache_descr(struct rrdengine_instance *ctx, struct
must_unlock = 1;
just_locked = 0;
/* Try deallocate if there are no pending references on the page */
- if (!pg_cache_descr->flags && !pg_cache_descr->refcnt) {
+ if (!pg_cache_descr->flags && !pg_cache_descr->refcnt && !pg_cache_descr->waiters) {
rrdeng_destroy_pg_cache_descr(ctx, pg_cache_descr);
we_freed = 1;
/* success */
@@ -204,13 +210,13 @@ void rrdeng_try_deallocate_pg_cache_descr(struct rrdengine_instance *ctx, struct
assert(0 == old_users);
continue; /* spin */
}
- pg_cache_descr = descr->pg_cache_descr;
/* caller is the only page cache descriptor user */
if (0 == old_users) {
new_state = old_state | PG_CACHE_DESCR_LOCKED;
ret_state = ulong_compare_and_swap(&descr->pg_cache_descr_state, old_state, new_state);
if (old_state == ret_state) {
just_locked = 1;
+ pg_cache_descr = descr->pg_cache_descr;
/* retry */
continue;
}