diff --git a/casadm/cas_lib.c b/casadm/cas_lib.c index 1d4093d92..da9e17cb2 100644 --- a/casadm/cas_lib.c +++ b/casadm/cas_lib.c @@ -1054,6 +1054,63 @@ int attach_cache(uint16_t cache_id, const char *cache_device, int force) ocf_cache_mode_none, ocf_cache_line_size_none, force, false); } +int detach_cache(uint16_t cache_id) +{ + int fd = 0; + struct kcas_stop_cache cmd = {}; + int ioctl_code = KCAS_IOCTL_DETACH_CACHE; + int status; + + fd = open_ctrl_device(); + if (fd == -1) + return FAILURE; + + cmd.cache_id = cache_id; + cmd.flush_data = true; + + status = run_ioctl_interruptible_retry( + fd, + ioctl_code, + &cmd, + "Detaching the device from cache", + cache_id, + OCF_CORE_ID_INVALID); + close(fd); + + if (status < 0) { + if (OCF_ERR_FLUSHING_INTERRUPTED == cmd.ext_err_code) { + cas_printf(LOG_ERR, + "You have interrupted detaching the device " + "from cache %d. CAS continues to operate " + "normally.\n", + cache_id + ); + return INTERRUPTED; + } else if (OCF_ERR_WRITE_CACHE == cmd.ext_err_code){ + cas_printf(LOG_ERR, + "Detached the device from cache %d " + "with errors\n", + cache_id + ); + print_err(cmd.ext_err_code); + return FAILURE; + } else { + cas_printf(LOG_ERR, + "Error while detaching the device from" + " cache %d\n", + cache_id + ); + print_err(cmd.ext_err_code); + return FAILURE; + } + } + + cas_printf(LOG_INFO, "Successfully detached device from cache %hu\n", + cache_id); + + return SUCCESS; +} + int stop_cache(uint16_t cache_id, int flush) { int fd = 0; @@ -1082,7 +1139,6 @@ int stop_cache(uint16_t cache_id, int flush) close(fd); if (status < 0) { - if (OCF_ERR_FLUSHING_INTERRUPTED == cmd.ext_err_code) { cas_printf(LOG_ERR, "You have interrupted stopping of cache %d. " diff --git a/casadm/cas_lib.h b/casadm/cas_lib.h index 835d8bca3..9d8c48d99 100644 --- a/casadm/cas_lib.h +++ b/casadm/cas_lib.h @@ -117,6 +117,7 @@ int start_cache(uint16_t cache_id, unsigned int cache_init, ocf_cache_line_size_t line_size, int force); int stop_cache(uint16_t cache_id, int flush); +int detach_cache(uint16_t cache_id); int attach_cache(uint16_t cache_id, const char *cache_device, int force); #ifdef WI_AVAILABLE diff --git a/casadm/cas_main.c b/casadm/cas_main.c index f4e592734..f41fb5a4e 100644 --- a/casadm/cas_main.c +++ b/casadm/cas_main.c @@ -421,6 +421,11 @@ int handle_cache_attach(void) ); } +int handle_cache_detach(void) +{ + return detach_cache(command_args_values.cache_id); +} + int handle_start() { int status; @@ -543,6 +548,11 @@ static cli_option stop_options[] = { {0} }; +static cli_option detach_options[] = { + {'i', "cache-id", CACHE_ID_DESC, 1, "ID", CLI_OPTION_REQUIRED}, + {0} +}; + int handle_stop() { return stop_cache(command_args_values.cache_id, @@ -2230,6 +2240,16 @@ static cli_command cas_commands[] = { .flags = CLI_SU_REQUIRED, .help = NULL, }, + { + .name = "detach-cache", + .desc = "Detach cache device", + .long_desc = NULL, + .options = detach_options, + .command_handle_opts = command_handle_option, + .handle = handle_cache_detach, + .flags = CLI_SU_REQUIRED, + .help = NULL, + }, { .name = "stop-cache", .short_name = 'T', diff --git a/modules/cas_cache/layer_cache_management.c b/modules/cas_cache/layer_cache_management.c index 3ba65a386..ca591f97c 100644 --- a/modules/cas_cache/layer_cache_management.c +++ b/modules/cas_cache/layer_cache_management.c @@ -2506,6 +2506,22 @@ int cache_mngt_create_cache_standby_activate_cfg( return 0; } +static void _cache_mngt_detach_cache_complete(ocf_cache_t cache, void *priv, + int error) +{ + struct _cache_mngt_async_context *context = priv; + int result; + + result = _cache_mngt_async_callee_set_result(context, error); + + if (result != -KCAS_ERR_WAITING_INTERRUPTED) + return; + + kfree(context); + ocf_mngt_cache_unlock(cache); + kfree(context); +} + int cache_mngt_attach_device(const char *cache_name, size_t name_len, const char *device, struct ocf_mngt_cache_attach_config *attach_cfg) { @@ -3110,6 +3126,53 @@ int cache_mngt_set_cache_mode(const char *cache_name, size_t name_len, return result; } +int cache_mngt_detach_cache(const char *cache_name, size_t name_len) +{ + ocf_cache_t cache; + int status = 0; + struct _cache_mngt_async_context *context; + + context = kmalloc(sizeof(*context), GFP_KERNEL); + if (!context) + return -ENOMEM; + + _cache_mngt_async_context_init(context); + + status = ocf_mngt_cache_get_by_name(cas_ctx, cache_name, + name_len, &cache); + if (status) + goto err_get_cache; + + if (ocf_cache_is_running(cache)) + status = _cache_flush_with_lock(cache); + if (status) + goto err_flush; + + status = _cache_mngt_lock_sync(cache); + if (status) + goto err_lock; + + ocf_mngt_cache_detach(cache, _cache_mngt_detach_cache_complete, context); + + status = wait_for_completion_interruptible(&context->cmpl); + status = _cache_mngt_async_caller_set_result(context, status); + + if (status == -KCAS_ERR_WAITING_INTERRUPTED) { + printk(KERN_WARNING "Waiting for cache detach interrupted. " + "The operation will finish asynchronously.\n"); + goto err_int; + } + + ocf_mngt_cache_unlock(cache); +err_lock: +err_flush: + ocf_mngt_cache_put(cache); +err_get_cache: + kfree(context); +err_int: + return status; +} + /** * @brief routine implements --stop-cache command. * @param[in] cache_name caching device name to be removed diff --git a/modules/cas_cache/layer_cache_management.h b/modules/cas_cache/layer_cache_management.h index 8dd6bf38b..4e36d2c4d 100644 --- a/modules/cas_cache/layer_cache_management.h +++ b/modules/cas_cache/layer_cache_management.h @@ -43,6 +43,8 @@ int cache_mngt_reset_stats(const char *cache_name, size_t cache_name_len, int cache_mngt_set_partitions(const char *cache_name, size_t name_len, struct kcas_io_classes *cfg); +int cache_mngt_detach_cache(const char *cache_name, size_t name_len); + int cache_mngt_attach_device(const char *cache_name, size_t name_len, const char *device, struct ocf_mngt_cache_attach_config *attach_cfg); diff --git a/modules/cas_cache/service_ui_ioctl.c b/modules/cas_cache/service_ui_ioctl.c index ef5383bd8..0bd8e19ca 100644 --- a/modules/cas_cache/service_ui_ioctl.c +++ b/modules/cas_cache/service_ui_ioctl.c @@ -99,6 +99,20 @@ long cas_service_ioctl_ctrl(struct file *filp, unsigned int cmd, RETURN_CMD_RESULT(cmd_info, arg, retval); } + case KCAS_IOCTL_DETACH_CACHE: { + struct kcas_stop_cache *cmd_info; + char cache_name[OCF_CACHE_NAME_SIZE]; + + GET_CMD_INFO(cmd_info, arg); + + cache_name_from_id(cache_name, cmd_info->cache_id); + + retval = cache_mngt_detach_cache(cache_name, + OCF_CACHE_NAME_SIZE); + + RETURN_CMD_RESULT(cmd_info, arg, retval); + } + case KCAS_IOCTL_SET_CACHE_STATE: { struct kcas_set_cache_state *cmd_info; char cache_name[OCF_CACHE_NAME_SIZE]; diff --git a/modules/include/cas_ioctl_codes.h b/modules/include/cas_ioctl_codes.h index db1f85ca6..bdfad29e0 100644 --- a/modules/include/cas_ioctl_codes.h +++ b/modules/include/cas_ioctl_codes.h @@ -406,6 +406,7 @@ struct kcas_standby_activate * 39 * KCAS_IOCTL_STANDBY_ACTIVATE * OK * * 40 * KCAS_IOCTL_CORE_INFO * OK * * 41 * KCAS_IOCTL_START_CACHE * OK * + * 42 * KCAS_IOCTL_DETACH_CACHE * OK * * 43 * KCAS_IOCTL_ATTACH_CACHE * OK * ******************************************************************************* */ @@ -505,6 +506,9 @@ struct kcas_standby_activate /** Start new cache instance, load cache or recover cache */ #define KCAS_IOCTL_START_CACHE _IOWR(KCAS_IOCTL_MAGIC, 41, struct kcas_start_cache) +/** Detach cache device */ +#define KCAS_IOCTL_DETACH_CACHE _IOWR(KCAS_IOCTL_MAGIC, 42, struct kcas_stop_cache) + /** Attach cache device */ #define KCAS_IOCTL_ATTACH_CACHE _IOWR(KCAS_IOCTL_MAGIC, 43, struct kcas_start_cache)