From 4f04b2762f642341c0f77c1b9e5a59f872463d9d Mon Sep 17 00:00:00 2001 From: Adam Rutkowski Date: Thu, 27 Jun 2019 11:54:28 -0400 Subject: [PATCH 1/2] Simplified stop path for cache detached case When cache is detached we cannot assume there is a management queue created. This change introduces simplified cache stop path, performing all the necessary deinit without using IO queues. Signed-off-by: Adam Rutkowski --- src/mngt/ocf_mngt_cache.c | 78 ++++++++++++++++++++++++--------------- 1 file changed, 49 insertions(+), 29 deletions(-) diff --git a/src/mngt/ocf_mngt_cache.c b/src/mngt/ocf_mngt_cache.c index fca2ab8..359c576 100644 --- a/src/mngt/ocf_mngt_cache.c +++ b/src/mngt/ocf_mngt_cache.c @@ -1848,7 +1848,6 @@ struct ocf_mngt_cache_stop_context { ocf_ctx_t ctx; char cache_name[OCF_CACHE_NAME_SIZE]; int cache_write_error; - bool cache_attached; }; static void ocf_mngt_cache_stop_wait_metadata_io_finish(void *priv) @@ -1864,19 +1863,13 @@ static void ocf_mngt_cache_stop_wait_metadata_io(ocf_pipeline_t pipeline, struct ocf_mngt_cache_stop_context *context = priv; ocf_cache_t cache = context->cache; - if (!context->cache_attached) - OCF_PL_NEXT_RET(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, - void *priv, ocf_pipeline_arg_t arg) +static void _ocf_mngt_cache_stop_remove_cores(ocf_cache_t cache, bool attached) { - struct ocf_mngt_cache_stop_context *context = priv; - ocf_cache_t cache = context->cache; ocf_core_t core; ocf_core_id_t core_id; int no = cache->conf_meta->core_count; @@ -1884,13 +1877,22 @@ static void ocf_mngt_cache_stop_remove_cores(ocf_pipeline_t pipeline, /* All exported objects removed, cleaning up rest. */ for_each_core(cache, core, core_id) { cache_mngt_core_remove_from_cache(core); - if (context->cache_attached) + if (attached) cache_mngt_core_remove_from_cleaning_pol(core); cache_mngt_core_close(core); if (--no == 0) break; } ENV_BUG_ON(cache->conf_meta->core_count != 0); +} + +static void ocf_mngt_cache_stop_remove_cores(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; + + _ocf_mngt_cache_stop_remove_cores(cache, true); ocf_pipeline_next(pipeline); } @@ -1913,26 +1915,39 @@ 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 (!context->cache_attached) - OCF_PL_NEXT_RET(pipeline); - _ocf_mngt_cache_unplug(cache, true, &context->unplug_context, ocf_mngt_cache_stop_unplug_complete, context); } +static void _ocf_mngt_cache_put_io_queues(ocf_cache_t cache) +{ + ocf_queue_t queue, tmp_queue; + + list_for_each_entry_safe(queue, tmp_queue, &cache->io_queues, list) + ocf_queue_put(queue); +} + static void ocf_mngt_cache_stop_put_io_queues(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; - ocf_queue_t queue, tmp_queue; - list_for_each_entry_safe(queue, tmp_queue, &cache->io_queues, list) - ocf_queue_put(queue); + _ocf_mngt_cache_put_io_queues(cache); ocf_pipeline_next(pipeline); } +static void ocf_mngt_cache_remove(ocf_ctx_t ctx, ocf_cache_t cache) +{ + env_mutex_lock(&ctx->lock); + /* Mark device uninitialized */ + ocf_refcnt_freeze(&cache->refcnt.cache); + /* Remove cache from the list */ + list_del(&cache->list); + env_mutex_unlock(&ctx->lock); +} + static void ocf_mngt_cache_stop_finish(ocf_pipeline_t pipeline, void *priv, int error) { @@ -1944,12 +1959,7 @@ static void ocf_mngt_cache_stop_finish(ocf_pipeline_t pipeline, void *completion_priv; if (!error) { - env_mutex_lock(&ctx->lock); - /* Mark device uninitialized */ - ocf_refcnt_freeze(&cache->refcnt.cache); - /* Remove cache from the list */ - list_del(&cache->list); - env_mutex_unlock(&ctx->lock); + ocf_mngt_cache_remove(context->ctx, cache); } else { /* undo metadata counter freeze */ ocf_refcnt_unfreeze(&cache->refcnt.metadata); @@ -2004,6 +2014,18 @@ struct ocf_pipeline_properties ocf_mngt_cache_stop_pipeline_properties = { }, }; +static void ocf_mngt_cache_stop_detached(ocf_cache_t cache, + ocf_mngt_cache_stop_end_t cmpl, void *priv) +{ + _ocf_mngt_cache_stop_remove_cores(cache, false); + _ocf_mngt_cache_put_io_queues(cache); + ocf_mngt_cache_remove(cache->owner, cache); + ocf_cache_log(cache, log_info, "Cache %s successfully stopped\n", + ocf_cache_get_name(cache)); + cmpl(cache, priv, 0); + ocf_mngt_cache_put(cache); +} + void ocf_mngt_cache_stop(ocf_cache_t cache, ocf_mngt_cache_stop_end_t cmpl, void *priv) { @@ -2013,13 +2035,12 @@ void ocf_mngt_cache_stop(ocf_cache_t cache, OCF_CHECK_NULL(cache); - /* - * FIXME: What if creating/setting management queue failed? - * In such case we will be unable to use pipeline, and thus - * perform cache stop procedure. - */ - if (!cache->mngt_queue) - OCF_CMPL_RET(cache, priv, -OCF_ERR_INVAL); + if (!ocf_cache_is_device_attached(cache)) { + ocf_mngt_cache_stop_detached(cache, cmpl, priv); + return; + } + + ENV_BUG_ON(!cache->mngt_queue); result = ocf_pipeline_create(&pipeline, cache, &ocf_mngt_cache_stop_pipeline_properties); @@ -2033,7 +2054,6 @@ void ocf_mngt_cache_stop(ocf_cache_t cache, context->pipeline = pipeline; context->cache = cache; context->ctx = cache->owner; - context->cache_attached = ocf_cache_is_device_attached(cache); result = env_strncpy(context->cache_name, sizeof(context->cache_name), ocf_cache_get_name(cache), sizeof(context->cache_name)); From af4727675a93cd1560dcd97fbec64c8eed257909 Mon Sep 17 00:00:00 2001 From: Adam Rutkowski Date: Thu, 27 Jun 2019 12:25:50 -0400 Subject: [PATCH 2/2] pytest: simple start stop without mngmt queue test Signed-off-by: Adam Rutkowski --- .../tests/management/test_start_stop.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/tests/functional/tests/management/test_start_stop.py b/tests/functional/tests/management/test_start_stop.py index 3e86b3d..9a4541a 100644 --- a/tests/functional/tests/management/test_start_stop.py +++ b/tests/functional/tests/management/test_start_stop.py @@ -354,6 +354,25 @@ def test_start_too_small_device(pyocf_ctx, mode, cls): Cache.start_on_device(cache_device, cache_mode=mode, cache_line_size=cls) +def test_start_stop_noqueue(pyocf_ctx): + # cache object just to construct cfg conveniently + _cache = Cache(pyocf_ctx.ctx_handle) + + cache_handle = c_void_p() + status = pyocf_ctx.lib.ocf_mngt_cache_start( + pyocf_ctx.ctx_handle, byref(cache_handle), byref(_cache.cfg) + ) + assert not status, "Failed to start cache: {}".format(status) + + # stop without creating mngmt queue + c = OcfCompletion( + [("cache", c_void_p), ("priv", c_void_p), ("error", c_int)] + ) + pyocf_ctx.lib.ocf_mngt_cache_stop(cache_handle, c, None) + c.wait() + assert not c.results["error"], "Failed to stop cache: {}".format(c.results["error"]) + + def run_io_and_cache_data_if_possible(exported_obj, mode, cls, cls_no): test_data = Data(cls_no * cls)