508 lines
10 KiB
C
508 lines
10 KiB
C
/*
|
|
* 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_mngt_core_close(ocf_core_t core)
|
|
{
|
|
if (!core->opened)
|
|
return -OCF_ERR_CORE_IN_INACTIVE_STATE;
|
|
|
|
ocf_volume_close(&core->front_volume);
|
|
ocf_volume_deinit(&core->front_volume);
|
|
|
|
ocf_volume_close(&core->volume);
|
|
ocf_volume_deinit(&core->volume);
|
|
core->opened = false;
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* Remove core from cleaning policy */
|
|
void cache_mngt_core_remove_from_cleaning_pol(ocf_core_t core)
|
|
{
|
|
ocf_cache_t cache = ocf_core_get_cache(core);
|
|
ocf_core_id_t core_id = ocf_core_get_id(core);
|
|
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_mngt_core_deinit_attached_meta(ocf_core_t core)
|
|
{
|
|
int retry = 1;
|
|
uint64_t core_size = 0;
|
|
ocf_cleaning_t clean_pol_type;
|
|
ocf_cache_t cache = ocf_core_get_cache(core);
|
|
ocf_core_id_t core_id = ocf_core_get_id(core);
|
|
|
|
core_size = ocf_volume_get_length(&core->volume);
|
|
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_mngt_core_remove_from_meta(ocf_core_t core)
|
|
{
|
|
ocf_cache_t cache = ocf_core_get_cache(core);
|
|
|
|
OCF_METADATA_LOCK_WR();
|
|
|
|
/* In metadata mark data this core was removed from cache */
|
|
core->conf_meta->added = false;
|
|
|
|
/* Clear UUID of core */
|
|
ocf_mngt_core_clear_uuid_metadata(core);
|
|
core->conf_meta->seq_no = OCF_SEQ_NO_INVALID;
|
|
|
|
OCF_METADATA_UNLOCK_WR();
|
|
}
|
|
|
|
/* Deinit in-memory structures related to this core */
|
|
void cache_mngt_core_remove_from_cache(ocf_core_t core)
|
|
{
|
|
ocf_cache_t cache = ocf_core_get_cache(core);
|
|
ocf_core_id_t core_id = ocf_core_get_id(core);
|
|
|
|
env_free(core->counters);
|
|
core->counters = NULL;
|
|
env_bit_clear(core_id, cache->conf_meta->valid_core_bitmap);
|
|
|
|
if (!core->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_rmutex_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_rmutex_unlock(&ocf_ctx->lock);
|
|
|
|
if (!instance)
|
|
error = -OCF_ERR_CACHE_NOT_EXIST;
|
|
else
|
|
*cache = instance;
|
|
|
|
return error;
|
|
}
|
|
|
|
int ocf_mngt_cache_get_by_name(ocf_ctx_t ctx, const char *name,
|
|
ocf_cache_t *cache)
|
|
{
|
|
struct ocf_cache *instance = NULL;
|
|
struct ocf_cache *iter = NULL;
|
|
|
|
OCF_CHECK_NULL(ctx);
|
|
OCF_CHECK_NULL(cache);
|
|
|
|
/* Lock caches list */
|
|
env_rmutex_lock(&ctx->lock);
|
|
|
|
list_for_each_entry(iter, &ctx->caches, list) {
|
|
if (!env_strncmp(ocf_cache_get_name(iter), name,
|
|
OCF_CACHE_NAME_SIZE)) {
|
|
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_rmutex_unlock(&ctx->lock);
|
|
|
|
if (!instance)
|
|
return -OCF_ERR_CACHE_NOT_EXIST;
|
|
|
|
*cache = instance;
|
|
|
|
return 0;
|
|
}
|
|
|
|
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_rmutex_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_rmutex_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;
|
|
}
|