From 196437f9bc2b258bb9026922489a0f511f64e57a Mon Sep 17 00:00:00 2001 From: Adam Rutkowski Date: Tue, 21 Dec 2021 18:16:23 +0100 Subject: [PATCH 1/2] Zero superblock before writing metadata This is the first step towards atomic initialization of metadata on cache disk. Signed-off-by: Adam Rutkowski --- src/metadata/metadata.c | 10 +++++ src/metadata/metadata.h | 3 ++ src/metadata/metadata_raw.c | 57 +++++++++++++++++++++++++++- src/metadata/metadata_raw.h | 20 ++++++++++ src/metadata/metadata_raw_volatile.c | 9 +++++ src/metadata/metadata_raw_volatile.h | 5 +++ src/metadata/metadata_superblock.c | 10 +++++ src/metadata/metadata_superblock.h | 3 ++ src/mngt/ocf_mngt_cache.c | 26 +++++++++++++ 9 files changed, 141 insertions(+), 2 deletions(-) diff --git a/src/metadata/metadata.c b/src/metadata/metadata.c index 9c033df..ac43b33 100644 --- a/src/metadata/metadata.c +++ b/src/metadata/metadata.c @@ -1628,6 +1628,16 @@ void ocf_metadata_load_properties(ocf_volume_t volume, OCF_CMPL_RET(priv, result, NULL); } +void ocf_metadata_zero_superblock(ocf_cache_t cache, + ocf_metadata_end_t cmpl, void *context) +{ + struct ocf_metadata_ctrl *ctrl = (struct ocf_metadata_ctrl *) + cache->metadata.priv; + + ocf_metadata_sb_zero(ctrl->segment[metadata_segment_sb_config], + cmpl, context); +} + /* metadata segment data + iterators */ struct query_cores_data { diff --git a/src/metadata/metadata.h b/src/metadata/metadata.h index 630b470..9f0ef00 100644 --- a/src/metadata/metadata.h +++ b/src/metadata/metadata.h @@ -217,4 +217,7 @@ static inline ocf_cache_line_t ocf_metadata_collision_table_entries( return cache->device->collision_table_entries; } +void ocf_metadata_zero_superblock(ocf_cache_t cache, + ocf_metadata_end_t cmpl, void *context); + #endif /* METADATA_H_ */ diff --git a/src/metadata/metadata_raw.c b/src/metadata/metadata_raw.c index 3276443..f19560e 100644 --- a/src/metadata/metadata_raw.c +++ b/src/metadata/metadata_raw.c @@ -41,13 +41,21 @@ static uint32_t _raw_ram_segment_size_on_ssd(struct ocf_metadata_raw *raw) return OCF_DIV_ROUND_UP(raw->ssd_pages, alignment) * alignment; } + +static uint32_t _raw_ram_segment_size_on_ssd_total(struct ocf_metadata_raw *raw) +{ + uint32_t size = _raw_ram_segment_size_on_ssd(raw) * + (raw->flapping ? 2 : 1); + + return size; +} + /* * Check if page is valid for specified RAW descriptor */ static bool _raw_ssd_page_is_valid(struct ocf_metadata_raw *raw, uint32_t page) { - uint32_t size = _raw_ram_segment_size_on_ssd(raw) * - (raw->flapping ? 2 : 1); + uint32_t size = _raw_ram_segment_size_on_ssd_total(raw); ENV_BUG_ON(page < raw->ssd_pages_offset); ENV_BUG_ON(page >= (raw->ssd_pages_offset + size)); @@ -235,6 +243,47 @@ static int _raw_ram_update(ocf_cache_t cache, } +static int raw_ram_zero_do_asynch_fill(ocf_cache_t cache, + ctx_data_t *data, uint32_t page, void *context) +{ + ctx_data_zero(cache->owner, data, PAGE_SIZE); + + return 0; +} + +struct ocf_raw_ram_zero_ctx +{ + ocf_metadata_end_t cmpl; + void *priv; +}; + +static void raw_ram_zero_end(ocf_cache_t cache, + void *context, int error) +{ + struct ocf_raw_ram_zero_ctx *zero_ctx = context; + + zero_ctx->cmpl(zero_ctx->priv, error); + env_free(zero_ctx); +} + +static void raw_ram_zero(ocf_cache_t cache, struct ocf_metadata_raw *raw, + ocf_metadata_end_t cmpl, void *priv) +{ + struct ocf_raw_ram_zero_ctx *ctx; + + ctx = env_malloc(sizeof(*ctx), ENV_MEM_NORMAL); + if (!ctx) + cmpl(priv, -OCF_ERR_NO_MEM); + ctx->cmpl = cmpl; + ctx->priv = priv; + + metadata_io_write_i_asynch(cache, cache->mngt_queue, ctx, + raw->ssd_pages_offset, + _raw_ram_segment_size_on_ssd_total(raw), + 0, raw_ram_zero_do_asynch_fill, + raw_ram_zero_end, NULL); +} + struct _raw_ram_load_all_context { struct ocf_metadata_raw *raw; uint64_t ssd_pages_offset; @@ -603,6 +652,7 @@ static const struct raw_iface IRAW[metadata_raw_type_max] = { .page = _raw_ram_page, .access = _raw_ram_access, .update = _raw_ram_update, + .zero = raw_ram_zero, .load_all = _raw_ram_load_all, .flush_all = _raw_ram_flush_all, .flush_mark = _raw_ram_flush_mark, @@ -617,6 +667,7 @@ static const struct raw_iface IRAW[metadata_raw_type_max] = { .page = raw_dynamic_page, .access = raw_dynamic_access, .update = raw_dynamic_update, + .zero = raw_ram_zero, .load_all = raw_dynamic_load_all, .flush_all = raw_dynamic_flush_all, .flush_mark = raw_dynamic_flush_mark, @@ -631,6 +682,7 @@ static const struct raw_iface IRAW[metadata_raw_type_max] = { .page = _raw_ram_page, .access = _raw_ram_access, .update = raw_volatile_update, + .zero = raw_volatile_zero, .load_all = raw_volatile_load_all, .flush_all = raw_volatile_flush_all, .flush_mark = raw_volatile_flush_mark, @@ -645,6 +697,7 @@ static const struct raw_iface IRAW[metadata_raw_type_max] = { .page = _raw_ram_page, .access = _raw_ram_access, .update = _raw_ram_update, + .zero = raw_ram_zero, .load_all = _raw_ram_load_all, .flush_all = _raw_ram_flush_all, .flush_mark = raw_atomic_flush_mark, diff --git a/src/metadata/metadata_raw.h b/src/metadata/metadata_raw.h index b016dee..f262709 100644 --- a/src/metadata/metadata_raw.h +++ b/src/metadata/metadata_raw.h @@ -129,6 +129,9 @@ struct raw_iface { int (*update)(ocf_cache_t cache, struct ocf_metadata_raw *raw, ctx_data_t *data, uint64_t page, uint64_t count); + void (*zero)(ocf_cache_t cache, struct ocf_metadata_raw *raw, + ocf_metadata_end_t cmpl, void *priv); + void (*load_all)(ocf_cache_t cache, struct ocf_metadata_raw *raw, ocf_metadata_end_t cmpl, void *priv, unsigned flapping_idx); @@ -265,6 +268,23 @@ static inline int ocf_metadata_raw_update(ocf_cache_t cache, return raw->iface->update(cache, raw, data, page, count); } +/** + * @brief Zero metadata + * @details NOTE: this is fo management purposes only, no synchronization with + * I/O is guarangeed + * + * @param cache - Cache instance + * @param raw - RAW descriptor + * @param cmpl - completion callback + * @param priv - completion callback private context + */ +static inline void ocf_metadata_raw_zero(ocf_cache_t cache, + struct ocf_metadata_raw *raw, ocf_metadata_end_t cmpl, + void *priv) +{ + raw->iface->zero(cache, raw, cmpl, priv); +} + /** * @brief Load all entries from SSD cache (cahce cache) * diff --git a/src/metadata/metadata_raw_volatile.c b/src/metadata/metadata_raw_volatile.c index a7b4e15..8a4a720 100644 --- a/src/metadata/metadata_raw_volatile.c +++ b/src/metadata/metadata_raw_volatile.c @@ -37,6 +37,15 @@ int raw_volatile_update(ocf_cache_t cache, return 0; } +/* + * RAW volatile Implementation - Zero - implemented as noop + */ +void raw_volatile_zero(ocf_cache_t cache, struct ocf_metadata_raw *raw, + ocf_metadata_end_t cmpl, void *context) +{ + cmpl(context, 0); +} + /* * RAW volatile Implementation - Load all metadata elements from SSD */ diff --git a/src/metadata/metadata_raw_volatile.h b/src/metadata/metadata_raw_volatile.h index fe3a71e..8a28564 100644 --- a/src/metadata/metadata_raw_volatile.h +++ b/src/metadata/metadata_raw_volatile.h @@ -24,6 +24,11 @@ int raw_volatile_update(ocf_cache_t cache, struct ocf_metadata_raw *raw, ctx_data_t *data, uint64_t page, uint64_t count); +/* + * RAW volatile Implementation - Zero + */ +void raw_volatile_zero(ocf_cache_t cache, struct ocf_metadata_raw *raw, + ocf_metadata_end_t cmpl, void *context); /* * RAW volatile Implementation - Load all metadata elements from SSD */ diff --git a/src/metadata/metadata_superblock.c b/src/metadata/metadata_superblock.c index 52772a3..f4eab78 100644 --- a/src/metadata/metadata_superblock.c +++ b/src/metadata/metadata_superblock.c @@ -504,6 +504,7 @@ struct ocf_metadata_superblock { struct ocf_metadata_segment segment; struct ocf_superblock_config *config; + ocf_cache_t cache; }; #define _ocf_segment_to_sb(_segment) \ @@ -529,6 +530,7 @@ int ocf_metadata_superblock_init( } sb->config = ocf_metadata_raw_get_mem(sb->segment.raw); + sb->cache = cache; *self = &sb->segment; return 0; @@ -752,3 +754,11 @@ void ocf_metadata_sb_crc_recovery(ocf_cache_t cache, ocf_pipeline_next(pipeline); } + +void ocf_metadata_sb_zero(struct ocf_metadata_segment *self, + ocf_metadata_end_t cmpl, void *priv) +{ + struct ocf_metadata_superblock *sb = _ocf_segment_to_sb(self); + + ocf_metadata_raw_zero(sb->cache, sb->segment.raw, cmpl, priv); +} diff --git a/src/metadata/metadata_superblock.h b/src/metadata/metadata_superblock.h index 16e0285..073abe3 100644 --- a/src/metadata/metadata_superblock.h +++ b/src/metadata/metadata_superblock.h @@ -131,4 +131,7 @@ int ocf_metadata_read_sb(ocf_ctx_t ctx, ocf_volume_t volume, void ocf_metadata_sb_crc_recovery(ocf_cache_t cache, ocf_metadata_end_t cmpl, void *priv); +void ocf_metadata_sb_zero(struct ocf_metadata_segment *self, + ocf_metadata_end_t cmpl, void *priv); + #endif /* METADATA_SUPERBLOCK_H_ */ diff --git a/src/mngt/ocf_mngt_cache.c b/src/mngt/ocf_mngt_cache.c index affe120..6e08f94 100644 --- a/src/mngt/ocf_mngt_cache.c +++ b/src/mngt/ocf_mngt_cache.c @@ -1476,6 +1476,30 @@ static void _ocf_mngt_init_promotion(ocf_pipeline_t pipeline, ocf_pipeline_next(pipeline); } +static void _ocf_mngt_zero_superblock_complete(void *priv, int error) +{ + struct ocf_cache_attach_context *context = priv; + ocf_cache_t cache = context->cache; + + if (error) { + ocf_cache_log(cache, log_err, + "ERROR: Failed to clear superblock\n"); + OCF_PL_FINISH_RET(context->pipeline, -OCF_ERR_WRITE_CACHE); + } + + ocf_pipeline_next(context->pipeline); +} + +static void _ocf_mngt_zero_superblock(ocf_pipeline_t pipeline, + void *priv, ocf_pipeline_arg_t arg) +{ + struct ocf_cache_attach_context *context = priv; + ocf_cache_t cache = context->cache; + + ocf_metadata_zero_superblock(cache, + _ocf_mngt_zero_superblock_complete, context); +} + static void _ocf_mngt_attach_flush_metadata_complete(void *priv, int error) { struct ocf_cache_attach_context *context = priv; @@ -1685,6 +1709,7 @@ struct ocf_pipeline_properties _ocf_mngt_cache_attach_pipeline_properties = { OCF_PL_STEP(_ocf_mngt_init_cleaner), OCF_PL_STEP(_ocf_mngt_init_promotion), OCF_PL_STEP(_ocf_mngt_attach_init_instance), + OCF_PL_STEP(_ocf_mngt_zero_superblock), OCF_PL_STEP(_ocf_mngt_attach_flush_metadata), OCF_PL_STEP(_ocf_mngt_attach_discard), OCF_PL_STEP(_ocf_mngt_attach_flush), @@ -2139,6 +2164,7 @@ struct ocf_pipeline_properties _ocf_mngt_cache_standby_attach_pipeline_propertie OCF_PL_STEP(_ocf_mngt_standby_init_cleaning), OCF_PL_STEP(_ocf_mngt_standby_preapre_mempool), OCF_PL_STEP(_ocf_mngt_standby_init_pio_concurrency), + OCF_PL_STEP(_ocf_mngt_zero_superblock), OCF_PL_STEP(_ocf_mngt_attach_flush_metadata), OCF_PL_STEP(_ocf_mngt_attach_discard), OCF_PL_STEP(_ocf_mngt_attach_flush), From 9693b82cf9899abe35c13959135cd56ccae86fae Mon Sep 17 00:00:00 2001 From: Adam Rutkowski Date: Thu, 23 Dec 2021 13:29:04 +0100 Subject: [PATCH 2/2] Only flush superblock at the end of cache attach The purpose of this change is not to write superblock to the cache drive untill all other sections are initilized on disk in attach() path. Combined with superblock clearing at the erarlier stage of attach(), this assures there are no residual mappings in the collision section in case of power failure during attach with pre-existing metadata. This is implemented by removing ocf_metadata_flush_all_set_status() step at the beginning of ocf_metadata_flush_all(). ocf_metadata_flush_all() is called, except for the attach() case described above, in two cases: 1. at the end of cache load - potentially after cache recovery 2. during detaching cache drive in cache stop. To make sure there are no regressions in the first case, an explicit _ocf_mngt_attach_shutdown_status() is added to load pipeline before ocf_metadata_flush_all(). The second case is always ran after cache drive is attached, so dirty status bit must have already be written to the disk. Signed-off-by: Adam Rutkowski --- src/metadata/metadata.c | 2 -- src/mngt/ocf_mngt_cache.c | 1 + 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/metadata/metadata.c b/src/metadata/metadata.c index ac43b33..02c6be6 100644 --- a/src/metadata/metadata.c +++ b/src/metadata/metadata.c @@ -991,8 +991,6 @@ struct ocf_pipeline_properties ocf_metadata_flush_all_pipeline_props = { .priv_size = sizeof(struct ocf_metadata_context), .finish = ocf_metadata_flush_all_finish, .steps = { - OCF_PL_STEP_ARG_INT(ocf_metadata_flush_all_set_status, - ocf_metadata_dirty_shutdown), OCF_PL_STEP_FOREACH(ocf_metadata_flush_segment, ocf_metadata_flush_all_args), OCF_PL_STEP_FOREACH(ocf_metadata_calculate_crc, diff --git a/src/mngt/ocf_mngt_cache.c b/src/mngt/ocf_mngt_cache.c index 6e08f94..5ea714a 100644 --- a/src/mngt/ocf_mngt_cache.c +++ b/src/mngt/ocf_mngt_cache.c @@ -1737,6 +1737,7 @@ struct ocf_pipeline_properties _ocf_mngt_cache_load_pipeline_properties = { OCF_PL_STEP(_ocf_mngt_load_add_cores), OCF_PL_STEP(_ocf_mngt_load_metadata), OCF_PL_STEP(_ocf_mngt_load_post_metadata_load), + OCF_PL_STEP(_ocf_mngt_attach_shutdown_status), OCF_PL_STEP(_ocf_mngt_attach_flush_metadata), OCF_PL_STEP(_ocf_mngt_attach_shutdown_status), OCF_PL_STEP(_ocf_mngt_attach_post_init),