diff --git a/src/metadata/metadata.c b/src/metadata/metadata.c index 911a7aa..ab33ee7 100644 --- a/src/metadata/metadata.c +++ b/src/metadata/metadata.c @@ -1617,102 +1617,6 @@ void ocf_metadata_error(struct ocf_cache *cache) 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( struct ocf_metadata_read_sb_ctx *context) { @@ -1721,41 +1625,11 @@ static void ocf_metadata_load_properties_cmpl( ocf_metadata_load_properties_end_t cmpl = context->priv1; void *priv = context->priv2; ocf_ctx_t ctx = context->ctx; + int result; - if (superblock->magic_number != CACHE_MAGIC_NUMBER) { - ocf_log(ctx, log_info, "Cannot detect pre-existing metadata\n"); - OCF_CMPL_RET(priv, -OCF_ERR_NO_METADATA, 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); - } + result = ocf_metadata_validate_superblock(ctx, superblock); + if (result) + OCF_CMPL_RET(priv, result, NULL); properties.line_size = superblock->line_size; properties.layout = superblock->metadata_layout; diff --git a/src/metadata/metadata_superblock.c b/src/metadata/metadata_superblock.c index 00ebb5b..f0f5a14 100644 --- a/src/metadata/metadata_superblock.c +++ b/src/metadata/metadata_superblock.c @@ -10,6 +10,7 @@ #include "metadata_superblock.h" #include "../ocf_priv.h" #include "../utils/utils_io.h" +#include "../utils/utils_cache_line.h" #define OCF_METADATA_SUPERBLOCK_DEBUG 0 @@ -503,3 +504,170 @@ bool ocf_metadata_superblock_get_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); +} diff --git a/src/metadata/metadata_superblock.h b/src/metadata/metadata_superblock.h index 4602b3b..290bb24 100644 --- a/src/metadata/metadata_superblock.h +++ b/src/metadata/metadata_superblock.h @@ -97,4 +97,27 @@ void ocf_metadata_superblock_set_checksum( bool ocf_metadata_superblock_get_clean_shutdown( 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_ */