diff --git a/inc/ocf_cache.h b/inc/ocf_cache.h index 786b2fc..f6388e2 100644 --- a/inc/ocf_cache.h +++ b/inc/ocf_cache.h @@ -174,6 +174,13 @@ void ocf_cache_wait_for_io_finish(ocf_cache_t cache); */ bool ocf_cache_has_pending_requests(ocf_cache_t cache); +/** + * @brief Check if cleaning triggered by eviction runs on the cache + * + * @param[in] cache Cache object + */ +bool ocf_cache_has_pending_cleaning(ocf_cache_t cache); + /** * @brief Get cache mode of given cache object * diff --git a/src/mngt/ocf_mngt_common.c b/src/mngt/ocf_mngt_common.c index 03e426b..a8d758f 100644 --- a/src/mngt/ocf_mngt_common.c +++ b/src/mngt/ocf_mngt_common.c @@ -9,7 +9,6 @@ #include "../ocf_ctx_priv.h" #include "../metadata/metadata.h" #include "../engine/cache_engine.h" -#include "../utils/utils_part.h" #include "../utils/utils_req.h" #include "../utils/utils_device.h" #include "../eviction/ops.h" @@ -118,53 +117,6 @@ void cache_mng_core_remove_from_cache(struct ocf_cache *cache, int core_id) cache->conf_meta->core_count--; } -/** - * @brief Wait for the end of asynchronous cleaning - * - * @param cache OCF cache instance - * @param timeout_ms Timeout for waiting in milliseconds - * @note When timeout is less than zero it means wait forever - * - * @retval 0 cleaning finished - * @retval non-zero timeout and cleaning still in progress - */ -static int _ocf_cleaning_wait_for_finish(struct ocf_cache *cache, - const int32_t timeout_ms) -{ - struct ocf_user_part *curr_part; - ocf_part_id_t part_id; - bool cleaning_active = ocf_cache_is_device_attached(cache); - int64_t _timeout = timeout_ms; - - while (cleaning_active) { - cleaning_active = false; - - OCF_METADATA_LOCK_WR(); - for_each_part(cache, curr_part, part_id) { - if (env_atomic_read(&cache->cleaning[part_id])) { - cleaning_active = true; - break; - } - } - OCF_METADATA_UNLOCK_WR(); - - if (cleaning_active) { - env_msleep(20); - - if (timeout_ms >= 0) { - _timeout -= 20; - if (_timeout <= 0) - break; - } - } - }; - - if (cleaning_active) - return -EBUSY; - - return 0; -} - void ocf_mngt_cache_put(ocf_cache_t cache) { OCF_CHECK_NULL(cache); @@ -275,15 +227,6 @@ static int _ocf_mngt_cache_lock(ocf_cache_t cache, int (*lock_fn)(env_rwsem *s), goto unlock; } - /* Return, when asynchronous cleaning is finished */ - if (_ocf_cleaning_wait_for_finish(cache, 60 * 1000)) { - /* Because of some reasons, asynchronous cleaning still active, - * cannot continue - */ - ret = -OCF_ERR_CACHE_IN_USE; - goto unlock; - } - return 0; unlock: @@ -321,15 +264,15 @@ int ocf_mngt_cache_read_trylock(ocf_cache_t cache) } /* if cache is either fully initialized or during recovery */ -static ocf_cache_t _ocf_mngt_cache_try_get(ocf_cache_t cache) +static bool _ocf_mngt_cache_try_get(ocf_cache_t cache) { if (!!cache->valid_ocf_cache_device_t) { /* Increase reference counter */ env_atomic_inc(&cache->ref_count); - return cache; + return true; } - return NULL; + return false; } int ocf_mngt_cache_get(ocf_cache_t cache) @@ -345,7 +288,7 @@ static int _ocf_mngt_cache_get_list_cpy(ocf_ctx_t ocf_ctx, ocf_cache_t **list, { int result = 0; uint32_t count = 0, i = 0; - struct ocf_cache *iter, *this; + ocf_cache_t iter; *list = NULL; *size = 0; @@ -366,12 +309,9 @@ static int _ocf_mngt_cache_get_list_cpy(ocf_ctx_t ocf_ctx, ocf_cache_t **list, } list_for_each_entry(iter, &ocf_ctx->caches, list) { - this = _ocf_mngt_cache_try_get(iter); - if (this) { - (*list)[i] = this; - i++; - } + if (_ocf_mngt_cache_try_get(iter)) + (*list)[i++] = iter; } if (i) { diff --git a/src/mngt/ocf_mngt_core.c b/src/mngt/ocf_mngt_core.c index 470dc0c..b61b90c 100644 --- a/src/mngt/ocf_mngt_core.c +++ b/src/mngt/ocf_mngt_core.c @@ -588,6 +588,26 @@ err_pipeline: cmpl(cache, NULL, priv, result); } +/* + * Synchronously wait until cleaning triggered by eviction finishes. + * TODO: Replace it with asynchronous mechanism. + */ +static int _ocf_cleaning_wait_for_finish(ocf_cache_t cache, int32_t timeout_ms) +{ + if (!ocf_cache_is_device_attached(cache)) + return 0; + + while (ocf_cache_has_pending_cleaning(cache)) { + env_msleep(20); + + timeout_ms -= 20; + if (timeout_ms <= 0) + return -EBUSY; + } + + return 0; +} + struct ocf_mngt_cache_remove_core_context { ocf_mngt_cache_remove_core_end_t cmpl; void *priv; @@ -650,6 +670,12 @@ void ocf_mngt_cache_remove_core(ocf_core_t core, cache = ocf_core_get_cache(core); core_id = ocf_core_get_id(core); + /* TODO: Make this asynchronous */ + if (_ocf_cleaning_wait_for_finish(cache, 60 * 1000)) { + cmpl(priv, -OCF_ERR_CACHE_IN_USE); + return; + } + result = ocf_pipeline_create(&pipeline, cache, &ocf_mngt_cache_remove_core_pipeline_props); if (result) { @@ -702,10 +728,21 @@ static int _ocf_mngt_cache_detach_core(ocf_core_t core) void ocf_mngt_cache_detach_core(ocf_core_t core, ocf_mngt_cache_detach_core_end_t cmpl, void *priv) { - ocf_cache_t cache = ocf_core_get_cache(core); - const char *core_name = ocf_core_get_name(core); + ocf_cache_t cache; + const char *core_name; int result; + OCF_CHECK_NULL(core); + + cache = ocf_core_get_cache(core); + core_name = ocf_core_get_name(core); + + /* TODO: Make this asynchronous */ + if (_ocf_cleaning_wait_for_finish(cache, 60 * 1000)) { + cmpl(priv, -OCF_ERR_CACHE_IN_USE); + return; + } + ocf_core_log(core, log_debug, "Detaching core\n"); result = _ocf_mngt_cache_detach_core(core); diff --git a/src/ocf_cache.c b/src/ocf_cache.c index ffe4ab4..fe55415 100644 --- a/src/ocf_cache.c +++ b/src/ocf_cache.c @@ -8,6 +8,7 @@ #include "engine/cache_engine.h" #include "utils/utils_cache_line.h" #include "utils/utils_req.h" +#include "utils/utils_part.h" #include "ocf_priv.h" #include "ocf_cache_priv.h" @@ -68,12 +69,42 @@ void ocf_cache_wait_for_io_finish(ocf_cache_t cache) bool ocf_cache_has_pending_requests(ocf_cache_t cache) { OCF_CHECK_NULL(cache); + return ocf_req_get_allocated(cache) > 0; } +/* + * This is temporary workaround allowing to check if cleaning triggered + * by eviction policy is running on the cache. This information is needed + * to remove core from cache properly. + * + * TODO: Replace this with asynchronous notification to which remove/detach + * core pipelines can subscribe. + */ +bool ocf_cache_has_pending_cleaning(ocf_cache_t cache) +{ + struct ocf_user_part *curr_part; + ocf_part_id_t part_id; + bool cleaning_active = false; + + OCF_CHECK_NULL(cache); + + OCF_METADATA_LOCK_RD(); + for_each_part(cache, curr_part, part_id) { + if (env_atomic_read(&cache->cleaning[part_id])) { + cleaning_active = true; + break; + } + } + OCF_METADATA_UNLOCK_RD(); + + return cleaning_active; +} + ocf_cache_mode_t ocf_cache_get_mode(ocf_cache_t cache) { OCF_CHECK_NULL(cache); + return cache->conf_meta->cache_mode; }