From 555f4772480dc4631f1c23419a816b9eece3ded4 Mon Sep 17 00:00:00 2001 From: Adam Rutkowski Date: Tue, 30 Apr 2019 15:59:20 -0400 Subject: [PATCH 01/14] Do not increment attached metadata counter on behalf of mngt requests Signed-off-by: Adam Rutkowski --- src/utils/utils_req.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/utils/utils_req.c b/src/utils/utils_req.c index 66605dc..1f20fec 100644 --- a/src/utils/utils_req.c +++ b/src/utils/utils_req.c @@ -155,6 +155,9 @@ static void start_cache_req(struct ocf_request *req) { ocf_cache_t cache = req->cache; + if (req->queue == req->cache->mngt_queue) + return; + req->d2c = 1; if (env_atomic_read(&cache->attached)) { req->d2c = 0; From 979f51612f7739f26ec900d830286aef300497e7 Mon Sep 17 00:00:00 2001 From: Adam Rutkowski Date: Mon, 8 Apr 2019 19:39:52 -0400 Subject: [PATCH 02/14] Move dirty ref counter to cache->refcnt aggregate Signed-off-by: Adam Rutkowski --- src/mngt/ocf_mngt_cache.c | 4 ++-- src/mngt/ocf_mngt_flush.c | 6 +++--- src/ocf_cache_priv.h | 6 ++++-- src/ocf_core.c | 4 ++-- 4 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/mngt/ocf_mngt_cache.c b/src/mngt/ocf_mngt_cache.c index b535415..9a34d53 100644 --- a/src/mngt/ocf_mngt_cache.c +++ b/src/mngt/ocf_mngt_cache.c @@ -2361,7 +2361,7 @@ static void ocf_mngt_cache_detach_finish(ocf_pipeline_t pipeline, struct ocf_mngt_cache_detach_context *context = priv; ocf_cache_t cache = context->cache; - ocf_refcnt_unfreeze(&cache->dirty); + ocf_refcnt_unfreeze(&cache->refcnt.dirty); if (!error) { if (!context->cache_write_error) { @@ -2422,7 +2422,7 @@ void ocf_mngt_cache_detach(ocf_cache_t cache, context->cache = cache; /* prevent dirty io */ - ocf_refcnt_freeze(&cache->dirty); + ocf_refcnt_freeze(&cache->refcnt.dirty); ocf_pipeline_next(pipeline); } diff --git a/src/mngt/ocf_mngt_flush.c b/src/mngt/ocf_mngt_flush.c index 05fcd15..f5e2af9 100644 --- a/src/mngt/ocf_mngt_flush.c +++ b/src/mngt/ocf_mngt_flush.c @@ -94,15 +94,15 @@ static void _ocf_mngt_begin_flush(ocf_pipeline_t pipeline, void *priv, * finish */ env_mutex_lock(&cache->flush_mutex); - ocf_refcnt_freeze(&cache->dirty); + ocf_refcnt_freeze(&cache->refcnt.dirty); - ocf_refcnt_register_zero_cb(&cache->dirty, + 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->dirty); + ocf_refcnt_unfreeze(&cache->refcnt.dirty); env_mutex_unlock(&cache->flush_mutex); } diff --git a/src/ocf_cache_priv.h b/src/ocf_cache_priv.h index 333ad3e..6842ca0 100644 --- a/src/ocf_cache_priv.h +++ b/src/ocf_cache_priv.h @@ -170,11 +170,13 @@ struct ocf_cache { env_atomic pending_requests; + struct { + struct ocf_refcnt dirty; + } refcnt; + env_atomic pending_cache_requests; env_waitqueue pending_cache_wq; - struct ocf_refcnt dirty; - uint32_t fallback_pt_error_threshold; env_atomic fallback_pt_error_counter; diff --git a/src/ocf_core.c b/src/ocf_core.c index 4f10335..020e271 100644 --- a/src/ocf_core.c +++ b/src/ocf_core.c @@ -156,7 +156,7 @@ static inline ocf_core_t ocf_volume_to_core(ocf_volume_t volume) static inline int ocf_io_set_dirty(ocf_cache_t cache, struct ocf_core_io *core_io) { - core_io->dirty = ocf_refcnt_inc(&cache->dirty); + core_io->dirty = ocf_refcnt_inc(&cache->refcnt.dirty); return core_io->dirty ? 0 : -EBUSY; } @@ -167,7 +167,7 @@ static inline void dec_counter_if_req_was_dirty(struct ocf_core_io *core_io, return; core_io->dirty = 0; - ocf_refcnt_dec(&cache->dirty); + ocf_refcnt_dec(&cache->refcnt.dirty); } static inline int ocf_core_validate_io(struct ocf_io *io) From dc716d6a08dd5c4f8ff9a36208083b18127c1ef3 Mon Sep 17 00:00:00 2001 From: Adam Rutkowski Date: Tue, 9 Apr 2019 14:22:33 -0400 Subject: [PATCH 03/14] Use ref counter to track attach state Signed-off-by: Adam Rutkowski --- src/engine/cache_engine.c | 2 +- src/mngt/ocf_mngt_cache.c | 28 +++++++++++++++------------- src/ocf_cache.c | 2 +- src/ocf_cache_priv.h | 7 +------ src/utils/utils_refcnt.c | 5 +++++ src/utils/utils_refcnt.h | 2 ++ src/utils/utils_req.c | 27 ++++----------------------- 7 files changed, 29 insertions(+), 44 deletions(-) diff --git a/src/engine/cache_engine.c b/src/engine/cache_engine.c index 6a23e96..19769e2 100644 --- a/src/engine/cache_engine.c +++ b/src/engine/cache_engine.c @@ -158,7 +158,7 @@ bool ocf_fallback_pt_is_on(ocf_cache_t cache) static inline bool ocf_seq_cutoff_is_on(ocf_cache_t cache) { - if (!env_atomic_read(&cache->attached)) + if (!ocf_cache_is_device_attached(cache)) return false; return (cache->device->freelist_part->curr_size <= SEQ_CUTOFF_FULL_MARGIN); diff --git a/src/mngt/ocf_mngt_cache.c b/src/mngt/ocf_mngt_cache.c index 9a34d53..9fb0877 100644 --- a/src/mngt/ocf_mngt_cache.c +++ b/src/mngt/ocf_mngt_cache.c @@ -562,6 +562,9 @@ static int _ocf_mngt_init_new_cache(struct ocf_cachemng_init_params *params) env_atomic_set(&cache->ref_count, 1); cache->owner = params->ctx; + /* start with freezed metadata ref counter to indicate detached device*/ + ocf_refcnt_freeze(&cache->refcnt.metadata); + /* Copy all required initialization parameters */ cache->cache_id = params->id; @@ -1511,9 +1514,7 @@ static void _ocf_mngt_attach_post_init(ocf_pipeline_t pipeline, context->flags.cleaner_started = true; } - env_waitqueue_init(&cache->pending_cache_wq); - - env_atomic_set(&cache->attached, 1); + ocf_refcnt_unfreeze(&cache->refcnt.metadata); ocf_pipeline_next(context->pipeline); } @@ -1769,7 +1770,6 @@ static void _ocf_mngt_cache_unplug_complete(void *priv, int error) env_vfree(cache->device); cache->device = NULL; - env_atomic_set(&cache->attached, 0); /* TODO: this should be removed from detach after 'attached' stats are better separated in statistics */ @@ -1960,7 +1960,7 @@ static void ocf_mngt_cache_stop_unplug(ocf_pipeline_t pipeline, struct ocf_mngt_cache_stop_context *context = priv; ocf_cache_t cache = context->cache; - if (!env_atomic_read(&cache->attached)) + if (!ocf_cache_is_device_attached(cache)) OCF_PL_NEXT_RET(pipeline); _ocf_mngt_cache_unplug(cache, true, &context->unplug_context, @@ -2295,19 +2295,21 @@ static void ocf_mngt_cache_detach_flush(ocf_pipeline_t pipeline, context); } +static void ocf_mngt_cache_detach_wait_pending_finish(void *priv) +{ + struct ocf_mngt_cache_detach_context *context = priv; + ocf_pipeline_next(context->pipeline); +} + static void ocf_mngt_cache_detach_wait_pending(ocf_pipeline_t pipeline, void *priv, ocf_pipeline_arg_t arg) { struct ocf_mngt_cache_detach_context *context = priv; ocf_cache_t cache = context->cache; - env_atomic_set(&cache->attached, 0); - - /* FIXME: This should be asynchronous! */ - env_waitqueue_wait(cache->pending_cache_wq, - !env_atomic_read(&cache->pending_cache_requests)); - - ocf_pipeline_next(context->pipeline); + ocf_refcnt_freeze(&cache->refcnt.metadata); + ocf_refcnt_register_zero_cb(&cache->refcnt.metadata, + ocf_mngt_cache_detach_wait_pending_finish, context); } static void ocf_mngt_cache_detach_update_metadata(ocf_pipeline_t pipeline, @@ -2406,7 +2408,7 @@ void ocf_mngt_cache_detach(ocf_cache_t cache, if (!cache->mngt_queue) OCF_CMPL_RET(cache, priv, -OCF_ERR_INVAL); - if (!env_atomic_read(&cache->attached)) + if (!ocf_cache_is_device_attached(cache)) OCF_CMPL_RET(cache, priv, -OCF_ERR_INVAL); result = ocf_pipeline_create(&pipeline, cache, diff --git a/src/ocf_cache.c b/src/ocf_cache.c index fe55415..ffc7c86 100644 --- a/src/ocf_cache.c +++ b/src/ocf_cache.c @@ -50,7 +50,7 @@ bool ocf_cache_is_running(ocf_cache_t cache) bool ocf_cache_is_device_attached(ocf_cache_t cache) { OCF_CHECK_NULL(cache); - return env_atomic_read(&(cache)->attached); + return !ocf_refcnt_frozen(&cache->refcnt.metadata); } void ocf_cache_wait_for_io_finish(ocf_cache_t cache) diff --git a/src/ocf_cache_priv.h b/src/ocf_cache_priv.h index 6842ca0..d9af32d 100644 --- a/src/ocf_cache_priv.h +++ b/src/ocf_cache_priv.h @@ -172,11 +172,9 @@ struct ocf_cache { struct { struct ocf_refcnt dirty; + struct ocf_refcnt metadata; } refcnt; - env_atomic pending_cache_requests; - env_waitqueue pending_cache_wq; - uint32_t fallback_pt_error_threshold; env_atomic fallback_pt_error_counter; @@ -197,9 +195,6 @@ struct ocf_cache { env_atomic flush_in_progress; - /* 1 if cache device attached, 0 otherwise */ - env_atomic attached; - env_atomic cleaning[OCF_IO_CLASS_MAX]; struct ocf_cleaner cleaner; diff --git a/src/utils/utils_refcnt.c b/src/utils/utils_refcnt.c index 450092a..43fda33 100644 --- a/src/utils/utils_refcnt.c +++ b/src/utils/utils_refcnt.c @@ -59,3 +59,8 @@ void ocf_refcnt_unfreeze(struct ocf_refcnt *rc) int val = env_atomic_dec_return(&rc->freeze); ENV_BUG_ON(val < 0); } + +bool ocf_refcnt_frozen(struct ocf_refcnt *rc) +{ + return !!env_atomic_read(&rc->freeze); +} diff --git a/src/utils/utils_refcnt.h b/src/utils/utils_refcnt.h index 10bb24b..ed00872 100644 --- a/src/utils/utils_refcnt.h +++ b/src/utils/utils_refcnt.h @@ -37,6 +37,8 @@ void ocf_refcnt_freeze(struct ocf_refcnt *rc); /* Cancel the effect of single ocf_refcnt_freeze call */ void ocf_refcnt_unfreeze(struct ocf_refcnt *rc); +bool ocf_refcnt_frozen(struct ocf_refcnt *rc); + /* Register callback to be called when reference counter drops to 0. * Must be called after counter is freezed. * Cannot be called until previously regsitered callback had fired. */ diff --git a/src/utils/utils_req.c b/src/utils/utils_req.c index 1f20fec..11ec35c 100644 --- a/src/utils/utils_req.c +++ b/src/utils/utils_req.c @@ -151,24 +151,6 @@ static env_allocator *_ocf_req_get_allocator( return ocf_ctx->resources.req->allocator[idx]; } -static void start_cache_req(struct ocf_request *req) -{ - ocf_cache_t cache = req->cache; - - if (req->queue == req->cache->mngt_queue) - return; - - req->d2c = 1; - if (env_atomic_read(&cache->attached)) { - req->d2c = 0; - env_atomic_inc(&cache->pending_cache_requests); - if (!env_atomic_read(&cache->attached)) { - req->d2c = 1; - env_atomic_dec(&cache->pending_cache_requests); - } - } -} - struct ocf_request *ocf_req_new(ocf_queue_t queue, ocf_core_t core, uint64_t addr, uint32_t bytes, int rw) { @@ -212,7 +194,8 @@ struct ocf_request *ocf_req_new(ocf_queue_t queue, ocf_core_t core, if (queue != cache->mngt_queue) env_atomic_inc(&cache->pending_requests); - start_cache_req(req); + req->d2c = (queue != cache->mngt_queue) && !ocf_refcnt_inc( + &cache->refcnt.metadata); env_atomic_set(&req->ref_count, 1); @@ -292,10 +275,8 @@ void ocf_req_put(struct ocf_request *req) OCF_DEBUG_TRACE(req->cache); - if (!req->d2c && !env_atomic_dec_return( - &req->cache->pending_cache_requests)) { - env_waitqueue_wake_up(&req->cache->pending_cache_wq); - } + if (!req->d2c && req->io_queue != req->cache->mngt_queue) + ocf_refcnt_dec(&req->cache->refcnt.metadata); if (req->io_queue != req->cache->mngt_queue) env_atomic_dec(&req->cache->pending_requests); From 92e9ae12f1d31f5f2a7db0378989af2bc8d9b6cd Mon Sep 17 00:00:00 2001 From: Adam Rutkowski Date: Mon, 8 Apr 2019 19:10:08 -0400 Subject: [PATCH 04/14] Wait for metadata requests in stop Signed-off-by: Adam Rutkowski --- src/mngt/ocf_mngt_cache.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/src/mngt/ocf_mngt_cache.c b/src/mngt/ocf_mngt_cache.c index 9fb0877..77b15f0 100644 --- a/src/mngt/ocf_mngt_cache.c +++ b/src/mngt/ocf_mngt_cache.c @@ -1907,15 +1907,22 @@ struct ocf_mngt_cache_stop_context { int cache_write_error; }; -static void ocf_mngt_cache_stop_wait_io(ocf_pipeline_t pipeline, +static void ocf_mngt_cache_stop_wait_metadata_io_finish(void *priv) +{ + struct ocf_mngt_cache_stop_context *context = priv; + + ocf_pipeline_next(context->pipeline); +} + +static void ocf_mngt_cache_stop_wait_metadata_io(ocf_pipeline_t pipeline, void *priv, ocf_pipeline_arg_t arg) { struct ocf_mngt_cache_stop_context *context = priv; ocf_cache_t cache = context->cache; - /* TODO: Make this asynchronous! */ - ocf_cache_wait_for_io_finish(cache); - ocf_pipeline_next(pipeline); + ocf_refcnt_freeze(&cache->refcnt.metadata); + ocf_refcnt_register_zero_cb(&cache->refcnt.metadata, + ocf_mngt_cache_stop_wait_metadata_io_finish, context); } static void ocf_mngt_cache_stop_remove_cores(ocf_pipeline_t pipeline, @@ -1995,6 +2002,9 @@ static void ocf_mngt_cache_stop_finish(ocf_pipeline_t pipeline, list_del(&cache->list); env_mutex_unlock(&ctx->lock); } else { + /* undo metadata counter freeze */ + ocf_refcnt_unfreeze(&cache->refcnt.metadata); + env_bit_clear(ocf_cache_state_stopping, &cache->cache_state); env_bit_set(ocf_cache_state_running, &cache->cache_state); } @@ -2028,7 +2038,7 @@ struct ocf_pipeline_properties ocf_mngt_cache_stop_pipeline_properties = { .priv_size = sizeof(struct ocf_mngt_cache_stop_context), .finish = ocf_mngt_cache_stop_finish, .steps = { - OCF_PL_STEP(ocf_mngt_cache_stop_wait_io), + OCF_PL_STEP(ocf_mngt_cache_stop_wait_metadata_io), OCF_PL_STEP(ocf_mngt_cache_stop_remove_cores), OCF_PL_STEP(ocf_mngt_cache_stop_unplug), OCF_PL_STEP(ocf_mngt_cache_stop_put_io_queues), From 962f9d17d1771215551a23d00e23fcadfdf783c1 Mon Sep 17 00:00:00 2001 From: Adam Rutkowski Date: Fri, 19 Apr 2019 12:12:20 -0400 Subject: [PATCH 05/14] Remove functions to wait for cache pending requests Signed-off-by: Adam Rutkowski --- inc/ocf_cache.h | 14 -------------- src/ocf_cache.c | 20 -------------------- src/ocf_cache_priv.h | 2 -- src/utils/utils_req.c | 11 ----------- src/utils/utils_req.h | 9 --------- 5 files changed, 56 deletions(-) diff --git a/inc/ocf_cache.h b/inc/ocf_cache.h index f6388e2..efd6ea1 100644 --- a/inc/ocf_cache.h +++ b/inc/ocf_cache.h @@ -160,20 +160,6 @@ bool ocf_cache_is_device_attached(ocf_cache_t cache); */ bool ocf_cache_is_running(ocf_cache_t cache); -/** - * @brief Wait for all IO to finish - * - * @param[in] cache Cache object - */ -void ocf_cache_wait_for_io_finish(ocf_cache_t cache); - -/** - * @brief Check if cache has any unfunished requests - * - * @param[in] cache Cache object - */ -bool ocf_cache_has_pending_requests(ocf_cache_t cache); - /** * @brief Check if cleaning triggered by eviction runs on the cache * diff --git a/src/ocf_cache.c b/src/ocf_cache.c index ffc7c86..eadf234 100644 --- a/src/ocf_cache.c +++ b/src/ocf_cache.c @@ -53,26 +53,6 @@ bool ocf_cache_is_device_attached(ocf_cache_t cache) return !ocf_refcnt_frozen(&cache->refcnt.metadata); } -void ocf_cache_wait_for_io_finish(ocf_cache_t cache) -{ - uint32_t req_active = 0; - - OCF_CHECK_NULL(cache); - - do { - req_active = ocf_req_get_allocated(cache); - if (req_active) - env_msleep(500); - } while (req_active); -} - -bool ocf_cache_has_pending_requests(ocf_cache_t cache) -{ - OCF_CHECK_NULL(cache); - - return ocf_req_get_allocated(cache) > 0; -} - /* * This is temporary workaround allowing to check if cleaning triggered * by eviction policy is running on the cache. This information is needed diff --git a/src/ocf_cache_priv.h b/src/ocf_cache_priv.h index d9af32d..609c73b 100644 --- a/src/ocf_cache_priv.h +++ b/src/ocf_cache_priv.h @@ -168,8 +168,6 @@ struct ocf_cache { char name[OCF_CACHE_NAME_SIZE]; - env_atomic pending_requests; - struct { struct ocf_refcnt dirty; struct ocf_refcnt metadata; diff --git a/src/utils/utils_req.c b/src/utils/utils_req.c index 11ec35c..7448ea5 100644 --- a/src/utils/utils_req.c +++ b/src/utils/utils_req.c @@ -191,9 +191,6 @@ struct ocf_request *ocf_req_new(ocf_queue_t queue, ocf_core_t core, req->core_id = core ? ocf_core_get_id(core) : 0; req->cache = cache; - if (queue != cache->mngt_queue) - env_atomic_inc(&cache->pending_requests); - req->d2c = (queue != cache->mngt_queue) && !ocf_refcnt_inc( &cache->refcnt.metadata); @@ -278,9 +275,6 @@ void ocf_req_put(struct ocf_request *req) if (!req->d2c && req->io_queue != req->cache->mngt_queue) ocf_refcnt_dec(&req->cache->refcnt.metadata); - if (req->io_queue != req->cache->mngt_queue) - env_atomic_dec(&req->cache->pending_requests); - allocator = _ocf_req_get_allocator(req->cache, req->alloc_core_line_count); if (allocator) { @@ -302,8 +296,3 @@ void ocf_req_clear_map(struct ocf_request *req) ENV_BUG_ON(env_memset(req->map, sizeof(req->map[0]) * req->core_line_count, 0)); } - -uint32_t ocf_req_get_allocated(struct ocf_cache *cache) -{ - return env_atomic_read(&cache->pending_requests); -} diff --git a/src/utils/utils_req.h b/src/utils/utils_req.h index 1d64154..c53b878 100644 --- a/src/utils/utils_req.h +++ b/src/utils/utils_req.h @@ -83,15 +83,6 @@ struct ocf_request *ocf_req_new_extended(ocf_queue_t queue, ocf_core_t core, struct ocf_request *ocf_req_new_discard(ocf_queue_t queue, ocf_core_t core, uint64_t addr, uint32_t bytes, int rw); -/** - * @brief Get number of allocated requests - * - * @param cache OCF cache instance - * - * @return Number of allocated requests - */ -uint32_t ocf_req_get_allocated(struct ocf_cache *cache); - /** * @brief Increment OCF request reference count * From 0e15c693fd05962921959d93bdc93e846e94c9be Mon Sep 17 00:00:00 2001 From: Adam Rutkowski Date: Tue, 9 Apr 2019 16:29:24 -0400 Subject: [PATCH 06/14] Return post modification value from ocf_refcnt_inc/dec If counter is frozen then increment returns 0. Signed-off-by: Adam Rutkowski --- src/ocf_core.c | 2 +- src/utils/utils_refcnt.c | 14 +++++++++----- src/utils/utils_refcnt.h | 13 +++++++------ 3 files changed, 17 insertions(+), 12 deletions(-) diff --git a/src/ocf_core.c b/src/ocf_core.c index 020e271..383cacd 100644 --- a/src/ocf_core.c +++ b/src/ocf_core.c @@ -156,7 +156,7 @@ static inline ocf_core_t ocf_volume_to_core(ocf_volume_t volume) static inline int ocf_io_set_dirty(ocf_cache_t cache, struct ocf_core_io *core_io) { - core_io->dirty = ocf_refcnt_inc(&cache->refcnt.dirty); + core_io->dirty = !!ocf_refcnt_inc(&cache->refcnt.dirty); return core_io->dirty ? 0 : -EBUSY; } diff --git a/src/utils/utils_refcnt.c b/src/utils/utils_refcnt.c index 43fda33..983a3f5 100644 --- a/src/utils/utils_refcnt.c +++ b/src/utils/utils_refcnt.c @@ -13,26 +13,30 @@ void ocf_refcnt_init(struct ocf_refcnt *rc) rc->cb = NULL; } -void ocf_refcnt_dec(struct ocf_refcnt *rc) +int ocf_refcnt_dec(struct ocf_refcnt *rc) { int val = env_atomic_dec_return(&rc->counter); ENV_BUG_ON(val < 0); if (!val && env_atomic_cmpxchg(&rc->callback, 1, 0)) rc->cb(rc->priv); + + return val; } -bool ocf_refcnt_inc(struct ocf_refcnt *rc) +int ocf_refcnt_inc(struct ocf_refcnt *rc) { + int val; + if (!env_atomic_read(&rc->freeze)) { - env_atomic_inc(&rc->counter); + val = env_atomic_inc_return(&rc->counter); if (!env_atomic_read(&rc->freeze)) - return true; + return val; else ocf_refcnt_dec(rc); } - return false; + return 0; } diff --git a/src/utils/utils_refcnt.h b/src/utils/utils_refcnt.h index ed00872..5567560 100644 --- a/src/utils/utils_refcnt.h +++ b/src/utils/utils_refcnt.h @@ -22,15 +22,16 @@ struct ocf_refcnt /* Initialize reference counter */ void ocf_refcnt_init(struct ocf_refcnt *rc); -/* Try to increment counter. Returns true if successfull, false if freezed */ -bool ocf_refcnt_inc(struct ocf_refcnt *rc); +/* Try to increment counter. Returns counter value (> 0) if successfull, 0 + * if counter is frozen */ +int ocf_refcnt_inc(struct ocf_refcnt *rc); -/* Decrement reference counter */ -void ocf_refcnt_dec(struct ocf_refcnt *rc); +/* Decrement reference counter and return post-decrement value */ +int ocf_refcnt_dec(struct ocf_refcnt *rc); /* Disallow incrementing of underlying counter - attempts to increment counter * will be failing until ocf_refcnt_unfreeze is calleed. - * It's ok to call freeze multiple times, in which case counter is freezed + * It's ok to call freeze multiple times, in which case counter is frozen * until all freeze calls are offset by a corresponding unfreeze.*/ void ocf_refcnt_freeze(struct ocf_refcnt *rc); @@ -40,7 +41,7 @@ void ocf_refcnt_unfreeze(struct ocf_refcnt *rc); bool ocf_refcnt_frozen(struct ocf_refcnt *rc); /* Register callback to be called when reference counter drops to 0. - * Must be called after counter is freezed. + * Must be called after counter is frozen. * Cannot be called until previously regsitered callback had fired. */ void ocf_refcnt_register_zero_cb(struct ocf_refcnt *rc, ocf_refcnt_cb_t cb, void *priv); From 348b0f9ab889b41f57d0ba4e5cac219198fd387a Mon Sep 17 00:00:00 2001 From: Adam Rutkowski Date: Thu, 11 Apr 2019 13:16:16 -0400 Subject: [PATCH 07/14] Async wait for cleaner completion Signed-off-by: Adam Rutkowski --- inc/ocf_cache.h | 7 -- src/eviction/lru.c | 52 ++++---- src/mngt/ocf_mngt_core.c | 250 +++++++++++++++++++++++++------------- src/ocf_cache.c | 28 ----- src/ocf_cache_priv.h | 3 +- src/utils/utils_cleaner.c | 47 +++++++ src/utils/utils_cleaner.h | 38 ++++++ 7 files changed, 281 insertions(+), 144 deletions(-) diff --git a/inc/ocf_cache.h b/inc/ocf_cache.h index efd6ea1..d2964f8 100644 --- a/inc/ocf_cache.h +++ b/inc/ocf_cache.h @@ -160,13 +160,6 @@ bool ocf_cache_is_device_attached(ocf_cache_t cache); */ bool ocf_cache_is_running(ocf_cache_t cache); -/** - * @brief Check if cleaning triggered by eviction runs on the cache - * - * @param[in] cache Cache object - */ -bool ocf_cache_has_pending_cleaning(ocf_cache_t cache); - /** * @brief Get cache mode of given cache object * diff --git a/src/eviction/lru.c b/src/eviction/lru.c index 604e1fc..3b1c21e 100644 --- a/src/eviction/lru.c +++ b/src/eviction/lru.c @@ -273,9 +273,9 @@ void evp_lru_rm_cline(ocf_cache_t cache, ocf_cache_line_t cline) static void evp_lru_clean_end(void *private_data, int error) { - env_atomic *cleaning_in_progress = private_data; + struct ocf_refcnt *counter = private_data; - env_atomic_set(cleaning_in_progress, 0); + ocf_refcnt_dec(counter); } static int evp_lru_clean_getter(ocf_cache_t cache, @@ -309,32 +309,40 @@ static int evp_lru_clean_getter(ocf_cache_t cache, static void evp_lru_clean(ocf_cache_t cache, ocf_queue_t io_queue, ocf_part_id_t part_id, uint32_t count) { - env_atomic *progress = &cache->cleaning[part_id]; + struct ocf_refcnt *counter = &cache->refcnt.cleaning[part_id]; struct ocf_user_part *part = &cache->user_parts[part_id]; + struct ocf_cleaner_attribs attribs = { + .cache_line_lock = true, + .do_sort = true, + + .cmpl_context = counter, + .cmpl_fn = evp_lru_clean_end, + + .getter = evp_lru_clean_getter, + .getter_context = &attribs, + .getter_item = part->runtime->eviction.policy.lru.dirty_tail, + + .count = count > 32 ? 32 : count, + + .io_queue = io_queue + }; + int cnt; if (ocf_mngt_is_cache_locked(cache)) return; - if (env_atomic_cmpxchg(progress, 0, 1) == 0) { - /* Initialize attributes for cleaner */ - struct ocf_cleaner_attribs attribs = { - .cache_line_lock = true, - .do_sort = true, - - .cmpl_context = progress, - .cmpl_fn = evp_lru_clean_end, - - .getter = evp_lru_clean_getter, - .getter_context = &attribs, - .getter_item = part->runtime->eviction.policy.lru.dirty_tail, - - .count = count > 32 ? 32 : count, - - .io_queue = io_queue - }; - - ocf_cleaner_fire(cache, &attribs); + cnt = ocf_refcnt_inc(counter); + if (!cnt) { + /* cleaner disabled by mngmt operation */ + return; } + if (cnt > 1) { + /* cleaning already running for this partition */ + ocf_refcnt_dec(counter); + return; + } + + ocf_cleaner_fire(cache, &attribs); } static void evp_lru_zero_line_complete(struct ocf_request *ocf_req, int error) diff --git a/src/mngt/ocf_mngt_core.c b/src/mngt/ocf_mngt_core.c index aef375a..d3b9e8b 100644 --- a/src/mngt/ocf_mngt_core.c +++ b/src/mngt/ocf_mngt_core.c @@ -560,32 +560,14 @@ err_pipeline: OCF_CMPL_RET(cache, NULL, priv, result); } -/* - * Synchronously wait until cleaning triggered by eviction finishes. - * TODO: Replace it with asynchronous mechanism. - */ -static int _ocf_cleaning_wait_for_finish(ocf_cache_t cache, int32_t timeout_ms) -{ - if (!ocf_cache_is_device_attached(cache)) - return 0; - - while (ocf_cache_has_pending_cleaning(cache)) { - env_msleep(20); - - timeout_ms -= 20; - if (timeout_ms <= 0) - return -EBUSY; - } - - return 0; -} - struct ocf_mngt_cache_remove_core_context { ocf_mngt_cache_remove_core_end_t cmpl; void *priv; ocf_pipeline_t pipeline; ocf_cache_t cache; + ocf_core_t core; const char *core_name; + struct ocf_cleaner_wait_context cleaner_wait; }; static void ocf_mngt_cache_remove_core_finish(ocf_pipeline_t pipeline, @@ -602,19 +584,13 @@ static void ocf_mngt_cache_remove_core_finish(ocf_pipeline_t pipeline, context->core_name); } + ocf_cleaner_refcnt_unfreeze(cache); + context->cmpl(context->priv, error); ocf_pipeline_destroy(context->pipeline); } -struct ocf_pipeline_properties ocf_mngt_cache_remove_core_pipeline_props = { - .priv_size = sizeof(struct ocf_mngt_cache_remove_core_context), - .finish = ocf_mngt_cache_remove_core_finish, - .steps = { - OCF_PL_STEP_TERMINATOR(), - }, -}; - static void ocf_mngt_cache_remove_core_flush_sb_complete(void *priv, int error) { struct ocf_mngt_cache_remove_core_context *context = priv; @@ -623,39 +599,13 @@ static void ocf_mngt_cache_remove_core_flush_sb_complete(void *priv, int error) error ? -OCF_ERR_WRITE_CACHE : 0); } -void ocf_mngt_cache_remove_core(ocf_core_t core, - ocf_mngt_cache_remove_core_end_t cmpl, void *priv) +static void _ocf_mngt_cache_remove_core(ocf_pipeline_t pipeline, void *priv, + ocf_pipeline_arg_t arg) { - struct ocf_mngt_cache_remove_core_context *context; - ocf_pipeline_t pipeline; - ocf_cache_t cache; - ocf_core_id_t core_id; - int result; - - OCF_CHECK_NULL(core); - - cache = ocf_core_get_cache(core); - core_id = ocf_core_get_id(core); - - if (!cache->mngt_queue) - OCF_CMPL_RET(cache, -OCF_ERR_INVAL); - - /* TODO: Make this asynchronous */ - if (_ocf_cleaning_wait_for_finish(cache, 60 * 1000)) - OCF_CMPL_RET(priv, -OCF_ERR_CACHE_IN_USE); - - result = ocf_pipeline_create(&pipeline, cache, - &ocf_mngt_cache_remove_core_pipeline_props); - if (result) - OCF_CMPL_RET(priv, result); - - context = ocf_pipeline_get_priv(pipeline); - - context->cmpl = cmpl; - context->priv = priv; - context->pipeline = pipeline; - context->cache = cache; - context->core_name = ocf_core_get_name(core); + struct ocf_mngt_cache_remove_core_context *context = priv; + ocf_cache_t cache = context->cache; + ocf_core_t core = context->core; + ocf_core_id_t core_id = ocf_core_get_id(core); ocf_core_log(core, log_debug, "Removing core\n"); @@ -675,53 +625,183 @@ void ocf_mngt_cache_remove_core(ocf_core_t core, ocf_mngt_cache_remove_core_flush_sb_complete, context); } -static int _ocf_mngt_cache_detach_core(ocf_core_t core) +static void ocf_mngt_cache_remove_core_wait_cleaning_complete(void *priv) { - struct ocf_cache *cache = core->volume.cache; - ocf_core_id_t core_id = ocf_core_get_id(core); - int status; - - status = cache_mng_core_close(cache, core_id); - if (!status) { - cache->ocf_core_inactive_count++; - env_bit_set(ocf_cache_state_incomplete, - &cache->cache_state); - } - - return status; + ocf_pipeline_t pipeline = priv; + ocf_pipeline_next(pipeline); } -void ocf_mngt_cache_detach_core(ocf_core_t core, - ocf_mngt_cache_detach_core_end_t cmpl, void *priv) +static void ocf_mngt_cache_remove_core_wait_cleaning(ocf_pipeline_t pipeline, + void *priv, ocf_pipeline_arg_t arg) { + struct ocf_mngt_cache_remove_core_context *context = priv; + ocf_cache_t cache = context->cache; + + if (!ocf_cache_is_device_attached(cache)) + OCF_PL_NEXT_RET(pipeline); + + ocf_cleaner_refcnt_freeze(cache); + ocf_cleaner_refcnt_register_zero_cb(cache, &context->cleaner_wait, + ocf_mngt_cache_remove_core_wait_cleaning_complete, + pipeline); +} + +struct ocf_pipeline_properties ocf_mngt_cache_remove_core_pipeline_props = { + .priv_size = sizeof(struct ocf_mngt_cache_remove_core_context), + .finish = ocf_mngt_cache_remove_core_finish, + .steps = { + OCF_PL_STEP(ocf_mngt_cache_remove_core_wait_cleaning), + OCF_PL_STEP(_ocf_mngt_cache_remove_core), + OCF_PL_STEP_TERMINATOR(), + }, +}; + +void ocf_mngt_cache_remove_core(ocf_core_t core, + ocf_mngt_cache_remove_core_end_t cmpl, void *priv) +{ + struct ocf_mngt_cache_remove_core_context *context; + ocf_pipeline_t pipeline; ocf_cache_t cache; - const char *core_name; int result; OCF_CHECK_NULL(core); cache = ocf_core_get_cache(core); - core_name = ocf_core_get_name(core); if (!cache->mngt_queue) OCF_CMPL_RET(cache, -OCF_ERR_INVAL); - /* TODO: Make this asynchronous */ - if (_ocf_cleaning_wait_for_finish(cache, 60 * 1000)) - OCF_CMPL_RET(priv, -OCF_ERR_CACHE_IN_USE); + result = ocf_pipeline_create(&pipeline, cache, + &ocf_mngt_cache_remove_core_pipeline_props); + if (result) + OCF_CMPL_RET(priv, result); + + context = ocf_pipeline_get_priv(pipeline); + + context->cmpl = cmpl; + context->priv = priv; + context->pipeline = pipeline; + context->cache = cache; + context->core = core; + context->core_name = ocf_core_get_name(core); + + ocf_pipeline_next(pipeline); +} + +struct ocf_mngt_cache_detach_core_context { + ocf_mngt_cache_detach_core_end_t cmpl; + void *priv; + ocf_pipeline_t pipeline; + ocf_cache_t cache; + ocf_core_t core; + const char *core_name; + struct ocf_cleaner_wait_context cleaner_wait; +}; + +static void _ocf_mngt_cache_detach_core(ocf_pipeline_t pipeline, + void *priv, ocf_pipeline_arg_t arg) +{ + struct ocf_mngt_cache_remove_core_context *context = priv; + ocf_cache_t cache = context->cache; + ocf_core_t core = context->core; + ocf_core_id_t core_id = ocf_core_get_id(core); + int status; ocf_core_log(core, log_debug, "Detaching core\n"); - result = _ocf_mngt_cache_detach_core(core); - if (!result) { + status = cache_mng_core_close(cache, core_id); + + if (status) + OCF_PL_FINISH_RET(pipeline, status); + + cache->ocf_core_inactive_count++; + env_bit_set(ocf_cache_state_incomplete, + &cache->cache_state); + ocf_pipeline_next(pipeline); +} + +static void ocf_mngt_cache_detach_core_finish(ocf_pipeline_t pipeline, + void *priv, int error) +{ + struct ocf_mngt_cache_remove_core_context *context = priv; + ocf_cache_t cache = context->cache; + + if (!error) { ocf_cache_log(cache, log_info, "Core %s successfully detached\n", - core_name); + context->core_name); } else { ocf_cache_log(cache, log_err, "Detaching core %s failed\n", - core_name); + context->core_name); } - OCF_CMPL_RET(priv, result); + ocf_cleaner_refcnt_unfreeze(context->cache); + + context->cmpl(context->priv, error); + + ocf_pipeline_destroy(context->pipeline); +} + +static void ocf_mngt_cache_detach_core_wait_cleaning_complete(void *priv) +{ + ocf_pipeline_t pipeline = priv; + ocf_pipeline_next(pipeline); +} + +static void ocf_mngt_cache_detach_core_wait_cleaning(ocf_pipeline_t pipeline, + void *priv, ocf_pipeline_arg_t arg) +{ + struct ocf_mngt_cache_remove_core_context *context = priv; + ocf_cache_t cache = context->cache; + + if (!ocf_cache_is_device_attached(cache)) + OCF_PL_NEXT_RET(pipeline); + + ocf_cleaner_refcnt_freeze(cache); + ocf_cleaner_refcnt_register_zero_cb(cache, &context->cleaner_wait, + ocf_mngt_cache_detach_core_wait_cleaning_complete, + pipeline); +} + +struct ocf_pipeline_properties ocf_mngt_cache_detach_core_pipeline_props = { + .priv_size = sizeof(struct ocf_mngt_cache_detach_core_context), + .finish = ocf_mngt_cache_detach_core_finish, + .steps = { + OCF_PL_STEP(ocf_mngt_cache_detach_core_wait_cleaning), + OCF_PL_STEP(_ocf_mngt_cache_detach_core), + OCF_PL_STEP_TERMINATOR(), + }, +}; + +void ocf_mngt_cache_detach_core(ocf_core_t core, + ocf_mngt_cache_detach_core_end_t cmpl, void *priv) +{ + struct ocf_mngt_cache_detach_core_context *context; + ocf_pipeline_t pipeline; + ocf_cache_t cache; + int result; + + OCF_CHECK_NULL(core); + + cache = ocf_core_get_cache(core); + + if (!cache->mngt_queue) + OCF_CMPL_RET(cache, -OCF_ERR_INVAL); + + result = ocf_pipeline_create(&pipeline, cache, + &ocf_mngt_cache_detach_core_pipeline_props); + if (result) + OCF_CMPL_RET(priv, result); + + context = ocf_pipeline_get_priv(pipeline); + + context->cmpl = cmpl; + context->priv = priv; + context->pipeline = pipeline; + context->cache = ocf_core_get_cache(core); + context->core = core; + context->core_name = ocf_core_get_name(core); + + ocf_pipeline_next(pipeline); } int ocf_mngt_core_set_uuid(ocf_core_t core, const struct ocf_volume_uuid *uuid) diff --git a/src/ocf_cache.c b/src/ocf_cache.c index eadf234..0970f75 100644 --- a/src/ocf_cache.c +++ b/src/ocf_cache.c @@ -53,34 +53,6 @@ bool ocf_cache_is_device_attached(ocf_cache_t cache) return !ocf_refcnt_frozen(&cache->refcnt.metadata); } -/* - * This is temporary workaround allowing to check if cleaning triggered - * by eviction policy is running on the cache. This information is needed - * to remove core from cache properly. - * - * TODO: Replace this with asynchronous notification to which remove/detach - * core pipelines can subscribe. - */ -bool ocf_cache_has_pending_cleaning(ocf_cache_t cache) -{ - struct ocf_user_part *curr_part; - ocf_part_id_t part_id; - bool cleaning_active = false; - - OCF_CHECK_NULL(cache); - - OCF_METADATA_LOCK_RD(); - for_each_part(cache, curr_part, part_id) { - if (env_atomic_read(&cache->cleaning[part_id])) { - cleaning_active = true; - break; - } - } - OCF_METADATA_UNLOCK_RD(); - - return cleaning_active; -} - ocf_cache_mode_t ocf_cache_get_mode(ocf_cache_t cache) { OCF_CHECK_NULL(cache); diff --git a/src/ocf_cache_priv.h b/src/ocf_cache_priv.h index 609c73b..aa0b824 100644 --- a/src/ocf_cache_priv.h +++ b/src/ocf_cache_priv.h @@ -171,6 +171,7 @@ struct ocf_cache { struct { struct ocf_refcnt dirty; struct ocf_refcnt metadata; + struct ocf_refcnt cleaning[OCF_IO_CLASS_MAX]; } refcnt; uint32_t fallback_pt_error_threshold; @@ -193,8 +194,6 @@ struct ocf_cache { env_atomic flush_in_progress; - env_atomic cleaning[OCF_IO_CLASS_MAX]; - struct ocf_cleaner cleaner; struct ocf_metadata_updater metadata_updater; diff --git a/src/utils/utils_cleaner.c b/src/utils/utils_cleaner.c index f221a4c..14384da 100644 --- a/src/utils/utils_cleaner.c +++ b/src/utils/utils_cleaner.c @@ -8,6 +8,7 @@ #include "../engine/engine_common.h" #include "../concurrency/ocf_concurrency.h" #include "utils_cleaner.h" +#include "utils_part.h" #include "utils_req.h" #include "utils_io.h" #include "utils_cache_line.h" @@ -1014,3 +1015,49 @@ void ocf_cleaner_sort_flush_containers(struct flush_container *fctbl, _ocf_cleaner_swap); } } + +void ocf_cleaner_refcnt_freeze(ocf_cache_t cache) +{ + struct ocf_user_part *curr_part; + ocf_part_id_t part_id; + + for_each_part(cache, curr_part, part_id) + ocf_refcnt_freeze(&cache->refcnt.cleaning[part_id]); +} + +void ocf_cleaner_refcnt_unfreeze(ocf_cache_t cache) +{ + struct ocf_user_part *curr_part; + ocf_part_id_t part_id; + + for_each_part(cache, curr_part, part_id) + ocf_refcnt_unfreeze(&cache->refcnt.cleaning[part_id]); +} + +static void ocf_cleaner_refcnt_register_zero_cb_finish(void *priv) +{ + struct ocf_cleaner_wait_context *ctx = priv; + + if (!env_atomic_dec_return(&ctx->waiting)) + ctx->cb(ctx->priv); +} + +void ocf_cleaner_refcnt_register_zero_cb(ocf_cache_t cache, + struct ocf_cleaner_wait_context *ctx, + ocf_cleaner_refcnt_zero_cb_t cb, void *priv) +{ + struct ocf_user_part *curr_part; + ocf_part_id_t part_id; + + env_atomic_set(&ctx->waiting, 1); + ctx->cb = cb; + ctx->priv = priv; + + for_each_part(cache, curr_part, part_id) { + env_atomic_inc(&ctx->waiting); + ocf_refcnt_register_zero_cb(&cache->refcnt.cleaning[part_id], + ocf_cleaner_refcnt_register_zero_cb_finish, ctx); + } + + ocf_cleaner_refcnt_register_zero_cb_finish(ctx); +} diff --git a/src/utils/utils_cleaner.h b/src/utils/utils_cleaner.h index 5773779..80d19a9 100644 --- a/src/utils/utils_cleaner.h +++ b/src/utils/utils_cleaner.h @@ -79,6 +79,18 @@ struct flush_container { struct ocf_mngt_cache_flush_context *context; }; +typedef void (*ocf_cleaner_refcnt_zero_cb_t)(void *priv); + +/** + * @brief Context for ocf_cleaner_refcnt_register_zero_cb + */ +struct ocf_cleaner_wait_context +{ + env_atomic waiting; + ocf_cleaner_refcnt_zero_cb_t cb; + void *priv; +}; + /** * @brief Run cleaning procedure * @@ -119,4 +131,30 @@ void ocf_cleaner_sort_sectors(struct flush_data *tbl, uint32_t num); void ocf_cleaner_sort_flush_containers(struct flush_container *fctbl, uint32_t num); +/** + * @brief Disable incrementing of cleaner reference counters + * + * @param cache - Cache instance + */ +void ocf_cleaner_refcnt_freeze(ocf_cache_t cache); + +/** + * @brief Enable incrementing of cleaner reference counters + * + * @param cache - Cache instance + */ +void ocf_cleaner_refcnt_unfreeze(ocf_cache_t cache); + +/** + * @brief Register callback for cleaner reference counters dropping to 0 + * + * @param cache - Cache instance + * @param ctx - Routine private context, allocated by caller to avoid ENOMEM + * @param cb - Caller callback + * @param priv - Caller callback private data + */ +void ocf_cleaner_refcnt_register_zero_cb(ocf_cache_t cache, + struct ocf_cleaner_wait_context *ctx, + ocf_cleaner_refcnt_zero_cb_t cb, void *priv); + #endif /* UTILS_CLEANER_H_ */ From af4b9b13d0d57a0c103132759f34f87099d9c005 Mon Sep 17 00:00:00 2001 From: Adam Rutkowski Date: Thu, 11 Apr 2019 13:16:34 -0400 Subject: [PATCH 08/14] Freeze / unfreeze cleaning reference counters in detach/attach Signed-off-by: Adam Rutkowski --- src/mngt/ocf_mngt_cache.c | 31 +++++++++++++++++++++++++++---- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/src/mngt/ocf_mngt_cache.c b/src/mngt/ocf_mngt_cache.c index 77b15f0..ec30c08 100644 --- a/src/mngt/ocf_mngt_cache.c +++ b/src/mngt/ocf_mngt_cache.c @@ -209,6 +209,8 @@ static void __init_partitions(ocf_cache_t cache) /* Add other partition to the cache and make it as dummy */ for (i_part = 0; i_part < OCF_IO_CLASS_MAX; i_part++) { + ocf_refcnt_freeze(&cache->refcnt.cleaning[i_part]); + if (i_part == PARTITION_DEFAULT) continue; @@ -1514,6 +1516,7 @@ static void _ocf_mngt_attach_post_init(ocf_pipeline_t pipeline, context->flags.cleaner_started = true; } + ocf_cleaner_refcnt_unfreeze(cache); ocf_refcnt_unfreeze(&cache->refcnt.metadata); ocf_pipeline_next(context->pipeline); @@ -2285,6 +2288,7 @@ struct ocf_mngt_cache_detach_context { ocf_pipeline_t pipeline; ocf_cache_t cache; int cache_write_error; + struct ocf_cleaner_wait_context cleaner_wait; }; static void ocf_mngt_cache_detach_flush_cmpl(ocf_cache_t cache, @@ -2305,13 +2309,13 @@ static void ocf_mngt_cache_detach_flush(ocf_pipeline_t pipeline, context); } -static void ocf_mngt_cache_detach_wait_pending_finish(void *priv) +static void ocf_mngt_cache_detach_stop_cache_io_finish(void *priv) { struct ocf_mngt_cache_detach_context *context = priv; ocf_pipeline_next(context->pipeline); } -static void ocf_mngt_cache_detach_wait_pending(ocf_pipeline_t pipeline, +static void ocf_mngt_cache_detach_stop_cache_io(ocf_pipeline_t pipeline, void *priv, ocf_pipeline_arg_t arg) { struct ocf_mngt_cache_detach_context *context = priv; @@ -2319,7 +2323,25 @@ static void ocf_mngt_cache_detach_wait_pending(ocf_pipeline_t pipeline, ocf_refcnt_freeze(&cache->refcnt.metadata); ocf_refcnt_register_zero_cb(&cache->refcnt.metadata, - ocf_mngt_cache_detach_wait_pending_finish, context); + ocf_mngt_cache_detach_stop_cache_io_finish, context); +} + +static void ocf_mngt_cache_detach_stop_cleaner_io_finish(void *priv) +{ + ocf_pipeline_t pipeline = priv; + ocf_pipeline_next(pipeline); +} + +static void ocf_mngt_cache_detach_stop_cleaner_io(ocf_pipeline_t pipeline, + void *priv, ocf_pipeline_arg_t arg) +{ + struct ocf_mngt_cache_detach_context *context = priv; + ocf_cache_t cache = context->cache; + + ocf_cleaner_refcnt_freeze(cache); + ocf_cleaner_refcnt_register_zero_cb(cache, &context->cleaner_wait, + ocf_mngt_cache_detach_stop_cleaner_io_finish, + pipeline); } static void ocf_mngt_cache_detach_update_metadata(ocf_pipeline_t pipeline, @@ -2399,7 +2421,8 @@ struct ocf_pipeline_properties ocf_mngt_cache_detach_pipeline_properties = { .finish = ocf_mngt_cache_detach_finish, .steps = { OCF_PL_STEP(ocf_mngt_cache_detach_flush), - OCF_PL_STEP(ocf_mngt_cache_detach_wait_pending), + OCF_PL_STEP(ocf_mngt_cache_detach_stop_cache_io), + OCF_PL_STEP(ocf_mngt_cache_detach_stop_cleaner_io), OCF_PL_STEP(ocf_mngt_cache_detach_update_metadata), OCF_PL_STEP(ocf_mngt_cache_detach_unplug), OCF_PL_STEP_TERMINATOR(), From 4251cc63e7d5b273718d5bf0c673d3368c97e98f Mon Sep 17 00:00:00 2001 From: Adam Rutkowski Date: Tue, 9 Apr 2019 18:26:58 -0400 Subject: [PATCH 09/14] Do not send zero_line request if d2c Signed-off-by: Adam Rutkowski --- src/eviction/lru.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/src/eviction/lru.c b/src/eviction/lru.c index 3b1c21e..dc95aac 100644 --- a/src/eviction/lru.c +++ b/src/eviction/lru.c @@ -362,14 +362,21 @@ static void evp_lru_zero_line(ocf_cache_t cache, ocf_queue_t io_queue, req = ocf_req_new(io_queue, &cache->core[id], addr, ocf_line_size(cache), OCF_WRITE); - if (req) { - req->info.internal = true; - req->complete = evp_lru_zero_line_complete; + if (!req) + return; - env_atomic_inc(&cache->pending_eviction_clines); - - ocf_engine_zero_line(req); + if (req->d2c) { + /* cache device is being detached */ + ocf_req_put(req); + return; } + + req->info.internal = true; + req->complete = evp_lru_zero_line_complete; + + env_atomic_inc(&cache->pending_eviction_clines); + + ocf_engine_zero_line(req); } bool evp_lru_can_evict(ocf_cache_t cache) From aafc067fa5b83e176f9686b107049c6d3181f9be Mon Sep 17 00:00:00 2001 From: Adam Rutkowski Date: Wed, 10 Apr 2019 15:59:21 -0400 Subject: [PATCH 10/14] Combine cache ref counter and valid flag into ocf_refcnt Signed-off-by: Adam Rutkowski --- src/mngt/ocf_mngt_cache.c | 7 +++---- src/mngt/ocf_mngt_common.c | 18 +++++------------- src/ocf_cache_priv.h | 11 +++++++---- 3 files changed, 15 insertions(+), 21 deletions(-) diff --git a/src/mngt/ocf_mngt_cache.c b/src/mngt/ocf_mngt_cache.c index ec30c08..eb2edf7 100644 --- a/src/mngt/ocf_mngt_cache.c +++ b/src/mngt/ocf_mngt_cache.c @@ -561,7 +561,7 @@ static int _ocf_mngt_init_new_cache(struct ocf_cachemng_init_params *params) INIT_LIST_HEAD(&cache->list); list_add_tail(&cache->list, ¶ms->ctx->caches); - env_atomic_set(&cache->ref_count, 1); + ocf_refcnt_inc(&cache->refcnt.cache); cache->owner = params->ctx; /* start with freezed metadata ref counter to indicate detached device*/ @@ -1221,7 +1221,7 @@ static int _ocf_mngt_cache_start(ocf_ctx_t ctx, ocf_cache_t *cache, cache_unlock convention. User is expected to call ocf_mngt_cache_unlock in future which would up the semaphore as well as decrement ref_count. */ - env_atomic_inc(&(*cache)->ref_count); + ocf_refcnt_inc(&(*cache)->refcnt.cache); } else { /* User did not request to lock cache instance after creation - up the semaphore here since we have acquired the lock to @@ -1244,7 +1244,6 @@ static void _ocf_mng_cache_set_valid(ocf_cache_t cache) * Clear initialization state and set the valid bit so we know * its in use. */ - cache->valid_ocf_cache_device_t = 1; env_bit_clear(ocf_cache_state_initializing, &cache->cache_state); env_bit_set(ocf_cache_state_running, &cache->cache_state); } @@ -2000,7 +1999,7 @@ static void ocf_mngt_cache_stop_finish(ocf_pipeline_t pipeline, if (!error) { env_mutex_lock(&ctx->lock); /* Mark device uninitialized */ - cache->valid_ocf_cache_device_t = 0; + ocf_refcnt_freeze(&cache->refcnt.cache); /* Remove cache from the list */ list_del(&cache->list); env_mutex_unlock(&ctx->lock); diff --git a/src/mngt/ocf_mngt_common.c b/src/mngt/ocf_mngt_common.c index a8d758f..9a6e816 100644 --- a/src/mngt/ocf_mngt_common.c +++ b/src/mngt/ocf_mngt_common.c @@ -121,7 +121,7 @@ void ocf_mngt_cache_put(ocf_cache_t cache) { OCF_CHECK_NULL(cache); - if (env_atomic_dec_return(&cache->ref_count) == 0) { + if (ocf_refcnt_dec(&cache->refcnt.cache) == 0) { ocf_metadata_deinit(cache); env_vfree(cache); } @@ -155,10 +155,7 @@ int ocf_mngt_cache_get_by_id(ocf_ctx_t ocf_ctx, ocf_cache_id_t id, ocf_cache_t * if (instance) { /* if cache is either fully initialized or during recovery */ - if (instance->valid_ocf_cache_device_t) { - /* Increase reference counter */ - env_atomic_inc(&instance->ref_count); - } else { + if (!ocf_refcnt_inc(&instance->refcnt.cache)) { /* Cache not initialized yet */ instance = NULL; } @@ -210,7 +207,8 @@ static int _ocf_mngt_cache_lock(ocf_cache_t cache, int (*lock_fn)(env_rwsem *s), int ret; /* Increment reference counter */ - env_atomic_inc(&cache->ref_count); + if (!ocf_refcnt_inc(&cache->refcnt.cache)) + return -OCF_ERR_CACHE_NOT_EXIST; env_atomic_inc(&cache->lock_waiter); ret = lock_fn(&cache->lock); @@ -266,13 +264,7 @@ int ocf_mngt_cache_read_trylock(ocf_cache_t cache) /* if cache is either fully initialized or during recovery */ static bool _ocf_mngt_cache_try_get(ocf_cache_t cache) { - if (!!cache->valid_ocf_cache_device_t) { - /* Increase reference counter */ - env_atomic_inc(&cache->ref_count); - return true; - } - - return false; + return !!ocf_refcnt_inc(&cache->refcnt.cache); } int ocf_mngt_cache_get(ocf_cache_t cache) diff --git a/src/ocf_cache_priv.h b/src/ocf_cache_priv.h index aa0b824..4533ace 100644 --- a/src/ocf_cache_priv.h +++ b/src/ocf_cache_priv.h @@ -146,13 +146,10 @@ struct ocf_cache { ocf_ctx_t owner; struct list_head list; - /* set to make valid */ - uint8_t valid_ocf_cache_device_t; + /* unset running to not serve any more I/O requests */ unsigned long cache_state; - env_atomic ref_count; - struct ocf_superblock_config *conf_meta; struct ocf_cache_device *device; @@ -169,8 +166,14 @@ struct ocf_cache { char name[OCF_CACHE_NAME_SIZE]; struct { + /* cache get/put counter */ + struct ocf_refcnt cache; + /* # of requests potentially dirtying cachelines */ struct ocf_refcnt dirty; + /* # of requests accessing attached metadata, excluding + * management reqs */ struct ocf_refcnt metadata; + /* # of forced cleaning requests (eviction path) */ struct ocf_refcnt cleaning[OCF_IO_CLASS_MAX]; } refcnt; From 84f5454b2943091268011a8d506e69aefd8100b6 Mon Sep 17 00:00:00 2001 From: Adam Rutkowski Date: Fri, 19 Apr 2019 13:06:01 -0400 Subject: [PATCH 11/14] Update unit tests to work with extedned ref counters Signed-off-by: Adam Rutkowski --- .../_cache_mng_set_cache_mode_test.c | 13 ++++++++++++- ...ocf_mngt_cache_set_fallback_pt_error_threshold.c | 12 +++++++++++- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/tests/unit/tests/mngt/ocf_mngt_cache.c/_cache_mng_set_cache_mode_test.c b/tests/unit/tests/mngt/ocf_mngt_cache.c/_cache_mng_set_cache_mode_test.c index 71fd249..69e283c 100644 --- a/tests/unit/tests/mngt/ocf_mngt_cache.c/_cache_mng_set_cache_mode_test.c +++ b/tests/unit/tests/mngt/ocf_mngt_cache.c/_cache_mng_set_cache_mode_test.c @@ -188,7 +188,7 @@ void __wrap__ocf_mngt_attach_post_init( { } -void __wrap_ocf_mngt_cache_stop_wait_io( +void __wrap_ocf_mngt_cache_stop_wait_metadata_io( ocf_pipeline_t pipeline, void *priv, ocf_pipeline_arg_t arg) { } @@ -213,6 +213,17 @@ void __wrap_ocf_mngt_cache_detach_flush( { } + +void ocf_mngt_cache_detach_stop_cache_io(ocf_pipeline_t pipeline, + void *priv, ocf_pipeline_arg_t arg) +{ +} + +void ocf_mngt_cache_detach_stop_cleaner_io(ocf_pipeline_t pipeline, + void *priv, ocf_pipeline_arg_t arg) +{ +} + void __wrap_ocf_mngt_cache_detach_wait_pending( ocf_pipeline_t pipeline, void *priv, ocf_pipeline_arg_t arg) { diff --git a/tests/unit/tests/mngt/ocf_mngt_cache.c/ocf_mngt_cache_set_fallback_pt_error_threshold.c b/tests/unit/tests/mngt/ocf_mngt_cache.c/ocf_mngt_cache_set_fallback_pt_error_threshold.c index a314362..d9e11b7 100644 --- a/tests/unit/tests/mngt/ocf_mngt_cache.c/ocf_mngt_cache_set_fallback_pt_error_threshold.c +++ b/tests/unit/tests/mngt/ocf_mngt_cache.c/ocf_mngt_cache_set_fallback_pt_error_threshold.c @@ -145,7 +145,7 @@ void __wrap__ocf_mngt_attach_post_init( { } -void __wrap_ocf_mngt_cache_stop_wait_io( +void __wrap_ocf_mngt_cache_stop_wait_metadata_io( ocf_pipeline_t pipeline, void *priv, ocf_pipeline_arg_t arg) { } @@ -170,6 +170,16 @@ void __wrap_ocf_mngt_cache_detach_flush( { } +void __wrap_ocf_mngt_cache_detach_stop_cache_io(ocf_pipeline_t pipeline, + void *priv, ocf_pipeline_arg_t arg) +{ +} + +void ocf_mngt_cache_detach_stop_cleaner_io(ocf_pipeline_t pipeline, + void *priv, ocf_pipeline_arg_t arg) +{ +} + void __wrap_ocf_mngt_cache_detach_wait_pending( ocf_pipeline_t pipeline, void *priv, ocf_pipeline_arg_t arg) { From 248558448774f1e6058f430646482b6906355277 Mon Sep 17 00:00:00 2001 From: Adam Rutkowski Date: Fri, 19 Apr 2019 13:06:31 -0400 Subject: [PATCH 12/14] Remove obsolete ocf_cache_wait_for_io_finish from pyocf Signed-off-by: Adam Rutkowski --- tests/functional/pyocf/types/cache.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/functional/pyocf/types/cache.py b/tests/functional/pyocf/types/cache.py index 80c2048..b3d444b 100644 --- a/tests/functional/pyocf/types/cache.py +++ b/tests/functional/pyocf/types/cache.py @@ -482,7 +482,6 @@ class Cache: [("cache", c_void_p), ("priv", c_void_p), ("error", c_int)] ) - self.owner.lib.ocf_cache_wait_for_io_finish(self.cache_handle) self.owner.lib.ocf_mngt_cache_stop(self.cache_handle, c, None) c.wait() From c8e6b96ecea18062292e3e689de2d416a99c20c2 Mon Sep 17 00:00:00 2001 From: Adam Rutkowski Date: Fri, 19 Apr 2019 17:01:06 -0400 Subject: [PATCH 13/14] pyocf: remove put from cache stop to match get count Signed-off-by: Adam Rutkowski --- tests/functional/pyocf/types/cache.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/functional/pyocf/types/cache.py b/tests/functional/pyocf/types/cache.py index b3d444b..7e9d294 100644 --- a/tests/functional/pyocf/types/cache.py +++ b/tests/functional/pyocf/types/cache.py @@ -302,7 +302,7 @@ class Cache: @classmethod def start_on_device(cls, device, **kwargs): - c = cls(locked=True, owner=device.owner, **kwargs) + c = cls(owner=device.owner, **kwargs) c.start_cache() try: @@ -494,7 +494,6 @@ class Cache: self.started = False self.put_and_write_unlock() - self.put() self.owner.caches.remove(self) From 1e812b4eaf993bd40a2b6ac41319d90a7bfd6386 Mon Sep 17 00:00:00 2001 From: Adam Rutkowski Date: Tue, 23 Apr 2019 18:51:53 -0400 Subject: [PATCH 14/14] Unit tests for reference counter utility Signed-off-by: Adam Rutkowski --- .../utils/utils_refcnt.c/utils_refcnt_dec.c | 62 ++++++++++ .../utils_refcnt.c/utils_refcnt_freeze.c | 116 ++++++++++++++++++ .../utils/utils_refcnt.c/utils_refcnt_inc.c | 51 ++++++++ .../utils/utils_refcnt.c/utils_refcnt_init.c | 50 ++++++++ .../utils_refcnt_register_zero_cb.c | 100 +++++++++++++++ .../utils_refcnt.c/utils_refcnt_unfreeze.c | 100 +++++++++++++++ 6 files changed, 479 insertions(+) create mode 100644 tests/unit/tests/utils/utils_refcnt.c/utils_refcnt_dec.c create mode 100644 tests/unit/tests/utils/utils_refcnt.c/utils_refcnt_freeze.c create mode 100644 tests/unit/tests/utils/utils_refcnt.c/utils_refcnt_inc.c create mode 100644 tests/unit/tests/utils/utils_refcnt.c/utils_refcnt_init.c create mode 100644 tests/unit/tests/utils/utils_refcnt.c/utils_refcnt_register_zero_cb.c create mode 100644 tests/unit/tests/utils/utils_refcnt.c/utils_refcnt_unfreeze.c diff --git a/tests/unit/tests/utils/utils_refcnt.c/utils_refcnt_dec.c b/tests/unit/tests/utils/utils_refcnt.c/utils_refcnt_dec.c new file mode 100644 index 0000000..5b05c2f --- /dev/null +++ b/tests/unit/tests/utils/utils_refcnt.c/utils_refcnt_dec.c @@ -0,0 +1,62 @@ +/* + * src/utils/utils_refcnt.c + * ocf_refcnt_dec + * + * ocf_refcnt_init + * ocf_refcnt_inc + * + */ + +#undef static + +#undef inline + + +#include +#include +#include +#include +#include "print_desc.h" + +#include "../utils/utils_refcnt.h" + + +static void ocf_refcnt_dec_test01(void **state) +{ + struct ocf_refcnt rc; + int val, val2; + + print_test_description("Decrement subtracts 1 and returns proper value"); + + ocf_refcnt_init(&rc); + + ocf_refcnt_inc(&rc); + ocf_refcnt_inc(&rc); + ocf_refcnt_inc(&rc); + + val = ocf_refcnt_dec(&rc); + assert_int_equal(2, val); + val2 = env_atomic_read(&rc.counter); + assert_int_equal(2, val2); + + val = ocf_refcnt_dec(&rc); + assert_int_equal(1, val); + val2 = env_atomic_read(&rc.counter); + assert_int_equal(1, val2); + + val = ocf_refcnt_dec(&rc); + assert_int_equal(0, val); + val2 = env_atomic_read(&rc.counter); + assert_int_equal(0, val2); +} + +int main(void) +{ + const struct CMUnitTest tests[] = { + cmocka_unit_test(ocf_refcnt_dec_test01) + }; + + print_message("Unit test of src/utils/utils_refcnt.c"); + + return cmocka_run_group_tests(tests, NULL, NULL); +} diff --git a/tests/unit/tests/utils/utils_refcnt.c/utils_refcnt_freeze.c b/tests/unit/tests/utils/utils_refcnt.c/utils_refcnt_freeze.c new file mode 100644 index 0000000..bce92b0 --- /dev/null +++ b/tests/unit/tests/utils/utils_refcnt.c/utils_refcnt_freeze.c @@ -0,0 +1,116 @@ +/* + * src/utils/utils_refcnt.c + * ocf_refcnt_freeze + * + * ocf_refcnt_init + * ocf_refcnt_inc + * ocf_refcnt_dec + * + */ + +#undef static + +#undef inline + + +#include +#include +#include +#include +#include "print_desc.h" + +#include "../utils/utils_refcnt.h" + + +static void ocf_refcnt_freeze_test01(void **state) +{ + struct ocf_refcnt rc; + int val; + + print_test_description("Freeze increments freeze counter"); + + ocf_refcnt_init(&rc); + + ocf_refcnt_freeze(&rc); + assert_int_equal(1, env_atomic_read(&rc.freeze)); + + ocf_refcnt_freeze(&rc); + assert_int_equal(2, env_atomic_read(&rc.freeze)); +} + +static void ocf_refcnt_freeze_test02(void **state) +{ + struct ocf_refcnt rc; + int val; + + print_test_description("Increment returns 0 for frozen counter"); + + ocf_refcnt_init(&rc); + + ocf_refcnt_inc(&rc); + ocf_refcnt_inc(&rc); + ocf_refcnt_inc(&rc); + + ocf_refcnt_freeze(&rc); + + val = ocf_refcnt_inc(&rc); + + assert_int_equal(0, val); +} + +static void ocf_refcnt_freeze_test03(void **state) +{ + struct ocf_refcnt rc; + int val, val2; + + print_test_description("Freeze bocks increment"); + + ocf_refcnt_init(&rc); + + val = ocf_refcnt_inc(&rc); + val = ocf_refcnt_inc(&rc); + val = ocf_refcnt_inc(&rc); + + ocf_refcnt_freeze(&rc); + + ocf_refcnt_inc(&rc); + + val2 = env_atomic_read(&rc.counter); + + assert_int_equal(val, val2); +} + +static void ocf_refcnt_freeze_test04(void **state) +{ + struct ocf_refcnt rc; + int val, val2; + + print_test_description("Freeze allows decrement"); + + ocf_refcnt_init(&rc); + + val = ocf_refcnt_inc(&rc); + val = ocf_refcnt_inc(&rc); + val = ocf_refcnt_inc(&rc); + + ocf_refcnt_freeze(&rc); + + val2 = ocf_refcnt_dec(&rc); + assert_int_equal(val2, val - 1); + + val2 = ocf_refcnt_dec(&rc); + assert_int_equal(val2, val - 2); +} +int main(void) +{ + const struct CMUnitTest tests[] = { + cmocka_unit_test(ocf_refcnt_freeze_test01), + cmocka_unit_test(ocf_refcnt_freeze_test02), + cmocka_unit_test(ocf_refcnt_freeze_test03), + cmocka_unit_test(ocf_refcnt_freeze_test04), + }; + + print_message("Unit test of src/utils/utils_refcnt.c"); + + return cmocka_run_group_tests(tests, NULL, NULL); +} diff --git a/tests/unit/tests/utils/utils_refcnt.c/utils_refcnt_inc.c b/tests/unit/tests/utils/utils_refcnt.c/utils_refcnt_inc.c new file mode 100644 index 0000000..cd9de65 --- /dev/null +++ b/tests/unit/tests/utils/utils_refcnt.c/utils_refcnt_inc.c @@ -0,0 +1,51 @@ +/* + * src/utils/utils_refcnt.c + * ocf_refcnt_inc + * + * ocf_refcnt_init + * ocf_refcnt_dec + * + */ + +#undef static + +#undef inline + + +#include +#include +#include +#include +#include "print_desc.h" + +#include "../utils/utils_refcnt.h" + + +static void ocf_refcnt_inc_test(void **state) +{ + struct ocf_refcnt rc; + int val; + + print_test_description("Increment adds 1 and returns proper value"); + + ocf_refcnt_init(&rc); + + val = ocf_refcnt_inc(&rc); + assert_int_equal(1, val); + assert_int_equal(1, env_atomic_read(&rc.counter)); + + val = ocf_refcnt_inc(&rc); + assert_int_equal(2, val); + assert_int_equal(2, env_atomic_read(&rc.counter)); +} + +int main(void) +{ + const struct CMUnitTest tests[] = { + cmocka_unit_test(ocf_refcnt_inc_test) + }; + + print_message("Unit test of src/utils/utils_refcnt.c"); + + return cmocka_run_group_tests(tests, NULL, NULL); +} diff --git a/tests/unit/tests/utils/utils_refcnt.c/utils_refcnt_init.c b/tests/unit/tests/utils/utils_refcnt.c/utils_refcnt_init.c new file mode 100644 index 0000000..09b3251 --- /dev/null +++ b/tests/unit/tests/utils/utils_refcnt.c/utils_refcnt_init.c @@ -0,0 +1,50 @@ +/* + * src/utils/utils_refcnt.c + * ocf_refcnt_init + * + * INSERT HERE LIST OF FUNCTIONS YOU WANT TO LEAVE + * ONE FUNCTION PER LINE + * + */ + +#undef static + +#undef inline + + +#include +#include +#include +#include +#include "print_desc.h" + +#include "../utils/utils_refcnt.h" + + +static void ocf_refcnt_init_test(void **state) +{ + struct ocf_refcnt rc; + + print_test_description("Reference counter is properly initialized"); + + env_atomic_set(&rc.counter, 1); + env_atomic_set(&rc.freeze, 1); + env_atomic_set(&rc.callback, 1); + + ocf_refcnt_init(&rc); + + assert_int_equal(0, env_atomic_read(&rc.counter)); + assert_int_equal(0, env_atomic_read(&rc.freeze)); + assert_int_equal(0, env_atomic_read(&rc.cb)); +} + +int main(void) +{ + const struct CMUnitTest tests[] = { + cmocka_unit_test(ocf_refcnt_init_test) + }; + + print_message("Unit test of src/utils/utils_refcnt.c"); + + return cmocka_run_group_tests(tests, NULL, NULL); +} diff --git a/tests/unit/tests/utils/utils_refcnt.c/utils_refcnt_register_zero_cb.c b/tests/unit/tests/utils/utils_refcnt.c/utils_refcnt_register_zero_cb.c new file mode 100644 index 0000000..72cfd8e --- /dev/null +++ b/tests/unit/tests/utils/utils_refcnt.c/utils_refcnt_register_zero_cb.c @@ -0,0 +1,100 @@ +/* + * src/utils/utils_refcnt.c + * ocf_refcnt_register_zero_cb + * + * ocf_refcnt_init + * ocf_refcnt_inc + * ocf_refcnt_dec + * ocf_refcnt_freeze +* + */ + +#undef static + +#undef inline + + +#include +#include +#include +#include +#include "print_desc.h" + +#include "../utils/utils_refcnt.h" + +static void zero_cb(void *ctx) +{ + function_called(); + check_expected_ptr(ctx); +} + +static void ocf_refcnt_register_zero_cb_test01(void **state) +{ + struct ocf_refcnt rc; + int val; + void *ptr = 0x12345678; + + print_test_description("Callback fires when counter drops to 0"); + + /* cnt = 2 */ + ocf_refcnt_init(&rc); + ocf_refcnt_inc(&rc); + ocf_refcnt_inc(&rc); + + /* freeze and register cb */ + ocf_refcnt_freeze(&rc); + ocf_refcnt_register_zero_cb(&rc, zero_cb, ptr); + + /* 2 -> 1 */ + ocf_refcnt_dec(&rc); + + val = env_atomic_read(&rc.callback); + assert_int_equal(1, val); + + /* expect callback now */ + expect_function_calls(zero_cb, 1); + expect_value(zero_cb, ctx, ptr); + + /* 1 -> 0 */ + ocf_refcnt_dec(&rc); + + val = env_atomic_read(&rc.callback); + assert_int_equal(0, val); +} + +static void ocf_refcnt_register_zero_cb_test02(void **state) +{ + struct ocf_refcnt rc; + int val; + void *ptr = 0x12345678; + + print_test_description("Callback fires when counter is already 0"); + + /* cnt = 0 */ + ocf_refcnt_init(&rc); + + /* freeze */ + ocf_refcnt_freeze(&rc); + + /* expect callback now */ + expect_function_calls(zero_cb, 1); + expect_value(zero_cb, ctx, ptr); + + /* regiser callback */ + ocf_refcnt_register_zero_cb(&rc, zero_cb, ptr); + + val = env_atomic_read(&rc.callback); + assert_int_equal(0, val); +} + +int main(void) +{ + const struct CMUnitTest tests[] = { + cmocka_unit_test(ocf_refcnt_register_zero_cb_test01), + cmocka_unit_test(ocf_refcnt_register_zero_cb_test02), + }; + + print_message("Unit test of src/utils/utils_refcnt.c"); + + return cmocka_run_group_tests(tests, NULL, NULL); +} diff --git a/tests/unit/tests/utils/utils_refcnt.c/utils_refcnt_unfreeze.c b/tests/unit/tests/utils/utils_refcnt.c/utils_refcnt_unfreeze.c new file mode 100644 index 0000000..bc305a5 --- /dev/null +++ b/tests/unit/tests/utils/utils_refcnt.c/utils_refcnt_unfreeze.c @@ -0,0 +1,100 @@ +/* + * src/utils/utils_refcnt.c + * ocf_refcnt_unfreeze + * + * ocf_refcnt_init + * ocf_refcnt_inc + * ocf_refcnt_dec + * ocf_refcnt_freeze + * + */ + +#undef static + +#undef inline + + +#include +#include +#include +#include +#include "print_desc.h" + +#include "../utils/utils_refcnt.h" + + +static void ocf_refcnt_unfreeze_test01(void **state) +{ + struct ocf_refcnt rc; + int val, val2; + + print_test_description("Unfreeze decrements freeze counter"); + + ocf_refcnt_init(&rc); + + ocf_refcnt_freeze(&rc); + ocf_refcnt_freeze(&rc); + val = env_atomic_read(&rc.freeze); + + ocf_refcnt_unfreeze(&rc); + val2 = env_atomic_read(&rc.freeze); + assert_int_equal(val2, val - 1); + + ocf_refcnt_unfreeze(&rc); + val2 = env_atomic_read(&rc.freeze); + assert_int_equal(val2, val - 2); + +} + +static void ocf_refcnt_unfreeze_test02(void **state) +{ + struct ocf_refcnt rc; + int val, val2; + + print_test_description("Unfreezed counter can be incremented"); + + ocf_refcnt_init(&rc); + + val = ocf_refcnt_inc(&rc); + ocf_refcnt_freeze(&rc); + ocf_refcnt_unfreeze(&rc); + val2 = ocf_refcnt_inc(&rc); + + assert_int_equal(val2, val + 1); +} + +static void ocf_refcnt_unfreeze_test03(void **state) +{ + struct ocf_refcnt rc; + int val, val2; + + print_test_description("Two freezes require two unfreezes"); + + ocf_refcnt_init(&rc); + + val = ocf_refcnt_inc(&rc); + ocf_refcnt_freeze(&rc); + ocf_refcnt_freeze(&rc); + ocf_refcnt_unfreeze(&rc); + val2 = ocf_refcnt_inc(&rc); + + assert_int_equal(0, val2); + + ocf_refcnt_unfreeze(&rc); + val2 = ocf_refcnt_inc(&rc); + + assert_int_equal(val2, val + 1); +} + +int main(void) +{ + const struct CMUnitTest tests[] = { + cmocka_unit_test(ocf_refcnt_unfreeze_test01), + cmocka_unit_test(ocf_refcnt_unfreeze_test02), + cmocka_unit_test(ocf_refcnt_unfreeze_test03), + }; + + print_message("Unit test of src/utils/utils_refcnt.c"); + + return cmocka_run_group_tests(tests, NULL, NULL); +}