Add cache activation from passive state

Signed-off-by: Robert Baldyga <robert.baldyga@intel.com>
This commit is contained in:
Robert Baldyga 2021-08-12 13:04:50 +02:00
parent cc22c57cb7
commit 7b38ad205c
3 changed files with 397 additions and 43 deletions

View File

@ -128,6 +128,12 @@ typedef enum {
/** Core with the uuid already exists */
OCF_ERR_CORE_UUID_EXISTS,
/** Cache initialized with wrong metadata layout */
OCF_ERR_METADATA_LAYOUT_MISMATCH,
/** Cache initialized with wrong cache line size */
OCF_ERR_CACHE_LINE_SIZE_MISMATCH,
} ocf_error_t;
#endif /* __OCF_ERR_H__ */

View File

@ -536,6 +536,28 @@ void ocf_mngt_cache_bind(ocf_cache_t cache,
struct ocf_mngt_cache_device_config *cfg,
ocf_mngt_cache_bind_end_t cmpl, void *priv);
/**
* @brief Completion callback of cache activate operation
*
* @param[in] cache Cache handle
* @param[in] priv Callback context
* @param[in] error Error code (zero on success)
*/
typedef void (*ocf_mngt_cache_activate_end_t)(ocf_cache_t cache,
void *priv, int error);
/**
* @brief Activate cache instance
*
* @param[in] cache Cache handle
* @param[in] cfg Caching device configuration
* @param[in] cmpl Completion callback
* @param[in] priv Completion callback context
*/
void ocf_mngt_cache_activate(ocf_cache_t cache,
struct ocf_mngt_cache_device_config *cfg,
ocf_mngt_cache_activate_end_t cmpl, void *priv);
/* Adding and removing cores */
/**

View File

@ -95,6 +95,8 @@ struct ocf_cache_attach_context {
uint64_t volume_size;
/*!< size of the device in cache lines */
struct ocf_volume cache_volume;
/**
* @brief initialization state (in case of error, it is used to know
* which assets have to be deallocated in premature exit from function
@ -103,6 +105,9 @@ struct ocf_cache_attach_context {
bool device_alloc : 1;
/*!< data structure allocated */
bool volume_stored : 1;
/*!< underlying device volume is stored in contex */
bool volume_inited : 1;
/*!< underlying device volume is initialized */
@ -626,9 +631,6 @@ static void _ocf_mngt_load_init_instance_recovery(
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");
ocf_metadata_load_recovery(cache,
@ -639,11 +641,15 @@ static void _ocf_mngt_load_init_instance(ocf_pipeline_t pipeline,
void *priv, ocf_pipeline_arg_t arg)
{
struct ocf_cache_attach_context *context = priv;
ocf_cache_t cache = context->cache;
if (context->metadata.shutdown_status == ocf_metadata_clean_shutdown)
if (context->metadata.shutdown_status == ocf_metadata_clean_shutdown) {
_ocf_mngt_load_init_instance_clean_load(context);
else
} else {
ocf_cache_log(cache, log_warn,
"ERROR: Cache device did not shut down properly!\n");
_ocf_mngt_load_init_instance_recovery(context);
}
}
/**
@ -1215,44 +1221,6 @@ static void _ocf_mngt_init_handle_error(ocf_ctx_t ctx,
env_rmutex_unlock(&ctx->lock);
}
static void _ocf_mngt_attach_handle_error(
struct ocf_cache_attach_context *context)
{
ocf_cache_t cache = context->cache;
if (context->flags.cleaner_started)
ocf_stop_cleaner(cache);
if (context->flags.promotion_initialized)
__deinit_promotion_policy(cache);
if (context->flags.cores_opened)
_ocf_mngt_close_all_uninitialized_cores(cache);
if (context->flags.attached_metadata_inited)
ocf_metadata_deinit_variable_size(cache);
if (context->flags.concurrency_inited)
ocf_concurrency_deinit(cache);
if (context->flags.volume_opened)
ocf_volume_close(&cache->device->volume);
if (context->flags.volume_inited)
ocf_volume_deinit(&cache->device->volume);
if (context->flags.front_volume_opened)
ocf_volume_close(&cache->device->front_volume);
if (context->flags.front_volume_inited)
ocf_volume_deinit(&cache->device->front_volume);
if (context->flags.device_alloc)
env_vfree(cache->device);
ocf_pipeline_destroy(cache->stop_pipeline);
}
static void _ocf_mngt_cache_init(ocf_cache_t cache,
struct ocf_cache_mngt_init_params *params)
{
@ -1370,6 +1338,15 @@ static void _ocf_mngt_cache_set_passive(ocf_cache_t cache)
env_bit_set(ocf_cache_state_passive, &cache->cache_state);
}
static void _ocf_mngt_cache_set_active(ocf_cache_t cache)
{
/*
* Clear passive state and set the running bit.
*/
env_bit_clear(ocf_cache_state_passive, &cache->cache_state);
env_bit_set(ocf_cache_state_running, &cache->cache_state);
}
static void _ocf_mngt_init_attached_nonpersistent(ocf_pipeline_t pipeline,
void *priv, ocf_pipeline_arg_t arg)
{
@ -1634,6 +1611,46 @@ static void _ocf_mngt_attach_post_init(ocf_pipeline_t pipeline,
ocf_pipeline_next(pipeline);
}
static void _ocf_mngt_attach_handle_error(
struct ocf_cache_attach_context *context)
{
ocf_cache_t cache = context->cache;
if (context->flags.cleaner_started)
ocf_stop_cleaner(cache);
if (context->flags.promotion_initialized)
__deinit_promotion_policy(cache);
if (context->flags.cores_opened)
_ocf_mngt_close_all_uninitialized_cores(cache);
if (context->flags.attached_metadata_inited)
ocf_metadata_deinit_variable_size(cache);
if (context->flags.concurrency_inited)
ocf_concurrency_deinit(cache);
if (context->flags.volume_opened)
ocf_volume_close(&cache->device->volume);
if (context->flags.volume_inited)
ocf_volume_deinit(&cache->device->volume);
if (context->flags.front_volume_opened)
ocf_volume_close(&cache->device->front_volume);
if (context->flags.front_volume_inited)
ocf_volume_deinit(&cache->device->front_volume);
if (context->flags.device_alloc) {
env_vfree(cache->device);
cache->device = NULL;
}
ocf_pipeline_destroy(cache->stop_pipeline);
}
static void _ocf_mngt_cache_attach_finish(ocf_pipeline_t pipeline,
void *priv, int error)
{
@ -2038,6 +2055,241 @@ struct ocf_pipeline_properties _ocf_mngt_cache_bind_pipeline_properties = {
},
};
static void _ocf_mngt_activate_wait_metadata_io_finish(void *priv)
{
struct ocf_cache_attach_context *context = priv;
ocf_pipeline_next(context->pipeline);
}
static void _ocf_mngt_activate_wait_metadata_io(ocf_pipeline_t pipeline,
void *priv, ocf_pipeline_arg_t arg)
{
struct ocf_cache_attach_context *context = priv;
ocf_cache_t cache = context->cache;
ocf_refcnt_freeze(&cache->refcnt.metadata);
ocf_refcnt_register_zero_cb(&cache->refcnt.metadata,
_ocf_mngt_activate_wait_metadata_io_finish, context);
}
static void _ocf_mngt_activate_swap_cache_device(ocf_pipeline_t pipeline,
void *priv, ocf_pipeline_arg_t arg)
{
struct ocf_cache_attach_context *context = priv;
ocf_cache_t cache = context->cache;
const struct ocf_volume_uuid *cache_uuid;
ocf_volume_type_t type;
int ret, cmp;
cache_uuid = ocf_volume_get_uuid(ocf_cache_get_volume(cache));
ret = env_memcmp(context->cfg.uuid.data, context->cfg.uuid.size,
cache_uuid->data, cache_uuid->size, &cmp);
if (ret)
OCF_PL_FINISH_RET(pipeline, ret);
if (cmp == 0)
OCF_PL_NEXT_RET(pipeline);
ret = ocf_volume_init(&context->cache_volume, 0, NULL, false);
if (!ret)
OCF_PL_FINISH_RET(pipeline, ret);
ocf_volume_move(&context->cache_volume, &cache->device->volume);
context->flags.volume_stored = true;
type = ocf_ctx_get_volume_type(cache->owner, context->cfg.volume_type);
if (!type) {
OCF_PL_FINISH_RET(pipeline,
-OCF_ERR_INVAL_VOLUME_TYPE);
}
ret = ocf_volume_init(&cache->device->volume, type,
&context->cfg.uuid, true);
if (ret)
OCF_PL_FINISH_RET(pipeline, ret);
cache->device->volume.cache = cache;
context->flags.volume_inited = true;
ret = ocf_volume_open(&cache->device->volume,
context->cfg.volume_params);
if (ret) {
ocf_cache_log(cache, log_err, "ERROR: Cache not available\n");
OCF_PL_FINISH_RET(pipeline, ret);
}
context->flags.volume_opened = true;
context->volume_size = ocf_volume_get_length(&cache->device->volume);
ocf_pipeline_next(pipeline);
}
static void _ocf_mngt_activate_check_superblock_complete(void *priv, int error)
{
struct ocf_cache_attach_context *context = priv;
ocf_cache_t cache = context->cache;
int result;
if (error)
OCF_PL_FINISH_RET(context->pipeline, error);
result = ocf_metadata_validate_superblock(cache->owner,
cache->conf_meta);
if (result)
OCF_PL_FINISH_RET(context->pipeline, result);
if (cache->conf_meta->metadata_layout != cache->metadata.layout) {
OCF_PL_FINISH_RET(context->pipeline,
-OCF_ERR_METADATA_LAYOUT_MISMATCH);
}
if (cache->conf_meta->line_size != cache->metadata.settings.size) {
OCF_PL_FINISH_RET(context->pipeline,
-OCF_ERR_CACHE_LINE_SIZE_MISMATCH);
}
ocf_pipeline_next(context->pipeline);
}
static void _ocf_mngt_activate_check_superblock(ocf_pipeline_t pipeline,
void *priv, ocf_pipeline_arg_t arg)
{
struct ocf_cache_attach_context *context = priv;
ocf_cache_t cache = context->cache;
ocf_metadata_sb_crc_recovery(cache,
_ocf_mngt_activate_check_superblock_complete, context);
}
static void _ocf_mngt_activate_compare_superblock_end(
struct ocf_metadata_read_sb_ctx *sb_ctx)
{
struct ocf_superblock_config *superblock = &sb_ctx->superblock;
struct ocf_cache_attach_context *context = sb_ctx->priv1;
ocf_cache_t cache = context->cache;
int result, diff;
result = env_memcmp(cache->conf_meta, sizeof(*cache->conf_meta),
superblock, sizeof(*superblock), &diff);
if (result)
OCF_PL_FINISH_RET(context->pipeline, result);
if (diff) {
ocf_cache_log(cache, log_err, "Superblock missmatch!\n");
OCF_PL_FINISH_RET(context->pipeline, -OCF_ERR_INVAL);
}
ocf_pipeline_next(context->pipeline);
}
static void _ocf_mngt_activate_compare_superblock(ocf_pipeline_t pipeline,
void *priv, ocf_pipeline_arg_t arg)
{
struct ocf_cache_attach_context *context = priv;
ocf_cache_t cache = context->cache;
int result;
result = ocf_metadata_read_sb(cache->owner, ocf_cache_get_volume(cache),
_ocf_mngt_activate_compare_superblock_end,
context, NULL);
if (result)
OCF_PL_FINISH_RET(pipeline, result);
}
static void _ocf_mngt_activate_init_properties(ocf_pipeline_t pipeline,
void *priv, ocf_pipeline_arg_t arg)
{
struct ocf_cache_attach_context *context = priv;
ocf_cache_t cache = context->cache;
OCF_ASSERT_PLUGGED(cache);
context->metadata.shutdown_status = ocf_metadata_dirty_shutdown;
context->metadata.dirty_flushed = DIRTY_NOT_FLUSHED;
context->metadata.line_size = context->cfg.cache_line_size;
ocf_pipeline_next(pipeline);
}
static void _ocf_mngt_activate_handle_error(
struct ocf_cache_attach_context *context)
{
ocf_cache_t cache = context->cache;
if (context->flags.cleaner_started)
ocf_stop_cleaner(cache);
if (context->flags.promotion_initialized)
__deinit_promotion_policy(cache);
if (context->flags.cores_opened)
_ocf_mngt_close_all_uninitialized_cores(cache);
if (context->flags.volume_opened)
ocf_volume_close(&cache->device->volume);
if (context->flags.volume_inited)
ocf_volume_deinit(&cache->device->volume);
if (context->flags.volume_stored)
ocf_volume_move(&cache->device->volume, &context->cache_volume);
ocf_refcnt_unfreeze(&cache->refcnt.metadata);
}
static void _ocf_mngt_cache_activate_finish(ocf_pipeline_t pipeline,
void *priv, int error)
{
struct ocf_cache_attach_context *context = priv;
ocf_cache_t cache = context->cache;
ocf_pipeline_t stop_pipeline;
if (error) {
_ocf_mngt_activate_handle_error(context);
goto out;
}
error = ocf_pipeline_create(&stop_pipeline, cache,
&ocf_mngt_cache_stop_pipeline_properties);
if (error) {
_ocf_mngt_activate_handle_error(context);
goto out;
}
ocf_pipeline_destroy(cache->stop_pipeline);
cache->stop_pipeline = stop_pipeline;
ocf_volume_deinit(&context->cache_volume);
out:
context->cmpl(context->cache, context->priv1, context->priv2, error);
env_vfree(context->cfg.uuid.data);
ocf_pipeline_destroy(context->pipeline);
}
struct ocf_pipeline_properties _ocf_mngt_cache_activate_pipeline_properties = {
.priv_size = sizeof(struct ocf_cache_attach_context),
.finish = _ocf_mngt_cache_activate_finish,
.steps = {
OCF_PL_STEP(_ocf_mngt_copy_uuid_data),
OCF_PL_STEP(_ocf_mngt_activate_wait_metadata_io),
OCF_PL_STEP(_ocf_mngt_activate_swap_cache_device),
OCF_PL_STEP(_ocf_mngt_activate_check_superblock),
OCF_PL_STEP(_ocf_mngt_activate_compare_superblock),
OCF_PL_STEP(_ocf_mngt_activate_init_properties),
OCF_PL_STEP(_ocf_mngt_test_volume),
OCF_PL_STEP(_ocf_mngt_init_cleaner),
OCF_PL_STEP(_ocf_mngt_init_promotion),
OCF_PL_STEP(_ocf_mngt_load_add_cores),
OCF_PL_STEP(_ocf_mngt_load_post_metadata_load),
OCF_PL_STEP(_ocf_mngt_attach_shutdown_status),
OCF_PL_STEP(_ocf_mngt_attach_post_init),
OCF_PL_STEP_TERMINATOR(),
},
};
static void _ocf_mngt_cache_attach(ocf_cache_t cache,
struct ocf_mngt_cache_device_config *cfg,
_ocf_mngt_cache_attach_end_t cmpl, void *priv1, void *priv2)
@ -2149,6 +2401,35 @@ static void _ocf_mngt_cache_bind(ocf_cache_t cache,
OCF_PL_NEXT_RET(pipeline);
}
static void _ocf_mngt_cache_activate(ocf_cache_t cache,
struct ocf_mngt_cache_device_config *cfg,
_ocf_mngt_cache_attach_end_t cmpl, void *priv1, void *priv2)
{
struct ocf_cache_attach_context *context;
ocf_pipeline_t pipeline;
int result;
if (!ocf_cache_is_passive(cache))
OCF_CMPL_RET(cache, priv1, priv2, -OCF_ERR_CACHE_EXIST);
result = ocf_pipeline_create(&pipeline, cache,
&_ocf_mngt_cache_activate_pipeline_properties);
if (result)
OCF_CMPL_RET(cache, priv1, priv2, -OCF_ERR_NO_MEM);
context = ocf_pipeline_get_priv(pipeline);
context->cmpl = cmpl;
context->priv1 = priv1;
context->priv2 = priv2;
context->pipeline = pipeline;
context->cache = cache;
context->cfg = *cfg;
OCF_PL_NEXT_RET(pipeline);
}
static int _ocf_mngt_cache_validate_cfg(struct ocf_mngt_cache_config *cfg)
{
if (!strnlen(cfg->name, OCF_CACHE_NAME_SIZE))
@ -2444,6 +2725,51 @@ void ocf_mngt_cache_bind(ocf_cache_t cache,
cmpl, priv);
}
static void _ocf_mngt_cache_activate_complete(ocf_cache_t cache, void *priv1,
void *priv2, int error)
{
ocf_mngt_cache_bind_end_t cmpl = priv1;
if (error)
OCF_CMPL_RET(cache, priv2, error);
_ocf_mngt_cache_set_active(cache);
ocf_cache_log(cache, log_info, "Successfully activated\n");
OCF_CMPL_RET(cache, priv2, 0);
}
void ocf_mngt_cache_activate(ocf_cache_t cache,
struct ocf_mngt_cache_device_config *cfg,
ocf_mngt_cache_activate_end_t cmpl, void *priv)
{
int result;
OCF_CHECK_NULL(cache);
OCF_CHECK_NULL(cfg);
if (!cache->mngt_queue)
OCF_CMPL_RET(cache, priv, -OCF_ERR_INVAL);
/* Activate is not allowed in volatile metadata mode */
if (cache->metadata.is_volatile)
OCF_CMPL_RET(cache, priv, -OCF_ERR_INVAL);
/* Activate is not allowed with 'force' flag on */
if (cfg->force) {
ocf_cache_log(cache, log_err, "Using 'force' flag is forbidden "
"for activate operation.");
OCF_CMPL_RET(cache, priv, -OCF_ERR_INVAL);
}
result = _ocf_mngt_cache_validate_device_cfg(cfg);
if (result)
OCF_CMPL_RET(cache, priv, result);
_ocf_mngt_cache_activate(cache, cfg, _ocf_mngt_cache_activate_complete,
cmpl, priv);
}
static void ocf_mngt_cache_stop_detached(ocf_cache_t cache,
ocf_mngt_cache_stop_end_t cmpl, void *priv)
{