Merge pull request #557 from robertbaldyga/cache-passive-state
Introduce cache passive state
This commit is contained in:
commit
fd4400476e
@ -103,6 +103,15 @@ struct ocf_cache_info {
|
|||||||
*/
|
*/
|
||||||
ocf_volume_t ocf_cache_get_volume(ocf_cache_t cache);
|
ocf_volume_t ocf_cache_get_volume(ocf_cache_t cache);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Obtain front volume from cache
|
||||||
|
*
|
||||||
|
* @param[in] cache Cache object
|
||||||
|
*
|
||||||
|
* @retval Volume, NULL if dettached.
|
||||||
|
*/
|
||||||
|
ocf_volume_t ocf_cache_get_front_volume(ocf_cache_t cache);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get name of given cache object
|
* @brief Get name of given cache object
|
||||||
*
|
*
|
||||||
@ -137,11 +146,21 @@ bool ocf_cache_is_device_attached(ocf_cache_t cache);
|
|||||||
*
|
*
|
||||||
* @param[in] cache Cache object
|
* @param[in] cache Cache object
|
||||||
*
|
*
|
||||||
* @retval 1 Caching device is being stopped
|
* @retval 1 Caching device is running
|
||||||
* @retval 0 Caching device is being stopped
|
* @retval 0 Caching device is not running
|
||||||
*/
|
*/
|
||||||
bool ocf_cache_is_running(ocf_cache_t cache);
|
bool ocf_cache_is_running(ocf_cache_t cache);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Check if cache object is passive
|
||||||
|
*
|
||||||
|
* @param[in] cache Cache object
|
||||||
|
*
|
||||||
|
* @retval 1 Caching device is in passive state
|
||||||
|
* @retval 0 Caching device is not in passive state
|
||||||
|
*/
|
||||||
|
bool ocf_cache_is_passive(ocf_cache_t cache);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get cache mode of given cache object
|
* @brief Get cache mode of given cache object
|
||||||
*
|
*
|
||||||
|
@ -124,6 +124,9 @@ typedef enum {
|
|||||||
ocf_cache_state_incomplete = 3, //!< ocf_cache_state_incomplete
|
ocf_cache_state_incomplete = 3, //!< ocf_cache_state_incomplete
|
||||||
/*!< OCF cache has at least one inactive core */
|
/*!< OCF cache has at least one inactive core */
|
||||||
|
|
||||||
|
ocf_cache_state_passive = 4, //!< ocf_cache_state_passive
|
||||||
|
/*!< OCF is currently in passive mode */
|
||||||
|
|
||||||
ocf_cache_state_max //!< ocf_cache_state_max
|
ocf_cache_state_max //!< ocf_cache_state_max
|
||||||
/*!< Stopper of cache state enumerator */
|
/*!< Stopper of cache state enumerator */
|
||||||
} ocf_cache_state_t;
|
} ocf_cache_state_t;
|
||||||
|
@ -128,6 +128,12 @@ typedef enum {
|
|||||||
|
|
||||||
/** Core with the uuid already exists */
|
/** Core with the uuid already exists */
|
||||||
OCF_ERR_CORE_UUID_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;
|
} ocf_error_t;
|
||||||
|
|
||||||
#endif /* __OCF_ERR_H__ */
|
#endif /* __OCF_ERR_H__ */
|
||||||
|
@ -514,6 +514,50 @@ void ocf_mngt_cache_load(ocf_cache_t cache,
|
|||||||
struct ocf_mngt_cache_device_config *cfg,
|
struct ocf_mngt_cache_device_config *cfg,
|
||||||
ocf_mngt_cache_load_end_t cmpl, void *priv);
|
ocf_mngt_cache_load_end_t cmpl, void *priv);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Completion callback of cache bind operation
|
||||||
|
*
|
||||||
|
* @param[in] cache Cache handle
|
||||||
|
* @param[in] priv Callback context
|
||||||
|
* @param[in] error Error code (zero on success)
|
||||||
|
*/
|
||||||
|
typedef void (*ocf_mngt_cache_bind_end_t)(ocf_cache_t cache,
|
||||||
|
void *priv, int error);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Bind 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_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 */
|
/* Adding and removing cores */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1146,102 +1146,75 @@ void ocf_metadata_load_all(ocf_cache_t cache,
|
|||||||
ocf_pipeline_next(pipeline);
|
ocf_pipeline_next(pipeline);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _recovery_rebuild_cline_metadata(ocf_cache_t cache,
|
static void ocf_metadata_load_unsafe_finish(ocf_pipeline_t pipeline,
|
||||||
ocf_core_id_t core_id, uint64_t core_line,
|
void *priv, int error)
|
||||||
ocf_cache_line_t cache_line)
|
|
||||||
{
|
|
||||||
ocf_core_t core = ocf_cache_get_core(cache, core_id);
|
|
||||||
ocf_part_id_t part_id;
|
|
||||||
ocf_cache_line_t hash_index;
|
|
||||||
struct ocf_part_runtime *part;
|
|
||||||
|
|
||||||
part_id = PARTITION_DEFAULT;
|
|
||||||
part = cache->user_parts[part_id].part.runtime;
|
|
||||||
|
|
||||||
ocf_metadata_set_partition_id(cache, cache_line, part_id);
|
|
||||||
env_atomic_inc(&part->curr_size);
|
|
||||||
|
|
||||||
hash_index = ocf_metadata_hash_func(cache, core_line, core_id);
|
|
||||||
ocf_metadata_add_to_collision(cache, core_id, core_line, hash_index,
|
|
||||||
cache_line);
|
|
||||||
|
|
||||||
ocf_lru_init_cline(cache, cache_line);
|
|
||||||
|
|
||||||
ocf_lru_add(cache, cache_line);
|
|
||||||
|
|
||||||
env_atomic_inc(&core->runtime_meta->cached_clines);
|
|
||||||
env_atomic_inc(&core->runtime_meta->
|
|
||||||
part_counters[part_id].cached_clines);
|
|
||||||
|
|
||||||
if (metadata_test_dirty(cache, cache_line)) {
|
|
||||||
env_atomic_inc(&core->runtime_meta->dirty_clines);
|
|
||||||
env_atomic_inc(&core->runtime_meta->
|
|
||||||
part_counters[part_id].dirty_clines);
|
|
||||||
if (!env_atomic64_read(&core->runtime_meta->dirty_since))
|
|
||||||
env_atomic64_cmpxchg(&core->runtime_meta->dirty_since, 0,
|
|
||||||
env_ticks_to_secs(env_get_tick_count()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void _recovery_invalidate_clean_sec(struct ocf_cache *cache,
|
|
||||||
ocf_cache_line_t cline)
|
|
||||||
{
|
|
||||||
uint8_t i;
|
|
||||||
|
|
||||||
for (i = ocf_line_start_sector(cache);
|
|
||||||
i <= ocf_line_end_sector(cache); i++) {
|
|
||||||
if (!metadata_test_dirty_one(cache, cline, i)) {
|
|
||||||
/* Invalidate clear sectors */
|
|
||||||
metadata_clear_valid_sec_one(cache, cline, i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void _recovery_reset_cline_metadata(struct ocf_cache *cache,
|
|
||||||
ocf_cache_line_t cline)
|
|
||||||
{
|
|
||||||
|
|
||||||
ocf_metadata_set_core_info(cache, cline, OCF_CORE_MAX, ULLONG_MAX);
|
|
||||||
|
|
||||||
metadata_clear_valid(cache, cline);
|
|
||||||
|
|
||||||
ocf_cleaning_init_cache_block(cache, cline);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void _recovery_rebuild_metadata(ocf_pipeline_t pipeline,
|
|
||||||
void *priv, ocf_pipeline_arg_t arg)
|
|
||||||
{
|
{
|
||||||
struct ocf_metadata_context *context = priv;
|
struct ocf_metadata_context *context = priv;
|
||||||
bool dirty_only = ocf_pipeline_arg_get_int(arg);
|
|
||||||
ocf_cache_t cache = context->cache;
|
ocf_cache_t cache = context->cache;
|
||||||
ocf_cache_line_t cline;
|
|
||||||
ocf_core_id_t core_id;
|
|
||||||
uint64_t core_line;
|
|
||||||
unsigned char step = 0;
|
|
||||||
const uint64_t collision_table_entries =
|
|
||||||
ocf_metadata_collision_table_entries(cache);
|
|
||||||
|
|
||||||
ocf_metadata_start_exclusive_access(&cache->metadata.lock);
|
if (error) {
|
||||||
|
ocf_cache_log(cache, log_err, "Metadata read FAILURE\n");
|
||||||
for (cline = 0; cline < collision_table_entries; cline++) {
|
ocf_metadata_error(cache);
|
||||||
ocf_metadata_get_core_info(cache, cline, &core_id, &core_line);
|
goto out;
|
||||||
if (core_id != OCF_CORE_MAX &&
|
|
||||||
(!dirty_only || metadata_test_dirty(cache,
|
|
||||||
cline))) {
|
|
||||||
/* Rebuild metadata for mapped cache line */
|
|
||||||
_recovery_rebuild_cline_metadata(cache, core_id,
|
|
||||||
core_line, cline);
|
|
||||||
if (dirty_only)
|
|
||||||
_recovery_invalidate_clean_sec(cache, cline);
|
|
||||||
} else {
|
|
||||||
/* Reset metadata for not mapped or clean cache line */
|
|
||||||
_recovery_reset_cline_metadata(cache, cline);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
OCF_COND_RESCHED(step, 128);
|
ocf_cache_log(cache, log_info, "Done loading cache state\n");
|
||||||
|
|
||||||
|
out:
|
||||||
|
context->cmpl(context->priv, error);
|
||||||
|
ocf_pipeline_destroy(pipeline);
|
||||||
}
|
}
|
||||||
|
|
||||||
ocf_metadata_end_exclusive_access(&cache->metadata.lock);
|
struct ocf_pipeline_arg ocf_metadata_load_unsafe_args[] = {
|
||||||
|
OCF_PL_ARG_INT(metadata_segment_sb_config),
|
||||||
|
OCF_PL_ARG_INT(metadata_segment_sb_runtime),
|
||||||
|
OCF_PL_ARG_INT(metadata_segment_part_config),
|
||||||
|
OCF_PL_ARG_INT(metadata_segment_part_runtime),
|
||||||
|
OCF_PL_ARG_INT(metadata_segment_core_config),
|
||||||
|
OCF_PL_ARG_INT(metadata_segment_core_runtime),
|
||||||
|
OCF_PL_ARG_INT(metadata_segment_core_uuid),
|
||||||
|
OCF_PL_ARG_INT(metadata_segment_cleaning),
|
||||||
|
OCF_PL_ARG_INT(metadata_segment_lru),
|
||||||
|
OCF_PL_ARG_INT(metadata_segment_collision),
|
||||||
|
OCF_PL_ARG_INT(metadata_segment_list_info),
|
||||||
|
OCF_PL_ARG_INT(metadata_segment_hash),
|
||||||
|
OCF_PL_ARG_TERMINATOR(),
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ocf_pipeline_properties ocf_metadata_load_unsafe_pipeline_props = {
|
||||||
|
.priv_size = sizeof(struct ocf_metadata_context),
|
||||||
|
.finish = ocf_metadata_load_unsafe_finish,
|
||||||
|
.steps = {
|
||||||
|
OCF_PL_STEP_FOREACH(ocf_metadata_load_segment,
|
||||||
|
ocf_metadata_load_unsafe_args),
|
||||||
|
OCF_PL_STEP_TERMINATOR(),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Load metadata unsafe
|
||||||
|
*/
|
||||||
|
void ocf_metadata_load_unsafe(ocf_cache_t cache,
|
||||||
|
ocf_metadata_end_t cmpl, void *priv)
|
||||||
|
{
|
||||||
|
struct ocf_metadata_context *context;
|
||||||
|
ocf_pipeline_t pipeline;
|
||||||
|
int result;
|
||||||
|
|
||||||
|
OCF_DEBUG_TRACE(cache);
|
||||||
|
|
||||||
|
result = ocf_pipeline_create(&pipeline, cache,
|
||||||
|
&ocf_metadata_load_unsafe_pipeline_props);
|
||||||
|
if (result)
|
||||||
|
OCF_CMPL_RET(priv, result);
|
||||||
|
|
||||||
|
context = ocf_pipeline_get_priv(pipeline);
|
||||||
|
|
||||||
|
context->cmpl = cmpl;
|
||||||
|
context->priv = priv;
|
||||||
|
context->pipeline = pipeline;
|
||||||
|
context->cache = cache;
|
||||||
|
context->ctrl = cache->metadata.priv;
|
||||||
|
|
||||||
ocf_pipeline_next(pipeline);
|
ocf_pipeline_next(pipeline);
|
||||||
}
|
}
|
||||||
@ -1273,7 +1246,6 @@ ocf_metadata_load_recovery_legacy_pl_props = {
|
|||||||
.steps = {
|
.steps = {
|
||||||
OCF_PL_STEP_ARG_INT(ocf_metadata_load_segment,
|
OCF_PL_STEP_ARG_INT(ocf_metadata_load_segment,
|
||||||
metadata_segment_collision),
|
metadata_segment_collision),
|
||||||
OCF_PL_STEP_ARG_INT(_recovery_rebuild_metadata, true),
|
|
||||||
OCF_PL_STEP_TERMINATOR(),
|
OCF_PL_STEP_TERMINATOR(),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@ -1415,7 +1387,6 @@ ocf_metadata_load_recovery_atomic_pl_props = {
|
|||||||
.finish = ocf_metadata_load_recovery_atomic_finish,
|
.finish = ocf_metadata_load_recovery_atomic_finish,
|
||||||
.steps = {
|
.steps = {
|
||||||
OCF_PL_STEP(ocf_metadata_load_atomic_metadata),
|
OCF_PL_STEP(ocf_metadata_load_atomic_metadata),
|
||||||
OCF_PL_STEP_ARG_INT(_recovery_rebuild_metadata, false),
|
|
||||||
OCF_PL_STEP_TERMINATOR(),
|
OCF_PL_STEP_TERMINATOR(),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@ -1617,102 +1588,6 @@ void ocf_metadata_error(struct ocf_cache *cache)
|
|||||||
cache->device->metadata_error = -1;
|
cache->device->metadata_error = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ocf_metadata_read_sb_ctx;
|
|
||||||
|
|
||||||
typedef void (*ocf_metadata_read_sb_end_t)(
|
|
||||||
struct ocf_metadata_read_sb_ctx *context);
|
|
||||||
|
|
||||||
struct ocf_metadata_read_sb_ctx {
|
|
||||||
struct ocf_superblock_config superblock;
|
|
||||||
ocf_metadata_read_sb_end_t cmpl;
|
|
||||||
ocf_ctx_t ctx;
|
|
||||||
void *priv1;
|
|
||||||
void *priv2;
|
|
||||||
int error;
|
|
||||||
};
|
|
||||||
|
|
||||||
static void ocf_metadata_read_sb_complete(struct ocf_io *io, int error)
|
|
||||||
{
|
|
||||||
struct ocf_metadata_read_sb_ctx *context = io->priv1;
|
|
||||||
ctx_data_t *data = ocf_io_get_data(io);
|
|
||||||
|
|
||||||
if (!error) {
|
|
||||||
/* Read data from data into super block buffer */
|
|
||||||
ctx_data_rd_check(context->ctx, &context->superblock, data,
|
|
||||||
sizeof(context->superblock));
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx_data_free(context->ctx, data);
|
|
||||||
ocf_io_put(io);
|
|
||||||
|
|
||||||
context->error = error;
|
|
||||||
context->cmpl(context);
|
|
||||||
|
|
||||||
env_free(context);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int ocf_metadata_read_sb(ocf_ctx_t ctx, ocf_volume_t volume,
|
|
||||||
ocf_metadata_read_sb_end_t cmpl, void *priv1, void *priv2)
|
|
||||||
{
|
|
||||||
struct ocf_metadata_read_sb_ctx *context;
|
|
||||||
size_t sb_pages = BYTES_TO_PAGES(sizeof(context->superblock));
|
|
||||||
ctx_data_t *data;
|
|
||||||
struct ocf_io *io;
|
|
||||||
int result = 0;
|
|
||||||
|
|
||||||
/* Allocate memory for first page of super block */
|
|
||||||
context = env_zalloc(sizeof(*context), ENV_MEM_NORMAL);
|
|
||||||
if (!context) {
|
|
||||||
ocf_log(ctx, log_err, "Memory allocation error");
|
|
||||||
return -OCF_ERR_NO_MEM;
|
|
||||||
}
|
|
||||||
|
|
||||||
context->cmpl = cmpl;
|
|
||||||
context->ctx = ctx;
|
|
||||||
context->priv1 = priv1;
|
|
||||||
context->priv2 = priv2;
|
|
||||||
|
|
||||||
/* Allocate resources for IO */
|
|
||||||
io = ocf_volume_new_io(volume, NULL, 0, sb_pages * PAGE_SIZE,
|
|
||||||
OCF_READ, 0, 0);
|
|
||||||
if (!io) {
|
|
||||||
ocf_log(ctx, log_err, "Memory allocation error");
|
|
||||||
result = -OCF_ERR_NO_MEM;
|
|
||||||
goto err_io;
|
|
||||||
}
|
|
||||||
|
|
||||||
data = ctx_data_alloc(ctx, sb_pages);
|
|
||||||
if (!data) {
|
|
||||||
ocf_log(ctx, log_err, "Memory allocation error");
|
|
||||||
result = -OCF_ERR_NO_MEM;
|
|
||||||
goto err_data;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Read first page of cache device in order to recover metadata
|
|
||||||
* properties
|
|
||||||
*/
|
|
||||||
result = ocf_io_set_data(io, data, 0);
|
|
||||||
if (result) {
|
|
||||||
ocf_log(ctx, log_err, "Metadata IO configuration error\n");
|
|
||||||
result = -OCF_ERR_IO;
|
|
||||||
goto err_set_data;
|
|
||||||
}
|
|
||||||
|
|
||||||
ocf_io_set_cmpl(io, context, NULL, ocf_metadata_read_sb_complete);
|
|
||||||
ocf_volume_submit_io(io);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
err_set_data:
|
|
||||||
ctx_data_free(ctx, data);
|
|
||||||
err_data:
|
|
||||||
ocf_io_put(io);
|
|
||||||
err_io:
|
|
||||||
env_free(context);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void ocf_metadata_load_properties_cmpl(
|
static void ocf_metadata_load_properties_cmpl(
|
||||||
struct ocf_metadata_read_sb_ctx *context)
|
struct ocf_metadata_read_sb_ctx *context)
|
||||||
{
|
{
|
||||||
@ -1721,41 +1596,11 @@ static void ocf_metadata_load_properties_cmpl(
|
|||||||
ocf_metadata_load_properties_end_t cmpl = context->priv1;
|
ocf_metadata_load_properties_end_t cmpl = context->priv1;
|
||||||
void *priv = context->priv2;
|
void *priv = context->priv2;
|
||||||
ocf_ctx_t ctx = context->ctx;
|
ocf_ctx_t ctx = context->ctx;
|
||||||
|
int result;
|
||||||
|
|
||||||
if (superblock->magic_number != CACHE_MAGIC_NUMBER) {
|
result = ocf_metadata_validate_superblock(ctx, superblock);
|
||||||
ocf_log(ctx, log_info, "Cannot detect pre-existing metadata\n");
|
if (result)
|
||||||
OCF_CMPL_RET(priv, -OCF_ERR_NO_METADATA, NULL);
|
OCF_CMPL_RET(priv, result, NULL);
|
||||||
}
|
|
||||||
|
|
||||||
if (METADATA_VERSION() != superblock->metadata_version) {
|
|
||||||
ocf_log(ctx, log_err, "Metadata version mismatch!\n");
|
|
||||||
OCF_CMPL_RET(priv, -OCF_ERR_METADATA_VER, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!ocf_cache_line_size_is_valid(superblock->line_size)) {
|
|
||||||
ocf_log(ctx, log_err, "ERROR: Invalid cache line size!\n");
|
|
||||||
OCF_CMPL_RET(priv, -OCF_ERR_INVAL, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((unsigned)superblock->metadata_layout >= ocf_metadata_layout_max) {
|
|
||||||
ocf_log(ctx, log_err, "ERROR: Invalid metadata layout!\n");
|
|
||||||
OCF_CMPL_RET(priv, -OCF_ERR_INVAL, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (superblock->cache_mode >= ocf_cache_mode_max) {
|
|
||||||
ocf_log(ctx, log_err, "ERROR: Invalid cache mode!\n");
|
|
||||||
OCF_CMPL_RET(priv, -OCF_ERR_INVAL, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (superblock->clean_shutdown > ocf_metadata_clean_shutdown) {
|
|
||||||
ocf_log(ctx, log_err, "ERROR: Invalid shutdown status!\n");
|
|
||||||
OCF_CMPL_RET(priv, -OCF_ERR_INVAL, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (superblock->dirty_flushed > DIRTY_FLUSHED) {
|
|
||||||
ocf_log(ctx, log_err, "ERROR: Invalid flush status!\n");
|
|
||||||
OCF_CMPL_RET(priv, -OCF_ERR_INVAL, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
properties.line_size = superblock->line_size;
|
properties.line_size = superblock->line_size;
|
||||||
properties.layout = superblock->metadata_layout;
|
properties.layout = superblock->metadata_layout;
|
||||||
@ -1772,7 +1617,7 @@ void ocf_metadata_load_properties(ocf_volume_t volume,
|
|||||||
{
|
{
|
||||||
int result;
|
int result;
|
||||||
|
|
||||||
OCF_DEBUG_TRACE(cache);
|
OCF_DEBUG_TRACE(volume->cache);
|
||||||
|
|
||||||
result = ocf_metadata_read_sb(volume->cache->owner, volume,
|
result = ocf_metadata_read_sb(volume->cache->owner, volume,
|
||||||
ocf_metadata_load_properties_cmpl, cmpl, priv);
|
ocf_metadata_load_properties_cmpl, cmpl, priv);
|
||||||
@ -2159,3 +2004,51 @@ void ocf_metadata_probe_cores(ocf_ctx_t ctx, ocf_volume_t volume,
|
|||||||
ocf_metadata_query_cores(ctx, volume, uuids, uuids_count,
|
ocf_metadata_query_cores(ctx, volume, uuids, uuids_count,
|
||||||
ocf_metadata_probe_cores_end, context);
|
ocf_metadata_probe_cores_end, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int ocf_metadata_passive_update(ocf_cache_t cache, struct ocf_io *io)
|
||||||
|
{
|
||||||
|
struct ocf_metadata_ctrl *ctrl = cache->metadata.priv;
|
||||||
|
ctx_data_t *data = ocf_io_get_data(io);
|
||||||
|
uint64_t io_start_page = BYTES_TO_PAGES(io->addr);
|
||||||
|
uint64_t io_end_page = io_start_page + BYTES_TO_PAGES(io->bytes);
|
||||||
|
enum ocf_metadata_segment_id update_segments[] = {
|
||||||
|
metadata_segment_sb_config,
|
||||||
|
metadata_segment_part_config,
|
||||||
|
metadata_segment_core_config,
|
||||||
|
metadata_segment_core_uuid,
|
||||||
|
metadata_segment_collision,
|
||||||
|
};
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (io->dir == OCF_READ)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (io->addr % PAGE_SIZE || io->bytes % PAGE_SIZE) {
|
||||||
|
ocf_cache_log(cache, log_crit,
|
||||||
|
"Metadata update not aligned to page size!\n");
|
||||||
|
return -OCF_ERR_INVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (io_end_page >= ctrl->count_pages)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
for (i = 0; i < ARRAY_SIZE(update_segments); i++) {
|
||||||
|
enum ocf_metadata_segment_id seg = update_segments[i];
|
||||||
|
struct ocf_metadata_raw *raw = &(ctrl->raw_desc[seg]);
|
||||||
|
uint64_t raw_start_page = raw->ssd_pages_offset;
|
||||||
|
uint64_t raw_end_page = raw_start_page + raw->ssd_pages;
|
||||||
|
uint64_t overlap_start = OCF_MAX(io_start_page, raw_start_page);
|
||||||
|
uint64_t overlap_end = OCF_MIN(io_end_page, raw_end_page);
|
||||||
|
uint64_t overlap_start_data = overlap_start - io_start_page;
|
||||||
|
|
||||||
|
if (overlap_start < overlap_end) {
|
||||||
|
ctx_data_seek(cache->owner, data, ctx_data_seek_begin,
|
||||||
|
PAGES_TO_BYTES(overlap_start_data));
|
||||||
|
ocf_metadata_raw_update(cache, raw, data,
|
||||||
|
overlap_start - raw_start_page,
|
||||||
|
overlap_end - overlap_start);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
@ -164,6 +164,16 @@ void ocf_metadata_flush_do_asynch(struct ocf_cache *cache,
|
|||||||
void ocf_metadata_load_all(ocf_cache_t cache,
|
void ocf_metadata_load_all(ocf_cache_t cache,
|
||||||
ocf_metadata_end_t cmpl, void *priv);
|
ocf_metadata_end_t cmpl, void *priv);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Load metadata unsafe
|
||||||
|
*
|
||||||
|
* @param cache - Cache instance
|
||||||
|
* @param cmpl - Completion callback
|
||||||
|
* @param priv - Completion context
|
||||||
|
*/
|
||||||
|
void ocf_metadata_load_unsafe(ocf_cache_t cache,
|
||||||
|
ocf_metadata_end_t cmpl, void *priv);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Load metadata required for recovery procedure
|
* @brief Load metadata required for recovery procedure
|
||||||
*
|
*
|
||||||
@ -216,4 +226,6 @@ static inline ocf_cache_line_t ocf_metadata_collision_table_entries(
|
|||||||
return cache->device->collision_table_entries;
|
return cache->device->collision_table_entries;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int ocf_metadata_passive_update(ocf_cache_t cache, struct ocf_io *io);
|
||||||
|
|
||||||
#endif /* METADATA_H_ */
|
#endif /* METADATA_H_ */
|
||||||
|
@ -188,6 +188,42 @@ static void *_raw_ram_access(ocf_cache_t cache,
|
|||||||
return _RAW_RAM_ADDR(raw, entry);
|
return _RAW_RAM_ADDR(raw, entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int _raw_ram_drain_page(ocf_cache_t cache,
|
||||||
|
struct ocf_metadata_raw *raw, ctx_data_t *data, uint32_t page)
|
||||||
|
{
|
||||||
|
|
||||||
|
uint32_t size = raw->entry_size * raw->entries_in_page;
|
||||||
|
ocf_cache_line_t line;
|
||||||
|
|
||||||
|
ENV_BUG_ON(page > raw->ssd_pages);
|
||||||
|
ENV_BUG_ON(size > PAGE_SIZE);
|
||||||
|
|
||||||
|
line = page * raw->entries_in_page;
|
||||||
|
|
||||||
|
OCF_DEBUG_PARAM(cache, "Line = %u, Page = %u", line, page);
|
||||||
|
|
||||||
|
ctx_data_rd_check(cache->owner, _RAW_RAM_ADDR(raw, line), data, size);
|
||||||
|
ctx_data_seek(cache->owner, data, ctx_data_seek_current,
|
||||||
|
PAGE_SIZE - size);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* RAM Implementation - update
|
||||||
|
*/
|
||||||
|
static int _raw_ram_update(ocf_cache_t cache,
|
||||||
|
struct ocf_metadata_raw *raw, ctx_data_t *data,
|
||||||
|
uint64_t page, uint64_t count)
|
||||||
|
{
|
||||||
|
uint64_t i;
|
||||||
|
|
||||||
|
for (i = 0; i < count; i++)
|
||||||
|
_raw_ram_drain_page(cache, raw, data, page + i);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
struct _raw_ram_load_all_context {
|
struct _raw_ram_load_all_context {
|
||||||
struct ocf_metadata_raw *raw;
|
struct ocf_metadata_raw *raw;
|
||||||
ocf_metadata_end_t cmpl;
|
ocf_metadata_end_t cmpl;
|
||||||
@ -202,23 +238,9 @@ static int _raw_ram_load_all_drain(ocf_cache_t cache,
|
|||||||
{
|
{
|
||||||
struct _raw_ram_load_all_context *context = priv;
|
struct _raw_ram_load_all_context *context = priv;
|
||||||
struct ocf_metadata_raw *raw = context->raw;
|
struct ocf_metadata_raw *raw = context->raw;
|
||||||
uint32_t size = raw->entry_size * raw->entries_in_page;
|
|
||||||
ocf_cache_line_t line;
|
|
||||||
uint32_t raw_page;
|
|
||||||
|
|
||||||
ENV_BUG_ON(!_raw_ssd_page_is_valid(raw, page));
|
return _raw_ram_drain_page(cache, raw, data,
|
||||||
ENV_BUG_ON(size > PAGE_SIZE);
|
page - raw->ssd_pages_offset);
|
||||||
|
|
||||||
raw_page = page - raw->ssd_pages_offset;
|
|
||||||
line = raw_page * raw->entries_in_page;
|
|
||||||
|
|
||||||
OCF_DEBUG_PARAM(cache, "Line = %u, Page = %u", line, raw_page);
|
|
||||||
|
|
||||||
ctx_data_rd_check(cache->owner, _RAW_RAM_ADDR(raw, line), data, size);
|
|
||||||
ctx_data_seek(cache->owner, data, ctx_data_seek_current,
|
|
||||||
PAGE_SIZE - size);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _raw_ram_load_all_complete(ocf_cache_t cache,
|
static void _raw_ram_load_all_complete(ocf_cache_t cache,
|
||||||
@ -562,6 +584,7 @@ static const struct raw_iface IRAW[metadata_raw_type_max] = {
|
|||||||
.checksum = _raw_ram_checksum,
|
.checksum = _raw_ram_checksum,
|
||||||
.page = _raw_ram_page,
|
.page = _raw_ram_page,
|
||||||
.access = _raw_ram_access,
|
.access = _raw_ram_access,
|
||||||
|
.update = _raw_ram_update,
|
||||||
.load_all = _raw_ram_load_all,
|
.load_all = _raw_ram_load_all,
|
||||||
.flush_all = _raw_ram_flush_all,
|
.flush_all = _raw_ram_flush_all,
|
||||||
.flush_mark = _raw_ram_flush_mark,
|
.flush_mark = _raw_ram_flush_mark,
|
||||||
@ -575,6 +598,7 @@ static const struct raw_iface IRAW[metadata_raw_type_max] = {
|
|||||||
.checksum = raw_dynamic_checksum,
|
.checksum = raw_dynamic_checksum,
|
||||||
.page = raw_dynamic_page,
|
.page = raw_dynamic_page,
|
||||||
.access = raw_dynamic_access,
|
.access = raw_dynamic_access,
|
||||||
|
.update = raw_dynamic_update,
|
||||||
.load_all = raw_dynamic_load_all,
|
.load_all = raw_dynamic_load_all,
|
||||||
.flush_all = raw_dynamic_flush_all,
|
.flush_all = raw_dynamic_flush_all,
|
||||||
.flush_mark = raw_dynamic_flush_mark,
|
.flush_mark = raw_dynamic_flush_mark,
|
||||||
@ -588,6 +612,7 @@ static const struct raw_iface IRAW[metadata_raw_type_max] = {
|
|||||||
.checksum = raw_volatile_checksum,
|
.checksum = raw_volatile_checksum,
|
||||||
.page = _raw_ram_page,
|
.page = _raw_ram_page,
|
||||||
.access = _raw_ram_access,
|
.access = _raw_ram_access,
|
||||||
|
.update = raw_volatile_update,
|
||||||
.load_all = raw_volatile_load_all,
|
.load_all = raw_volatile_load_all,
|
||||||
.flush_all = raw_volatile_flush_all,
|
.flush_all = raw_volatile_flush_all,
|
||||||
.flush_mark = raw_volatile_flush_mark,
|
.flush_mark = raw_volatile_flush_mark,
|
||||||
@ -601,6 +626,7 @@ static const struct raw_iface IRAW[metadata_raw_type_max] = {
|
|||||||
.checksum = _raw_ram_checksum,
|
.checksum = _raw_ram_checksum,
|
||||||
.page = _raw_ram_page,
|
.page = _raw_ram_page,
|
||||||
.access = _raw_ram_access,
|
.access = _raw_ram_access,
|
||||||
|
.update = _raw_ram_update,
|
||||||
.load_all = _raw_ram_load_all,
|
.load_all = _raw_ram_load_all,
|
||||||
.flush_all = _raw_ram_flush_all,
|
.flush_all = _raw_ram_flush_all,
|
||||||
.flush_mark = raw_atomic_flush_mark,
|
.flush_mark = raw_atomic_flush_mark,
|
||||||
|
@ -125,6 +125,9 @@ struct raw_iface {
|
|||||||
void* (*access)(ocf_cache_t cache, struct ocf_metadata_raw *raw,
|
void* (*access)(ocf_cache_t cache, struct ocf_metadata_raw *raw,
|
||||||
uint32_t entry);
|
uint32_t entry);
|
||||||
|
|
||||||
|
int (*update)(ocf_cache_t cache, struct ocf_metadata_raw *raw,
|
||||||
|
ctx_data_t *data, uint64_t page, uint64_t count);
|
||||||
|
|
||||||
void (*load_all)(ocf_cache_t cache, struct ocf_metadata_raw *raw,
|
void (*load_all)(ocf_cache_t cache, struct ocf_metadata_raw *raw,
|
||||||
ocf_metadata_end_t cmpl, void *priv);
|
ocf_metadata_end_t cmpl, void *priv);
|
||||||
|
|
||||||
@ -234,7 +237,6 @@ static inline void *ocf_metadata_raw_wr_access(ocf_cache_t cache,
|
|||||||
* @param cache - Cache instance
|
* @param cache - Cache instance
|
||||||
* @param raw - RAW descriptor
|
* @param raw - RAW descriptor
|
||||||
* @param entry - Entry to be get
|
* @param entry - Entry to be get
|
||||||
* @param data - Data where metadata entry will be copied into
|
|
||||||
* @return 0 - Point to accessed data, in case of error NULL
|
* @return 0 - Point to accessed data, in case of error NULL
|
||||||
*/
|
*/
|
||||||
static inline const void *ocf_metadata_raw_rd_access( ocf_cache_t cache,
|
static inline const void *ocf_metadata_raw_rd_access( ocf_cache_t cache,
|
||||||
@ -243,6 +245,23 @@ static inline const void *ocf_metadata_raw_rd_access( ocf_cache_t cache,
|
|||||||
return raw->iface->access(cache, raw, entry);
|
return raw->iface->access(cache, raw, entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Update metadata based on cache device I/O
|
||||||
|
*
|
||||||
|
* @param cache - Cache instance
|
||||||
|
* @param raw - RAW descriptor
|
||||||
|
* @param data - Data buffer containing metadata pages
|
||||||
|
* @param page - First metadata page
|
||||||
|
* @param count - Number of metadata pages
|
||||||
|
* @return 0 - Operation success, otherwise error
|
||||||
|
*/
|
||||||
|
static inline int ocf_metadata_raw_update(ocf_cache_t cache,
|
||||||
|
struct ocf_metadata_raw *raw, ctx_data_t *data,
|
||||||
|
uint64_t page, uint64_t count)
|
||||||
|
{
|
||||||
|
return raw->iface->update(cache, raw, data, page, count);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Load all entries from SSD cache (cahce cache)
|
* @brief Load all entries from SSD cache (cahce cache)
|
||||||
*
|
*
|
||||||
|
@ -256,6 +256,78 @@ void *raw_dynamic_access(ocf_cache_t cache,
|
|||||||
return _raw_dynamic_get_item(cache, raw, entry);
|
return _raw_dynamic_get_item(cache, raw, entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* RAM DYNAMIC Implementation - update
|
||||||
|
*/
|
||||||
|
static int raw_dynamic_update_pages(ocf_cache_t cache,
|
||||||
|
struct ocf_metadata_raw *raw, ctx_data_t *data, uint64_t page,
|
||||||
|
uint64_t count, uint8_t **buffer, uint8_t *zpage)
|
||||||
|
{
|
||||||
|
struct _raw_ctrl *ctrl = (struct _raw_ctrl *)raw->priv;
|
||||||
|
int result = 0;
|
||||||
|
uint64_t i;
|
||||||
|
int cmp;
|
||||||
|
|
||||||
|
for (i = 0; i < count; i++) {
|
||||||
|
if (!*buffer) {
|
||||||
|
*buffer = env_secure_alloc(PAGE_SIZE);
|
||||||
|
if (!*buffer)
|
||||||
|
return -OCF_ERR_NO_MEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx_data_rd_check(cache->owner, *buffer, data, PAGE_SIZE);
|
||||||
|
|
||||||
|
result = env_memcmp(zpage, PAGE_SIZE, *buffer, PAGE_SIZE, &cmp);
|
||||||
|
if (result < 0)
|
||||||
|
return result;
|
||||||
|
|
||||||
|
/* When page is zero set, no need to allocate space for it */
|
||||||
|
if (cmp == 0) {
|
||||||
|
OCF_DEBUG_PARAM(cache, "Zero loaded %llu", i);
|
||||||
|
if (ctrl->pages[page + i]) {
|
||||||
|
env_secure_free(ctrl->pages[page + i],
|
||||||
|
PAGE_SIZE);
|
||||||
|
ctrl->pages[page + i] = NULL;
|
||||||
|
env_atomic_dec(&ctrl->count);
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
OCF_DEBUG_PARAM(cache, "Non-zero loaded %llu", i);
|
||||||
|
|
||||||
|
if (ctrl->pages[page + i])
|
||||||
|
env_secure_free(ctrl->pages[page + i], PAGE_SIZE);
|
||||||
|
ctrl->pages[page + i] = *buffer;
|
||||||
|
*buffer = NULL;
|
||||||
|
|
||||||
|
env_atomic_inc(&ctrl->count);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int raw_dynamic_update(ocf_cache_t cache,
|
||||||
|
struct ocf_metadata_raw *raw, ctx_data_t *data,
|
||||||
|
uint64_t page, uint64_t count)
|
||||||
|
{
|
||||||
|
uint8_t *buffer = NULL, *zpage;
|
||||||
|
int result;
|
||||||
|
|
||||||
|
zpage = env_vzalloc(PAGE_SIZE);
|
||||||
|
if (!zpage)
|
||||||
|
return -OCF_ERR_NO_MEM;
|
||||||
|
|
||||||
|
result = raw_dynamic_update_pages(cache, raw, data, page,
|
||||||
|
count, &buffer, zpage);
|
||||||
|
|
||||||
|
if (buffer)
|
||||||
|
env_secure_free(buffer, PAGE_SIZE);
|
||||||
|
|
||||||
|
env_vfree(zpage);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* RAM DYNAMIC Implementation - Load all
|
* RAM DYNAMIC Implementation - Load all
|
||||||
*/
|
*/
|
||||||
@ -269,7 +341,7 @@ struct raw_dynamic_load_all_context {
|
|||||||
ctx_data_t *data;
|
ctx_data_t *data;
|
||||||
uint8_t *zpage;
|
uint8_t *zpage;
|
||||||
uint8_t *page;
|
uint8_t *page;
|
||||||
uint64_t i;
|
uint64_t i_page;
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
ocf_metadata_end_t cmpl;
|
ocf_metadata_end_t cmpl;
|
||||||
@ -317,11 +389,12 @@ static int raw_dynamic_load_all_read(struct ocf_request *req)
|
|||||||
uint64_t count;
|
uint64_t count;
|
||||||
int result;
|
int result;
|
||||||
|
|
||||||
count = OCF_MIN(RAW_DYNAMIC_LOAD_PAGES, raw->ssd_pages - context->i);
|
count = OCF_MIN(RAW_DYNAMIC_LOAD_PAGES,
|
||||||
|
raw->ssd_pages - context->i_page);
|
||||||
|
|
||||||
/* Allocate IO */
|
/* Allocate IO */
|
||||||
context->io = ocf_new_cache_io(context->cache, req->io_queue,
|
context->io = ocf_new_cache_io(context->cache, req->io_queue,
|
||||||
PAGES_TO_BYTES(raw->ssd_pages_offset + context->i),
|
PAGES_TO_BYTES(raw->ssd_pages_offset + context->i_page),
|
||||||
PAGES_TO_BYTES(count), OCF_READ, 0, 0);
|
PAGES_TO_BYTES(count), OCF_READ, 0, 0);
|
||||||
|
|
||||||
if (!context->io) {
|
if (!context->io) {
|
||||||
@ -354,53 +427,20 @@ static int raw_dynamic_load_all_update(struct ocf_request *req)
|
|||||||
{
|
{
|
||||||
struct raw_dynamic_load_all_context *context = req->priv;
|
struct raw_dynamic_load_all_context *context = req->priv;
|
||||||
struct ocf_metadata_raw *raw = context->raw;
|
struct ocf_metadata_raw *raw = context->raw;
|
||||||
struct _raw_ctrl *ctrl = (struct _raw_ctrl *)raw->priv;
|
|
||||||
ocf_cache_t cache = context->cache;
|
ocf_cache_t cache = context->cache;
|
||||||
uint64_t count = BYTES_TO_PAGES(context->io->bytes);
|
uint64_t count = BYTES_TO_PAGES(context->io->bytes);
|
||||||
uint64_t i_page;
|
|
||||||
int result = 0;
|
int result = 0;
|
||||||
int cmp;
|
|
||||||
|
|
||||||
/* Reset head of data buffer */
|
/* Reset head of data buffer */
|
||||||
ctx_data_seek_check(context->cache->owner, context->data,
|
ctx_data_seek_check(context->cache->owner, context->data,
|
||||||
ctx_data_seek_begin, 0);
|
ctx_data_seek_begin, 0);
|
||||||
|
|
||||||
for (i_page = 0; i_page < count; i_page++, context->i++) {
|
result = raw_dynamic_update_pages(cache, raw, context->data,
|
||||||
if (!context->page) {
|
context->i_page, count, &context->page, context->zpage);
|
||||||
context->page = env_secure_alloc(PAGE_SIZE);
|
|
||||||
if (!context->page) {
|
|
||||||
/* Allocation error */
|
|
||||||
result = -OCF_ERR_NO_MEM;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx_data_rd_check(cache->owner, context->page,
|
context->i_page += count;
|
||||||
context->data, PAGE_SIZE);
|
|
||||||
|
|
||||||
result = env_memcmp(context->zpage, PAGE_SIZE, context->page,
|
if (result || context->i_page >= raw->ssd_pages) {
|
||||||
PAGE_SIZE, &cmp);
|
|
||||||
if (result)
|
|
||||||
break;
|
|
||||||
|
|
||||||
/* When page is zero set, no need to allocate space for it */
|
|
||||||
if (cmp == 0) {
|
|
||||||
OCF_DEBUG_PARAM(cache, "Zero loaded %llu", i);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
OCF_DEBUG_PARAM(cache, "Non-zero loaded %llu", i);
|
|
||||||
|
|
||||||
if (ctrl->pages[context->i])
|
|
||||||
env_vfree(ctrl->pages[context->i]);
|
|
||||||
|
|
||||||
ctrl->pages[context->i] = context->page;
|
|
||||||
context->page = NULL;
|
|
||||||
|
|
||||||
env_atomic_inc(&ctrl->count);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (result || context->i >= raw->ssd_pages) {
|
|
||||||
raw_dynamic_load_all_complete(context, result);
|
raw_dynamic_load_all_complete(context, result);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -53,6 +53,13 @@ uint32_t raw_dynamic_page(struct ocf_metadata_raw *raw, uint32_t entry);
|
|||||||
void *raw_dynamic_access(ocf_cache_t cache,
|
void *raw_dynamic_access(ocf_cache_t cache,
|
||||||
struct ocf_metadata_raw *raw, uint32_t entry);
|
struct ocf_metadata_raw *raw, uint32_t entry);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* RAW DYNAMIC - Update metadata based on cache volume io
|
||||||
|
*/
|
||||||
|
int raw_dynamic_update(ocf_cache_t cache,
|
||||||
|
struct ocf_metadata_raw *raw, ctx_data_t *data,
|
||||||
|
uint64_t page, uint64_t count);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* RAW DYNAMIC - Load all metadata of this RAW metadata container
|
* RAW DYNAMIC - Load all metadata of this RAW metadata container
|
||||||
* from cache device
|
* from cache device
|
||||||
|
@ -26,6 +26,17 @@ uint32_t raw_volatile_checksum(ocf_cache_t cache,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* RAW volatile Implementation - Update
|
||||||
|
*/
|
||||||
|
int raw_volatile_update(ocf_cache_t cache,
|
||||||
|
struct ocf_metadata_raw *raw, ctx_data_t *data,
|
||||||
|
uint64_t page, uint64_t count)
|
||||||
|
{
|
||||||
|
/* Do nothing on purpose. */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* RAW volatile Implementation - Load all metadata elements from SSD
|
* RAW volatile Implementation - Load all metadata elements from SSD
|
||||||
*/
|
*/
|
||||||
|
@ -17,6 +17,13 @@ uint32_t raw_volatile_size_on_ssd(struct ocf_metadata_raw *raw);
|
|||||||
uint32_t raw_volatile_checksum(ocf_cache_t cache,
|
uint32_t raw_volatile_checksum(ocf_cache_t cache,
|
||||||
struct ocf_metadata_raw *raw);
|
struct ocf_metadata_raw *raw);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* RAW volatile Implementation - Update
|
||||||
|
*/
|
||||||
|
int raw_volatile_update(ocf_cache_t cache,
|
||||||
|
struct ocf_metadata_raw *raw, ctx_data_t *data,
|
||||||
|
uint64_t page, uint64_t count);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* RAW volatile Implementation - Load all metadata elements from SSD
|
* RAW volatile Implementation - Load all metadata elements from SSD
|
||||||
*/
|
*/
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
#include "metadata_superblock.h"
|
#include "metadata_superblock.h"
|
||||||
#include "../ocf_priv.h"
|
#include "../ocf_priv.h"
|
||||||
#include "../utils/utils_io.h"
|
#include "../utils/utils_io.h"
|
||||||
|
#include "../utils/utils_cache_line.h"
|
||||||
|
|
||||||
#define OCF_METADATA_SUPERBLOCK_DEBUG 0
|
#define OCF_METADATA_SUPERBLOCK_DEBUG 0
|
||||||
|
|
||||||
@ -131,30 +132,10 @@ static void ocf_metadata_load_superblock_post(ocf_pipeline_t pipeline,
|
|||||||
struct ocf_metadata_ctrl *ctrl;
|
struct ocf_metadata_ctrl *ctrl;
|
||||||
struct ocf_superblock_config *sb_config;
|
struct ocf_superblock_config *sb_config;
|
||||||
ocf_cache_t cache = context->cache;
|
ocf_cache_t cache = context->cache;
|
||||||
struct ocf_metadata_uuid *muuid;
|
|
||||||
struct ocf_volume_uuid uuid;
|
|
||||||
ocf_volume_type_t volume_type;
|
|
||||||
ocf_core_t core;
|
|
||||||
ocf_core_id_t core_id;
|
|
||||||
|
|
||||||
ctrl = (struct ocf_metadata_ctrl *)cache->metadata.priv;
|
ctrl = (struct ocf_metadata_ctrl *)cache->metadata.priv;
|
||||||
sb_config = METADATA_MEM_POOL(ctrl, metadata_segment_sb_config);
|
sb_config = METADATA_MEM_POOL(ctrl, metadata_segment_sb_config);
|
||||||
|
|
||||||
for_each_core_metadata(cache, core, core_id) {
|
|
||||||
muuid = ocf_metadata_get_core_uuid(cache, core_id);
|
|
||||||
uuid.data = muuid->data;
|
|
||||||
uuid.size = muuid->size;
|
|
||||||
|
|
||||||
volume_type = ocf_ctx_get_volume_type(cache->owner,
|
|
||||||
core->conf_meta->type);
|
|
||||||
|
|
||||||
/* Initialize core volume */
|
|
||||||
ocf_volume_init(&core->volume, volume_type, &uuid, false);
|
|
||||||
core->has_volume = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Restore all dynamics items */
|
|
||||||
|
|
||||||
if (sb_config->core_count > OCF_CORE_MAX) {
|
if (sb_config->core_count > OCF_CORE_MAX) {
|
||||||
ocf_cache_log(cache, log_err,
|
ocf_cache_log(cache, log_err,
|
||||||
"Loading cache state ERROR, invalid cores count\n");
|
"Loading cache state ERROR, invalid cores count\n");
|
||||||
@ -503,3 +484,170 @@ bool ocf_metadata_superblock_get_clean_shutdown(
|
|||||||
return sb->config->clean_shutdown;
|
return sb->config->clean_shutdown;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int ocf_metadata_validate_superblock(ocf_ctx_t ctx,
|
||||||
|
struct ocf_superblock_config *superblock)
|
||||||
|
{
|
||||||
|
if (superblock->magic_number != CACHE_MAGIC_NUMBER) {
|
||||||
|
ocf_log(ctx, log_info, "Cannot detect pre-existing metadata\n");
|
||||||
|
return -OCF_ERR_NO_METADATA;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (METADATA_VERSION() != superblock->metadata_version) {
|
||||||
|
ocf_log(ctx, log_err, "Metadata version mismatch!\n");
|
||||||
|
return -OCF_ERR_METADATA_VER;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ocf_cache_line_size_is_valid(superblock->line_size)) {
|
||||||
|
ocf_log(ctx, log_err, "ERROR: Invalid cache line size!\n");
|
||||||
|
return -OCF_ERR_INVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((unsigned)superblock->metadata_layout >= ocf_metadata_layout_max) {
|
||||||
|
ocf_log(ctx, log_err, "ERROR: Invalid metadata layout!\n");
|
||||||
|
return -OCF_ERR_INVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (superblock->cache_mode >= ocf_cache_mode_max) {
|
||||||
|
ocf_log(ctx, log_err, "ERROR: Invalid cache mode!\n");
|
||||||
|
return -OCF_ERR_INVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (superblock->clean_shutdown > ocf_metadata_clean_shutdown) {
|
||||||
|
ocf_log(ctx, log_err, "ERROR: Invalid shutdown status!\n");
|
||||||
|
return -OCF_ERR_INVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (superblock->dirty_flushed > DIRTY_FLUSHED) {
|
||||||
|
ocf_log(ctx, log_err, "ERROR: Invalid flush status!\n");
|
||||||
|
return -OCF_ERR_INVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ocf_metadata_read_sb_complete(struct ocf_io *io, int error)
|
||||||
|
{
|
||||||
|
struct ocf_metadata_read_sb_ctx *context = io->priv1;
|
||||||
|
ctx_data_t *data = ocf_io_get_data(io);
|
||||||
|
|
||||||
|
if (!error) {
|
||||||
|
/* Read data from data into super block buffer */
|
||||||
|
ctx_data_rd_check(context->ctx, &context->superblock, data,
|
||||||
|
sizeof(context->superblock));
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx_data_free(context->ctx, data);
|
||||||
|
ocf_io_put(io);
|
||||||
|
|
||||||
|
context->error = error;
|
||||||
|
context->cmpl(context);
|
||||||
|
|
||||||
|
env_free(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
int ocf_metadata_read_sb(ocf_ctx_t ctx, ocf_volume_t volume,
|
||||||
|
ocf_metadata_read_sb_end_t cmpl, void *priv1, void *priv2)
|
||||||
|
{
|
||||||
|
struct ocf_metadata_read_sb_ctx *context;
|
||||||
|
size_t sb_pages = BYTES_TO_PAGES(sizeof(context->superblock));
|
||||||
|
ctx_data_t *data;
|
||||||
|
struct ocf_io *io;
|
||||||
|
int result = 0;
|
||||||
|
|
||||||
|
/* Allocate memory for first page of super block */
|
||||||
|
context = env_zalloc(sizeof(*context), ENV_MEM_NORMAL);
|
||||||
|
if (!context) {
|
||||||
|
ocf_log(ctx, log_err, "Memory allocation error");
|
||||||
|
return -OCF_ERR_NO_MEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
context->cmpl = cmpl;
|
||||||
|
context->ctx = ctx;
|
||||||
|
context->priv1 = priv1;
|
||||||
|
context->priv2 = priv2;
|
||||||
|
|
||||||
|
/* Allocate resources for IO */
|
||||||
|
io = ocf_volume_new_io(volume, NULL, 0, sb_pages * PAGE_SIZE,
|
||||||
|
OCF_READ, 0, 0);
|
||||||
|
if (!io) {
|
||||||
|
ocf_log(ctx, log_err, "Memory allocation error");
|
||||||
|
result = -OCF_ERR_NO_MEM;
|
||||||
|
goto err_io;
|
||||||
|
}
|
||||||
|
|
||||||
|
data = ctx_data_alloc(ctx, sb_pages);
|
||||||
|
if (!data) {
|
||||||
|
ocf_log(ctx, log_err, "Memory allocation error");
|
||||||
|
result = -OCF_ERR_NO_MEM;
|
||||||
|
goto err_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Read first page of cache device in order to recover metadata
|
||||||
|
* properties
|
||||||
|
*/
|
||||||
|
result = ocf_io_set_data(io, data, 0);
|
||||||
|
if (result) {
|
||||||
|
ocf_log(ctx, log_err, "Metadata IO configuration error\n");
|
||||||
|
result = -OCF_ERR_IO;
|
||||||
|
goto err_set_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
ocf_io_set_cmpl(io, context, NULL, ocf_metadata_read_sb_complete);
|
||||||
|
ocf_volume_submit_io(io);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
err_set_data:
|
||||||
|
ctx_data_free(ctx, data);
|
||||||
|
err_data:
|
||||||
|
ocf_io_put(io);
|
||||||
|
err_io:
|
||||||
|
env_free(context);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ocf_metadata_sb_crc_recovery_finish(ocf_pipeline_t pipeline,
|
||||||
|
void *priv, int error)
|
||||||
|
{
|
||||||
|
struct ocf_metadata_context *context = priv;
|
||||||
|
|
||||||
|
context->cmpl(context->priv, error);
|
||||||
|
ocf_pipeline_destroy(pipeline);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ocf_pipeline_properties ocf_metadata_sb_crc_recovery_pipeline_props = {
|
||||||
|
.priv_size = sizeof(struct ocf_metadata_context),
|
||||||
|
.finish = ocf_metadata_sb_crc_recovery_finish,
|
||||||
|
.steps = {
|
||||||
|
OCF_PL_STEP(ocf_metadata_check_crc_sb_config),
|
||||||
|
OCF_PL_STEP_FOREACH(ocf_metadata_check_crc,
|
||||||
|
ocf_metadata_load_sb_check_crc_args),
|
||||||
|
OCF_PL_STEP_TERMINATOR(),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
void ocf_metadata_sb_crc_recovery(ocf_cache_t cache,
|
||||||
|
ocf_metadata_end_t cmpl, void *priv)
|
||||||
|
{
|
||||||
|
struct ocf_metadata_context *context;
|
||||||
|
ocf_pipeline_t pipeline;
|
||||||
|
int result;
|
||||||
|
|
||||||
|
OCF_DEBUG_TRACE(cache);
|
||||||
|
|
||||||
|
result = ocf_pipeline_create(&pipeline, cache,
|
||||||
|
&ocf_metadata_sb_crc_recovery_pipeline_props);
|
||||||
|
if (result)
|
||||||
|
OCF_CMPL_RET(priv, result);
|
||||||
|
|
||||||
|
context = ocf_pipeline_get_priv(pipeline);
|
||||||
|
|
||||||
|
context->cmpl = cmpl;
|
||||||
|
context->priv = priv;
|
||||||
|
context->pipeline = pipeline;
|
||||||
|
context->cache = cache;
|
||||||
|
context->ctrl = cache->metadata.priv;
|
||||||
|
|
||||||
|
ocf_pipeline_next(pipeline);
|
||||||
|
}
|
||||||
|
@ -97,4 +97,27 @@ void ocf_metadata_superblock_set_checksum(
|
|||||||
bool ocf_metadata_superblock_get_clean_shutdown(
|
bool ocf_metadata_superblock_get_clean_shutdown(
|
||||||
struct ocf_metadata_segment *self);
|
struct ocf_metadata_segment *self);
|
||||||
|
|
||||||
|
int ocf_metadata_validate_superblock(ocf_ctx_t ctx,
|
||||||
|
struct ocf_superblock_config *superblock);
|
||||||
|
|
||||||
|
struct ocf_metadata_read_sb_ctx;
|
||||||
|
|
||||||
|
typedef void (*ocf_metadata_read_sb_end_t)(
|
||||||
|
struct ocf_metadata_read_sb_ctx *context);
|
||||||
|
|
||||||
|
struct ocf_metadata_read_sb_ctx {
|
||||||
|
struct ocf_superblock_config superblock;
|
||||||
|
ocf_metadata_read_sb_end_t cmpl;
|
||||||
|
ocf_ctx_t ctx;
|
||||||
|
void *priv1;
|
||||||
|
void *priv2;
|
||||||
|
int error;
|
||||||
|
};
|
||||||
|
|
||||||
|
int ocf_metadata_read_sb(ocf_ctx_t ctx, ocf_volume_t volume,
|
||||||
|
ocf_metadata_read_sb_end_t cmpl, void *priv1, void *priv2);
|
||||||
|
|
||||||
|
void ocf_metadata_sb_crc_recovery(ocf_cache_t cache,
|
||||||
|
ocf_metadata_end_t cmpl, void *priv);
|
||||||
|
|
||||||
#endif /* METADATA_SUPERBLOCK_H_ */
|
#endif /* METADATA_SUPERBLOCK_H_ */
|
||||||
|
@ -95,6 +95,8 @@ struct ocf_cache_attach_context {
|
|||||||
uint64_t volume_size;
|
uint64_t volume_size;
|
||||||
/*!< size of the device in cache lines */
|
/*!< size of the device in cache lines */
|
||||||
|
|
||||||
|
struct ocf_volume cache_volume;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief initialization state (in case of error, it is used to know
|
* @brief initialization state (in case of error, it is used to know
|
||||||
* which assets have to be deallocated in premature exit from function
|
* which assets have to be deallocated in premature exit from function
|
||||||
@ -103,15 +105,24 @@ struct ocf_cache_attach_context {
|
|||||||
bool device_alloc : 1;
|
bool device_alloc : 1;
|
||||||
/*!< data structure allocated */
|
/*!< data structure allocated */
|
||||||
|
|
||||||
|
bool volume_stored : 1;
|
||||||
|
/*!< underlying device volume is stored in contex */
|
||||||
|
|
||||||
bool volume_inited : 1;
|
bool volume_inited : 1;
|
||||||
/*!< uuid for cache device is allocated */
|
/*!< underlying device volume is initialized */
|
||||||
|
|
||||||
|
bool volume_opened : 1;
|
||||||
|
/*!< underlying device volume is open */
|
||||||
|
|
||||||
|
bool front_volume_inited : 1;
|
||||||
|
/*!< front volume is initialized */
|
||||||
|
|
||||||
|
bool front_volume_opened : 1;
|
||||||
|
/*!< front volume is open */
|
||||||
|
|
||||||
bool attached_metadata_inited : 1;
|
bool attached_metadata_inited : 1;
|
||||||
/*!< attached metadata sections initialized */
|
/*!< attached metadata sections initialized */
|
||||||
|
|
||||||
bool device_opened : 1;
|
|
||||||
/*!< underlying device volume is open */
|
|
||||||
|
|
||||||
bool cleaner_started : 1;
|
bool cleaner_started : 1;
|
||||||
/*!< Cleaner has been started */
|
/*!< Cleaner has been started */
|
||||||
|
|
||||||
@ -234,9 +245,11 @@ static void __setup_promotion_policy(ocf_cache_t cache)
|
|||||||
|
|
||||||
static void __deinit_promotion_policy(ocf_cache_t cache)
|
static void __deinit_promotion_policy(ocf_cache_t cache)
|
||||||
{
|
{
|
||||||
|
if (cache->promotion_policy) {
|
||||||
ocf_promotion_deinit(cache->promotion_policy);
|
ocf_promotion_deinit(cache->promotion_policy);
|
||||||
cache->promotion_policy = NULL;
|
cache->promotion_policy = NULL;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void __init_free(ocf_cache_t cache)
|
static void __init_free(ocf_cache_t cache)
|
||||||
{
|
{
|
||||||
@ -344,9 +357,10 @@ static void _ocf_mngt_close_all_uninitialized_cores(
|
|||||||
* @brief routine loading metadata from cache device
|
* @brief routine loading metadata from cache device
|
||||||
* - attempts to open all the underlying cores
|
* - attempts to open all the underlying cores
|
||||||
*/
|
*/
|
||||||
static int _ocf_mngt_load_add_cores(
|
static void _ocf_mngt_load_add_cores(ocf_pipeline_t pipeline,
|
||||||
struct ocf_cache_attach_context *context)
|
void *priv, ocf_pipeline_arg_t arg)
|
||||||
{
|
{
|
||||||
|
struct ocf_cache_attach_context *context = priv;
|
||||||
ocf_cache_t cache = context->cache;
|
ocf_cache_t cache = context->cache;
|
||||||
ocf_core_t core;
|
ocf_core_t core;
|
||||||
ocf_core_id_t core_id;
|
ocf_core_id_t core_id;
|
||||||
@ -361,10 +375,22 @@ static int _ocf_mngt_load_add_cores(
|
|||||||
|
|
||||||
/* Check in metadata which cores were saved in cache metadata */
|
/* Check in metadata which cores were saved in cache metadata */
|
||||||
for_each_core_metadata(cache, core, core_id) {
|
for_each_core_metadata(cache, core, core_id) {
|
||||||
|
struct ocf_metadata_uuid *muuid;
|
||||||
|
struct ocf_volume_uuid uuid;
|
||||||
|
ocf_volume_type_t volume_type;
|
||||||
ocf_volume_t tvolume = NULL;
|
ocf_volume_t tvolume = NULL;
|
||||||
|
|
||||||
if (!core->volume.type)
|
muuid = ocf_metadata_get_core_uuid(cache, core_id);
|
||||||
|
uuid.data = muuid->data;
|
||||||
|
uuid.size = muuid->size;
|
||||||
|
|
||||||
|
volume_type = ocf_ctx_get_volume_type(cache->owner,
|
||||||
|
core->conf_meta->type);
|
||||||
|
|
||||||
|
ret = ocf_volume_init(&core->volume, volume_type, &uuid, false);
|
||||||
|
if (ret)
|
||||||
goto err;
|
goto err;
|
||||||
|
core->has_volume = true;
|
||||||
|
|
||||||
tvolume = ocf_mngt_core_pool_lookup(ocf_cache_get_ctx(cache),
|
tvolume = ocf_mngt_core_pool_lookup(ocf_cache_get_ctx(cache),
|
||||||
&core->volume.uuid, core->volume.type);
|
&core->volume.uuid, core->volume.type);
|
||||||
@ -438,29 +464,120 @@ static int _ocf_mngt_load_add_cores(
|
|||||||
}
|
}
|
||||||
|
|
||||||
context->flags.cores_opened = true;
|
context->flags.cores_opened = true;
|
||||||
return 0;
|
OCF_PL_NEXT_RET(context->pipeline);
|
||||||
|
|
||||||
err:
|
err:
|
||||||
_ocf_mngt_close_all_uninitialized_cores(cache);
|
_ocf_mngt_close_all_uninitialized_cores(cache);
|
||||||
|
|
||||||
return -OCF_ERR_START_CACHE_FAIL;
|
OCF_PL_FINISH_RET(pipeline, -OCF_ERR_START_CACHE_FAIL);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _ocf_mngt_load_init_instance_complete(void *priv, int error)
|
static void _recovery_rebuild_cline_metadata(ocf_cache_t cache,
|
||||||
|
ocf_core_id_t core_id, uint64_t core_line,
|
||||||
|
ocf_cache_line_t cache_line)
|
||||||
|
{
|
||||||
|
ocf_core_t core = ocf_cache_get_core(cache, core_id);
|
||||||
|
ocf_part_id_t part_id;
|
||||||
|
ocf_cache_line_t hash_index;
|
||||||
|
struct ocf_part_runtime *part;
|
||||||
|
|
||||||
|
part_id = PARTITION_DEFAULT;
|
||||||
|
part = cache->user_parts[part_id].part.runtime;
|
||||||
|
|
||||||
|
ocf_metadata_set_partition_id(cache, cache_line, part_id);
|
||||||
|
env_atomic_inc(&part->curr_size);
|
||||||
|
|
||||||
|
hash_index = ocf_metadata_hash_func(cache, core_line, core_id);
|
||||||
|
ocf_metadata_add_to_collision(cache, core_id, core_line, hash_index,
|
||||||
|
cache_line);
|
||||||
|
|
||||||
|
ocf_lru_init_cline(cache, cache_line);
|
||||||
|
|
||||||
|
ocf_lru_add(cache, cache_line);
|
||||||
|
|
||||||
|
env_atomic_inc(&core->runtime_meta->cached_clines);
|
||||||
|
env_atomic_inc(&core->runtime_meta->
|
||||||
|
part_counters[part_id].cached_clines);
|
||||||
|
|
||||||
|
if (metadata_test_dirty(cache, cache_line)) {
|
||||||
|
env_atomic_inc(&core->runtime_meta->dirty_clines);
|
||||||
|
env_atomic_inc(&core->runtime_meta->
|
||||||
|
part_counters[part_id].dirty_clines);
|
||||||
|
if (!env_atomic64_read(&core->runtime_meta->dirty_since))
|
||||||
|
env_atomic64_cmpxchg(&core->runtime_meta->dirty_since, 0,
|
||||||
|
env_ticks_to_secs(env_get_tick_count()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _recovery_invalidate_clean_sec(struct ocf_cache *cache,
|
||||||
|
ocf_cache_line_t cline)
|
||||||
|
{
|
||||||
|
uint8_t i;
|
||||||
|
|
||||||
|
for (i = ocf_line_start_sector(cache);
|
||||||
|
i <= ocf_line_end_sector(cache); i++) {
|
||||||
|
if (!metadata_test_dirty_one(cache, cline, i)) {
|
||||||
|
/* Invalidate clear sectors */
|
||||||
|
metadata_clear_valid_sec_one(cache, cline, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _recovery_reset_cline_metadata(struct ocf_cache *cache,
|
||||||
|
ocf_cache_line_t cline)
|
||||||
|
{
|
||||||
|
ocf_metadata_set_core_info(cache, cline, OCF_CORE_MAX, ULLONG_MAX);
|
||||||
|
|
||||||
|
metadata_clear_valid(cache, cline);
|
||||||
|
|
||||||
|
ocf_cleaning_init_cache_block(cache, cline);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _ocf_mngt_recovery_rebuild_metadata(ocf_cache_t cache)
|
||||||
|
{
|
||||||
|
ocf_cache_line_t cline;
|
||||||
|
ocf_core_id_t core_id;
|
||||||
|
uint64_t core_line;
|
||||||
|
unsigned char step = 0;
|
||||||
|
bool dirty_only = !ocf_volume_is_atomic(ocf_cache_get_volume(cache));
|
||||||
|
const uint64_t collision_table_entries =
|
||||||
|
ocf_metadata_collision_table_entries(cache);
|
||||||
|
|
||||||
|
ocf_metadata_start_exclusive_access(&cache->metadata.lock);
|
||||||
|
|
||||||
|
for (cline = 0; cline < collision_table_entries; cline++) {
|
||||||
|
ocf_metadata_get_core_info(cache, cline, &core_id, &core_line);
|
||||||
|
if (core_id != OCF_CORE_MAX &&
|
||||||
|
(!dirty_only || metadata_test_dirty(cache,
|
||||||
|
cline))) {
|
||||||
|
/* Rebuild metadata for mapped cache line */
|
||||||
|
_recovery_rebuild_cline_metadata(cache, core_id,
|
||||||
|
core_line, cline);
|
||||||
|
if (dirty_only)
|
||||||
|
_recovery_invalidate_clean_sec(cache, cline);
|
||||||
|
} else {
|
||||||
|
/* Reset metadata for not mapped or clean cache line */
|
||||||
|
_recovery_reset_cline_metadata(cache, cline);
|
||||||
|
}
|
||||||
|
|
||||||
|
OCF_COND_RESCHED(step, 128);
|
||||||
|
}
|
||||||
|
|
||||||
|
ocf_metadata_end_exclusive_access(&cache->metadata.lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _ocf_mngt_load_post_metadata_load(ocf_pipeline_t pipeline,
|
||||||
|
void *priv, ocf_pipeline_arg_t arg)
|
||||||
{
|
{
|
||||||
struct ocf_cache_attach_context *context = priv;
|
struct ocf_cache_attach_context *context = priv;
|
||||||
ocf_cache_t cache = context->cache;
|
ocf_cache_t cache = context->cache;
|
||||||
ocf_cleaning_t cleaning_policy;
|
ocf_cleaning_t cleaning_policy;
|
||||||
ocf_error_t result;
|
ocf_error_t result;
|
||||||
|
|
||||||
if (error) {
|
if (context->metadata.shutdown_status != ocf_metadata_clean_shutdown) {
|
||||||
ocf_cache_log(cache, log_err,
|
_ocf_mngt_recovery_rebuild_metadata(cache);
|
||||||
"Cannot read cache metadata\n");
|
|
||||||
OCF_PL_FINISH_RET(context->pipeline, -OCF_ERR_START_CACHE_FAIL);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (context->metadata.shutdown_status != ocf_metadata_clean_shutdown)
|
|
||||||
__populate_free(cache);
|
__populate_free(cache);
|
||||||
|
}
|
||||||
|
|
||||||
cleaning_policy = cache->conf_meta->cleaning_policy_type;
|
cleaning_policy = cache->conf_meta->cleaning_policy_type;
|
||||||
|
|
||||||
@ -472,7 +589,21 @@ void _ocf_mngt_load_init_instance_complete(void *priv, int error)
|
|||||||
if (result) {
|
if (result) {
|
||||||
ocf_cache_log(cache, log_err,
|
ocf_cache_log(cache, log_err,
|
||||||
"Cannot initialize cleaning policy\n");
|
"Cannot initialize cleaning policy\n");
|
||||||
OCF_PL_FINISH_RET(context->pipeline, result);
|
OCF_PL_FINISH_RET(pipeline, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
ocf_pipeline_next(pipeline);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _ocf_mngt_load_init_instance_complete(void *priv, int error)
|
||||||
|
{
|
||||||
|
struct ocf_cache_attach_context *context = priv;
|
||||||
|
ocf_cache_t cache = context->cache;
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
ocf_cache_log(cache, log_err,
|
||||||
|
"Cannot read cache metadata\n");
|
||||||
|
OCF_PL_FINISH_RET(context->pipeline, -OCF_ERR_START_CACHE_FAIL);
|
||||||
}
|
}
|
||||||
|
|
||||||
ocf_pipeline_next(context->pipeline);
|
ocf_pipeline_next(context->pipeline);
|
||||||
@ -500,9 +631,6 @@ static void _ocf_mngt_load_init_instance_recovery(
|
|||||||
|
|
||||||
init_attached_data_structures_recovery(cache);
|
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_cache_log(cache, log_info, "Initiating recovery sequence...\n");
|
||||||
|
|
||||||
ocf_metadata_load_recovery(cache,
|
ocf_metadata_load_recovery(cache,
|
||||||
@ -514,19 +642,15 @@ static void _ocf_mngt_load_init_instance(ocf_pipeline_t pipeline,
|
|||||||
{
|
{
|
||||||
struct ocf_cache_attach_context *context = priv;
|
struct ocf_cache_attach_context *context = priv;
|
||||||
ocf_cache_t cache = context->cache;
|
ocf_cache_t cache = context->cache;
|
||||||
int ret;
|
|
||||||
|
|
||||||
OCF_ASSERT_PLUGGED(cache);
|
if (context->metadata.shutdown_status == ocf_metadata_clean_shutdown) {
|
||||||
|
|
||||||
ret = _ocf_mngt_load_add_cores(context);
|
|
||||||
if (ret)
|
|
||||||
OCF_PL_FINISH_RET(pipeline, ret);
|
|
||||||
|
|
||||||
if (context->metadata.shutdown_status == ocf_metadata_clean_shutdown)
|
|
||||||
_ocf_mngt_load_init_instance_clean_load(context);
|
_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);
|
_ocf_mngt_load_init_instance_recovery(context);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief allocate memory for new cache, add it to cache queue, set initial
|
* @brief allocate memory for new cache, add it to cache queue, set initial
|
||||||
@ -615,7 +739,7 @@ static void _ocf_mngt_attach_cache_device(ocf_pipeline_t pipeline,
|
|||||||
ocf_cache_log(cache, log_err, "ERROR: Cache not available\n");
|
ocf_cache_log(cache, log_err, "ERROR: Cache not available\n");
|
||||||
OCF_PL_FINISH_RET(pipeline, ret);
|
OCF_PL_FINISH_RET(pipeline, ret);
|
||||||
}
|
}
|
||||||
context->flags.device_opened = true;
|
context->flags.volume_opened = true;
|
||||||
|
|
||||||
context->volume_size = ocf_volume_get_length(&cache->device->volume);
|
context->volume_size = ocf_volume_get_length(&cache->device->volume);
|
||||||
|
|
||||||
@ -902,7 +1026,7 @@ static void _ocf_mngt_load_read_properties_end(void *priv, int error,
|
|||||||
/*
|
/*
|
||||||
* Check if name loaded from disk is the same as present one.
|
* Check if name loaded from disk is the same as present one.
|
||||||
*/
|
*/
|
||||||
if (env_strncmp(cache->conf_meta->name, OCF_CACHE_NAME_SIZE,
|
if (env_strncmp(cache->name, OCF_CACHE_NAME_SIZE,
|
||||||
properties->cache_name, OCF_CACHE_NAME_SIZE)) {
|
properties->cache_name, OCF_CACHE_NAME_SIZE)) {
|
||||||
OCF_PL_FINISH_RET(context->pipeline, -OCF_ERR_CACHE_NAME_MISMATCH);
|
OCF_PL_FINISH_RET(context->pipeline, -OCF_ERR_CACHE_NAME_MISMATCH);
|
||||||
}
|
}
|
||||||
@ -1097,38 +1221,6 @@ static void _ocf_mngt_init_handle_error(ocf_ctx_t ctx,
|
|||||||
env_rmutex_unlock(&ctx->lock);
|
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.device_opened)
|
|
||||||
ocf_volume_close(&cache->device->volume);
|
|
||||||
|
|
||||||
if (context->flags.concurrency_inited)
|
|
||||||
ocf_concurrency_deinit(cache);
|
|
||||||
|
|
||||||
if (context->flags.volume_inited)
|
|
||||||
ocf_volume_deinit(&cache->device->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,
|
static void _ocf_mngt_cache_init(ocf_cache_t cache,
|
||||||
struct ocf_cache_mngt_init_params *params)
|
struct ocf_cache_mngt_init_params *params)
|
||||||
{
|
{
|
||||||
@ -1237,6 +1329,24 @@ static void _ocf_mngt_cache_set_valid(ocf_cache_t cache)
|
|||||||
env_bit_set(ocf_cache_state_running, &cache->cache_state);
|
env_bit_set(ocf_cache_state_running, &cache->cache_state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void _ocf_mngt_cache_set_passive(ocf_cache_t cache)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Clear initialization state and set the passive bit.
|
||||||
|
*/
|
||||||
|
env_bit_clear(ocf_cache_state_initializing, &cache->cache_state);
|
||||||
|
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,
|
static void _ocf_mngt_init_attached_nonpersistent(ocf_pipeline_t pipeline,
|
||||||
void *priv, ocf_pipeline_arg_t arg)
|
void *priv, ocf_pipeline_arg_t arg)
|
||||||
{
|
{
|
||||||
@ -1501,6 +1611,46 @@ static void _ocf_mngt_attach_post_init(ocf_pipeline_t pipeline,
|
|||||||
ocf_pipeline_next(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,
|
static void _ocf_mngt_cache_attach_finish(ocf_pipeline_t pipeline,
|
||||||
void *priv, int error)
|
void *priv, int error)
|
||||||
{
|
{
|
||||||
@ -1554,7 +1704,9 @@ struct ocf_pipeline_properties _ocf_mngt_cache_load_pipeline_properties = {
|
|||||||
OCF_PL_STEP(_ocf_mngt_load_superblock),
|
OCF_PL_STEP(_ocf_mngt_load_superblock),
|
||||||
OCF_PL_STEP(_ocf_mngt_init_cleaner),
|
OCF_PL_STEP(_ocf_mngt_init_cleaner),
|
||||||
OCF_PL_STEP(_ocf_mngt_init_promotion),
|
OCF_PL_STEP(_ocf_mngt_init_promotion),
|
||||||
|
OCF_PL_STEP(_ocf_mngt_load_add_cores),
|
||||||
OCF_PL_STEP(_ocf_mngt_load_init_instance),
|
OCF_PL_STEP(_ocf_mngt_load_init_instance),
|
||||||
|
OCF_PL_STEP(_ocf_mngt_load_post_metadata_load),
|
||||||
OCF_PL_STEP(_ocf_mngt_attach_flush_metadata),
|
OCF_PL_STEP(_ocf_mngt_attach_flush_metadata),
|
||||||
OCF_PL_STEP(_ocf_mngt_attach_shutdown_status),
|
OCF_PL_STEP(_ocf_mngt_attach_shutdown_status),
|
||||||
OCF_PL_STEP(_ocf_mngt_attach_post_init),
|
OCF_PL_STEP(_ocf_mngt_attach_post_init),
|
||||||
@ -1689,6 +1841,29 @@ static void _ocf_mngt_cache_put_io_queues(ocf_cache_t cache)
|
|||||||
ocf_queue_put(queue);
|
ocf_queue_put(queue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void ocf_mngt_cache_stop_deinit_metadata(ocf_pipeline_t pipeline,
|
||||||
|
void *priv, ocf_pipeline_arg_t arg)
|
||||||
|
{
|
||||||
|
struct ocf_mngt_cache_stop_context *context = priv;
|
||||||
|
ocf_cache_t cache = context->cache;
|
||||||
|
|
||||||
|
ocf_volume_close(&cache->device->volume);
|
||||||
|
|
||||||
|
ocf_metadata_deinit_variable_size(cache);
|
||||||
|
ocf_concurrency_deinit(cache);
|
||||||
|
|
||||||
|
ocf_volume_deinit(&cache->device->volume);
|
||||||
|
|
||||||
|
env_vfree(cache->device);
|
||||||
|
cache->device = NULL;
|
||||||
|
|
||||||
|
/* TODO: this should be removed from detach after 'attached' stats
|
||||||
|
are better separated in statistics */
|
||||||
|
env_atomic_set(&cache->fallback_pt_error_counter, 0);
|
||||||
|
|
||||||
|
ocf_pipeline_next(pipeline);
|
||||||
|
}
|
||||||
|
|
||||||
static void ocf_mngt_cache_stop_put_io_queues(ocf_pipeline_t pipeline,
|
static void ocf_mngt_cache_stop_put_io_queues(ocf_pipeline_t pipeline,
|
||||||
void *priv, ocf_pipeline_arg_t arg)
|
void *priv, ocf_pipeline_arg_t arg)
|
||||||
{
|
{
|
||||||
@ -1777,11 +1952,343 @@ struct ocf_pipeline_properties ocf_mngt_cache_stop_pipeline_properties = {
|
|||||||
OCF_PL_STEP(ocf_mngt_cache_stop_check_dirty),
|
OCF_PL_STEP(ocf_mngt_cache_stop_check_dirty),
|
||||||
OCF_PL_STEP(ocf_mngt_cache_stop_remove_cores),
|
OCF_PL_STEP(ocf_mngt_cache_stop_remove_cores),
|
||||||
OCF_PL_STEP(ocf_mngt_cache_stop_unplug),
|
OCF_PL_STEP(ocf_mngt_cache_stop_unplug),
|
||||||
|
OCF_PL_STEP(ocf_mngt_cache_stop_deinit_metadata),
|
||||||
OCF_PL_STEP(ocf_mngt_cache_stop_put_io_queues),
|
OCF_PL_STEP(ocf_mngt_cache_stop_put_io_queues),
|
||||||
OCF_PL_STEP_TERMINATOR(),
|
OCF_PL_STEP_TERMINATOR(),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static void _ocf_mngt_init_cache_front_volume(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_volume_type_t type;
|
||||||
|
struct ocf_volume_uuid uuid = {
|
||||||
|
.data = cache,
|
||||||
|
.size = sizeof(cache),
|
||||||
|
};
|
||||||
|
int result;
|
||||||
|
|
||||||
|
type = ocf_ctx_get_volume_type_internal(cache->owner, OCF_VOLUME_TYPE_CACHE);
|
||||||
|
if (!type)
|
||||||
|
OCF_PL_FINISH_RET(context->pipeline, -OCF_ERR_INVAL);
|
||||||
|
|
||||||
|
result = ocf_volume_init(&cache->device->front_volume, type, &uuid, false);
|
||||||
|
if (result)
|
||||||
|
OCF_PL_FINISH_RET(context->pipeline, result);
|
||||||
|
cache->device->front_volume.cache = cache;
|
||||||
|
context->flags.front_volume_inited = true;
|
||||||
|
|
||||||
|
result = ocf_volume_open(&cache->device->front_volume, NULL);
|
||||||
|
if (result)
|
||||||
|
OCF_PL_FINISH_RET(context->pipeline, result);
|
||||||
|
context->flags.front_volume_opened = true;
|
||||||
|
|
||||||
|
ocf_pipeline_next(context->pipeline);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _ocf_mngt_load_unsafe_complete(void *priv, int error)
|
||||||
|
{
|
||||||
|
struct ocf_cache_attach_context *context = priv;
|
||||||
|
ocf_cache_t cache = context->cache;
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
ocf_cache_log(cache, log_err,
|
||||||
|
"ERROR: Cannot load metadata\n");
|
||||||
|
OCF_PL_FINISH_RET(context->pipeline,
|
||||||
|
-OCF_ERR_START_CACHE_FAIL);
|
||||||
|
}
|
||||||
|
|
||||||
|
ocf_pipeline_next(context->pipeline);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _ocf_mngt_load_metadata_unsafe(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_cache_log(cache, log_info, "Loading cache state...\n");
|
||||||
|
ocf_metadata_load_unsafe(cache,
|
||||||
|
_ocf_mngt_load_unsafe_complete, context);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _ocf_mngt_bind_init_attached_structures(ocf_pipeline_t pipeline,
|
||||||
|
void *priv, ocf_pipeline_arg_t arg)
|
||||||
|
{
|
||||||
|
struct ocf_cache_attach_context *context = priv;
|
||||||
|
ocf_cache_t cache = context->cache;
|
||||||
|
|
||||||
|
init_attached_data_structures_recovery(cache);
|
||||||
|
|
||||||
|
ocf_pipeline_next(context->pipeline);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _ocf_mngt_bind_post_init(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_unfreeze(&cache->refcnt.metadata);
|
||||||
|
|
||||||
|
ocf_pipeline_next(pipeline);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ocf_pipeline_properties _ocf_mngt_cache_bind_pipeline_properties = {
|
||||||
|
.priv_size = sizeof(struct ocf_cache_attach_context),
|
||||||
|
.finish = _ocf_mngt_cache_attach_finish,
|
||||||
|
.steps = {
|
||||||
|
OCF_PL_STEP(_ocf_mngt_copy_uuid_data),
|
||||||
|
OCF_PL_STEP(_ocf_mngt_init_attached_nonpersistent),
|
||||||
|
OCF_PL_STEP(_ocf_mngt_attach_cache_device),
|
||||||
|
OCF_PL_STEP(_ocf_mngt_init_cache_front_volume),
|
||||||
|
OCF_PL_STEP(_ocf_mngt_init_properties),
|
||||||
|
OCF_PL_STEP(_ocf_mngt_attach_check_ram),
|
||||||
|
OCF_PL_STEP(_ocf_mngt_test_volume),
|
||||||
|
OCF_PL_STEP(_ocf_mngt_attach_prepare_metadata),
|
||||||
|
OCF_PL_STEP(_ocf_mngt_load_metadata_unsafe),
|
||||||
|
OCF_PL_STEP(_ocf_mngt_bind_init_attached_structures),
|
||||||
|
OCF_PL_STEP(_ocf_mngt_bind_post_init),
|
||||||
|
OCF_PL_STEP_TERMINATOR(),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
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,
|
static void _ocf_mngt_cache_attach(ocf_cache_t cache,
|
||||||
struct ocf_mngt_cache_device_config *cfg,
|
struct ocf_mngt_cache_device_config *cfg,
|
||||||
@ -1849,6 +2356,80 @@ static void _ocf_mngt_cache_load(ocf_cache_t cache,
|
|||||||
OCF_PL_NEXT_RET(pipeline);
|
OCF_PL_NEXT_RET(pipeline);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct ocf_pipeline_properties
|
||||||
|
ocf_mngt_cache_stop_passive_pipeline_properties = {
|
||||||
|
.priv_size = sizeof(struct ocf_mngt_cache_stop_context),
|
||||||
|
.finish = ocf_mngt_cache_stop_finish,
|
||||||
|
.steps = {
|
||||||
|
OCF_PL_STEP(ocf_mngt_cache_stop_wait_metadata_io),
|
||||||
|
OCF_PL_STEP(ocf_mngt_cache_stop_deinit_metadata),
|
||||||
|
OCF_PL_STEP(ocf_mngt_cache_stop_put_io_queues),
|
||||||
|
OCF_PL_STEP_TERMINATOR(),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static void _ocf_mngt_cache_bind(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;
|
||||||
|
|
||||||
|
result = ocf_pipeline_create(&pipeline, cache,
|
||||||
|
&_ocf_mngt_cache_bind_pipeline_properties);
|
||||||
|
if (result)
|
||||||
|
OCF_CMPL_RET(cache, priv1, priv2, -OCF_ERR_NO_MEM);
|
||||||
|
|
||||||
|
result = ocf_pipeline_create(&cache->stop_pipeline, cache,
|
||||||
|
&ocf_mngt_cache_stop_passive_pipeline_properties);
|
||||||
|
if (result) {
|
||||||
|
ocf_pipeline_destroy(pipeline);
|
||||||
|
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 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)
|
static int _ocf_mngt_cache_validate_cfg(struct ocf_mngt_cache_config *cfg)
|
||||||
{
|
{
|
||||||
if (!strnlen(cfg->name, OCF_CACHE_NAME_SIZE))
|
if (!strnlen(cfg->name, OCF_CACHE_NAME_SIZE))
|
||||||
@ -1923,8 +2504,6 @@ int ocf_mngt_cache_start(ocf_ctx_t ctx, ocf_cache_t *cache,
|
|||||||
|
|
||||||
result = _ocf_mngt_cache_start(ctx, cache, cfg, priv);
|
result = _ocf_mngt_cache_start(ctx, cache, cfg, priv);
|
||||||
if (!result) {
|
if (!result) {
|
||||||
_ocf_mngt_cache_set_valid(*cache);
|
|
||||||
|
|
||||||
ocf_cache_log(*cache, log_info, "Successfully added\n");
|
ocf_cache_log(*cache, log_info, "Successfully added\n");
|
||||||
ocf_cache_log(*cache, log_info, "Cache mode : %s\n",
|
ocf_cache_log(*cache, log_info, "Cache mode : %s\n",
|
||||||
_ocf_cache_mode_get_name(ocf_cache_get_mode(*cache)));
|
_ocf_cache_mode_get_name(ocf_cache_get_mode(*cache)));
|
||||||
@ -1954,6 +2533,7 @@ static void _ocf_mngt_cache_attach_complete(ocf_cache_t cache, void *priv1,
|
|||||||
ocf_mngt_cache_attach_end_t cmpl = priv1;
|
ocf_mngt_cache_attach_end_t cmpl = priv1;
|
||||||
|
|
||||||
if (!error) {
|
if (!error) {
|
||||||
|
_ocf_mngt_cache_set_valid(cache);
|
||||||
ocf_cache_log(cache, log_info, "Successfully attached\n");
|
ocf_cache_log(cache, log_info, "Successfully attached\n");
|
||||||
} else {
|
} else {
|
||||||
ocf_cache_log(cache, log_err, "Attaching cache device "
|
ocf_cache_log(cache, log_err, "Attaching cache device "
|
||||||
@ -1985,21 +2565,6 @@ void ocf_mngt_cache_attach(ocf_cache_t cache,
|
|||||||
static void _ocf_mngt_cache_unplug_complete(void *priv, int error)
|
static void _ocf_mngt_cache_unplug_complete(void *priv, int error)
|
||||||
{
|
{
|
||||||
struct _ocf_mngt_cache_unplug_context *context = priv;
|
struct _ocf_mngt_cache_unplug_context *context = priv;
|
||||||
ocf_cache_t cache = context->cache;
|
|
||||||
|
|
||||||
ocf_volume_close(&cache->device->volume);
|
|
||||||
|
|
||||||
ocf_metadata_deinit_variable_size(cache);
|
|
||||||
ocf_concurrency_deinit(cache);
|
|
||||||
|
|
||||||
ocf_volume_deinit(&cache->device->volume);
|
|
||||||
|
|
||||||
env_vfree(cache->device);
|
|
||||||
cache->device = NULL;
|
|
||||||
|
|
||||||
/* TODO: this should be removed from detach after 'attached' stats
|
|
||||||
are better separated in statistics */
|
|
||||||
env_atomic_set(&cache->fallback_pt_error_counter, 0);
|
|
||||||
|
|
||||||
context->cmpl(context->priv, error ? -OCF_ERR_WRITE_CACHE : 0);
|
context->cmpl(context->priv, error ? -OCF_ERR_WRITE_CACHE : 0);
|
||||||
}
|
}
|
||||||
@ -2115,6 +2680,96 @@ void ocf_mngt_cache_load(ocf_cache_t cache,
|
|||||||
_ocf_mngt_cache_load(cache, cfg, _ocf_mngt_cache_load_complete, cmpl, priv);
|
_ocf_mngt_cache_load(cache, cfg, _ocf_mngt_cache_load_complete, cmpl, priv);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void _ocf_mngt_cache_bind_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_passive(cache);
|
||||||
|
ocf_cache_log(cache, log_info, "Successfully binded\n");
|
||||||
|
|
||||||
|
OCF_CMPL_RET(cache, priv2, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
int result;
|
||||||
|
|
||||||
|
OCF_CHECK_NULL(cache);
|
||||||
|
OCF_CHECK_NULL(cfg);
|
||||||
|
|
||||||
|
if (!cache->mngt_queue)
|
||||||
|
OCF_CMPL_RET(cache, priv, -OCF_ERR_INVAL);
|
||||||
|
|
||||||
|
/* Bind is not allowed in volatile metadata mode */
|
||||||
|
if (cache->metadata.is_volatile)
|
||||||
|
OCF_CMPL_RET(cache, priv, -OCF_ERR_INVAL);
|
||||||
|
|
||||||
|
/* Bind is not allowed with 'force' flag on */
|
||||||
|
if (cfg->force) {
|
||||||
|
ocf_cache_log(cache, log_err, "Using 'force' flag is forbidden "
|
||||||
|
"for bind 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_bind(cache, cfg, _ocf_mngt_cache_bind_complete,
|
||||||
|
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,
|
static void ocf_mngt_cache_stop_detached(ocf_cache_t cache,
|
||||||
ocf_mngt_cache_stop_end_t cmpl, void *priv)
|
ocf_mngt_cache_stop_end_t cmpl, void *priv)
|
||||||
{
|
{
|
||||||
|
@ -220,7 +220,8 @@ int ocf_mngt_core_init_front_volume(ocf_core_t core)
|
|||||||
};
|
};
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
type = ocf_ctx_get_volume_type(cache->owner, 0);
|
type = ocf_ctx_get_volume_type_internal(cache->owner,
|
||||||
|
OCF_VOLUME_TYPE_CORE);
|
||||||
if (!type)
|
if (!type)
|
||||||
return -OCF_ERR_INVAL;
|
return -OCF_ERR_INVAL;
|
||||||
|
|
||||||
@ -228,6 +229,8 @@ int ocf_mngt_core_init_front_volume(ocf_core_t core)
|
|||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
core->front_volume.cache = cache;
|
||||||
|
|
||||||
ret = ocf_volume_open(&core->front_volume, NULL);
|
ret = ocf_volume_open(&core->front_volume, NULL);
|
||||||
if (ret)
|
if (ret)
|
||||||
ocf_volume_deinit(&core->front_volume);
|
ocf_volume_deinit(&core->front_volume);
|
||||||
|
@ -27,13 +27,18 @@ int ocf_mngt_core_pool_get_count(ocf_ctx_t ctx)
|
|||||||
|
|
||||||
int ocf_mngt_core_pool_add(ocf_ctx_t ctx, ocf_uuid_t uuid, uint8_t type)
|
int ocf_mngt_core_pool_add(ocf_ctx_t ctx, ocf_uuid_t uuid, uint8_t type)
|
||||||
{
|
{
|
||||||
|
ocf_volume_type_t volume_type;
|
||||||
ocf_volume_t volume;
|
ocf_volume_t volume;
|
||||||
|
|
||||||
int result = 0;
|
int result = 0;
|
||||||
|
|
||||||
OCF_CHECK_NULL(ctx);
|
OCF_CHECK_NULL(ctx);
|
||||||
|
|
||||||
result = ocf_ctx_volume_create(ctx, &volume, uuid, type);
|
volume_type = ocf_ctx_get_volume_type(ctx, type);
|
||||||
|
if (!volume_type)
|
||||||
|
return -OCF_ERR_INVAL;
|
||||||
|
|
||||||
|
result = ocf_volume_create(&volume, volume_type, uuid);
|
||||||
if (result)
|
if (result)
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
@ -74,6 +79,8 @@ ocf_volume_t ocf_mngt_core_pool_lookup(ocf_ctx_t ctx, ocf_uuid_t uuid,
|
|||||||
ocf_volume_type_t type)
|
ocf_volume_type_t type)
|
||||||
{
|
{
|
||||||
ocf_volume_t svolume;
|
ocf_volume_t svolume;
|
||||||
|
int result;
|
||||||
|
int cmp;
|
||||||
|
|
||||||
OCF_CHECK_NULL(ctx);
|
OCF_CHECK_NULL(ctx);
|
||||||
OCF_CHECK_NULL(uuid);
|
OCF_CHECK_NULL(uuid);
|
||||||
@ -81,11 +88,16 @@ ocf_volume_t ocf_mngt_core_pool_lookup(ocf_ctx_t ctx, ocf_uuid_t uuid,
|
|||||||
|
|
||||||
list_for_each_entry(svolume, &ctx->core_pool.core_pool_head,
|
list_for_each_entry(svolume, &ctx->core_pool.core_pool_head,
|
||||||
core_pool_item) {
|
core_pool_item) {
|
||||||
if (svolume->type == type && !env_strncmp(svolume->uuid.data,
|
if (svolume->type != type)
|
||||||
svolume->uuid.size, uuid->data, uuid->size)) {
|
continue;
|
||||||
|
|
||||||
|
result = env_memcmp(svolume->uuid.data, svolume->uuid.size,
|
||||||
|
uuid->data, uuid->size, &cmp);
|
||||||
|
if (result || cmp)
|
||||||
|
continue;
|
||||||
|
|
||||||
return svolume;
|
return svolume;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
280
src/ocf_cache.c
280
src/ocf_cache.c
@ -19,9 +19,21 @@ ocf_volume_t ocf_cache_get_volume(ocf_cache_t cache)
|
|||||||
return cache->device ? &cache->device->volume : NULL;
|
return cache->device ? &cache->device->volume : NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ocf_volume_t ocf_cache_get_front_volume(ocf_cache_t cache)
|
||||||
|
{
|
||||||
|
return cache->device ? &cache->device->front_volume : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
int ocf_cache_set_name(ocf_cache_t cache, const char *src, size_t src_size)
|
int ocf_cache_set_name(ocf_cache_t cache, const char *src, size_t src_size)
|
||||||
{
|
{
|
||||||
|
int result;
|
||||||
|
|
||||||
OCF_CHECK_NULL(cache);
|
OCF_CHECK_NULL(cache);
|
||||||
|
|
||||||
|
result = env_strncpy(cache->name, OCF_CACHE_NAME_SIZE, src, src_size);
|
||||||
|
if (result)
|
||||||
|
return result;
|
||||||
|
|
||||||
return env_strncpy(cache->conf_meta->name, OCF_CACHE_NAME_SIZE,
|
return env_strncpy(cache->conf_meta->name, OCF_CACHE_NAME_SIZE,
|
||||||
src, src_size);
|
src, src_size);
|
||||||
}
|
}
|
||||||
@ -29,7 +41,7 @@ int ocf_cache_set_name(ocf_cache_t cache, const char *src, size_t src_size)
|
|||||||
const char *ocf_cache_get_name(ocf_cache_t cache)
|
const char *ocf_cache_get_name(ocf_cache_t cache)
|
||||||
{
|
{
|
||||||
OCF_CHECK_NULL(cache);
|
OCF_CHECK_NULL(cache);
|
||||||
return cache->conf_meta->name;
|
return cache->name;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ocf_cache_is_incomplete(ocf_cache_t cache)
|
bool ocf_cache_is_incomplete(ocf_cache_t cache)
|
||||||
@ -44,10 +56,16 @@ bool ocf_cache_is_running(ocf_cache_t cache)
|
|||||||
return env_bit_test(ocf_cache_state_running, &cache->cache_state);
|
return env_bit_test(ocf_cache_state_running, &cache->cache_state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ocf_cache_is_passive(ocf_cache_t cache)
|
||||||
|
{
|
||||||
|
OCF_CHECK_NULL(cache);
|
||||||
|
return env_bit_test(ocf_cache_state_passive, &cache->cache_state);
|
||||||
|
}
|
||||||
|
|
||||||
bool ocf_cache_is_device_attached(ocf_cache_t cache)
|
bool ocf_cache_is_device_attached(ocf_cache_t cache)
|
||||||
{
|
{
|
||||||
OCF_CHECK_NULL(cache);
|
OCF_CHECK_NULL(cache);
|
||||||
return !ocf_refcnt_frozen(&cache->refcnt.metadata);
|
return !!cache->device;
|
||||||
}
|
}
|
||||||
|
|
||||||
ocf_cache_mode_t ocf_cache_get_mode(ocf_cache_t cache)
|
ocf_cache_mode_t ocf_cache_get_mode(ocf_cache_t cache)
|
||||||
@ -94,6 +112,16 @@ int ocf_cache_get_info(ocf_cache_t cache, struct ocf_cache_info *info)
|
|||||||
cache->device->volume.type);
|
cache->device->volume.type);
|
||||||
info->size = cache->conf_meta->cachelines;
|
info->size = cache->conf_meta->cachelines;
|
||||||
}
|
}
|
||||||
|
info->state = cache->cache_state;
|
||||||
|
info->cache_line_size = ocf_line_size(cache);
|
||||||
|
info->metadata_end_offset = ocf_cache_is_device_attached(cache) ?
|
||||||
|
cache->device->metadata_offset / PAGE_SIZE : 0;
|
||||||
|
info->metadata_footprint = ocf_cache_is_device_attached(cache) ?
|
||||||
|
ocf_metadata_size_of(cache) : 0;
|
||||||
|
|
||||||
|
if (env_bit_test(ocf_cache_state_passive, &cache->cache_state))
|
||||||
|
return 0;
|
||||||
|
|
||||||
info->core_count = cache->conf_meta->core_count;
|
info->core_count = cache->conf_meta->core_count;
|
||||||
|
|
||||||
info->cache_mode = ocf_cache_get_mode(cache);
|
info->cache_mode = ocf_cache_get_mode(cache);
|
||||||
@ -145,10 +173,6 @@ int ocf_cache_get_info(ocf_cache_t cache, struct ocf_cache_info *info)
|
|||||||
info->dirty_initial = initial_dirty_blocks_total;
|
info->dirty_initial = initial_dirty_blocks_total;
|
||||||
info->occupancy = cache_occupancy_total;
|
info->occupancy = cache_occupancy_total;
|
||||||
info->dirty_for = _calc_dirty_for(dirty_since);
|
info->dirty_for = _calc_dirty_for(dirty_since);
|
||||||
info->metadata_end_offset = ocf_cache_is_device_attached(cache) ?
|
|
||||||
cache->device->metadata_offset / PAGE_SIZE : 0;
|
|
||||||
|
|
||||||
info->state = cache->cache_state;
|
|
||||||
|
|
||||||
if (info->attached) {
|
if (info->attached) {
|
||||||
_set(&info->inactive.occupancy,
|
_set(&info->inactive.occupancy,
|
||||||
@ -172,8 +196,6 @@ int ocf_cache_get_info(ocf_cache_t cache, struct ocf_cache_info *info)
|
|||||||
|
|
||||||
info->cleaning_policy = cache->conf_meta->cleaning_policy_type;
|
info->cleaning_policy = cache->conf_meta->cleaning_policy_type;
|
||||||
info->promotion_policy = cache->conf_meta->promotion_policy_type;
|
info->promotion_policy = cache->conf_meta->promotion_policy_type;
|
||||||
info->metadata_footprint = ocf_cache_is_device_attached(cache) ?
|
|
||||||
ocf_metadata_size_of(cache) : 0;
|
|
||||||
info->cache_line_size = ocf_line_size(cache);
|
info->cache_line_size = ocf_line_size(cache);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -231,3 +253,245 @@ void *ocf_cache_get_priv(ocf_cache_t cache)
|
|||||||
OCF_CHECK_NULL(cache);
|
OCF_CHECK_NULL(cache);
|
||||||
return cache->priv;
|
return cache->priv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct ocf_cache_volume_io_priv {
|
||||||
|
struct ocf_io *io;
|
||||||
|
struct ctx_data_t *data;
|
||||||
|
env_atomic remaining;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ocf_cache_volume {
|
||||||
|
ocf_cache_t cache;
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline ocf_cache_t ocf_volume_to_cache(ocf_volume_t volume)
|
||||||
|
{
|
||||||
|
struct ocf_cache_volume *cache_volume = ocf_volume_get_priv(volume);
|
||||||
|
|
||||||
|
return cache_volume->cache;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ocf_cache_volume_io_complete(struct ocf_io *vol_io, int error)
|
||||||
|
{
|
||||||
|
struct ocf_cache_volume_io_priv *priv;
|
||||||
|
struct ocf_io *io = vol_io->priv1;
|
||||||
|
ocf_cache_t cache = ocf_volume_to_cache(ocf_io_get_volume(io));
|
||||||
|
|
||||||
|
priv = ocf_io_get_priv(io);
|
||||||
|
|
||||||
|
if (env_atomic_dec_return(&priv->remaining))
|
||||||
|
return;
|
||||||
|
|
||||||
|
ocf_io_put(vol_io);
|
||||||
|
ocf_io_end(io, error);
|
||||||
|
ocf_refcnt_dec(&cache->refcnt.metadata);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ocf_cache_volume_prepare_vol_io(struct ocf_io *io,
|
||||||
|
struct ocf_io **vol_io)
|
||||||
|
{
|
||||||
|
struct ocf_cache_volume_io_priv *priv;
|
||||||
|
ocf_cache_t cache;
|
||||||
|
struct ocf_io *tmp_io;
|
||||||
|
int result;
|
||||||
|
|
||||||
|
OCF_CHECK_NULL(io);
|
||||||
|
|
||||||
|
priv = ocf_io_get_priv(io);
|
||||||
|
cache = ocf_volume_to_cache(ocf_io_get_volume(io));
|
||||||
|
|
||||||
|
tmp_io = ocf_volume_new_io(ocf_cache_get_volume(cache), io->io_queue,
|
||||||
|
io->addr, io->bytes, io->dir, io->io_class, io->flags);
|
||||||
|
if (!tmp_io)
|
||||||
|
return -OCF_ERR_NO_MEM;
|
||||||
|
|
||||||
|
result = ocf_io_set_data(tmp_io, priv->data, 0);
|
||||||
|
if (result) {
|
||||||
|
ocf_io_put(tmp_io);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
ocf_io_set_cmpl(tmp_io, io, NULL, ocf_cache_volume_io_complete);
|
||||||
|
|
||||||
|
*vol_io = tmp_io;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void ocf_cache_volume_submit_io(struct ocf_io *io)
|
||||||
|
{
|
||||||
|
struct ocf_cache_volume_io_priv *priv;
|
||||||
|
struct ocf_io *vol_io;
|
||||||
|
ocf_cache_t cache;
|
||||||
|
int result;
|
||||||
|
|
||||||
|
cache = ocf_volume_to_cache(ocf_io_get_volume(io));
|
||||||
|
priv = ocf_io_get_priv(io);
|
||||||
|
|
||||||
|
if (!ocf_refcnt_inc(&cache->refcnt.metadata)) {
|
||||||
|
ocf_io_end(io, -OCF_ERR_IO);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
env_atomic_set(&priv->remaining, 2);
|
||||||
|
|
||||||
|
result = ocf_cache_volume_prepare_vol_io(io, &vol_io);
|
||||||
|
if (result) {
|
||||||
|
ocf_io_end(io, result);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ocf_volume_submit_io(vol_io);
|
||||||
|
|
||||||
|
result = ocf_metadata_passive_update(cache, io);
|
||||||
|
if (result) {
|
||||||
|
ocf_cache_log(cache, log_crit,
|
||||||
|
"Metadata update error (error=%d)!\n", result);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (env_atomic_dec_return(&priv->remaining))
|
||||||
|
return;
|
||||||
|
|
||||||
|
ocf_io_put(vol_io);
|
||||||
|
ocf_io_end(io, 0);
|
||||||
|
ocf_refcnt_dec(&cache->refcnt.metadata);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void ocf_cache_volume_submit_flush(struct ocf_io *io)
|
||||||
|
{
|
||||||
|
struct ocf_cache_volume_io_priv *priv;
|
||||||
|
struct ocf_io *vol_io;
|
||||||
|
ocf_cache_t cache;
|
||||||
|
int result;
|
||||||
|
|
||||||
|
cache = ocf_volume_to_cache(ocf_io_get_volume(io));
|
||||||
|
priv = ocf_io_get_priv(io);
|
||||||
|
|
||||||
|
if (!ocf_refcnt_inc(&cache->refcnt.metadata)) {
|
||||||
|
ocf_io_end(io, -OCF_ERR_IO);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
env_atomic_set(&priv->remaining, 1);
|
||||||
|
|
||||||
|
result = ocf_cache_volume_prepare_vol_io(io, &vol_io);
|
||||||
|
if (result) {
|
||||||
|
ocf_io_end(io, result);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ocf_volume_submit_flush(vol_io);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void ocf_cache_volume_submit_discard(struct ocf_io *io)
|
||||||
|
{
|
||||||
|
struct ocf_cache_volume_io_priv *priv;
|
||||||
|
struct ocf_io *vol_io;
|
||||||
|
ocf_cache_t cache;
|
||||||
|
int result;
|
||||||
|
|
||||||
|
cache = ocf_volume_to_cache(ocf_io_get_volume(io));
|
||||||
|
priv = ocf_io_get_priv(io);
|
||||||
|
|
||||||
|
if (!ocf_refcnt_inc(&cache->refcnt.metadata)) {
|
||||||
|
ocf_io_end(io, -OCF_ERR_IO);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
env_atomic_set(&priv->remaining, 1);
|
||||||
|
|
||||||
|
result = ocf_cache_volume_prepare_vol_io(io, &vol_io);
|
||||||
|
if (result) {
|
||||||
|
ocf_io_end(io, result);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ocf_volume_submit_discard(vol_io);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* *** VOLUME OPS *** */
|
||||||
|
|
||||||
|
static int ocf_cache_volume_open(ocf_volume_t volume, void *volume_params)
|
||||||
|
{
|
||||||
|
struct ocf_cache_volume *cache_volume = ocf_volume_get_priv(volume);
|
||||||
|
const struct ocf_volume_uuid *uuid = ocf_volume_get_uuid(volume);
|
||||||
|
ocf_cache_t cache = (ocf_cache_t)uuid->data;
|
||||||
|
|
||||||
|
cache_volume->cache = cache;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ocf_cache_volume_close(ocf_volume_t volume)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned int ocf_cache_volume_get_max_io_size(ocf_volume_t volume)
|
||||||
|
{
|
||||||
|
ocf_cache_t cache = ocf_volume_to_cache(volume);
|
||||||
|
|
||||||
|
return ocf_volume_get_max_io_size(ocf_cache_get_volume(cache));
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint64_t ocf_cache_volume_get_byte_length(ocf_volume_t volume)
|
||||||
|
{
|
||||||
|
ocf_cache_t cache = ocf_volume_to_cache(volume);
|
||||||
|
|
||||||
|
return ocf_volume_get_length(ocf_cache_get_volume(cache));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* *** IO OPS *** */
|
||||||
|
|
||||||
|
static int ocf_cache_io_set_data(struct ocf_io *io,
|
||||||
|
ctx_data_t *data, uint32_t offset)
|
||||||
|
{
|
||||||
|
struct ocf_cache_volume_io_priv *priv = ocf_io_get_priv(io);
|
||||||
|
|
||||||
|
if (!data || offset)
|
||||||
|
return -OCF_ERR_INVAL;
|
||||||
|
|
||||||
|
priv->data = data;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ctx_data_t *ocf_cache_io_get_data(struct ocf_io *io)
|
||||||
|
{
|
||||||
|
struct ocf_cache_volume_io_priv *priv = ocf_io_get_priv(io);
|
||||||
|
|
||||||
|
return priv->data;
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct ocf_volume_properties ocf_cache_volume_properties = {
|
||||||
|
.name = "OCF Cache",
|
||||||
|
.io_priv_size = sizeof(struct ocf_cache_volume_io_priv),
|
||||||
|
.volume_priv_size = sizeof(struct ocf_cache_volume),
|
||||||
|
.caps = {
|
||||||
|
.atomic_writes = 0,
|
||||||
|
},
|
||||||
|
.ops = {
|
||||||
|
.submit_io = ocf_cache_volume_submit_io,
|
||||||
|
.submit_flush = ocf_cache_volume_submit_flush,
|
||||||
|
.submit_discard = ocf_cache_volume_submit_discard,
|
||||||
|
.submit_metadata = NULL,
|
||||||
|
|
||||||
|
.open = ocf_cache_volume_open,
|
||||||
|
.close = ocf_cache_volume_close,
|
||||||
|
.get_max_io_size = ocf_cache_volume_get_max_io_size,
|
||||||
|
.get_length = ocf_cache_volume_get_byte_length,
|
||||||
|
},
|
||||||
|
.io_ops = {
|
||||||
|
.set_data = ocf_cache_io_set_data,
|
||||||
|
.get_data = ocf_cache_io_get_data,
|
||||||
|
},
|
||||||
|
.deinit = NULL,
|
||||||
|
};
|
||||||
|
|
||||||
|
int ocf_cache_volume_type_init(ocf_ctx_t ctx)
|
||||||
|
{
|
||||||
|
return ocf_ctx_register_volume_type_internal(ctx, OCF_VOLUME_TYPE_CACHE,
|
||||||
|
&ocf_cache_volume_properties, NULL);
|
||||||
|
}
|
||||||
|
@ -26,6 +26,7 @@
|
|||||||
|
|
||||||
/* Cache device */
|
/* Cache device */
|
||||||
struct ocf_cache_device {
|
struct ocf_cache_device {
|
||||||
|
struct ocf_volume front_volume;
|
||||||
struct ocf_volume volume;
|
struct ocf_volume volume;
|
||||||
|
|
||||||
/* Hash Table contains contains pointer to the entry in
|
/* Hash Table contains contains pointer to the entry in
|
||||||
@ -51,6 +52,8 @@ struct ocf_cache_device {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct ocf_cache {
|
struct ocf_cache {
|
||||||
|
char name[OCF_CACHE_NAME_SIZE];
|
||||||
|
|
||||||
ocf_ctx_t owner;
|
ocf_ctx_t owner;
|
||||||
|
|
||||||
struct list_head list;
|
struct list_head list;
|
||||||
@ -169,4 +172,6 @@ static inline uint64_t ocf_get_cache_occupancy(ocf_cache_t cache)
|
|||||||
|
|
||||||
int ocf_cache_set_name(ocf_cache_t cache, const char *src, size_t src_size);
|
int ocf_cache_set_name(ocf_cache_t cache, const char *src, size_t src_size);
|
||||||
|
|
||||||
|
int ocf_cache_volume_type_init(ocf_ctx_t ctx);
|
||||||
|
|
||||||
#endif /* __OCF_CACHE_PRIV_H__ */
|
#endif /* __OCF_CACHE_PRIV_H__ */
|
||||||
|
@ -519,7 +519,7 @@ const struct ocf_volume_extended ocf_core_volume_extended = {
|
|||||||
|
|
||||||
int ocf_core_volume_type_init(ocf_ctx_t ctx)
|
int ocf_core_volume_type_init(ocf_ctx_t ctx)
|
||||||
{
|
{
|
||||||
return ocf_ctx_register_volume_type_extended(ctx, 0,
|
return ocf_ctx_register_volume_type_internal(ctx, OCF_VOLUME_TYPE_CORE,
|
||||||
&ocf_core_volume_properties,
|
&ocf_core_volume_properties,
|
||||||
&ocf_core_volume_extended);
|
&ocf_core_volume_extended);
|
||||||
}
|
}
|
||||||
|
@ -10,13 +10,14 @@
|
|||||||
#include "ocf_request.h"
|
#include "ocf_request.h"
|
||||||
#include "ocf_logger_priv.h"
|
#include "ocf_logger_priv.h"
|
||||||
#include "ocf_core_priv.h"
|
#include "ocf_core_priv.h"
|
||||||
|
#include "ocf_cache_priv.h"
|
||||||
#include "mngt/ocf_mngt_core_pool_priv.h"
|
#include "mngt/ocf_mngt_core_pool_priv.h"
|
||||||
#include "metadata/metadata_io.h"
|
#include "metadata/metadata_io.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
int ocf_ctx_register_volume_type_extended(ocf_ctx_t ctx, uint8_t type_id,
|
int ocf_ctx_register_volume_type_internal(ocf_ctx_t ctx, uint8_t type_id,
|
||||||
const struct ocf_volume_properties *properties,
|
const struct ocf_volume_properties *properties,
|
||||||
const struct ocf_volume_extended *extended)
|
const struct ocf_volume_extended *extended)
|
||||||
{
|
{
|
||||||
@ -55,14 +56,17 @@ err:
|
|||||||
int ocf_ctx_register_volume_type(ocf_ctx_t ctx, uint8_t type_id,
|
int ocf_ctx_register_volume_type(ocf_ctx_t ctx, uint8_t type_id,
|
||||||
const struct ocf_volume_properties *properties)
|
const struct ocf_volume_properties *properties)
|
||||||
{
|
{
|
||||||
return ocf_ctx_register_volume_type_extended(ctx, type_id,
|
if (type_id >= OCF_VOLUME_TYPE_MAX_USER)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
return ocf_ctx_register_volume_type_internal(ctx, type_id,
|
||||||
properties, NULL);
|
properties, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
void ocf_ctx_unregister_volume_type(ocf_ctx_t ctx, uint8_t type_id)
|
void ocf_ctx_unregister_volume_type_internal(ocf_ctx_t ctx, uint8_t type_id)
|
||||||
{
|
{
|
||||||
OCF_CHECK_NULL(ctx);
|
OCF_CHECK_NULL(ctx);
|
||||||
|
|
||||||
@ -76,17 +80,42 @@ void ocf_ctx_unregister_volume_type(ocf_ctx_t ctx, uint8_t type_id)
|
|||||||
env_rmutex_unlock(&ctx->lock);
|
env_rmutex_unlock(&ctx->lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ocf_ctx_unregister_volume_type(ocf_ctx_t ctx, uint8_t type_id)
|
||||||
|
{
|
||||||
|
OCF_CHECK_NULL(ctx);
|
||||||
|
|
||||||
|
if (type_id < OCF_VOLUME_TYPE_MAX_USER)
|
||||||
|
ocf_ctx_unregister_volume_type_internal(ctx, type_id);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
ocf_volume_type_t ocf_ctx_get_volume_type(ocf_ctx_t ctx, uint8_t type_id)
|
ocf_volume_type_t ocf_ctx_get_volume_type_internal(ocf_ctx_t ctx,
|
||||||
|
uint8_t type_id)
|
||||||
{
|
{
|
||||||
|
ocf_volume_type_t volume_type;
|
||||||
|
|
||||||
OCF_CHECK_NULL(ctx);
|
OCF_CHECK_NULL(ctx);
|
||||||
|
|
||||||
if (type_id >= OCF_VOLUME_TYPE_MAX)
|
if (type_id >= OCF_VOLUME_TYPE_MAX)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
return ctx->volume_type[type_id];
|
env_rmutex_lock(&ctx->lock);
|
||||||
|
volume_type = ctx->volume_type[type_id];
|
||||||
|
env_rmutex_unlock(&ctx->lock);
|
||||||
|
|
||||||
|
return volume_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
ocf_volume_type_t ocf_ctx_get_volume_type(ocf_ctx_t ctx, uint8_t type_id)
|
||||||
|
{
|
||||||
|
OCF_CHECK_NULL(ctx);
|
||||||
|
|
||||||
|
if (type_id >= OCF_VOLUME_TYPE_MAX_USER)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return ocf_ctx_get_volume_type_internal(ctx, type_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -98,12 +127,14 @@ int ocf_ctx_get_volume_type_id(ocf_ctx_t ctx, ocf_volume_type_t type)
|
|||||||
|
|
||||||
OCF_CHECK_NULL(ctx);
|
OCF_CHECK_NULL(ctx);
|
||||||
|
|
||||||
|
env_rmutex_lock(&ctx->lock);
|
||||||
for (i = 0; i < OCF_VOLUME_TYPE_MAX; ++i) {
|
for (i = 0; i < OCF_VOLUME_TYPE_MAX; ++i) {
|
||||||
if (ctx->volume_type[i] == type)
|
if (ctx->volume_type[i] == type)
|
||||||
return i;
|
break;
|
||||||
}
|
}
|
||||||
|
env_rmutex_unlock(&ctx->lock);
|
||||||
|
|
||||||
return -1;
|
return (i < OCF_VOLUME_TYPE_MAX) ? i : -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -112,12 +143,15 @@ int ocf_ctx_get_volume_type_id(ocf_ctx_t ctx, ocf_volume_type_t type)
|
|||||||
int ocf_ctx_volume_create(ocf_ctx_t ctx, ocf_volume_t *volume,
|
int ocf_ctx_volume_create(ocf_ctx_t ctx, ocf_volume_t *volume,
|
||||||
struct ocf_volume_uuid *uuid, uint8_t type_id)
|
struct ocf_volume_uuid *uuid, uint8_t type_id)
|
||||||
{
|
{
|
||||||
|
ocf_volume_type_t volume_type;
|
||||||
|
|
||||||
OCF_CHECK_NULL(ctx);
|
OCF_CHECK_NULL(ctx);
|
||||||
|
|
||||||
if (type_id >= OCF_VOLUME_TYPE_MAX)
|
volume_type = ocf_ctx_get_volume_type(ctx, type_id);
|
||||||
|
if (!volume_type)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
return ocf_volume_create(volume, ctx->volume_type[type_id], uuid);
|
return ocf_volume_create(volume, volume_type, uuid);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void check_ops_provided(const struct ocf_ctx_ops *ops)
|
static void check_ops_provided(const struct ocf_ctx_ops *ops)
|
||||||
@ -182,6 +216,10 @@ int ocf_ctx_create(ocf_ctx_t *ctx, const struct ocf_ctx_config *cfg)
|
|||||||
if (ret)
|
if (ret)
|
||||||
goto err_utils;
|
goto err_utils;
|
||||||
|
|
||||||
|
ret = ocf_cache_volume_type_init(ocf_ctx);
|
||||||
|
if (ret)
|
||||||
|
goto err_utils;
|
||||||
|
|
||||||
ocf_mngt_core_pool_init(ocf_ctx);
|
ocf_mngt_core_pool_init(ocf_ctx);
|
||||||
|
|
||||||
*ctx = ocf_ctx;
|
*ctx = ocf_ctx;
|
||||||
|
@ -11,7 +11,14 @@
|
|||||||
#include "ocf_logger_priv.h"
|
#include "ocf_logger_priv.h"
|
||||||
#include "ocf_volume_priv.h"
|
#include "ocf_volume_priv.h"
|
||||||
|
|
||||||
#define OCF_VOLUME_TYPE_MAX 8
|
#define OCF_VOLUME_TYPE_CNT_USER 8
|
||||||
|
#define OCF_VOLUME_TYPE_CNT_PRIV 2
|
||||||
|
#define OCF_VOLUME_TYPE_MAX_USER OCF_VOLUME_TYPE_CNT_USER
|
||||||
|
#define OCF_VOLUME_TYPE_MAX \
|
||||||
|
(OCF_VOLUME_TYPE_CNT_USER + OCF_VOLUME_TYPE_CNT_PRIV)
|
||||||
|
|
||||||
|
#define OCF_VOLUME_TYPE_CORE (OCF_VOLUME_TYPE_MAX_USER + 0)
|
||||||
|
#define OCF_VOLUME_TYPE_CACHE (OCF_VOLUME_TYPE_MAX_USER + 1)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief OCF main control structure
|
* @brief OCF main control structure
|
||||||
@ -50,10 +57,15 @@ struct ocf_ctx {
|
|||||||
#define ocf_log_stack_trace(ctx) \
|
#define ocf_log_stack_trace(ctx) \
|
||||||
ocf_log_stack_trace_raw(&ctx->logger)
|
ocf_log_stack_trace_raw(&ctx->logger)
|
||||||
|
|
||||||
int ocf_ctx_register_volume_type_extended(ocf_ctx_t ctx, uint8_t type_id,
|
int ocf_ctx_register_volume_type_internal(ocf_ctx_t ctx, uint8_t type_id,
|
||||||
const struct ocf_volume_properties *properties,
|
const struct ocf_volume_properties *properties,
|
||||||
const struct ocf_volume_extended *extended);
|
const struct ocf_volume_extended *extended);
|
||||||
|
|
||||||
|
void ocf_ctx_unregister_volume_type_internal(ocf_ctx_t ctx, uint8_t type_id);
|
||||||
|
|
||||||
|
ocf_volume_type_t ocf_ctx_get_volume_type_internal(ocf_ctx_t ctx,
|
||||||
|
uint8_t type_id);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @name Environment data buffer operations wrappers
|
* @name Environment data buffer operations wrappers
|
||||||
* @{
|
* @{
|
||||||
|
@ -78,11 +78,6 @@ ocf_io_allocator_type_t ocf_io_allocator_get_type_default(void)
|
|||||||
* IO internal API
|
* IO internal API
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static struct ocf_io_internal *ocf_io_get_internal(struct ocf_io* io)
|
|
||||||
{
|
|
||||||
return container_of(io, struct ocf_io_internal, io);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct ocf_io *ocf_io_new(ocf_volume_t volume, ocf_queue_t queue,
|
struct ocf_io *ocf_io_new(ocf_volume_t volume, ocf_queue_t queue,
|
||||||
uint64_t addr, uint32_t bytes, uint32_t dir,
|
uint64_t addr, uint32_t bytes, uint32_t dir,
|
||||||
uint32_t io_class, uint64_t flags)
|
uint32_t io_class, uint64_t flags)
|
||||||
|
@ -22,6 +22,11 @@ struct ocf_io_internal {
|
|||||||
struct ocf_io io;
|
struct ocf_io io;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static inline struct ocf_io_internal *ocf_io_get_internal(struct ocf_io* io)
|
||||||
|
{
|
||||||
|
return container_of(io, struct ocf_io_internal, io);
|
||||||
|
}
|
||||||
|
|
||||||
int ocf_io_allocator_init(ocf_io_allocator_t allocator, ocf_io_allocator_type_t type,
|
int ocf_io_allocator_init(ocf_io_allocator_t allocator, ocf_io_allocator_type_t type,
|
||||||
uint32_t priv_size, const char *name);
|
uint32_t priv_size, const char *name);
|
||||||
|
|
||||||
|
@ -49,6 +49,9 @@ class OcfErrorCode(IntEnum):
|
|||||||
OCF_ERR_INVALID_CACHE_LINE_SIZE = auto()
|
OCF_ERR_INVALID_CACHE_LINE_SIZE = auto()
|
||||||
OCF_ERR_CACHE_NAME_MISMATCH = auto()
|
OCF_ERR_CACHE_NAME_MISMATCH = auto()
|
||||||
OCF_ERR_INVAL_CACHE_DEV = auto()
|
OCF_ERR_INVAL_CACHE_DEV = auto()
|
||||||
|
OCF_ERR_CORE_UUID_EXISTS = auto()
|
||||||
|
OCF_ERR_METADATA_LAYOUT_MISMATCH = auto()
|
||||||
|
OCF_ERR_CACHE_LINE_SIZE_MISMATCH = auto()
|
||||||
|
|
||||||
|
|
||||||
class OcfCompletion:
|
class OcfCompletion:
|
||||||
|
Loading…
Reference in New Issue
Block a user