From 90d8584bd7ffc047c26bfcf9945d4544451ba05b Mon Sep 17 00:00:00 2001 From: Adam Rutkowski Date: Thu, 7 Oct 2021 12:58:42 +0200 Subject: [PATCH] failover detach Signed-off-by: Adam Rutkowski --- casadm/cas_lib.c | 43 +++- casadm/cas_lib.h | 19 ++ casadm/cas_main.c | 101 +++++++-- casadm/statistics_model.c | 7 +- modules/cas_cache/cas_cache.h | 1 + modules/cas_cache/layer_cache_management.c | 250 +++++++++++++++------ modules/cas_cache/layer_cache_management.h | 15 +- modules/cas_cache/service_ui_ioctl.c | 29 ++- modules/include/cas_ioctl_codes.h | 24 +- 9 files changed, 382 insertions(+), 107 deletions(-) diff --git a/casadm/cas_lib.c b/casadm/cas_lib.c index a501687..d44fbfd 100644 --- a/casadm/cas_lib.c +++ b/casadm/cas_lib.c @@ -68,7 +68,7 @@ static const char *cache_states_name[ocf_cache_state_max + 1] = { [ocf_cache_state_stopping] = "Stopping", [ocf_cache_state_initializing] = "Initializing", [ocf_cache_state_incomplete] = "Incomplete", - [ocf_cache_state_passive] = "Passive", + [ocf_cache_state_standby] = "Standby", [ocf_cache_state_max] = "Unknown", }; @@ -782,6 +782,9 @@ struct cache_device *get_cache_device(const struct kcas_cache_info *info, bool b cache->id = cache_id; cache->state = info->info.state; + if (info->info.failover_detached) + return NULL; + if (strncpy_s(cache->device, sizeof(cache->device), info->cache_path_name, sizeof(info->cache_path_name))) { @@ -2776,7 +2779,7 @@ int list_caches(unsigned int list_format, bool by_id_path) cache_mode_to_name(curr_cache->mode)); } else { tmp_status = get_cache_state_name(curr_cache->state); - if (curr_cache->state & (1 << ocf_cache_state_passive)) { + if (curr_cache->state & (1 << ocf_cache_state_standby)) { strncpy(mode_string, "-", sizeof(mode_string)); } else { snprintf(mode_string, sizeof(mode_string), "%s", @@ -2973,3 +2976,39 @@ int zero_md(const char *cache_device, bool force) cas_printf(LOG_INFO, "OpenCAS's metadata wiped succesfully from device '%s'.\n", cache_device); return SUCCESS; } + +int cas_ioctl(int id, void *data) +{ + int fd, result; + + fd = open_ctrl_device(); + if (fd == -1) + return FAILURE; + + result = run_ioctl(fd, id, data); + close(fd); + + return result < 0 ? FAILURE : SUCCESS; +} + + +int failover_detach(int cache_id) +{ + struct kcas_failover_detach data = {.cache_id = cache_id}; + + return cas_ioctl(KCAS_IOCTL_FAILOVER_DETACH, &data); +} + +int failover_activate(int cache_id, const char *cache_device) +{ + struct kcas_failover_activate data = {.cache_id = cache_id}; + + if (cache_device) { + if (set_device_path(data.cache_path, sizeof(data.cache_path), + cache_device, MAX_STR_LEN) != SUCCESS) { + return FAILURE; + } + } + + return cas_ioctl(KCAS_IOCTL_FAILOVER_ACTIVATE, &data); +} diff --git a/casadm/cas_lib.h b/casadm/cas_lib.h index ee736bb..2d380e5 100644 --- a/casadm/cas_lib.h +++ b/casadm/cas_lib.h @@ -204,6 +204,25 @@ int get_core_info(int fd, int cache_id, int core_id, struct kcas_core_info *info int remove_core(unsigned int cache_id, unsigned int core_id, bool detach, bool force_no_flush); +/** + * @brief detach caching device from failover standby cache instance + * + * @param cache_id cache instance identifier + * + * @return 0 upon successful detach, 1 upon failure + */ +int failover_detach(int cache_id); + +/** + * @brief activate failover standby cache instance + * + * @param cache_id cache instance identifier + * @param cache_device cache device path + * + * @return 0 upon successful detach, 1 upon failure + */ +int failover_activate(int cache_id, const char *cache_device); + /** * @brief remove inactive core device from a cache * diff --git a/casadm/cas_main.c b/casadm/cas_main.c index a8084a1..612a290 100644 --- a/casadm/cas_main.c +++ b/casadm/cas_main.c @@ -198,10 +198,8 @@ int start_cache_command_handle_option(char *opt, const char **arg) command_args_values.cache_id = atoi(arg[0]); } else if (!strcmp(opt, "load")) { command_args_values.state = CACHE_INIT_LOAD; - } else if (!strcmp(opt, "bind")) { - command_args_values.state = CACHE_INIT_BIND; - } else if (!strcmp(opt, "activate")) { - command_args_values.state = CACHE_INIT_ACTIVATE; + } else if (!strcmp(opt, "failover-standby")) { + command_args_values.state = CACHE_INIT_STANDBY; } else if (!strcmp(opt, "cache-device")) { if(validate_device_name(arg[0]) == FAILURE) return FAILURE; @@ -247,8 +245,7 @@ static cli_option start_options[] = { {'d', "cache-device", CACHE_DEVICE_DESC, 1, "DEVICE", CLI_OPTION_REQUIRED}, {'i', "cache-id", CACHE_ID_DESC_LONG, 1, "ID", 0}, {'l', "load", "Load cache metadata from caching device (DANGEROUS - see manual or Admin Guide for details)"}, - {'b', "bind", "Bind caching device (DANGEROUS - see manual or Admin Guide for details)"}, - {'a', "activate", "Activate caching device after bind"}, + {'s', "failover-standby", "Start cache in standby mode for failover purpose (DANGEROUS - see manual or Admin Guide for details)"}, {'f', "force", "Force the creation of cache instance"}, {'c', "cache-mode", "Set cache mode from available: {"CAS_CLI_HELP_START_CACHE_MODES"} "CAS_CLI_HELP_START_CACHE_MODES_FULL"; without this parameter Write-Through will be set by default", 1, "NAME"}, {'x', "cache-line-size", "Set cache line size in kibibytes: {4,8,16,32,64}[KiB] (default: %d)", 1, "NUMBER", CLI_OPTION_DEFAULT_INT, 0, 0, ocf_cache_line_size_default / KiB}, @@ -288,45 +285,34 @@ static int check_fs(const char* device) return SUCCESS; } -int handle_start() +int validate_cache_path(const char* path) { - int cache_device = 0; - int status; + int cache_device; struct stat device_info; - if (command_args_values.state == CACHE_INIT_LOAD && command_args_values.force) { - cas_printf(LOG_ERR, "Use of 'load' and 'force' simultaneously is forbidden.\n"); - return FAILURE; - } - if (command_args_values.state == CACHE_INIT_BIND && command_args_values.force) { - cas_printf(LOG_ERR, "Use of 'bind' and 'force' simultaneously is forbidden.\n"); - return FAILURE; - } - - cache_device = open(command_args_values.cache_device, O_RDONLY); + cache_device = open(path, O_RDONLY); if (cache_device < 0) { - cas_printf(LOG_ERR, "Couldn't open cache device %s.\n", - command_args_values.cache_device); + cas_printf(LOG_ERR, "Couldn't open cache device %s.\n", path); return FAILURE; } if (fstat(cache_device, &device_info)) { close(cache_device); cas_printf(LOG_ERR, "Could not stat target device:%s!\n", - command_args_values.cache_device); + path); return FAILURE; } if (!S_ISBLK(device_info.st_mode)) { close(cache_device); cas_printf(LOG_ERR, WRONG_DEVICE_ERROR NOT_BLOCK_ERROR, - command_args_values.cache_device); + path); return FAILURE; } - if (check_fs(command_args_values.cache_device)) { + if (check_fs(path)) { close(cache_device); return FAILURE; } @@ -336,6 +322,26 @@ int handle_start() return FAILURE; } + return SUCCESS; +} + +int handle_start() +{ + int status; + + if (command_args_values.state == CACHE_INIT_LOAD && command_args_values.force) { + cas_printf(LOG_ERR, "Use of 'load' and 'force' simultaneously is forbidden.\n"); + return FAILURE; + } + + if (command_args_values.state == CACHE_INIT_STANDBY && command_args_values.force) { + cas_printf(LOG_ERR, "Use of 'failover-standby' and 'force' simultaneously is forbidden.\n"); + return FAILURE; + } + + if (validate_cache_path(command_args_values.cache_device) == FAILURE) + return FAILURE; + status = start_cache(command_args_values.cache_id, command_args_values.state, command_args_values.cache_device, @@ -1449,6 +1455,18 @@ int io_class_handle() { return FAILURE; } + +static cli_option failover_detach_options[] = { + {'i', "cache-id", CACHE_ID_DESC, 1, "ID", CLI_OPTION_REQUIRED}, + {} +}; + +static cli_option failover_activate_options[] = { + {'i', "cache-id", CACHE_ID_DESC, 1, "ID", CLI_OPTION_REQUIRED}, + {'d', "cache-device", CACHE_DEVICE_DESC, 1, "DEVICE"}, + {} +}; + /******************************************************************************* * Script Commands ******************************************************************************/ @@ -1684,6 +1702,17 @@ int script_command_is_valid() { return result; } +int handle_failover_detach() +{ + return failover_detach(command_args_values.cache_id); +} + +int handle_failover_activate() +{ + return failover_activate(command_args_values.cache_id, + command_args_values.cache_device); +} + int script_handle() { if (script_cmd_unknown == command_args_values.script_subcmd) { cas_printf(LOG_ERR, "Invalid or missing first sub-command parameter\n"); @@ -2094,6 +2123,30 @@ static cli_command cas_commands[] = { .flags = CLI_SU_REQUIRED, .help = NULL }, + { + .name = "failover-detach", + .desc = "Detach cache device from standby cache instance", + .long_desc = "Detach cache device from standby cache instance. " + "Cache continues to run in failover standby mode, " + "awaiting activation on a new drive.", + .options = failover_detach_options, + .command_handle_opts = command_handle_option, + .handle = handle_failover_detach, + .flags = CLI_SU_REQUIRED, + .help = NULL, + + }, + { + .name = "failover-activate", + .desc = "Activate standby cache instance", + .long_desc = NULL, + .options = failover_activate_options, + .command_handle_opts = command_handle_option, + .handle = handle_failover_activate, + .flags = CLI_SU_REQUIRED, + .help = NULL, + + }, { .name = "script", .options = script_params_options, diff --git a/casadm/statistics_model.c b/casadm/statistics_model.c index 52b1d7c..20beeaf 100644 --- a/casadm/statistics_model.c +++ b/casadm/statistics_model.c @@ -538,10 +538,13 @@ int cache_stats_conf(int ctrl_fd, const struct kcas_cache_info *cache_info, char dev_path[MAX_STR_LEN]; int inactive_cores; - if (!by_id_path && get_dev_path(cache_info->cache_path_name, dev_path, sizeof(dev_path)) == SUCCESS) + if (strnlen(cache_info->cache_path_name, sizeof(cache_info->cache_path_name)) == 0) { + cache_path = "-"; + } else if (!by_id_path && get_dev_path(cache_info->cache_path_name, dev_path, sizeof(dev_path)) == SUCCESS) { cache_path = dev_path; - else + } else { cache_path = cache_info->cache_path_name; + } flush_progress = calculate_flush_progress(cache_info->info.dirty, cache_info->info.flushed); diff --git a/modules/cas_cache/cas_cache.h b/modules/cas_cache/cas_cache.h index 1be5508..cfe1380 100644 --- a/modules/cas_cache/cas_cache.h +++ b/modules/cas_cache/cas_cache.h @@ -58,6 +58,7 @@ struct cache_priv { atomic_t flush_interrupt_enabled; ocf_queue_t mngt_queue; void *attach_context; + bool cache_exp_obj_initialized; ocf_queue_t io_queues[]; }; diff --git a/modules/cas_cache/layer_cache_management.c b/modules/cas_cache/layer_cache_management.c index cdc1790..1b10156 100644 --- a/modules/cas_cache/layer_cache_management.c +++ b/modules/cas_cache/layer_cache_management.c @@ -576,7 +576,7 @@ static int exit_instance_finish(void *data) else result = ctx->error; - if (!ocf_cache_is_passive(ctx->cache)) + if (!ocf_cache_is_standby(ctx->cache)) cas_cls_deinit(ctx->cache); vfree(cache_priv); @@ -595,7 +595,8 @@ static int exit_instance_finish(void *data) struct _cache_mngt_attach_context { struct _cache_mngt_async_context async; - struct kcas_start_cache *cmd; + char cache_elevator[MAX_ELEVATOR_NAME]; + uint64_t min_free_ram; struct ocf_mngt_cache_device_config *device_cfg; ocf_cache_t cache; int ocf_start_error; @@ -1284,7 +1285,7 @@ static void _cache_mngt_add_core_complete(ocf_cache_t cache, complete(&context->cmpl); } -static void _cache_mngt_remove_core_complete(void *priv, int error); +static void _cache_mngt_generic_complete(void *priv, int error); int cache_mngt_add_core_to_cache(const char *cache_name, size_t name_len, struct ocf_mngt_core_config *cfg, @@ -1372,7 +1373,7 @@ error_after_create_exported_object: error_after_add_core: init_completion(&remove_context.cmpl); remove_context.result = &remove_core_result; - ocf_mngt_cache_remove_core(core, _cache_mngt_remove_core_complete, + ocf_mngt_cache_remove_core(core, _cache_mngt_generic_complete, &remove_context); wait_for_completion(&remove_context.cmpl); @@ -1429,7 +1430,7 @@ put: return result; } -static void _cache_mngt_remove_core_complete(void *priv, int error) +static void _cache_mngt_generic_complete(void *priv, int error) { struct _cache_mngt_sync_context *context = priv; @@ -1450,7 +1451,7 @@ static void _cache_mngt_remove_core_fallback(ocf_cache_t cache, ocf_core_t core) context.result = &result; ocf_mngt_cache_detach_core(core, - _cache_mngt_remove_core_complete, &context); + _cache_mngt_generic_complete, &context); wait_for_completion(&context.cmpl); @@ -1523,10 +1524,10 @@ int cache_mngt_remove_core_from_cache(struct kcas_remove_core *cmd) if (cmd->detach) { ocf_mngt_cache_detach_core(core, - _cache_mngt_remove_core_complete, &context); + _cache_mngt_generic_complete, &context); } else { ocf_mngt_cache_remove_core(core, - _cache_mngt_remove_core_complete, &context); + _cache_mngt_generic_complete, &context); } wait_for_completion(&context.cmpl); @@ -1584,7 +1585,7 @@ int cache_mngt_remove_inactive_core(struct kcas_remove_inactive *cmd) init_completion(&context.cmpl); context.result = &result; - ocf_mngt_cache_remove_core(core, _cache_mngt_remove_core_complete, + ocf_mngt_cache_remove_core(core, _cache_mngt_generic_complete, &context); wait_for_completion(&context.cmpl); @@ -1755,16 +1756,29 @@ static int cache_mngt_initialize_core_exported_objects(ocf_cache_t cache) return result; } -static void cache_mngt_destroy_cache_exp_obj(ocf_cache_t cache) +static int cache_mngt_destroy_cache_exp_obj(ocf_cache_t cache) { - if (kcas_cache_destroy_exported_object(cache)) { + struct cache_priv *cache_priv = ocf_cache_get_priv(cache); + int ret; + + if (!cache_priv->cache_exp_obj_initialized) + return 0; + + ret = kcas_cache_destroy_exported_object(cache); + + if (ret) { printk(KERN_ERR "Cannot destroy %s exported object\n", ocf_cache_get_name(cache)); + } else { + cache_priv->cache_exp_obj_initialized = false; } + + return ret; } static int cache_mngt_initialize_cache_exported_object(ocf_cache_t cache) { + struct cache_priv *cache_priv = ocf_cache_get_priv(cache); int result; result = kcas_cache_create_exported_object(cache); @@ -1777,11 +1791,42 @@ static int cache_mngt_initialize_cache_exported_object(ocf_cache_t cache) return result; } + cache_priv->cache_exp_obj_initialized = true; + return 0; } +int cache_mngt_prepare_cache_device_cfg(struct ocf_mngt_cache_device_config *cfg, + char *cache_path) +{ + int result = 0; + + memset(cfg, 0, sizeof(*cfg)); + + if (strnlen(cache_path, MAX_STR_LEN) == MAX_STR_LEN) + return -OCF_ERR_INVAL; + + cfg->uuid.data = cache_path; + cfg->uuid.size = strnlen(cfg->uuid.data, MAX_STR_LEN) + 1; + cfg->perform_test = false; + + if (cfg->uuid.size == 1) { + // empty string means empty uuid + cfg->uuid.size = 0; + return 0; + } + + if (cfg->uuid.size > 1) { + result = cas_blk_identify_type(cfg->uuid.data, + &cfg->volume_type); + } + + return result; +} + + int cache_mngt_prepare_cache_cfg(struct ocf_mngt_cache_config *cfg, - struct ocf_mngt_cache_device_config *device_cfg, + struct ocf_mngt_cache_attach_config *attach_cfg, struct kcas_start_cache *cmd) { int init_cache, result; @@ -1791,9 +1836,6 @@ int cache_mngt_prepare_cache_cfg(struct ocf_mngt_cache_config *cfg, if (!cmd) return -OCF_ERR_INVAL; - if (strnlen(cmd->cache_path_name, MAX_STR_LEN) >= MAX_STR_LEN) - return -OCF_ERR_INVAL; - if (cmd->cache_id == OCF_CACHE_ID_INVALID) { cache_id = find_free_cache_id(cas_ctx); if (cache_id == OCF_CACHE_ID_INVALID) @@ -1805,7 +1847,15 @@ int cache_mngt_prepare_cache_cfg(struct ocf_mngt_cache_config *cfg, cache_name_from_id(cache_name, cmd->cache_id); memset(cfg, 0, sizeof(*cfg)); - memset(device_cfg, 0, sizeof(*device_cfg)); + memset(attach_cfg, 0, sizeof(*attach_cfg)); + + result = cache_mngt_prepare_cache_device_cfg(&attach_cfg->device, + cmd->cache_path_name); + if (result) + return result; + + if (attach_cfg->device.uuid.size <= 1) + return -OCF_ERR_INVAL; strncpy(cfg->name, cache_name, OCF_CACHE_NAME_SIZE - 1); cfg->cache_mode = cmd->caching_mode; @@ -1820,31 +1870,22 @@ int cache_mngt_prepare_cache_cfg(struct ocf_mngt_cache_config *cfg, cfg->backfill.max_queue_size = max_writeback_queue_size; cfg->backfill.queue_unblock_size = writeback_queue_unblock_size; - - device_cfg->uuid.data = cmd->cache_path_name; - device_cfg->uuid.size = strnlen(device_cfg->uuid.data, MAX_STR_LEN) + 1; - device_cfg->cache_line_size = cmd->line_size; - device_cfg->force = cmd->force; - device_cfg->discard_on_start = true; - device_cfg->perform_test = false; + attach_cfg->cache_line_size = cmd->line_size; + attach_cfg->force = cmd->force; + attach_cfg->discard_on_start = true; init_cache = cmd->init_cache; switch (init_cache) { case CACHE_INIT_LOAD: - case CACHE_INIT_ACTIVATE: - device_cfg->open_cores = true; + attach_cfg->open_cores = true; case CACHE_INIT_NEW: - case CACHE_INIT_BIND: + case CACHE_INIT_STANDBY: break; default: return -OCF_ERR_INVAL; } - result = cas_blk_identify_type(device_cfg->uuid.data, - &device_cfg->volume_type); - if (result) - return result; return 0; } @@ -1935,9 +1976,8 @@ static void init_instance_complete(struct _cache_mngt_attach_context *ctx, /* Set other back information */ name = block_dev_get_elevator_name( casdsk_disk_get_queue(bd_cache_obj->dsk)); - if (name && ctx->cmd) - strlcpy(ctx->cmd->cache_elevator, - name, MAX_ELEVATOR_NAME); + if (name) + strlcpy(ctx->cache_elevator, name, MAX_ELEVATOR_NAME); } static void _cache_mngt_start_complete(ocf_cache_t cache, void *priv, int error) @@ -1945,9 +1985,9 @@ static void _cache_mngt_start_complete(ocf_cache_t cache, void *priv, int error) struct _cache_mngt_attach_context *ctx = priv; int caller_status; - if (error == -OCF_ERR_NO_FREE_RAM && ctx->cmd) { + if (error == -OCF_ERR_NO_FREE_RAM) { ocf_mngt_get_ram_needed(cache, ctx->device_cfg, - &ctx->cmd->min_free_ram); + &ctx->min_free_ram); } caller_status =_cache_mngt_async_callee_set_result(&ctx->async, error); @@ -2051,8 +2091,8 @@ out_bdev: return result; } -static int _cache_start_finalize(ocf_cache_t cache, - struct kcas_start_cache *cmd) +static int _cache_start_finalize(ocf_cache_t cache, int init_mode, + bool activate) { struct cache_priv *cache_priv = ocf_cache_get_priv(cache); struct _cache_mngt_attach_context *ctx = cache_priv->attach_context; @@ -2060,7 +2100,7 @@ static int _cache_start_finalize(ocf_cache_t cache, _cache_mngt_log_cache_device_path(cache, ctx->device_cfg); - if (cmd->init_cache != CACHE_INIT_BIND) { + if (activate || init_mode != CACHE_INIT_STANDBY) { result = cas_cls_init(cache); if (result) { ctx->ocf_start_error = result; @@ -2069,10 +2109,14 @@ static int _cache_start_finalize(ocf_cache_t cache, ctx->cls_inited = true; } - switch(cmd->init_cache) { - case CACHE_INIT_ACTIVATE: + if (activate) cache_mngt_destroy_cache_exp_obj(cache); - /* fall through */ + + /* after destroying exported object activate should follow + * load path */ + init_mode = activate ? CACHE_INIT_LOAD : init_mode; + + switch(init_mode) { case CACHE_INIT_LOAD: result = cache_mngt_initialize_core_exported_objects(cache); if (result) { @@ -2082,7 +2126,7 @@ static int _cache_start_finalize(ocf_cache_t cache, ocf_core_visit(cache, _cache_mngt_core_device_loaded_visitor, NULL, false); break; - case CACHE_INIT_BIND: + case CACHE_INIT_STANDBY: result = cache_mngt_initialize_cache_exported_object(cache); if (result) { ctx->ocf_start_error = result; @@ -2100,7 +2144,8 @@ static int _cache_start_finalize(ocf_cache_t cache, return 0; } -int cache_mngt_check_bdev(struct ocf_mngt_cache_device_config *device_cfg) +int cache_mngt_check_bdev(struct ocf_mngt_cache_device_config *device_cfg, + bool force) { char holder[] = "CAS START\n"; struct block_device *bdev; @@ -2119,15 +2164,68 @@ int cache_mngt_check_bdev(struct ocf_mngt_cache_device_config *device_cfg) part_count = cas_blk_get_part_count(bdev); blkdev_put(bdev, (FMODE_EXCL|FMODE_READ)); - if (!is_part && part_count > 1 && !device_cfg->force) + if (!is_part && part_count > 1 && !force) return -KCAS_ERR_CONTAINS_PART; return 0; } -int cache_mngt_init_instance_activate(struct ocf_mngt_cache_config *cfg, - struct ocf_mngt_cache_device_config *device_cfg, - struct kcas_start_cache *cmd) +int cache_mngt_failover_detach(struct kcas_failover_detach *cmd) +{ + ocf_cache_t cache; + struct cache_priv *cache_priv; + char cache_name[OCF_CACHE_NAME_SIZE]; + int result = 0; + struct _cache_mngt_sync_context context = { + .result = &result + }; + + init_completion(&context.cmpl); + + if (!try_module_get(THIS_MODULE)) + return -KCAS_ERR_SYSTEM; + + cache_name_from_id(cache_name, cmd->cache_id); + + result = ocf_mngt_cache_get_by_name(cas_ctx, cache_name, + OCF_CACHE_NAME_SIZE, &cache); + if (result) + goto out_module_put; + + if (!ocf_cache_is_standby(cache)) { + result = -OCF_ERR_CACHE_EXIST; + goto out_cache_put; + } + + cache_priv = ocf_cache_get_priv(cache); + if (!cache_priv->cache_exp_obj_initialized) { + result = -KCAS_ERR_DETACHED; + goto out_cache_put; + } + + result = cache_mngt_destroy_cache_exp_obj(cache); + if (result) + goto out_cache_put; + + result = _cache_mngt_lock_sync(cache); + if (result) + goto out_cache_put; + + ocf_mngt_cache_failover_detach(cache, _cache_mngt_generic_complete, + &context); + + wait_for_completion(&context.cmpl); + ocf_mngt_cache_unlock(cache); + +out_cache_put: + ocf_mngt_cache_put(cache); +out_module_put: + module_put(THIS_MODULE); + return result; +} + +int cache_mngt_activate(struct ocf_mngt_cache_device_config *cfg, + struct kcas_failover_activate *cmd) { struct _cache_mngt_attach_context *context; ocf_cache_t cache; @@ -2147,7 +2245,7 @@ int cache_mngt_init_instance_activate(struct ocf_mngt_cache_config *cfg, if (result) goto out_module_put; - if (!ocf_cache_is_passive(cache)) { + if (!ocf_cache_is_standby(cache)) { result = -OCF_ERR_CACHE_EXIST; goto out_cache_put; } @@ -2156,12 +2254,16 @@ int cache_mngt_init_instance_activate(struct ocf_mngt_cache_config *cfg, if (result) goto out_cache_put; - cache_volume = ocf_cache_get_volume(cache); - cache_uuid = ocf_volume_get_uuid(cache_volume); - if (strcmp(device_cfg->uuid.data, cache_uuid->data) != 0) { - result = cache_mngt_check_bdev(device_cfg); - if (result) - goto out_cache_unlock; + if (strnlen(cmd->cache_path, MAX_STR_LEN) > 0) { + cache_volume = ocf_cache_get_volume(cache); + cache_uuid = ocf_volume_get_uuid(cache_volume); + if (cache_uuid->size > 0 && + strcmp(cfg->uuid.data, cache_uuid->data) + != 0) { + result = cache_mngt_check_bdev(cfg, false); + if (result) + goto out_cache_unlock; + } } context = kzalloc(sizeof(*context), GFP_KERNEL); @@ -2170,8 +2272,10 @@ int cache_mngt_init_instance_activate(struct ocf_mngt_cache_config *cfg, goto out_cache_unlock; } - context->device_cfg = device_cfg; - context->cmd = cmd; + /* TODO: doesn't this need to be copied to avoid use-after-free + * in case where calle is interrupted and returns??? + */ + context->device_cfg = cfg; context->cache = cache; cache_priv = ocf_cache_get_priv(cache); @@ -2185,8 +2289,8 @@ int cache_mngt_init_instance_activate(struct ocf_mngt_cache_config *cfg, } _cache_mngt_async_context_init(&context->async); - ocf_mngt_cache_activate(cache, device_cfg, - _cache_mngt_start_complete, context); + ocf_mngt_cache_activate(cache, cfg, _cache_mngt_start_complete, + context); result = wait_for_completion_interruptible(&context->async.cmpl); result = _cache_mngt_async_caller_set_result(&context->async, result); @@ -2198,7 +2302,7 @@ int cache_mngt_init_instance_activate(struct ocf_mngt_cache_config *cfg, if (result) goto err_free_context; - result = _cache_start_finalize(cache, cmd); + result = _cache_start_finalize(cache, -1, true); err_free_context: kfree(context); @@ -2214,7 +2318,7 @@ out_module_put: } int cache_mngt_init_instance(struct ocf_mngt_cache_config *cfg, - struct ocf_mngt_cache_device_config *device_cfg, + struct ocf_mngt_cache_attach_config *attach_cfg, struct kcas_start_cache *cmd) { struct _cache_mngt_attach_context *context; @@ -2222,13 +2326,10 @@ int cache_mngt_init_instance(struct ocf_mngt_cache_config *cfg, struct cache_priv *cache_priv; int result = 0, rollback_result = 0; - if (cmd->init_cache == CACHE_INIT_ACTIVATE) - return cache_mngt_init_instance_activate(cfg, device_cfg, cmd); - if (!try_module_get(THIS_MODULE)) return -KCAS_ERR_SYSTEM; - result = cache_mngt_check_bdev(device_cfg); + result = cache_mngt_check_bdev(&attach_cfg->device, attach_cfg->force); if (result) { module_put(THIS_MODULE); return result; @@ -2256,8 +2357,7 @@ int cache_mngt_init_instance(struct ocf_mngt_cache_config *cfg, return result; } - context->device_cfg = device_cfg; - context->cmd = cmd; + context->device_cfg = &attach_cfg->device; _cache_mngt_async_context_init(&context->async); /* Start cache. Returned cache instance will be locked as it was set @@ -2286,15 +2386,15 @@ int cache_mngt_init_instance(struct ocf_mngt_cache_config *cfg, switch (cmd->init_cache) { case CACHE_INIT_NEW: - ocf_mngt_cache_attach(cache, device_cfg, + ocf_mngt_cache_attach(cache, attach_cfg, _cache_mngt_start_complete, context); break; case CACHE_INIT_LOAD: - ocf_mngt_cache_load(cache, device_cfg, + ocf_mngt_cache_load(cache, attach_cfg, _cache_mngt_start_complete, context); break; - case CACHE_INIT_BIND: - ocf_mngt_cache_bind(cache, device_cfg, + case CACHE_INIT_STANDBY: + ocf_mngt_cache_standby(cache, attach_cfg, _cache_mngt_start_complete, context); break; default: @@ -2310,7 +2410,11 @@ int cache_mngt_init_instance(struct ocf_mngt_cache_config *cfg, if (result) goto err; - result = _cache_start_finalize(cache, cmd); + strlcpy(cmd->cache_elevator, context->cache_elevator, + MAX_ELEVATOR_NAME); + cmd->min_free_ram = context->min_free_ram; + + result = _cache_start_finalize(cache, cmd->init_cache, false); if (result) goto err; @@ -2827,11 +2931,13 @@ int cache_mngt_get_info(struct kcas_cache_info *info) if (result) goto unlock; - if (info->info.attached) { + if (info->info.attached && !info->info.failover_detached) { uuid = ocf_cache_get_uuid(cache); BUG_ON(!uuid); strlcpy(info->cache_path_name, uuid->data, min(sizeof(info->cache_path_name), uuid->size)); + } else { + memset(info->cache_path_name, 0, sizeof(info->cache_path_name)); } /* Collect cores IDs */ diff --git a/modules/cas_cache/layer_cache_management.h b/modules/cas_cache/layer_cache_management.h index 23da710..a432369 100644 --- a/modules/cas_cache/layer_cache_management.h +++ b/modules/cas_cache/layer_cache_management.h @@ -45,8 +45,11 @@ int cache_mngt_set_partitions(const char *cache_name, size_t name_len, int cache_mngt_exit_instance(const char *cache_name, size_t name_len, int flush); +int cache_mngt_prepare_cache_device_cfg(struct ocf_mngt_cache_device_config *cfg, + char *cache_path); + int cache_mngt_prepare_cache_cfg(struct ocf_mngt_cache_config *cfg, - struct ocf_mngt_cache_device_config *device_cfg, + struct ocf_mngt_cache_attach_config *attach_cfg, struct kcas_start_cache *cmd); int cache_mngt_core_pool_get_paths(struct kcas_core_pool_path *cmd_info); @@ -59,9 +62,12 @@ int cache_mngt_prepare_core_cfg(struct ocf_mngt_core_config *cfg, struct kcas_insert_core *cmd_info); int cache_mngt_init_instance(struct ocf_mngt_cache_config *cfg, - struct ocf_mngt_cache_device_config *device_cfg, + struct ocf_mngt_cache_attach_config *attach_cfg, struct kcas_start_cache *cmd); +int cache_mngt_activate(struct ocf_mngt_cache_device_config *cfg, + struct kcas_failover_activate *cmd); + int cache_mngt_set_seq_cutoff_threshold(ocf_cache_t cache, ocf_core_t core, uint32_t thresh); @@ -108,4 +114,9 @@ int cache_mngt_set_cache_params(struct kcas_set_cache_param *info); int cache_mngt_get_cache_params(struct kcas_get_cache_param *info); +int cache_mngt_failover_detach(struct kcas_failover_detach *cmd); + +int cache_mngt_activate(struct ocf_mngt_cache_device_config *cfg, + struct kcas_failover_activate *cmd); + #endif diff --git a/modules/cas_cache/service_ui_ioctl.c b/modules/cas_cache/service_ui_ioctl.c index 14fe4d2..aa7a31f 100644 --- a/modules/cas_cache/service_ui_ioctl.c +++ b/modules/cas_cache/service_ui_ioctl.c @@ -50,15 +50,15 @@ long cas_service_ioctl_ctrl(struct file *filp, unsigned int cmd, case KCAS_IOCTL_START_CACHE: { struct kcas_start_cache *cmd_info; struct ocf_mngt_cache_config cfg; - struct ocf_mngt_cache_device_config device_cfg; + struct ocf_mngt_cache_attach_config attach_cfg; GET_CMD_INFO(cmd_info, arg); - retval = cache_mngt_prepare_cache_cfg(&cfg, &device_cfg, cmd_info); + retval = cache_mngt_prepare_cache_cfg(&cfg, &attach_cfg, cmd_info); if (retval) RETURN_CMD_RESULT(cmd_info, arg, retval); - retval = cache_mngt_init_instance(&cfg, &device_cfg, cmd_info); + retval = cache_mngt_init_instance(&cfg, &attach_cfg, cmd_info); RETURN_CMD_RESULT(cmd_info, arg, retval); } @@ -378,7 +378,30 @@ long cas_service_ioctl_ctrl(struct file *filp, unsigned int cmd, RETURN_CMD_RESULT(cmd_info, arg, retval); } + case KCAS_IOCTL_FAILOVER_DETACH: { + struct kcas_failover_detach *cmd_info; + GET_CMD_INFO(cmd_info, arg); + + retval = cache_mngt_failover_detach(cmd_info); + + RETURN_CMD_RESULT(cmd_info, arg, retval); + } + case KCAS_IOCTL_FAILOVER_ACTIVATE: { + struct kcas_failover_activate *cmd_info; + struct ocf_mngt_cache_device_config cfg; + + GET_CMD_INFO(cmd_info, arg); + + retval = cache_mngt_prepare_cache_device_cfg(&cfg, + cmd_info->cache_path); + if (retval) + RETURN_CMD_RESULT(cmd_info, arg, retval); + + retval = cache_mngt_activate(&cfg, cmd_info); + + RETURN_CMD_RESULT(cmd_info, arg, retval); + } default: return -EINVAL; } diff --git a/modules/include/cas_ioctl_codes.h b/modules/include/cas_ioctl_codes.h index e8cb267..06c70e8 100644 --- a/modules/include/cas_ioctl_codes.h +++ b/modules/include/cas_ioctl_codes.h @@ -36,8 +36,7 @@ #define CACHE_INIT_NEW 0 /**< initialize new metadata from fresh start */ #define CACHE_INIT_LOAD 1 /**< load existing metadata */ -#define CACHE_INIT_BIND 2 /**< bind existing metadata */ -#define CACHE_INIT_ACTIVATE 3 /**< activate cache after bind */ +#define CACHE_INIT_STANDBY 2 /**< initialize failover standby cache */ struct kcas_start_cache { /** @@ -353,6 +352,21 @@ struct kcas_get_cache_param { int ext_err_code; }; +struct kcas_failover_detach +{ + uint16_t cache_id; + + int ext_err_code; +}; + +struct kcas_failover_activate +{ + uint16_t cache_id; + char cache_path[MAX_STR_LEN]; /**< path to an ssd*/ + + int ext_err_code; +}; + /******************************************************************************* * CODE * NAME * STATUS * ******************************************************************************* @@ -483,6 +497,12 @@ struct kcas_get_cache_param { /** Remove inactive core object from an running cache instance */ #define KCAS_IOCTL_REMOVE_INACTIVE _IOWR(KCAS_IOCTL_MAGIC, 37, struct kcas_remove_inactive) +/** Detach caching drive from failover standby cache instance */ +#define KCAS_IOCTL_FAILOVER_DETACH _IOWR(KCAS_IOCTL_MAGIC, 38, struct kcas_failover_detach) + +/** Activate standby failover cache instance */ +#define KCAS_IOCTL_FAILOVER_ACTIVATE _IOWR(KCAS_IOCTL_MAGIC, 39, struct kcas_failover_activate) + /** * Extended kernel CAS error codes */