Expose superblock operations as part of internal metadata API

Signed-off-by: Robert Baldyga <robert.baldyga@intel.com>
This commit is contained in:
Robert Baldyga 2021-08-30 14:58:57 +02:00
parent ab034ab53d
commit 9ab4c51dfa
3 changed files with 195 additions and 130 deletions

View File

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

View File

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

View File

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