From d6c725371ff507c396e5514e2264e575e15d488d Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Thu, 15 Oct 2026 12:03:20 +0200 Subject: [PATCH 1/9] uuid: Allow setting zero size uuid This allows for proper cleaning of uuid in metadata on core removal. Signed-off-by: Robert Baldyga --- src/mngt/ocf_mngt_core.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/mngt/ocf_mngt_core.c b/src/mngt/ocf_mngt_core.c index 6b65656d..d08e9987 100644 --- a/src/mngt/ocf_mngt_core.c +++ b/src/mngt/ocf_mngt_core.c @@ -62,16 +62,18 @@ static int _ocf_uuid_set(const struct ocf_volume_uuid *uuid, { int result; - if (!uuid->data) + if (!uuid->data && uuid->size) return -OCF_ERR_INVAL; if (uuid->size > sizeof(muuid->data)) return -OCF_ERR_INVAL; - result = env_memcpy(muuid->data, sizeof(muuid->data), - uuid->data, uuid->size); - if (result) - return result; + if (uuid->size) { + result = env_memcpy(muuid->data, sizeof(muuid->data), + uuid->data, uuid->size); + if (result) + return result; + } if (uuid->size < sizeof(muuid->data)) { result = env_memset(muuid->data + uuid->size, From 1da06b5c0dbed74ce08947459c48a50ae8a39003 Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Wed, 14 Oct 2026 23:17:36 +0200 Subject: [PATCH 2/9] pipeline: Introduce OCF_PL_STEP_FOREACH_COND() Signed-off-by: Robert Baldyga --- src/utils/utils_pipeline.c | 16 ++++++++++++++++ src/utils/utils_pipeline.h | 10 ++++++++++ 2 files changed, 26 insertions(+) diff --git a/src/utils/utils_pipeline.c b/src/utils/utils_pipeline.c index a364b216..a95b84a5 100644 --- a/src/utils/utils_pipeline.c +++ b/src/utils/utils_pipeline.c @@ -73,6 +73,22 @@ static int _ocf_pipeline_run_step(struct ocf_request *req) step->hndl(pipeline, pipeline->priv, arg); pipeline->arg++; return 0; + case ocf_pipeline_step_foreach_conditional: + if (!pipeline->arg) + pipeline->arg = &step->args[0]; + arg = pipeline->arg; + if (arg->type == ocf_pipeline_arg_terminator) { + pipeline->arg = NULL; + pipeline->step++; + continue; + } + if (step->pred(pipeline, pipeline->priv, arg)) { + step->hndl(pipeline, pipeline->priv, arg); + pipeline->arg++; + return 0; + } + pipeline->arg++; + continue; case ocf_pipeline_step_terminator: pipeline->properties->finish(pipeline, pipeline->priv, pipeline->error); diff --git a/src/utils/utils_pipeline.h b/src/utils/utils_pipeline.h index 9bd85081..9642a98d 100644 --- a/src/utils/utils_pipeline.h +++ b/src/utils/utils_pipeline.h @@ -14,6 +14,7 @@ enum ocf_pipeline_step_type { ocf_pipeline_step_single, ocf_pipeline_step_foreach, ocf_pipeline_step_conditional, + ocf_pipeline_step_foreach_conditional, ocf_pipeline_step_terminator, }; @@ -162,6 +163,15 @@ typedef struct ocf_pipeline_step *ocf_pipeline_step_t; } \ } +#define OCF_PL_STEP_FOREACH_COND(_pred, _hndl, _args) \ + { \ + .name = xstr(_hndl), \ + .pred = _pred, \ + .type = ocf_pipeline_step_foreach_conditional, \ + .hndl = _hndl, \ + .args = _args, \ + } + struct ocf_pipeline_properties { uint32_t priv_size; ocf_pipeline_finish_t finish; From 7a680eb27faa2ace90d3848870d132da1e2ffa1b Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Tue, 13 Oct 2026 12:23:59 +0200 Subject: [PATCH 3/9] metadata: Move layout definitions to a separate subdirectory Make clean separation between layout layer and metadata management layer. Signed-off-by: Robert Baldyga --- src/metadata/layout/cleaning_policy.h | 82 ++++++++++++++ src/metadata/layout/collision.h | 104 ++++++++++++++++++ src/metadata/layout/core.h | 68 ++++++++++++ .../{metadata_layout.c => layout/layout.c} | 16 +-- .../{metadata_layout.h => layout/layout.h} | 4 +- src/metadata/layout/lru.h | 38 +++++++ src/metadata/layout/partition.h | 46 ++++++++ src/metadata/layout/prefetch_policy.h | 26 +++++ src/metadata/layout/promotion_policy.h | 29 +++++ .../segment_id.h} | 6 +- .../{metadata_bit.h => layout/status.h} | 8 +- src/metadata/layout/superblock.h | 103 +++++++++++++++++ src/metadata/metadata.c | 6 +- src/metadata/metadata.h | 2 +- src/metadata/metadata_cleaning_policy.h | 72 +----------- src/metadata/metadata_collision.h | 94 +--------------- src/metadata/metadata_core.h | 56 +--------- src/metadata/metadata_internal.h | 4 +- src/metadata/metadata_lru.h | 26 +---- src/metadata/metadata_partition.h | 34 +----- src/metadata/metadata_passive_update.c | 2 +- src/metadata/metadata_prefetch_policy.h | 16 +-- src/metadata/metadata_promotion_policy.h | 19 +--- src/metadata/metadata_raw.c | 4 +- src/metadata/metadata_raw.h | 4 +- src/metadata/metadata_raw_atomic.c | 2 +- src/metadata/metadata_raw_dynamic.c | 4 +- src/metadata/metadata_raw_volatile.c | 3 +- src/metadata/metadata_superblock.c | 2 +- src/metadata/metadata_superblock.h | 91 +-------------- 30 files changed, 539 insertions(+), 432 deletions(-) create mode 100644 src/metadata/layout/cleaning_policy.h create mode 100644 src/metadata/layout/collision.h create mode 100644 src/metadata/layout/core.h rename src/metadata/{metadata_layout.c => layout/layout.c} (97%) rename src/metadata/{metadata_layout.h => layout/layout.h} (99%) create mode 100644 src/metadata/layout/lru.h create mode 100644 src/metadata/layout/partition.h create mode 100644 src/metadata/layout/prefetch_policy.h create mode 100644 src/metadata/layout/promotion_policy.h rename src/metadata/{metadata_segment_id.h => layout/segment_id.h} (91%) rename src/metadata/{metadata_bit.h => layout/status.h} (98%) create mode 100644 src/metadata/layout/superblock.h diff --git a/src/metadata/layout/cleaning_policy.h b/src/metadata/layout/cleaning_policy.h new file mode 100644 index 00000000..d9237d24 --- /dev/null +++ b/src/metadata/layout/cleaning_policy.h @@ -0,0 +1,82 @@ +/* + * Copyright(c) 2012-2021 Intel Corporation + * Copyright(c) 2026 Unvertical + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef __METADATA_LAYOUT_CLEANING_POLICY_H__ +#define __METADATA_LAYOUT_CLEANING_POLICY_H__ + +#include "ocf/ocf.h" + +/* Cleaning policy configuration (stored in superblock) */ + +#define CLEANING_POLICY_CONFIG_BYTES 256 +#define CLEANING_POLICY_TYPE_MAX 4 + +struct cleaning_policy_config { + uint8_t data[CLEANING_POLICY_CONFIG_BYTES]; +} __attribute__((aligned(4))); + +struct alru_cleaning_policy_config { + uint32_t thread_wakeup_time; /* in seconds */ + uint32_t stale_buffer_time; /* in seconds */ + uint32_t flush_max_buffers; /* in lines */ + uint32_t activity_threshold; /* in milliseconds */ + uint32_t dirty_ratio_threshold; /* percent */ + uint32_t dirty_ratio_inertia; /* bytes */ +}; + +struct acp_cleaning_policy_config { + uint32_t thread_wakeup_time; /* in milliseconds*/ + uint32_t flush_max_buffers; /* in lines */ +}; + +/* Cleaning policy metadata per partition */ + +struct nop_cleaning_policy { +}; + +struct alru_cleaning_policy { + env_atomic size; + uint32_t lru_head; + uint32_t lru_tail; +}; + +struct acp_cleaning_policy { +}; + +struct cleaning_policy { + union { + struct nop_cleaning_policy nop; + struct alru_cleaning_policy alru; + struct acp_cleaning_policy acp; + } policy; +}; + +/* Cleaning policy metadata per cache line */ + +struct nop_cleaning_policy_meta { +} __attribute__((packed)); + +struct alru_cleaning_policy_meta { + /* Lru pointers 2*4=8 bytes */ + uint32_t timestamp; + uint32_t lru_prev; + uint32_t lru_next; +} __attribute__((packed)); + +/* TODO: remove acp metadata */ +struct acp_cleaning_policy_meta { + uint8_t dirty : 1; +}; + +struct cleaning_policy_meta { + union { + struct nop_cleaning_policy_meta nop; + struct alru_cleaning_policy_meta alru; + struct acp_cleaning_policy_meta acp; + } meta; +}; + +#endif /* __METADATA_LAYOUT_CLEANING_POLICY_H__ */ diff --git a/src/metadata/layout/collision.h b/src/metadata/layout/collision.h new file mode 100644 index 00000000..b29ae7d1 --- /dev/null +++ b/src/metadata/layout/collision.h @@ -0,0 +1,104 @@ +/* + * Copyright(c) 2012-2022 Intel Corporation + * Copyright(c) 2022-2023 Huawei Technologies + * Copyright(c) 2026 Unvertical + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef __METADATA_LAYOUT_COLLISION_H__ +#define __METADATA_LAYOUT_COLLISION_H__ + +#include "../../ocf_def_priv.h" + +/** + * @brief Metadata map structure + */ + +struct ocf_metadata_list_info { + union { + struct { + /* Previous cache line in collision list */ + ocf_cache_line_t prev_col : OCF_CACHE_LINE_BITS; + ocf_cache_line_t unused : 3; + /* Next cache line in collision list*/ + ocf_cache_line_t next_col : OCF_CACHE_LINE_BITS; + ocf_cache_line_t unused2 : 3; + } __attribute__((packed)); + uint64_t entry; + }; +}; + +/* Keep the struct ocf_metadata_list_info size of 8 bytes */ +_Static_assert(sizeof(struct ocf_metadata_list_info) == sizeof(uint64_t), + "Size of struct ocf_metadata_list_info is not equal to 8 bytes"); + +struct ocf_hash_entry { + union { + struct { + uint32_t line : OCF_CACHE_LINE_BITS; + /* Hash lock bits */ + uint32_t rd : 2; + uint32_t wr : 1; + }; + uint32_t raw; + }; +}; + +/** + * @brief Hash bucket of core line + * + * Hash function intentionally returns consecutive (modulo @hash_entries) + * values for consecutive @core_line. This way it is trivial to sort all + * core lines within a single request in ascending hash value order. This kind + * of sorting is required to assure that (future) hash bucket metadata locks are + * always acquired in fixed order, eliminating the risk of dead locks. + * + * @param hash_entries - Number of entries in hash segment + * @param core_line - Core line number + * @param core_id - Core id + */ +static inline ocf_cache_line_t ocf_metadata_collision_hash( + ocf_cache_line_t hash_entries, uint64_t core_line, + ocf_core_id_t core_id) +{ + return (ocf_cache_line_t) ((core_line + (core_id * (hash_entries / 32))) + % hash_entries); +} + +/** + * @brief Hash bucket following given one + * + * @param hash_entries - Number of entries in hash segment + * @param hash - Hash bucket + */ +static inline ocf_cache_line_t ocf_metadata_collision_hash_next( + ocf_cache_line_t hash_entries, ocf_cache_line_t hash) +{ + hash++; + return likely(hash < hash_entries) ? hash : 0; +} + +/** + * @brief Metadata map structure + */ + +struct ocf_metadata_map { + uint64_t core_line : OCF_CORE_LINE_BITS; + /*!< Core line address on cache mapped by this structure */ + + uint64_t core_id : OCF_CORE_ID_BITS; + /*!< ID of core where is assigned this cache line*/ + +#ifdef OCF_BLOCK_SIZE_4K + uint64_t _valid : 1; + /*!< valid bit for 4K cache line */ + + uint64_t _dirty : 1; + /*!< dirty bit for 4K cache line */ +#endif + + uint8_t status[]; + /*!< Entry status structure e.g. valid, dirty...*/ +} __attribute__((packed)); + +#endif /* __METADATA_LAYOUT_COLLISION_H__ */ diff --git a/src/metadata/layout/core.h b/src/metadata/layout/core.h new file mode 100644 index 00000000..814ac77d --- /dev/null +++ b/src/metadata/layout/core.h @@ -0,0 +1,68 @@ +/* + * Copyright(c) 2012-2021 Intel Corporation + * Copyright(c) 2026 Unvertical + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef __METADATA_LAYOUT_CORE_H__ +#define __METADATA_LAYOUT_CORE_H__ + +#include "ocf/ocf.h" + +struct ocf_metadata_uuid { + uint32_t size; + uint8_t data[OCF_VOLUME_UUID_MAX_SIZE]; +} __packed; + +struct ocf_core_meta_config { + char name[OCF_CORE_NAME_SIZE]; + + uint8_t type; + + /* This bit means that object was saved in cache metadata */ + uint32_t valid : 1; + + /* Core sequence number used to correlate cache lines with cores + * when recovering from atomic device + */ + ocf_seq_no_t seq_no; + + /* Sequential cutoff threshold (in bytes) */ + env_atomic seq_cutoff_threshold; + + /* Sequential cutoff policy */ + env_atomic seq_cutoff_policy; + + /* Sequence detector stream promotion request count */ + env_atomic seq_detect_promotion_count; + + /* Sequence detector stream promotion threshold (in bytes) */ + env_atomic seq_detect_promotion_threshold; + + /* core object size in bytes */ + uint64_t length; + + uint8_t user_data[OCF_CORE_USER_DATA_SIZE]; +}; + +struct ocf_core_meta_runtime { + /* Number of blocks from that objects that currently are cached + * on the caching device. + */ + env_atomic cached_clines; + env_atomic dirty_clines; + env_atomic initial_dirty_clines; + + env_atomic64 dirty_since; + + struct { + /* clines within lru list (?) */ + env_atomic cached_clines; + /* dirty clines assigned to this specific partition within + * cache device + */ + env_atomic dirty_clines; + } part_counters[OCF_USER_IO_CLASS_MAX]; +}; + +#endif /* __METADATA_LAYOUT_CORE_H__ */ diff --git a/src/metadata/metadata_layout.c b/src/metadata/layout/layout.c similarity index 97% rename from src/metadata/metadata_layout.c rename to src/metadata/layout/layout.c index 2a20e30e..88376ca5 100644 --- a/src/metadata/metadata_layout.c +++ b/src/metadata/layout/layout.c @@ -4,14 +4,14 @@ * SPDX-License-Identifier: BSD-3-Clause */ -#include "metadata_layout.h" -#include "metadata_bit.h" -#include "metadata_cleaning_policy.h" -#include "metadata_collision.h" -#include "metadata_core.h" -#include "metadata_lru.h" -#include "metadata_partition.h" -#include "metadata_superblock.h" +#include "layout.h" +#include "status.h" +#include "cleaning_policy.h" +#include "collision.h" +#include "core.h" +#include "lru.h" +#include "partition.h" +#include "superblock.h" #define OCF_METADATA_LAYOUT_ITER_MAX 1000 diff --git a/src/metadata/metadata_layout.h b/src/metadata/layout/layout.h similarity index 99% rename from src/metadata/metadata_layout.h rename to src/metadata/layout/layout.h index c1b35707..1aaca92e 100644 --- a/src/metadata/metadata_layout.h +++ b/src/metadata/layout/layout.h @@ -8,8 +8,8 @@ #define __METADATA_LAYOUT_H__ #include "ocf/ocf.h" -#include "../ocf_def_priv.h" -#include "metadata_segment_id.h" +#include "../../ocf_def_priv.h" +#include "segment_id.h" /* * On-disk metadata layout. diff --git a/src/metadata/layout/lru.h b/src/metadata/layout/lru.h new file mode 100644 index 00000000..66698979 --- /dev/null +++ b/src/metadata/layout/lru.h @@ -0,0 +1,38 @@ +/* + * Copyright(c) 2012-2021 Intel Corporation + * Copyright(c) 2022-2023 Huawei Technologies + * Copyright(c) 2026 Unvertical + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef __METADATA_LAYOUT_LRU_H__ +#define __METADATA_LAYOUT_LRU_H__ + +#include "ocf/ocf.h" + +#define OCF_NUM_LRU_LISTS 32 + +struct ocf_lru_meta { + uint64_t prev : OCF_CACHE_LINE_BITS; + uint64_t unused : 3; + uint64_t next : OCF_CACHE_LINE_BITS; + uint64_t hot : 1; + uint64_t unused2 : 2; + ocf_part_id_t partition_id : 8; +} __attribute__((packed)); + +struct ocf_lru_list { + uint32_t num_nodes; + uint32_t head : OCF_CACHE_LINE_BITS; + uint32_t tail : OCF_CACHE_LINE_BITS; + uint32_t num_hot; + uint32_t last_hot : OCF_CACHE_LINE_BITS; + bool track_hot; +}; + +struct ocf_lru_part_meta { + struct ocf_lru_list clean; + struct ocf_lru_list dirty; +}; + +#endif /* __METADATA_LAYOUT_LRU_H__ */ diff --git a/src/metadata/layout/partition.h b/src/metadata/layout/partition.h new file mode 100644 index 00000000..0991b84d --- /dev/null +++ b/src/metadata/layout/partition.h @@ -0,0 +1,46 @@ +/* + * Copyright(c) 2012-2021 Intel Corporation + * Copyright(c) 2024 Huawei Technologies Co., Ltd. + * Copyright(c) 2026 Unvertical + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef __METADATA_LAYOUT_PARTITION_H__ +#define __METADATA_LAYOUT_PARTITION_H__ + +#include "ocf/ocf.h" +#include "lru.h" +#include "cleaning_policy.h" + +#define PARTITION_UNSPECIFIED ((ocf_part_id_t)-1) +#define PARTITION_FREELIST (OCF_USER_IO_CLASS_MAX + 1) +#define PARTITION_FREE_DETACHED (OCF_USER_IO_CLASS_MAX + 2) +#define PARTITION_SIZE_MIN 0 +#define PARTITION_SIZE_MAX 100 + +#define OCF_NUM_PARTITIONS (OCF_USER_IO_CLASS_MAX + 3) + +struct ocf_user_part_config { + char name[OCF_IO_CLASS_NAME_MAX]; + uint32_t min_size; + uint32_t max_size; + struct { + uint8_t valid : 1; + uint8_t added : 1; + uint8_t eviction : 1; + /*!< This bits is setting during partition sorting, + * and means that can evict from this partition + */ + } flags; + int16_t priority; + ocf_cache_mode_t cache_mode; +}; + +struct ocf_part_runtime { + env_atomic curr_size; + env_atomic evict_counter; + struct ocf_lru_part_meta lru[OCF_NUM_LRU_LISTS]; + struct cleaning_policy clean_pol; +}; + +#endif /* __METADATA_LAYOUT_PARTITION_H__ */ diff --git a/src/metadata/layout/prefetch_policy.h b/src/metadata/layout/prefetch_policy.h new file mode 100644 index 00000000..1e4344cf --- /dev/null +++ b/src/metadata/layout/prefetch_policy.h @@ -0,0 +1,26 @@ +/* + * Copyright(c) 2022-2024 Huawei Technologies + * Copyright(c) 2026 Unvertical + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef __METADATA_LAYOUT_PREFETCH_POLICY_H__ +#define __METADATA_LAYOUT_PREFETCH_POLICY_H__ + +#include "ocf/ocf.h" +#include "ocf/ocf_prefetch.h" + +/* Prefetch policy configuration (stored in superblock) */ + +#define PREFETCH_POLICY_CONFIG_BYTES 256 +#define PREFETCH_POLICY_TYPE_MAX ((int)ocf_pf_num) + +struct prefetch_policy_config { + uint8_t data[PREFETCH_POLICY_CONFIG_BYTES]; +} __attribute__((aligned(4))); + +struct readahead_prefetch_policy_config { + uint32_t threshold; /* in bytes */ +}; + +#endif /* __METADATA_LAYOUT_PREFETCH_POLICY_H__ */ diff --git a/src/metadata/layout/promotion_policy.h b/src/metadata/layout/promotion_policy.h new file mode 100644 index 00000000..a8673ace --- /dev/null +++ b/src/metadata/layout/promotion_policy.h @@ -0,0 +1,29 @@ +/* + * Copyright(c) 2012-2021 Intel Corporation + * Copyright(c) 2026 Unvertical + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef __METADATA_LAYOUT_PROMOTION_POLICY_H__ +#define __METADATA_LAYOUT_PROMOTION_POLICY_H__ + +#include "ocf/ocf.h" + +/* Promotion policy configuration (stored in superblock) */ + +#define PROMOTION_POLICY_CONFIG_BYTES 256 +#define PROMOTION_POLICY_TYPE_MAX 2 + +struct promotion_policy_config { + uint8_t data[PROMOTION_POLICY_CONFIG_BYTES]; +} __attribute__((aligned(4))); + +struct nhit_promotion_policy_config { + uint32_t insertion_threshold; + /*!< Number of hits */ + + uint32_t trigger_threshold; + /*!< Cache occupancy (percentage value) */ +}; + +#endif /* __METADATA_LAYOUT_PROMOTION_POLICY_H__ */ diff --git a/src/metadata/metadata_segment_id.h b/src/metadata/layout/segment_id.h similarity index 91% rename from src/metadata/metadata_segment_id.h rename to src/metadata/layout/segment_id.h index 411be1a4..bca933a5 100644 --- a/src/metadata/metadata_segment_id.h +++ b/src/metadata/layout/segment_id.h @@ -4,8 +4,8 @@ * SPDX-License-Identifier: BSD-3-Clause */ -#ifndef __METADATA_SEGMENT_ID_H__ -#define __METADATA_SEGMENT_ID_H__ +#ifndef __METADATA_LAYOUT_SEGMENT_ID_H__ +#define __METADATA_LAYOUT_SEGMENT_ID_H__ /** * @file metadata_.h @@ -41,4 +41,4 @@ enum ocf_metadata_segment_id { metadata_segment_max, /*!< MAX */ }; -#endif /* __METADATA_SEGMENT_ID_H__ */ +#endif /* __METADATA_LAYOUT_SEGMENT_ID_H__ */ diff --git a/src/metadata/metadata_bit.h b/src/metadata/layout/status.h similarity index 98% rename from src/metadata/metadata_bit.h rename to src/metadata/layout/status.h index 01ccaf81..d6cca1b7 100644 --- a/src/metadata/metadata_bit.h +++ b/src/metadata/layout/status.h @@ -5,10 +5,10 @@ * SPDX-License-Identifier: BSD-3-Clause */ -#ifndef __METADATA_BIT_H__ -#define __METADATA_BIT_H__ +#ifndef __METADATA_LAYOUT_STATUS_H__ +#define __METADATA_LAYOUT_STATUS_H__ -#include "metadata_collision.h" +#include "collision.h" /* * Cache line status bits (valid, dirty) stored in collision segment. @@ -549,4 +549,4 @@ static inline bool ocf_metadata_bit_check( return false; } -#endif /* __METADATA_BIT_H__ */ +#endif /* __METADATA_LAYOUT_STATUS_H__ */ diff --git a/src/metadata/layout/superblock.h b/src/metadata/layout/superblock.h new file mode 100644 index 00000000..9f58ca0c --- /dev/null +++ b/src/metadata/layout/superblock.h @@ -0,0 +1,103 @@ +/* + * Copyright(c) 2012-2022 Intel Corporation + * Copyright(c) 2024 Huawei Technologies + * Copyright(c) 2026 Unvertical + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef __METADATA_LAYOUT_SUPERBLOCK_H__ +#define __METADATA_LAYOUT_SUPERBLOCK_H__ + +#include "ocf/ocf.h" +#include "../../ocf_def_priv.h" +#include "segment_id.h" +#include "cleaning_policy.h" +#include "promotion_policy.h" +#include "prefetch_policy.h" + +#define CACHE_MAGIC_NUMBER 0x187E1CA6 + +/** + * @brief Metadata shutdown status + */ +enum ocf_metadata_shutdown_status { + ocf_metadata_dirty_shutdown = 0, /*!< Dirty OCF shutdown*/ + ocf_metadata_clean_shutdown = 1, /*!< OCF shutdown graceful*/ +}; + +/** + * @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 { + /* Superblock header */ + struct { + uint8_t clean_shutdown; + uint8_t dirty_flushed; + uint16_t _padding; + uint32_t magic_number; + uint32_t metadata_version; + }; + + /* Identity of the adapter */ + char adapter_name[OCF_ADAPTER_NAME_SIZE]; + uint32_t adapter_version; + + bool metadata_4k_mode; + + unsigned flapping_idx; + + /* Currently set cache mode */ + ocf_cache_mode_t cache_mode; + + char name[OCF_CACHE_NAME_SIZE]; + + ocf_cache_line_t cachelines; + uint32_t valid_parts_no; + + 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)]; + + bool cleaner_disabled; + ocf_cleaning_t cleaning_policy_type; + struct cleaning_policy_config cleaning[CLEANING_POLICY_TYPE_MAX]; + + ocf_promotion_t promotion_policy_type; + struct promotion_policy_config promotion[PROMOTION_POLICY_TYPE_MAX]; + + ocf_pf_mask_t prefetch_mask; + struct prefetch_policy_config prefetch[PREFETCH_POLICY_TYPE_MAX]; + + /* + * Checksum for each metadata region. + * This field has to be the last one! + */ + uint32_t checksum[metadata_segment_max]; +}; + +/** + * @brief OCF cache metadata runtime superblock + */ +struct ocf_superblock_runtime { + uint32_t cleaning_thread_access; +}; + +#endif /* __METADATA_LAYOUT_SUPERBLOCK_H__ */ diff --git a/src/metadata/metadata.c b/src/metadata/metadata.c index 3cb584df..e22d5815 100644 --- a/src/metadata/metadata.c +++ b/src/metadata/metadata.c @@ -8,11 +8,11 @@ #include "ocf/ocf.h" #include "metadata.h" -#include "metadata_bit.h" +#include "layout/status.h" #include "metadata_collision.h" -#include "metadata_segment_id.h" +#include "layout/segment_id.h" #include "metadata_internal.h" -#include "metadata_layout.h" +#include "layout/layout.h" #include "metadata_io.h" #include "metadata_raw.h" #include "metadata_segment.h" diff --git a/src/metadata/metadata.h b/src/metadata/metadata.h index f8939034..59a533d6 100644 --- a/src/metadata/metadata.h +++ b/src/metadata/metadata.h @@ -12,7 +12,7 @@ #include "metadata_cleaning_policy.h" #include "metadata_lru.h" #include "metadata_partition.h" -#include "metadata_segment_id.h" +#include "layout/segment_id.h" #include "metadata_superblock.h" #include "metadata_status.h" #include "metadata_collision.h" diff --git a/src/metadata/metadata_cleaning_policy.h b/src/metadata/metadata_cleaning_policy.h index a3f9bfe2..4878b498 100644 --- a/src/metadata/metadata_cleaning_policy.h +++ b/src/metadata/metadata_cleaning_policy.h @@ -8,80 +8,10 @@ #define __METADATA_CLEANING_POLICY_H__ #include "ocf/ocf.h" - -/* Cleaning policy configuration (stored in superblock) */ - -#define CLEANING_POLICY_CONFIG_BYTES 256 -#define CLEANING_POLICY_TYPE_MAX 4 - -struct cleaning_policy_config { - uint8_t data[CLEANING_POLICY_CONFIG_BYTES]; -} __attribute__((aligned(4))); - -struct alru_cleaning_policy_config { - uint32_t thread_wakeup_time; /* in seconds */ - uint32_t stale_buffer_time; /* in seconds */ - uint32_t flush_max_buffers; /* in lines */ - uint32_t activity_threshold; /* in milliseconds */ - uint32_t dirty_ratio_threshold; /* percent */ - uint32_t dirty_ratio_inertia; /* bytes */ -}; - -struct acp_cleaning_policy_config { - uint32_t thread_wakeup_time; /* in milliseconds*/ - uint32_t flush_max_buffers; /* in lines */ -}; - -/* Cleaning policy metadata per partition */ - -struct nop_cleaning_policy { -}; - -struct alru_cleaning_policy { - env_atomic size; - uint32_t lru_head; - uint32_t lru_tail; -}; - -struct acp_cleaning_policy { -}; - -struct cleaning_policy { - union { - struct nop_cleaning_policy nop; - struct alru_cleaning_policy alru; - struct acp_cleaning_policy acp; - } policy; -}; - -/* Cleaning policy metadata per cache line */ - -struct nop_cleaning_policy_meta { -} __attribute__((packed)); - -struct alru_cleaning_policy_meta { - /* Lru pointers 2*4=8 bytes */ - uint32_t timestamp; - uint32_t lru_prev; - uint32_t lru_next; -} __attribute__((packed)); - -/* TODO: remove acp metadata */ -struct acp_cleaning_policy_meta { - uint8_t dirty : 1; -}; - -struct cleaning_policy_meta { - union { - struct nop_cleaning_policy_meta nop; - struct alru_cleaning_policy_meta alru; - struct acp_cleaning_policy_meta acp; - } meta; -}; +#include "layout/cleaning_policy.h" struct cleaning_policy_meta * ocf_metadata_get_cleaning_policy(struct ocf_cache *cache, ocf_cache_line_t line); - #endif /* __METADATA_CLEANING_POLICY_H__ */ diff --git a/src/metadata/metadata_collision.h b/src/metadata/metadata_collision.h index d2a0c5ef..9f33dc99 100644 --- a/src/metadata/metadata_collision.h +++ b/src/metadata/metadata_collision.h @@ -8,98 +8,8 @@ #ifndef __METADATA_COLLISION_H__ #define __METADATA_COLLISION_H__ -#include "../ocf_def_priv.h" - -/** - * @brief Metadata map structure - */ - -struct ocf_metadata_list_info { - union { - struct { - /* Previous cache line in collision list */ - ocf_cache_line_t prev_col : OCF_CACHE_LINE_BITS; - ocf_cache_line_t unused : 3; - /* Next cache line in collision list*/ - ocf_cache_line_t next_col : OCF_CACHE_LINE_BITS; - ocf_cache_line_t unused2 : 3; - } __attribute__((packed)); - uint64_t entry; - }; -}; - -/* Keep the struct ocf_metadata_list_info size of 8 bytes */ -_Static_assert(sizeof(struct ocf_metadata_list_info) == sizeof(uint64_t), - "Size of struct ocf_metadata_list_info is not equal to 8 bytes"); - -struct ocf_hash_entry { - union { - struct { - uint32_t line : OCF_CACHE_LINE_BITS; - /* Hash lock bits */ - uint32_t rd : 2; - uint32_t wr : 1; - }; - uint32_t raw; - }; -}; - -/** - * @brief Hash bucket of core line - * - * Hash function intentionally returns consecutive (modulo @hash_entries) - * values for consecutive @core_line. This way it is trivial to sort all - * core lines within a single request in ascending hash value order. This kind - * of sorting is required to assure that (future) hash bucket metadata locks are - * always acquired in fixed order, eliminating the risk of dead locks. - * - * @param hash_entries - Number of entries in hash segment - * @param core_line - Core line number - * @param core_id - Core id - */ -static inline ocf_cache_line_t ocf_metadata_collision_hash( - ocf_cache_line_t hash_entries, uint64_t core_line, - ocf_core_id_t core_id) -{ - return (ocf_cache_line_t) ((core_line + (core_id * (hash_entries / 32))) - % hash_entries); -} - -/** - * @brief Hash bucket following given one - * - * @param hash_entries - Number of entries in hash segment - * @param hash - Hash bucket - */ -static inline ocf_cache_line_t ocf_metadata_collision_hash_next( - ocf_cache_line_t hash_entries, ocf_cache_line_t hash) -{ - hash++; - return likely(hash < hash_entries) ? hash : 0; -} - -/** - * @brief Metadata map structure - */ - -struct ocf_metadata_map { - uint64_t core_line : OCF_CORE_LINE_BITS; - /*!< Core line addres on cache mapped by this strcture */ - - uint64_t core_id : OCF_CORE_ID_BITS; - /*!< ID of core where is assigned this cache line*/ - -#ifdef OCF_BLOCK_SIZE_4K - uint64_t _valid : 1; - /*!< valid bit for 4K cache line */ - - uint64_t _dirty : 1; - /*!< dirty bit for 4K cache line */ -#endif - - uint8_t status[]; - /*!< Entry status structure e.g. valid, dirty...*/ -} __attribute__((packed)); +#include "ocf/ocf.h" +#include "layout/collision.h" void ocf_metadata_set_collision_info( struct ocf_cache *cache, ocf_cache_line_t line, diff --git a/src/metadata/metadata_core.h b/src/metadata/metadata_core.h index db106a0d..f02bc2c6 100644 --- a/src/metadata/metadata_core.h +++ b/src/metadata/metadata_core.h @@ -8,61 +8,7 @@ #define __METADATA_CORE_H__ #include "ocf/ocf.h" - -struct ocf_metadata_uuid { - uint32_t size; - uint8_t data[OCF_VOLUME_UUID_MAX_SIZE]; -} __packed; - -struct ocf_core_meta_config { - char name[OCF_CORE_NAME_SIZE]; - - uint8_t type; - - /* This bit means that object was saved in cache metadata */ - uint32_t valid : 1; - - /* Core sequence number used to correlate cache lines with cores - * when recovering from atomic device */ - ocf_seq_no_t seq_no; - - /* Sequential cutoff threshold (in bytes) */ - env_atomic seq_cutoff_threshold; - - /* Sequential cutoff policy */ - env_atomic seq_cutoff_policy; - - /* Sequence detector stream promotion request count */ - env_atomic seq_detect_promotion_count; - - /* Sequence detector stream promotion threshold (in bytes) */ - env_atomic seq_detect_promotion_threshold; - - /* core object size in bytes */ - uint64_t length; - - uint8_t user_data[OCF_CORE_USER_DATA_SIZE]; -}; - -struct ocf_core_meta_runtime { - /* Number of blocks from that objects that currently are cached - * on the caching device. - */ - env_atomic cached_clines; - env_atomic dirty_clines; - env_atomic initial_dirty_clines; - - env_atomic64 dirty_since; - - struct { - /* clines within lru list (?) */ - env_atomic cached_clines; - /* dirty clines assigned to this specific partition within - * cache device - */ - env_atomic dirty_clines; - } part_counters[OCF_USER_IO_CLASS_MAX]; -}; +#include "layout/core.h" struct ocf_metadata_uuid *ocf_metadata_get_core_uuid( struct ocf_cache *cache, ocf_core_id_t core_id); diff --git a/src/metadata/metadata_internal.h b/src/metadata/metadata_internal.h index 9910a346..60c1a2c9 100644 --- a/src/metadata/metadata_internal.h +++ b/src/metadata/metadata_internal.h @@ -11,9 +11,9 @@ #include #include "../ocf_cache_priv.h" #include "metadata_segment.h" -#include "metadata_segment_id.h" +#include "layout/segment_id.h" #include "metadata_raw.h" -#include "metadata_layout.h" +#include "layout/layout.h" #define METADATA_MEM_POOL(ctrl, section) ctrl->raw_desc[section].mem_pool diff --git a/src/metadata/metadata_lru.h b/src/metadata/metadata_lru.h index 58d17284..4f462d84 100644 --- a/src/metadata/metadata_lru.h +++ b/src/metadata/metadata_lru.h @@ -9,31 +9,7 @@ #define __METADATA_LRU_H__ #include "ocf/ocf.h" - -#define OCF_NUM_LRU_LISTS 32 - -struct ocf_lru_meta { - uint64_t prev : OCF_CACHE_LINE_BITS; - uint64_t unused : 3; - uint64_t next : OCF_CACHE_LINE_BITS; - uint64_t hot : 1; - uint64_t unused2 : 2; - ocf_part_id_t partition_id : 8; -} __attribute__((packed)); - -struct ocf_lru_list { - uint32_t num_nodes; - uint32_t head : OCF_CACHE_LINE_BITS; - uint32_t tail : OCF_CACHE_LINE_BITS; - uint32_t num_hot; - uint32_t last_hot : OCF_CACHE_LINE_BITS; - bool track_hot; -}; - -struct ocf_lru_part_meta { - struct ocf_lru_list clean; - struct ocf_lru_list dirty; -}; +#include "layout/lru.h" struct ocf_lru_meta * ocf_metadata_get_lru( diff --git a/src/metadata/metadata_partition.h b/src/metadata/metadata_partition.h index 2755743d..a9c1cc2e 100644 --- a/src/metadata/metadata_partition.h +++ b/src/metadata/metadata_partition.h @@ -9,39 +9,7 @@ #define __METADATA_PARTITION_H__ #include "ocf/ocf.h" -#include "metadata_lru.h" -#include "metadata_cleaning_policy.h" - -#define PARTITION_UNSPECIFIED ((ocf_part_id_t)-1) -#define PARTITION_FREELIST (OCF_USER_IO_CLASS_MAX + 1) -#define PARTITION_FREE_DETACHED (OCF_USER_IO_CLASS_MAX + 2) -#define PARTITION_SIZE_MIN 0 -#define PARTITION_SIZE_MAX 100 - -#define OCF_NUM_PARTITIONS (OCF_USER_IO_CLASS_MAX + 3) - -struct ocf_user_part_config { - char name[OCF_IO_CLASS_NAME_MAX]; - uint32_t min_size; - uint32_t max_size; - struct { - uint8_t valid : 1; - uint8_t added : 1; - uint8_t eviction : 1; - /*!< This bits is setting during partition sorting, - * and means that can evict from this partition - */ - } flags; - int16_t priority; - ocf_cache_mode_t cache_mode; -}; - -struct ocf_part_runtime { - env_atomic curr_size; - env_atomic evict_counter; - struct ocf_lru_part_meta lru[OCF_NUM_LRU_LISTS]; - struct cleaning_policy clean_pol; -}; +#include "layout/partition.h" ocf_part_id_t ocf_metadata_get_partition_id(struct ocf_cache *cache, ocf_cache_line_t line); diff --git a/src/metadata/metadata_passive_update.c b/src/metadata/metadata_passive_update.c index fbc9110f..e34b98a8 100644 --- a/src/metadata/metadata_passive_update.c +++ b/src/metadata/metadata_passive_update.c @@ -10,7 +10,7 @@ #include "metadata.h" #include "metadata_passive_update.h" #include "metadata_collision.h" -#include "metadata_segment_id.h" +#include "layout/segment_id.h" #include "metadata_internal.h" #include "metadata_io.h" #include "metadata_raw.h" diff --git a/src/metadata/metadata_prefetch_policy.h b/src/metadata/metadata_prefetch_policy.h index e228ce50..281f7bd2 100644 --- a/src/metadata/metadata_prefetch_policy.h +++ b/src/metadata/metadata_prefetch_policy.h @@ -7,20 +7,6 @@ #ifndef __METADATA_PREFETCH_POLICY_H__ #define __METADATA_PREFETCH_POLICY_H__ -#include "ocf/ocf.h" -#include "ocf/ocf_prefetch.h" - -/* Prefetch policy configuration (stored in superblock) */ - -#define PREFETCH_POLICY_CONFIG_BYTES 256 -#define PREFETCH_POLICY_TYPE_MAX ((int)ocf_pf_num) - -struct prefetch_policy_config { - uint8_t data[PREFETCH_POLICY_CONFIG_BYTES]; -} __attribute__((aligned(4))); - -struct readahead_prefetch_policy_config { - uint32_t threshold; /* in bytes */ -}; +#include "layout/prefetch_policy.h" #endif /* __METADATA_PREFETCH_POLICY_H__ */ diff --git a/src/metadata/metadata_promotion_policy.h b/src/metadata/metadata_promotion_policy.h index 5af84b5b..78a7f112 100644 --- a/src/metadata/metadata_promotion_policy.h +++ b/src/metadata/metadata_promotion_policy.h @@ -7,23 +7,6 @@ #ifndef __METADATA_PROMOTION_POLICY_H__ #define __METADATA_PROMOTION_POLICY_H__ -#include "ocf/ocf.h" - -/* Promotion policy configuration (stored in superblock) */ - -#define PROMOTION_POLICY_CONFIG_BYTES 256 -#define PROMOTION_POLICY_TYPE_MAX 2 - -struct promotion_policy_config { - uint8_t data[PROMOTION_POLICY_CONFIG_BYTES]; -} __attribute__((aligned(4))); - -struct nhit_promotion_policy_config { - uint32_t insertion_threshold; - /*!< Number of hits */ - - uint32_t trigger_threshold; - /*!< Cache occupancy (percentage value) */ -}; +#include "layout/promotion_policy.h" #endif /* __METADATA_PROMOTION_POLICY_H__ */ diff --git a/src/metadata/metadata_raw.c b/src/metadata/metadata_raw.c index 916ddf08..7e2d233a 100644 --- a/src/metadata/metadata_raw.c +++ b/src/metadata/metadata_raw.c @@ -6,9 +6,9 @@ */ #include "metadata.h" -#include "metadata_segment_id.h" +#include "layout/segment_id.h" #include "metadata_raw.h" -#include "metadata_layout.h" +#include "layout/layout.h" #include "metadata_io.h" #include "metadata_raw_atomic.h" #include "../ocf_def_priv.h" diff --git a/src/metadata/metadata_raw.h b/src/metadata/metadata_raw.h index cebc4d3c..225e40c6 100644 --- a/src/metadata/metadata_raw.h +++ b/src/metadata/metadata_raw.h @@ -8,8 +8,8 @@ #define __METADATA_RAW_H__ #include "metadata_common.h" -#include "metadata_segment_id.h" -#include "metadata_layout.h" +#include "layout/segment_id.h" +#include "layout/layout.h" #include "../concurrency/ocf_mio_concurrency.h" /** diff --git a/src/metadata/metadata_raw_atomic.c b/src/metadata/metadata_raw_atomic.c index 257b053c..040b6b71 100644 --- a/src/metadata/metadata_raw_atomic.c +++ b/src/metadata/metadata_raw_atomic.c @@ -7,7 +7,7 @@ #include "metadata.h" #include "metadata_io.h" -#include "metadata_segment_id.h" +#include "layout/segment_id.h" #include "metadata_raw.h" #include "metadata_raw_atomic.h" #include "../utils/utils_cache_line.h" diff --git a/src/metadata/metadata_raw_dynamic.c b/src/metadata/metadata_raw_dynamic.c index 224b2d55..7119d30d 100644 --- a/src/metadata/metadata_raw_dynamic.c +++ b/src/metadata/metadata_raw_dynamic.c @@ -6,10 +6,10 @@ */ #include "metadata.h" -#include "metadata_segment_id.h" +#include "layout/segment_id.h" #include "metadata_raw.h" #include "metadata_raw_dynamic.h" -#include "metadata_layout.h" +#include "layout/layout.h" #include "metadata_io.h" #include "../ocf_request.h" #include "../ocf_def_priv.h" diff --git a/src/metadata/metadata_raw_volatile.c b/src/metadata/metadata_raw_volatile.c index 8a4a720c..4dc3e72e 100644 --- a/src/metadata/metadata_raw_volatile.c +++ b/src/metadata/metadata_raw_volatile.c @@ -1,10 +1,11 @@ /* * Copyright(c) 2012-2021 Intel Corporation + * Copyright(c) 2026 Unvertical * SPDX-License-Identifier: BSD-3-Clause */ #include "metadata.h" -#include "metadata_segment_id.h" +#include "layout/segment_id.h" #include "metadata_raw.h" #include "metadata_io.h" #include "metadata_raw_volatile.h" diff --git a/src/metadata/metadata_superblock.c b/src/metadata/metadata_superblock.c index ddfda756..51638262 100644 --- a/src/metadata/metadata_superblock.c +++ b/src/metadata/metadata_superblock.c @@ -9,7 +9,7 @@ #include "metadata_core.h" #include "metadata_internal.h" #include "metadata_segment.h" -#include "metadata_segment_id.h" +#include "layout/segment_id.h" #include "metadata_superblock.h" #include "../ocf_priv.h" #include "../utils/utils_io.h" diff --git a/src/metadata/metadata_superblock.h b/src/metadata/metadata_superblock.h index d5a003ea..d352cdf0 100644 --- a/src/metadata/metadata_superblock.h +++ b/src/metadata/metadata_superblock.h @@ -9,97 +9,8 @@ #define __METADATA_SUPERBLOCK_H__ #include "ocf/ocf.h" -#include "../ocf_def_priv.h" #include "metadata_common.h" -#include "metadata_segment_id.h" -#include "metadata_cleaning_policy.h" -#include "metadata_promotion_policy.h" -#include "metadata_prefetch_policy.h" - -#define CACHE_MAGIC_NUMBER 0x187E1CA6 - -/** - * @brief Metadata shutdown status - */ -enum ocf_metadata_shutdown_status { - ocf_metadata_dirty_shutdown = 0, /*!< Dirty OCF shutdown*/ - ocf_metadata_clean_shutdown = 1, /*!< OCF shutdown graceful*/ -}; - -/** - * @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 { - /* Superblock header */ - struct { - uint8_t clean_shutdown; - uint8_t dirty_flushed; - uint16_t _padding; - uint32_t magic_number; - uint32_t metadata_version; - }; - - /* Identity of the adapter */ - char adapter_name[OCF_ADAPTER_NAME_SIZE]; - uint32_t adapter_version; - - bool metadata_4k_mode; - - unsigned flapping_idx; - - /* Currently set cache mode */ - ocf_cache_mode_t cache_mode; - - char name[OCF_CACHE_NAME_SIZE]; - - ocf_cache_line_t cachelines; - uint32_t valid_parts_no; - - 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)]; - - bool cleaner_disabled; - ocf_cleaning_t cleaning_policy_type; - struct cleaning_policy_config cleaning[CLEANING_POLICY_TYPE_MAX]; - - ocf_promotion_t promotion_policy_type; - struct promotion_policy_config promotion[PROMOTION_POLICY_TYPE_MAX]; - - ocf_pf_mask_t prefetch_mask; - struct prefetch_policy_config prefetch[PREFETCH_POLICY_TYPE_MAX]; - - /* - * Checksum for each metadata region. - * This field has to be the last one! - */ - uint32_t checksum[metadata_segment_max]; -}; - -/** - * @brief OCF cache metadata runtime superblock - */ -struct ocf_superblock_runtime { - uint32_t cleaning_thread_access; -}; +#include "layout/superblock.h" struct ocf_metadata_ctrl; struct ocf_metadata_segment; From eaeaa2e8fa9918eb8f44d935fd2ab2002ddb715a Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Wed, 14 Oct 2026 20:46:30 +0200 Subject: [PATCH 4/9] metadata: Add to layout definitions needed to interpret the metadata Signed-off-by: Robert Baldyga --- src/metadata/layout/layout.c | 48 ++++++++++++++++++++++++++++++++ src/metadata/layout/layout.h | 47 +++++++++++++++++++++++++++++++ src/metadata/layout/superblock.h | 6 ++++ src/ocf_cache_priv.h | 3 -- 4 files changed, 101 insertions(+), 3 deletions(-) diff --git a/src/metadata/layout/layout.c b/src/metadata/layout/layout.c index 88376ca5..8b042caa 100644 --- a/src/metadata/layout/layout.c +++ b/src/metadata/layout/layout.c @@ -139,6 +139,54 @@ uint32_t ocf_metadata_segment_layout_entry_size( return size; } +enum ocf_metadata_segment_persistence ocf_metadata_segment_layout_persistence( + enum ocf_metadata_segment_id segment) +{ + switch (segment) { + case metadata_segment_reserved: + return ocf_metadata_segment_persistence_none; + + case metadata_segment_sb_config: + case metadata_segment_part_config: + case metadata_segment_core_config: + case metadata_segment_core_uuid: + return ocf_metadata_segment_persistence_config; + + case metadata_segment_sb_runtime: + case metadata_segment_part_runtime: + case metadata_segment_core_runtime: + case metadata_segment_cleaning: + case metadata_segment_lru: + case metadata_segment_list_info: + case metadata_segment_hash: + return ocf_metadata_segment_persistence_shutdown; + + case metadata_segment_collision: + return ocf_metadata_segment_persistence_io; + + default: + break; + } + + ENV_BUG(); + return ocf_metadata_segment_persistence_none; +} + +bool ocf_metadata_segment_layout_is_valid( + enum ocf_metadata_segment_id segment, bool clean_shutdown) +{ + switch (ocf_metadata_segment_layout_persistence(segment)) { + case ocf_metadata_segment_persistence_config: + case ocf_metadata_segment_persistence_io: + return true; + case ocf_metadata_segment_persistence_shutdown: + return clean_shutdown; + case ocf_metadata_segment_persistence_none: + default: + return false; + } +} + bool ocf_metadata_segment_layout_is_flapped( enum ocf_metadata_segment_id segment) { diff --git a/src/metadata/layout/layout.h b/src/metadata/layout/layout.h index 1aaca92e..2b6151a0 100644 --- a/src/metadata/layout/layout.h +++ b/src/metadata/layout/layout.h @@ -87,6 +87,53 @@ uint32_t ocf_metadata_segment_layout_entry_size( enum ocf_metadata_segment_id segment, ocf_cache_line_size_t line_size); +/** + * @brief When content of metadata segment is written to disk + * + * Superblock config holds checksums of all other segments. Checksum of + * segment is meaningful only if segment content on disk is valid in current + * state of metadata. + */ +enum ocf_metadata_segment_persistence { + ocf_metadata_segment_persistence_none, + /*!< Content on disk has no meaning */ + + ocf_metadata_segment_persistence_config, + /*!< Written on every superblock flush, together with + * superblock config. Content and checksum are valid regardless + * of shutdown status. + */ + + ocf_metadata_segment_persistence_shutdown, + /*!< Written on clean shutdown. Content and checksum are + * valid only if superblock indicates clean shutdown. + */ + + ocf_metadata_segment_persistence_io, + /*!< Updated on disk during cache operation and written on + * clean shutdown. Content is valid regardless of shutdown + * status, checksum is valid only if superblock indicates + * clean shutdown. On atomic cache device the content is kept + * up to date in per-sector metadata (struct + * ocf_atomic_metadata) instead of the segment itself. + */ +}; + +/** + * @brief Persistence of metadata segment + */ +enum ocf_metadata_segment_persistence ocf_metadata_segment_layout_persistence( + enum ocf_metadata_segment_id segment); + +/** + * @brief Check if content of metadata segment on disk is valid + * + * @param segment - Segment id + * @param clean_shutdown - Superblock config indicates clean shutdown + */ +bool ocf_metadata_segment_layout_is_valid( + enum ocf_metadata_segment_id segment, bool clean_shutdown); + /** * @brief Check if metadata segment is stored in two copies */ diff --git a/src/metadata/layout/superblock.h b/src/metadata/layout/superblock.h index 9f58ca0c..77e5c1d9 100644 --- a/src/metadata/layout/superblock.h +++ b/src/metadata/layout/superblock.h @@ -25,6 +25,12 @@ enum ocf_metadata_shutdown_status { ocf_metadata_clean_shutdown = 1, /*!< OCF shutdown graceful*/ }; +/* + * Values of dirty_flushed field of superblock config + */ +#define DIRTY_NOT_FLUSHED 0 +#define DIRTY_FLUSHED 1 + /** * @brief OCF cache metadata configuration superblock * diff --git a/src/ocf_cache_priv.h b/src/ocf_cache_priv.h index ac0c8634..1b8f82f4 100644 --- a/src/ocf_cache_priv.h +++ b/src/ocf_cache_priv.h @@ -24,9 +24,6 @@ #include "ocf_queue_priv.h" #include "promotion/promotion.h" -#define DIRTY_FLUSHED 1 -#define DIRTY_NOT_FLUSHED 0 - /* Cache device */ struct ocf_cache_device { struct ocf_volume front_volume; From 75379a16576ae1034a3aacee5ad602bc6d212646 Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Wed, 14 Oct 2026 23:45:59 +0200 Subject: [PATCH 5/9] metadata: Use layout information in superblock load Signed-off-by: Robert Baldyga --- src/metadata/metadata_internal.h | 1 + src/metadata/metadata_superblock.c | 84 ++++++++---------------------- 2 files changed, 24 insertions(+), 61 deletions(-) diff --git a/src/metadata/metadata_internal.h b/src/metadata/metadata_internal.h index 60c1a2c9..540ee0fb 100644 --- a/src/metadata/metadata_internal.h +++ b/src/metadata/metadata_internal.h @@ -32,6 +32,7 @@ struct ocf_metadata_context { ocf_pipeline_t pipeline; ocf_cache_t cache; struct ocf_metadata_ctrl *ctrl; + bool clean_shutdown; struct ocf_metadata_raw segment_copy[metadata_segment_fixed_size_max]; }; diff --git a/src/metadata/metadata_superblock.c b/src/metadata/metadata_superblock.c index 51638262..8eacf992 100644 --- a/src/metadata/metadata_superblock.c +++ b/src/metadata/metadata_superblock.c @@ -353,6 +353,16 @@ struct ocf_pipeline_arg ocf_metadata_load_sb_load_segment_args[] = { OCF_PL_ARG_TERMINATOR(), }; +static bool ocf_metadata_load_sb_segment_is_valid(ocf_pipeline_t pipeline, + void *priv, ocf_pipeline_arg_t arg) +{ + struct ocf_metadata_context *context = priv; + + return ocf_metadata_segment_layout_is_valid( + ocf_pipeline_arg_get_int(arg), + context->clean_shutdown); +} + struct ocf_pipeline_properties ocf_metadata_load_sb_pipeline_props = { .priv_size = sizeof(struct ocf_metadata_context), .finish = ocf_metadata_load_superblock_finish, @@ -362,9 +372,11 @@ struct ocf_pipeline_properties ocf_metadata_load_sb_pipeline_props = { OCF_PL_STEP_ARG_INT(ocf_metadata_load_segment, metadata_segment_sb_config), OCF_PL_STEP(_ocf_metadata_validate_superblock), - OCF_PL_STEP_FOREACH(ocf_metadata_load_segment, + OCF_PL_STEP_FOREACH_COND(ocf_metadata_load_sb_segment_is_valid, + ocf_metadata_load_segment, ocf_metadata_load_sb_load_segment_args), - OCF_PL_STEP_FOREACH(ocf_metadata_check_crc, + OCF_PL_STEP_FOREACH_COND(ocf_metadata_load_sb_segment_is_valid, + ocf_metadata_check_crc, ocf_metadata_load_sb_load_segment_args), OCF_PL_STEP(_ocf_metadata_validate_core_config), OCF_PL_STEP_TERMINATOR(), @@ -374,8 +386,8 @@ struct ocf_pipeline_properties ocf_metadata_load_sb_pipeline_props = { /* * Super Block - Load, This function has to prevent to pointers overwrite */ -void ocf_metadata_load_superblock(ocf_cache_t cache, ocf_metadata_end_t cmpl, - void *priv) +static void _ocf_metadata_load_superblock(ocf_cache_t cache, + bool clean_shutdown, ocf_metadata_end_t cmpl, void *priv) { struct ocf_metadata_context *context; ocf_pipeline_t pipeline; @@ -408,34 +420,16 @@ void ocf_metadata_load_superblock(ocf_cache_t cache, ocf_metadata_end_t cmpl, context->pipeline = pipeline; context->cache = cache; context->ctrl = cache->metadata.priv; + context->clean_shutdown = clean_shutdown; ocf_pipeline_next(pipeline); } -struct ocf_pipeline_arg ocf_metadata_load_sb_recov_load_segment_args[] = { - OCF_PL_ARG_INT(metadata_segment_part_config), - OCF_PL_ARG_INT(metadata_segment_core_config), - OCF_PL_ARG_INT(metadata_segment_core_uuid), - OCF_PL_ARG_TERMINATOR(), -}; - -struct ocf_pipeline_properties ocf_metadata_load_sb_recov_pipeline_props = { - .priv_size = sizeof(struct ocf_metadata_context), - .finish = ocf_metadata_load_superblock_finish, - .steps = { - OCF_PL_STEP_FOREACH(ocf_metadata_store_segment, - 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_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_validate_core_config), - OCF_PL_STEP_TERMINATOR(), - }, -}; +void ocf_metadata_load_superblock(ocf_cache_t cache, ocf_metadata_end_t cmpl, + void *priv) +{ + _ocf_metadata_load_superblock(cache, true, cmpl, priv); +} /* * Super Block - Recovery load @@ -443,39 +437,7 @@ struct ocf_pipeline_properties ocf_metadata_load_sb_recov_pipeline_props = { void ocf_metadata_load_superblock_recovery(ocf_cache_t cache, ocf_metadata_end_t cmpl, void *priv) { - struct ocf_metadata_context *context; - ocf_pipeline_t pipeline; - struct ocf_metadata_ctrl *ctrl; - struct ocf_superblock_config *sb_config; - struct ocf_superblock_runtime *sb_runtime; - int result; - - OCF_DEBUG_TRACE(cache); - - /* TODO: get ctrl from args rather than from cache */ - ctrl = cache->metadata.priv; - ENV_BUG_ON(!ctrl); - - sb_config = METADATA_MEM_POOL(ctrl, metadata_segment_sb_config); - ENV_BUG_ON(!sb_config); - - sb_runtime = METADATA_MEM_POOL(ctrl, metadata_segment_sb_runtime); - ENV_BUG_ON(!sb_runtime); - - result = ocf_pipeline_create(&pipeline, cache, - &ocf_metadata_load_sb_recov_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); + _ocf_metadata_load_superblock(cache, false, cmpl, priv); } static void ocf_metadata_flush_superblock_flap(ocf_pipeline_t pipeline, From 494c8138b91c9faa363d77986d226841a598d81e Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Thu, 15 Oct 2026 00:01:15 +0200 Subject: [PATCH 6/9] metadata: Check shutdown status on superblock load Instead of relying on passing shutdown status information from the probe through cache management layer, read it directly from freshly loaded superblock config segment. That eliminates need for a separate superblock load function for recovery path, simplifying metadata handling on the cache management layer. Signed-off-by: Robert Baldyga --- src/metadata/metadata_superblock.c | 37 +++++++++++++++--------------- src/metadata/metadata_superblock.h | 3 --- src/mngt/ocf_mngt_cache.c | 9 ++------ 3 files changed, 21 insertions(+), 28 deletions(-) diff --git a/src/metadata/metadata_superblock.c b/src/metadata/metadata_superblock.c index 8eacf992..d9b6e2c2 100644 --- a/src/metadata/metadata_superblock.c +++ b/src/metadata/metadata_superblock.c @@ -255,6 +255,22 @@ static void _ocf_metadata_validate_superblock(ocf_pipeline_t pipeline, ocf_pipeline_next(pipeline); } +static void _ocf_metadata_get_shutdown_status(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 *superblock; + + ctrl = (struct ocf_metadata_ctrl *)context->ctrl; + superblock = METADATA_MEM_POOL(ctrl, metadata_segment_sb_config); + + context->clean_shutdown = (superblock->clean_shutdown == + ocf_metadata_clean_shutdown); + + ocf_pipeline_next(pipeline); +} + static void _ocf_metadata_validate_core_config(ocf_pipeline_t pipeline, void *priv, ocf_pipeline_arg_t arg) { @@ -372,6 +388,7 @@ struct ocf_pipeline_properties ocf_metadata_load_sb_pipeline_props = { OCF_PL_STEP_ARG_INT(ocf_metadata_load_segment, metadata_segment_sb_config), OCF_PL_STEP(_ocf_metadata_validate_superblock), + OCF_PL_STEP(_ocf_metadata_get_shutdown_status), OCF_PL_STEP_FOREACH_COND(ocf_metadata_load_sb_segment_is_valid, ocf_metadata_load_segment, ocf_metadata_load_sb_load_segment_args), @@ -386,8 +403,8 @@ struct ocf_pipeline_properties ocf_metadata_load_sb_pipeline_props = { /* * Super Block - Load, This function has to prevent to pointers overwrite */ -static void _ocf_metadata_load_superblock(ocf_cache_t cache, - bool clean_shutdown, ocf_metadata_end_t cmpl, void *priv) +void ocf_metadata_load_superblock(ocf_cache_t cache, ocf_metadata_end_t cmpl, + void *priv) { struct ocf_metadata_context *context; ocf_pipeline_t pipeline; @@ -420,26 +437,10 @@ static void _ocf_metadata_load_superblock(ocf_cache_t cache, context->pipeline = pipeline; context->cache = cache; context->ctrl = cache->metadata.priv; - context->clean_shutdown = clean_shutdown; ocf_pipeline_next(pipeline); } -void ocf_metadata_load_superblock(ocf_cache_t cache, ocf_metadata_end_t cmpl, - void *priv) -{ - _ocf_metadata_load_superblock(cache, true, cmpl, priv); -} - -/* - * Super Block - Recovery load - */ -void ocf_metadata_load_superblock_recovery(ocf_cache_t cache, - ocf_metadata_end_t cmpl, void *priv) -{ - _ocf_metadata_load_superblock(cache, false, cmpl, priv); -} - static void ocf_metadata_flush_superblock_flap(ocf_pipeline_t pipeline, void *priv, ocf_pipeline_arg_t arg) { diff --git a/src/metadata/metadata_superblock.h b/src/metadata/metadata_superblock.h index d352cdf0..7f04a1b3 100644 --- a/src/metadata/metadata_superblock.h +++ b/src/metadata/metadata_superblock.h @@ -23,9 +23,6 @@ void ocf_metadata_set_shutdown_status(ocf_cache_t cache, void ocf_metadata_load_superblock(ocf_cache_t cache, ocf_metadata_end_t cmpl, void *priv); -void ocf_metadata_load_superblock_recovery(ocf_cache_t cache, - ocf_metadata_end_t cmpl, void *priv); - void ocf_metadata_flush_superblock(ocf_cache_t cache, ocf_metadata_end_t cmpl, void *priv); diff --git a/src/mngt/ocf_mngt_cache.c b/src/mngt/ocf_mngt_cache.c index 8a9b59ee..fce28885 100644 --- a/src/mngt/ocf_mngt_cache.c +++ b/src/mngt/ocf_mngt_cache.c @@ -1832,13 +1832,8 @@ static void _ocf_mngt_load_superblock(ocf_pipeline_t pipeline, ocf_cache_t cache = context->cache; ocf_cache_log(cache, log_info, "Loading cache state...\n"); - if (context->metadata.shutdown_status == ocf_metadata_clean_shutdown) { - ocf_metadata_load_superblock(cache, - _ocf_mngt_load_superblock_complete, context); - } else { - ocf_metadata_load_superblock_recovery(cache, - _ocf_mngt_load_superblock_complete, context); - } + ocf_metadata_load_superblock(cache, + _ocf_mngt_load_superblock_complete, context); } static void _ocf_mngt_attach_update_cores_atomic(ocf_pipeline_t pipeline, From 7d999f3bc7f1a463c76de6ddb45d7d33d8251db5 Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Thu, 15 Oct 2026 00:27:57 +0200 Subject: [PATCH 7/9] metadata: Move superblock validation to the layout layer Signed-off-by: Robert Baldyga --- src/metadata/layout/superblock.c | 91 ++++++++++++++++++++++++++++++ src/metadata/layout/superblock.h | 39 +++++++++++++ src/metadata/metadata_superblock.c | 47 +++++++-------- 3 files changed, 150 insertions(+), 27 deletions(-) create mode 100644 src/metadata/layout/superblock.c diff --git a/src/metadata/layout/superblock.c b/src/metadata/layout/superblock.c new file mode 100644 index 00000000..11004a6f --- /dev/null +++ b/src/metadata/layout/superblock.c @@ -0,0 +1,91 @@ +/* + * Copyright(c) 2012-2022 Intel Corporation + * Copyright(c) 2026 Unvertical + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "superblock.h" +#include "layout.h" + +static bool ocf_superblock_config_line_size_is_valid(uint64_t size) +{ + switch (size) { + case ocf_cache_line_size_4: + case ocf_cache_line_size_8: + case ocf_cache_line_size_16: + case ocf_cache_line_size_32: + case ocf_cache_line_size_64: + return true; + default: + return false; + } +} + +void ocf_superblock_config_validate( + const struct ocf_superblock_config *superblock, + struct ocf_superblock_config_validity *valid) +{ + env_memset(valid, sizeof(*valid), 0); + + valid->magic_number = + superblock->magic_number == CACHE_MAGIC_NUMBER; + if (!valid->magic_number) + return; + + valid->metadata_version = + superblock->metadata_version == METADATA_VERSION(); + if (!valid->metadata_version) + return; + + valid->checksum = + superblock->checksum[metadata_segment_sb_config] == + ocf_metadata_segment_layout_checksum_superblock(superblock); + + valid->adapter_name = + !env_strncmp(superblock->adapter_name, OCF_ADAPTER_NAME_SIZE, + ENV_ADAPTER_NAME, OCF_ADAPTER_NAME_SIZE); + + valid->adapter_version = + superblock->adapter_version == ADAPTER_VERSION(); + + valid->metadata_4k_mode = + superblock->metadata_4k_mode == METADATA_4K_MODE(); + + valid->clean_shutdown = + superblock->clean_shutdown <= ocf_metadata_clean_shutdown; + + valid->dirty_flushed = + superblock->dirty_flushed <= DIRTY_FLUSHED; + + valid->flapping_idx = + superblock->flapping_idx <= 1; + + valid->cache_mode = + superblock->cache_mode >= 0 && + superblock->cache_mode < ocf_cache_mode_max; + + valid->name = + env_strnlen(superblock->name, sizeof(superblock->name)) < + OCF_CACHE_NAME_SIZE; + + valid->valid_parts_no = + superblock->valid_parts_no <= OCF_USER_IO_CLASS_MAX; + + valid->line_size = + ocf_superblock_config_line_size_is_valid(superblock->line_size); + + valid->core_count = + superblock->core_count <= OCF_CORE_NUM; + + valid->cleaning_policy_type = + superblock->cleaning_policy_type >= 0 && + superblock->cleaning_policy_type < ocf_cleaning_max; + + valid->cleaner_disabled = + !superblock->cleaner_disabled || + superblock->cleaning_policy_type == ocf_cleaning_nop; + + valid->promotion_policy_type = + superblock->promotion_policy_type >= 0 && + superblock->promotion_policy_type < ocf_promotion_max; +} diff --git a/src/metadata/layout/superblock.h b/src/metadata/layout/superblock.h index 77e5c1d9..ae88f5af 100644 --- a/src/metadata/layout/superblock.h +++ b/src/metadata/layout/superblock.h @@ -106,4 +106,43 @@ struct ocf_superblock_runtime { uint32_t cleaning_thread_access; }; +/** + * @brief Validity of superblock config fields + * + * Each field tells whether the superblock config field of the same name + * holds a valid value. Fields are listed in the order of checking. + * Fields following magic_number and metadata_version are meaningful + * only if both of these are valid - otherwise they are left false. + */ +struct ocf_superblock_config_validity { + bool magic_number; + bool metadata_version; + bool checksum; + bool adapter_name; + bool adapter_version; + bool metadata_4k_mode; + bool clean_shutdown; + bool dirty_flushed; + bool flapping_idx; + bool cache_mode; + bool name; + bool valid_parts_no; + bool line_size; + bool core_count; + bool cleaning_policy_type; + bool cleaner_disabled; + /*!< Cleaner can be disabled only with nop cleaning policy */ + bool promotion_policy_type; +}; + +/** + * @brief Validate superblock config + * + * @param superblock - Superblock config + * @param valid - Validity of superblock config fields + */ +void ocf_superblock_config_validate( + const struct ocf_superblock_config *superblock, + struct ocf_superblock_config_validity *valid); + #endif /* __METADATA_LAYOUT_SUPERBLOCK_H__ */ diff --git a/src/metadata/metadata_superblock.c b/src/metadata/metadata_superblock.c index d9b6e2c2..fb186e23 100644 --- a/src/metadata/metadata_superblock.c +++ b/src/metadata/metadata_superblock.c @@ -105,17 +105,19 @@ static void ocf_metadata_store_segment(ocf_pipeline_t pipeline, int ocf_metadata_validate_superblock(ocf_ctx_t ctx, struct ocf_superblock_config *superblock) { + struct ocf_superblock_config_validity valid; const char *segment_name; - uint32_t crc; segment_name = ocf_metadata_segment_names[metadata_segment_sb_config]; - if (superblock->magic_number != CACHE_MAGIC_NUMBER) { + ocf_superblock_config_validate(superblock, &valid); + + if (!valid.magic_number) { ocf_log(ctx, log_info, "Cannot detect pre-existing metadata\n"); return -OCF_ERR_NO_METADATA; } - if (METADATA_VERSION() != superblock->metadata_version) { + if (!valid.metadata_version) { 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, @@ -128,15 +130,12 @@ int ocf_metadata_validate_superblock(ocf_ctx_t ctx, return -OCF_ERR_METADATA_VER; } - crc = ocf_metadata_segment_layout_checksum_superblock(superblock); - - if (crc != superblock->checksum[metadata_segment_sb_config]) { + if (!valid.checksum) { ocf_log_invalid_superblock("checksum"); return -OCF_ERR_CRC_MISMATCH; } - if (env_strncmp(superblock->adapter_name, OCF_ADAPTER_NAME_SIZE, - ENV_ADAPTER_NAME, OCF_ADAPTER_NAME_SIZE)) { + if (!valid.adapter_name) { /* Field comes off disk and need not be terminated - bound * the print to its size instead of running past it. */ @@ -147,7 +146,7 @@ int ocf_metadata_validate_superblock(ocf_ctx_t ctx, return -OCF_ERR_ADAPTER_MISMATCH; } - if (superblock->adapter_version != ADAPTER_VERSION()) { + if (!valid.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, @@ -162,7 +161,7 @@ int ocf_metadata_validate_superblock(ocf_ctx_t ctx, return -OCF_ERR_ADAPTER_VER; } - if (superblock->metadata_4k_mode != METADATA_4K_MODE()) { + if (!valid.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, @@ -171,65 +170,59 @@ int ocf_metadata_validate_superblock(ocf_ctx_t ctx, return -OCF_ERR_BLOCK_MODE_MISMATCH; } - if (superblock->clean_shutdown > ocf_metadata_clean_shutdown) { + if (!valid.clean_shutdown) { ocf_log_invalid_superblock("shutdown status"); return -OCF_ERR_INVAL; } - if (superblock->dirty_flushed > DIRTY_FLUSHED) { + if (!valid.dirty_flushed) { ocf_log_invalid_superblock("flush status"); return -OCF_ERR_INVAL; } - if (superblock->flapping_idx > 1) { + if (!valid.flapping_idx) { ocf_log_invalid_superblock("flapping index"); return -OCF_ERR_INVAL; } - if (superblock->cache_mode < 0 || - superblock->cache_mode >= ocf_cache_mode_max) { + if (!valid.cache_mode) { ocf_log_invalid_superblock("cache mode"); return -OCF_ERR_INVAL; } - if (env_strnlen(superblock->name, sizeof(superblock->name)) >= - OCF_CACHE_NAME_SIZE) { + if (!valid.name) { ocf_log_invalid_superblock("name"); return -OCF_ERR_INVAL; } - if (superblock->valid_parts_no > OCF_USER_IO_CLASS_MAX) { + if (!valid.valid_parts_no) { ocf_log_invalid_superblock("partition count"); return -OCF_ERR_INVAL; } - if (!ocf_cache_line_size_is_valid(superblock->line_size)) { + if (!valid.line_size) { ocf_log_invalid_superblock("cache line size"); return -OCF_ERR_INVAL; } - if (superblock->core_count > OCF_CORE_NUM) { + if (!valid.core_count) { ocf_log_invalid_superblock("core count"); return -OCF_ERR_INVAL; } - if (superblock->cleaning_policy_type < 0 || - superblock->cleaning_policy_type >= ocf_cleaning_max) { + if (!valid.cleaning_policy_type) { ocf_log_invalid_superblock("cleaning policy"); return -OCF_ERR_INVAL; } - if (superblock->cleaner_disabled && - superblock->cleaning_policy_type != ocf_cleaning_nop) { + if (!valid.cleaner_disabled) { ocf_log(ctx, log_err, "Loading %s: cleaner is disabled, but " "cleaning policy is not set to nop!\n", segment_name); return -OCF_ERR_INVAL; } - if (superblock->promotion_policy_type < 0 || - superblock->promotion_policy_type >= - ocf_promotion_max) { + if (!valid.promotion_policy_type) { ocf_log_invalid_superblock("promotion policy"); return -OCF_ERR_INVAL; } From c415bb8931ad5d70ee4dd7e6a5dae5f128b162bd Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Thu, 15 Oct 2026 11:32:52 +0200 Subject: [PATCH 8/9] metadata: Remove valid field from core metadata This field is redundant with superblock valid core map. It does nothing, except introducing a potential inconsistency. Signed-off-by: Robert Baldyga --- src/metadata/layout/core.h | 3 --- src/metadata/metadata_superblock.c | 36 ------------------------------ src/mngt/ocf_mngt_cache.c | 3 ++- src/mngt/ocf_mngt_common.c | 3 --- src/mngt/ocf_mngt_core.c | 2 -- src/ocf_cache_priv.h | 2 +- 6 files changed, 3 insertions(+), 46 deletions(-) diff --git a/src/metadata/layout/core.h b/src/metadata/layout/core.h index 814ac77d..259a6eba 100644 --- a/src/metadata/layout/core.h +++ b/src/metadata/layout/core.h @@ -19,9 +19,6 @@ struct ocf_core_meta_config { uint8_t type; - /* This bit means that object was saved in cache metadata */ - uint32_t valid : 1; - /* Core sequence number used to correlate cache lines with cores * when recovering from atomic device */ diff --git a/src/metadata/metadata_superblock.c b/src/metadata/metadata_superblock.c index fb186e23..ca39167c 100644 --- a/src/metadata/metadata_superblock.c +++ b/src/metadata/metadata_superblock.c @@ -264,41 +264,6 @@ static void _ocf_metadata_get_shutdown_status(ocf_pipeline_t pipeline, ocf_pipeline_next(pipeline); } -static void _ocf_metadata_validate_core_config(ocf_pipeline_t pipeline, - void *priv, ocf_pipeline_arg_t arg) -{ - struct ocf_metadata_context *context = priv; - ocf_ctx_t ctx = context->cache->owner; - struct ocf_metadata_ctrl *ctrl; - struct ocf_superblock_config *superblock; - struct ocf_core_meta_config *core_config; - ocf_core_id_t core_id; - bool valid_in_bitmap; - - ctrl = (struct ocf_metadata_ctrl *)context->ctrl; - superblock = METADATA_MEM_POOL(ctrl, metadata_segment_sb_config); - core_config = METADATA_MEM_POOL(ctrl, metadata_segment_core_config); - - for (core_id = 0; core_id < OCF_CORE_NUM; core_id++) { - valid_in_bitmap = env_bit_test(core_id, - superblock->valid_core_bitmap); - - if (valid_in_bitmap && !core_config[core_id].valid) { - ocf_log(ctx, log_err, "Core is marked as valid in " - "bitmap but not in core metadata!\n"); - OCF_PL_FINISH_RET(pipeline, -OCF_ERR_INVAL); - } - - if (core_config[core_id].valid && !valid_in_bitmap) { - ocf_log(ctx, log_err, "Core is marked as valid in " - "core metadata but not in bitmap!\n"); - OCF_PL_FINISH_RET(pipeline, -OCF_ERR_INVAL); - } - } - - ocf_pipeline_next(pipeline); -} - static void ocf_metadata_load_sb_restore( struct ocf_metadata_context *context) { @@ -388,7 +353,6 @@ struct ocf_pipeline_properties ocf_metadata_load_sb_pipeline_props = { OCF_PL_STEP_FOREACH_COND(ocf_metadata_load_sb_segment_is_valid, ocf_metadata_check_crc, ocf_metadata_load_sb_load_segment_args), - OCF_PL_STEP(_ocf_metadata_validate_core_config), OCF_PL_STEP_TERMINATOR(), }, }; diff --git a/src/mngt/ocf_mngt_cache.c b/src/mngt/ocf_mngt_cache.c index fce28885..00f13033 100644 --- a/src/mngt/ocf_mngt_cache.c +++ b/src/mngt/ocf_mngt_cache.c @@ -659,7 +659,8 @@ static int ocf_mngt_rebuild_metadata_handle(ocf_parallelize_t parallelize, continue; } - if (!cache->core[core_id].conf_meta->valid) { + if (!env_bit_test(core_id, + cache->conf_meta->valid_core_bitmap)) { ocf_cache_log(cache, log_err, "Stale mapping in " "on-disk metadata - refusing to " "recover cache.\n"); diff --git a/src/mngt/ocf_mngt_common.c b/src/mngt/ocf_mngt_common.c index 57da32d8..2b2cfd01 100644 --- a/src/mngt/ocf_mngt_common.c +++ b/src/mngt/ocf_mngt_common.c @@ -118,9 +118,6 @@ void cache_mngt_core_remove_from_meta(ocf_core_t core) ocf_metadata_start_exclusive_access(&cache->metadata_lock); - /* In metadata mark data this core was removed from cache */ - core->conf_meta->valid = false; - /* Clear UUID of core */ ocf_mngt_core_clear_uuid_metadata(core); core->conf_meta->seq_no = OCF_SEQ_NO_INVALID; diff --git a/src/mngt/ocf_mngt_core.c b/src/mngt/ocf_mngt_core.c index d08e9987..6f4dc435 100644 --- a/src/mngt/ocf_mngt_core.c +++ b/src/mngt/ocf_mngt_core.c @@ -148,7 +148,6 @@ static void _ocf_mngt_cache_add_core_handle_error( env_bit_clear(core_id, cache->conf_meta->valid_core_bitmap); cache->conf_meta->core_count--; - core->conf_meta->valid = false; core->added = false; core->opened = false; @@ -517,7 +516,6 @@ static void ocf_mngt_cache_add_core_insert(ocf_pipeline_t pipeline, env_bit_set(core_id, cache->conf_meta->valid_core_bitmap); context->cache->conf_meta->core_count++; - core->conf_meta->valid = true; core->added = true; core->opened = true; diff --git a/src/ocf_cache_priv.h b/src/ocf_cache_priv.h index 1b8f82f4..570da8c6 100644 --- a/src/ocf_cache_priv.h +++ b/src/ocf_cache_priv.h @@ -155,7 +155,7 @@ static inline ocf_core_t ocf_cache_get_core(ocf_cache_t cache, #define for_each_core_metadata(_cache, _core, _id) \ for_each_core_all(_cache, _core, _id) \ - if (_core->conf_meta->valid) + if (env_bit_test(_id, _cache->conf_meta->valid_core_bitmap)) #define ocf_cache_log_prefix(cache, lvl, prefix, fmt, ...) \ ocf_log_prefix(ocf_cache_get_ctx(cache), lvl, "%s" prefix, \ From 570874ef755d765fd8e9199bc39caa3a331a1e1a Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Thu, 15 Oct 2026 15:47:50 +0200 Subject: [PATCH 9/9] metadata: Add validation of all the config sections Signed-off-by: Robert Baldyga --- src/metadata/layout/cleaning_policy.c | 52 ++++++ src/metadata/layout/cleaning_policy.h | 39 ++++ src/metadata/layout/core.c | 107 +++++++++++ src/metadata/layout/core.h | 75 ++++++++ src/metadata/layout/partition.c | 59 ++++++ src/metadata/layout/partition.h | 50 +++++ src/metadata/layout/promotion_policy.c | 21 +++ src/metadata/layout/promotion_policy.h | 18 ++ src/metadata/layout/superblock.c | 55 +++++- src/metadata/layout/superblock.h | 11 ++ src/metadata/metadata_superblock.c | 245 +++++++++++++++++++++++++ 11 files changed, 731 insertions(+), 1 deletion(-) create mode 100644 src/metadata/layout/cleaning_policy.c create mode 100644 src/metadata/layout/core.c create mode 100644 src/metadata/layout/partition.c create mode 100644 src/metadata/layout/promotion_policy.c diff --git a/src/metadata/layout/cleaning_policy.c b/src/metadata/layout/cleaning_policy.c new file mode 100644 index 00000000..99cc5584 --- /dev/null +++ b/src/metadata/layout/cleaning_policy.c @@ -0,0 +1,52 @@ +/* + * Copyright(c) 2026 Unvertical + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "cleaning_policy.h" + +void ocf_alru_cleaning_policy_config_validate( + const struct alru_cleaning_policy_config *config, + struct alru_cleaning_policy_config_validity *valid) +{ + env_memset(valid, sizeof(*valid), 0); + + valid->thread_wakeup_time = + config->thread_wakeup_time >= OCF_ALRU_MIN_WAKE_UP && + config->thread_wakeup_time <= OCF_ALRU_MAX_WAKE_UP; + + valid->stale_buffer_time = + config->stale_buffer_time >= OCF_ALRU_MIN_STALENESS_TIME && + config->stale_buffer_time <= OCF_ALRU_MAX_STALENESS_TIME; + + valid->flush_max_buffers = + config->flush_max_buffers >= OCF_ALRU_MIN_FLUSH_MAX_BUFFERS && + config->flush_max_buffers <= OCF_ALRU_MAX_FLUSH_MAX_BUFFERS; + + valid->activity_threshold = + config->activity_threshold >= + OCF_ALRU_MIN_ACTIVITY_THRESHOLD && + config->activity_threshold <= + OCF_ALRU_MAX_ACTIVITY_THRESHOLD; + + valid->dirty_ratio_threshold = + config->dirty_ratio_threshold >= + OCF_ALRU_MIN_DIRTY_RATIO_THRESHOLD && + config->dirty_ratio_threshold <= + OCF_ALRU_MAX_DIRTY_RATIO_THRESHOLD; +} + +void ocf_acp_cleaning_policy_config_validate( + const struct acp_cleaning_policy_config *config, + struct acp_cleaning_policy_config_validity *valid) +{ + env_memset(valid, sizeof(*valid), 0); + + valid->thread_wakeup_time = + config->thread_wakeup_time >= OCF_ACP_MIN_WAKE_UP && + config->thread_wakeup_time <= OCF_ACP_MAX_WAKE_UP; + + valid->flush_max_buffers = + config->flush_max_buffers >= OCF_ACP_MIN_FLUSH_MAX_BUFFERS && + config->flush_max_buffers <= OCF_ACP_MAX_FLUSH_MAX_BUFFERS; +} diff --git a/src/metadata/layout/cleaning_policy.h b/src/metadata/layout/cleaning_policy.h index d9237d24..35b5c6a0 100644 --- a/src/metadata/layout/cleaning_policy.h +++ b/src/metadata/layout/cleaning_policy.h @@ -32,6 +32,45 @@ struct acp_cleaning_policy_config { uint32_t flush_max_buffers; /* in lines */ }; +/** + * @brief Validity of ALRU cleaning policy config fields + */ +struct alru_cleaning_policy_config_validity { + bool thread_wakeup_time; + bool stale_buffer_time; + bool flush_max_buffers; + bool activity_threshold; + bool dirty_ratio_threshold; +}; + +/** + * @brief Validate ALRU cleaning policy config + * + * @param config - ALRU cleaning policy config + * @param valid - Validity of ALRU cleaning policy config fields + */ +void ocf_alru_cleaning_policy_config_validate( + const struct alru_cleaning_policy_config *config, + struct alru_cleaning_policy_config_validity *valid); + +/** + * @brief Validity of ACP cleaning policy config fields + */ +struct acp_cleaning_policy_config_validity { + bool thread_wakeup_time; + bool flush_max_buffers; +}; + +/** + * @brief Validate ACP cleaning policy config + * + * @param config - ACP cleaning policy config + * @param valid - Validity of ACP cleaning policy config fields + */ +void ocf_acp_cleaning_policy_config_validate( + const struct acp_cleaning_policy_config *config, + struct acp_cleaning_policy_config_validity *valid); + /* Cleaning policy metadata per partition */ struct nop_cleaning_policy { diff --git a/src/metadata/layout/core.c b/src/metadata/layout/core.c new file mode 100644 index 00000000..bcd167a7 --- /dev/null +++ b/src/metadata/layout/core.c @@ -0,0 +1,107 @@ +/* + * Copyright(c) 2026 Unvertical + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "core.h" + +void ocf_core_meta_config_validate( + const struct ocf_superblock_config *superblock, + ocf_core_id_t core_id, + const struct ocf_core_meta_config *core_config, + struct ocf_core_meta_config_validity *valid) +{ + uint32_t seq_cutoff_threshold, seq_detect_promotion_count; + uint32_t seq_detect_promotion_threshold; + int seq_cutoff_policy; + + if (!env_bit_test(core_id, superblock->valid_core_bitmap)) { + /* Core is not in use - there is nothing to check */ + env_memset(valid, sizeof(*valid), true); + return; + } + + env_memset(valid, sizeof(*valid), 0); + + valid->name = + core_config->name[0] != '\0' && + env_strnlen(core_config->name, sizeof(core_config->name)) < + OCF_CORE_NAME_SIZE; + + valid->seq_no = + core_config->seq_no <= superblock->curr_core_seq_no; + + seq_cutoff_threshold = + env_atomic_read(&core_config->seq_cutoff_threshold); + valid->seq_cutoff_threshold = + seq_cutoff_threshold >= OCF_SEQ_CUTOFF_MIN_THRESHOLD && + seq_cutoff_threshold <= OCF_SEQ_CUTOFF_MAX_THRESHOLD; + + seq_cutoff_policy = + env_atomic_read(&core_config->seq_cutoff_policy); + valid->seq_cutoff_policy = + seq_cutoff_policy >= 0 && + seq_cutoff_policy < ocf_seq_cutoff_policy_max; + + seq_detect_promotion_count = + env_atomic_read(&core_config->seq_detect_promotion_count); + valid->seq_detect_promotion_count = + seq_detect_promotion_count >= + OCF_SEQ_DETECT_MIN_PROMOTION_COUNT && + seq_detect_promotion_count <= + OCF_SEQ_DETECT_MAX_PROMOTION_COUNT; + + seq_detect_promotion_threshold = + env_atomic_read(&core_config->seq_detect_promotion_threshold); + valid->seq_detect_promotion_threshold = + seq_detect_promotion_threshold <= + OCF_SEQ_DETECT_MAX_PROMOTION_THRESHOLD; +} + +void ocf_cores_validate(const struct ocf_superblock_config *superblock, + const struct ocf_core_meta_config *core_config, + struct ocf_cores_validity *valid) +{ + ocf_core_id_t i, j; + + env_memset(valid, sizeof(*valid), 0); + + /* + * Sequence number is assigned only on atomic cache device, otherwise + * it is OCF_SEQ_NO_INVALID for all cores. + */ + for (i = 0; i < OCF_CORE_NUM; i++) { + if (!env_bit_test(i, superblock->valid_core_bitmap)) + continue; + + if (core_config[i].seq_no == OCF_SEQ_NO_INVALID) + continue; + + for (j = i + 1; j < OCF_CORE_NUM; j++) { + if (!env_bit_test(j, superblock->valid_core_bitmap)) + continue; + + if (core_config[i].seq_no == core_config[j].seq_no) + return; + } + } + + valid->seq_no = true; +} + +void ocf_metadata_uuid_validate( + const struct ocf_superblock_config *superblock, + ocf_core_id_t core_id, + const struct ocf_metadata_uuid *uuid, + struct ocf_metadata_uuid_validity *valid) +{ + if (!env_bit_test(core_id, superblock->valid_core_bitmap)) { + /* Core is not in use - there is nothing to check */ + env_memset(valid, sizeof(*valid), true); + return; + } + + env_memset(valid, sizeof(*valid), 0); + + valid->size = uuid->size <= OCF_VOLUME_UUID_MAX_SIZE; +} diff --git a/src/metadata/layout/core.h b/src/metadata/layout/core.h index 259a6eba..b16ef9e0 100644 --- a/src/metadata/layout/core.h +++ b/src/metadata/layout/core.h @@ -8,6 +8,7 @@ #define __METADATA_LAYOUT_CORE_H__ #include "ocf/ocf.h" +#include "superblock.h" struct ocf_metadata_uuid { uint32_t size; @@ -62,4 +63,78 @@ struct ocf_core_meta_runtime { } part_counters[OCF_USER_IO_CLASS_MAX]; }; +/** + * @brief Validity of core config fields + * + * Each field tells whether the core config field of the same name holds + * a valid value. Fields are listed in the order of checking. Config of core + * which is not in use (according to superblock valid core bitmap) is valid + * as a whole. + */ +struct ocf_core_meta_config_validity { + bool name; + bool seq_no; + bool seq_cutoff_threshold; + bool seq_cutoff_policy; + bool seq_detect_promotion_count; + bool seq_detect_promotion_threshold; +}; + +/** + * @brief Validate core config + * + * @param superblock - Superblock config + * @param core_id - Core id + * @param core_config - Core config of given core + * @param valid - Validity of core config fields + */ +void ocf_core_meta_config_validate( + const struct ocf_superblock_config *superblock, + ocf_core_id_t core_id, + const struct ocf_core_meta_config *core_config, + struct ocf_core_meta_config_validity *valid); + +/** + * @brief Validity of core configs as a whole + */ +struct ocf_cores_validity { + bool seq_no; + /*!< Sequence numbers of cores in use are unique */ +}; + +/** + * @brief Validate core configs as a whole + * + * @param superblock - Superblock config + * @param core_config - Configs of all cores + * @param valid - Validity of core configs as a whole + */ +void ocf_cores_validate(const struct ocf_superblock_config *superblock, + const struct ocf_core_meta_config *core_config, + struct ocf_cores_validity *valid); + +/** + * @brief Validity of core uuid fields + * + * Uuid of core which is not in use (according to superblock valid core + * bitmap) is valid as a whole. + */ +struct ocf_metadata_uuid_validity { + bool size; +}; + +/** + * @brief Validate core uuid + * + * @param superblock - Superblock config + * @param core_id - Core id + * @param uuid - Core uuid + * @param valid - Validity of core uuid fields + */ +void ocf_metadata_uuid_validate( + const struct ocf_superblock_config *superblock, + ocf_core_id_t core_id, + const struct ocf_metadata_uuid *uuid, + struct ocf_metadata_uuid_validity *valid); + #endif /* __METADATA_LAYOUT_CORE_H__ */ diff --git a/src/metadata/layout/partition.c b/src/metadata/layout/partition.c new file mode 100644 index 00000000..a3dd7133 --- /dev/null +++ b/src/metadata/layout/partition.c @@ -0,0 +1,59 @@ +/* + * Copyright(c) 2026 Unvertical + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "partition.h" + +void ocf_user_part_config_validate( + const struct ocf_user_part_config *part_config, + struct ocf_user_part_config_validity *valid) +{ + env_memset(valid, sizeof(*valid), 0); + + valid->name = + part_config->name[0] != '\0' && + env_strnlen(part_config->name, sizeof(part_config->name)) < + OCF_IO_CLASS_NAME_MAX; + + valid->min_size = + part_config->min_size <= part_config->max_size; + + valid->max_size = + part_config->max_size <= PARTITION_SIZE_MAX; + + valid->priority = + part_config->priority == OCF_IO_CLASS_PRIO_PINNED || + (part_config->priority >= OCF_IO_CLASS_PRIO_HIGHEST && + part_config->priority <= OCF_IO_CLASS_PRIO_LOWEST); + + valid->cache_mode = + part_config->cache_mode >= ocf_cache_mode_none && + part_config->cache_mode <= ocf_cache_mode_max; +} + +void ocf_user_parts_validate( + const struct ocf_superblock_config *superblock, + const struct ocf_user_part_config *part_config, + struct ocf_user_parts_validity *valid) +{ + uint32_t valid_parts_no = 0; + uint64_t min_size = 0; + ocf_part_id_t part_id; + + env_memset(valid, sizeof(*valid), 0); + + for (part_id = 0; part_id < OCF_USER_IO_CLASS_MAX; part_id++) { + if (!part_config[part_id].flags.valid) + continue; + + valid_parts_no++; + min_size += part_config[part_id].min_size; + } + + valid->valid_parts_no = + superblock->valid_parts_no == valid_parts_no; + + valid->min_size = + min_size <= PARTITION_SIZE_MAX; +} diff --git a/src/metadata/layout/partition.h b/src/metadata/layout/partition.h index 0991b84d..84c54a7a 100644 --- a/src/metadata/layout/partition.h +++ b/src/metadata/layout/partition.h @@ -11,6 +11,7 @@ #include "ocf/ocf.h" #include "lru.h" #include "cleaning_policy.h" +#include "superblock.h" #define PARTITION_UNSPECIFIED ((ocf_part_id_t)-1) #define PARTITION_FREELIST (OCF_USER_IO_CLASS_MAX + 1) @@ -43,4 +44,53 @@ struct ocf_part_runtime { struct cleaning_policy clean_pol; }; +/** + * @brief Validity of user partition config fields + * + * Each field tells whether the partition config field of the same name + * holds a valid value. Fields are listed in the order of checking. + */ +struct ocf_user_part_config_validity { + bool name; + bool min_size; + /*!< Min size does not exceed max size */ + bool max_size; + bool priority; + bool cache_mode; +}; + +/** + * @brief Validate user partition config + * + * @param part_config - Partition config + * @param valid - Validity of partition config fields + */ +void ocf_user_part_config_validate( + const struct ocf_user_part_config *part_config, + struct ocf_user_part_config_validity *valid); + +/** + * @brief Validity of user partition configs as a whole + */ +struct ocf_user_parts_validity { + bool valid_parts_no; + /*!< Number of valid partitions matches superblock */ + bool min_size; + /*!< Sum of min sizes of valid partitions does not exceed + * PARTITION_SIZE_MAX + */ +}; + +/** + * @brief Validate user partition configs as a whole + * + * @param superblock - Superblock config + * @param part_config - Configs of all user partitions + * @param valid - Validity of user partition configs as a whole + */ +void ocf_user_parts_validate( + const struct ocf_superblock_config *superblock, + const struct ocf_user_part_config *part_config, + struct ocf_user_parts_validity *valid); + #endif /* __METADATA_LAYOUT_PARTITION_H__ */ diff --git a/src/metadata/layout/promotion_policy.c b/src/metadata/layout/promotion_policy.c new file mode 100644 index 00000000..2537d58c --- /dev/null +++ b/src/metadata/layout/promotion_policy.c @@ -0,0 +1,21 @@ +/* + * Copyright(c) 2026 Unvertical + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "promotion_policy.h" + +void ocf_nhit_promotion_policy_config_validate( + const struct nhit_promotion_policy_config *config, + struct nhit_promotion_policy_config_validity *valid) +{ + env_memset(valid, sizeof(*valid), 0); + + valid->insertion_threshold = + config->insertion_threshold >= OCF_NHIT_MIN_THRESHOLD && + config->insertion_threshold <= OCF_NHIT_MAX_THRESHOLD; + + valid->trigger_threshold = + config->trigger_threshold >= OCF_NHIT_MIN_TRIGGER && + config->trigger_threshold <= OCF_NHIT_MAX_TRIGGER; +} diff --git a/src/metadata/layout/promotion_policy.h b/src/metadata/layout/promotion_policy.h index a8673ace..14db7cad 100644 --- a/src/metadata/layout/promotion_policy.h +++ b/src/metadata/layout/promotion_policy.h @@ -26,4 +26,22 @@ struct nhit_promotion_policy_config { /*!< Cache occupancy (percentage value) */ }; +/** + * @brief Validity of NHIT promotion policy config fields + */ +struct nhit_promotion_policy_config_validity { + bool insertion_threshold; + bool trigger_threshold; +}; + +/** + * @brief Validate NHIT promotion policy config + * + * @param config - NHIT promotion policy config + * @param valid - Validity of NHIT promotion policy config fields + */ +void ocf_nhit_promotion_policy_config_validate( + const struct nhit_promotion_policy_config *config, + struct nhit_promotion_policy_config_validity *valid); + #endif /* __METADATA_LAYOUT_PROMOTION_POLICY_H__ */ diff --git a/src/metadata/layout/superblock.c b/src/metadata/layout/superblock.c index 11004a6f..e058d8c8 100644 --- a/src/metadata/layout/superblock.c +++ b/src/metadata/layout/superblock.c @@ -21,6 +21,36 @@ static bool ocf_superblock_config_line_size_is_valid(uint64_t size) } } +static bool ocf_superblock_config_core_count_is_valid( + const struct ocf_superblock_config *superblock) +{ + uint32_t core_count = 0; + ocf_core_id_t core_id; + + for (core_id = 0; core_id < OCF_CORE_NUM; core_id++) { + if (env_bit_test(core_id, superblock->valid_core_bitmap)) + core_count++; + } + + return superblock->core_count == core_count; +} + +static bool ocf_superblock_config_valid_core_bitmap_is_valid( + const struct ocf_superblock_config *superblock) +{ + uint32_t bit; + + /* Bits beyond the last core id must not be set */ + for (bit = OCF_CORE_NUM; + bit < sizeof(superblock->valid_core_bitmap) * 8; + bit++) { + if (env_bit_test(bit, superblock->valid_core_bitmap)) + return false; + } + + return true; +} + void ocf_superblock_config_validate( const struct ocf_superblock_config *superblock, struct ocf_superblock_config_validity *valid) @@ -65,9 +95,14 @@ void ocf_superblock_config_validate( superblock->cache_mode < ocf_cache_mode_max; valid->name = + superblock->name[0] != '\0' && env_strnlen(superblock->name, sizeof(superblock->name)) < OCF_CACHE_NAME_SIZE; + valid->cachelines = + superblock->cachelines > 0 && + superblock->cachelines <= OCF_CACHE_LINE_MAX; + valid->valid_parts_no = superblock->valid_parts_no <= OCF_USER_IO_CLASS_MAX; @@ -75,7 +110,10 @@ void ocf_superblock_config_validate( ocf_superblock_config_line_size_is_valid(superblock->line_size); valid->core_count = - superblock->core_count <= OCF_CORE_NUM; + ocf_superblock_config_core_count_is_valid(superblock); + + valid->valid_core_bitmap = + ocf_superblock_config_valid_core_bitmap_is_valid(superblock); valid->cleaning_policy_type = superblock->cleaning_policy_type >= 0 && @@ -85,7 +123,22 @@ void ocf_superblock_config_validate( !superblock->cleaner_disabled || superblock->cleaning_policy_type == ocf_cleaning_nop; + ocf_alru_cleaning_policy_config_validate( + (const void *)superblock->cleaning[ocf_cleaning_alru].data, + &valid->cleaning.alru); + + ocf_acp_cleaning_policy_config_validate( + (const void *)superblock->cleaning[ocf_cleaning_acp].data, + &valid->cleaning.acp); + valid->promotion_policy_type = superblock->promotion_policy_type >= 0 && superblock->promotion_policy_type < ocf_promotion_max; + + ocf_nhit_promotion_policy_config_validate( + (const void *)superblock->promotion[ocf_promotion_nhit].data, + &valid->promotion.nhit); + + valid->prefetch_mask = + !(superblock->prefetch_mask & ~((1 << ocf_pf_num) - 1)); } diff --git a/src/metadata/layout/superblock.h b/src/metadata/layout/superblock.h index ae88f5af..96930b75 100644 --- a/src/metadata/layout/superblock.h +++ b/src/metadata/layout/superblock.h @@ -126,13 +126,24 @@ struct ocf_superblock_config_validity { bool flapping_idx; bool cache_mode; bool name; + bool cachelines; bool valid_parts_no; bool line_size; bool core_count; + /*!< Core count matches number of cores in valid core bitmap */ + bool valid_core_bitmap; bool cleaning_policy_type; bool cleaner_disabled; /*!< Cleaner can be disabled only with nop cleaning policy */ + struct { + struct alru_cleaning_policy_config_validity alru; + struct acp_cleaning_policy_config_validity acp; + } cleaning; bool promotion_policy_type; + struct { + struct nhit_promotion_policy_config_validity nhit; + } promotion; + bool prefetch_mask; }; /** diff --git a/src/metadata/metadata_superblock.c b/src/metadata/metadata_superblock.c index ca39167c..687de974 100644 --- a/src/metadata/metadata_superblock.c +++ b/src/metadata/metadata_superblock.c @@ -8,6 +8,7 @@ #include "metadata.h" #include "metadata_core.h" #include "metadata_internal.h" +#include "metadata_partition.h" #include "metadata_segment.h" #include "layout/segment_id.h" #include "metadata_superblock.h" @@ -195,6 +196,11 @@ int ocf_metadata_validate_superblock(ocf_ctx_t ctx, return -OCF_ERR_INVAL; } + if (!valid.cachelines) { + ocf_log_invalid_superblock("cache line count"); + return -OCF_ERR_INVAL; + } + if (!valid.valid_parts_no) { ocf_log_invalid_superblock("partition count"); return -OCF_ERR_INVAL; @@ -210,6 +216,11 @@ int ocf_metadata_validate_superblock(ocf_ctx_t ctx, return -OCF_ERR_INVAL; } + if (!valid.valid_core_bitmap) { + ocf_log_invalid_superblock("valid core bitmap"); + return -OCF_ERR_INVAL; + } + if (!valid.cleaning_policy_type) { ocf_log_invalid_superblock("cleaning policy"); return -OCF_ERR_INVAL; @@ -222,11 +233,61 @@ int ocf_metadata_validate_superblock(ocf_ctx_t ctx, return -OCF_ERR_INVAL; } + if (!valid.cleaning.alru.thread_wakeup_time) { + ocf_log_invalid_superblock("ALRU wake up time"); + return -OCF_ERR_INVAL; + } + + if (!valid.cleaning.alru.stale_buffer_time) { + ocf_log_invalid_superblock("ALRU staleness time"); + return -OCF_ERR_INVAL; + } + + if (!valid.cleaning.alru.flush_max_buffers) { + ocf_log_invalid_superblock("ALRU flush max buffers"); + return -OCF_ERR_INVAL; + } + + if (!valid.cleaning.alru.activity_threshold) { + ocf_log_invalid_superblock("ALRU activity threshold"); + return -OCF_ERR_INVAL; + } + + if (!valid.cleaning.alru.dirty_ratio_threshold) { + ocf_log_invalid_superblock("ALRU dirty ratio threshold"); + return -OCF_ERR_INVAL; + } + + if (!valid.cleaning.acp.thread_wakeup_time) { + ocf_log_invalid_superblock("ACP wake up time"); + return -OCF_ERR_INVAL; + } + + if (!valid.cleaning.acp.flush_max_buffers) { + ocf_log_invalid_superblock("ACP flush max buffers"); + return -OCF_ERR_INVAL; + } + if (!valid.promotion_policy_type) { ocf_log_invalid_superblock("promotion policy"); return -OCF_ERR_INVAL; } + if (!valid.promotion.nhit.insertion_threshold) { + ocf_log_invalid_superblock("NHIT insertion threshold"); + return -OCF_ERR_INVAL; + } + + if (!valid.promotion.nhit.trigger_threshold) { + ocf_log_invalid_superblock("NHIT trigger threshold"); + return -OCF_ERR_INVAL; + } + + if (!valid.prefetch_mask) { + ocf_log_invalid_superblock("prefetch mask"); + return -OCF_ERR_INVAL; + } + return 0; } @@ -264,6 +325,187 @@ static void _ocf_metadata_get_shutdown_status(ocf_pipeline_t pipeline, ocf_pipeline_next(pipeline); } +#define ocf_log_invalid_core(segment, core_id, param) \ + ocf_log(ctx, log_err, \ + "Loading %s: invalid %s of core %u\n", \ + ocf_metadata_segment_names[segment], \ + param, core_id) + +static void _ocf_metadata_validate_core_config(ocf_pipeline_t pipeline, + void *priv, ocf_pipeline_arg_t arg) +{ + struct ocf_metadata_context *context = priv; + ocf_ctx_t ctx = context->cache->owner; + struct ocf_metadata_ctrl *ctrl; + struct ocf_superblock_config *superblock; + struct ocf_core_meta_config *core_config; + struct ocf_core_meta_config_validity valid; + struct ocf_cores_validity cores_valid; + const enum ocf_metadata_segment_id segment = + metadata_segment_core_config; + ocf_core_id_t core_id; + + ctrl = (struct ocf_metadata_ctrl *)context->ctrl; + superblock = METADATA_MEM_POOL(ctrl, metadata_segment_sb_config); + core_config = METADATA_MEM_POOL(ctrl, metadata_segment_core_config); + + for (core_id = 0; core_id < OCF_CORE_NUM; core_id++) { + ocf_core_meta_config_validate(superblock, core_id, + &core_config[core_id], &valid); + + if (!valid.name) { + ocf_log_invalid_core(segment, core_id, "name"); + OCF_PL_FINISH_RET(pipeline, -OCF_ERR_INVAL); + } + + if (!valid.seq_no) { + ocf_log_invalid_core(segment, core_id, + "sequence number"); + OCF_PL_FINISH_RET(pipeline, -OCF_ERR_INVAL); + } + + if (!valid.seq_cutoff_threshold) { + ocf_log_invalid_core(segment, core_id, + "sequential cutoff threshold"); + OCF_PL_FINISH_RET(pipeline, -OCF_ERR_INVAL); + } + + if (!valid.seq_cutoff_policy) { + ocf_log_invalid_core(segment, core_id, + "sequential cutoff policy"); + OCF_PL_FINISH_RET(pipeline, -OCF_ERR_INVAL); + } + + if (!valid.seq_detect_promotion_count) { + ocf_log_invalid_core(segment, core_id, + "sequential detect promotion count"); + OCF_PL_FINISH_RET(pipeline, -OCF_ERR_INVAL); + } + + if (!valid.seq_detect_promotion_threshold) { + ocf_log_invalid_core(segment, core_id, + "sequential detect promotion threshold"); + OCF_PL_FINISH_RET(pipeline, -OCF_ERR_INVAL); + } + } + + ocf_cores_validate(superblock, core_config, &cores_valid); + + if (!cores_valid.seq_no) { + ocf_log(ctx, log_err, "Loading %s: core sequence numbers " + "are not unique\n", + ocf_metadata_segment_names[segment]); + OCF_PL_FINISH_RET(pipeline, -OCF_ERR_INVAL); + } + + ocf_pipeline_next(pipeline); +} + +static void _ocf_metadata_validate_core_uuid(ocf_pipeline_t pipeline, + void *priv, ocf_pipeline_arg_t arg) +{ + struct ocf_metadata_context *context = priv; + ocf_ctx_t ctx = context->cache->owner; + struct ocf_metadata_ctrl *ctrl; + struct ocf_superblock_config *superblock; + const struct ocf_metadata_uuid *core_uuid; + struct ocf_metadata_uuid_validity valid; + const enum ocf_metadata_segment_id segment = + metadata_segment_core_uuid; + ocf_core_id_t core_id; + + ctrl = (struct ocf_metadata_ctrl *)context->ctrl; + superblock = METADATA_MEM_POOL(ctrl, metadata_segment_sb_config); + + for (core_id = 0; core_id < OCF_CORE_NUM; core_id++) { + core_uuid = ocf_metadata_raw_rd_access(context->cache, + &ctrl->raw_desc[segment], core_id); + + ocf_metadata_uuid_validate(superblock, core_id, core_uuid, + &valid); + + if (!valid.size) { + ocf_log_invalid_core(segment, core_id, "uuid size"); + OCF_PL_FINISH_RET(pipeline, -OCF_ERR_INVAL); + } + } + + ocf_pipeline_next(pipeline); +} + +#define ocf_log_invalid_part(part_id, param) \ + ocf_log(ctx, log_err, \ + "Loading %s: invalid %s of partition %u\n", \ + ocf_metadata_segment_names[metadata_segment_part_config], \ + param, part_id) + +static void _ocf_metadata_validate_part_config(ocf_pipeline_t pipeline, + void *priv, ocf_pipeline_arg_t arg) +{ + struct ocf_metadata_context *context = priv; + ocf_ctx_t ctx = context->cache->owner; + struct ocf_metadata_ctrl *ctrl; + struct ocf_superblock_config *superblock; + struct ocf_user_part_config *part_config; + struct ocf_user_part_config_validity valid; + struct ocf_user_parts_validity parts_valid; + ocf_part_id_t part_id; + + ctrl = (struct ocf_metadata_ctrl *)context->ctrl; + superblock = METADATA_MEM_POOL(ctrl, metadata_segment_sb_config); + part_config = METADATA_MEM_POOL(ctrl, metadata_segment_part_config); + + for (part_id = 0; part_id < OCF_USER_IO_CLASS_MAX; part_id++) { + ocf_user_part_config_validate(&part_config[part_id], &valid); + + if (!valid.name) { + ocf_log_invalid_part(part_id, "name"); + OCF_PL_FINISH_RET(pipeline, -OCF_ERR_INVAL); + } + + if (!valid.min_size) { + ocf_log_invalid_part(part_id, "min size"); + OCF_PL_FINISH_RET(pipeline, -OCF_ERR_INVAL); + } + + if (!valid.max_size) { + ocf_log_invalid_part(part_id, "max size"); + OCF_PL_FINISH_RET(pipeline, -OCF_ERR_INVAL); + } + + if (!valid.priority) { + ocf_log_invalid_part(part_id, "priority"); + OCF_PL_FINISH_RET(pipeline, -OCF_ERR_INVAL); + } + + if (!valid.cache_mode) { + ocf_log_invalid_part(part_id, "cache mode"); + OCF_PL_FINISH_RET(pipeline, -OCF_ERR_INVAL); + } + } + + ocf_user_parts_validate(superblock, part_config, &parts_valid); + + if (!parts_valid.valid_parts_no) { + ocf_log(ctx, log_err, "Loading %s: number of valid partitions " + "does not match superblock\n", + ocf_metadata_segment_names[ + metadata_segment_part_config]); + OCF_PL_FINISH_RET(pipeline, -OCF_ERR_INVAL); + } + + if (!parts_valid.min_size) { + ocf_log(ctx, log_err, "Loading %s: sum of partition min sizes " + "exceeds %u%%\n", + ocf_metadata_segment_names[ + metadata_segment_part_config], + PARTITION_SIZE_MAX); + OCF_PL_FINISH_RET(pipeline, -OCF_ERR_INVAL); + } + + ocf_pipeline_next(pipeline); +} + static void ocf_metadata_load_sb_restore( struct ocf_metadata_context *context) { @@ -353,6 +595,9 @@ struct ocf_pipeline_properties ocf_metadata_load_sb_pipeline_props = { OCF_PL_STEP_FOREACH_COND(ocf_metadata_load_sb_segment_is_valid, ocf_metadata_check_crc, ocf_metadata_load_sb_load_segment_args), + OCF_PL_STEP(_ocf_metadata_validate_part_config), + OCF_PL_STEP(_ocf_metadata_validate_core_config), + OCF_PL_STEP(_ocf_metadata_validate_core_uuid), OCF_PL_STEP_TERMINATOR(), }, };