/* * Copyright(c) 2012-2018 Intel Corporation * SPDX-License-Identifier: BSD-3-Clause-Clear */ #include "ocf/ocf.h" #include "ocf_mngt_common.h" #include "ocf_mngt_core_priv.h" #include "../ocf_priv.h" #include "../ocf_ctx_priv.h" #include "../metadata/metadata.h" #include "../engine/cache_engine.h" #include "../ocf_request.h" #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) { if (!cache->core[core_id].opened) return -OCF_ERR_CORE_IN_INACTIVE_STATE; ocf_volume_close(&cache->core[core_id].volume); cache->core[core_id].opened = false; return 0; } /* Remove core from cleaning policy */ void cache_mng_core_remove_from_cleaning_pol(struct ocf_cache *cache, int core_id) { ocf_cleaning_t clean_pol_type; OCF_METADATA_LOCK_WR(); clean_pol_type = cache->conf_meta->cleaning_policy_type; if (cache->core[core_id].opened) { if (cleaning_policy_ops[clean_pol_type].remove_core) { cleaning_policy_ops[clean_pol_type]. remove_core(cache, core_id); } } OCF_METADATA_UNLOCK_WR(); } /* Deinitialize core metadata in attached metadata */ void cache_mng_core_deinit_attached_meta(struct ocf_cache *cache, int core_id) { int retry = 1; uint64_t core_size = 0; ocf_cleaning_t clean_pol_type; ocf_volume_t core; core = &cache->core[core_id].volume; core_size = ocf_volume_get_length(core); if (!core_size) core_size = ~0ULL; OCF_METADATA_LOCK_WR(); clean_pol_type = cache->conf_meta->cleaning_policy_type; while (retry) { retry = 0; if (cleaning_policy_ops[clean_pol_type].purge_range) { retry = cleaning_policy_ops[clean_pol_type].purge_range(cache, core_id, 0, core_size); } if (!retry) { /* Remove from collision_table and Partition. Put in FREELIST */ retry = ocf_metadata_sparse_range(cache, core_id, 0, core_size); } if (retry) { OCF_METADATA_UNLOCK_WR(); env_msleep(100); OCF_METADATA_LOCK_WR(); } } OCF_METADATA_UNLOCK_WR(); } /* Mark core as removed in metadata */ void cache_mng_core_remove_from_meta(struct ocf_cache *cache, int core_id) { OCF_METADATA_LOCK_WR(); /* In metadata mark data this core was removed from cache */ cache->core_conf_meta[core_id].added = false; /* Clear UUID of core */ ocf_mngt_core_clear_uuid_metadata(&cache->core[core_id]); cache->core_conf_meta[core_id].seq_no = OCF_SEQ_NO_INVALID; OCF_METADATA_UNLOCK_WR(); } /* Deinit in-memory structures related to this core */ void cache_mng_core_remove_from_cache(struct ocf_cache *cache, int core_id) { env_free(cache->core[core_id].counters); cache->core[core_id].counters = NULL; env_bit_clear(core_id, cache->conf_meta->valid_core_bitmap); if (!cache->core[core_id].opened && --cache->ocf_core_inactive_count == 0) { env_bit_clear(ocf_cache_state_incomplete, &cache->cache_state); } cache->conf_meta->core_count--; } void ocf_mngt_cache_put(ocf_cache_t cache) { ocf_ctx_t ctx; OCF_CHECK_NULL(cache); if (ocf_refcnt_dec(&cache->refcnt.cache) == 0) { ctx = cache->owner; ocf_metadata_deinit(cache); ocf_mngt_cache_lock_deinit(cache); env_vfree(cache); ocf_ctx_put(ctx); } } int ocf_mngt_cache_get_by_id(ocf_ctx_t ocf_ctx, ocf_cache_id_t id, ocf_cache_t *cache) { int error = 0; struct ocf_cache *instance = NULL; struct ocf_cache *iter = NULL; OCF_CHECK_NULL(ocf_ctx); OCF_CHECK_NULL(cache); *cache = NULL; if ((id < OCF_CACHE_ID_MIN) || (id > OCF_CACHE_ID_MAX)) { /* Cache id out of range */ return -OCF_ERR_INVAL; } /* Lock caches list */ env_mutex_lock(&ocf_ctx->lock); list_for_each_entry(iter, &ocf_ctx->caches, list) { if (iter->cache_id == id) { instance = iter; break; } } if (instance) { /* if cache is either fully initialized or during recovery */ if (!ocf_refcnt_inc(&instance->refcnt.cache)) { /* Cache not initialized yet */ instance = NULL; } } env_mutex_unlock(&ocf_ctx->lock); if (!instance) error = -OCF_ERR_CACHE_NOT_EXIST; else *cache = instance; return error; } typedef void (*ocf_lock_fn_t)(ocf_async_lock_waiter_t waiter); typedef int (*ocf_trylock_fn_t)(ocf_async_lock_t lock); typedef void (*ocf_unlock_fn_t)(ocf_async_lock_t lock); struct ocf_mngt_cache_lock_context { ocf_cache_t cache; ocf_unlock_fn_t unlock_fn; ocf_mngt_cache_lock_end_t cmpl; void *priv; }; static void _ocf_mngt_cache_lock_complete( ocf_async_lock_waiter_t waiter, int error) { struct ocf_mngt_cache_lock_context *context; ocf_cache_t cache; context = ocf_async_lock_waiter_get_priv(waiter); cache = context->cache; if (error) { ocf_mngt_cache_put(cache); goto out; } if (env_bit_test(ocf_cache_state_stopping, &cache->cache_state)) { /* Cache already stopping, do not allow any operation */ context->unlock_fn(ocf_async_lock_waiter_get_lock(waiter)); ocf_mngt_cache_put(cache); error = -OCF_ERR_CACHE_NOT_EXIST; } out: context->cmpl(context->cache, context->priv, error); } static void _ocf_mngt_cache_lock(ocf_cache_t cache, ocf_mngt_cache_lock_end_t cmpl, void *priv, ocf_lock_fn_t lock_fn, ocf_unlock_fn_t unlock_fn) { ocf_async_lock_waiter_t waiter; struct ocf_mngt_cache_lock_context *context; if (ocf_mngt_cache_get(cache)) OCF_CMPL_RET(cache, priv, -OCF_ERR_CACHE_NOT_EXIST); waiter = ocf_async_lock_new_waiter(&cache->lock, _ocf_mngt_cache_lock_complete); if (!waiter) { ocf_mngt_cache_put(cache); OCF_CMPL_RET(cache, priv, -OCF_ERR_NO_MEM); } context = ocf_async_lock_waiter_get_priv(waiter); context->cache = cache; context->unlock_fn = unlock_fn; context->cmpl = cmpl; context->priv = priv; lock_fn(waiter); } static int _ocf_mngt_cache_trylock(ocf_cache_t cache, ocf_trylock_fn_t trylock_fn, ocf_unlock_fn_t unlock_fn) { int result; if (ocf_mngt_cache_get(cache)) return -OCF_ERR_CACHE_NOT_EXIST; result = trylock_fn(&cache->lock); if (result) return result; if (env_bit_test(ocf_cache_state_stopping, &cache->cache_state)) { /* Cache already stopping, do not allow any operation */ unlock_fn(&cache->lock); return -OCF_ERR_CACHE_NOT_EXIST; } return 0; } static void _ocf_mngt_cache_unlock(ocf_cache_t cache, ocf_unlock_fn_t unlock_fn) { unlock_fn(&cache->lock); ocf_mngt_cache_put(cache); } int ocf_mngt_cache_lock_init(ocf_cache_t cache) { return ocf_async_lock_init(&cache->lock, sizeof(struct ocf_mngt_cache_lock_context)); } void ocf_mngt_cache_lock_deinit(ocf_cache_t cache) { ocf_async_lock_deinit(&cache->lock); } void ocf_mngt_cache_lock(ocf_cache_t cache, ocf_mngt_cache_lock_end_t cmpl, void *priv) { OCF_CHECK_NULL(cache); _ocf_mngt_cache_lock(cache, cmpl, priv, ocf_async_lock, ocf_async_unlock); } int ocf_mngt_cache_trylock(ocf_cache_t cache) { OCF_CHECK_NULL(cache); return _ocf_mngt_cache_trylock(cache, ocf_async_trylock, ocf_async_unlock); } void ocf_mngt_cache_unlock(ocf_cache_t cache) { OCF_CHECK_NULL(cache); _ocf_mngt_cache_unlock(cache, ocf_async_unlock); } void ocf_mngt_cache_read_lock(ocf_cache_t cache, ocf_mngt_cache_lock_end_t cmpl, void *priv) { OCF_CHECK_NULL(cache); _ocf_mngt_cache_lock(cache, cmpl, priv, ocf_async_read_lock, ocf_async_read_unlock); } int ocf_mngt_cache_read_trylock(ocf_cache_t cache) { OCF_CHECK_NULL(cache); return _ocf_mngt_cache_trylock(cache, ocf_async_read_trylock, ocf_async_read_unlock); } void ocf_mngt_cache_read_unlock(ocf_cache_t cache) { OCF_CHECK_NULL(cache); _ocf_mngt_cache_unlock(cache, ocf_async_read_unlock); } bool ocf_mngt_cache_is_locked(ocf_cache_t cache) { return ocf_async_is_locked(&cache->lock); } /* if cache is either fully initialized or during recovery */ static bool _ocf_mngt_cache_try_get(ocf_cache_t cache) { return !!ocf_refcnt_inc(&cache->refcnt.cache); } int ocf_mngt_cache_get(ocf_cache_t cache) { if (!_ocf_mngt_cache_try_get(cache)) return -OCF_ERR_CACHE_NOT_AVAIL; return 0; } static int _ocf_mngt_cache_get_list_cpy(ocf_ctx_t ocf_ctx, ocf_cache_t **list, uint32_t *size) { int result = 0; uint32_t count = 0, i = 0; ocf_cache_t iter; *list = NULL; *size = 0; env_mutex_lock(&ocf_ctx->lock); list_for_each_entry(iter, &ocf_ctx->caches, list) { count++; } if (!count) goto END; *list = env_vmalloc(sizeof((*list)[0]) * count); if (*list == NULL) { result = -ENOMEM; goto END; } list_for_each_entry(iter, &ocf_ctx->caches, list) { if (_ocf_mngt_cache_try_get(iter)) (*list)[i++] = iter; } if (i) { /* Update size if cache list */ *size = i; } else { env_vfree(*list); *list = NULL; } END: env_mutex_unlock(&ocf_ctx->lock); return result; } int ocf_mngt_cache_visit(ocf_ctx_t ocf_ctx, ocf_mngt_cache_visitor_t visitor, void *cntx) { ocf_cache_t *list; uint32_t size, i; int result; OCF_CHECK_NULL(ocf_ctx); OCF_CHECK_NULL(visitor); result = _ocf_mngt_cache_get_list_cpy(ocf_ctx, &list, &size); if (result) return result; if (size == 0) return 0; /* Iterate over caches */ for (i = 0; i < size; i++) { ocf_cache_t this = list[i]; result = visitor(this, cntx); if (result) break; } /* Put caches */ for (i = 0; i < size; i++) ocf_mngt_cache_put(list[i]); env_vfree(list); return result; } int ocf_mngt_cache_visit_reverse(ocf_ctx_t ocf_ctx, ocf_mngt_cache_visitor_t visitor, void *cntx) { ocf_cache_t *list; uint32_t size, i; int result; OCF_CHECK_NULL(ocf_ctx); OCF_CHECK_NULL(visitor); result = _ocf_mngt_cache_get_list_cpy(ocf_ctx, &list, &size); if (result) return result; if (size == 0) return 0; /* Iterate over caches */ for (i = size; i; i--) { ocf_cache_t this = list[i - 1]; result = visitor(this, cntx); if (result) break; } /* Put caches */ for (i = 0; i < size; i++) ocf_mngt_cache_put(list[i]); env_vfree(list); return result; }