From 91e0345b78aaa4cbb8594e1fd4a8b40ed122cb16 Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Mon, 4 Mar 2019 10:55:16 +0100 Subject: [PATCH] Implement asynchronous attach, load, detach and stop NOTE: This is still not the real asynchronism. Metadata interfaces are still not fully asynchronous. Signed-off-by: Robert Baldyga Signed-off-by: Michal Mielewczyk --- inc/ocf_cache.h | 8 - inc/ocf_mngt.h | 24 + src/engine/engine_common.c | 7 +- src/metadata/metadata.c | 21 +- src/metadata/metadata.h | 22 +- src/metadata/metadata_superblock.h | 19 +- src/mngt/ocf_mngt_cache.c | 1720 +++++++++++------ src/mngt/ocf_mngt_common.c | 81 + src/mngt/ocf_mngt_common.h | 18 + src/mngt/ocf_mngt_flush.c | 10 +- src/ocf_cache.c | 14 - src/ocf_cache_priv.h | 2 +- src/utils/utils_io.c | 229 ++- src/utils/utils_io.h | 17 +- src/utils/utils_req.c | 7 +- .../_cache_mng_set_cache_mode_test.c | 130 ++ ...gt_cache_set_fallback_pt_error_threshold.c | 130 ++ 17 files changed, 1692 insertions(+), 767 deletions(-) diff --git a/inc/ocf_cache.h b/inc/ocf_cache.h index d23d629..786b2fc 100644 --- a/inc/ocf_cache.h +++ b/inc/ocf_cache.h @@ -266,12 +266,4 @@ void ocf_cache_set_priv(ocf_cache_t cache, void *priv); */ void *ocf_cache_get_priv(ocf_cache_t cache); -/** - * @brief Set queue to be used during flush operation - * - * @param[in] cache Cache object - * @param[in] queue Queue object - */ -void ocf_cache_set_flush_queue(ocf_cache_t cache, ocf_queue_t queue); - #endif /* __OCF_CACHE_H__ */ diff --git a/inc/ocf_mngt.h b/inc/ocf_mngt.h index 08d6359..d7dccf4 100644 --- a/inc/ocf_mngt.h +++ b/inc/ocf_mngt.h @@ -356,6 +356,17 @@ struct ocf_mngt_cache_device_config { int ocf_mngt_cache_start(ocf_ctx_t ctx, ocf_cache_t *cache, struct ocf_mngt_cache_config *cfg); +/** + * @brief Set queue to be used during management operations + * + * @param[in] cache Cache object + * @param[in] queue Queue object + * + * @retval 0 Success + * @retval Non-zero Error occurred + */ +int ocf_mngt_cache_set_mngt_queue(ocf_cache_t cache, ocf_queue_t queue); + /** * @brief Completion callback of cache stop operation * @@ -376,6 +387,19 @@ typedef void (*ocf_mngt_cache_stop_end_t)(ocf_cache_t cache, void ocf_mngt_cache_stop(ocf_cache_t cache, ocf_mngt_cache_stop_end_t cmpl, void *priv); +/** + * @brief Get amount of free RAM needed to attach cache volume + * + * @param[in] cache Cache handle + * @param[in] cfg Caching device configuration + * @param[out] ram_needed Amount of RAM needed in bytes + * + * @retval 0 Success + * @retval Non-zero Error occurred + */ +int ocf_mngt_get_ram_needed(ocf_cache_t cache, + struct ocf_mngt_cache_device_config *cfg, uint64_t *ram_needed); + /** * @brief Completion callback of cache attach operation * diff --git a/src/engine/engine_common.c b/src/engine/engine_common.c index 55e4e83..dcf9dbe 100644 --- a/src/engine/engine_common.c +++ b/src/engine/engine_common.c @@ -504,9 +504,10 @@ void ocf_engine_push_req_back(struct ocf_request *req, bool allow_sync) env_spinlock_unlock_irqrestore(&q->io_list_lock, lock_flags); - if (!req->info.internal) + if (!req->info.internal) { env_atomic_set(&cache->last_access_ms, env_ticks_to_msecs(env_get_tick_count())); + } ocf_queue_kick(q, allow_sync); } @@ -517,6 +518,7 @@ void ocf_engine_push_req_front(struct ocf_request *req, bool allow_sync) ocf_queue_t q = NULL; unsigned long lock_flags = 0; + ENV_BUG_ON(!req->io_queue); INIT_LIST_HEAD(&req->list); q = req->io_queue; @@ -528,9 +530,10 @@ void ocf_engine_push_req_front(struct ocf_request *req, bool allow_sync) env_spinlock_unlock_irqrestore(&q->io_list_lock, lock_flags); - if (!req->info.internal) + if (!req->info.internal) { env_atomic_set(&cache->last_access_ms, env_ticks_to_msecs(env_get_tick_count())); + } ocf_queue_kick(q, allow_sync); } diff --git a/src/metadata/metadata.c b/src/metadata/metadata.c index df468f9..89a8bbe 100644 --- a/src/metadata/metadata.c +++ b/src/metadata/metadata.c @@ -103,20 +103,20 @@ ocf_cache_line_t ocf_metadata_get_pages_count(struct ocf_cache *cache) return cache->metadata.iface.pages(cache); } -ocf_cache_line_t -ocf_metadata_get_cachelines_count(struct ocf_cache *cache) +ocf_cache_line_t ocf_metadata_get_cachelines_count(ocf_cache_t cache) { return cache->metadata.iface.cachelines(cache); } -int ocf_metadata_flush_all(struct ocf_cache *cache) +void ocf_metadata_flush_all(ocf_cache_t cache, + ocf_metadata_end_t cmpl, void *priv) { int result; OCF_METADATA_LOCK_WR(); result = cache->metadata.iface.flush_all(cache); OCF_METADATA_UNLOCK_WR(); - return result; + cmpl(priv, result); } void ocf_metadata_flush(struct ocf_cache *cache, ocf_cache_line_t line) @@ -124,19 +124,24 @@ void ocf_metadata_flush(struct ocf_cache *cache, ocf_cache_line_t line) cache->metadata.iface.flush(cache, line); } -int ocf_metadata_load_all(struct ocf_cache *cache) +void ocf_metadata_load_all(ocf_cache_t cache, + ocf_metadata_end_t cmpl, void *priv) { int result; OCF_METADATA_LOCK_WR(); result = cache->metadata.iface.load_all(cache); OCF_METADATA_UNLOCK_WR(); - return result; + cmpl(priv, result); } -int ocf_metadata_load_recovery(struct ocf_cache *cache) +void ocf_metadata_load_recovery(ocf_cache_t cache, + ocf_metadata_end_t cmpl, void *priv) { - return cache->metadata.iface.load_recovery(cache); + int result; + + result = cache->metadata.iface.load_recovery(cache); + cmpl(priv, result); } void ocf_metadata_flush_mark(struct ocf_cache *cache, struct ocf_request *req, diff --git a/src/metadata/metadata.h b/src/metadata/metadata.h index 6126452..a883dce 100644 --- a/src/metadata/metadata.h +++ b/src/metadata/metadata.h @@ -124,6 +124,8 @@ static inline void ocf_metadata_status_bits_unlock( #define OCF_METADATA_FLUSH_UNLOCK() \ ocf_metadata_flush_unlock(cache) +typedef void (*ocf_metadata_end_t)(void *priv, int error); + #include "metadata_cleaning_policy.h" #include "metadata_eviction_policy.h" #include "metadata_partition.h" @@ -224,10 +226,12 @@ ocf_cache_line_t ocf_metadata_get_pages_count(struct ocf_cache *cache); /** * @brief Flush metadata * - * @param cache - * @return 0 - Operation success otherwise failure + * @param cache - Cache instance + * @param cmpl - Completion callback + * @param priv - Completion context */ -int ocf_metadata_flush_all(struct ocf_cache *cache); +void ocf_metadata_flush_all(ocf_cache_t cache, + ocf_metadata_end_t cmpl, void *priv); /** @@ -263,17 +267,21 @@ void ocf_metadata_flush_do_asynch(struct ocf_cache *cache, * @brief Load metadata * * @param cache - Cache instance - * @return 0 - Operation success otherwise failure + * @param cmpl - Completion callback + * @param priv - Completion context */ -int ocf_metadata_load_all(struct ocf_cache *cache); +void ocf_metadata_load_all(ocf_cache_t cache, + ocf_metadata_end_t cmpl, void *priv); /** * @brief Load metadata required for recovery procedure * * @param cache Cache instance - * @return 0 - Operation success otherwise failure + * @param cmpl - Completion callback + * @param priv - Completion context */ -int ocf_metadata_load_recovery(struct ocf_cache *cache); +void ocf_metadata_load_recovery(ocf_cache_t cache, + ocf_metadata_end_t cmpl, void *priv); /* * NOTE Hash table is specific for hash table metadata service implementation diff --git a/src/metadata/metadata_superblock.h b/src/metadata/metadata_superblock.h index d207467..9f588c3 100644 --- a/src/metadata/metadata_superblock.h +++ b/src/metadata/metadata_superblock.h @@ -62,17 +62,24 @@ struct ocf_superblock_runtime { uint32_t cleaning_thread_access; }; -static inline int ocf_metadata_set_shutdown_status( - struct ocf_cache *cache, - enum ocf_metadata_shutdown_status shutdown_status) +static inline void ocf_metadata_set_shutdown_status(ocf_cache_t cache, + enum ocf_metadata_shutdown_status shutdown_status, + ocf_metadata_end_t cmpl, void *priv) { - return cache->metadata.iface.set_shutdown_status(cache, + int result; + + result = cache->metadata.iface.set_shutdown_status(cache, shutdown_status); + cmpl(priv, result); } -static inline int ocf_metadata_load_superblock(struct ocf_cache *cache) +static inline void ocf_metadata_load_superblock(ocf_cache_t cache, + ocf_metadata_end_t cmpl, void *priv) { - return cache->metadata.iface.load_superblock(cache); + int result; + + result = cache->metadata.iface.load_superblock(cache); + cmpl(priv, result); } static inline diff --git a/src/mngt/ocf_mngt_cache.c b/src/mngt/ocf_mngt_cache.c index 9234e09..a50c16a 100644 --- a/src/mngt/ocf_mngt_cache.c +++ b/src/mngt/ocf_mngt_cache.c @@ -24,11 +24,11 @@ #define OCF_ASSERT_PLUGGED(cache) ENV_BUG_ON(!(cache)->device) -static struct ocf_cache *_ocf_mngt_get_cache(ocf_ctx_t owner, +static ocf_cache_t _ocf_mngt_get_cache(ocf_ctx_t owner, ocf_cache_id_t cache_id) { - struct ocf_cache *iter = NULL; - struct ocf_cache *cache = NULL; + ocf_cache_t iter = NULL; + ocf_cache_t cache = NULL; list_for_each_entry(iter, &owner->caches, list) { if (iter->cache_id == cache_id) { @@ -60,7 +60,7 @@ struct ocf_cachemng_init_params { ocf_ctx_t ctx; /*!< OCF context */ - struct ocf_cache *cache; + ocf_cache_t cache; /*!< cache that is being initialized */ uint8_t locked; @@ -93,30 +93,20 @@ struct ocf_cachemng_init_params { } metadata; }; -struct ocf_cachemng_attach_params { - struct ocf_cache *cache; +typedef void (*_ocf_mngt_cache_attach_end_t)(ocf_cache_t, void *priv1, + void *priv2, int error); + +struct ocf_cache_attach_context { + ocf_cache_t cache; /*!< cache that is being initialized */ - struct ocf_volume_uuid uuid; - /*!< Caching device volume UUID */ + struct ocf_mngt_cache_device_config cfg; - uint8_t device_type; - /*!< volume (block device) type */ - - uint64_t device_size; + uint64_t volume_size; /*!< size of the device in cache lines */ - uint8_t force; - /*!< if force switch was passed in CLI (if this flag is set, - * routine overrides some safety checks, that normally prevent - * completion of initialization procedure - */ - - uint8_t load; - /*!< 1 if load from attached device is requested */ - - bool perform_test; - /*!< Test cache before starting */ + enum ocf_mngt_cache_init_mode init_mode; + /*!< cache init mode */ /** * @brief initialization state (in case of error, it is used to know @@ -168,10 +158,18 @@ struct ocf_cachemng_attach_params { */ } metadata; - uint64_t min_free_ram; - /*!< Minimum free RAM required to start cache. Set during - * cache start procedure - */ + struct { + void *rw_buffer; + void *cmp_buffer; + unsigned long reserved_lba_addr; + ocf_mngt_pipeline_t pipeline; + } test; + + _ocf_mngt_cache_attach_end_t cmpl; + void *priv1; + void *priv2; + + ocf_mngt_pipeline_t pipeline; }; static ocf_cache_id_t _ocf_mngt_cache_find_free_id(ocf_ctx_t owner) @@ -186,19 +184,19 @@ static ocf_cache_id_t _ocf_mngt_cache_find_free_id(ocf_ctx_t owner) return OCF_CACHE_ID_INVALID; } -static void __init_hash_table(struct ocf_cache *cache) +static void __init_hash_table(ocf_cache_t cache) { /* Initialize hash table*/ ocf_metadata_init_hash_table(cache); } -static void __init_freelist(struct ocf_cache *cache) +static void __init_freelist(ocf_cache_t cache) { /* Initialize free list partition*/ ocf_metadata_init_freelist_partition(cache); } -static void __init_partitions(struct ocf_cache *cache) +static void __init_partitions(ocf_cache_t cache) { ocf_part_id_t i_part; @@ -219,7 +217,7 @@ static void __init_partitions(struct ocf_cache *cache) } } -static void __init_partitions_attached(struct ocf_cache *cache) +static void __init_partitions_attached(ocf_cache_t cache) { ocf_part_id_t part_id; @@ -232,7 +230,7 @@ static void __init_partitions_attached(struct ocf_cache *cache) } } -static void __init_cleaning_policy(struct ocf_cache *cache) +static void __init_cleaning_policy(ocf_cache_t cache) { ocf_cleaning_t cleaning_policy = ocf_cleaning_default; int i; @@ -249,7 +247,7 @@ static void __init_cleaning_policy(struct ocf_cache *cache) cleaning_policy_ops[cleaning_policy].initialize(cache, 1); } -static void __deinit_cleaning_policy(struct ocf_cache *cache) +static void __deinit_cleaning_policy(ocf_cache_t cache) { ocf_cleaning_t cleaning_policy; @@ -258,7 +256,7 @@ static void __deinit_cleaning_policy(struct ocf_cache *cache) cleaning_policy_ops[cleaning_policy].deinitialize(cache); } -static void __init_eviction_policy(struct ocf_cache *cache, +static void __init_eviction_policy(ocf_cache_t cache, ocf_eviction_t eviction) { ENV_BUG_ON(eviction < 0 || eviction >= ocf_eviction_max); @@ -266,7 +264,7 @@ static void __init_eviction_policy(struct ocf_cache *cache, cache->conf_meta->eviction_policy_type = eviction; } -static void __init_cores(struct ocf_cache *cache) +static void __init_cores(ocf_cache_t cache) { /* No core devices yet */ cache->conf_meta->core_count = 0; @@ -274,25 +272,12 @@ static void __init_cores(struct ocf_cache *cache) sizeof(cache->conf_meta->valid_core_bitmap), 0)); } -static void __init_metadata_version(struct ocf_cache *cache) +static void __init_metadata_version(ocf_cache_t cache) { cache->conf_meta->metadata_version = METADATA_VERSION(); } -static void init_attached_data_structures(struct ocf_cache *cache, - ocf_eviction_t eviction_policy) -{ - /* Lock to ensure consistency */ - OCF_METADATA_LOCK_WR(); - __init_hash_table(cache); - __init_freelist(cache); - __init_partitions_attached(cache); - __init_cleaning_policy(cache); - __init_eviction_policy(cache, eviction_policy); - OCF_METADATA_UNLOCK_WR(); -} - -static void __reset_stats(struct ocf_cache *cache) +static void __reset_stats(ocf_cache_t cache) { int core_id; ocf_part_id_t i; @@ -314,7 +299,20 @@ static void __reset_stats(struct ocf_cache *cache) } } -static void init_attached_data_structures_recovery(struct ocf_cache *cache) +static void init_attached_data_structures(ocf_cache_t cache, + ocf_eviction_t eviction_policy) +{ + /* Lock to ensure consistency */ + OCF_METADATA_LOCK_WR(); + __init_hash_table(cache); + __init_freelist(cache); + __init_partitions_attached(cache); + __init_cleaning_policy(cache); + __init_eviction_policy(cache, eviction_policy); + OCF_METADATA_UNLOCK_WR(); +} + +static void init_attached_data_structures_recovery(ocf_cache_t cache) { OCF_METADATA_LOCK_WR(); __init_hash_table(cache); @@ -325,32 +323,13 @@ static void init_attached_data_structures_recovery(struct ocf_cache *cache) OCF_METADATA_UNLOCK_WR(); } -/** - * @brief initialize partitions for a caching device - */ -static void _init_partitions(ocf_cache_t cache) -{ - int clean_type = cache->conf_meta->cleaning_policy_type; - - if (clean_type >= 0 && clean_type < ocf_cleaning_max) { - /* Initialize policy with settings restored - * from metadata. - */ - if (cleaning_policy_ops[clean_type].initialize) - cleaning_policy_ops[clean_type].initialize(cache, 0); - } else { - ocf_cache_log(cache, log_warn, - "Wrong cleaning policy type=%d\n", clean_type); - } -} - /**************************************************************** * Function for removing all uninitialized core objects * * from the cache instance. * * Used in case of cache initialization errors. * ****************************************************************/ static void _ocf_mngt_close_all_uninitialized_cores( - struct ocf_cache *cache) + ocf_cache_t cache) { ocf_volume_t volume; int j, i; @@ -378,9 +357,9 @@ static void _ocf_mngt_close_all_uninitialized_cores( * - attempts to open all the underlying cores */ static int _ocf_mngt_init_instance_add_cores( - struct ocf_cachemng_attach_params *attach_params) + struct ocf_cache_attach_context *context) { - struct ocf_cache *cache = attach_params->cache; + ocf_cache_t cache = context->cache; /* FIXME: This is temporary hack. Remove after storing name it meta. */ char core_name[OCF_CORE_NAME_SIZE]; int ret = -1, i; @@ -388,13 +367,6 @@ static int _ocf_mngt_init_instance_add_cores( OCF_ASSERT_PLUGGED(cache); - ocf_cache_log(cache, log_info, "Loading cache state...\n"); - if (ocf_metadata_load_superblock(cache)) { - ocf_cache_log(cache, log_err, - "ERROR: Cannot load cache state\n"); - return -OCF_ERR_START_CACHE_FAIL; - } - if (cache->conf_meta->cachelines != ocf_metadata_get_cachelines_count(cache)) { ocf_cache_log(cache, log_err, @@ -483,7 +455,7 @@ static int _ocf_mngt_init_instance_add_cores( } } - attach_params->flags.cores_opened = true; + context->flags.cores_opened = true; return 0; err: @@ -492,89 +464,82 @@ err: return -OCF_ERR_START_CACHE_FAIL; } -/** - * @brief routine implementing "recovery" feature - flushes dirty data to - * underlying cores and closes them - * @param cache caching device that is opened but not fully initialized - */ -static int _recover_cache(struct ocf_cache *cache) +void _ocf_mngt_init_instance_load_complete(void *priv, int error) { + struct ocf_cache_attach_context *context = priv; + ocf_cache_t cache = context->cache; + ocf_cleaning_t cleaning_policy; + + if (error) { + ocf_cache_log(cache, log_err, + "Cannot read cache metadata\n"); + ocf_mngt_pipeline_finish(context->pipeline, + -OCF_ERR_START_CACHE_FAIL); + return; + } + + cleaning_policy = cache->conf_meta->cleaning_policy_type; + if (!cleaning_policy_ops[cleaning_policy].initialize) + goto out; + + if (context->metadata.shutdown_status == ocf_metadata_clean_shutdown) + cleaning_policy_ops[cleaning_policy].initialize(cache, 0); + else + cleaning_policy_ops[cleaning_policy].initialize(cache, 1); + +out: + ocf_mngt_pipeline_next(context->pipeline); +} + +/** + * handle load variant + */ +static void _ocf_mngt_init_instance_clean_load( + struct ocf_cache_attach_context *context) +{ + ocf_cache_t cache = context->cache; + + ocf_metadata_load_all(cache, + _ocf_mngt_init_instance_load_complete, context); +} + +/** + * handle recovery variant + */ +static void _ocf_mngt_init_instance_recovery( + struct ocf_cache_attach_context *context) +{ + ocf_cache_t cache = context->cache; + + init_attached_data_structures_recovery(cache); + ocf_cache_log(cache, log_warn, "ERROR: Cache device did not shut down properly!\n"); ocf_cache_log(cache, log_info, "Initiating recovery sequence...\n"); - if (ocf_metadata_load_recovery(cache)) { - ocf_cache_log(cache, log_err, - "Cannot read metadata for recovery\n"); - return -OCF_ERR_START_CACHE_FAIL; - } - - return 0; + ocf_metadata_load_recovery(cache, + _ocf_mngt_init_instance_load_complete, context); } -/** - * handle --start-cache -r variant - */ -static int _ocf_mngt_init_instance_recovery( - struct ocf_cachemng_attach_params *attach_params) +static void _ocf_mngt_init_instance_load( + struct ocf_cache_attach_context *context) { - int result = 0; - struct ocf_cache *cache = attach_params->cache; - ocf_cleaning_t cleaning_policy; - - OCF_ASSERT_PLUGGED(cache); - - init_attached_data_structures_recovery(cache); - - result = _recover_cache(cache); - if (result) - return result; - - cleaning_policy = cache->conf_meta->cleaning_policy_type; - if (cleaning_policy_ops[cleaning_policy].initialize) { - cleaning_policy_ops[cleaning_policy].initialize(cache, 1); - } - - if (ocf_metadata_flush_all(cache)) { - ocf_cache_log(cache, log_err, - "ERROR: Cannot save cache state\n"); - return -OCF_ERR_START_CACHE_FAIL; - } - - return 0; -} - -/** - * handle --start-cache -l variant - */ -static int _ocf_mngt_init_instance_load( - struct ocf_cachemng_attach_params *attach_params) -{ - struct ocf_cache *cache = attach_params->cache; + ocf_cache_t cache = context->cache; int ret; OCF_ASSERT_PLUGGED(cache); - ret = _ocf_mngt_init_instance_add_cores(attach_params); - if (ret) - return ret; - - if (ocf_metadata_clean_shutdown != attach_params->metadata.shutdown_status) { - /* When dirty shutdown perform recovery */ - return _ocf_mngt_init_instance_recovery(attach_params); - } - - ret = ocf_metadata_load_all(cache); + ret = _ocf_mngt_init_instance_add_cores(context); if (ret) { - ocf_cache_log(cache, log_err, - "ERROR: Cannot load cache state\n"); - return -OCF_ERR_START_CACHE_FAIL; + ocf_mngt_pipeline_finish(context->pipeline, ret); + return; } - _init_partitions(cache); - - return ret; + if (context->metadata.shutdown_status == ocf_metadata_clean_shutdown) + _ocf_mngt_init_instance_clean_load(context); + else + _ocf_mngt_init_instance_recovery(context); } /** @@ -583,7 +548,7 @@ static int _ocf_mngt_init_instance_load( */ static int _ocf_mngt_init_new_cache(struct ocf_cachemng_init_params *params) { - struct ocf_cache *cache = env_vzalloc(sizeof(*cache)); + ocf_cache_t cache = env_vzalloc(sizeof(*cache)); if (!cache) return -OCF_ERR_NO_MEM; @@ -613,33 +578,36 @@ static int _ocf_mngt_init_new_cache(struct ocf_cachemng_init_params *params) return 0; } -static int _ocf_mngt_attach_cache_device(struct ocf_cache *cache, - struct ocf_cachemng_attach_params *attach_params) +static void _ocf_mngt_attach_cache_device(ocf_mngt_pipeline_t pipeline, void *priv) { + struct ocf_cache_attach_context *context = priv; + ocf_cache_t cache = context->cache; ocf_volume_type_t type; int ret; cache->device = env_vzalloc(sizeof(*cache->device)); - if (!cache->device) - return -OCF_ERR_NO_MEM; - attach_params->flags.device_alloc = true; + if (!cache->device) { + ret = -OCF_ERR_NO_MEM; + goto err; + } + context->flags.device_alloc = true; - cache->device->volume.cache = cache; + cache->device->init_mode = context->init_mode; /* Prepare UUID of cache volume */ - type = ocf_ctx_get_volume_type(cache->owner, - attach_params->device_type); + type = ocf_ctx_get_volume_type(cache->owner, context->cfg.volume_type); if (!type) { ret = -OCF_ERR_INVAL_VOLUME_TYPE; goto err; } ret = ocf_volume_init(&cache->device->volume, type, - &attach_params->uuid, true); + &context->cfg.uuid, true); if (ret) goto err; - attach_params->flags.volume_inited = true; + cache->device->volume.cache = cache; + context->flags.volume_inited = true; /* * Open cache device, It has to be done first because metadata service @@ -650,29 +618,23 @@ static int _ocf_mngt_attach_cache_device(struct ocf_cache *cache, ocf_cache_log(cache, log_err, "ERROR: Cache not available\n"); goto err; } - attach_params->flags.device_opened = true; + context->flags.device_opened = true; - attach_params->device_size = ocf_volume_get_length(&cache->device->volume); + context->volume_size = ocf_volume_get_length(&cache->device->volume); /* Check minimum size of cache device */ - if (attach_params->device_size < OCF_CACHE_SIZE_MIN) { + if (context->volume_size < OCF_CACHE_SIZE_MIN) { ocf_cache_log(cache, log_err, "ERROR: Cache cache size must " "be at least %llu [MiB]\n", OCF_CACHE_SIZE_MIN / MiB); ret = -OCF_ERR_START_CACHE_FAIL; goto err; } - if (cache->metadata.is_volatile) { - cache->device->init_mode = ocf_init_mode_metadata_volatile; - } else { - cache->device->init_mode = attach_params->load ? - ocf_init_mode_load : ocf_init_mode_init; - } - - return 0; + ocf_mngt_pipeline_next(pipeline); + return; err: - return ret; + ocf_mngt_pipeline_finish(context->pipeline, ret); } /** @@ -682,7 +644,7 @@ err: static int _ocf_mngt_init_prepare_cache(struct ocf_cachemng_init_params *param, struct ocf_mngt_cache_config *cfg) { - struct ocf_cache *cache; + ocf_cache_t cache; char cache_name[OCF_CACHE_NAME_SIZE]; int ret = 0; @@ -749,106 +711,131 @@ out: return ret; } - -/** - * @brief read data from given address and compare it against cmp_buffer - * - * @param[in] cache OCF cache - * @param[in] addr target adres for read operation - * @param[in] rw_buffer buffer to store data read from addr - * @param[in] cmp_buffer buffer to compare against - * @param[out] diff buffers diff - - * @return error code in case of error, 0 in case of success -*/ -static int __ocf_mngt_init_test_device_submit_and_cmp(struct ocf_cache *cache, - uint64_t addr, void *rw_buffer, void *cmp_buffer, int *diff) +static void _ocf_mngt_test_volume_initial_write_complete(void *priv, int error) { - int ret; + struct ocf_cache_attach_context *context = priv; - ret = ocf_submit_cache_page(cache, addr, OCF_READ, - rw_buffer); - if (ret) - goto end; + if (error) { + ocf_mngt_pipeline_finish(context->test.pipeline, error); + return; + } - ret = env_memcmp(rw_buffer, PAGE_SIZE, cmp_buffer, PAGE_SIZE, diff); - -end: - return ret; + ocf_mngt_pipeline_next(context->test.pipeline); } -static int _ocf_mngt_init_test_device(struct ocf_cache *cache) +static void _ocf_mngt_test_volume_initial_write( + ocf_mngt_pipeline_t test_pipeline, void *priv) { - unsigned long reserved_lba_addr; - void *rw_buffer = NULL, *cmp_buffer = NULL; - int ret; - int diff; - - rw_buffer = env_malloc(PAGE_SIZE, ENV_MEM_NORMAL); - if (!rw_buffer) { - ret = -OCF_ERR_NO_MEM; - goto end; - } - - cmp_buffer = env_malloc(PAGE_SIZE, ENV_MEM_NORMAL); - if (!cmp_buffer) { - ret = -OCF_ERR_NO_MEM; - goto end; - } - - reserved_lba_addr = ocf_metadata_get_reserved_lba(cache); + struct ocf_cache_attach_context *context = priv; + ocf_cache_t cache = context->cache; /* - * Write buffer filled "1" + * Write buffer filled with "1" */ - ENV_BUG_ON(env_memset(rw_buffer, PAGE_SIZE, 1)); + ENV_BUG_ON(env_memset(context->test.rw_buffer, PAGE_SIZE, 1)); - ret = ocf_submit_cache_page(cache, reserved_lba_addr, - OCF_WRITE, rw_buffer); - if (ret) - goto end; + ocf_submit_cache_page(cache, context->test.reserved_lba_addr, + OCF_WRITE, context->test.rw_buffer, + _ocf_mngt_test_volume_initial_write_complete, context); +} + +static void _ocf_mngt_test_volume_first_read_complete(void *priv, int error) +{ + struct ocf_cache_attach_context *context = priv; + ocf_cache_t cache = context->cache; + int ret, diff; + + if (error) { + ocf_mngt_pipeline_finish(context->test.pipeline, error); + return; + } + + ret = env_memcmp(context->test.rw_buffer, PAGE_SIZE, + context->test.cmp_buffer, PAGE_SIZE, &diff); + if (ret) { + ocf_mngt_pipeline_finish(context->test.pipeline, ret); + return; + } + + if (diff) { + /* we read back different data than what we had just + written - this is fatal error */ + ocf_mngt_pipeline_finish(context->test.pipeline, -EIO); + return; + } + + if (!ocf_volume_is_atomic(&cache->device->volume)) { + /* If not atomic, stop testing here */ + ocf_mngt_pipeline_finish(context->test.pipeline, 0); + return; + } + + ocf_mngt_pipeline_next(context->test.pipeline); +} + +static void _ocf_mngt_test_volume_first_read( + ocf_mngt_pipeline_t test_pipeline, void *priv) +{ + struct ocf_cache_attach_context *context = priv; + ocf_cache_t cache = context->cache; /* * First read */ - ENV_BUG_ON(env_memset(rw_buffer, PAGE_SIZE, 0)); - ENV_BUG_ON(env_memset(cmp_buffer, PAGE_SIZE, 1)); + ENV_BUG_ON(env_memset(context->test.rw_buffer, PAGE_SIZE, 0)); + ENV_BUG_ON(env_memset(context->test.cmp_buffer, PAGE_SIZE, 1)); - ret = __ocf_mngt_init_test_device_submit_and_cmp(cache, - reserved_lba_addr, rw_buffer, cmp_buffer, &diff); - if (ret) - goto end; - if (diff) { - /* we read back different data than what we had just - written - this is fatal error */ - ret = -EIO; - goto end; + ocf_submit_cache_page(cache, context->test.reserved_lba_addr, + OCF_READ, context->test.rw_buffer, + _ocf_mngt_test_volume_first_read_complete, context); +} + +static void _ocf_mngt_test_volume_discard_complete(void *priv, int error) +{ + struct ocf_cache_attach_context *context = priv; + + if (error) { + ocf_mngt_pipeline_finish(context->test.pipeline, error); + return; } - if (!ocf_volume_is_atomic(&cache->device->volume)) - goto end; + ocf_mngt_pipeline_next(context->test.pipeline); +} + +static void _ocf_mngt_test_volume_discard( + ocf_mngt_pipeline_t test_pipeline, void *priv) +{ + struct ocf_cache_attach_context *context = priv; + ocf_cache_t cache = context->cache; /* * Submit discard request */ - ret = ocf_submit_volume_discard_wait(&cache->device->volume, - reserved_lba_addr, PAGE_SIZE); - if (ret) - goto end; - /* - * Second read - */ + ocf_submit_volume_discard(&cache->device->volume, + context->test.reserved_lba_addr, PAGE_SIZE, + _ocf_mngt_test_volume_discard_complete, context); +} - ENV_BUG_ON(env_memset(rw_buffer, PAGE_SIZE, 1)); - ENV_BUG_ON(env_memset(cmp_buffer, PAGE_SIZE, 0)); +static void _ocf_mngt_test_volume_second_read_complete(void *priv, int error) +{ + struct ocf_cache_attach_context *context = priv; + ocf_cache_t cache = context->cache; + int ret, diff; - ret = __ocf_mngt_init_test_device_submit_and_cmp(cache, - reserved_lba_addr, rw_buffer, cmp_buffer, &diff); - if (ret) - goto end; + if (error) { + ocf_mngt_pipeline_finish(context->test.pipeline, error); + return; + } + + ret = env_memcmp(context->test.rw_buffer, PAGE_SIZE, + context->test.cmp_buffer, PAGE_SIZE, &diff); + if (ret) { + ocf_mngt_pipeline_finish(context->test.pipeline, ret); + return; + } if (diff) { /* discard does not cause target adresses to return 0 on @@ -856,82 +843,174 @@ static int _ocf_mngt_init_test_device(struct ocf_cache *cache) cache->device->volume.features.discard_zeroes = 0; } -end: - env_free(rw_buffer); - env_free(cmp_buffer); - - return ret; + ocf_mngt_pipeline_next(context->test.pipeline); } -struct _ocf_mngt_load_properties_context { - struct ocf_cachemng_attach_params *params; - env_completion complete; +static void _ocf_mngt_test_volume_second_read( + ocf_mngt_pipeline_t test_pipeline, void *priv) +{ + struct ocf_cache_attach_context *context = priv; + ocf_cache_t cache = context->cache; + + /* + * Second read + */ + + ENV_BUG_ON(env_memset(context->test.rw_buffer, PAGE_SIZE, 1)); + ENV_BUG_ON(env_memset(context->test.cmp_buffer, PAGE_SIZE, 0)); + + ocf_submit_cache_page(cache, context->test.reserved_lba_addr, + OCF_READ, context->test.rw_buffer, + _ocf_mngt_test_volume_second_read_complete, context); +} + +ocf_mngt_pipeline_step_t _ocf_mngt_test_volume_steps[] = { + _ocf_mngt_test_volume_initial_write, + _ocf_mngt_test_volume_first_read, + _ocf_mngt_test_volume_discard, + _ocf_mngt_test_volume_second_read, + NULL, }; -static void _ocf_mngt_load_properties_end(void *priv, int error, - struct ocf_metadata_load_properties *properties) +static void _ocf_mngt_test_volume_finish(ocf_mngt_pipeline_t pipeline, + void *priv, int error) { - struct _ocf_mngt_load_properties_context *context = priv; - struct ocf_cachemng_attach_params *params = context->params; - ocf_cache_t cache = params->cache; + struct ocf_cache_attach_context *context = priv; + + env_free(context->test.rw_buffer); + env_free(context->test.cmp_buffer); + ocf_mngt_pipeline_destroy(context->test.pipeline); if (error) - goto out; + ocf_mngt_pipeline_finish(context->pipeline, error); + else + ocf_mngt_pipeline_next(context->pipeline); +} - params->metadata.shutdown_status = properties->shutdown_status; - params->metadata.dirty_flushed = properties->shutdown_status; +static void _ocf_mngt_test_volume(ocf_mngt_pipeline_t pipeline, void *priv) +{ + struct ocf_cache_attach_context *context = priv; + ocf_cache_t cache = context->cache; + ocf_mngt_pipeline_t test_pipeline; + int result; - if (cache->device->init_mode == ocf_init_mode_load) { - params->metadata.line_size = properties->line_size; - cache->conf_meta->metadata_layout = properties->layout; - cache->conf_meta->cache_mode = properties->cache_mode; + cache->device->volume.features.discard_zeroes = 1; + + if (!context->cfg.perform_test) { + ocf_mngt_pipeline_next(pipeline); + return; } -out: - params->metadata.status = error; - env_completion_complete(&context->complete); + context->test.reserved_lba_addr = ocf_metadata_get_reserved_lba(cache); + + context->test.rw_buffer = env_malloc(PAGE_SIZE, ENV_MEM_NORMAL); + if (!context->test.rw_buffer) { + ocf_mngt_pipeline_finish(context->pipeline, -OCF_ERR_NO_MEM); + return; + } + + context->test.cmp_buffer = env_malloc(PAGE_SIZE, ENV_MEM_NORMAL); + if (!context->test.cmp_buffer) + goto err_buffer; + + result = ocf_mngt_pipeline_create(&test_pipeline, cache, + _ocf_mngt_test_volume_steps, + _ocf_mngt_test_volume_finish, context); + if (result) + goto err_pipeline; + + context->test.pipeline = test_pipeline; + + ocf_mngt_pipeline_next(test_pipeline); + return; + +err_pipeline: + env_free(context->test.rw_buffer); +err_buffer: + env_free(context->test.cmp_buffer); + ocf_mngt_pipeline_finish(context->pipeline, -OCF_ERR_NO_MEM); } /** * Prepare metadata accordingly to mode (for load/recovery read from disk) */ -static int _ocf_mngt_init_prepare_metadata( - struct ocf_cachemng_attach_params *params) -{ - struct _ocf_mngt_load_properties_context context; - ocf_cache_t cache = params->cache; - int ret, i; - context.params = params; - env_completion_init(&context.complete); +static void _ocf_mngt_attach_load_properties_end(void *priv, int error, + struct ocf_metadata_load_properties *properties) +{ + struct ocf_cache_attach_context *context = priv; + ocf_cache_t cache = context->cache; + + context->metadata.status = error; + + if (error) { + ocf_mngt_pipeline_next(context->pipeline); + return; + } + + context->metadata.shutdown_status = properties->shutdown_status; + context->metadata.dirty_flushed = properties->shutdown_status; + + if (cache->device->init_mode == ocf_init_mode_load) { + context->metadata.line_size = properties->line_size; + cache->conf_meta->metadata_layout = properties->layout; + cache->conf_meta->cache_mode = properties->cache_mode; + } + + ocf_mngt_pipeline_next(context->pipeline); +} + +static void _ocf_mngt_attach_load_properties(ocf_mngt_pipeline_t pipeline, + void *priv) +{ + struct ocf_cache_attach_context *context = priv; + ocf_cache_t cache = context->cache; OCF_ASSERT_PLUGGED(cache); - if (cache->device->init_mode != ocf_init_mode_metadata_volatile) { - ocf_metadata_load_properties(&cache->device->volume, - _ocf_mngt_load_properties_end, &context); + context->metadata.shutdown_status = ocf_metadata_clean_shutdown; + context->metadata.dirty_flushed = DIRTY_FLUSHED; + context->metadata.line_size = context->cfg.cache_line_size; - env_completion_wait(&context.complete); - if (params->load && params->metadata.status) { - ret = -OCF_ERR_START_CACHE_FAIL; - return ret; - } + if (cache->device->init_mode == ocf_init_mode_metadata_volatile) { + ocf_mngt_pipeline_next(context->pipeline); + return; } - params->metadata.line_size = params->metadata.line_size ?: + ocf_metadata_load_properties(&cache->device->volume, + _ocf_mngt_attach_load_properties_end, context); +} + +static void _ocf_mngt_attach_prepare_metadata(ocf_mngt_pipeline_t pipeline, + void *priv) +{ + struct ocf_cache_attach_context *context = priv; + ocf_cache_t cache = context->cache; + int ret, i; + + if (context->init_mode == ocf_init_mode_load && + context->metadata.status) { + ocf_mngt_pipeline_finish(context->pipeline, + -OCF_ERR_START_CACHE_FAIL); + return; + } + + context->metadata.line_size = context->metadata.line_size ?: cache->metadata.settings.size; /* * Initialize variable size metadata segments */ - if (ocf_metadata_init_variable_size(cache, params->device_size, - params->metadata.line_size, + if (ocf_metadata_init_variable_size(cache, context->volume_size, + context->metadata.line_size, cache->conf_meta->metadata_layout)) { - return -OCF_ERR_START_CACHE_FAIL; - + ocf_mngt_pipeline_finish(context->pipeline, + -OCF_ERR_START_CACHE_FAIL); + return; } + ocf_cache_log(cache, log_debug, "Cache attached\n"); - params->flags.attached_metadata_inited = true; + context->flags.attached_metadata_inited = true; for (i = 0; i < OCF_IO_CLASS_MAX + 1; ++i) { cache->user_parts[i].runtime = @@ -941,119 +1020,109 @@ static int _ocf_mngt_init_prepare_metadata( cache->device->freelist_part = &cache->device->runtime_meta->freelist_part; ret = ocf_concurrency_init(cache); - if (!ret) - params->flags.concurrency_inited = 1; + if (ret) { + ocf_mngt_pipeline_finish(context->pipeline, ret); + return; + } - return ret; + context->flags.concurrency_inited = 1; + + ocf_mngt_pipeline_next(context->pipeline); } /** * @brief initializing cache anew (not loading or recovering) */ -static int _ocf_mngt_init_instance_init(struct ocf_cachemng_attach_params *attach_params) +static void _ocf_mngt_init_instance_init(struct ocf_cache_attach_context *context) { - struct ocf_cache *cache = attach_params->cache; + ocf_cache_t cache = context->cache; - if (!attach_params->metadata.status && !attach_params->force && - attach_params->metadata.shutdown_status != + if (!context->metadata.status && !context->cfg.force && + context->metadata.shutdown_status != ocf_metadata_detached) { - if (attach_params->metadata.shutdown_status != + if (context->metadata.shutdown_status != ocf_metadata_clean_shutdown) { ocf_cache_log(cache, log_err, DIRTY_SHUTDOWN_ERROR_MSG); - return -OCF_ERR_DIRTY_SHUTDOWN; + ocf_mngt_pipeline_finish(context->pipeline, + -OCF_ERR_DIRTY_SHUTDOWN); + return; } - if (attach_params->metadata.dirty_flushed == DIRTY_NOT_FLUSHED) { + if (context->metadata.dirty_flushed == DIRTY_NOT_FLUSHED) { ocf_cache_log(cache, log_err, DIRTY_NOT_FLUSHED_ERROR_MSG); - return -OCF_ERR_DIRTY_EXISTS; + ocf_mngt_pipeline_finish(context->pipeline, + -OCF_ERR_DIRTY_EXISTS); + return; } } - init_attached_data_structures(cache, - attach_params->cache->eviction_policy_init); + init_attached_data_structures(cache, cache->eviction_policy_init); /* In initial cache state there is no dirty data, so all dirty data is considered to be flushed */ cache->conf_meta->dirty_flushed = true; - if (ocf_metadata_flush_all(cache)) { - ocf_cache_log(cache, log_err, - "ERROR: Cannot save cache state\n"); - return -OCF_ERR_WRITE_CACHE; - } - return 0; + ocf_mngt_pipeline_next(context->pipeline); } -static int check_ram_availability(ocf_ctx_t ctx, - struct ocf_cachemng_attach_params *attach_params) +uint64_t _ocf_mngt_calculate_ram_needed(ocf_cache_t cache, + ocf_volume_t cache_volume) { - struct ocf_cache *cache = attach_params->cache; - ocf_cache_line_size_t line_size = cache->metadata.settings.size; + ocf_cache_line_size_t line_size = ocf_line_size(cache); + uint64_t volume_size = ocf_volume_get_length(cache_volume); uint64_t const_data_size; uint64_t cache_line_no; uint64_t data_per_line; - uint64_t free_ram; + uint64_t min_free_ram; /* Superblock + per core metadata */ const_data_size = 50 * MiB; /* Cache metadata */ - cache_line_no = attach_params->device_size / line_size; + cache_line_no = volume_size / line_size; data_per_line = (52 + (2 * (line_size / KiB / 4))); - attach_params->min_free_ram = const_data_size + cache_line_no * data_per_line; + min_free_ram = const_data_size + cache_line_no * data_per_line; /* 110% of calculated value */ - attach_params->min_free_ram = (11 * attach_params->min_free_ram) / 10; + min_free_ram = (11 * min_free_ram) / 10; - free_ram = env_get_free_memory(); - - if (free_ram < attach_params->min_free_ram) { - ocf_log(ctx, log_err, "Not enough free RAM for cache " - "metadata to start cache\n"); - ocf_log(ctx, log_err, "Available RAM: %" ENV_PRIu64 " B\n", - free_ram); - ocf_log(ctx, log_err, "Needed RAM: %" ENV_PRIu64 " B\n", - attach_params->min_free_ram); - return -OCF_ERR_NO_FREE_RAM; - } - - return 0; + return min_free_ram; } -/** - * finalize init instance action - * (same handling for all three initialization modes) - */ -static int _ocf_mngt_init_post_action(struct ocf_cachemng_attach_params *attach_params) +int ocf_mngt_get_ram_needed(ocf_cache_t cache, + struct ocf_mngt_cache_device_config *cfg, uint64_t *ram_needed) { - struct ocf_cache *cache = attach_params->cache; + struct ocf_volume volume; + ocf_volume_type_t type; int result; - /* clear clean shutdown status */ - if (ocf_metadata_set_shutdown_status(cache, - ocf_metadata_dirty_shutdown)) { - ocf_cache_log(cache, log_err, "Cannot flush shutdown status\n"); - return -OCF_ERR_WRITE_CACHE; + OCF_CHECK_NULL(cache); + OCF_CHECK_NULL(cfg); + OCF_CHECK_NULL(ram_needed); + + type = ocf_ctx_get_volume_type(cache->owner, cfg->volume_type); + if (!type) + return -OCF_ERR_INVAL_VOLUME_TYPE; + + result = ocf_volume_init(&cache->device->volume, type, + &cfg->uuid, false); + if (result) + return result; + + result = ocf_volume_open(&volume); + if (result) { + ocf_volume_deinit(&volume); + return result; } - if (!attach_params->flags.cleaner_started) { - result = ocf_start_cleaner(cache); - if (result) { - ocf_cache_log(cache, log_err, - "Error while starting cleaner\n"); - return result; - } - attach_params->flags.cleaner_started = true; - } + *ram_needed = _ocf_mngt_calculate_ram_needed(cache, &volume); - env_waitqueue_init(&cache->pending_dirty_wq); - env_waitqueue_init(&cache->pending_cache_wq); - - env_atomic_set(&cache->attached, 1); + ocf_volume_close(&volume); + ocf_volume_deinit(&volume); return 0; } @@ -1078,8 +1147,8 @@ static void _ocf_mngt_init_handle_error(ocf_cache_t cache, env_mutex_lock(&ctx->lock); - if (cache->flush_queue) - ocf_queue_put(cache->flush_queue); + if (cache->mngt_queue) + ocf_queue_put(cache->mngt_queue); list_for_each_entry_safe(queue, tmp_queue, &cache->io_queues, list) ocf_queue_put(queue); @@ -1093,73 +1162,32 @@ static void _ocf_mngt_init_handle_error(ocf_cache_t cache, } static void _ocf_mngt_attach_handle_error( - struct ocf_cachemng_attach_params *attach_params) + struct ocf_cache_attach_context *context) { - struct ocf_cache *cache = attach_params->cache; + ocf_cache_t cache = context->cache; - if (attach_params->flags.cleaner_started) + if (context->flags.cleaner_started) ocf_stop_cleaner(cache); - if (attach_params->flags.cores_opened) + if (context->flags.cores_opened) _ocf_mngt_close_all_uninitialized_cores(cache); - if (attach_params->flags.attached_metadata_inited) + if (context->flags.attached_metadata_inited) ocf_metadata_deinit_variable_size(cache); - if (attach_params->flags.device_opened) + if (context->flags.device_opened) ocf_volume_close(&cache->device->volume); - if (attach_params->flags.concurrency_inited) + if (context->flags.concurrency_inited) ocf_concurrency_deinit(cache); - if (attach_params->flags.volume_inited) + if (context->flags.volume_inited) ocf_volume_deinit(&cache->device->volume); - if (attach_params->flags.device_alloc) + if (context->flags.device_alloc) env_vfree(cache->device); } -static int _ocf_mngt_cache_discard_after_metadata(struct ocf_cache *cache) -{ - int result; - uint64_t addr = cache->device->metadata_offset; - uint64_t length = ocf_volume_get_length( - &cache->device->volume) - addr; - bool discard = cache->device->volume.features.discard_zeroes; - - if (!discard && ocf_volume_is_atomic(&cache->device->volume)) { - /* discard does not zero data - need to explicitly write - zeroes */ - result = ocf_submit_write_zeroes_wait( - &cache->device->volume, addr, length); - if (!result) { - result = ocf_submit_volume_flush_wait( - &cache->device->volume); - } - } else { - /* Discard volume after metadata */ - result = ocf_submit_volume_discard_wait(&cache->device->volume, addr, - length); - } - - if (result) { - ocf_cache_log(cache, log_warn, "%s failed\n", - discard ? "Discarding whole cache device" : - "Overwriting cache with zeroes"); - - if (ocf_volume_is_atomic(&cache->device->volume)) { - ocf_cache_log(cache, log_err, "This step is required" - " for atomic mode!\n"); - } else { - ocf_cache_log(cache, log_warn, "This may impact cache" - " performance!\n"); - result = 0; - } - } - - return result; -} - static int _ocf_mngt_cache_init(ocf_cache_t cache, struct ocf_cachemng_init_params *params) { @@ -1300,94 +1328,349 @@ static void _ocf_mngt_init_attached_nonpersistent(ocf_cache_t cache) env_atomic_set(&cache->fallback_pt_error_counter, 0); } -static int _ocf_mngt_cache_attach(ocf_cache_t cache, - struct ocf_mngt_cache_device_config *device_cfg, - bool load) - +static void _ocf_mngt_attach_check_ram(ocf_mngt_pipeline_t pipeline, void *priv) { - struct ocf_cachemng_attach_params attach_params; - int result; + struct ocf_cache_attach_context *context = priv; + ocf_cache_t cache = context->cache; + uint64_t min_free_ram; + uint64_t free_ram; - ENV_BUG_ON(env_memset(&attach_params, sizeof(attach_params), 0)); + min_free_ram = _ocf_mngt_calculate_ram_needed(cache, + &cache->device->volume); - if (cache->metadata.is_volatile && load) - return -EINVAL; + free_ram = env_get_free_memory(); - attach_params.force = device_cfg->force; - attach_params.uuid = device_cfg->uuid; - attach_params.device_type = device_cfg->volume_type; - attach_params.perform_test = device_cfg->perform_test; - attach_params.metadata.shutdown_status = ocf_metadata_clean_shutdown; - attach_params.metadata.dirty_flushed = DIRTY_FLUSHED; - attach_params.metadata.line_size = device_cfg->cache_line_size; - attach_params.cache = cache; - attach_params.load = load; - - _ocf_mngt_init_attached_nonpersistent(cache); - - result = _ocf_mngt_attach_cache_device(cache, &attach_params); - if (result) - goto _cache_mng_init_attach_ERROR; - - result = check_ram_availability(ocf_cache_get_ctx(cache), - &attach_params); - device_cfg->min_free_ram = attach_params.min_free_ram; - if (result) - goto _cache_mng_init_attach_ERROR; - - /* Prepare metadata */ - result = _ocf_mngt_init_prepare_metadata(&attach_params); - if (result) - goto _cache_mng_init_attach_ERROR; - - /* Test device features */ - cache->device->volume.features.discard_zeroes = 1; - if (attach_params.perform_test) { - result = _ocf_mngt_init_test_device(cache); - if (result) - goto _cache_mng_init_attach_ERROR; + if (free_ram < min_free_ram) { + ocf_cache_log(cache, log_err, "Not enough free RAM for cache " + "metadata to start cache\n"); + ocf_cache_log(cache, log_err, + "Available RAM: %" ENV_PRIu64 " B\n", free_ram); + ocf_cache_log(cache, log_err, "Needed RAM: %" ENV_PRIu64 " B\n", + min_free_ram); + ocf_mngt_pipeline_finish(pipeline, -OCF_ERR_NO_FREE_RAM); } + ocf_mngt_pipeline_next(pipeline); +} + + +static void _ocf_mngt_attach_load_superblock_complete(void *priv, int error) +{ + struct ocf_cache_attach_context *context = priv; + ocf_cache_t cache = context->cache; + + if (error) { + ocf_cache_log(cache, log_err, + "ERROR: Cannot load cache state\n"); + ocf_mngt_pipeline_finish(context->pipeline, + -OCF_ERR_START_CACHE_FAIL); + return; + } + + ocf_mngt_pipeline_next(context->pipeline); +} + +static void _ocf_mngt_attach_load_superblock(ocf_mngt_pipeline_t pipeline, + void *priv) +{ + struct ocf_cache_attach_context *context = priv; + ocf_cache_t cache = context->cache; + + if (cache->device->init_mode != ocf_init_mode_load) { + ocf_mngt_pipeline_next(context->pipeline); + return; + } + + ocf_cache_log(cache, log_info, "Loading cache state...\n"); + ocf_metadata_load_superblock(cache, + _ocf_mngt_attach_load_superblock_complete, context); +} + +static void _ocf_mngt_attach_init_instance(ocf_mngt_pipeline_t pipeline, + void *priv) +{ + struct ocf_cache_attach_context *context = priv; + ocf_cache_t cache = context->cache; + switch (cache->device->init_mode) { case ocf_init_mode_init: case ocf_init_mode_metadata_volatile: - result = _ocf_mngt_init_instance_init(&attach_params); - break; + _ocf_mngt_init_instance_init(context); + return; case ocf_init_mode_load: - result = _ocf_mngt_init_instance_load(&attach_params); - break; + _ocf_mngt_init_instance_load(context); + return; default: - result = OCF_ERR_INVAL; + ocf_mngt_pipeline_finish(context->pipeline, -OCF_ERR_INVAL); } - - if (result) - goto _cache_mng_init_attach_ERROR; - - /* Discard whole device after metadata if it's a new instance. */ - if (device_cfg->discard_on_start && cache->device->init_mode != - ocf_init_mode_load) { - result = _ocf_mngt_cache_discard_after_metadata(cache); - if (result) - goto _cache_mng_init_attach_ERROR; - } - - if (cache->device->init_mode != ocf_init_mode_load) { - result = _ocf_mngt_cache_add_cores_t_clean_pol(cache); - if (result) - goto _cache_mng_init_attach_ERROR; - } - - result = _ocf_mngt_init_post_action(&attach_params); - if (result) - goto _cache_mng_init_attach_ERROR; - - return 0; - -_cache_mng_init_attach_ERROR: - _ocf_mngt_attach_handle_error(&attach_params); - return result; } +static void _ocf_mngt_attach_clean_pol(ocf_mngt_pipeline_t pipeline, void *priv) +{ + struct ocf_cache_attach_context *context = priv; + ocf_cache_t cache = context->cache; + int result; + + /* TODO: Should this even be here? */ + if (cache->device->init_mode != ocf_init_mode_load) { + result = _ocf_mngt_cache_add_cores_t_clean_pol(cache); + if (result) { + ocf_mngt_pipeline_finish(context->pipeline, result); + return; + } + } + + ocf_mngt_pipeline_next(context->pipeline); +} + +static void _ocf_mngt_attach_flush_metadata_complete(void *priv, int error) +{ + struct ocf_cache_attach_context *context = priv; + ocf_cache_t cache = context->cache; + + if (error) { + ocf_cache_log(cache, log_err, + "ERROR: Cannot save cache state\n"); + ocf_mngt_pipeline_finish(context->pipeline, + -OCF_ERR_WRITE_CACHE); + return; + } + + ocf_mngt_pipeline_next(context->pipeline); +} + +static void _ocf_mngt_attach_flush_metadata(ocf_mngt_pipeline_t pipeline, + void *priv) +{ + struct ocf_cache_attach_context *context = priv; + ocf_cache_t cache = context->cache; + + ocf_metadata_flush_all(cache, + _ocf_mngt_attach_flush_metadata_complete, context); +} + +static void _ocf_mngt_attach_discard_complete(void *priv, int error) +{ + struct ocf_cache_attach_context *context = priv; + ocf_cache_t cache = context->cache; + bool discard = cache->device->volume.features.discard_zeroes; + + if (error) { + ocf_cache_log(cache, log_warn, "%s failed\n", + discard ? "Discarding whole cache device" : + "Overwriting cache with zeroes"); + + if (ocf_volume_is_atomic(&cache->device->volume)) { + ocf_cache_log(cache, log_err, "This step is required" + " for atomic mode!\n"); + ocf_mngt_pipeline_finish(context->pipeline, error); + return; + } + + ocf_cache_log(cache, log_warn, "This may impact cache" + " performance!\n"); + } + + ocf_mngt_pipeline_next(context->pipeline); +} + +static void _ocf_mngt_attach_discard(ocf_mngt_pipeline_t pipeline, void *priv) +{ + struct ocf_cache_attach_context *context = priv; + ocf_cache_t cache = context->cache; + uint64_t addr = cache->device->metadata_offset; + uint64_t length = ocf_volume_get_length(&cache->device->volume) - addr; + bool discard = cache->device->volume.features.discard_zeroes; + + if (cache->device->init_mode == ocf_init_mode_load) { + ocf_mngt_pipeline_next(context->pipeline); + return; + } + + if (!context->cfg.discard_on_start) { + ocf_mngt_pipeline_next(context->pipeline); + return; + } + + if (!discard && ocf_volume_is_atomic(&cache->device->volume)) { + /* discard doesn't zero data - need to explicitly write zeros */ + ocf_submit_write_zeros(&cache->device->volume, addr, length, + _ocf_mngt_attach_discard_complete, context); + } else { + /* Discard volume after metadata */ + ocf_submit_volume_discard(&cache->device->volume, addr, length, + _ocf_mngt_attach_discard_complete, context); + } +} + +static void _ocf_mngt_attach_flush_complete(void *priv, int error) +{ + struct ocf_cache_attach_context *context = priv; + + if (error) + ocf_mngt_pipeline_finish(context->pipeline, error); + else + ocf_mngt_pipeline_next(context->pipeline); +} + +static void _ocf_mngt_attach_flush(ocf_mngt_pipeline_t pipeline, void *priv) +{ + struct ocf_cache_attach_context *context = priv; + ocf_cache_t cache = context->cache; + bool discard = cache->device->volume.features.discard_zeroes; + + if (!discard && ocf_volume_is_atomic(&cache->device->volume)) { + ocf_submit_volume_flush(&cache->device->volume, + _ocf_mngt_attach_flush_complete, context); + } else { + ocf_mngt_pipeline_next(context->pipeline); + } +} + +static void _ocf_mngt_attach_shutdown_status_complete(void *priv, int error) +{ + struct ocf_cache_attach_context *context = priv; + ocf_cache_t cache = context->cache; + + if (error) { + ocf_cache_log(cache, log_err, "Cannot flush shutdown status\n"); + ocf_mngt_pipeline_finish(context->pipeline, + -OCF_ERR_WRITE_CACHE); + return; + } + + ocf_mngt_pipeline_next(context->pipeline); +} + +static void _ocf_mngt_attach_shutdown_status(ocf_mngt_pipeline_t pipeline, + void *priv) +{ + struct ocf_cache_attach_context *context = priv; + ocf_cache_t cache = context->cache; + + /* clear clean shutdown status */ + ocf_metadata_set_shutdown_status(cache, ocf_metadata_dirty_shutdown, + _ocf_mngt_attach_shutdown_status_complete, context); +} + +static void _ocf_mngt_attach_post_init(ocf_mngt_pipeline_t pipeline, void *priv) +{ + struct ocf_cache_attach_context *context = priv; + ocf_cache_t cache = context->cache; + int result; + + if (!context->flags.cleaner_started) { + result = ocf_start_cleaner(cache); + if (result) { + ocf_cache_log(cache, log_err, + "Error while starting cleaner\n"); + ocf_mngt_pipeline_finish(context->pipeline, result); + return; + } + context->flags.cleaner_started = true; + } + + env_waitqueue_init(&cache->pending_dirty_wq); + env_waitqueue_init(&cache->pending_cache_wq); + + env_atomic_set(&cache->attached, 1); + + ocf_mngt_pipeline_next(context->pipeline); +} + +ocf_mngt_pipeline_step_t _ocf_mngt_cache_attach_pipeline_steps[] = { + _ocf_mngt_attach_cache_device, + _ocf_mngt_attach_check_ram, + _ocf_mngt_attach_load_properties, + _ocf_mngt_attach_prepare_metadata, + _ocf_mngt_test_volume, + _ocf_mngt_attach_load_superblock, + _ocf_mngt_attach_init_instance, + _ocf_mngt_attach_clean_pol, + _ocf_mngt_attach_flush_metadata, + _ocf_mngt_attach_discard, + _ocf_mngt_attach_flush, + _ocf_mngt_attach_shutdown_status, + _ocf_mngt_attach_post_init, + NULL, +}; + +static void _ocf_mngt_cache_attach_finish(ocf_mngt_pipeline_t pipeline, + void *priv, int error) +{ + struct ocf_cache_attach_context *context = priv; + + ocf_mngt_pipeline_destroy(context->pipeline); + + if (error) + _ocf_mngt_attach_handle_error(context); + + context->cmpl(context->cache, context->priv1, context->priv2, error); + env_vfree(context->cfg.uuid.data); + env_vfree(context); +} + +static void _ocf_mngt_cache_attach(ocf_cache_t cache, + struct ocf_mngt_cache_device_config *cfg, bool load, + _ocf_mngt_cache_attach_end_t cmpl, void *priv1, void *priv2) +{ + struct ocf_cache_attach_context *context; + ocf_mngt_pipeline_t pipeline; + void *data; + int result; + + context = env_vzalloc(sizeof(*context)); + if (!context) { + context->cmpl(cache, priv1, priv2, -OCF_ERR_NO_MEM); + return; + } + + context->cmpl = cmpl; + context->priv1 = priv1; + context->priv2 = priv2; + + context->cache = cache; + context->cfg = *cfg; + + data = env_vmalloc(cfg->uuid.size); + if (!data) { + result = -OCF_ERR_NO_MEM; + goto err_context; + } + + result = env_memcpy(data, cfg->uuid.size, cfg->uuid.data, + cfg->uuid.size); + if (result) + goto err_uuid; + + context->cfg.uuid.data = data; + + if (cache->metadata.is_volatile) { + context->init_mode = ocf_init_mode_metadata_volatile; + } else { + context->init_mode = load ? + ocf_init_mode_load : ocf_init_mode_init; + } + + result = ocf_mngt_pipeline_create(&pipeline, cache, + _ocf_mngt_cache_attach_pipeline_steps, + _ocf_mngt_cache_attach_finish, context); + if (result) + goto err_uuid; + + context->pipeline = pipeline; + + _ocf_mngt_init_attached_nonpersistent(cache); + + ocf_mngt_pipeline_next(pipeline); + return; + +err_uuid: + env_vfree(data); +err_context: + env_vfree(context); + cmpl(cache, priv1, priv2, result); +} static int _ocf_mngt_cache_validate_cfg(struct ocf_mngt_cache_config *cfg) { @@ -1476,6 +1759,35 @@ int ocf_mngt_cache_start(ocf_ctx_t ctx, ocf_cache_t *cache, return result; } +int ocf_mngt_cache_set_mngt_queue(ocf_cache_t cache, ocf_queue_t queue) +{ + OCF_CHECK_NULL(cache); + OCF_CHECK_NULL(queue); + + if (cache->mngt_queue) + return -OCF_ERR_INVAL; + + ocf_queue_get(queue); + cache->mngt_queue = queue; + + return 0; +} + +static void _ocf_mngt_cache_attach_complete(ocf_cache_t cache, void *priv1, + void *priv2, int error) +{ + ocf_mngt_cache_attach_end_t cmpl = priv1; + + if (!error) { + ocf_cache_log(cache, log_info, "Successfully attached\n"); + } else { + ocf_cache_log(cache, log_err, "Attaching cache device " + "failed\n"); + } + + cmpl(cache, priv2, error); +} + void ocf_mngt_cache_attach(ocf_cache_t cache, struct ocf_mngt_cache_device_config *cfg, ocf_mngt_cache_attach_end_t cmpl, void *priv) @@ -1491,15 +1803,40 @@ void ocf_mngt_cache_attach(ocf_cache_t cache, return; } - result = _ocf_mngt_cache_attach(cache, cfg, false); - if (!result) { - ocf_cache_log(cache, log_info, "Successfully attached\n"); - } else { - ocf_cache_log(cache, log_err, "Attaching cache device " - "failed\n"); - } + _ocf_mngt_cache_attach(cache, cfg, false, + _ocf_mngt_cache_attach_complete, cmpl, priv); +} - cmpl(cache, priv, result); +typedef void (*_ocf_mngt_cache_unplug_end_t)(void *context, int error); + +struct _ocf_mngt_cache_unplug_context { + _ocf_mngt_cache_unplug_end_t cmpl; + void *priv; + ocf_cache_t cache; +}; + +static void _ocf_mngt_cache_unplug_complete(void *priv, int error) +{ + struct _ocf_mngt_cache_unplug_context *context = priv; + ocf_cache_t cache = context->cache; + + ocf_volume_close(&cache->device->volume); + + ocf_metadata_deinit_variable_size(cache); + ocf_concurrency_deinit(cache); + + ocf_volume_deinit(&cache->device->volume); + + 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 */ + _ocf_mngt_init_attached_nonpersistent(cache); + + context->cmpl(context->priv, error ? -OCF_ERR_WRITE_CACHE : 0); + env_vfree(context); } /** @@ -1512,16 +1849,25 @@ void ocf_mngt_cache_attach(ocf_cache_t cache, * clean shutdown in metadata and flush all containers. * - false if the device is to be detached from cache - loading * metadata from this device will not be possible. - * - * @retval 0 operation successfull - * @retval non-zero error status + * @param cmpl Completion callback + * @param priv Completion context */ -static int _ocf_mngt_cache_unplug(ocf_cache_t cache, bool stop) +static void _ocf_mngt_cache_unplug(ocf_cache_t cache, bool stop, + _ocf_mngt_cache_unplug_end_t cmpl, void *priv) { - int result; + struct _ocf_mngt_cache_unplug_context *context; - if (stop) - ENV_BUG_ON(cache->conf_meta->core_count != 0); + ENV_BUG_ON(stop && cache->conf_meta->core_count != 0); + + context = env_vzalloc(sizeof(*context)); + if (!context) { + cmpl(priv, -OCF_ERR_NO_MEM); + return; + } + + context->cmpl = cmpl; + context->priv = priv; + context->cache = cache; ocf_stop_cleaner(cache); @@ -1541,78 +1887,13 @@ static int _ocf_mngt_cache_unplug(ocf_cache_t cache, bool stop) if (!stop) { /* Just set correct shutdown status */ - result = ocf_metadata_set_shutdown_status(cache, - ocf_metadata_detached); + ocf_metadata_set_shutdown_status(cache, ocf_metadata_detached, + _ocf_mngt_cache_unplug_complete, context); } else { /* Flush metadata */ - result = ocf_metadata_flush_all(cache); + ocf_metadata_flush_all(cache, + _ocf_mngt_cache_unplug_complete, context); } - - ocf_volume_close(&cache->device->volume); - - ocf_metadata_deinit_variable_size(cache); - ocf_concurrency_deinit(cache); - - ocf_volume_deinit(&cache->device->volume); - - 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 */ - _ocf_mngt_init_attached_nonpersistent(cache); - - if (result) - return -OCF_ERR_WRITE_CACHE; - - return 0; -} - -static int _ocf_mngt_cache_stop(ocf_cache_t cache) -{ - int i, j, no, result = 0; - ocf_ctx_t owner = cache->owner; - ocf_queue_t queue, tmp_queue; - - no = cache->conf_meta->core_count; - - env_bit_set(ocf_cache_state_stopping, &cache->cache_state); - env_bit_clear(ocf_cache_state_running, &cache->cache_state); - - ocf_cache_wait_for_io_finish(cache); - - /* All exported objects removed, cleaning up rest. */ - for (i = 0, j = 0; j < no && i < OCF_CORE_MAX; i++) { - if (!env_bit_test(i, cache->conf_meta->valid_core_bitmap)) - continue; - cache_mng_core_remove_from_cache(cache, i); - if (ocf_cache_is_device_attached(cache)) - cache_mng_core_remove_from_cleaning_pol(cache, i); - cache_mng_core_close(cache, i); - j++; - } - ENV_BUG_ON(cache->conf_meta->core_count != 0); - - if (env_atomic_read(&cache->attached)) - result = _ocf_mngt_cache_unplug(cache, true); - - if (cache->flush_queue) - ocf_queue_put(cache->flush_queue); - - list_for_each_entry_safe(queue, tmp_queue, &cache->io_queues, list) - ocf_queue_put(queue); - - env_mutex_lock(&owner->lock); - /* Mark device uninitialized */ - cache->valid_ocf_cache_device_t = 0; - /* Remove cache from the list */ - list_del(&cache->list); - /* Finally release cache instance */ - ocf_mngt_cache_put(cache); - env_mutex_unlock(&owner->lock); - - return result; } static int _ocf_mngt_cache_load_core_log(ocf_core_t core, void *cntx) @@ -1639,6 +1920,22 @@ static void _ocf_mngt_cache_load_log(ocf_cache_t cache) cache, false); } +static void _ocf_mngt_cache_load_complete(ocf_cache_t cache, void *priv1, + void *priv2, int error) +{ + ocf_mngt_cache_load_end_t cmpl = priv1; + + if (error) { + cmpl(cache, priv2, error); + return; + } + + _ocf_mng_cache_set_valid(cache); + _ocf_mngt_cache_load_log(cache); + + cmpl(cache, priv2, 0); +} + void ocf_mngt_cache_load(ocf_cache_t cache, struct ocf_mngt_cache_device_config *cfg, ocf_mngt_cache_load_end_t cmpl, void *priv) @@ -1648,59 +1945,190 @@ void ocf_mngt_cache_load(ocf_cache_t cache, OCF_CHECK_NULL(cache); OCF_CHECK_NULL(cfg); + /* Load is not allowed in volatile metadata mode */ + if (cache->metadata.is_volatile) + cmpl(cache, priv, -EINVAL); + result = _ocf_mngt_cache_validate_device_cfg(cfg); if (result) { cmpl(cache, priv, result); return; } - result = _ocf_mngt_cache_attach(cache, cfg, true); - if (result) { - cmpl(cache, priv, result); + _ocf_mngt_cache_attach(cache, cfg, true, + _ocf_mngt_cache_load_complete, cmpl, priv); +} + +struct ocf_mngt_cache_stop_context { + ocf_mngt_cache_stop_end_t cmpl; + void *priv; + ocf_mngt_pipeline_t pipeline; + ocf_cache_t cache; + ocf_ctx_t ctx; + char cache_name[OCF_CACHE_NAME_SIZE]; + int error; +}; + +static void ocf_mngt_cache_stop_wait_io(ocf_mngt_pipeline_t pipeline, + void *priv) +{ + 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_mngt_pipeline_next(pipeline); +} + +static void ocf_mngt_cache_stop_remove_cores(ocf_mngt_pipeline_t pipeline, + void *priv) +{ + struct ocf_mngt_cache_stop_context *context = priv; + ocf_cache_t cache = context->cache; + int i, j, no; + + no = cache->conf_meta->core_count; + + /* All exported objects removed, cleaning up rest. */ + for (i = 0, j = 0; j < no && i < OCF_CORE_MAX; i++) { + if (!env_bit_test(i, cache->conf_meta->valid_core_bitmap)) + continue; + cache_mng_core_remove_from_cache(cache, i); + if (ocf_cache_is_device_attached(cache)) + cache_mng_core_remove_from_cleaning_pol(cache, i); + cache_mng_core_close(cache, i); + j++; + } + ENV_BUG_ON(cache->conf_meta->core_count != 0); + + ocf_mngt_pipeline_next(pipeline); +} + +static void ocf_mngt_cache_stop_unplug_complete(void *priv, int error) +{ + struct ocf_mngt_cache_stop_context *context = priv; + + context->error = error; + ocf_mngt_pipeline_next(context->pipeline); +} + +static void ocf_mngt_cache_stop_unplug(ocf_mngt_pipeline_t pipeline, + void *priv) +{ + struct ocf_mngt_cache_stop_context *context = priv; + ocf_cache_t cache = context->cache; + + if (!env_atomic_read(&cache->attached)) { + ocf_mngt_pipeline_next(pipeline); return; } - _ocf_mng_cache_set_valid(cache); + _ocf_mngt_cache_unplug(cache, true, + ocf_mngt_cache_stop_unplug_complete, context); +} - _ocf_mngt_cache_load_log(cache); +static void ocf_mngt_cache_stop_put_io_queues(ocf_mngt_pipeline_t pipeline, + void *priv) +{ + struct ocf_mngt_cache_stop_context *context = priv; + ocf_cache_t cache = context->cache; + ocf_queue_t queue, tmp_queue; - cmpl(cache, priv, 0); + list_for_each_entry_safe(queue, tmp_queue, &cache->io_queues, list) + ocf_queue_put(queue); + + ocf_mngt_pipeline_next(pipeline); +} + +ocf_mngt_pipeline_step_t ocf_mngt_cache_stop_pipeline_steps[] = { + ocf_mngt_cache_stop_wait_io, + ocf_mngt_cache_stop_remove_cores, + ocf_mngt_cache_stop_unplug, + ocf_mngt_cache_stop_put_io_queues, + NULL, +}; + +static void ocf_mngt_cache_stop_finish(ocf_mngt_pipeline_t pipeline, + void *priv, int error) +{ + struct ocf_mngt_cache_stop_context *context = priv; + ocf_cache_t cache = context->cache; + ocf_ctx_t ctx = context->ctx; + + ocf_mngt_pipeline_destroy(context->pipeline); + + if (error) + context->error = error; + + env_mutex_lock(&ctx->lock); + /* Mark device uninitialized */ + cache->valid_ocf_cache_device_t = 0; + /* Remove cache from the list */ + list_del(&cache->list); + /* Finally release cache instance */ + ocf_mngt_cache_put(cache); + env_mutex_unlock(&ctx->lock); + + + if (context->error == -OCF_ERR_WRITE_CACHE) { + ocf_log(ctx, log_warn, "Stopped cache %s with errors\n", + context->cache_name); + } else if (context->error) { + ocf_log(ctx, log_err, "Stopping cache %s failed\n", + context->cache_name); + } else { + ocf_log(ctx, log_info, "Cache %s successfully stopped\n", + context->cache_name); + } + + context->cmpl(cache, context->priv, context->error); + env_vfree(context); } 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; + ocf_mngt_pipeline_t pipeline; int result; - char cache_name[OCF_CACHE_NAME_SIZE]; - ocf_ctx_t ctx; OCF_CHECK_NULL(cache); - result = env_strncpy(cache_name, sizeof(cache_name), - ocf_cache_get_name(cache), sizeof(cache_name)); - if (result) { - cmpl(cache, priv, result); + context = env_vzalloc(sizeof(*context)); + if (!context) { + cmpl(cache, priv, -OCF_ERR_NO_MEM); return; } - ctx = ocf_cache_get_ctx(cache); + result = env_strncpy(context->cache_name, sizeof(context->cache_name), + ocf_cache_get_name(cache), sizeof(context->cache_name)); + if (result) { + env_vfree(context); + cmpl(cache, priv, -OCF_ERR_NO_MEM); + return; + } + + result = ocf_mngt_pipeline_create(&pipeline, cache, + ocf_mngt_cache_stop_pipeline_steps, + ocf_mngt_cache_stop_finish, context); + if (result) { + env_vfree(context); + cmpl(cache, priv, -OCF_ERR_NO_MEM); + return; + } + + context->cmpl = cmpl; + context->priv = priv; + context->pipeline = pipeline; + context->cache = cache; + context->ctx = cache->owner; ocf_cache_log(cache, log_info, "Stopping cache\n"); - result = _ocf_mngt_cache_stop(cache); + env_bit_set(ocf_cache_state_stopping, &cache->cache_state); + env_bit_clear(ocf_cache_state_running, &cache->cache_state); - if (result == -OCF_ERR_WRITE_CACHE) { - ocf_log(ctx, log_warn, "Stopped cache %s with errors\n", - cache_name); - } else if (result) { - ocf_log(ctx, log_err, "Stopping cache %s failed\n", - cache_name); - } else { - ocf_log(ctx, log_info, "Cache %s successfully stopped\n", - cache_name); - } - - cmpl(cache, priv, result); + ocf_mngt_pipeline_next(pipeline); } void ocf_mngt_cache_save(ocf_cache_t cache, @@ -1835,30 +2263,54 @@ int ocf_mngt_cache_get_fallback_pt_error_threshold(ocf_cache_t cache, struct ocf_mngt_cache_detach_context { ocf_mngt_cache_detach_end_t cmpl; void *priv; + ocf_mngt_pipeline_t pipeline; + ocf_cache_t cache; }; static void ocf_mngt_cache_detach_flush_cmpl(ocf_cache_t cache, void *priv, int error) { struct ocf_mngt_cache_detach_context *context = priv; - int i, j, no; - int result; if (error) { - ENV_BUG_ON(env_atomic_dec_return(&cache->flush_started) < 0); - context->cmpl(cache, context->priv, error); - env_vfree(context); + ocf_mngt_pipeline_finish(context->pipeline, error); return; } - /* wait for all requests referencing cacheline metadata to finish */ + ocf_mngt_pipeline_next(context->pipeline); +} + +static void ocf_mngt_cache_detach_flush(ocf_mngt_pipeline_t pipeline, + void *priv) +{ + struct ocf_mngt_cache_detach_context *context = priv; + ocf_cache_t cache = context->cache; + + ocf_mngt_cache_flush(cache, true, ocf_mngt_cache_detach_flush_cmpl, + context); +} + +static void ocf_mngt_cache_detach_wait_pending(ocf_mngt_pipeline_t pipeline, + void *priv) +{ + 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)); - ENV_BUG_ON(env_atomic_dec_return(&cache->flush_started) < 0); + ocf_mngt_pipeline_next(context->pipeline); +} + +static void ocf_mngt_cache_detach_update_metadata(ocf_mngt_pipeline_t pipeline, + void *priv) +{ + struct ocf_mngt_cache_detach_context *context = priv; + ocf_cache_t cache = context->cache; + int i, j, no; no = cache->conf_meta->core_count; @@ -1871,14 +2323,55 @@ static void ocf_mngt_cache_detach_flush_cmpl(ocf_cache_t cache, j++; } - /* Do the actual detach - deinit cacheline metadata, stop cleaner - thread and close cache bottom device */ - result = _ocf_mngt_cache_unplug(cache, false); + ocf_mngt_pipeline_next(context->pipeline); +} - if (!result) { +static void ocf_mngt_cache_detach_unplug_complete(void *priv, int error) +{ + struct ocf_mngt_cache_detach_context *context = priv; + + if (error) { + ocf_mngt_pipeline_finish(context->pipeline, error); + return; + } + + ocf_mngt_pipeline_next(context->pipeline); +} + +static void ocf_mngt_cache_detach_unplug(ocf_mngt_pipeline_t pipeline, + void *priv) +{ + struct ocf_mngt_cache_detach_context *context = priv; + ocf_cache_t cache = context->cache; + + /* Do the actual detach - deinit cacheline metadata, + * stop cleaner thread and close cache bottom device */ + _ocf_mngt_cache_unplug(cache, false, + ocf_mngt_cache_detach_unplug_complete, context); +} + +ocf_mngt_pipeline_step_t ocf_mngt_cache_detach_pipeline_steps[] = { + ocf_mngt_cache_detach_flush, + ocf_mngt_cache_detach_wait_pending, + ocf_mngt_cache_detach_update_metadata, + ocf_mngt_cache_detach_unplug, + NULL, +}; + +static void ocf_mngt_cache_detach_finish(ocf_mngt_pipeline_t pipeline, + void *priv, int error) +{ + struct ocf_mngt_cache_detach_context *context = priv; + ocf_cache_t cache = context->cache; + + ocf_mngt_pipeline_destroy(context->pipeline); + + ENV_BUG_ON(env_atomic_dec_return(&cache->flush_started) < 0); + + if (!error) { ocf_cache_log(cache, log_info, "Successfully detached\n"); } else { - if (result == -OCF_ERR_WRITE_CACHE) { + if (error == -OCF_ERR_WRITE_CACHE) { ocf_cache_log(cache, log_warn, "Detached cache with errors\n"); } else { @@ -1887,7 +2380,7 @@ static void ocf_mngt_cache_detach_flush_cmpl(ocf_cache_t cache, } } - context->cmpl(cache, context->priv, result); + context->cmpl(cache, context->priv, error); env_vfree(context); } @@ -1895,6 +2388,9 @@ 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; + ocf_mngt_pipeline_t pipeline; + int result; + OCF_CHECK_NULL(cache); if (!env_atomic_read(&cache->attached)) { @@ -1902,18 +2398,28 @@ void ocf_mngt_cache_detach(ocf_cache_t cache, return; } - context = env_vmalloc(sizeof(*context)); + context = env_vzalloc(sizeof(*context)); if (!context) { cmpl(cache, priv, -OCF_ERR_NO_MEM); return; } + result = ocf_mngt_pipeline_create(&pipeline, cache, + ocf_mngt_cache_detach_pipeline_steps, + ocf_mngt_cache_detach_finish, context); + if (result) { + env_vfree(context); + cmpl(cache, priv, -OCF_ERR_NO_MEM); + return; + } + context->cmpl = cmpl; context->priv = priv; + context->pipeline = pipeline; + context->cache = cache; /* prevent dirty io */ env_atomic_inc(&cache->flush_started); - ocf_mngt_cache_flush(cache, true, ocf_mngt_cache_detach_flush_cmpl, - context); + ocf_mngt_pipeline_next(pipeline); } diff --git a/src/mngt/ocf_mngt_common.c b/src/mngt/ocf_mngt_common.c index d5d80da..e18a0cc 100644 --- a/src/mngt/ocf_mngt_common.c +++ b/src/mngt/ocf_mngt_common.c @@ -15,6 +15,7 @@ #include "../eviction/ops.h" #include "../ocf_logger_priv.h" #include "../ocf_queue_priv.h" +#include "../engine/engine_common.h" /* Close if opened */ int cache_mng_core_close(ocf_cache_t cache, ocf_core_id_t core_id) @@ -457,3 +458,83 @@ int ocf_mngt_cache_visit_reverse(ocf_ctx_t ocf_ctx, return result; } + +struct ocf_mngt_pipeline { + ocf_mngt_pipeline_step_t *steps; + int next_step; + ocf_mngt_pipeline_end_t cmpl; + struct ocf_request *req; + bool finish; + int error; + + void *priv; +}; + +static int _ocf_mngt_pipeline_run_step(struct ocf_request *req) +{ + ocf_mngt_pipeline_t pipeline = req->priv; + + if (pipeline->steps[pipeline->next_step] && !pipeline->finish) + pipeline->steps[pipeline->next_step++](pipeline, pipeline->priv); + else + pipeline->cmpl(pipeline, pipeline->priv, pipeline->error); + + return 0; +} + +static const struct ocf_io_if _io_if_pipeline = { + .read = _ocf_mngt_pipeline_run_step, + .write = _ocf_mngt_pipeline_run_step, +}; + +int ocf_mngt_pipeline_create(ocf_mngt_pipeline_t *pipeline, ocf_cache_t cache, + ocf_mngt_pipeline_step_t *steps, ocf_mngt_pipeline_end_t cmpl, + void *priv) +{ + ocf_mngt_pipeline_t tmp_pipeline; + struct ocf_request *req; + + tmp_pipeline = env_vzalloc(sizeof(struct ocf_mngt_pipeline)); + if (!tmp_pipeline) + return -OCF_ERR_NO_MEM; + + req = ocf_req_new(cache->mngt_queue, NULL, 0, 0, 0); + if (!req) { + env_vfree(tmp_pipeline); + return -OCF_ERR_NO_MEM; + } + + tmp_pipeline->steps = steps; + tmp_pipeline->next_step = 0; + tmp_pipeline->cmpl = cmpl; + tmp_pipeline->req = req; + tmp_pipeline->finish = false; + tmp_pipeline->error = 0; + tmp_pipeline->priv = priv; + + req->info.internal = true; + req->io_if = &_io_if_pipeline; + req->priv = tmp_pipeline; + + *pipeline = tmp_pipeline; + + return 0; +} + +void ocf_mngt_pipeline_destroy(ocf_mngt_pipeline_t pipeline) +{ + ocf_req_put(pipeline->req); + env_vfree(pipeline); +} + +void ocf_mngt_pipeline_next(ocf_mngt_pipeline_t pipeline) +{ + ocf_engine_push_req_front(pipeline->req, true); +} + +void ocf_mngt_pipeline_finish(ocf_mngt_pipeline_t pipeline, int error) +{ + pipeline->finish = true; + pipeline->error = error; + ocf_engine_push_req_front(pipeline->req, true); +} diff --git a/src/mngt/ocf_mngt_common.h b/src/mngt/ocf_mngt_common.h index 66b7735..4a27ade 100644 --- a/src/mngt/ocf_mngt_common.h +++ b/src/mngt/ocf_mngt_common.h @@ -30,4 +30,22 @@ int ocf_mngt_add_partition_to_cache(struct ocf_cache *cache, bool ocf_mngt_is_cache_locked(ocf_cache_t cache); +typedef struct ocf_mngt_pipeline *ocf_mngt_pipeline_t; + +typedef void (*ocf_mngt_pipeline_step_t)(ocf_mngt_pipeline_t pipeline, + void *priv); + +typedef void (*ocf_mngt_pipeline_end_t)(ocf_mngt_pipeline_t pipeline, + void *priv, int error); + +int ocf_mngt_pipeline_create(ocf_mngt_pipeline_t *pipeline, ocf_cache_t cache, + ocf_mngt_pipeline_step_t *steps, ocf_mngt_pipeline_end_t cmpl, + void *priv); + +void ocf_mngt_pipeline_destroy(ocf_mngt_pipeline_t pipeline); + +void ocf_mngt_pipeline_next(ocf_mngt_pipeline_t pipeline); + +void ocf_mngt_pipeline_finish(ocf_mngt_pipeline_t pipeline, int error); + #endif /* __OCF_MNGT_COMMON_H__ */ diff --git a/src/mngt/ocf_mngt_flush.c b/src/mngt/ocf_mngt_flush.c index 0437f38..bc771e5 100644 --- a/src/mngt/ocf_mngt_flush.c +++ b/src/mngt/ocf_mngt_flush.c @@ -318,7 +318,7 @@ static int _ocf_mngt_flush_containers(ocf_cache_t cache, fctbl[i].attribs.cache_line_lock = true; fctbl[i].attribs.cmpl_context = &fctbl[i]; fctbl[i].attribs.cmpl_fn = _ocf_mngt_flush_end; - fctbl[i].attribs.io_queue = cache->flush_queue; + fctbl[i].attribs.io_queue = cache->mngt_queue; fctbl[i].cache = cache; fctbl[i].progress = &progress; fctbl[i].error = &error; @@ -482,7 +482,7 @@ void ocf_mngt_cache_flush(ocf_cache_t cache, bool interruption, return; } - if (!cache->flush_queue) { + if (!cache->mngt_queue) { ocf_cache_log(cache, log_err, "Cannot flush cache - no flush queue set\n"); cmpl(cache, priv, -OCF_ERR_INVAL); @@ -549,7 +549,7 @@ void ocf_mngt_core_flush(ocf_core_t core, bool interruption, return; } - if (!cache->flush_queue) { + if (!cache->mngt_queue) { ocf_core_log(core, log_err, "Cannot flush core - no flush queue set\n"); cmpl(core, priv, -OCF_ERR_INVAL); @@ -577,7 +577,7 @@ void ocf_mngt_cache_purge(ocf_cache_t cache, OCF_CHECK_NULL(cache); - if (!cache->flush_queue) { + if (!cache->mngt_queue) { ocf_cache_log(cache, log_err, "Cannot purge cache - no flush queue set\n"); cmpl(cache, priv, -OCF_ERR_INVAL); @@ -618,7 +618,7 @@ void ocf_mngt_core_purge(ocf_core_t core, cache = ocf_core_get_cache(core); core_id = ocf_core_get_id(core); - if (!cache->flush_queue) { + if (!cache->mngt_queue) { ocf_core_log(core, log_err, "Cannot purge core - no flush queue set\n"); cmpl(core, priv, -OCF_ERR_INVAL); diff --git a/src/ocf_cache.c b/src/ocf_cache.c index 534892d..ffe4ab4 100644 --- a/src/ocf_cache.c +++ b/src/ocf_cache.c @@ -242,17 +242,3 @@ void *ocf_cache_get_priv(ocf_cache_t cache) OCF_CHECK_NULL(cache); return cache->priv; } - -void ocf_cache_set_flush_queue(ocf_cache_t cache, ocf_queue_t queue) -{ - OCF_CHECK_NULL(cache); - OCF_CHECK_NULL(queue); - - if (cache->flush_queue) - ocf_queue_put(cache->flush_queue); - - if (queue) - ocf_queue_get(queue); - - cache->flush_queue = queue; -} diff --git a/src/ocf_cache_priv.h b/src/ocf_cache_priv.h index c5ff6ce..99bc000 100644 --- a/src/ocf_cache_priv.h +++ b/src/ocf_cache_priv.h @@ -186,7 +186,7 @@ struct ocf_cache { env_atomic pending_eviction_clines; struct list_head io_queues; - ocf_queue_t flush_queue; + ocf_queue_t mngt_queue; uint16_t ocf_core_inactive_count; struct ocf_core core[OCF_CORE_MAX]; diff --git a/src/utils/utils_io.c b/src/utils/utils_io.c index 05f3e61..7ae5ce5 100644 --- a/src/utils/utils_io.c +++ b/src/utils/utils_io.c @@ -11,171 +11,194 @@ #include "utils_io.h" #include "utils_cache_line.h" -struct ocf_submit_io_wait_context { - env_completion complete; - int error; +struct ocf_submit_volume_context { env_atomic req_remaining; + int error; + ocf_submit_end_t cmpl; + void *priv; }; -/* - * IO discard context - */ -struct discard_io_request { - void *context; - env_atomic req_remaining; - env_completion completion; - int error; -}; - -static void _ocf_volume_flush_end(struct ocf_io *io, int err) +static void _ocf_volume_flush_end(struct ocf_io *io, int error) { - struct ocf_submit_io_wait_context *cntx = io->priv1; - cntx->error = err; - env_completion_complete(&cntx->complete); + ocf_submit_end_t cmpl = io->priv1; + cmpl(io->priv2, error); ocf_io_put(io); } -int ocf_submit_volume_flush_wait(ocf_volume_t volume) +void ocf_submit_volume_flush(ocf_volume_t volume, + ocf_submit_end_t cmpl, void *priv) { - struct ocf_submit_io_wait_context cntx = { }; struct ocf_io *io; - env_atomic_set(&cntx.req_remaining, 1); - env_completion_init(&cntx.complete); - io = ocf_volume_new_io(volume); - if (!io) - return -ENOMEM; + if (!io) { + cmpl(priv, -OCF_ERR_NO_MEM); + return; + } ocf_io_configure(io, 0, 0, OCF_WRITE, 0, 0); - ocf_io_set_cmpl(io, &cntx, NULL, _ocf_volume_flush_end); + ocf_io_set_cmpl(io, cmpl, priv, _ocf_volume_flush_end); ocf_volume_submit_flush(io); - - env_completion_wait(&cntx.complete); - - return cntx.error; } -static void ocf_submit_volume_discard_wait_io(struct ocf_io *io, int error) +static void ocf_submit_volume_end(struct ocf_io *io, int error) { - struct ocf_submit_io_wait_context *cntx = io->priv1; + struct ocf_submit_volume_context *context = io->priv1; if (error) - cntx->error = error; + context->error = error; - ocf_io_put(io); /* Release IO */ + ocf_io_put(io); - if (env_atomic_dec_return(&cntx->req_remaining)) + if (env_atomic_dec_return(&context->req_remaining)) return; - /* All discard IO handled, signal it by setting completion */ - env_completion_complete(&cntx->complete); + context->cmpl(context->priv, context->error); + env_vfree(context); } -int ocf_submit_volume_discard_wait(ocf_volume_t volume, uint64_t addr, - uint64_t length) +void ocf_submit_volume_discard(ocf_volume_t volume, uint64_t addr, + uint64_t length, ocf_submit_end_t cmpl, void *priv) { - struct ocf_submit_io_wait_context cntx = { }; + struct ocf_submit_volume_context *context; uint64_t bytes; uint64_t max_length = (uint32_t)~0; + struct ocf_io *io; - ENV_BUG_ON(env_memset(&cntx, sizeof(cntx), 0)); - env_atomic_set(&cntx.req_remaining, 1); - env_completion_init(&cntx.complete); + context = env_vzalloc(sizeof(*context)); + if (!context) { + cmpl(priv, -OCF_ERR_NO_MEM); + return; + } + + env_atomic_set(&context->req_remaining, 1); + context->cmpl = cmpl; + context->priv = priv; while (length) { - struct ocf_io *io = ocf_volume_new_io(volume); - + io = ocf_volume_new_io(volume); if (!io) { - cntx.error = -ENOMEM; + context->error = -OCF_ERR_NO_MEM; break; } + env_atomic_inc(&context->req_remaining); + bytes = OCF_MIN(length, max_length); - env_atomic_inc(&cntx.req_remaining); - ocf_io_configure(io, addr, bytes, OCF_WRITE, 0, 0); - ocf_io_set_cmpl(io, &cntx, NULL, - ocf_submit_volume_discard_wait_io); + ocf_io_set_cmpl(io, context, NULL, ocf_submit_volume_end); ocf_volume_submit_discard(io); addr += bytes; length -= bytes; } - if (env_atomic_dec_return(&cntx.req_remaining) == 0) - env_completion_complete(&cntx.complete); + if (env_atomic_dec_return(&context->req_remaining)) + return; - env_completion_wait(&cntx.complete); - - return cntx.error; + cmpl(priv, context->error); + env_vfree(context); } -static void ocf_submit_volume_zeroes_wait_io(struct ocf_io *io, int error) +void ocf_submit_write_zeros(ocf_volume_t volume, uint64_t addr, + uint64_t length, ocf_submit_end_t cmpl, void *priv) { - struct ocf_submit_io_wait_context *cntx = io->priv1; - - if (error) - cntx->error = error; - - env_completion_complete(&cntx->complete); -} - -int ocf_submit_write_zeroes_wait(ocf_volume_t volume, uint64_t addr, - uint64_t length) -{ - struct ocf_submit_io_wait_context cntx = { }; + struct ocf_submit_volume_context *context; uint32_t bytes; uint32_t max_length = ~((uint32_t)PAGE_SIZE - 1); - uint32_t step = 0; struct ocf_io *io; - io = ocf_volume_new_io(volume); - if (!io) - return -ENOMEM; + context = env_vzalloc(sizeof(*context)); + if (!context) { + cmpl(priv, -OCF_ERR_NO_MEM); + return; + } + + env_atomic_set(&context->req_remaining, 1); + context->cmpl = cmpl; + context->priv = priv; while (length) { - env_completion_init(&cntx.complete); + io = ocf_volume_new_io(volume); + if (!io) { + context->error = -OCF_ERR_NO_MEM; + break; + } + + env_atomic_inc(&context->req_remaining); bytes = OCF_MIN(length, max_length); ocf_io_configure(io, addr, bytes, OCF_WRITE, 0, 0); - ocf_io_set_cmpl(io, &cntx, NULL, - ocf_submit_volume_zeroes_wait_io); + ocf_io_set_cmpl(io, context, NULL, ocf_submit_volume_end); ocf_volume_submit_write_zeroes(io); addr += bytes; length -= bytes; - - env_completion_wait(&cntx.complete); - if (cntx.error) - break; - - OCF_COND_RESCHED_DEFAULT(step); } - ocf_io_put(io); + if (env_atomic_dec_return(&context->req_remaining)) + return; - return cntx.error; + cmpl(priv, context->error); + env_vfree(context); } -int ocf_submit_cache_page(struct ocf_cache *cache, uint64_t addr, - int dir, void *buffer) +struct ocf_submit_cache_page_context { + ocf_cache_t cache; + void *buffer; + ocf_submit_end_t cmpl; + void *priv; +}; + +static void ocf_submit_cache_page_end(struct ocf_io *io, int error) { + struct ocf_submit_cache_page_context *context = io->priv1; + ctx_data_t *data = ocf_io_get_data(io); + + if (io->dir == OCF_READ) { + ctx_data_rd_check(context->cache->owner, context->buffer, + data, PAGE_SIZE); + } + + context->cmpl(context->priv, error); + ctx_data_free(context->cache->owner, data); + env_vfree(context); + ocf_io_put(io); +} + +void ocf_submit_cache_page(ocf_cache_t cache, uint64_t addr, int dir, + void *buffer, ocf_submit_end_t cmpl, void *priv) +{ + struct ocf_submit_cache_page_context *context; ctx_data_t *data; struct ocf_io *io; int result = 0; - /* Allocate resources for IO */ - io = ocf_volume_new_io(&cache->device->volume); - data = ctx_data_alloc(cache->owner, 1); + context = env_vmalloc(sizeof(*context)); + if (!context) { + cmpl(priv, -OCF_ERR_NO_MEM); + return; + } - if (!io || !data) { - result = -ENOMEM; - goto end; + context->cache = cache; + context->buffer = buffer; + context->cmpl = cmpl; + context->priv = priv; + + io = ocf_volume_new_io(&cache->device->volume); + if (!io) { + result = -OCF_ERR_NO_MEM; + goto err_io; + } + + data = ctx_data_alloc(cache->owner, 1); + if (!data) { + result = -OCF_ERR_NO_MEM; + goto err_data; } if (dir == OCF_WRITE) @@ -183,21 +206,21 @@ int ocf_submit_cache_page(struct ocf_cache *cache, uint64_t addr, result = ocf_io_set_data(io, data, 0); if (result) - goto end; + goto err_set_data; ocf_io_configure(io, addr, PAGE_SIZE, dir, 0, 0); + ocf_io_set_cmpl(io, context, NULL, ocf_submit_cache_page_end); - result = ocf_submit_io_wait(io); - if (result) - goto end; + ocf_volume_submit_io(io); + return; - if (dir == OCF_READ) - ctx_data_rd_check(cache->owner, buffer, data, PAGE_SIZE); -end: - if (io) - ocf_io_put(io); +err_set_data: ctx_data_free(cache->owner, data); - return result; +err_data: + ocf_io_put(io); +err_io: + env_vfree(context); + cmpl(priv, result); } static void ocf_submit_volume_req_cmpl(struct ocf_io *io, int error) @@ -347,6 +370,12 @@ void ocf_submit_volume_req(ocf_volume_t volume, struct ocf_request *req, ocf_volume_submit_io(io); } +struct ocf_submit_io_wait_context { + env_completion complete; + int error; + env_atomic req_remaining; +}; + static void ocf_submit_io_wait_end(struct ocf_io *io, int error) { struct ocf_submit_io_wait_context *context = io->priv1; diff --git a/src/utils/utils_io.h b/src/utils/utils_io.h index 982e2e5..7254ee5 100644 --- a/src/utils/utils_io.h +++ b/src/utils/utils_io.h @@ -43,18 +43,21 @@ static inline int ocf_io_overlaps(uint32_t start1, uint32_t count1, start2 + count2 - 1); } +typedef void (*ocf_submit_end_t)(void *priv, int error); + int ocf_submit_io_wait(struct ocf_io *io); -int ocf_submit_volume_flush_wait(ocf_volume_t volume); +void ocf_submit_volume_flush(ocf_volume_t volume, + ocf_submit_end_t cmpl, void *priv); -int ocf_submit_volume_discard_wait(ocf_volume_t volume, uint64_t addr, - uint64_t length); +void ocf_submit_volume_discard(ocf_volume_t volume, uint64_t addr, + uint64_t length, ocf_submit_end_t cmpl, void *priv); -int ocf_submit_write_zeroes_wait(ocf_volume_t volume, uint64_t addr, - uint64_t length); +void ocf_submit_write_zeros(ocf_volume_t volume, uint64_t addr, + uint64_t length, ocf_submit_end_t cmpl, void *priv); -int ocf_submit_cache_page(struct ocf_cache *cache, uint64_t addr, - int dir, void *buffer); +void ocf_submit_cache_page(ocf_cache_t cache, uint64_t addr, int dir, + void *buffer, ocf_submit_end_t cmpl, void *priv); void ocf_submit_volume_req(ocf_volume_t volume, struct ocf_request *req, ocf_req_end_t callback); diff --git a/src/utils/utils_req.c b/src/utils/utils_req.c index e11244a..66605dc 100644 --- a/src/utils/utils_req.c +++ b/src/utils/utils_req.c @@ -206,7 +206,9 @@ 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; - env_atomic_inc(&cache->pending_requests); + if (queue != cache->mngt_queue) + env_atomic_inc(&cache->pending_requests); + start_cache_req(req); env_atomic_set(&req->ref_count, 1); @@ -292,7 +294,8 @@ void ocf_req_put(struct ocf_request *req) env_waitqueue_wake_up(&req->cache->pending_cache_wq); } - env_atomic_dec(&req->cache->pending_requests); + 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); 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 c065906..b57addd 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 @@ -102,6 +102,136 @@ char *__wrap_ocf_cache_get_name(ocf_cache_t cache) { } +void __wrap__ocf_mngt_test_volume_initial_write( + ocf_mngt_pipeline_t test_pipeline, void *priv) +{ +} + +void __wrap_ocf_mngt_test_volume_first_read( + ocf_mngt_pipeline_t test_pipeline, void *priv) +{ +} + +void __wrap__ocf_mngt_test_volume_discard( + ocf_mngt_pipeline_t test_pipeline, void *priv) +{ +} + +void __wrap__ocf_mngt_test_volume_second_read( + ocf_mngt_pipeline_t test_pipeline, void *priv) +{ +} + +void __wrap__ocf_mngt_attach_cache_device( + ocf_mngt_pipeline_t test_pipeline, void *priv) +{ +} + +void __wrap__ocf_mngt_attach_check_ram( + ocf_mngt_pipeline_t test_pipeline, void *priv) +{ +} + +void __wrap__ocf_mngt_attach_load_properties( + ocf_mngt_pipeline_t test_pipeline, void *priv) +{ +} + +void __wrap__ocf_mngt_attach_prepare_metadata( + ocf_mngt_pipeline_t test_pipeline, void *priv) +{ +} + +void __wrap__ocf_mngt_test_volume( + ocf_mngt_pipeline_t test_pipeline, void *priv) +{ +} + +void __wrap__ocf_mngt_attach_load_superblock( + ocf_mngt_pipeline_t test_pipeline, void *priv) +{ +} + +void __wrap__ocf_mngt_attach_init_instance( + ocf_mngt_pipeline_t test_pipeline, void *priv) +{ +} + +void __wrap__ocf_mngt_attach_clean_pol( + ocf_mngt_pipeline_t test_pipeline, void *priv) +{ +} + +void __wrap__ocf_mngt_attach_flush_metadata( + ocf_mngt_pipeline_t test_pipeline, void *priv) +{ +} + +void __wrap__ocf_mngt_attach_discard( + ocf_mngt_pipeline_t test_pipeline, void *priv) +{ +} + +void __wrap__ocf_mngt_attach_flush( + ocf_mngt_pipeline_t test_pipeline, void *priv) +{ +} + +void __wrap__ocf_mngt_attach_shutdown_status( + ocf_mngt_pipeline_t test_pipeline, void *priv) +{ +} + +void __wrap__ocf_mngt_attach_post_init( + ocf_mngt_pipeline_t test_pipeline, void *priv) +{ +} + +void __wrap_ocf_mngt_cache_stop_wait_io( + ocf_mngt_pipeline_t test_pipeline, void *priv) +{ +} + +void __wrap_ocf_mngt_cache_stop_remove_cores( + ocf_mngt_pipeline_t test_pipeline, void *priv) +{ +} + +void __wrap_ocf_mngt_cache_stop_unplug( + ocf_mngt_pipeline_t test_pipeline, void *priv) +{ +} + +void __wrap_ocf_mngt_cache_stop_put_io_queues( + ocf_mngt_pipeline_t test_pipeline, void *priv) +{ +} + +void __wrap_ocf_mngt_cache_detach_flush( + ocf_mngt_pipeline_t test_pipeline, void *priv) +{ +} + +void __wrap_ocf_mngt_cache_detach_wait_pending( + ocf_mngt_pipeline_t test_pipeline, void *priv) +{ +} + +void __wrap_ocf_mngt_cache_detach_update_metadata( + ocf_mngt_pipeline_t test_pipeline, void *priv) +{ +} + +void __wrap_ocf_mngt_cache_detach_unplug( + ocf_mngt_pipeline_t test_pipeline, void *priv) +{ +} + +void __wrap__ocf_mngt_test_volume_first_read( + ocf_mngt_pipeline_t test_pipeline, void *priv) +{ +} + static void _cache_mng_set_cache_mode_test01(void **state) { ocf_cache_mode_t mode_old = -20; 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 aaf9d1f..b506dc6 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 @@ -59,6 +59,136 @@ char *__wrap_ocf_cache_get_name(ocf_cache_t cache) { } +void __wrap__ocf_mngt_test_volume_initial_write( + ocf_mngt_pipeline_t test_pipeline, void *priv) +{ +} + +void __wrap_ocf_mngt_test_volume_first_read( + ocf_mngt_pipeline_t test_pipeline, void *priv) +{ +} + +void __wrap__ocf_mngt_test_volume_discard( + ocf_mngt_pipeline_t test_pipeline, void *priv) +{ +} + +void __wrap__ocf_mngt_test_volume_second_read( + ocf_mngt_pipeline_t test_pipeline, void *priv) +{ +} + +void __wrap__ocf_mngt_attach_cache_device( + ocf_mngt_pipeline_t test_pipeline, void *priv) +{ +} + +void __wrap__ocf_mngt_attach_check_ram( + ocf_mngt_pipeline_t test_pipeline, void *priv) +{ +} + +void __wrap__ocf_mngt_attach_load_properties( + ocf_mngt_pipeline_t test_pipeline, void *priv) +{ +} + +void __wrap__ocf_mngt_attach_prepare_metadata( + ocf_mngt_pipeline_t test_pipeline, void *priv) +{ +} + +void __wrap__ocf_mngt_test_volume( + ocf_mngt_pipeline_t test_pipeline, void *priv) +{ +} + +void __wrap__ocf_mngt_attach_load_superblock( + ocf_mngt_pipeline_t test_pipeline, void *priv) +{ +} + +void __wrap__ocf_mngt_attach_init_instance( + ocf_mngt_pipeline_t test_pipeline, void *priv) +{ +} + +void __wrap__ocf_mngt_attach_clean_pol( + ocf_mngt_pipeline_t test_pipeline, void *priv) +{ +} + +void __wrap__ocf_mngt_attach_flush_metadata( + ocf_mngt_pipeline_t test_pipeline, void *priv) +{ +} + +void __wrap__ocf_mngt_attach_discard( + ocf_mngt_pipeline_t test_pipeline, void *priv) +{ +} + +void __wrap__ocf_mngt_attach_flush( + ocf_mngt_pipeline_t test_pipeline, void *priv) +{ +} + +void __wrap__ocf_mngt_attach_shutdown_status( + ocf_mngt_pipeline_t test_pipeline, void *priv) +{ +} + +void __wrap__ocf_mngt_attach_post_init( + ocf_mngt_pipeline_t test_pipeline, void *priv) +{ +} + +void __wrap_ocf_mngt_cache_stop_wait_io( + ocf_mngt_pipeline_t test_pipeline, void *priv) +{ +} + +void __wrap_ocf_mngt_cache_stop_remove_cores( + ocf_mngt_pipeline_t test_pipeline, void *priv) +{ +} + +void __wrap_ocf_mngt_cache_stop_unplug( + ocf_mngt_pipeline_t test_pipeline, void *priv) +{ +} + +void __wrap_ocf_mngt_cache_stop_put_io_queues( + ocf_mngt_pipeline_t test_pipeline, void *priv) +{ +} + +void __wrap_ocf_mngt_cache_detach_flush( + ocf_mngt_pipeline_t test_pipeline, void *priv) +{ +} + +void __wrap_ocf_mngt_cache_detach_wait_pending( + ocf_mngt_pipeline_t test_pipeline, void *priv) +{ +} + +void __wrap_ocf_mngt_cache_detach_update_metadata( + ocf_mngt_pipeline_t test_pipeline, void *priv) +{ +} + +void __wrap_ocf_mngt_cache_detach_unplug( + ocf_mngt_pipeline_t test_pipeline, void *priv) +{ +} + +void __wrap__ocf_mngt_test_volume_first_read( + ocf_mngt_pipeline_t test_pipeline, void *priv) +{ +} + static void ocf_mngt_cache_set_fallback_pt_error_threshold_test01(void **state) { struct ocf_cache cache;