failover detach

Signed-off-by: Adam Rutkowski <adam.j.rutkowski@intel.com>
This commit is contained in:
Adam Rutkowski 2021-10-07 12:58:42 +02:00 committed by ajrutkow
parent 86c7a9f5ae
commit 90d8584bd7
9 changed files with 382 additions and 107 deletions

View File

@ -68,7 +68,7 @@ static const char *cache_states_name[ocf_cache_state_max + 1] = {
[ocf_cache_state_stopping] = "Stopping", [ocf_cache_state_stopping] = "Stopping",
[ocf_cache_state_initializing] = "Initializing", [ocf_cache_state_initializing] = "Initializing",
[ocf_cache_state_incomplete] = "Incomplete", [ocf_cache_state_incomplete] = "Incomplete",
[ocf_cache_state_passive] = "Passive", [ocf_cache_state_standby] = "Standby",
[ocf_cache_state_max] = "Unknown", [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->id = cache_id;
cache->state = info->info.state; cache->state = info->info.state;
if (info->info.failover_detached)
return NULL;
if (strncpy_s(cache->device, sizeof(cache->device), if (strncpy_s(cache->device, sizeof(cache->device),
info->cache_path_name, info->cache_path_name,
sizeof(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)); cache_mode_to_name(curr_cache->mode));
} else { } else {
tmp_status = get_cache_state_name(curr_cache->state); 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)); strncpy(mode_string, "-", sizeof(mode_string));
} else { } else {
snprintf(mode_string, sizeof(mode_string), "%s", 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); cas_printf(LOG_INFO, "OpenCAS's metadata wiped succesfully from device '%s'.\n", cache_device);
return SUCCESS; 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);
}

View File

@ -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, int remove_core(unsigned int cache_id, unsigned int core_id,
bool detach, bool force_no_flush); 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 * @brief remove inactive core device from a cache
* *

View File

