From 7685b70810d9c6b3014d635021f425c1b3d0fa4a Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Mon, 2 Oct 2023 11:26:42 +0200 Subject: [PATCH] Protect cache lock against locking during lock deinitialization Signed-off-by: Robert Baldyga Signed-off-by: Michal Mielewczyk --- src/mngt/ocf_mngt_cache.c | 6 ++--- src/mngt/ocf_mngt_common.c | 47 ++++++++++++++++++++++++++++++++++---- src/ocf_cache_priv.h | 3 +++ 3 files changed, 49 insertions(+), 7 deletions(-) diff --git a/src/mngt/ocf_mngt_cache.c b/src/mngt/ocf_mngt_cache.c index 94147c9..ee08ad4 100644 --- a/src/mngt/ocf_mngt_cache.c +++ b/src/mngt/ocf_mngt_cache.c @@ -2317,14 +2317,14 @@ static void _ocf_mngt_cache_dealloc(void *priv) static void ocf_mngt_cache_remove(ocf_ctx_t ctx, ocf_cache_t cache) { + /* Deinitialize cache lock */ + ocf_mngt_cache_lock_deinit(cache); + /* Mark device uninitialized */ env_refcnt_freeze(&cache->refcnt.cache); env_refcnt_register_zero_cb(&cache->refcnt.cache, _ocf_mngt_cache_dealloc, cache); - /* Deinitialize locks */ - ocf_mngt_cache_lock_deinit(cache); - env_spinlock_destroy(&cache->io_queues_lock); env_mutex_destroy(&cache->flush_mutex); diff --git a/src/mngt/ocf_mngt_common.c b/src/mngt/ocf_mngt_common.c index d292322..5a9a3bc 100644 --- a/src/mngt/ocf_mngt_common.c +++ b/src/mngt/ocf_mngt_common.c @@ -238,9 +238,15 @@ static void _ocf_mngt_cache_lock(ocf_cache_t cache, if (ocf_mngt_cache_get(cache)) OCF_CMPL_RET(cache, priv, -OCF_ERR_CACHE_NOT_EXIST); + if (!env_refcnt_inc(&cache->refcnt.lock)) { + ocf_mngt_cache_put(cache); + OCF_CMPL_RET(cache, priv, -OCF_ERR_CACHE_NOT_EXIST); + } + waiter = ocf_async_lock_new_waiter(&cache->lock, _ocf_mngt_cache_lock_complete); if (!waiter) { + env_refcnt_dec(&cache->refcnt.lock); ocf_mngt_cache_put(cache); OCF_CMPL_RET(cache, priv, -OCF_ERR_NO_MEM); } @@ -252,20 +258,26 @@ static void _ocf_mngt_cache_lock(ocf_cache_t cache, context->priv = priv; lock_fn(waiter); + env_refcnt_dec(&cache->refcnt.lock); } static int _ocf_mngt_cache_trylock(ocf_cache_t cache, ocf_trylock_fn_t trylock_fn, ocf_unlock_fn_t unlock_fn) { - int result; + int result = 0; if (ocf_mngt_cache_get(cache)) return -OCF_ERR_CACHE_NOT_EXIST; + if (!env_refcnt_inc(&cache->refcnt.lock)) { + ocf_mngt_cache_put(cache); + return -OCF_ERR_CACHE_NOT_EXIST; + } + result = trylock_fn(&cache->lock); if (result) { ocf_mngt_cache_put(cache); - return result; + goto out; } if (env_bit_test(ocf_cache_state_stopping, &cache->cache_state)) { @@ -274,6 +286,8 @@ static int _ocf_mngt_cache_trylock(ocf_cache_t cache, result = -OCF_ERR_CACHE_NOT_EXIST; } +out: + env_refcnt_dec(&cache->refcnt.lock); return result; } @@ -286,13 +300,38 @@ static void _ocf_mngt_cache_unlock(ocf_cache_t cache, int ocf_mngt_cache_lock_init(ocf_cache_t cache) { - return ocf_async_lock_init(&cache->lock, + int result; + + result = env_refcnt_init(&cache->refcnt.lock, "lock", sizeof("lock")); + if (result) + return result; + + result = ocf_async_lock_init(&cache->lock, sizeof(struct ocf_mngt_cache_lock_context)); + if (result) + env_refcnt_deinit(&cache->refcnt.lock); + + return result; +} + +static void _ocf_mngt_cache_lock_deinit(void *priv) +{ + ocf_cache_t cache = priv; + + ocf_async_lock_deinit(&cache->lock); + env_refcnt_dec(&cache->refcnt.cache); + env_refcnt_deinit(&cache->refcnt.lock); } void ocf_mngt_cache_lock_deinit(ocf_cache_t cache) { - ocf_async_lock_deinit(&cache->lock); + bool cache_get; + + cache_get = env_refcnt_inc(&cache->refcnt.cache); + ENV_BUG_ON(!cache_get); + env_refcnt_freeze(&cache->refcnt.lock); + env_refcnt_register_zero_cb(&cache->refcnt.lock, + _ocf_mngt_cache_lock_deinit, cache); } void ocf_mngt_cache_lock(ocf_cache_t cache, diff --git a/src/ocf_cache_priv.h b/src/ocf_cache_priv.h index 7c9c0a3..49b856c 100644 --- a/src/ocf_cache_priv.h +++ b/src/ocf_cache_priv.h @@ -86,6 +86,9 @@ struct ocf_cache { struct env_refcnt metadata; /* # of requests in d2c mode */ struct env_refcnt d2c; + /* # of unsettled cache lock operations (lock not acquired, + * waiter not added yet) */ + struct env_refcnt lock; } refcnt; struct {