diff --git a/src/mngt/ocf_mngt_cache.c b/src/mngt/ocf_mngt_cache.c index 8ed3201..5cc6667 100644 --- a/src/mngt/ocf_mngt_cache.c +++ b/src/mngt/ocf_mngt_cache.c @@ -1928,7 +1928,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) @@ -1944,19 +1943,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; @@ -1964,13 +1957,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); } @@ -1993,26 +1995,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) { @@ -2024,12 +2039,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); @@ -2084,6 +2094,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) { @@ -2093,13 +2115,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); @@ -2113,7 +2134,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)); diff --git a/tests/functional/tests/management/test_start_stop.py b/tests/functional/tests/management/test_start_stop.py index 46258e4..d765bc9 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)