From 7799b248584c72062414f3a2fe052c6e8c9fe7d2 Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Fri, 3 Apr 2020 18:05:31 +0200 Subject: [PATCH 1/2] env: posix: Add missing env_mutex_trylock() function Signed-off-by: Robert Baldyga --- env/posix/ocf_env.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/env/posix/ocf_env.h b/env/posix/ocf_env.h index 55fbe0a..da9c642 100644 --- a/env/posix/ocf_env.h +++ b/env/posix/ocf_env.h @@ -226,6 +226,11 @@ static inline void env_mutex_lock(env_mutex *mutex) ENV_BUG_ON(pthread_mutex_lock(&mutex->m)); } +static inline int env_mutex_trylock(env_mutex *mutex) +{ + return pthread_mutex_trylock(&mutex->m); +} + static inline int env_mutex_lock_interruptible(env_mutex *mutex) { env_mutex_lock(mutex); From a9c36477d26d36de78c342909d2e88ffdaca877e Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Fri, 3 Apr 2020 17:56:01 +0200 Subject: [PATCH 2/2] Fix deadlock on concurrent flush at the same cache Signed-off-by: Robert Baldyga --- inc/ocf_err.h | 3 +++ src/mngt/ocf_mngt_flush.c | 25 ++++++++++++++++--------- tests/functional/pyocf/types/shared.py | 1 + 3 files changed, 20 insertions(+), 9 deletions(-) diff --git a/inc/ocf_err.h b/inc/ocf_err.h index e3e7dba..e4f71f2 100644 --- a/inc/ocf_err.h +++ b/inc/ocf_err.h @@ -102,6 +102,9 @@ typedef enum { /** Flushing of core interrupted */ OCF_ERR_FLUSHING_INTERRUPTED, + /** Another flushing operation in progress */ + OCF_ERR_FLUSH_IN_PROGRESS, + /** Adding core to core pool failed */ OCF_ERR_CANNOT_ADD_CORE_TO_POOL, diff --git a/src/mngt/ocf_mngt_flush.c b/src/mngt/ocf_mngt_flush.c index 8e41104..78e63c2 100644 --- a/src/mngt/ocf_mngt_flush.c +++ b/src/mngt/ocf_mngt_flush.c @@ -47,6 +47,11 @@ struct ocf_mngt_cache_flush_context /* target core */ ocf_core_t core; + struct { + bool lock : 1; + bool freeze : 1; + } flags; + /* management operation identifier */ enum { flush_cache = 0, @@ -87,24 +92,22 @@ static void _ocf_mngt_begin_flush(ocf_pipeline_t pipeline, void *priv, { struct ocf_mngt_cache_flush_context *context = priv; ocf_cache_t cache = context->cache; + int result; /* FIXME: need mechanism for async waiting for outstanding flushes to * finish */ - env_mutex_lock(&cache->flush_mutex); + result = env_mutex_trylock(&cache->flush_mutex); + if (result) + OCF_PL_FINISH_RET(pipeline, -OCF_ERR_FLUSH_IN_PROGRESS); + context->flags.lock = true; ocf_refcnt_freeze(&cache->refcnt.dirty); + context->flags.freeze = true; ocf_refcnt_register_zero_cb(&cache->refcnt.dirty, _ocf_mngt_begin_flush_complete, context); } -static void _ocf_mngt_end_flush(ocf_cache_t cache) -{ - ocf_refcnt_unfreeze(&cache->refcnt.dirty); - - env_mutex_unlock(&cache->flush_mutex); -} - bool ocf_mngt_core_is_dirty(ocf_core_t core) { return !!env_atomic_read(&core->runtime_meta->dirty_clines); @@ -606,7 +609,11 @@ static void _ocf_mngt_flush_finish(ocf_pipeline_t pipeline, void *priv, ocf_cache_t cache = context->cache; ocf_core_t core = context->core; - _ocf_mngt_end_flush(cache); + if (context->flags.freeze) + ocf_refcnt_unfreeze(&cache->refcnt.dirty); + + if (context->flags.lock) + env_mutex_unlock(&cache->flush_mutex); switch (context->op) { case flush_cache: diff --git a/tests/functional/pyocf/types/shared.py b/tests/functional/pyocf/types/shared.py index 70d7f49..5244b4d 100644 --- a/tests/functional/pyocf/types/shared.py +++ b/tests/functional/pyocf/types/shared.py @@ -41,6 +41,7 @@ class OcfErrorCode(IntEnum): OCF_ERR_DIRTY_SHUTDOWN = auto() OCF_ERR_DIRTY_EXISTS = auto() OCF_ERR_FLUSHING_INTERRUPTED = auto() + OCF_ERR_FLUSH_IN_PROGRESS = auto() OCF_ERR_CANNOT_ADD_CORE_TO_POOL = auto() OCF_ERR_CACHE_IN_INCOMPLETE_STATE = auto() OCF_ERR_CORE_IN_INACTIVE_STATE = auto()