@ -198,10 +198,8 @@ int start_cache_command_handle_option(char *opt, const char **arg)
command_args_values.cache_id = atoi(arg[0]); command_args_values.cache_id = atoi(arg[0]);
} else if (!strcmp(opt, "load")) { } else if (!strcmp(opt, "load")) {
command_args_values.state = CACHE_INIT_LOAD; command_args_values.state = CACHE_INIT_LOAD;
} else if (!strcmp(opt, "bind")) { } else if (!strcmp(opt, "failover-standby")) {
command_args_values.state = CACHE_INIT_BIND; command_args_values.state = CACHE_INIT_STANDBY;
} else if (!strcmp(opt, "activate")) {
command_args_values.state = CACHE_INIT_ACTIVATE;
} else if (!strcmp(opt, "cache-device")) { } else if (!strcmp(opt, "cache-device")) {
if(validate_device_name(arg[0]) == FAILURE) if(validate_device_name(arg[0]) == FAILURE)
return FAILURE; return FAILURE;
@ -247,8 +245,7 @@ static cli_option start_options[] = {
{'d', "cache-device", CACHE_DEVICE_DESC, 1, "DEVICE", CLI_OPTION_REQUIRED}, {'d', "cache-device", CACHE_DEVICE_DESC, 1, "DEVICE", CLI_OPTION_REQUIRED},
{'i', "cache-id", CACHE_ID_DESC_LONG, 1, "ID", 0}, {'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)"}, {'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)"}, {'s', "failover-standby", "Start cache in standby mode for failover purpose (DANGEROUS - see manual or Admin Guide for details)"},
{'a', "activate", "Activate caching device after bind"},
{'f', "force", "Force the creation of cache instance"}, {'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"}, {'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}, {'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; return SUCCESS;
} }
int handle_start() int validate_cache_path(const char* path)
{ {
int cache_device = 0; int cache_device;
int status;
struct stat device_info; 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) { cache_device = open(path, O_RDONLY);
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);
if (cache_device < 0) { if (cache_device < 0) {
cas_printf(LOG_ERR, "Couldn't open cache device %s.\n", cas_printf(LOG_ERR, "Couldn't open cache device %s.\n", path);
command_args_values.cache_device);
return FAILURE; return FAILURE;
} }
if (fstat(cache_device, &device_info)) { if (fstat(cache_device, &device_info)) {
close(cache_device); close(cache_device);
cas_printf(LOG_ERR, "Could not stat target device:%s!\n", cas_printf(LOG_ERR, "Could not stat target device:%s!\n",
command_args_values.cache_device); path);
return FAILURE; return FAILURE;
} }
if (!S_ISBLK(device_info.st_mode)) { if (!S_ISBLK(device_info.st_mode)) {
close(cache_device); close(cache_device);
cas_printf(LOG_ERR, WRONG_DEVICE_ERROR NOT_BLOCK_ERROR, cas_printf(LOG_ERR, WRONG_DEVICE_ERROR NOT_BLOCK_ERROR,
command_args_values.cache_device); path);
return FAILURE; return FAILURE;
} }
if (check_fs(command_args_values.cache_device)) { if (check_fs(path)) {
close(cache_device); close(cache_device);
return FAILURE; return FAILURE;
} }
@ -336,6 +322,26 @@ int handle_start()
return FAILURE; 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, status = start_cache(command_args_values.cache_id,
command_args_values.state, command_args_values.state,
command_args_values.cache_device, command_args_values.cache_device,
@ -1449,6 +1455,18 @@ int io_class_handle() {
return FAILURE; 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 * Script Commands
******************************************************************************/ ******************************************************************************/
@ -1684,6 +1702,17 @@ int script_command_is_valid() {
return result; 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() { int script_handle() {
if (script_cmd_unknown == command_args_values.script_subcmd) { if (script_cmd_unknown == command_args_values.script_subcmd) {
cas_printf(LOG_ERR, "Invalid or missing first sub-command parameter\n"); 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, .flags = CLI_SU_REQUIRED,
.help = NULL .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", .name = "script",
.options = script_params_options, .options = script_params_options,

View File

@ -538,10 +538,13 @@ int cache_stats_conf(int ctrl_fd, const struct kcas_cache_info *cache_info,
char dev_path[MAX_STR_LEN]; char dev_path[MAX_STR_LEN];
int inactive_cores; 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; cache_path = dev_path;
else } else {
cache_path = cache_info->cache_path_name; cache_path = cache_info->cache_path_name;
}
flush_progress = calculate_flush_progress(cache_info->info.dirty, flush_progress = calculate_flush_progress(cache_info->info.dirty,
cache_info->info.flushed); cache_info->info.flushed);

View File

@ -58,6 +58,7 @@ struct cache_priv {
atomic_t flush_interrupt_enabled; atomic_t flush_interrupt_enabled;
ocf_queue_t mngt_queue; ocf_queue_t mngt_queue;
void *attach_context; void *attach_context;
bool cache_exp_obj_initialized;
ocf_queue_t io_queues[]; ocf_queue_t io_queues[];
}; };

View File

@ -576,7 +576,7 @@ static int exit_instance_finish(void *data)
else else
result = ctx->error; result = ctx->error;
if (!ocf_cache_is_passive(ctx->cache)) if (!ocf_cache_is_standby(ctx->cache))
cas_cls_deinit(ctx->cache); cas_cls_deinit(ctx->cache);
vfree(cache_priv); vfree(cache_priv);
@ -595,7 +595,8 @@ static int exit_instance_finish(void *data)
struct _cache_mngt_attach_context { struct _cache_mngt_attach_context {
struct _cache_mngt_async_context async; 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; struct ocf_mngt_cache_device_config *device_cfg;
ocf_cache_t cache; ocf_cache_t cache;
int ocf_start_error; int ocf_start_error;
@ -1284,7 +1285,7 @@ static void _cache_mngt_add_core_complete(ocf_cache_t cache,
complete(&context->cmpl); 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, int cache_mngt_add_core_to_cache(const char *cache_name, size_t name_len,
struct ocf_mngt_core_config *cfg, struct ocf_mngt_core_config *cfg,
@ -1372,7 +1373,7 @@ error_after_create_exported_object:
error_after_add_core: error_after_add_core:
init_completion(&remove_context.cmpl); init_completion(&remove_context.cmpl);
remove_context.result = &remove_core_result; 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); &remove_context);
wait_for_completion(&remove_context.cmpl); wait_for_completion(&remove_context.cmpl);
@ -1429,7 +1430,7 @@ put:
return result; 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; 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; context.result = &result;
ocf_mngt_cache_detach_core(core, ocf_mngt_cache_detach_core(core,
_cache_mngt_remove_core_complete, &context); _cache_mngt_generic_complete, &context);
wait_for_completion(&context.cmpl); wait_for_completion(&context.cmpl);
@ -1523,10 +1524,10 @@ int cache_mngt_remove_core_from_cache(struct kcas_remove_core *cmd)
if (cmd->detach) { if (cmd->detach) {
ocf_mngt_cache_detach_core(core, ocf_mngt_cache_detach_core(core,
_cache_mngt_remove_core_complete, &context); _cache_mngt_generic_complete, &context);
} else { } else {
ocf_mngt_cache_remove_core(core, ocf_mngt_cache_remove_core(core,
_cache_mngt_remove_core_complete, &context); _cache_mngt_generic_complete, &context);
} }
wait_for_completion(&context.cmpl); wait_for_completion(&context.cmpl);
@ -1584,7 +1585,7 @@ int cache_mngt_remove_inactive_core(struct kcas_remove_inactive *cmd)
init_completion(&context.cmpl); init_completion(&context.cmpl);
context.result = &result; 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); &context);
wait_for_completion(&context.cmpl); wait_for_completion(&context.cmpl);
@ -1755,16 +1756,29 @@ static int cache_mngt_initialize_core_exported_objects(ocf_cache_t cache)
return result; 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", printk(KERN_ERR "Cannot destroy %s exported object\n",
ocf_cache_get_name(cache)); 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) static int cache_mngt_initialize_cache_exported_object(ocf_cache_t cache)
{ {
struct cache_priv *cache_priv = ocf_cache_get_priv(cache);
int result; int result;
result = kcas_cache_create_exported_object(cache); 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; return result;
} }
cache_priv->cache_exp_obj_initialized = true;
return 0; 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, 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) struct kcas_start_cache *cmd)
{ {
int init_cache, result; int init_cache, result;
@ -1791,9 +1836,6 @@ int cache_mngt_prepare_cache_cfg(struct ocf_mngt_cache_config *cfg,
if (!cmd) if (!cmd)
return -OCF_ERR_INVAL; 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) { if (cmd->cache_id == OCF_CACHE_ID_INVALID) {
cache_id = find_free_cache_id(cas_ctx); cache_id = find_free_cache_id(cas_ctx);
if (cache_id == OCF_CACHE_ID_INVALID) 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); cache_name_from_id(cache_name, cmd->cache_id);
memset(cfg, 0, sizeof(*cfg)); 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); strncpy(cfg->name, cache_name, OCF_CACHE_NAME_SIZE - 1);
cfg->cache_mode = cmd->caching_mode; 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.max_queue_size = max_writeback_queue_size;
cfg->backfill.queue_unblock_size = writeback_queue_unblock_size; cfg->backfill.queue_unblock_size = writeback_queue_unblock_size;
attach_cfg->cache_line_size = cmd->line_size;
device_cfg->uuid.data = cmd->cache_path_name; attach_cfg->force = cmd->force;
device_cfg->uuid.size = strnlen(device_cfg->uuid.data, MAX_STR_LEN) + 1; attach_cfg->discard_on_start = true;
device_cfg->cache_line_size = cmd->line_size;
device_cfg->force = cmd->force;
device_cfg->discard_on_start = true;
device_cfg->perform_test = false;
init_cache = cmd->init_cache; init_cache = cmd->init_cache;
switch (init_cache) { switch (init_cache) {
case CACHE_INIT_LOAD: case CACHE_INIT_LOAD:
case CACHE_INIT_ACTIVATE: attach_cfg->open_cores = true;
device_cfg->open_cores = true;
case CACHE_INIT_NEW: case CACHE_INIT_NEW:
case CACHE_INIT_BIND: case CACHE_INIT_STANDBY:
break; break;
default: default:
return -OCF_ERR_INVAL; return -OCF_ERR_INVAL;
} }
result = cas_blk_identify_type(device_cfg->uuid.data,
&device_cfg->volume_type);
if (result)
return result;
return 0; return 0;
} }
@ -1935,9 +1976,8 @@ static void init_instance_complete(struct _cache_mngt_attach_context *ctx,
/* Set other back information */ /* Set other back information */
name = block_dev_get_elevator_name( name = block_dev_get_elevator_name(
casdsk_disk_get_queue(bd_cache_obj->dsk)); casdsk_disk_get_queue(bd_cache_obj->dsk));
if (name && ctx->cmd) if (name)
strlcpy(ctx->cmd->cache_elevator, strlcpy(ctx->cache_elevator, name, MAX_ELEVATOR_NAME);
name, MAX_ELEVATOR_NAME);
} }
static void _cache_mngt_start_complete(ocf_cache_t cache, void *priv, int error) 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; struct _cache_mngt_attach_context *ctx = priv;
int caller_status; 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, 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); caller_status =_cache_mngt_async_callee_set_result(&ctx->async, error);
@ -2051,8 +2091,8 @@ out_bdev:
return result; return result;
} }
static int _cache_start_finalize(ocf_cache_t cache, static int _cache_start_finalize(ocf_cache_t cache, int init_mode,
struct kcas_start_cache *cmd) bool activate)
{ {
struct cache_priv *cache_priv = ocf_cache_get_priv(cache); struct cache_priv *cache_priv = ocf_cache_get_priv(cache);
struct _cache_mngt_attach_context *ctx = cache_priv->attach_context; 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); _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); result = cas_cls_init(cache);
if (result) { if (result) {
ctx->ocf_start_error = result; ctx->ocf_start_error = result;
@ -2069,10 +2109,14 @@ static int _cache_start_finalize(ocf_cache_t cache,
ctx->cls_inited = true; ctx->cls_inited = true;
} }
switch(cmd->init_cache) { if (activate)
case CACHE_INIT_ACTIVATE:
cache_mngt_destroy_cache_exp_obj(cache); 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: case CACHE_INIT_LOAD:
result = cache_mngt_initialize_core_exported_objects(cache); result = cache_mngt_initialize_core_exported_objects(cache);
if (result) { 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, ocf_core_visit(cache, _cache_mngt_core_device_loaded_visitor,
NULL, false); NULL, false);
break; break;
case CACHE_INIT_BIND: case CACHE_INIT_STANDBY:
result = cache_mngt_initialize_cache_exported_object(cache); result = cache_mngt_initialize_cache_exported_object(cache);
if (result) { if (result) {
ctx->ocf_start_error = result; ctx->ocf_start_error = result;
@ -2100,7 +2144,8 @@ static int _cache_start_finalize(ocf_cache_t cache,
return 0; 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"; char holder[] = "CAS START\n";
struct block_device *bdev; 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); part_count = cas_blk_get_part_count(bdev);
blkdev_put(bdev, (FMODE_EXCL|FMODE_READ)); 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 -KCAS_ERR_CONTAINS_PART;
return 0; return 0;
} }
int cache_mngt_init_instance_activate(struct ocf_mngt_cache_config *cfg, int cache_mngt_failover_detach(struct kcas_failover_detach *cmd)
struct ocf_mngt_cache_device_config *device_cfg, {
struct kcas_start_cache *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; struct _cache_mngt_attach_context *context;
ocf_cache_t cache; ocf_cache_t cache;
@ -2147,7 +2245,7 @@ int cache_mngt_init_instance_activate(struct ocf_mngt_cache_config *cfg,
if (result) if (result)
goto out_module_put; goto out_module_put;
if (!ocf_cache_is_passive(cache)) { if (!ocf_cache_is_standby(cache)) {
result = -OCF_ERR_CACHE_EXIST; result = -OCF_ERR_CACHE_EXIST;
goto out_cache_put; goto out_cache_put;
} }
@ -2156,13 +2254,17 @@ int cache_mngt_init_instance_activate(struct ocf_mngt_cache_config *cfg,
if (result) if (result)
goto out_cache_put; goto out_cache_put;
if (strnlen(cmd->cache_path, MAX_STR_LEN) > 0) {
cache_volume = ocf_cache_get_volume(cache); cache_volume = ocf_cache_get_volume(cache);
cache_uuid = ocf_volume_get_uuid(cache_volume); cache_uuid = ocf_volume_get_uuid(cache_volume);
if (strcmp(device_cfg->uuid.data, cache_uuid->data) != 0) { if (cache_uuid->size > 0 &&
result = cache_mngt_check_bdev(device_cfg); strcmp(cfg->uuid.data, cache_uuid->data)
!= 0) {
result = cache_mngt_check_bdev(cfg, false);
if (result) if (result)
goto out_cache_unlock; goto out_cache_unlock;
} }
}
context = kzalloc(sizeof(*context), GFP_KERNEL); context = kzalloc(sizeof(*context), GFP_KERNEL);
if (!context) { if (!context) {
@ -2170,8 +2272,10 @@ int cache_mngt_init_instance_activate(struct ocf_mngt_cache_config *cfg,
goto out_cache_unlock; goto out_cache_unlock;
} }
context->device_cfg = device_cfg; /* TODO: doesn't this need to be copied to avoid use-after-free
context->cmd = cmd; * in case where calle is interrupted and returns???
*/
context->device_cfg = cfg;
context->cache = cache; context->cache = cache;
cache_priv = ocf_cache_get_priv(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); _cache_mngt_async_context_init(&context->async);
ocf_mngt_cache_activate(cache, device_cfg, ocf_mngt_cache_activate(cache, cfg, _cache_mngt_start_complete,
_cache_mngt_start_complete, context); context);
result = wait_for_completion_interruptible(&context->async.cmpl); result = wait_for_completion_interruptible(&context->async.cmpl);
result = _cache_mngt_async_caller_set_result(&context->async, result); 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) if (result)
goto err_free_context; goto err_free_context;
result = _cache_start_finalize(cache, cmd); result = _cache_start_finalize(cache, -1, true);
err_free_context: err_free_context:
kfree(context); kfree(context);
@ -2214,7 +2318,7 @@ out_module_put:
} }
int cache_mngt_init_instance(struct ocf_mngt_cache_config *cfg, 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 kcas_start_cache *cmd)
{ {
struct _cache_mngt_attach_context *context; 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; struct cache_priv *cache_priv;
int result = 0, rollback_result = 0; 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)) if (!try_module_get(THIS_MODULE))
return -KCAS_ERR_SYSTEM; return -KCAS_ERR_SYSTEM;
result = cache_mngt_check_bdev(device_cfg); result = cache_mngt_check_bdev(&attach_cfg->device, attach_cfg->force);
if (result) { if (result) {
module_put(THIS_MODULE); module_put(THIS_MODULE);
return result; return result;
@ -2256,8 +2357,7 @@ int cache_mngt_init_instance(struct ocf_mngt_cache_config *cfg,
return result; return result;
} }
context->device_cfg = device_cfg; context->device_cfg = &attach_cfg->device;
context->cmd = cmd;
_cache_mngt_async_context_init(&context->async); _cache_mngt_async_context_init(&context->async);
/* Start cache. Returned cache instance will be locked as it was set /* 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) { switch (cmd->init_cache) {
case CACHE_INIT_NEW: case CACHE_INIT_NEW:
ocf_mngt_cache_attach(cache, device_cfg, ocf_mngt_cache_attach(cache, attach_cfg,
_cache_mngt_start_complete, context); _cache_mngt_start_complete, context);
break; break;
case CACHE_INIT_LOAD: case CACHE_INIT_LOAD:
ocf_mngt_cache_load(cache, device_cfg, ocf_mngt_cache_load(cache, attach_cfg,
_cache_mngt_start_complete, context); _cache_mngt_start_complete, context);
break; break;
case CACHE_INIT_BIND: case CACHE_INIT_STANDBY:
ocf_mngt_cache_bind(cache, device_cfg, ocf_mngt_cache_standby(cache, attach_cfg,
_cache_mngt_start_complete, context); _cache_mngt_start_complete, context);
break; break;
default: default:
@ -2310,7 +2410,11 @@ int cache_mngt_init_instance(struct ocf_mngt_cache_config *cfg,
if (result) if (result)
goto err; 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) if (result)
goto err; goto err;
@ -2827,11 +2931,13 @@ int cache_mngt_get_info(struct kcas_cache_info *info)
if (result) if (result)
goto unlock; goto unlock;
if (info->info.attached) { if (info->info.attached && !info->info.failover_detached) {
uuid = ocf_cache_get_uuid(cache); uuid = ocf_cache_get_uuid(cache);
BUG_ON(!uuid); BUG_ON(!uuid);
strlcpy(info->cache_path_name, uuid->data, strlcpy(info->cache_path_name, uuid->data,
min(sizeof(info->cache_path_name), uuid->size)); min(sizeof(info->cache_path_name), uuid->size));
} else {
memset(info->cache_path_name, 0, sizeof(info->cache_path_name));
} }
/* Collect cores IDs */ /* Collect cores IDs */

View File

@ -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 cache_mngt_exit_instance(const char *cache_name, size_t name_len,
int flush); 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, 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); struct kcas_start_cache *cmd);
int cache_mngt_core_pool_get_paths(struct kcas_core_pool_path *cmd_info); 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); struct kcas_insert_core *cmd_info);
int cache_mngt_init_instance(struct ocf_mngt_cache_config *cfg, 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 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, int cache_mngt_set_seq_cutoff_threshold(ocf_cache_t cache, ocf_core_t core,
uint32_t thresh); 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_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 #endif

View File

@ -50,15 +50,15 @@ long cas_service_ioctl_ctrl(struct file *filp, unsigned int cmd,
case KCAS_IOCTL_START_CACHE: { case KCAS_IOCTL_START_CACHE: {
struct kcas_start_cache *cmd_info; struct kcas_start_cache *cmd_info;
struct ocf_mngt_cache_config cfg; 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); 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) if (retval)
RETURN_CMD_RESULT(cmd_info, arg, 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); 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); 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: default:
return -EINVAL; return -EINVAL;
} }

View File

@ -36,8 +36,7 @@
#define CACHE_INIT_NEW 0 /**< initialize new metadata from fresh start */ #define CACHE_INIT_NEW 0 /**< initialize new metadata from fresh start */
#define CACHE_INIT_LOAD 1 /**< load existing metadata */ #define CACHE_INIT_LOAD 1 /**< load existing metadata */
#define CACHE_INIT_BIND 2 /**< bind existing metadata */ #define CACHE_INIT_STANDBY 2 /**< initialize failover standby cache */
#define CACHE_INIT_ACTIVATE 3 /**< activate cache after bind */
struct kcas_start_cache { struct kcas_start_cache {
/** /**
@ -353,6 +352,21 @@ struct kcas_get_cache_param {
int ext_err_code; 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 * * CODE * NAME * STATUS *
******************************************************************************* *******************************************************************************
@ -483,6 +497,12 @@ struct kcas_get_cache_param {
/** Remove inactive core object from an running cache instance */ /** Remove inactive core object from an running cache instance */
#define KCAS_IOCTL_REMOVE_INACTIVE _IOWR(KCAS_IOCTL_MAGIC, 37, struct kcas_remove_inactive) #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 * Extended kernel CAS error codes
*/ */