diff --git a/src/metadata/metadata.c b/src/metadata/metadata.c index 02c6be6..a4763eb 100644 --- a/src/metadata/metadata.c +++ b/src/metadata/metadata.c @@ -1552,6 +1552,26 @@ void ocf_metadata_clear_dirty_if_invalid(struct ocf_cache *cache, } } +bool ocf_metadata_check(struct ocf_cache *cache, ocf_cache_line_t line) +{ + switch (cache->metadata.line_size) { + case ocf_cache_line_size_4: + return _ocf_metadata_check_u8(cache, line); + case ocf_cache_line_size_8: + return _ocf_metadata_check_u16(cache, line); + case ocf_cache_line_size_16: + return _ocf_metadata_check_u32(cache, line); + case ocf_cache_line_size_32: + return _ocf_metadata_check_u64(cache, line); + case ocf_cache_line_size_64: + return _ocf_metadata_check_u128(cache, line); + case ocf_cache_line_size_none: + default: + ENV_BUG_ON(1); + return false; + } +} + int ocf_metadata_init(struct ocf_cache *cache, ocf_cache_line_size_t cache_line_size) { diff --git a/src/metadata/metadata.h b/src/metadata/metadata.h index 9f0ef00..23e1844 100644 --- a/src/metadata/metadata.h +++ b/src/metadata/metadata.h @@ -220,4 +220,14 @@ static inline ocf_cache_line_t ocf_metadata_collision_table_entries( void ocf_metadata_zero_superblock(ocf_cache_t cache, ocf_metadata_end_t cmpl, void *context); +/** + * @brief Check for incorrect status bits combinations + * + * @param cache Cache instance + * @param line Cache line + * @return true - status bits are correct + * @return false - status bits have illegal value + */ +bool ocf_metadata_check(struct ocf_cache *cache, ocf_cache_line_t line); + #endif /* METADATA_H_ */ diff --git a/src/metadata/metadata_bit.h b/src/metadata/metadata_bit.h index 6acaac9..59f5662 100644 --- a/src/metadata/metadata_bit.h +++ b/src/metadata/metadata_bit.h @@ -263,6 +263,23 @@ static void _ocf_metadata_clear_dirty_if_invalid_##type(struct ocf_cache *cache, \ map[line].dirty &= (mask & map[line].valid) | (~mask); \ } \ +\ +/* true if no incorrect combination of status bits */ \ +static bool _ocf_metadata_check_##type(struct ocf_cache *cache, \ + ocf_cache_line_t line) \ +{ \ + struct ocf_metadata_ctrl *ctrl = \ + (struct ocf_metadata_ctrl *) cache->metadata.priv; \ +\ + struct ocf_metadata_raw *raw = \ + &ctrl->raw_desc[metadata_segment_collision]; \ +\ + struct ocf_metadata_map_##type *map = raw->mem_pool; \ +\ + _raw_bug_on(raw, line); \ +\ + return (map[line].dirty & (~map[line].valid)) == 0; \ +} \ #define ocf_metadata_bit_funcs(type) \ ocf_metadata_bit_struct(type); \ diff --git a/src/mngt/ocf_mngt_cache.c b/src/mngt/ocf_mngt_cache.c index 5ea714a..8b14bfe 100644 --- a/src/mngt/ocf_mngt_cache.c +++ b/src/mngt/ocf_mngt_cache.c @@ -495,7 +495,7 @@ static void _recovery_reset_cline_metadata(struct ocf_cache *cache, ocf_cleaning_init_cache_block(cache, cline); } -static void _ocf_mngt_rebuild_metadata(ocf_cache_t cache) +static int _ocf_mngt_rebuild_metadata(ocf_cache_t cache) { ocf_cache_line_t cline; ocf_core_id_t core_id; @@ -512,25 +512,40 @@ static void _ocf_mngt_rebuild_metadata(ocf_cache_t cache) OCF_COND_RESCHED(step, 128); ocf_metadata_get_core_info(cache, cline, &core_id, &core_line); - metadata_clear_dirty_if_invalid(cache, cline); + if (!ocf_metadata_check(cache, cline) || + core_id > OCF_CORE_MAX) { + ocf_cache_log(cache, log_err, "Inconsistent mapping " + "detected in on-disk metadata - " + "refusing to recover cache.\n"); + return -OCF_ERR_INVAL; + } any_valid = metadata_clear_valid_if_clean(cache, cline); - if (!any_valid || core_id >= OCF_CORE_MAX) { + if (!any_valid || core_id == OCF_CORE_MAX) { /* Reset metadata for not mapped or clean cache line */ _recovery_reset_cline_metadata(cache, cline); continue; } + if (!cache->core[core_id].added) { + ocf_cache_log(cache, log_err, "Stale mapping in " + "on-disk metadata - refusing to " + "recover cache.\n"); + return -OCF_ERR_INVAL; + } + /* Rebuild metadata for mapped cache line */ ocf_cline_rebuild_metadata(cache, core_id, core_line, cline); } ocf_metadata_end_exclusive_access(&cache->metadata.lock); + + return 0; } -static void _ocf_mngt_recovery_rebuild_metadata(ocf_cache_t cache) +static int _ocf_mngt_recovery_rebuild_metadata(ocf_cache_t cache) { - _ocf_mngt_rebuild_metadata(cache); + return _ocf_mngt_rebuild_metadata(cache); } static inline ocf_error_t _ocf_init_cleaning_policy(ocf_cache_t cache, @@ -556,9 +571,12 @@ static void _ocf_mngt_load_post_metadata_load(ocf_pipeline_t pipeline, struct ocf_cache_attach_context *context = priv; ocf_cache_t cache = context->cache; ocf_error_t result; + int ret; if (context->metadata.shutdown_status != ocf_metadata_clean_shutdown) { - _ocf_mngt_recovery_rebuild_metadata(cache); + ret = _ocf_mngt_recovery_rebuild_metadata(cache); + if (ret) + OCF_PL_FINISH_RET(pipeline, ret); __populate_free(cache); } @@ -2113,8 +2131,11 @@ static void _ocf_mngt_standby_recovery(ocf_pipeline_t pipeline, { struct ocf_cache_attach_context *context = priv; ocf_cache_t cache = context->cache; + int ret; - _ocf_mngt_recovery_rebuild_metadata(cache); + ret = _ocf_mngt_recovery_rebuild_metadata(cache); + if (ret) + OCF_PL_FINISH_RET(pipeline, ret); __populate_free(cache); ocf_pipeline_next(pipeline);