Explicitly validate superblock after load

Signed-off-by: Adam Rutkowski <adam.j.rutkowski@intel.com>

Additional changes - load sb recovery CRC check

Signed-off-by: Krzysztof Majzerowicz-Jaszcz <krzysztof.majzerowicz-jaszcz@intel.com>
This commit is contained in:
Adam Rutkowski 2022-01-24 15:31:06 +01:00 committed by Krzysztof Majzerowicz-Jaszcz
parent 90ff4afcda
commit 866bba72bf
7 changed files with 124 additions and 93 deletions

View File

@ -83,7 +83,7 @@
/**
* Maximum value of a valid core sequence number
*/
#define OCF_SEQ_NO_MAX (65535UL)
#define OCF_SEQ_NO_MAX ((1ULL << (sizeof(ocf_core_id_t) * 8)) - 1)
/*
* Invalid value of core sequence number
*/

View File

@ -286,3 +286,10 @@ void ocf_engine_hndl_ops_req(struct ocf_request *req)
ocf_engine_push_req_back(req, true);
}
bool ocf_req_cache_mode_has_lazy_write(ocf_req_cache_mode_t mode)
{
return ocf_cache_mode_is_valid((ocf_cache_mode_t)mode) &&
ocf_mngt_cache_mode_has_lazy_write(
(ocf_cache_mode_t)mode);
}

View File

@ -52,17 +52,7 @@ static inline const char *ocf_get_io_iface_name(ocf_cache_mode_t cache_mode)
return iface ? iface->name : "Unknown";
}
static inline bool ocf_cache_mode_is_valid(ocf_cache_mode_t mode)
{
return mode >= ocf_cache_mode_wt && mode < ocf_cache_mode_max;
}
static inline bool ocf_req_cache_mode_has_lazy_write(ocf_req_cache_mode_t mode)
{
return ocf_cache_mode_is_valid((ocf_cache_mode_t)mode) &&
ocf_mngt_cache_mode_has_lazy_write(
(ocf_cache_mode_t)mode);
}
bool ocf_req_cache_mode_has_lazy_write(ocf_req_cache_mode_t mode);
bool ocf_fallback_pt_is_on(ocf_cache_t cache);

View File

