diff --git a/inc/ocf_cache.h b/inc/ocf_cache.h index e3ff051..0305c71 100644 --- a/inc/ocf_cache.h +++ b/inc/ocf_cache.h @@ -1,6 +1,6 @@ /* * Copyright(c) 2012-2021 Intel Corporation - * Copyright(c) 2023 Huawei Technologies + * Copyright(c) 2023-2024 Huawei Technologies * SPDX-License-Identifier: BSD-3-Clause */ @@ -156,14 +156,14 @@ bool ocf_cache_is_device_attached(ocf_cache_t cache); bool ocf_cache_is_running(ocf_cache_t cache); /** - * @brief Check if cache object is initializing + * @brief Check if cache is detached * - * @param[in] cache Cache object + * @param[in] cache Cache * - * @retval 1 Caching device is initializing - * @retval 0 Caching device is not initializing + * @retval 1 Caching device is detached + * @retval 0 Caching device is not detached */ -bool ocf_cache_is_initializing(ocf_cache_t cache); +bool ocf_cache_is_detached(ocf_cache_t cache); /** * @brief Check if cache object is standby diff --git a/inc/ocf_def.h b/inc/ocf_def.h index 01d0d37..4ff2c51 100644 --- a/inc/ocf_def.h +++ b/inc/ocf_def.h @@ -1,5 +1,6 @@ /* * Copyright(c) 2012-2022 Intel Corporation + * Copyright(c) 2024 Huawei Technologies * SPDX-License-Identifier: BSD-3-Clause */ @@ -118,14 +119,14 @@ typedef enum { ocf_cache_state_stopping = 1, //!< ocf_cache_state_stopping /*!< OCF cache instance is stopping */ - ocf_cache_state_initializing = 2, //!< ocf_cache_state_initializing - /*!< OCF cache instance during initialization */ + ocf_cache_state_detached = 2, //!< ocf_cache_state_detached + /*!< OCF cache instance without caching device attached */ ocf_cache_state_incomplete = 3, //!< ocf_cache_state_incomplete /*!< OCF cache has at least one inactive core */ ocf_cache_state_standby = 4, //!< ocf_cache_state_standby - /*!< OCF is currently in standby mode */ + /*!< OCF cache is currently in standby mode */ ocf_cache_state_max //!< ocf_cache_state_max /*!< Stopper of cache state enumerator */ diff --git a/inc/ocf_err.h b/inc/ocf_err.h index a8d0563..eeb867d 100644 --- a/inc/ocf_err.h +++ b/inc/ocf_err.h @@ -1,5 +1,6 @@ /* * Copyright(c) 2012-2021 Intel Corporation + * Copyright(c) 2024 Huawei Technologies * SPDX-License-Identifier: BSD-3-Clause */ @@ -143,6 +144,9 @@ typedef enum { /** Invalid operation for cache in standby state. */ OCF_ERR_CACHE_STANDBY, + /** Invalid operation for cache in standby state. */ + OCF_ERR_CACHE_DETACHED, + /** Size of core volume doesn't match the size stored in cache metadata */ OCF_ERR_CORE_SIZE_MISMATCH, diff --git a/src/metadata/metadata_superblock.c b/src/metadata/metadata_superblock.c index ed53ea6..49d7381 100644 --- a/src/metadata/metadata_superblock.c +++ b/src/metadata/metadata_superblock.c @@ -547,6 +547,8 @@ void ocf_metadata_flush_superblock(ocf_cache_t cache, OCF_DEBUG_TRACE(cache); + ENV_BUG_ON(!ocf_cache_is_device_attached(cache)); + result = ocf_pipeline_create(&pipeline, cache, &ocf_metadata_flush_sb_pipeline_props); if (result) diff --git a/src/mngt/ocf_mngt_cache.c b/src/mngt/ocf_mngt_cache.c index c518d61..7c0ab5c 100644 --- a/src/mngt/ocf_mngt_cache.c +++ b/src/mngt/ocf_mngt_cache.c @@ -181,6 +181,8 @@ struct ocf_cache_attach_context { ocf_pipeline_t pipeline; }; +static void _ocf_mngt_cache_set_detached(ocf_cache_t cache); + static void __init_partitions(ocf_cache_t cache) { ocf_part_id_t i_part; @@ -856,7 +858,7 @@ static int _ocf_mngt_init_new_cache(struct ocf_cache_mngt_init_params *params) env_atomic_set(&(cache->last_access_ms), env_ticks_to_msecs(env_get_tick_count())); - env_bit_set(ocf_cache_state_initializing, &cache->cache_state); + _ocf_mngt_cache_set_detached(cache); params->cache = cache; params->flags.cache_alloc = true; @@ -1552,7 +1554,7 @@ static void _ocf_mngt_cache_set_valid(ocf_cache_t cache) * Clear initialization state and set the valid bit so we know * its in use. */ - env_bit_clear(ocf_cache_state_initializing, &cache->cache_state); + env_bit_clear(ocf_cache_state_detached, &cache->cache_state); env_bit_set(ocf_cache_state_running, &cache->cache_state); } @@ -1561,7 +1563,7 @@ static void _ocf_mngt_cache_set_standby(ocf_cache_t cache) /* * Clear initialization state and set the standby bit. */ - env_bit_clear(ocf_cache_state_initializing, &cache->cache_state); + env_bit_clear(ocf_cache_state_detached, &cache->cache_state); env_bit_set(ocf_cache_state_standby, &cache->cache_state); } @@ -1574,6 +1576,12 @@ static void _ocf_mngt_cache_set_active(ocf_cache_t cache) env_bit_set(ocf_cache_state_running, &cache->cache_state); } +static void _ocf_mngt_cache_set_detached(ocf_cache_t cache) +{ + env_bit_clear(ocf_cache_state_running, &cache->cache_state); + env_bit_set(ocf_cache_state_detached, &cache->cache_state); +} + static void _ocf_mngt_init_attached_nonpersistent(ocf_pipeline_t pipeline, void *priv, ocf_pipeline_arg_t arg) { @@ -1661,6 +1669,29 @@ static void _ocf_mngt_load_superblock(ocf_pipeline_t pipeline, } } +static void _ocf_mngt_attach_update_cores_atomic(ocf_pipeline_t pipeline, + void *priv, ocf_pipeline_arg_t arg) +{ + struct ocf_cache_attach_context *context = priv; + ocf_cache_t cache = context->cache; + ocf_core_t core; + ocf_core_id_t core_id; + ocf_seq_no_t core_sequence_no = 0; + + cache->conf_meta->curr_core_seq_no = 0; + + if (!ocf_volume_is_atomic(ocf_cache_get_volume(cache))) + OCF_PL_NEXT_RET(pipeline); + + for_each_core_metadata(cache, core, core_id) { + core_sequence_no = ocf_mngt_get_core_seq_no(cache); + if (core_sequence_no == OCF_SEQ_NO_INVALID) + OCF_PL_FINISH_RET(pipeline, -OCF_ERR_TOO_MANY_CORES); + + core->conf_meta->seq_no = core_sequence_no; + } +} + static void _ocf_mngt_init_cleaner(ocf_pipeline_t pipeline, void *priv, ocf_pipeline_arg_t arg) { @@ -1927,6 +1958,7 @@ struct ocf_pipeline_properties _ocf_mngt_cache_attach_pipeline_properties = { OCF_PL_STEP(_ocf_mngt_attach_check_ram), OCF_PL_STEP(_ocf_mngt_attach_prepare_metadata), OCF_PL_STEP(_ocf_mngt_test_volume), + OCF_PL_STEP(_ocf_mngt_attach_update_cores_atomic), OCF_PL_STEP(_ocf_mngt_init_cleaner), OCF_PL_STEP(_ocf_mngt_init_promotion), OCF_PL_STEP(_ocf_mngt_attach_init_metadata), @@ -1977,26 +2009,34 @@ struct _ocf_mngt_cache_unplug_context { ocf_cache_t cache; }; -struct ocf_mngt_cache_stop_context { +struct ocf_mngt_cache_unplug_context { + /* Fields that belong to cache stop pipeline */ + ocf_ctx_t ctx; + char cache_name[OCF_CACHE_NAME_SIZE]; + bool close_volume; + + /* Fields that belong to cache detach pipeline */ + struct ocf_cleaner_wait_context cleaner_wait; + bool detach_composite; + uint8_t composite_vol_id; + + /* Fields that belong to both cache detach and cache stop pipelines */ + /* unplug context - this is private structure of _ocf_mngt_cache_unplug, * it is member of stop context only to reserve memory in advance for * _ocf_mngt_cache_unplug, eliminating the possibility of ENOMEM error * at the point where we are effectively unable to handle it */ struct _ocf_mngt_cache_unplug_context unplug_context; - ocf_mngt_cache_stop_end_t cmpl; void *priv; ocf_pipeline_t pipeline; ocf_cache_t cache; - ocf_ctx_t ctx; - char cache_name[OCF_CACHE_NAME_SIZE]; int cache_write_error; - bool close_volume; }; static void ocf_mngt_cache_stop_wait_metadata_io_finish(void *priv) { - struct ocf_mngt_cache_stop_context *context = priv; + struct ocf_mngt_cache_unplug_context *context = priv; ocf_pipeline_next(context->pipeline); } @@ -2004,7 +2044,7 @@ static void ocf_mngt_cache_stop_wait_metadata_io_finish(void *priv) 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; + struct ocf_mngt_cache_unplug_context *context = priv; ocf_cache_t cache = context->cache; ocf_refcnt_freeze(&cache->refcnt.metadata); @@ -2015,7 +2055,7 @@ static void ocf_mngt_cache_stop_wait_metadata_io(ocf_pipeline_t pipeline, static void ocf_mngt_cache_stop_check_dirty(ocf_pipeline_t pipeline, void *priv, ocf_pipeline_arg_t arg) { - struct ocf_mngt_cache_stop_context *context = priv; + struct ocf_mngt_cache_unplug_context *context = priv; ocf_cache_t cache = context->cache; if (ocf_mngt_cache_is_dirty(cache)) { @@ -2051,7 +2091,7 @@ static void _ocf_mngt_cache_stop_remove_cores(ocf_cache_t cache, bool attached) 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; + struct ocf_mngt_cache_unplug_context *context = priv; ocf_cache_t cache = context->cache; _ocf_mngt_cache_stop_remove_cores(cache, true); @@ -2061,7 +2101,7 @@ static void ocf_mngt_cache_stop_remove_cores(ocf_pipeline_t pipeline, static void ocf_mngt_cache_stop_unplug_complete(void *priv, int error) { - struct ocf_mngt_cache_stop_context *context = priv; + struct ocf_mngt_cache_unplug_context *context = priv; if (error) { ENV_BUG_ON(error != -OCF_ERR_WRITE_CACHE); @@ -2078,7 +2118,7 @@ static void _ocf_mngt_cache_unplug(ocf_cache_t cache, bool stop, static void ocf_mngt_cache_stop_unplug(ocf_pipeline_t pipeline, void *priv, ocf_pipeline_arg_t arg) { - struct ocf_mngt_cache_stop_context *context = priv; + struct ocf_mngt_cache_unplug_context *context = priv; ocf_cache_t cache = context->cache; _ocf_mngt_cache_unplug(cache, true, &context->unplug_context, @@ -2096,7 +2136,7 @@ static void _ocf_mngt_cache_put_io_queues(ocf_cache_t cache) static void ocf_mngt_cache_close_cache_volume(ocf_pipeline_t pipeline, void *priv, ocf_pipeline_arg_t arg) { - struct ocf_mngt_cache_stop_context *context = priv; + struct ocf_mngt_cache_unplug_context *context = priv; ocf_cache_t cache = context->cache; ocf_volume_close(&cache->device->volume); @@ -2107,7 +2147,7 @@ static void ocf_mngt_cache_close_cache_volume(ocf_pipeline_t pipeline, static void ocf_mngt_cache_deinit_cache_volume(ocf_pipeline_t pipeline, void *priv, ocf_pipeline_arg_t arg) { - struct ocf_mngt_cache_stop_context *context = priv; + struct ocf_mngt_cache_unplug_context *context = priv; ocf_cache_t cache = context->cache; ocf_volume_deinit(&cache->device->volume); @@ -2121,10 +2161,9 @@ static void ocf_mngt_cache_deinit_cache_volume(ocf_pipeline_t pipeline, static void ocf_mngt_cache_deinit_metadata(ocf_pipeline_t pipeline, void *priv, ocf_pipeline_arg_t arg) { - struct ocf_mngt_cache_stop_context *context = priv; + struct ocf_mngt_cache_unplug_context *context = priv; ocf_cache_t cache = context->cache; - ocf_metadata_deinit_variable_size(cache); ocf_concurrency_deinit(cache); @@ -2138,7 +2177,7 @@ static void ocf_mngt_cache_deinit_metadata(ocf_pipeline_t pipeline, 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; + struct ocf_mngt_cache_unplug_context *context = priv; ocf_cache_t cache = context->cache; _ocf_mngt_cache_put_io_queues(cache); @@ -2164,7 +2203,7 @@ static void ocf_mngt_cache_remove(ocf_ctx_t ctx, ocf_cache_t cache) static void ocf_mngt_cache_stop_finish(ocf_pipeline_t pipeline, void *priv, int error) { - struct ocf_mngt_cache_stop_context *context = priv; + struct ocf_mngt_cache_unplug_context *context = priv; ocf_cache_t cache = context->cache; ocf_ctx_t ctx = context->ctx; int pipeline_error; @@ -2216,7 +2255,7 @@ static void ocf_mngt_cache_stop_finish(ocf_pipeline_t pipeline, } struct ocf_pipeline_properties ocf_mngt_cache_stop_pipeline_properties = { - .priv_size = sizeof(struct ocf_mngt_cache_stop_context), + .priv_size = sizeof(struct ocf_mngt_cache_unplug_context), .finish = ocf_mngt_cache_stop_finish, .steps = { OCF_PL_STEP(ocf_mngt_cache_stop_wait_metadata_io), @@ -2674,7 +2713,7 @@ static void _ocf_mngt_cache_load(ocf_cache_t cache, static void ocf_mngt_stop_standby_stop_prepare(ocf_pipeline_t pipeline, void *priv, ocf_pipeline_arg_t arg) { - struct ocf_mngt_cache_stop_context *context = priv; + struct ocf_mngt_cache_unplug_context *context = priv; ocf_cache_t cache = context->cache; context->close_volume = !ocf_refcnt_frozen(&cache->refcnt.metadata); @@ -2685,7 +2724,7 @@ static void ocf_mngt_stop_standby_stop_prepare(ocf_pipeline_t pipeline, static void ocf_mngt_stop_standby_stop_cleaner(ocf_pipeline_t pipeline, void *priv, ocf_pipeline_arg_t arg) { - struct ocf_mngt_cache_stop_context *context = priv; + struct ocf_mngt_cache_unplug_context *context = priv; ocf_cache_t cache = context->cache; ocf_stop_cleaner(cache); @@ -2696,7 +2735,7 @@ static void ocf_mngt_stop_standby_stop_cleaner(ocf_pipeline_t pipeline, static void ocf_mngt_cache_standby_close_cache_volume(ocf_pipeline_t pipeline, void *priv, ocf_pipeline_arg_t arg) { - struct ocf_mngt_cache_stop_context *context = priv; + struct ocf_mngt_cache_unplug_context *context = priv; ocf_cache_t cache = context->cache; if (context->close_volume) @@ -2708,7 +2747,7 @@ static void ocf_mngt_cache_standby_close_cache_volume(ocf_pipeline_t pipeline, static void ocf_mngt_cache_standby_deinit_pio(ocf_pipeline_t pipeline, void *priv, ocf_pipeline_arg_t arg) { - struct ocf_mngt_cache_stop_context *context = priv; + struct ocf_mngt_cache_unplug_context *context = priv; ocf_cache_t cache = context->cache; ocf_metadata_passive_io_ctx_deinit(cache); @@ -2720,7 +2759,7 @@ static void ocf_mngt_cache_standby_deinit_pio(ocf_pipeline_t pipeline, static void ocf_mngt_cache_standby_deinit_cache_volume(ocf_pipeline_t pipeline, void *priv, ocf_pipeline_arg_t arg) { - struct ocf_mngt_cache_stop_context *context = priv; + struct ocf_mngt_cache_unplug_context *context = priv; ocf_cache_t cache = context->cache; if (!ocf_refcnt_frozen(&cache->refcnt.metadata)) { @@ -2735,7 +2774,7 @@ static void ocf_mngt_cache_standby_deinit_cache_volume(ocf_pipeline_t pipeline, struct ocf_pipeline_properties ocf_mngt_cache_stop_standby_pipeline_properties = { - .priv_size = sizeof(struct ocf_mngt_cache_stop_context), + .priv_size = sizeof(struct ocf_mngt_cache_unplug_context), .finish = ocf_mngt_cache_stop_finish, .steps = { OCF_PL_STEP(ocf_mngt_stop_standby_stop_prepare), @@ -3040,6 +3079,11 @@ void ocf_mngt_cache_attach(ocf_cache_t cache, if (!cache->mngt_queue) OCF_CMPL_RET(cache, priv, -OCF_ERR_INVAL); + if (ocf_cache_is_device_attached(cache)) { + ocf_cache_log(cache, log_err, "Cache is already attached!\n"); + OCF_CMPL_RET(cache, priv, -OCF_ERR_INVAL); + } + result = _ocf_mngt_cache_validate_attach_cfg(cfg); if (result) OCF_CMPL_RET(cache, priv, result); @@ -3316,12 +3360,14 @@ static void ocf_mngt_cache_stop_detached(ocf_cache_t cache, void ocf_mngt_cache_stop(ocf_cache_t cache, ocf_mngt_cache_stop_end_t cmpl, void *priv) { - struct ocf_mngt_cache_stop_context *context; + struct ocf_mngt_cache_unplug_context *context; ocf_pipeline_t pipeline; OCF_CHECK_NULL(cache); if (!ocf_cache_is_device_attached(cache)) { + env_bit_set(ocf_cache_state_stopping, &cache->cache_state); + env_bit_clear(ocf_cache_state_detached, &cache->cache_state); ocf_mngt_cache_stop_detached(cache, cmpl, priv); return; } @@ -3397,6 +3443,13 @@ void ocf_mngt_cache_save(ocf_cache_t cache, OCF_CHECK_NULL(cache); + if (!ocf_cache_is_device_attached(cache)) { + ocf_cache_log(cache, log_info, "Cache is in detached state. Any changes" + " made to the cache configuration won't persist through cache " + "stop unless a caching volume is attached\n"); + OCF_CMPL_RET(cache, priv, -OCF_ERR_CACHE_DETACHED); + } + if (ocf_cache_is_standby(cache)) OCF_CMPL_RET(cache, priv, -OCF_ERR_CACHE_STANDBY); @@ -3473,6 +3526,9 @@ int ocf_mngt_cache_set_mode(ocf_cache_t cache, ocf_cache_mode_t mode) if (ocf_cache_is_standby(cache)) return -OCF_ERR_CACHE_STANDBY; + if (!ocf_cache_is_device_attached(cache)) + result = -OCF_ERR_CACHE_DETACHED; + if (!ocf_cache_mode_is_valid(mode)) { ocf_cache_log(cache, log_err, "Cache mode %u is invalid\n", mode); @@ -3498,6 +3554,9 @@ int ocf_mngt_cache_promotion_set_policy(ocf_cache_t cache, ocf_promotion_t type) if (ocf_cache_is_standby(cache)) return -OCF_ERR_CACHE_STANDBY; + if (!ocf_cache_is_device_attached(cache)) + result = -OCF_ERR_CACHE_DETACHED; + ocf_metadata_start_exclusive_access(&cache->metadata.lock); result = ocf_promotion_set_policy(cache->promotion_policy, type); @@ -3620,25 +3679,10 @@ int ocf_mngt_cache_get_fallback_pt_error_threshold(ocf_cache_t cache, return 0; } -struct ocf_mngt_cache_detach_context { - /* unplug context - this is private structure of _ocf_mngt_cache_unplug, - * it is member of detach context only to reserve memory in advance for - * _ocf_mngt_cache_unplug, eliminating the possibility of ENOMEM error - * at the point where we are effectively unable to handle it */ - struct _ocf_mngt_cache_unplug_context unplug_context; - - ocf_mngt_cache_detach_end_t cmpl; - void *priv; - 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, void *priv, int error) { - struct ocf_mngt_cache_detach_context *context = priv; + struct ocf_mngt_cache_unplug_context *context = priv; OCF_PL_NEXT_ON_SUCCESS_RET(context->pipeline, error); } @@ -3646,7 +3690,7 @@ static void ocf_mngt_cache_detach_flush_cmpl(ocf_cache_t cache, static void ocf_mngt_cache_detach_flush(ocf_pipeline_t pipeline, void *priv, ocf_pipeline_arg_t arg) { - struct ocf_mngt_cache_detach_context *context = priv; + struct ocf_mngt_cache_unplug_context *context = priv; ocf_cache_t cache = context->cache; ocf_mngt_cache_flush(cache, ocf_mngt_cache_detach_flush_cmpl, context); @@ -3654,14 +3698,14 @@ static void ocf_mngt_cache_detach_flush(ocf_pipeline_t pipeline, static void ocf_mngt_cache_detach_stop_cache_io_finish(void *priv) { - struct ocf_mngt_cache_detach_context *context = priv; + struct ocf_mngt_cache_unplug_context *context = priv; ocf_pipeline_next(context->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; + struct ocf_mngt_cache_unplug_context *context = priv; ocf_cache_t cache = context->cache; ocf_refcnt_freeze(&cache->refcnt.metadata); @@ -3678,7 +3722,7 @@ static void ocf_mngt_cache_detach_stop_cleaner_io_finish(void *priv) 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; + struct ocf_mngt_cache_unplug_context *context = priv; ocf_cache_t cache = context->cache; ocf_cleaner_refcnt_freeze(cache); @@ -3690,7 +3734,7 @@ static void ocf_mngt_cache_detach_stop_cleaner_io(ocf_pipeline_t pipeline, static void ocf_mngt_cache_detach_update_metadata(ocf_pipeline_t pipeline, void *priv, ocf_pipeline_arg_t arg) { - struct ocf_mngt_cache_detach_context *context = priv; + struct ocf_mngt_cache_unplug_context *context = priv; ocf_cache_t cache = context->cache; ocf_core_t core; ocf_core_id_t core_id; @@ -3709,7 +3753,7 @@ static void ocf_mngt_cache_detach_update_metadata(ocf_pipeline_t pipeline, static void ocf_mngt_cache_detach_unplug_complete(void *priv, int error) { - struct ocf_mngt_cache_detach_context *context = priv; + struct ocf_mngt_cache_unplug_context *context = priv; if (error) { ENV_BUG_ON(error != -OCF_ERR_WRITE_CACHE); @@ -3722,7 +3766,7 @@ static void ocf_mngt_cache_detach_unplug_complete(void *priv, int error) static void ocf_mngt_cache_detach_unplug(ocf_pipeline_t pipeline, void *priv, ocf_pipeline_arg_t arg) { - struct ocf_mngt_cache_detach_context *context = priv; + struct ocf_mngt_cache_unplug_context *context = priv; ocf_cache_t cache = context->cache; ENV_BUG_ON(cache->conf_meta->dirty_flushed == DIRTY_NOT_FLUSHED); @@ -3736,7 +3780,7 @@ static void ocf_mngt_cache_detach_unplug(ocf_pipeline_t pipeline, static void ocf_mngt_cache_detach_finish(ocf_pipeline_t pipeline, void *priv, int error) { - struct ocf_mngt_cache_detach_context *context = priv; + struct ocf_mngt_cache_unplug_context *context = priv; ocf_cache_t cache = context->cache; ocf_refcnt_unfreeze(&cache->refcnt.dirty); @@ -3749,21 +3793,24 @@ static void ocf_mngt_cache_detach_finish(ocf_pipeline_t pipeline, ocf_cache_log(cache, log_warn, "Device detached with errors\n"); } + + _ocf_mngt_cache_set_detached(cache); } else { ocf_cache_log(cache, log_err, "Detaching device failed\n"); } + ocf_pipeline_destroy(cache->stop_pipeline); + cache->stop_pipeline = NULL; + context->cmpl(cache, context->priv, error ?: context->cache_write_error); ocf_pipeline_destroy(context->pipeline); - ocf_pipeline_destroy(cache->stop_pipeline); - cache->stop_pipeline = NULL; } struct ocf_pipeline_properties ocf_mngt_cache_detach_pipeline_properties = { - .priv_size = sizeof(struct ocf_mngt_cache_detach_context), + .priv_size = sizeof(struct ocf_mngt_cache_unplug_context), .finish = ocf_mngt_cache_detach_finish, .steps = { OCF_PL_STEP(ocf_mngt_cache_detach_flush), @@ -3782,7 +3829,7 @@ struct ocf_pipeline_properties ocf_mngt_cache_detach_pipeline_properties = { void ocf_mngt_cache_detach(ocf_cache_t cache, ocf_mngt_cache_detach_end_t cmpl, void *priv) { - struct ocf_mngt_cache_detach_context *context; + struct ocf_mngt_cache_unplug_context *context; ocf_pipeline_t pipeline; int result; diff --git a/src/mngt/ocf_mngt_core.c b/src/mngt/ocf_mngt_core.c index afdc6e9..1c6dc37 100644 --- a/src/mngt/ocf_mngt_core.c +++ b/src/mngt/ocf_mngt_core.c @@ -1,5 +1,6 @@ /* * Copyright(c) 2012-2022 Intel Corporation + * Copyright(c) 2024 Huawei Technologies * SPDX-License-Identifier: BSD-3-Clause */ @@ -14,7 +15,7 @@ #include "../ocf_def_priv.h" #include "../cleaning/cleaning_ops.h" -static ocf_seq_no_t _ocf_mngt_get_core_seq_no(ocf_cache_t cache) +ocf_seq_no_t ocf_mngt_get_core_seq_no(ocf_cache_t cache) { if (cache->conf_meta->curr_core_seq_no == OCF_SEQ_NO_MAX) return OCF_SEQ_NO_INVALID; @@ -481,8 +482,9 @@ static void ocf_mngt_cache_add_core_insert(ocf_pipeline_t pipeline, cfg->seq_cutoff_promote_on_threshold); /* Add core sequence number for atomic metadata matching */ - if (ocf_volume_is_atomic(&cache->device->volume)) { - core_sequence_no = _ocf_mngt_get_core_seq_no(cache); + if (ocf_cache_is_device_attached(cache) && + ocf_volume_is_atomic(&cache->device->volume)) { + core_sequence_no = ocf_mngt_get_core_seq_no(cache); if (core_sequence_no == OCF_SEQ_NO_INVALID) OCF_PL_FINISH_RET(pipeline, -OCF_ERR_TOO_MANY_CORES); } @@ -490,6 +492,16 @@ static void ocf_mngt_cache_add_core_insert(ocf_pipeline_t pipeline, core->conf_meta->seq_no = core_sequence_no; /* Update super-block with core device addition */ + + if (!ocf_cache_is_device_attached(cache)) { + if (!cache->metadata.is_volatile) { + ocf_cache_log(cache, log_warn, "Cache is in detached state. " + "The changes about the new core won't persist cache stop " + "unless a cache volume is attached\n"); + } + OCF_PL_NEXT_RET(pipeline); + } + ocf_metadata_flush_superblock(cache, _ocf_mngt_cache_add_core_flush_sb_complete, context); } @@ -692,6 +704,9 @@ static void _ocf_mngt_cache_remove_core(ocf_pipeline_t pipeline, void *priv, cache_mngt_core_remove_from_cache(core); cache_mngt_core_deinit(core); + if (!ocf_cache_is_device_attached(cache)) + OCF_PL_NEXT_RET(pipeline); + ocf_metadata_flush_superblock(cache, ocf_mngt_cache_remove_core_flush_superblock_complete, context); @@ -997,6 +1012,9 @@ int ocf_mngt_core_set_seq_cutoff_threshold(ocf_core_t core, uint32_t thresh) if (ocf_cache_is_standby(cache)) return -OCF_ERR_CACHE_STANDBY; + if (!ocf_cache_is_device_attached(cache)) + return -OCF_ERR_CACHE_DETACHED; + return _cache_mngt_set_core_seq_cutoff_threshold(core, &thresh); } @@ -1008,6 +1026,9 @@ int ocf_mngt_core_set_seq_cutoff_threshold_all(ocf_cache_t cache, if (ocf_cache_is_standby(cache)) return -OCF_ERR_CACHE_STANDBY; + if (!ocf_cache_is_device_attached(cache)) + return -OCF_ERR_CACHE_DETACHED; + return ocf_core_visit(cache, _cache_mngt_set_core_seq_cutoff_threshold, &thresh, true); } @@ -1082,6 +1103,9 @@ int ocf_mngt_core_set_seq_cutoff_policy(ocf_core_t core, if (ocf_cache_is_standby(cache)) return -OCF_ERR_CACHE_STANDBY; + if (!ocf_cache_is_device_attached(cache)) + return -OCF_ERR_CACHE_DETACHED; + return _cache_mngt_set_core_seq_cutoff_policy(core, &policy); } int ocf_mngt_core_set_seq_cutoff_policy_all(ocf_cache_t cache, @@ -1092,6 +1116,9 @@ int ocf_mngt_core_set_seq_cutoff_policy_all(ocf_cache_t cache, if (ocf_cache_is_standby(cache)) return -OCF_ERR_CACHE_STANDBY; + if (!ocf_cache_is_device_attached(cache)) + return -OCF_ERR_CACHE_DETACHED; + return ocf_core_visit(cache, _cache_mngt_set_core_seq_cutoff_policy, &policy, true); } @@ -1154,6 +1181,9 @@ int ocf_mngt_core_set_seq_cutoff_promotion_count(ocf_core_t core, if (ocf_cache_is_standby(cache)) return -OCF_ERR_CACHE_STANDBY; + if (!ocf_cache_is_device_attached(cache)) + return -OCF_ERR_CACHE_DETACHED; + return _cache_mngt_set_core_seq_cutoff_promo_count(core, &count); } @@ -1165,6 +1195,9 @@ int ocf_mngt_core_set_seq_cutoff_promotion_count_all(ocf_cache_t cache, if (ocf_cache_is_standby(cache)) return -OCF_ERR_CACHE_STANDBY; + if (!ocf_cache_is_device_attached(cache)) + return -OCF_ERR_CACHE_DETACHED; + return ocf_core_visit(cache, _cache_mngt_set_core_seq_cutoff_promo_count, &count, true); } diff --git a/src/mngt/ocf_mngt_core_priv.h b/src/mngt/ocf_mngt_core_priv.h index 1784ad0..edecc19 100644 --- a/src/mngt/ocf_mngt_core_priv.h +++ b/src/mngt/ocf_mngt_core_priv.h @@ -1,5 +1,6 @@ /* * Copyright(c) 2012-2021 Intel Corporation + * Copyright(c) 2024 Huawei Technologies * SPDX-License-Identifier: BSD-3-Clause */ @@ -12,4 +13,6 @@ int ocf_mngt_core_init_front_volume(ocf_core_t core); void ocf_mngt_core_clear_uuid_metadata(ocf_core_t core); +ocf_seq_no_t ocf_mngt_get_core_seq_no(ocf_cache_t cache); + #endif /* __OCF_MNGT_CORE_PRIV_H__ */ diff --git a/src/mngt/ocf_mngt_flush.c b/src/mngt/ocf_mngt_flush.c index 2cfc565..b9ffa63 100644 --- a/src/mngt/ocf_mngt_flush.c +++ b/src/mngt/ocf_mngt_flush.c @@ -1101,6 +1101,9 @@ int ocf_mngt_cache_cleaning_set_param(ocf_cache_t cache, ocf_cleaning_t type, if (ocf_cache_is_standby(cache)) return -OCF_ERR_CACHE_STANDBY; + if (!ocf_cache_is_device_attached(cache)) + return -OCF_ERR_CACHE_DETACHED; + ocf_metadata_start_exclusive_access(&cache->metadata.lock); ret = ocf_cleaning_set_param(cache, type, param_id, param_value); diff --git a/src/ocf_cache.c b/src/ocf_cache.c index f6f7f5b..bafadba 100644 --- a/src/ocf_cache.c +++ b/src/ocf_cache.c @@ -1,6 +1,6 @@ /* * Copyright(c) 2012-2022 Intel Corporation - * Copyright(c) 2023 Huawei Technologies + * Copyright(c) 2023-2024 Huawei Technologies * SPDX-License-Identifier: BSD-3-Clause */ @@ -74,10 +74,10 @@ bool ocf_cache_is_running(ocf_cache_t cache) return env_bit_test(ocf_cache_state_running, &cache->cache_state); } -bool ocf_cache_is_initializing(ocf_cache_t cache) +bool ocf_cache_is_detached(ocf_cache_t cache) { OCF_CHECK_NULL(cache); - return env_bit_test(ocf_cache_state_initializing, &cache->cache_state); + return env_bit_test(ocf_cache_state_detached, &cache->cache_state); } bool ocf_cache_is_standby(ocf_cache_t cache) diff --git a/src/ocf_core.c b/src/ocf_core.c index ab29f1e..f7d1481 100644 --- a/src/ocf_core.c +++ b/src/ocf_core.c @@ -274,12 +274,6 @@ static void ocf_core_volume_submit_io(struct ocf_io *io) core = ocf_volume_to_core(ocf_io_get_volume(io)); cache = ocf_core_get_cache(core); - if (unlikely(!env_bit_test(ocf_cache_state_running, - &cache->cache_state))) { - ocf_io_end(io, -OCF_ERR_CACHE_NOT_AVAIL); - return; - } - if (unlikely(ocf_cache_is_standby(cache))) { ocf_io_end(io, -OCF_ERR_CACHE_STANDBY); return; @@ -340,12 +334,6 @@ static void ocf_core_volume_submit_flush(struct ocf_io *io) core = ocf_volume_to_core(ocf_io_get_volume(io)); cache = ocf_core_get_cache(core); - if (unlikely(!env_bit_test(ocf_cache_state_running, - &cache->cache_state))) { - ocf_io_end(io, -OCF_ERR_CACHE_NOT_AVAIL); - return; - } - if (unlikely(ocf_cache_is_standby(cache))) { ocf_io_end(io, -OCF_ERR_CACHE_STANDBY); return; @@ -383,12 +371,6 @@ static void ocf_core_volume_submit_discard(struct ocf_io *io) core = ocf_volume_to_core(ocf_io_get_volume(io)); cache = ocf_core_get_cache(core); - if (unlikely(!env_bit_test(ocf_cache_state_running, - &cache->cache_state))) { - ocf_io_end(io, -OCF_ERR_CACHE_NOT_AVAIL); - return; - } - if (unlikely(ocf_cache_is_standby(cache))) { ocf_io_end(io, -OCF_ERR_CACHE_STANDBY); return; diff --git a/tests/functional/pyocf/types/cache.py b/tests/functional/pyocf/types/cache.py index eedd278..c6d5118 100644 --- a/tests/functional/pyocf/types/cache.py +++ b/tests/functional/pyocf/types/cache.py @@ -1,5 +1,6 @@ # # Copyright(c) 2019-2022 Intel Corporation +# Copyright(c) 2024 Huawei Technologies # SPDX-License-Identifier: BSD-3-Clause # @@ -677,7 +678,7 @@ class Cache: self.device = None if c.results["error"]: - raise OcfError("Attaching cache device failed", c.results["error"]) + raise OcfError("Detaching cache device failed", c.results["error"]) def load_cache(self, device, open_cores=True, disable_cleaner=False): self.device = device diff --git a/tests/functional/pyocf/types/shared.py b/tests/functional/pyocf/types/shared.py index dc23dda..a4cd19a 100644 --- a/tests/functional/pyocf/types/shared.py +++ b/tests/functional/pyocf/types/shared.py @@ -1,5 +1,6 @@ # # Copyright(c) 2019-2022 Intel Corporation +# Copyright(c) 2024 Huawei Technologies # SPDX-License-Identifier: BSD-3-Clause # @@ -55,6 +56,7 @@ class OcfErrorCode(IntEnum): OCF_ERR_CORE_UUID_EXISTS = auto() OCF_ERR_CACHE_LINE_SIZE_MISMATCH = auto() OCF_ERR_CACHE_STANDBY = auto() + OCF_ERR_CACHE_DETACHED = auto() OCF_ERR_CORE_SIZE_MISMATCH = auto() OCF_ERR_STANDBY_ATTACHED = auto() OCF_ERR_CORE_NOT_REMOVED = auto() diff --git a/tests/functional/tests/engine/test_read.py b/tests/functional/tests/engine/test_read.py index b61f6b3..911c68a 100644 --- a/tests/functional/tests/engine/test_read.py +++ b/tests/functional/tests/engine/test_read.py @@ -1,5 +1,6 @@ # # Copyright(c) 2019-2022 Intel Corporation +# Copyright(c) 2024 Huawei Technologies # SPDX-License-Identifier: BSD-3-Clause # @@ -187,7 +188,7 @@ def print_test_case( @pytest.mark.parametrize("cacheline_size", CacheLineSize) @pytest.mark.parametrize("cache_mode", CacheMode) -@pytest.mark.parametrize("rand_seed", [datetime.now()]) +@pytest.mark.parametrize("rand_seed", [datetime.now().timestamp()]) def test_read_data_consistency(pyocf_ctx, cacheline_size, cache_mode, rand_seed): CACHELINE_COUNT = 9 SECTOR_SIZE = Size.from_sector(1).B diff --git a/tests/functional/tests/management/test_attach_cache.py b/tests/functional/tests/management/test_attach_cache.py index 115a1c1..5ad3d38 100644 --- a/tests/functional/tests/management/test_attach_cache.py +++ b/tests/functional/tests/management/test_attach_cache.py @@ -1,5 +1,6 @@ # # Copyright(c) 2019-2022 Intel Corporation +# Copyright(c) 2024 Huawei Technologies # SPDX-License-Identifier: BSD-3-Clause # @@ -26,6 +27,7 @@ from pyocf.types.shared import ( CacheLines, CacheLineSize, SeqCutOffPolicy, + OcfError, ) from pyocf.types.volume import RamVolume from pyocf.types.volume_core import CoreVolume @@ -34,6 +36,45 @@ from pyocf.utils import Size logger = logging.getLogger(__name__) +def test_add_remove_core_detached_cache(pyocf_ctx): + cache_device = RamVolume(Size.from_MiB(50)) + core_device = RamVolume(Size.from_MiB(50)) + + cache = Cache(owner=pyocf_ctx) + cache.start_cache() + core = Core.using_device(core_device) + cache.add_core(core) + cache.remove_core(core) + cache.stop() + + +def test_attach_cache_twice(pyocf_ctx): + cache_device_1 = RamVolume(Size.from_MiB(50)) + cache_device_2 = RamVolume(Size.from_MiB(50)) + + cache = Cache(owner=pyocf_ctx) + cache.start_cache() + + cache.attach_device(cache_device_1) + + with pytest.raises(OcfError, match="Attaching cache device failed"): + cache.attach_device(cache_device_2) + + cache.stop() + + +def test_detach_cache_twice(pyocf_ctx): + cache_device = RamVolume(Size.from_MiB(50)) + cache = Cache.start_on_device(cache_device) + + cache.detach_device() + + with pytest.raises(OcfError, match="Detaching cache device failed"): + cache.detach_device() + + cache.stop() + + @pytest.mark.parametrize("cls", CacheLineSize) @pytest.mark.parametrize("mode", [CacheMode.WB, CacheMode.WT, CacheMode.WO]) @pytest.mark.parametrize("new_cache_size", [80, 120])