diff --git a/inc/ocf_metadata.h b/inc/ocf_metadata.h index f9f645e..95bc83e 100644 --- a/inc/ocf_metadata.h +++ b/inc/ocf_metadata.h @@ -51,20 +51,37 @@ struct ocf_atomic_metadata { int ocf_metadata_get_atomic_entry(ocf_cache_t cache, uint64_t addr, struct ocf_atomic_metadata *entry); +/** + * @brief Metadata probe status + */ +struct ocf_metadata_probe_status { + /** Cache was graceful stopped */ + bool clean_shutdown; + + /** Cache contains dirty data */ + bool cache_dirty; +}; + +/** + * @brief Metadata probe completion callback + * + * @param[in] priv Completion context + * @param[in] error Error code (zero on success) + * @param[in] status Structure describing metadata probe status + */ +typedef void (*ocf_metadata_probe_end_t)(void *priv, int error, + struct ocf_metadata_probe_status *status); + /** * @brief Probe cache device * * @param[in] ctx handle to object designating ocf context - * @param[in] cache_volume Cache volume - * @param[out] clean_shutdown Cache was graceful stopped - * @param[out] cache_dirty Cache is dirty - * - * @retval 0 Probe successfully performed - * @retval -ENODATA Cache has not been detected - * @retval Non-zero ERROR + * @param[in] volume Cache volume + * @param[in] cmpl Completion callback + * @param[in] priv Completion context */ -int ocf_metadata_probe(ocf_ctx_t ctx, ocf_volume_t cache_volume, - bool *clean_shutdown, bool *cache_dirty); +void ocf_metadata_probe(ocf_ctx_t ctx, ocf_volume_t volume, + ocf_metadata_probe_end_t cmpl, void *priv); /** * @brief Check if sectors in cache line before given address are invalid diff --git a/src/metadata/metadata.c b/src/metadata/metadata.c index 7d4ee8d..df468f9 100644 --- a/src/metadata/metadata.c +++ b/src/metadata/metadata.c @@ -152,58 +152,74 @@ void ocf_metadata_flush_do_asynch(struct ocf_cache *cache, cache->metadata.iface.flush_do_asynch(cache, req, complete); } -static inline int ocf_metadata_check_properties(void) +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) { - uint32_t field_offset; + struct ocf_metadata_read_sb_ctx *context = io->priv1; + ctx_data_t *data = ocf_io_get_data(io); - /* Because metadata basic properties are on the beginning of super block - * read/write only first page of supper block. - * - * For safety reason check if offset of metadata properties are in first - * page of super block. - * - * Maybe in future super block fields order may be changed and metadata - * variant may go out first page of super block - */ + if (!error) { + /* Read data from data into super block buffer */ + ctx_data_rd_check(context->ctx, &context->superblock, data, + sizeof(context->superblock)); + } - field_offset = offsetof(struct ocf_superblock_config, line_size); - ENV_BUG_ON(field_offset >= PAGE_SIZE); - /* The same checking for magic number */ - field_offset = offsetof(struct ocf_superblock_config, magic_number); - ENV_BUG_ON(field_offset >= PAGE_SIZE); + context->error = error; + context->cmpl(context); - /* The same checking for IO interface type */ - field_offset = offsetof(struct ocf_superblock_config, cache_mode); - ENV_BUG_ON(field_offset >= PAGE_SIZE); - - /* And the same for version location within superblock structure */ - field_offset = offsetof(struct ocf_superblock_config, metadata_version); - ENV_BUG_ON(field_offset >= PAGE_SIZE); - - return 0; + ctx_data_free(context->ctx, data); + ocf_io_put(io); + env_free(context); } -static int ocf_metadata_read_properties(ocf_ctx_t ctx, - ocf_volume_t cache_volume, - struct ocf_superblock_config *superblock) +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; - if (ocf_metadata_check_properties()) - return -EINVAL; + /* 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 -ENOMEM; + } + + context->cmpl = cmpl; + context->ctx = ctx; + context->priv1 = priv1; + context->priv2 = priv2; /* Allocate resources for IO */ - io = ocf_volume_new_io(cache_volume); - data = ctx_data_alloc(ctx, 1); - - /* Check allocation result */ - if (!io || !data) { + io = ocf_volume_new_io(volume); + if (!io) { ocf_log(ctx, log_err, "Memory allocation error"); result = -ENOMEM; - goto out; + goto err_io; + } + + data = ctx_data_alloc(ctx, sb_pages); + if (!data) { + ocf_log(ctx, log_err, "Memory allocation error"); + result = -ENOMEM; + goto err_data; } /* @@ -214,176 +230,142 @@ static int ocf_metadata_read_properties(ocf_ctx_t ctx, if (result) { ocf_log(ctx, log_err, "Metadata IO configuration error\n"); result = -EIO; - goto out; - } - ocf_io_configure(io, 0, PAGE_SIZE, OCF_READ, 0, 0); - result = ocf_submit_io_wait(io); - if (result) { - ocf_log(ctx, log_err, "Metadata IO request submit error\n"); - result = -EIO; - goto out; + goto err_set_data; } - /* Read data from data into super block buffer */ - ctx_data_rd_check(ctx, superblock, data, - PAGE_SIZE); + ocf_io_configure(io, 0, sb_pages * PAGE_SIZE, OCF_READ, 0, 0); -out: - if (io) - ocf_io_put(io); + 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; } -/** - * @brief function loads individual properties from metadata set - * @param cache_volume volume from which to load metadata - * @param variant - field to which save metadata variant; if NULL, - * metadata variant won't be read. - * @param cache mode; if NULL is passed it won't be read - * @param shutdown_status - dirty shutdown or clean shutdown - * @param dirty_flushed - if all dirty data was flushed prior to closing - * the cache - * @return 0 upon successful completion - */ -int ocf_metadata_load_properties(ocf_volume_t cache_volume, - ocf_cache_line_size_t *line_size, - ocf_metadata_layout_t *layout, - ocf_cache_mode_t *cache_mode, - enum ocf_metadata_shutdown_status *shutdown_status, - uint8_t *dirty_flushed) +static void ocf_metadata_load_properties_cmpl( + struct ocf_metadata_read_sb_ctx *context) { - struct ocf_superblock_config *superblock; - int err_value = 0; - - /* Allocate first page of super block */ - superblock = env_zalloc(PAGE_SIZE, ENV_MEM_NORMAL); - if (!superblock) { - ocf_cache_log(cache_volume->cache, log_err, - "Allocation memory error"); - return -ENOMEM; - } - - OCF_DEBUG_TRACE(cache); - - err_value = ocf_metadata_read_properties(cache_volume->cache->owner, - cache_volume, superblock); - if (err_value) - goto ocf_metadata_load_variant_ERROR; + struct ocf_metadata_load_properties properties; + struct ocf_superblock_config *superblock = &context->superblock; + ocf_metadata_load_properties_end_t cmpl = context->priv1; + void *priv = context->priv2; + ocf_ctx_t ctx = context->ctx; if (superblock->magic_number != CACHE_MAGIC_NUMBER) { - err_value = -ENODATA; - ocf_cache_log(cache_volume->cache, log_info, - "Can not detect pre-existing metadata\n"); - goto ocf_metadata_load_variant_ERROR; + ocf_log(ctx, log_info, "Cannot detect pre-existing metadata\n"); + cmpl(priv, -ENODATA, NULL); + return; } if (METADATA_VERSION() != superblock->metadata_version) { - err_value = -EBADF; - ocf_cache_log(cache_volume->cache, log_err, - "Metadata version mismatch!\n"); - goto ocf_metadata_load_variant_ERROR; + ocf_log(ctx, log_err, "Metadata version mismatch!\n"); + cmpl(priv, -EBADF, NULL); + return; } - if (line_size) { - if (ocf_cache_line_size_is_valid(superblock->line_size)) { - *line_size = superblock->line_size; - } else { - err_value = -EINVAL; - ocf_cache_log(cache_volume->cache, log_err, - "ERROR: Invalid cache line size!\n"); - } + if (!ocf_cache_line_size_is_valid(superblock->line_size)) { + ocf_log(ctx, log_err, "ERROR: Invalid cache line size!\n"); + cmpl(priv, -EINVAL, NULL); + return; } - if (layout) { - if (superblock->metadata_layout >= ocf_metadata_layout_max || - superblock->metadata_layout < 0) { - err_value = -EINVAL; - ocf_cache_log(cache_volume->cache, log_err, - "ERROR: Invalid metadata layout!\n"); - } else { - *layout = superblock->metadata_layout; - } + if ((unsigned)superblock->metadata_layout >= ocf_metadata_layout_max) { + ocf_log(ctx, log_err, "ERROR: Invalid metadata layout!\n"); + cmpl(priv, -EINVAL, NULL); + return; } - if (cache_mode) { - if (superblock->cache_mode < ocf_cache_mode_max) { - *cache_mode = superblock->cache_mode; - } else { - ocf_cache_log(cache_volume->cache, log_err, - "ERROR: Invalid cache mode!\n"); - err_value = -EINVAL; - } + if (superblock->cache_mode >= ocf_cache_mode_max) { + ocf_log(ctx, log_err, "ERROR: Invalid cache mode!\n"); + cmpl(priv, -EINVAL, NULL); + return; } - if (shutdown_status != NULL) { - if (superblock->clean_shutdown <= ocf_metadata_clean_shutdown) { - *shutdown_status = superblock->clean_shutdown; - } else { - ocf_cache_log(cache_volume->cache, log_err, - "ERROR: Invalid shutdown status!\n"); - err_value = -EINVAL; - } + if (superblock->clean_shutdown > ocf_metadata_clean_shutdown) { + ocf_log(ctx, log_err, "ERROR: Invalid shutdown status!\n"); + cmpl(priv, -EINVAL, NULL); + return; } - if (dirty_flushed != NULL) { - if (superblock->dirty_flushed <= DIRTY_FLUSHED) { - *dirty_flushed = superblock->dirty_flushed; - } else { - ocf_cache_log(cache_volume->cache, log_err, - "ERROR: Invalid flush status!\n"); - err_value = -EINVAL; - } + if (superblock->dirty_flushed > DIRTY_FLUSHED) { + ocf_log(ctx, log_err, "ERROR: Invalid flush status!\n"); + cmpl(priv, -EINVAL, NULL); + return; } -ocf_metadata_load_variant_ERROR: + properties.line_size = superblock->line_size; + properties.layout = superblock->metadata_layout; + properties.cache_mode = superblock->cache_mode; + properties.shutdown_status = superblock->clean_shutdown; + properties.dirty_flushed = superblock->dirty_flushed; - env_free(superblock); - return err_value; + cmpl(priv, 0, &properties); } -int ocf_metadata_probe(ocf_ctx_t ctx, ocf_volume_t cache_volume, - bool *clean_shutdown, bool *cache_dirty) +void ocf_metadata_load_properties(ocf_volume_t volume, + ocf_metadata_load_properties_end_t cmpl, void *priv) { - struct ocf_superblock_config *superblock; - int result = 0; - - OCF_CHECK_NULL(ctx); - OCF_CHECK_NULL(cache_volume); - - /* Allocate first page of super block */ - superblock = env_zalloc(PAGE_SIZE, ENV_MEM_NORMAL); - if (!superblock) { - ocf_log(ctx, log_err, "Allocation memory error"); - return -ENOMEM; - } + int result; OCF_DEBUG_TRACE(cache); - result = ocf_metadata_read_properties(ctx, cache_volume, superblock); + result = ocf_metadata_read_sb(volume->cache->owner, volume, + ocf_metadata_load_properties_cmpl, cmpl, priv); if (result) - goto ocf_metadata_probe_END; - - if (superblock->magic_number != CACHE_MAGIC_NUMBER) { - result = -ENODATA; - goto ocf_metadata_probe_END; - } - - if (clean_shutdown != NULL) { - *clean_shutdown = (superblock->clean_shutdown != - ocf_metadata_dirty_shutdown); - } - - if (cache_dirty != NULL) - *cache_dirty = (superblock->dirty_flushed == DIRTY_NOT_FLUSHED); - - if (METADATA_VERSION() != superblock->metadata_version) - result = -EBADF; - -ocf_metadata_probe_END: - - env_free(superblock); - return result; + cmpl(priv, result, NULL); } +static void ocf_metadata_probe_cmpl(struct ocf_metadata_read_sb_ctx *context) +{ + struct ocf_metadata_probe_status status; + struct ocf_superblock_config *superblock = &context->superblock; + ocf_metadata_probe_end_t cmpl = context->priv1; + void *priv = context->priv2; + + if (superblock->magic_number != CACHE_MAGIC_NUMBER) { + cmpl(priv, -ENODATA, NULL); + return; + } + + if (METADATA_VERSION() != superblock->metadata_version) { + cmpl(priv, -EBADF, NULL); + return; + } + + if (superblock->clean_shutdown > ocf_metadata_clean_shutdown) { + cmpl(priv, -EINVAL, NULL); + return; + } + + if (superblock->dirty_flushed > DIRTY_FLUSHED) { + cmpl(priv, -EINVAL, NULL); + return; + } + + status.clean_shutdown = (superblock->clean_shutdown != + ocf_metadata_dirty_shutdown); + status.cache_dirty = (superblock->dirty_flushed == DIRTY_NOT_FLUSHED); + + cmpl(priv, 0, &status); +} + +void ocf_metadata_probe(ocf_ctx_t ctx, ocf_volume_t volume, + ocf_metadata_probe_end_t cmpl, void *priv) +{ + int result; + + OCF_CHECK_NULL(ctx); + OCF_CHECK_NULL(volume); + + result = ocf_metadata_read_sb(ctx, volume, ocf_metadata_probe_cmpl, + cmpl, priv); + if (result) + cmpl(priv, result, NULL); +} diff --git a/src/metadata/metadata.h b/src/metadata/metadata.h index 53ee0df..6126452 100644 --- a/src/metadata/metadata.h +++ b/src/metadata/metadata.h @@ -306,12 +306,19 @@ static inline ocf_cache_line_t ocf_metadata_entries_hash( return cache->metadata.iface.entries_hash(cache); } -int ocf_metadata_load_properties(ocf_volume_t cache_volume, - ocf_cache_line_size_t *line_size, - ocf_metadata_layout_t *layout, - ocf_cache_mode_t *cache_mode, - enum ocf_metadata_shutdown_status *shutdown_status, - uint8_t *dirty_flushed); +struct ocf_metadata_load_properties { + enum ocf_metadata_shutdown_status shutdown_status; + uint8_t dirty_flushed; + ocf_metadata_layout_t layout; + ocf_cache_line_size_t line_size; + ocf_cache_mode_t cache_mode; +}; + +typedef void (*ocf_metadata_load_properties_end_t)(void *priv, int error, + struct ocf_metadata_load_properties *properties); + +void ocf_metadata_load_properties(ocf_volume_t volume, + ocf_metadata_load_properties_end_t cmpl, void *priv); /** * @brief Validate cache line size diff --git a/src/mngt/ocf_mngt_cache.c b/src/mngt/ocf_mngt_cache.c index f2fc0ca..2a9e58c 100644 --- a/src/mngt/ocf_mngt_cache.c +++ b/src/mngt/ocf_mngt_cache.c @@ -863,57 +863,75 @@ end: return ret; } +struct _ocf_mngt_load_properties_context { + struct ocf_cachemng_attach_params *params; + env_completion complete; +}; + +static void _ocf_mngt_load_properties_end(void *priv, int error, + struct ocf_metadata_load_properties *properties) +{ + struct _ocf_mngt_load_properties_context *context = priv; + struct ocf_cachemng_attach_params *params = context->params; + ocf_cache_t cache = params->cache; + + if (error) + goto out; + + params->metadata.shutdown_status = properties->shutdown_status; + params->metadata.dirty_flushed = properties->shutdown_status; + + if (cache->device->init_mode == ocf_init_mode_load) { + params->metadata.line_size = properties->line_size; + cache->conf_meta->metadata_layout = properties->layout; + cache->conf_meta->cache_mode = properties->cache_mode; + } + +out: + params->metadata.status = error; + env_completion_complete(&context->complete); +} + /** * Prepare metadata accordingly to mode (for load/recovery read from disk) */ static int _ocf_mngt_init_prepare_metadata( - struct ocf_cachemng_attach_params *attach_params) + struct ocf_cachemng_attach_params *params) { - int ret; - int i; - ocf_cache_t cache = attach_params->cache; - ocf_cache_line_size_t line_size = attach_params->metadata.line_size ? - attach_params->metadata.line_size : - cache->metadata.settings.size; + struct _ocf_mngt_load_properties_context context; + ocf_cache_t cache = params->cache; + int ret, i; + + context.params = params; + env_completion_init(&context.complete); OCF_ASSERT_PLUGGED(cache); if (cache->device->init_mode != ocf_init_mode_metadata_volatile) { - if (cache->device->init_mode == ocf_init_mode_load) { - attach_params->metadata.status = ocf_metadata_load_properties( - &cache->device->volume, - &line_size, - &cache->conf_meta->metadata_layout, - &cache->conf_meta->cache_mode, - &attach_params->metadata.shutdown_status, - &attach_params->metadata.dirty_flushed); - if (attach_params->metadata.status) { - ret = -OCF_ERR_START_CACHE_FAIL; - return ret; - } - } else { - attach_params->metadata.status = ocf_metadata_load_properties( - &cache->device->volume, - NULL, NULL, NULL, - &attach_params->metadata.shutdown_status, - &attach_params->metadata.dirty_flushed); - /* don't handle result; if no valid metadata is present - * on caching device, we are about to use, it's not an issue - */ + ocf_metadata_load_properties(&cache->device->volume, + _ocf_mngt_load_properties_end, &context); + + env_completion_wait(&context.complete); + if (params->load && params->metadata.status) { + ret = -OCF_ERR_START_CACHE_FAIL; + return ret; } } + params->metadata.line_size = params->metadata.line_size ?: + cache->metadata.settings.size; + /* * Initialize variable size metadata segments */ - if (ocf_metadata_init_variable_size(cache, attach_params->device_size, - line_size, + if (ocf_metadata_init_variable_size(cache, params->device_size, + params->metadata.line_size, cache->conf_meta->metadata_layout)) { return -OCF_ERR_START_CACHE_FAIL; } ocf_cache_log(cache, log_debug, "Cache attached\n"); - attach_params->flags.attached_metadata_inited = true; + params->flags.attached_metadata_inited = true; for (i = 0; i < OCF_IO_CLASS_MAX + 1; ++i) { cache->user_parts[i].runtime = @@ -924,7 +942,7 @@ static int _ocf_mngt_init_prepare_metadata( ret = ocf_concurrency_init(cache); if (!ret) - attach_params->flags.concurrency_inited = 1; + params->flags.concurrency_inited = 1; return ret; } diff --git a/src/utils/utils_io.c b/src/utils/utils_io.c index 6535ffa..05f3e61 100644 --- a/src/utils/utils_io.c +++ b/src/utils/utils_io.c @@ -56,7 +56,6 @@ int ocf_submit_volume_flush_wait(ocf_volume_t volume) env_completion_wait(&cntx.complete); return cntx.error; - } static void ocf_submit_volume_discard_wait_io(struct ocf_io *io, int error)