Merge pull request #557 from robertbaldyga/cache-passive-state

Introduce cache passive state
This commit is contained in:
Robert Baldyga 2021-09-07 14:50:40 +02:00 committed by GitHub
commit fd4400476e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 1666 additions and 416 deletions

View File

@ -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
* *

View File

@ -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;

View File

@ -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__ */

View File

@ -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 */
/** /**

View File

@ -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_metadata_end_exclusive_access(&cache->metadata.lock); ocf_cache_log(cache, log_info, "Done loading cache state\n");
out:
context->cmpl(context->priv, error);
ocf_pipeline_destroy(pipeline);
}
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;
}

View File

@ -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_ */

View File

@ -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,

View File

@ -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)
* *

View File

@ -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;
} }

View File

@ -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

View File

@ -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
*/ */

View File

@ -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
*/ */

View File

@ -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);
}

View File

@ -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_ */

View File

@ -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,8 +245,10 @@ 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)
{ {
ocf_promotion_deinit(cache->promotion_policy); if (cache->promotion_policy) {
cache->promotion_policy = NULL; ocf_promotion_deinit(cache->promotion_policy);
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,18 +642,14 @@ 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);
}
} }
/** /**
@ -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)
{ {

View File

@ -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);

View File

@ -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,10 +88,15 @@ 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;
return svolume;
} result = env_memcmp(svolume->uuid.data, svolume->uuid.size,
uuid->data, uuid->size, &cmp);
if (result || cmp)
continue;
return svolume;
} }
return NULL; return NULL;

View File

@ -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);
}

View File

@ -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__ */

View File

@ -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);
} }

View File

@ -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;

View File

@ -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
* @{ * @{

View File

@ -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)

View File

@ -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);

View File

@ -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: