From 5ad4d937f6626fc27d715eb52798735e615a42e3 Mon Sep 17 00:00:00 2001 From: Adam Rutkowski Date: Wed, 6 Oct 2021 12:36:39 +0200 Subject: [PATCH 1/3] Failover detach Signed-off-by: Adam Rutkowski --- example/simple/src/main.c | 10 +- inc/ocf_cache.h | 5 +- inc/ocf_def.h | 4 +- inc/ocf_mngt.h | 68 +++++---- src/mngt/ocf_mngt_cache.c | 300 +++++++++++++++++++++++++++----------- src/ocf_cache.c | 10 +- 6 files changed, 273 insertions(+), 124 deletions(-) diff --git a/example/simple/src/main.c b/example/simple/src/main.c index d5b7d62..d8aec22 100644 --- a/example/simple/src/main.c +++ b/example/simple/src/main.c @@ -94,7 +94,7 @@ static void simple_complete(ocf_cache_t cache, void *priv, int error) int initialize_cache(ocf_ctx_t ctx, ocf_cache_t *cache) { struct ocf_mngt_cache_config cache_cfg = { .name = "cache1" }; - struct ocf_mngt_cache_device_config device_cfg = { }; + struct ocf_mngt_cache_attach_config attach_cfg = { }; struct cache_priv *cache_priv; struct simple_context context; int ret; @@ -110,9 +110,9 @@ int initialize_cache(ocf_ctx_t ctx, ocf_cache_t *cache) cache_cfg.metadata_volatile = true; /* Cache deivce (volume) configuration */ - ocf_mngt_cache_device_config_set_default(&device_cfg); - device_cfg.volume_type = VOL_TYPE; - ret = ocf_uuid_set_str(&device_cfg.uuid, "cache"); + ocf_mngt_cache_attach_config_set_default(&attach_cfg); + attach_cfg.device.volume_type = VOL_TYPE; + ret = ocf_uuid_set_str(&attach_cfg.device.uuid, "cache"); if (ret) return ret; @@ -158,7 +158,7 @@ int initialize_cache(ocf_ctx_t ctx, ocf_cache_t *cache) goto err_cache; /* Attach volume to cache */ - ocf_mngt_cache_attach(*cache, &device_cfg, simple_complete, &context); + ocf_mngt_cache_attach(*cache, &attach_cfg, simple_complete, &context); if (ret) goto err_cache; diff --git a/inc/ocf_cache.h b/inc/ocf_cache.h index 0595d87..5be621f 100644 --- a/inc/ocf_cache.h +++ b/inc/ocf_cache.h @@ -92,6 +92,9 @@ struct ocf_cache_info { uint32_t metadata_end_offset; /*!< LBA offset where metadata ends (in 4KiB blocks) */ + + bool failover_detached; + /*!< true if cache drive detached for failover */ }; /** @@ -159,7 +162,7 @@ bool ocf_cache_is_running(ocf_cache_t cache); * @retval 1 Caching device is in passive state * @retval 0 Caching device is not in passive state */ -bool ocf_cache_is_passive(ocf_cache_t cache); +bool ocf_cache_is_standby(ocf_cache_t cache); /** * @brief Get cache mode of given cache object diff --git a/inc/ocf_def.h b/inc/ocf_def.h index c654ef0..913807d 100644 --- a/inc/ocf_def.h +++ b/inc/ocf_def.h @@ -124,8 +124,8 @@ typedef enum { ocf_cache_state_incomplete = 3, //!< ocf_cache_state_incomplete /*!< OCF cache has at least one inactive core */ - ocf_cache_state_passive = 4, //!< ocf_cache_state_passive - /*!< OCF is currently in passive mode */ + ocf_cache_state_standby = 4, //!< ocf_cache_state_standby + /*!< OCF is currently in standby mode */ ocf_cache_state_max //!< ocf_cache_state_max /*!< Stopper of cache state enumerator */ diff --git a/inc/ocf_mngt.h b/inc/ocf_mngt.h index c61db74..a6db0a9 100644 --- a/inc/ocf_mngt.h +++ b/inc/ocf_mngt.h @@ -359,7 +359,7 @@ void ocf_mngt_cache_stop(ocf_cache_t cache, ocf_mngt_cache_stop_end_t cmpl, void *priv); /** - * @brief Cache attach configuration + * @brief Caching device configuration */ struct ocf_mngt_cache_device_config { /** @@ -367,16 +367,38 @@ struct ocf_mngt_cache_device_config { */ struct ocf_volume_uuid uuid; - /** - * @brief Cache line size - */ - ocf_cache_line_size_t cache_line_size; - /** * @brief Cache volume type */ uint8_t volume_type; + /** + * @brief If set, cache features (like discard) are tested + * before starting cache + */ + bool perform_test; + + /** + * @brief Optional opaque volume parameters, passed down to cache volume + * open callback + */ + void *volume_params; +}; + +/** + * @brief Cache attach configuration + */ +struct ocf_mngt_cache_attach_config { + /** + * @brief Cache device configuration - must be the first field + */ + struct ocf_mngt_cache_device_config device; + + /** + * @brief Cache line size + */ + ocf_cache_line_size_t cache_line_size; + /** * @brief Automatically open core volumes when loading cache * @@ -400,22 +422,10 @@ struct ocf_mngt_cache_device_config { */ bool force; - /** - * @brief If set, cache features (like discard) are tested - * before starting cache - */ - bool perform_test; - /** * @brief If set, cache device will be discarded on cache start */ bool discard_on_start; - - /** - * @brief Optional opaque volume parameters, passed down to cache volume - * open callback - */ - void *volume_params; }; /** @@ -426,15 +436,15 @@ struct ocf_mngt_cache_device_config { * * @param[in] cfg Cache device config stucture */ -static inline void ocf_mngt_cache_device_config_set_default( - struct ocf_mngt_cache_device_config *cfg) +static inline void ocf_mngt_cache_attach_config_set_default( + struct ocf_mngt_cache_attach_config *cfg) { cfg->cache_line_size = ocf_cache_line_size_none; cfg->open_cores = true; cfg->force = false; - cfg->perform_test = true; cfg->discard_on_start = true; - cfg->volume_params = NULL; + cfg->device.perform_test = true; + cfg->device.volume_params = NULL; } /** @@ -469,7 +479,7 @@ typedef void (*ocf_mngt_cache_attach_end_t)(ocf_cache_t cache, * @param[in] priv Completion callback context */ void ocf_mngt_cache_attach(ocf_cache_t cache, - struct ocf_mngt_cache_device_config *cfg, + struct ocf_mngt_cache_attach_config *cfg, ocf_mngt_cache_attach_end_t cmpl, void *priv); /** @@ -511,7 +521,7 @@ typedef void (*ocf_mngt_cache_load_end_t)(ocf_cache_t cache, * @param[in] priv Completion callback context */ void ocf_mngt_cache_load(ocf_cache_t cache, - struct ocf_mngt_cache_device_config *cfg, + struct ocf_mngt_cache_attach_config *cfg, ocf_mngt_cache_load_end_t cmpl, void *priv); /** @@ -525,17 +535,21 @@ typedef void (*ocf_mngt_cache_bind_end_t)(ocf_cache_t cache, void *priv, int error); /** - * @brief Bind cache instance + * @brief Initiate failover standby * * @param[in] cache Cache handle * @param[in] cfg Caching device configuration * @param[in] cmpl Completion callback * @param[in] priv Completion callback context */ -void ocf_mngt_cache_bind(ocf_cache_t cache, - struct ocf_mngt_cache_device_config *cfg, +void ocf_mngt_cache_standby(ocf_cache_t cache, + struct ocf_mngt_cache_attach_config *cfg, ocf_mngt_cache_bind_end_t cmpl, void *priv); +typedef void (*ocf_mngt_cache_failover_detach_end_t)(void *priv, int error); + +void ocf_mngt_cache_failover_detach(ocf_cache_t cache, + ocf_mngt_cache_failover_detach_end_t cmpl, void *priv); /** * @brief Completion callback of cache activate operation * diff --git a/src/mngt/ocf_mngt_cache.c b/src/mngt/ocf_mngt_cache.c index be4a59f..350cfe2 100644 --- a/src/mngt/ocf_mngt_cache.c +++ b/src/mngt/ocf_mngt_cache.c @@ -87,10 +87,11 @@ typedef void (*_ocf_mngt_cache_attach_end_t)(ocf_cache_t, void *priv1, void *priv2, int error); struct ocf_cache_attach_context { + struct ocf_mngt_cache_attach_config cfg; + ocf_cache_t cache; /*!< cache that is being initialized */ - struct ocf_mngt_cache_device_config cfg; uint64_t volume_size; /*!< size of the device in cache lines */ @@ -134,6 +135,14 @@ struct ocf_cache_attach_context { * load or recovery */ + bool uuid_copied : 1; + /*!< copied uuid data to context. + */ + + bool metadata_frozen : 1; + /*!< metadata reference counter frozen + */ + bool concurrency_inited : 1; } flags; @@ -690,6 +699,7 @@ static void _ocf_mngt_attach_cache_device(ocf_pipeline_t pipeline, void *priv, ocf_pipeline_arg_t arg) { struct ocf_cache_attach_context *context = priv; + struct ocf_mngt_cache_device_config *device_cfg = &context->cfg.device; ocf_cache_t cache = context->cache; ocf_volume_type_t type; int ret; @@ -701,14 +711,14 @@ static void _ocf_mngt_attach_cache_device(ocf_pipeline_t pipeline, context->flags.device_alloc = true; /* Prepare UUID of cache volume */ - type = ocf_ctx_get_volume_type(cache->owner, context->cfg.volume_type); + type = ocf_ctx_get_volume_type(cache->owner, device_cfg->volume_type); if (!type) { OCF_PL_FINISH_RET(pipeline, -OCF_ERR_INVAL_VOLUME_TYPE); } ret = ocf_volume_init(&cache->device->volume, type, - &context->cfg.uuid, true); + &device_cfg->uuid, true); if (ret) OCF_PL_FINISH_RET(pipeline, ret); @@ -720,7 +730,7 @@ static void _ocf_mngt_attach_cache_device(ocf_pipeline_t pipeline, * need to know size of cache device. */ ret = ocf_volume_open(&cache->device->volume, - context->cfg.volume_params); + device_cfg->volume_params); if (ret) { ocf_cache_log(cache, log_err, "ERROR: Cache not available\n"); OCF_PL_FINISH_RET(pipeline, ret); @@ -943,13 +953,14 @@ static void _ocf_mngt_test_volume(ocf_pipeline_t pipeline, void *priv, ocf_pipeline_arg_t arg) { struct ocf_cache_attach_context *context = priv; + struct ocf_mngt_cache_device_config *device_cfg = &context->cfg.device; ocf_cache_t cache = context->cache; ocf_pipeline_t test_pipeline; int result; cache->device->volume.features.discard_zeroes = 1; - if (!context->cfg.perform_test) + if (!device_cfg->perform_test) OCF_PL_NEXT_RET(pipeline); context->test.reserved_lba_addr = ocf_metadata_get_reserved_lba(cache); @@ -1154,8 +1165,7 @@ int ocf_mngt_get_ram_needed(ocf_cache_t cache, if (!type) return -OCF_ERR_INVAL_VOLUME_TYPE; - result = ocf_volume_create(&volume, type, - &cfg->uuid); + result = ocf_volume_create(&volume, type, &cfg->uuid); if (result) return result; @@ -1319,15 +1329,15 @@ static void _ocf_mngt_cache_set_passive(ocf_cache_t cache) * Clear initialization state and set the passive bit. */ env_bit_clear(ocf_cache_state_initializing, &cache->cache_state); - env_bit_set(ocf_cache_state_passive, &cache->cache_state); + env_bit_set(ocf_cache_state_standby, &cache->cache_state); } static void _ocf_mngt_cache_set_active(ocf_cache_t cache) { /* - * Clear passive state and set the running bit. + * Clear standby state and set the running bit. */ - env_bit_clear(ocf_cache_state_passive, &cache->cache_state); + env_bit_clear(ocf_cache_state_standby, &cache->cache_state); env_bit_set(ocf_cache_state_running, &cache->cache_state); } @@ -1346,22 +1356,26 @@ static void _ocf_mngt_copy_uuid_data(ocf_pipeline_t pipeline, void *priv, ocf_pipeline_arg_t arg) { struct ocf_cache_attach_context *context = priv; - struct ocf_mngt_cache_device_config *cfg = &context->cfg; + struct ocf_mngt_cache_device_config *device_cfg = &context->cfg.device; void *data; int result; - data = env_vmalloc(cfg->uuid.size); + if (device_cfg->uuid.size == 0) + OCF_PL_NEXT_RET(pipeline); + + data = env_vmalloc(device_cfg->uuid.size); if (!data) OCF_PL_FINISH_RET(pipeline, -OCF_ERR_NO_MEM); - result = env_memcpy(data, cfg->uuid.size, cfg->uuid.data, - cfg->uuid.size); + result = env_memcpy(data, device_cfg->uuid.size, device_cfg->uuid.data, + device_cfg->uuid.size); if (result) { env_vfree(data); OCF_PL_FINISH_RET(pipeline, -OCF_ERR_INVAL); } - context->cfg.uuid.data = data; + device_cfg->uuid.data = data; + context->flags.uuid_copied = true; ocf_pipeline_next(pipeline); } @@ -1639,13 +1653,16 @@ static void _ocf_mngt_cache_attach_finish(ocf_pipeline_t pipeline, void *priv, int error) { struct ocf_cache_attach_context *context = priv; + struct ocf_mngt_cache_device_config *device_cfg = &context->cfg.device; if (error) _ocf_mngt_attach_handle_error(context); context->cmpl(context->cache, context->priv1, context->priv2, error); - env_vfree(context->cfg.uuid.data); + if (context->flags.uuid_copied) + env_vfree(device_cfg->uuid.data); + ocf_pipeline_destroy(context->pipeline); } @@ -2020,7 +2037,7 @@ static void _ocf_mngt_bind_post_init(ocf_pipeline_t pipeline, ocf_pipeline_next(pipeline); } -struct ocf_pipeline_properties _ocf_mngt_cache_bind_pipeline_properties = { +struct ocf_pipeline_properties _ocf_mngt_cache_standby_pipeline_properties = { .priv_size = sizeof(struct ocf_cache_attach_context), .finish = _ocf_mngt_cache_attach_finish, .steps = { @@ -2039,57 +2056,78 @@ struct ocf_pipeline_properties _ocf_mngt_cache_bind_pipeline_properties = { }, }; -static void _ocf_mngt_activate_wait_metadata_io_finish(void *priv) +struct ocf_cache_failover_detach_context { + ocf_pipeline_t pipeline; + ocf_cache_t cache; + ocf_mngt_cache_failover_detach_end_t cmpl; + void *priv; +}; + +static void _ocf_mngt_failover_detach_wait_metadata_io_finish(void *priv) { - struct ocf_cache_attach_context *context = priv; + struct ocf_cache_failover_detach_context *context = priv; ocf_pipeline_next(context->pipeline); } -static void _ocf_mngt_activate_wait_metadata_io(ocf_pipeline_t pipeline, +static void _ocf_mngt_failover_detach_wait_metadata_io(ocf_pipeline_t pipeline, void *priv, ocf_pipeline_arg_t arg) { - struct ocf_cache_attach_context *context = priv; + struct ocf_cache_failover_detach_context *context = priv; ocf_cache_t cache = context->cache; ocf_refcnt_freeze(&cache->refcnt.metadata); ocf_refcnt_register_zero_cb(&cache->refcnt.metadata, - _ocf_mngt_activate_wait_metadata_io_finish, context); + _ocf_mngt_failover_detach_wait_metadata_io_finish, context); } static void _ocf_mngt_activate_swap_cache_device(ocf_pipeline_t pipeline, void *priv, ocf_pipeline_arg_t arg) { struct ocf_cache_attach_context *context = priv; - ocf_cache_t cache = context->cache; + struct ocf_mngt_cache_device_config *device_cfg = &context->cfg.device; const struct ocf_volume_uuid *cache_uuid; + ocf_cache_t cache = context->cache; + ocf_volume_t cache_volume = ocf_cache_get_volume(cache); ocf_volume_type_t type; int ret, cmp; - cache_uuid = ocf_volume_get_uuid(ocf_cache_get_volume(cache)); - ret = env_memcmp(context->cfg.uuid.data, context->cfg.uuid.size, - cache_uuid->data, cache_uuid->size, &cmp); - if (ret) - OCF_PL_FINISH_RET(pipeline, ret); + if (device_cfg->uuid.size == 0) { + if (cache_volume->opened) + OCF_PL_NEXT_RET(pipeline); + else + OCF_PL_FINISH_RET(pipeline, -EINVAL); + } - if (cmp == 0) - OCF_PL_NEXT_RET(pipeline); + if (cache_volume->opened) { + /* if uuid does not change then skip this step */ + cache_uuid = ocf_volume_get_uuid(cache_volume); + ret = env_memcmp(device_cfg->uuid.data, device_cfg->uuid.size, + cache_uuid->data, cache_uuid->size, &cmp); + if (ret) + OCF_PL_FINISH_RET(pipeline, ret); - ret = ocf_volume_init(&context->cache_volume, 0, NULL, false); - if (!ret) - OCF_PL_FINISH_RET(pipeline, ret); + if (cmp == 0) + OCF_PL_NEXT_RET(pipeline); - ocf_volume_move(&context->cache_volume, &cache->device->volume); - context->flags.volume_stored = true; + /* move cache volume to the context */ + ret = ocf_volume_init(&context->cache_volume, + cache_volume->type, NULL, false); + if (ret) + OCF_PL_FINISH_RET(pipeline, ret); - type = ocf_ctx_get_volume_type(cache->owner, context->cfg.volume_type); + ocf_volume_move(&context->cache_volume, &cache->device->volume); + context->flags.volume_stored = true; + } + + type = ocf_ctx_get_volume_type(cache->owner, device_cfg->volume_type); if (!type) { OCF_PL_FINISH_RET(pipeline, -OCF_ERR_INVAL_VOLUME_TYPE); } ret = ocf_volume_init(&cache->device->volume, type, - &context->cfg.uuid, true); + &device_cfg->uuid, true); if (ret) OCF_PL_FINISH_RET(pipeline, ret); @@ -2097,7 +2135,7 @@ static void _ocf_mngt_activate_swap_cache_device(ocf_pipeline_t pipeline, context->flags.volume_inited = true; ret = ocf_volume_open(&cache->device->volume, - context->cfg.volume_params); + device_cfg->volume_params); if (ret) { ocf_cache_log(cache, log_err, "ERROR: Cache not available\n"); OCF_PL_FINISH_RET(pipeline, ret); @@ -2219,13 +2257,15 @@ static void _ocf_mngt_activate_handle_error( if (context->flags.volume_stored) ocf_volume_move(&cache->device->volume, &context->cache_volume); - ocf_refcnt_unfreeze(&cache->refcnt.metadata); + if (context->flags.metadata_frozen) + ocf_refcnt_unfreeze(&cache->refcnt.metadata); } static void _ocf_mngt_cache_activate_finish(ocf_pipeline_t pipeline, void *priv, int error) { struct ocf_cache_attach_context *context = priv; + struct ocf_mngt_cache_device_config *device_cfg = &context->cfg.device; ocf_cache_t cache = context->cache; ocf_pipeline_t stop_pipeline; @@ -2244,12 +2284,18 @@ static void _ocf_mngt_cache_activate_finish(ocf_pipeline_t pipeline, ocf_pipeline_destroy(cache->stop_pipeline); cache->stop_pipeline = stop_pipeline; - ocf_volume_deinit(&context->cache_volume); + if (context->flags.volume_stored) { + if (context->cache_volume.opened) + ocf_volume_close(&context->cache_volume); + ocf_volume_deinit(&context->cache_volume); + } + out: context->cmpl(context->cache, context->priv1, context->priv2, error); - env_vfree(context->cfg.uuid.data); + if (context->flags.uuid_copied) + env_vfree(device_cfg->uuid.data); ocf_pipeline_destroy(context->pipeline); } @@ -2258,7 +2304,6 @@ struct ocf_pipeline_properties _ocf_mngt_cache_activate_pipeline_properties = { .finish = _ocf_mngt_cache_activate_finish, .steps = { OCF_PL_STEP(_ocf_mngt_copy_uuid_data), - OCF_PL_STEP(_ocf_mngt_activate_wait_metadata_io), OCF_PL_STEP(_ocf_mngt_activate_swap_cache_device), OCF_PL_STEP(_ocf_mngt_activate_check_superblock), OCF_PL_STEP(_ocf_mngt_activate_compare_superblock), @@ -2275,7 +2320,7 @@ struct ocf_pipeline_properties _ocf_mngt_cache_activate_pipeline_properties = { }; static void _ocf_mngt_cache_attach(ocf_cache_t cache, - struct ocf_mngt_cache_device_config *cfg, + struct ocf_mngt_cache_attach_config *cfg, _ocf_mngt_cache_attach_end_t cmpl, void *priv1, void *priv2) { struct ocf_cache_attach_context *context; @@ -2308,7 +2353,7 @@ static void _ocf_mngt_cache_attach(ocf_cache_t cache, } static void _ocf_mngt_cache_load(ocf_cache_t cache, - struct ocf_mngt_cache_device_config *cfg, + struct ocf_mngt_cache_attach_config *cfg, _ocf_mngt_cache_attach_end_t cmpl, void *priv1, void *priv2) { struct ocf_cache_attach_context *context; @@ -2352,8 +2397,8 @@ ocf_mngt_cache_stop_passive_pipeline_properties = { }, }; -static void _ocf_mngt_cache_bind(ocf_cache_t cache, - struct ocf_mngt_cache_device_config *cfg, +static void _ocf_mngt_cache_standby(ocf_cache_t cache, + struct ocf_mngt_cache_attach_config *cfg, _ocf_mngt_cache_attach_end_t cmpl, void *priv1, void *priv2) { struct ocf_cache_attach_context *context; @@ -2361,7 +2406,7 @@ static void _ocf_mngt_cache_bind(ocf_cache_t cache, int result; result = ocf_pipeline_create(&pipeline, cache, - &_ocf_mngt_cache_bind_pipeline_properties); + &_ocf_mngt_cache_standby_pipeline_properties); if (result) OCF_CMPL_RET(cache, priv1, priv2, -OCF_ERR_NO_MEM); @@ -2385,15 +2430,74 @@ static void _ocf_mngt_cache_bind(ocf_cache_t cache, OCF_PL_NEXT_RET(pipeline); } +static void _ocf_mngt_failover_detach_close_volume(ocf_pipeline_t pipeline, + void *priv, ocf_pipeline_arg_t arg) +{ + struct ocf_cache_failover_detach_context *context = priv; + ocf_cache_t cache = context->cache; + + if (cache->device->volume.opened) { + ocf_volume_close(&cache->device->volume); + ocf_volume_deinit(&cache->device->volume); + } + + ocf_pipeline_next(pipeline); +} + +static void ocf_mngt_cache_failover_detach_finish(ocf_pipeline_t pipeline, + void *priv, int error) +{ + struct ocf_cache_failover_detach_context *context = priv; + + context->cmpl(context->priv, error); + + ocf_pipeline_destroy(context->pipeline); +} + +struct ocf_pipeline_properties +_ocf_mngt_cache_failover_detach_pipeline_properties = { + .priv_size = sizeof(struct ocf_cache_failover_detach_context), + .finish = ocf_mngt_cache_failover_detach_finish, + .steps = { + OCF_PL_STEP(_ocf_mngt_failover_detach_wait_metadata_io), + OCF_PL_STEP(_ocf_mngt_failover_detach_close_volume), + OCF_PL_STEP_TERMINATOR(), + }, +}; + +void _ocf_mngt_cache_failover_detach(ocf_cache_t cache, + ocf_mngt_cache_failover_detach_end_t cmpl, void *priv) +{ + struct ocf_cache_failover_detach_context *context; + ocf_pipeline_t pipeline; + int result; + + result = ocf_pipeline_create(&pipeline, cache, + &_ocf_mngt_cache_failover_detach_pipeline_properties); + if (result) + OCF_CMPL_RET(priv, -OCF_ERR_NO_MEM); + + context = ocf_pipeline_get_priv(pipeline); + + context->cmpl = cmpl; + context->priv = priv; + context->pipeline = pipeline; + + context->cache = cache; + + OCF_PL_NEXT_RET(pipeline); +} + + static void _ocf_mngt_cache_activate(ocf_cache_t cache, - struct ocf_mngt_cache_device_config *cfg, + struct ocf_mngt_cache_device_config *device_cfg, _ocf_mngt_cache_attach_end_t cmpl, void *priv1, void *priv2) { struct ocf_cache_attach_context *context; ocf_pipeline_t pipeline; int result; - if (!ocf_cache_is_passive(cache)) + if (!ocf_cache_is_standby(cache)) OCF_CMPL_RET(cache, priv1, priv2, -OCF_ERR_CACHE_EXIST); result = ocf_pipeline_create(&pipeline, cache, @@ -2401,15 +2505,38 @@ static void _ocf_mngt_cache_activate(ocf_cache_t cache, if (result) OCF_CMPL_RET(cache, priv1, priv2, -OCF_ERR_NO_MEM); + context = ocf_pipeline_get_priv(pipeline); context->cmpl = cmpl; context->priv1 = priv1; context->priv2 = priv2; context->pipeline = pipeline; - context->cache = cache; - context->cfg = *cfg; + + context->cfg.device = *device_cfg; + context->cfg.cache_line_size = cache->metadata.line_size; + context->cfg.open_cores = true; + context->cfg.force = false; + context->cfg.discard_on_start = false; + + /* Metadata reference counter not frozen in standby mode + * indicates the caching drive is still attached. In + * this case it must be frozen now to avoid unwanted + * concurrency during management operation. + */ + if (!ocf_refcnt_frozen(&cache->refcnt.metadata)) { + ENV_BUG_ON(!cache->device->volume.opened); + context->flags.metadata_frozen = true; + ocf_refcnt_freeze(&cache->refcnt.metadata); + + /* Callback set to ocf_pipeline_next directly to + * queue pipeline first step upon receiving the + * callback. */ + ocf_refcnt_register_zero_cb(&cache->refcnt.metadata, + (ocf_refcnt_cb_t)ocf_pipeline_next, pipeline); + return; + } OCF_PL_NEXT_RET(pipeline); } @@ -2441,17 +2568,17 @@ static int _ocf_mngt_cache_validate_cfg(struct ocf_mngt_cache_config *cfg) return 0; } -static int _ocf_mngt_cache_validate_device_cfg( - struct ocf_mngt_cache_device_config *device_cfg) +static int _ocf_mngt_cache_validate_attach_cfg( + struct ocf_mngt_cache_attach_config *attach_cfg) { - if (!device_cfg->uuid.data) + if (!attach_cfg->device.uuid.data) return -OCF_ERR_INVAL; - if (device_cfg->uuid.size > OCF_VOLUME_UUID_MAX_SIZE) + if (attach_cfg->device.uuid.size > OCF_VOLUME_UUID_MAX_SIZE) return -OCF_ERR_INVAL; - if (device_cfg->cache_line_size != ocf_cache_line_size_none && - !ocf_cache_line_size_is_valid(device_cfg->cache_line_size)) + if (attach_cfg->cache_line_size != ocf_cache_line_size_none && + !ocf_cache_line_size_is_valid(attach_cfg->cache_line_size)) return -OCF_ERR_INVALID_CACHE_LINE_SIZE; return 0; @@ -2528,7 +2655,7 @@ static void _ocf_mngt_cache_attach_complete(ocf_cache_t cache, void *priv1, } void ocf_mngt_cache_attach(ocf_cache_t cache, - struct ocf_mngt_cache_device_config *cfg, + struct ocf_mngt_cache_attach_config *cfg, ocf_mngt_cache_attach_end_t cmpl, void *priv) { int result; @@ -2539,7 +2666,7 @@ void ocf_mngt_cache_attach(ocf_cache_t cache, if (!cache->mngt_queue) OCF_CMPL_RET(cache, priv, -OCF_ERR_INVAL); - result = _ocf_mngt_cache_validate_device_cfg(cfg); + result = _ocf_mngt_cache_validate_attach_cfg(cfg); if (result) OCF_CMPL_RET(cache, priv, result); @@ -2635,7 +2762,7 @@ static void _ocf_mngt_cache_load_complete(ocf_cache_t cache, void *priv1, } void ocf_mngt_cache_load(ocf_cache_t cache, - struct ocf_mngt_cache_device_config *cfg, + struct ocf_mngt_cache_attach_config *cfg, ocf_mngt_cache_load_end_t cmpl, void *priv) { int result; @@ -2657,14 +2784,14 @@ void ocf_mngt_cache_load(ocf_cache_t cache, OCF_CMPL_RET(cache, priv, -OCF_ERR_INVAL); } - result = _ocf_mngt_cache_validate_device_cfg(cfg); + result = _ocf_mngt_cache_validate_attach_cfg(cfg); if (result) OCF_CMPL_RET(cache, priv, result); _ocf_mngt_cache_load(cache, cfg, _ocf_mngt_cache_load_complete, cmpl, priv); } -static void _ocf_mngt_cache_bind_complete(ocf_cache_t cache, void *priv1, +static void _ocf_mngt_cache_standby_complete(ocf_cache_t cache, void *priv1, void *priv2, int error) { ocf_mngt_cache_bind_end_t cmpl = priv1; @@ -2678,8 +2805,8 @@ static void _ocf_mngt_cache_bind_complete(ocf_cache_t cache, void *priv1, OCF_CMPL_RET(cache, priv2, 0); } -void ocf_mngt_cache_bind(ocf_cache_t cache, - struct ocf_mngt_cache_device_config *cfg, +void ocf_mngt_cache_standby(ocf_cache_t cache, + struct ocf_mngt_cache_attach_config *cfg, ocf_mngt_cache_bind_end_t cmpl, void *priv) { int result; @@ -2701,18 +2828,18 @@ void ocf_mngt_cache_bind(ocf_cache_t cache, OCF_CMPL_RET(cache, priv, -OCF_ERR_INVAL); } - result = _ocf_mngt_cache_validate_device_cfg(cfg); + result = _ocf_mngt_cache_validate_attach_cfg(cfg); if (result) OCF_CMPL_RET(cache, priv, result); - _ocf_mngt_cache_bind(cache, cfg, _ocf_mngt_cache_bind_complete, + _ocf_mngt_cache_standby(cache, cfg, _ocf_mngt_cache_standby_complete, cmpl, priv); } static void _ocf_mngt_cache_activate_complete(ocf_cache_t cache, void *priv1, void *priv2, int error) { - ocf_mngt_cache_bind_end_t cmpl = priv1; + ocf_mngt_cache_activate_end_t cmpl = priv1; if (error) OCF_CMPL_RET(cache, priv2, error); @@ -2723,34 +2850,37 @@ static void _ocf_mngt_cache_activate_complete(ocf_cache_t cache, void *priv1, OCF_CMPL_RET(cache, priv2, 0); } +void ocf_mngt_cache_failover_detach(ocf_cache_t cache, + ocf_mngt_cache_failover_detach_end_t cmpl, void *priv) +{ + OCF_CHECK_NULL(cache); + + if (!cache->mngt_queue) + OCF_CMPL_RET(priv, -OCF_ERR_INVAL); + + if (!ocf_cache_is_standby(cache)) + OCF_CMPL_RET(priv, -OCF_ERR_CACHE_EXIST); + + if (ocf_refcnt_frozen(&cache->refcnt.metadata)) + OCF_CMPL_RET(priv, -OCF_ERR_INVAL); + + ENV_BUG_ON(!cache->device->volume.opened); + + _ocf_mngt_cache_failover_detach(cache, cmpl, priv); +} + void ocf_mngt_cache_activate(ocf_cache_t cache, struct ocf_mngt_cache_device_config *cfg, ocf_mngt_cache_activate_end_t cmpl, void *priv) { - int result; - OCF_CHECK_NULL(cache); OCF_CHECK_NULL(cfg); - if (cfg->force) { - ocf_cache_log(cache, log_err, "Using 'force' flag is forbidden " - "for activate operation."); - OCF_CMPL_RET(cache, priv, -OCF_ERR_INVAL); - } - - if (cfg->cache_line_size != ocf_cache_line_size_none && - cfg->cache_line_size != cache->metadata.line_size) { - ocf_cache_log(cache, log_err, "Specifying cache line size is " - "forbidden for activate operation."); - OCF_CMPL_RET(cache, priv, -OCF_ERR_INVAL); - } - if (!cache->mngt_queue) OCF_CMPL_RET(cache, priv, -OCF_ERR_INVAL); - result = _ocf_mngt_cache_validate_device_cfg(cfg); - if (result) - OCF_CMPL_RET(cache, priv, result); + if (cfg->uuid.size > OCF_VOLUME_UUID_MAX_SIZE) + OCF_CMPL_RET(cache, priv, -OCF_ERR_INVAL); _ocf_mngt_cache_activate(cache, cfg, _ocf_mngt_cache_activate_complete, cmpl, priv); diff --git a/src/ocf_cache.c b/src/ocf_cache.c index e78cd14..84f6708 100644 --- a/src/ocf_cache.c +++ b/src/ocf_cache.c @@ -56,10 +56,10 @@ bool ocf_cache_is_running(ocf_cache_t cache) return env_bit_test(ocf_cache_state_running, &cache->cache_state); } -bool ocf_cache_is_passive(ocf_cache_t cache) +bool ocf_cache_is_standby(ocf_cache_t cache) { OCF_CHECK_NULL(cache); - return env_bit_test(ocf_cache_state_passive, &cache->cache_state); + return env_bit_test(ocf_cache_state_standby, &cache->cache_state); } bool ocf_cache_is_device_attached(ocf_cache_t cache) @@ -107,7 +107,9 @@ int ocf_cache_get_info(ocf_cache_t cache, struct ocf_cache_info *info) _ocf_stats_zero(&info->inactive); info->attached = ocf_cache_is_device_attached(cache); - if (info->attached) { + info->failover_detached = ocf_cache_is_standby(cache) && + ocf_refcnt_frozen(&cache->refcnt.metadata); + if (info->attached && !info->failover_detached) { info->volume_type = ocf_ctx_get_volume_type_id(cache->owner, cache->device->volume.type); info->size = cache->conf_meta->cachelines; @@ -119,7 +121,7 @@ int ocf_cache_get_info(ocf_cache_t cache, struct ocf_cache_info *info) info->metadata_footprint = ocf_cache_is_device_attached(cache) ? ocf_metadata_size_of(cache) : 0; - if (env_bit_test(ocf_cache_state_passive, &cache->cache_state)) + if (ocf_cache_is_standby(cache)) return 0; info->core_count = cache->conf_meta->core_count; From e2c6a25ee944a307f7f04e8b167e7eedb0fc97fb Mon Sep 17 00:00:00 2001 From: Adam Rutkowski Date: Fri, 8 Oct 2021 22:10:49 +0200 Subject: [PATCH 2/3] [REVERTME] Disable option to perform activate without detach Signed-off-by: Adam Rutkowski --- src/mngt/ocf_mngt_cache.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/mngt/ocf_mngt_cache.c b/src/mngt/ocf_mngt_cache.c index 350cfe2..33b7588 100644 --- a/src/mngt/ocf_mngt_cache.c +++ b/src/mngt/ocf_mngt_cache.c @@ -2505,6 +2505,11 @@ static void _ocf_mngt_cache_activate(ocf_cache_t cache, if (result) OCF_CMPL_RET(cache, priv1, priv2, -OCF_ERR_NO_MEM); + if (!ocf_refcnt_frozen(&cache->refcnt.metadata) || + device_cfg->uuid.size == 0) { + ocf_cache_log(cache, log_err, "not yet implemented.\n"); + OCF_CMPL_RET(cache, priv1, priv2, -OCF_ERR_CACHE_EXIST); + } context = ocf_pipeline_get_priv(pipeline); From ad536d9ad965f2521f30d161cfa535a296b8a740 Mon Sep 17 00:00:00 2001 From: Michal Mielewczyk Date: Fri, 8 Oct 2021 15:38:51 +0200 Subject: [PATCH 3/3] pyocf: fix cache attach config struct Signed-off-by: Michal Mielewczyk Signed-off-by: ajrutkow --- tests/functional/pyocf/types/cache.py | 48 ++++++++++++++++++++------- 1 file changed, 36 insertions(+), 12 deletions(-) diff --git a/tests/functional/pyocf/types/cache.py b/tests/functional/pyocf/types/cache.py index 10ef466..90741e9 100644 --- a/tests/functional/pyocf/types/cache.py +++ b/tests/functional/pyocf/types/cache.py @@ -62,11 +62,18 @@ class CacheConfig(Structure): class CacheDeviceConfig(Structure): _fields_ = [ ("_uuid", Uuid), - ("_cache_line_size", c_uint64), ("_volume_type", c_uint8), - ("_force", c_bool), - ("_min_free_ram", c_uint64), ("_perform_test", c_bool), + ("_volume_params", c_void_p), + ] + + +class CacheAttachConfig(Structure): + _fields_ = [ + ("_device", CacheDeviceConfig), + ("_cache_line_size", c_uint64), + ("_open_cores", c_bool), + ("_force", c_bool), ("_discard_on_start", c_bool), ] @@ -324,7 +331,9 @@ class Cache: self.write_unlock() if status: - raise OcfError("Error setting cache seq cut off policy promotion count", status) + raise OcfError( + "Error setting cache seq cut off policy promotion count", status + ) def get_partition_info(self, part_id: int): ioclass_info = IoClassInfo() @@ -349,7 +358,13 @@ class Cache: } def add_partition( - self, part_id: int, name: str, min_size: int, max_size: int, priority: int, valid: bool + self, + part_id: int, + name: str, + min_size: int, + max_size: int, + priority: int, + valid: bool, ): self.write_lock() @@ -414,7 +429,8 @@ class Cache: ): self.device = device self.device_name = device.uuid - self.dev_cfg = CacheDeviceConfig( + + device_config = CacheDeviceConfig( _uuid=Uuid( _data=cast( create_string_buffer(self.device_name.encode("ascii")), c_char_p @@ -422,12 +438,17 @@ class Cache: _size=len(self.device_name) + 1, ), _volume_type=device.type_id, + _perform_test=perform_test, + _volume_params=None, + ) + + self.dev_cfg = CacheAttachConfig( + _device=device_config, _cache_line_size=cache_line_size if cache_line_size else self.cache_line_size, _force=force, - _min_free_ram=0, - _perform_test=perform_test, + _open_cores=True, _discard_on_start=False, ) @@ -454,9 +475,7 @@ class Cache: c = OcfCompletion([("cache", c_void_p), ("priv", c_void_p), ("error", c_int)]) - self.owner.lib.ocf_mngt_cache_detach( - self.cache_handle, c, None - ) + self.owner.lib.ocf_mngt_cache_detach(self.cache_handle, c, None) c.wait() self.write_unlock() @@ -706,7 +725,12 @@ lib.ocf_mngt_cache_remove_core.argtypes = [c_void_p, c_void_p, c_void_p] lib.ocf_mngt_cache_add_core.argtypes = [c_void_p, c_void_p, c_void_p, c_void_p] lib.ocf_cache_get_name.argtypes = [c_void_p] lib.ocf_cache_get_name.restype = c_char_p -lib.ocf_mngt_cache_cleaning_set_policy.argtypes = [c_void_p, c_uint32, c_void_p, c_void_p] +lib.ocf_mngt_cache_cleaning_set_policy.argtypes = [ + c_void_p, + c_uint32, + c_void_p, + c_void_p, +] lib.ocf_mngt_core_set_seq_cutoff_policy_all.argtypes = [c_void_p, c_uint32] lib.ocf_mngt_core_set_seq_cutoff_policy_all.restype = c_int lib.ocf_mngt_core_set_seq_cutoff_threshold_all.argtypes = [c_void_p, c_uint32]