ocf/src/mngt/ocf_mngt_common.c
Robert Baldyga 9ebb0de878 Do not modify core_count on cache load / activate
Increment core_count only on core addition, and decrement it only on core
removal.

Signed-off-by: Robert Baldyga <robert.baldyga@intel.com>
2022-03-31 10:00:24 +02:00

483 lines
11 KiB
C

/*
* Copyright(c) 2012-2021 Intel Corporation
* SPDX-License-Identifier: BSD-3-Clause
*/
#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 "../ocf_lru.h"
#include "../ocf_logger_priv.h"
#include "../ocf_queue_priv.h"
#include "../engine/engine_common.h"
/* Close if opened */
void cache_mngt_core_deinit(ocf_core_t core)
{
if (core->opened) {
ocf_volume_close(&core->front_volume);
ocf_volume_deinit(&core->front_volume);
ocf_volume_close(&core->volume);
}
if (core->has_volume)
ocf_volume_deinit(&core->volume);
core->opened = false;
}
/* 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_metadata_start_exclusive_access(&cache->metadata.lock);
ocf_cleaning_remove_core(cache, core_id);
ocf_metadata_end_exclusive_access(&cache->metadata.lock);
}
/* Deinitialize core metadata in attached metadata */
void cache_mngt_core_deinit_attached_meta(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_core_id_t iter_core_id;
ocf_cache_line_t curr_cline, prev_cline;
uint32_t hash, num_hash = cache->device->hash_table_entries;
unsigned lock_idx;
for (hash = 0; hash < num_hash;) {
prev_cline = cache->device->collision_table_entries;
lock_idx = ocf_metadata_concurrency_next_idx(cache->mngt_queue);
ocf_hb_id_prot_lock_wr(&cache->metadata.lock, lock_idx, hash);
curr_cline = ocf_metadata_get_hash(cache, hash);
while (curr_cline != cache->device->collision_table_entries) {
ocf_metadata_get_core_info(cache, curr_cline, &iter_core_id,
NULL);
if (iter_core_id != core_id) {
/* `prev_cline` is a pointer to last not sparsed cacheline in
* current hash */
prev_cline = curr_cline;
curr_cline = ocf_metadata_get_collision_next(cache, curr_cline);
continue;
}
if (!ocf_cache_line_try_lock_wr(
ocf_cache_line_concurrency(cache),
curr_cline)) {
break;
}
if (metadata_test_dirty(cache, curr_cline))
ocf_purge_cleaning_policy(cache, curr_cline);
ocf_metadata_sparse_cache_line(cache, curr_cline);
ocf_cache_line_unlock_wr(
ocf_cache_line_concurrency(cache),
curr_cline);
if (prev_cline != cache->device->collision_table_entries)
curr_cline = ocf_metadata_get_collision_next(cache, prev_cline);
else
curr_cline = ocf_metadata_get_hash(cache, hash);
}
ocf_hb_id_prot_unlock_wr(&cache->metadata.lock, lock_idx, hash);
/* Check whether all the cachelines from the hash bucket were sparsed */
if (curr_cline == cache->device->collision_table_entries)
hash++;
else
env_msleep(100);
}
}
/* 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_core_id_t core_id = ocf_core_get_id(core);
ocf_metadata_start_exclusive_access(&cache->metadata.lock);
/* In metadata mark data this core was removed from cache */
core->conf_meta->valid = false;
/* Clear UUID of core */
ocf_mngt_core_clear_uuid_metadata(core);
core->conf_meta->seq_no = OCF_SEQ_NO_INVALID;
env_bit_clear(core_id, cache->conf_meta->valid_core_bitmap);
cache->conf_meta->core_count--;
ocf_metadata_end_exclusive_access(&cache->metadata.lock);
}
/* 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_seq_cutoff_deinit(core);
env_free(core->counters);
core->counters = NULL;
core->added = false;
if (!core->opened && --cache->ocf_core_inactive_count == 0)
env_bit_clear(ocf_cache_state_incomplete, &cache->cache_state);
}
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);
env_vfree(cache);
ocf_ctx_put(ctx);
}
}
void __set_cleaning_policy(ocf_cache_t cache,
ocf_cleaning_t new_cleaning_policy)
{
cache->conf_meta->cleaning_policy_type = new_cleaning_policy;
cache->cleaner.policy = new_cleaning_policy;
}
int ocf_mngt_cache_get_by_name(ocf_ctx_t ctx, const char *name, size_t name_len,
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), OCF_CACHE_NAME_SIZE,
name, name_len)) {
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;
}