From f74426acb2ecdd09c6b1c4fe5e11ddb16ba3ac0e Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Fri, 16 Oct 2026 00:16:41 +0200 Subject: [PATCH] mngt: Report incompatible metadata as found on attach Attaching a device that holds metadata created by a different OCF or adapter version, or in a different block mode, failed with the specific incompatibility error instead of OCF_ERR_METADATA_FOUND. As a result the adapter could not tell the user that the device contains metadata which has to be discarded with --force. The detailed reason is still logged by the superblock validation. Signed-off-by: Robert Baldyga --- src/mngt/ocf_mngt_cache.c | 27 ++++++++++------- .../tests/management/test_attach_cache.py | 29 +++++++++++++++++++ 2 files changed, 45 insertions(+), 11 deletions(-) diff --git a/src/mngt/ocf_mngt_cache.c b/src/mngt/ocf_mngt_cache.c index 00f13033..4f259075 100644 --- a/src/mngt/ocf_mngt_cache.c +++ b/src/mngt/ocf_mngt_cache.c @@ -1319,19 +1319,24 @@ static void _ocf_mngt_attach_read_properties_end(void *priv, int error, { struct ocf_cache_attach_context *context = priv; - if (error != -OCF_ERR_NO_METADATA) { - if (!error) { - /* - * To prevent silent metadata overriding, return error if old - * metadata was detected when attempting to attach cache. - */ - OCF_PL_FINISH_RET(context->pipeline, -OCF_ERR_METADATA_FOUND); - } + switch (error) { + case -OCF_ERR_NO_METADATA: + /* No metadata exists on the device */ + OCF_PL_NEXT_RET(context->pipeline); + case 0: + case -OCF_ERR_METADATA_VER: + case -OCF_ERR_ADAPTER_MISMATCH: + case -OCF_ERR_ADAPTER_VER: + case -OCF_ERR_BLOCK_MODE_MISMATCH: + /* + * To prevent silent metadata overriding, return error if old + * metadata was detected when attempting to attach cache - also + * if it was created by incompatible OCF or adapter version. + */ + OCF_PL_FINISH_RET(context->pipeline, -OCF_ERR_METADATA_FOUND); + default: OCF_PL_FINISH_RET(context->pipeline, error); } - - /* No metadata exists on the device */ - OCF_PL_NEXT_RET(context->pipeline); } static void _ocf_mngt_load_read_properties_end(void *priv, int error, diff --git a/tests/functional/tests/management/test_attach_cache.py b/tests/functional/tests/management/test_attach_cache.py index 46f0d7ec..db967c8d 100644 --- a/tests/functional/tests/management/test_attach_cache.py +++ b/tests/functional/tests/management/test_attach_cache.py @@ -28,6 +28,7 @@ CacheLineSize, SeqCutOffPolicy, OcfError, + OcfErrorCode, ) from pyocf.types.volume import RamVolume from pyocf.types.volume_core import CoreVolume @@ -135,6 +136,34 @@ def test_detach_cache_zero_superblock(pyocf_ctx): cache.stop() +def test_attach_cache_incompatible_metadata_version(pyocf_ctx): + """Check if attaching a device holding metadata of a different version + without --force option reports that metadata was found. + """ + cache_device = RamVolume(Size.from_MiB(50)) + cache = Cache.start_on_device(cache_device) + cache.stop() + + # metadata_version follows clean_shutdown, dirty_flushed, padding and magic + version_offset = 8 + version = int.from_bytes( + cache_device.data[version_offset : version_offset + 4], "little" + ) + cache_device.data[version_offset : version_offset + 4] = (version ^ 0x0100).to_bytes( + 4, "little" + ) + + cache = Cache(owner=pyocf_ctx) + cache.start_cache() + + with pytest.raises(OcfError) as ex: + cache.attach_device(cache_device, force=False) + assert ex.value.error_code == OcfErrorCode.OCF_ERR_METADATA_FOUND + + cache.attach_device(cache_device, force=True) + cache.stop() + + def test_reattach_preserves_policy_params(pyocf_ctx): """Check if cleaning, promotion and prefetch policy parameters set before detach are preserved after the cache device is attached again.