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 new file mode 100644 index 00000000..35b5c6a0 --- /dev/null +++ b/src/metadata/layout/cleaning_policy.h @@ -0,0 +1,121 @@ +/* + * 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 */ +}; + +/** + * @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 { +}; + +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.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 new file mode 100644 index 00000000..b16ef9e0 --- /dev/null +++ b/src/metadata/layout/core.h @@ -0,0 +1,140 @@ +/* + * 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" +#include "superblock.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; + + /* 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]; +}; + +/** + * @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/metadata_layout.c b/src/metadata/layout/layout.c similarity index 84% rename from src/metadata/metadata_layout.c rename to src/metadata/layout/layout.c index 2a20e30e..8b042caa 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 @@ -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/metadata_layout.h b/src/metadata/layout/layout.h similarity index 79% rename from src/metadata/metadata_layout.h rename to src/metadata/layout/layout.h index c1b35707..2b6151a0 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. @@ -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/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.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 new file mode 100644 index 00000000..84c54a7a --- /dev/null +++ b/src/metadata/layout/partition.h @@ -0,0 +1,96 @@ +/* + * 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" +#include "superblock.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; +}; + +/** + * @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/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.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 new file mode 100644 index 00000000..14db7cad --- /dev/null +++ b/src/metadata/layout/promotion_policy.h @@ -0,0 +1,47 @@ +/* + * 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) */ +}; + +/** + * @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/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.c b/src/metadata/layout/superblock.c new file mode 100644 index 00000000..e058d8c8 --- /dev/null +++ b/src/metadata/layout/superblock.c @@ -0,0 +1,144 @@ +/* + * 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; + } +} + +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) +{ + 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 = + 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; + + valid->line_size = + ocf_superblock_config_line_size_is_valid(superblock->line_size); + + valid->core_count = + 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 && + superblock->cleaning_policy_type < ocf_cleaning_max; + + valid->cleaner_disabled = + !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 new file mode 100644 index 00000000..96930b75 --- /dev/null +++ b/src/metadata/layout/superblock.h @@ -0,0 +1,159 @@ +/* + * 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*/ +}; + +/* + * Values of dirty_flushed field of superblock config + */ +#define DIRTY_NOT_FLUSHED 0 +#define DIRTY_FLUSHED 1 + +/** + * @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; +}; + +/** + * @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 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; +}; + +/** + * @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.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..540ee0fb 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 @@ -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_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..687de974 100644 --- a/src/metadata/metadata_superblock.c +++ b/src/metadata/metadata_superblock.c @@ -8,8 +8,9 @@ #include "metadata.h" #include "metadata_core.h" #include "metadata_internal.h" +#include "metadata_partition.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" @@ -105,17 +106,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 +131,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 +147,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 +162,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,69 +171,123 @@ 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.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; } - 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.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; } - 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.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; } @@ -255,6 +309,28 @@ 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); +} + +#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) { @@ -263,30 +339,170 @@ static void _ocf_metadata_validate_core_config(ocf_pipeline_t pipeline, 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; - 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); + 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_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"); + 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 (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"); + 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); } @@ -353,6 +569,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,11 +588,16 @@ 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(_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), - 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_part_config), OCF_PL_STEP(_ocf_metadata_validate_core_config), + OCF_PL_STEP(_ocf_metadata_validate_core_uuid), OCF_PL_STEP_TERMINATOR(), }, }; @@ -412,72 +643,6 @@ void ocf_metadata_load_superblock(ocf_cache_t cache, ocf_metadata_end_t cmpl, 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(), - }, -}; - -/* - * Super Block - Recovery load - */ -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); -} - 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 d5a003ea..7f04a1b3 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; @@ -112,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..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"); @@ -1832,13 +1833,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, 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 6b65656d..6f4dc435 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, @@ -146,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; @@ -515,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 ac0c8634..570da8c6 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; @@ -158,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, \ 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;