@ -1609,6 +1609,16 @@ void ocf_metadata_error(struct ocf_cache *cache)
cache->device->metadata_error = -1;
}
typedef void (*ocf_metadata_read_sb_end_t)(
struct ocf_metadata_read_sb_ctx *context);
struct ocf_metadata_load_properties_ctx
{
ocf_cache_t cache;
ocf_metadata_load_properties_end_t cmpl;
void *priv;
};
static void ocf_metadata_load_properties_cmpl(
struct ocf_metadata_read_sb_ctx *context)
{

View File

@ -98,55 +98,115 @@ static void ocf_metadata_store_segment(ocf_pipeline_t pipeline,
ocf_pipeline_next(pipeline);
}
static void ocf_metadata_check_crc_sb_config(ocf_pipeline_t pipeline,
void *priv, ocf_pipeline_arg_t arg)
#define ocf_log_invalid_superblock(param) \
ocf_log(ctx, log_err, \
"Loading %s: invalid %s\n", \
ocf_metadata_segment_names[ \
metadata_segment_sb_config], \
param);
int ocf_metadata_validate_superblock(ocf_ctx_t ctx,
struct ocf_superblock_config *superblock)
{
struct ocf_metadata_context *context = priv;
struct ocf_metadata_ctrl *ctrl;
struct ocf_superblock_config *sb_config;
ocf_cache_t cache = context->cache;
int segment = metadata_segment_sb_config;
uint32_t crc;
ctrl = (struct ocf_metadata_ctrl *)cache->metadata.priv;
sb_config = METADATA_MEM_POOL(ctrl, metadata_segment_sb_config);
crc = env_crc32(0, (void *)sb_config,
offsetof(struct ocf_superblock_config, checksum));
if (crc != sb_config->checksum[segment]) {
/* Checksum does not match */
ocf_cache_log(cache, log_err,
"Loading %s ERROR, invalid checksum\n",
ocf_metadata_segment_names[segment]);
OCF_PL_FINISH_RET(pipeline, -OCF_ERR_INVAL);
if (superblock->magic_number != CACHE_MAGIC_NUMBER) {
ocf_log(ctx, log_info, "Cannot detect pre-existing metadata\n");
return -OCF_ERR_NO_METADATA;
}
ocf_pipeline_next(pipeline);
if (METADATA_VERSION() != superblock->metadata_version) {
ocf_log(ctx, log_err, "Metadata version mismatch!\n");
return -OCF_ERR_METADATA_VER;
}
crc = env_crc32(0, (void *)superblock,
offsetof(struct ocf_superblock_config, checksum));
if (crc != superblock->checksum[metadata_segment_sb_config]) {
ocf_log_invalid_superblock("checksum");
return -OCF_ERR_INVAL;
}
if (superblock->clean_shutdown > ocf_metadata_clean_shutdown) {
ocf_log_invalid_superblock("shutdown status");
return -OCF_ERR_INVAL;
}
if (superblock->dirty_flushed > DIRTY_FLUSHED) {
ocf_log_invalid_superblock("flush status");
return -OCF_ERR_INVAL;
}
if (superblock->flapping_idx > 1) {
ocf_log_invalid_superblock("flapping index");
return -OCF_ERR_INVAL;
}
if (superblock->cache_mode < 0 ||
superblock->cache_mode >= ocf_cache_mode_max) {
ocf_log_invalid_superblock("cache mode");
return -OCF_ERR_INVAL;
}
if (env_strnlen(superblock->name, sizeof(superblock->name)) >=
OCF_CACHE_NAME_SIZE) {
ocf_log_invalid_superblock("name");
return -OCF_ERR_INVAL;
}
if (superblock->valid_parts_no > OCF_USER_IO_CLASS_MAX) {
ocf_log_invalid_superblock("partition count");
return -OCF_ERR_INVAL;
}
if (!ocf_cache_line_size_is_valid(superblock->line_size)) {
ocf_log_invalid_superblock("cache line size");
return -OCF_ERR_INVAL;
}
if ((unsigned)superblock->metadata_layout >= ocf_metadata_layout_max) {
ocf_log_invalid_superblock("metadata layout");
return -OCF_ERR_INVAL;
}
if (superblock->core_count > OCF_CORE_MAX) {
ocf_log_invalid_superblock("core count");
return -OCF_ERR_INVAL;
}
if (superblock->cleaning_policy_type < 0 ||
superblock->cleaning_policy_type >= ocf_cleaning_max) {
ocf_log_invalid_superblock("cleaning policy");
return -OCF_ERR_INVAL;
}
if (superblock->promotion_policy_type < 0 ||
superblock->promotion_policy_type >=
ocf_promotion_max) {
ocf_log_invalid_superblock("promotion policy");
return -OCF_ERR_INVAL;
}
return 0;
}
static void ocf_metadata_load_superblock_post(ocf_pipeline_t pipeline,
static void _ocf_metadata_validate_superblock(ocf_pipeline_t pipeline,
void *priv, ocf_pipeline_arg_t arg)
{
struct ocf_metadata_context *context = priv;
struct ocf_metadata_ctrl *ctrl;
struct ocf_superblock_config *sb_config;
ocf_cache_t cache = context->cache;
struct ocf_superblock_config *superblock;
int ret;
ctrl = (struct ocf_metadata_ctrl *)cache->metadata.priv;
sb_config = METADATA_MEM_POOL(ctrl, metadata_segment_sb_config);
ctrl = (struct ocf_metadata_ctrl *)context->ctrl;
superblock = METADATA_MEM_POOL(ctrl, metadata_segment_sb_config);
if (sb_config->core_count > OCF_CORE_MAX) {
ocf_cache_log(cache, log_err,
"Loading cache state ERROR, invalid cores count\n");
OCF_PL_FINISH_RET(pipeline, -OCF_ERR_INVAL);
}
if (sb_config->valid_parts_no > OCF_USER_IO_CLASS_MAX) {
ocf_cache_log(cache, log_err,
"Loading cache state ERROR, invalid partition count\n");
OCF_PL_FINISH_RET(pipeline, -OCF_ERR_INVAL);
}
ret = ocf_metadata_validate_superblock(context->cache->owner, superblock);
if (ret)
OCF_PL_FINISH_RET(pipeline, ret);
ocf_pipeline_next(pipeline);
}
@ -222,12 +282,11 @@ struct ocf_pipeline_properties ocf_metadata_load_sb_pipeline_props = {
ocf_metadata_load_sb_store_segment_args),
OCF_PL_STEP_ARG_INT(ocf_metadata_load_segment,
metadata_segment_sb_config),
OCF_PL_STEP(ocf_metadata_check_crc_sb_config),
OCF_PL_STEP(_ocf_metadata_validate_superblock),
OCF_PL_STEP_FOREACH(ocf_metadata_load_segment,
ocf_metadata_load_sb_load_segment_args),
OCF_PL_STEP_FOREACH(ocf_metadata_check_crc,
ocf_metadata_load_sb_load_segment_args),
OCF_PL_STEP(ocf_metadata_load_superblock_post),
OCF_PL_STEP_TERMINATOR(),
},
};
@ -288,12 +347,11 @@ struct ocf_pipeline_properties ocf_metadata_load_sb_recov_pipeline_props = {
ocf_metadata_load_sb_store_segment_args),
OCF_PL_STEP_ARG_INT(ocf_metadata_load_segment,
metadata_segment_sb_config),
OCF_PL_STEP(ocf_metadata_check_crc_sb_config),
OCF_PL_STEP(_ocf_metadata_validate_superblock),
OCF_PL_STEP_FOREACH(ocf_metadata_load_segment,
ocf_metadata_load_sb_recov_load_segment_args),
OCF_PL_STEP_FOREACH(ocf_metadata_check_crc,
ocf_metadata_load_sb_recov_load_segment_args),
OCF_PL_STEP(ocf_metadata_load_superblock_post),
OCF_PL_STEP_TERMINATOR(),
},
};
@ -573,47 +631,6 @@ unsigned ocf_metadata_superblock_get_next_flapping_idx(
return (sb->config->flapping_idx + 1) % 2;
}
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;

View File

@ -39,6 +39,11 @@ int ocf_cache_set_name(ocf_cache_t cache, const char *src, size_t src_size)
src, src_size);
}
bool ocf_cache_mode_is_valid(ocf_cache_mode_t mode)
{
return mode >= ocf_cache_mode_wt && mode < ocf_cache_mode_max;
}
const char *ocf_cache_get_name(ocf_cache_t cache)
{
OCF_CHECK_NULL(cache);

View File

@ -179,4 +179,6 @@ 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);
bool ocf_cache_mode_is_valid(ocf_cache_mode_t mode);
#endif /* __OCF_CACHE_PRIV_H__ */