From ce22c304652788d21819025a345e863a41043eb5 Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Mon, 4 May 2026 09:47:13 +0200 Subject: [PATCH 1/4] metadata: Isolate superblock header Signed-off-by: Robert Baldyga --- src/metadata/metadata_superblock.h | 36 ++++++++++++++++++++---------- 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/src/metadata/metadata_superblock.h b/src/metadata/metadata_superblock.h index f0eab0aa..2a6e0d2b 100644 --- a/src/metadata/metadata_superblock.h +++ b/src/metadata/metadata_superblock.h @@ -18,20 +18,29 @@ /** * @brief OCF cache metadata configuration superblock + * + * The first 12 bytes of superblock do not change between verions. + * These fields are used by metadata probe to recognize OCF metadata + * and identify metadata version and status. + * The layout is following: + * 0:7 | clean shutdown status + * 8:15 | dirty metadata present + * 16:31 | padding; kept for historic reasons; zeroed + * 32:63 | OCF magic number; must be 0x187E1CA6 + * 64:95 | OCF metadata version + * + * The remaining fields can should be accessed only after confirming + * correct magic and metadata version. */ struct ocf_superblock_config { - /** WARNING: Metadata probe disregards metadata version when - * checking if the cache is dirty - position of next two fields - * shouldn't change!! */ - uint8_t clean_shutdown; - uint8_t dirty_flushed; - - /* Current core sequence number */ - ocf_core_id_t curr_core_seq_no; - - uint32_t magic_number; - - uint32_t metadata_version; + /* Superblock header */ + struct { + uint8_t clean_shutdown; + uint8_t dirty_flushed; + uint16_t _padding; + uint32_t magic_number; + uint32_t metadata_version; + }; unsigned flapping_idx; @@ -46,6 +55,9 @@ struct ocf_superblock_config { ocf_cache_line_size_t line_size; uint32_t core_count; + /* Current core sequence number */ + ocf_core_id_t curr_core_seq_no; + unsigned long valid_core_bitmap[OCF_DIV_ROUND_UP_STATIC(OCF_CORE_NUM, sizeof(unsigned long) * 8)]; From c1a84b1843efcfa7c233b0a25b49818319e0edac Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Wed, 26 Aug 2026 09:30:35 +0200 Subject: [PATCH 2/4] metadata: Separate OCF version from adapter version Signed-off-by: Robert Baldyga --- env/posix/ocf_env_headers.h | 8 +++++--- inc/ocf_def.h | 8 ++++++++ inc/ocf_err.h | 8 +++++++- src/metadata/metadata.c | 15 ++++++++++++++ src/metadata/metadata_superblock.c | 27 ++++++++++++++++++++++++++ src/metadata/metadata_superblock.h | 4 ++++ src/mngt/ocf_mngt_cache.c | 21 +++++++++++++++----- src/ocf_def_priv.h | 3 +++ tests/functional/pyocf/types/shared.py | 2 ++ 9 files changed, 87 insertions(+), 9 deletions(-) diff --git a/env/posix/ocf_env_headers.h b/env/posix/ocf_env_headers.h index b9841610..b90c4160 100644 --- a/env/posix/ocf_env_headers.h +++ b/env/posix/ocf_env_headers.h @@ -1,5 +1,6 @@ /* * Copyright(c) 2019-2021 Intel Corporation + * Copyright(c) 2026 Unvertical * SPDX-License-Identifier: BSD-3-Clause */ @@ -15,8 +16,9 @@ #define OCF_PREFIX_SHORT "[" OCF_LOGO "] " #define OCF_PREFIX_LONG "Open CAS Framework" -#define OCF_VERSION_MAIN 20 -#define OCF_VERSION_MAJOR 3 -#define OCF_VERSION_MINOR 0 +#define ENV_ADAPTER_NAME "OCF Posix" +#define ENV_ADAPTER_VERSION_MAIN 20 +#define ENV_ADAPTER_VERSION_MAJOR 3 +#define ENV_ADAPTER_VERSION_MINOR 0 #endif /* __OCF_ENV_HEADERS_H__ */ diff --git a/inc/ocf_def.h b/inc/ocf_def.h index 219c5965..8a354752 100644 --- a/inc/ocf_def.h +++ b/inc/ocf_def.h @@ -21,6 +21,10 @@ * @brief OCF definitions */ +#define OCF_VERSION_MAIN 26 +#define OCF_VERSION_MAJOR 9 +#define OCF_VERSION_MINOR 0 + /** * Enabling debug statistics */ @@ -64,6 +68,10 @@ * Size of cache name */ #define OCF_CACHE_NAME_SIZE 32 +/** + * Size of adapter name + */ +#define OCF_ADAPTER_NAME_SIZE 32 /** * Value to turn off fallback pass through */ diff --git a/inc/ocf_err.h b/inc/ocf_err.h index eec29e87..d5d75613 100644 --- a/inc/ocf_err.h +++ b/inc/ocf_err.h @@ -187,7 +187,13 @@ typedef enum { /** Operation not allowed when cleaner is disabled **/ OCF_ERR_CLEANER_DISABLED, - OCF_ERR_MAX = OCF_ERR_CLEANER_DISABLED, + /** Metadata was created by a different adapter */ + OCF_ERR_ADAPTER_MISMATCH, + + /** Adapter version mismatch */ + OCF_ERR_ADAPTER_VER, + + OCF_ERR_MAX = OCF_ERR_ADAPTER_VER, } ocf_error_t; diff --git a/src/metadata/metadata.c b/src/metadata/metadata.c index ca9cdd29..60865a5c 100644 --- a/src/metadata/metadata.c +++ b/src/metadata/metadata.c @@ -1954,8 +1954,23 @@ static void ocf_metadata_probe_cmpl(struct ocf_metadata_read_sb_ctx *context) if (METADATA_VERSION() != superblock->metadata_version) OCF_CMPL_RET(priv, -OCF_ERR_METADATA_VER, &status); + /* + * Following fields presence and offset is dependent on metadata + * version, so they can be safely accessed only after positive + * metadata version verification. + */ + + if (env_strncmp(superblock->adapter_name, OCF_ADAPTER_NAME_SIZE, + ENV_ADAPTER_NAME, OCF_ADAPTER_NAME_SIZE)) { + OCF_CMPL_RET(priv, -OCF_ERR_ADAPTER_MISMATCH, &status); + } + + if (superblock->adapter_version != ADAPTER_VERSION()) + OCF_CMPL_RET(priv, -OCF_ERR_ADAPTER_VER, &status); + env_strncpy(status.cache_name, OCF_CACHE_NAME_SIZE, superblock->name, OCF_CACHE_NAME_SIZE); + status.cache_mode = superblock->cache_mode; status.cache_line_size = superblock->line_size; diff --git a/src/metadata/metadata_superblock.c b/src/metadata/metadata_superblock.c index 1e28f02a..be93f05c 100644 --- a/src/metadata/metadata_superblock.c +++ b/src/metadata/metadata_superblock.c @@ -128,6 +128,33 @@ int ocf_metadata_validate_superblock(ocf_ctx_t ctx, return -OCF_ERR_CRC_MISMATCH; } + if (env_strncmp(superblock->adapter_name, OCF_ADAPTER_NAME_SIZE, + ENV_ADAPTER_NAME, OCF_ADAPTER_NAME_SIZE)) { + /* Field comes off disk and need not be terminated - bound + * the print to its size instead of running past it. + */ + ocf_log(ctx, log_err, "Loading %s: metadata was created by " + "adapter '%.*s', but OCF is running as '%s'!\n", + segment_name, OCF_ADAPTER_NAME_SIZE, + superblock->adapter_name, ENV_ADAPTER_NAME); + return -OCF_ERR_ADAPTER_MISMATCH; + } + + if (superblock->adapter_version != ADAPTER_VERSION()) { + ocf_log(ctx, log_err, "Loading %s: adapter version mismatch! " + "Metadata was created by %s %u.%u.%u, but OCF " + "is running under %s %u.%u.%u\n", segment_name, + ENV_ADAPTER_NAME, + (superblock->adapter_version >> 16) & 0xff, + (superblock->adapter_version >> 8) & 0xff, + superblock->adapter_version & 0xff, + ENV_ADAPTER_NAME, + ENV_ADAPTER_VERSION_MAIN, + ENV_ADAPTER_VERSION_MAJOR, + ENV_ADAPTER_VERSION_MINOR); + return -OCF_ERR_ADAPTER_VER; + } + if (superblock->clean_shutdown > ocf_metadata_clean_shutdown) { ocf_log_invalid_superblock("shutdown status"); return -OCF_ERR_INVAL; diff --git a/src/metadata/metadata_superblock.h b/src/metadata/metadata_superblock.h index 2a6e0d2b..e77426c2 100644 --- a/src/metadata/metadata_superblock.h +++ b/src/metadata/metadata_superblock.h @@ -42,6 +42,10 @@ struct ocf_superblock_config { uint32_t metadata_version; }; + /* Identity of the adapter */ + char adapter_name[OCF_ADAPTER_NAME_SIZE]; + uint32_t adapter_version; + unsigned flapping_idx; /* Currently set cache mode */ diff --git a/src/mngt/ocf_mngt_cache.c b/src/mngt/ocf_mngt_cache.c index 89a10119..f52e101e 100644 --- a/src/mngt/ocf_mngt_cache.c +++ b/src/mngt/ocf_mngt_cache.c @@ -297,9 +297,20 @@ static void __init_cores(ocf_cache_t cache) sizeof(cache->conf_meta->valid_core_bitmap), 0)); } -static void __init_metadata_version(ocf_cache_t cache) +static void __init_superblock_header(ocf_cache_t cache) { cache->conf_meta->metadata_version = METADATA_VERSION(); + cache->conf_meta->adapter_version = ADAPTER_VERSION(); + + /* + * Zero the whole field first - the name is covered by the superblock + * checksum, so the bytes past the terminator have to be deterministic. + */ + ENV_BUG_ON(env_memset(cache->conf_meta->adapter_name, + OCF_ADAPTER_NAME_SIZE, 0)); + ENV_BUG_ON(env_strncpy(cache->conf_meta->adapter_name, + OCF_ADAPTER_NAME_SIZE, ENV_ADAPTER_NAME, + OCF_ADAPTER_NAME_SIZE - 1)); } static void _reset_stats(ocf_pipeline_t pipeline, void *priv, @@ -327,13 +338,13 @@ static void _reset_stats(ocf_pipeline_t pipeline, void *priv, ocf_pipeline_next(pipeline); } -static void _init_metadata_version(ocf_pipeline_t pipeline, void *priv, +static void _init_superblock_header(ocf_pipeline_t pipeline, void *priv, ocf_pipeline_arg_t arg) { struct ocf_init_metadata_context *context = priv; ocf_cache_t cache = context->cache; - __init_metadata_version(cache); + __init_superblock_header(cache); ocf_pipeline_next(pipeline); } @@ -356,7 +367,7 @@ struct ocf_pipeline_properties ocf_init_attached_recovery_props = { OCF_PL_STEP(ocf_metadata_init_collision), OCF_PL_STEP(_init_parts_attached), OCF_PL_STEP(_reset_stats), - OCF_PL_STEP(_init_metadata_version), + OCF_PL_STEP(_init_superblock_header), OCF_PL_STEP_TERMINATOR(), }, }; @@ -1598,7 +1609,7 @@ static void _ocf_mngt_cache_init(ocf_cache_t cache, __init_free(cache); __init_cores(cache); - __init_metadata_version(cache); + __init_superblock_header(cache); __init_partitions(cache); } diff --git a/src/ocf_def_priv.h b/src/ocf_def_priv.h index 9b361b61..8844796b 100644 --- a/src/ocf_def_priv.h +++ b/src/ocf_def_priv.h @@ -56,6 +56,9 @@ #define METADATA_VERSION() ((OCF_VERSION_MAIN << 16) + \ (OCF_VERSION_MAJOR << 8) + OCF_VERSION_MINOR) +#define ADAPTER_VERSION() ((ENV_ADAPTER_VERSION_MAIN << 16) + \ + (ENV_ADAPTER_VERSION_MAJOR << 8) + ENV_ADAPTER_VERSION_MINOR) + /* call conditional reschedule every 'iterations' calls */ #define OCF_COND_RESCHED(cnt, iterations) \ if (unlikely(++(cnt) == (iterations))) { \ diff --git a/tests/functional/pyocf/types/shared.py b/tests/functional/pyocf/types/shared.py index 6203156c..5255fb40 100644 --- a/tests/functional/pyocf/types/shared.py +++ b/tests/functional/pyocf/types/shared.py @@ -71,6 +71,8 @@ class OcfErrorCode(IntEnum): OCF_ERR_CORE_NOT_REMOVED = auto() OCF_ERR_CACHE_NOT_STANDBY = auto() OCF_ERR_CLEANER_DISABLED = auto() + OCF_ERR_ADAPTER_MISMATCH = auto() + OCF_ERR_ADAPTER_VER = auto() class OcfCompletion: From 5883c6765e8d8de88c32b0a4dc9f0aabfb011571 Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Wed, 26 Aug 2026 09:31:01 +0200 Subject: [PATCH 3/4] metadata: Improve error message for metadata mismatch Signed-off-by: Robert Baldyga --- src/metadata/metadata_superblock.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/metadata/metadata_superblock.c b/src/metadata/metadata_superblock.c index be93f05c..38a9182a 100644 --- a/src/metadata/metadata_superblock.c +++ b/src/metadata/metadata_superblock.c @@ -116,7 +116,15 @@ int ocf_metadata_validate_superblock(ocf_ctx_t ctx, } if (METADATA_VERSION() != superblock->metadata_version) { - ocf_log(ctx, log_err, "Metadata version mismatch!\n"); + ocf_log(ctx, log_err, "Loading %s: metadata version mismatch! " + "Metadata was created by OCF %u.%u.%u, but " + "current version is %u.%u.%u\n", segment_name, + (superblock->metadata_version >> 16) & 0xff, + (superblock->metadata_version >> 8) & 0xff, + superblock->adapter_version & 0xff, + OCF_VERSION_MAIN, + OCF_VERSION_MAJOR, + OCF_VERSION_MINOR); return -OCF_ERR_METADATA_VER; } From 90ec5c17aa104e2e41de9b9a1a7dbd03fc5e1a14 Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Mon, 24 Aug 2026 16:38:57 +0200 Subject: [PATCH 4/4] metadata: Detect block mode mismatch Signed-off-by: Robert Baldyga --- inc/ocf_err.h | 5 ++++- src/metadata/metadata_superblock.c | 9 +++++++++ src/metadata/metadata_superblock.h | 2 ++ src/mngt/ocf_mngt_cache.c | 1 + src/ocf_def_priv.h | 6 ++++++ tests/functional/pyocf/types/shared.py | 1 + 6 files changed, 23 insertions(+), 1 deletion(-) diff --git a/inc/ocf_err.h b/inc/ocf_err.h index d5d75613..de350d0a 100644 --- a/inc/ocf_err.h +++ b/inc/ocf_err.h @@ -193,7 +193,10 @@ typedef enum { /** Adapter version mismatch */ OCF_ERR_ADAPTER_VER, - OCF_ERR_MAX = OCF_ERR_ADAPTER_VER, + /** Metadata was created in different block mode */ + OCF_ERR_BLOCK_MODE_MISMATCH, + + OCF_ERR_MAX = OCF_ERR_BLOCK_MODE_MISMATCH, } ocf_error_t; diff --git a/src/metadata/metadata_superblock.c b/src/metadata/metadata_superblock.c index 38a9182a..0c3eaad2 100644 --- a/src/metadata/metadata_superblock.c +++ b/src/metadata/metadata_superblock.c @@ -163,6 +163,15 @@ int ocf_metadata_validate_superblock(ocf_ctx_t ctx, return -OCF_ERR_ADAPTER_VER; } + if (superblock->metadata_4k_mode != METADATA_4K_MODE()) { + ocf_log(ctx, log_err, "Loading %s: metadata was created in %s " + "block mode, but OCF is running in %s block " + "mode!\n", segment_name, + superblock->metadata_4k_mode ? "4KiB" : "512B", + METADATA_4K_MODE() ? "4KiB" : "512B"); + return -OCF_ERR_BLOCK_MODE_MISMATCH; + } + if (superblock->clean_shutdown > ocf_metadata_clean_shutdown) { ocf_log_invalid_superblock("shutdown status"); return -OCF_ERR_INVAL; diff --git a/src/metadata/metadata_superblock.h b/src/metadata/metadata_superblock.h index e77426c2..a01f23fc 100644 --- a/src/metadata/metadata_superblock.h +++ b/src/metadata/metadata_superblock.h @@ -46,6 +46,8 @@ struct ocf_superblock_config { char adapter_name[OCF_ADAPTER_NAME_SIZE]; uint32_t adapter_version; + bool metadata_4k_mode; + unsigned flapping_idx; /* Currently set cache mode */ diff --git a/src/mngt/ocf_mngt_cache.c b/src/mngt/ocf_mngt_cache.c index f52e101e..ffdc396c 100644 --- a/src/mngt/ocf_mngt_cache.c +++ b/src/mngt/ocf_mngt_cache.c @@ -301,6 +301,7 @@ static void __init_superblock_header(ocf_cache_t cache) { cache->conf_meta->metadata_version = METADATA_VERSION(); cache->conf_meta->adapter_version = ADAPTER_VERSION(); + cache->conf_meta->metadata_4k_mode = METADATA_4K_MODE(); /* * Zero the whole field first - the name is covered by the superblock diff --git a/src/ocf_def_priv.h b/src/ocf_def_priv.h index 8844796b..d07ce7e3 100644 --- a/src/ocf_def_priv.h +++ b/src/ocf_def_priv.h @@ -59,6 +59,12 @@ #define ADAPTER_VERSION() ((ENV_ADAPTER_VERSION_MAIN << 16) + \ (ENV_ADAPTER_VERSION_MAJOR << 8) + ENV_ADAPTER_VERSION_MINOR) +#ifdef OCF_BLOCK_SIZE_4K +#define METADATA_4K_MODE() true +#else +#define METADATA_4K_MODE() false +#endif + /* call conditional reschedule every 'iterations' calls */ #define OCF_COND_RESCHED(cnt, iterations) \ if (unlikely(++(cnt) == (iterations))) { \ diff --git a/tests/functional/pyocf/types/shared.py b/tests/functional/pyocf/types/shared.py index 5255fb40..82a8cdda 100644 --- a/tests/functional/pyocf/types/shared.py +++ b/tests/functional/pyocf/types/shared.py @@ -73,6 +73,7 @@ class OcfErrorCode(IntEnum): OCF_ERR_CLEANER_DISABLED = auto() OCF_ERR_ADAPTER_MISMATCH = auto() OCF_ERR_ADAPTER_VER = auto() + OCF_ERR_BLOCK_MODE_MISMATCH = auto() class OcfCompletion: