diff --git a/casadm/cas_lib.c b/casadm/cas_lib.c index 7d561be..f673824 100644 --- a/casadm/cas_lib.c +++ b/casadm/cas_lib.c @@ -1915,6 +1915,29 @@ int core_pool_remove(const char *core_device) return SUCCESS; } +int purge_cache(unsigned int cache_id) +{ + int fd = 0; + struct kcas_flush_cache cmd; + + fd = open_ctrl_device(); + if (fd == -1) + return FAILURE; + + memset(&cmd, 0, sizeof(cmd)); + cmd.cache_id = cache_id; + /* synchronous flag */ + if (run_ioctl_interruptible(fd, KCAS_IOCTL_PURGE_CACHE, &cmd, "Purging cache", + cache_id, OCF_CORE_ID_INVALID) < 0) { + close(fd); + print_err(cmd.ext_err_code); + return FAILURE; + } + + close(fd); + return SUCCESS; +} + #define DIRTY_FLUSHING_WARNING "You have interrupted flushing of cache dirty data. CAS continues to operate\nnormally and dirty data that remains on cache device will be flushed by cleaning thread.\n" int flush_cache(unsigned int cache_id) { diff --git a/casadm/cas_lib.h b/casadm/cas_lib.h index cc545ac..9dafcdc 100644 --- a/casadm/cas_lib.h +++ b/casadm/cas_lib.h @@ -220,6 +220,8 @@ int get_core_pool_count(int fd); int reset_counters(unsigned int cache_id, unsigned int core_id); +int purge_cache(unsigned int cache_id); + int flush_cache(unsigned int cache_id); int flush_core(unsigned int cache_id, unsigned int core_id); diff --git a/casadm/cas_main.c b/casadm/cas_main.c index 7b0a63d..3b8bcef 100644 --- a/casadm/cas_main.c +++ b/casadm/cas_main.c @@ -1419,6 +1419,7 @@ enum { script_cmd_add_core, script_cmd_remove_core, + script_cmd_purge_cache, script_cmd_max_id, @@ -1477,6 +1478,14 @@ static cli_option script_params_options[] = { | (1 << script_opt_core_id), .flags = CLI_COMMAND_HIDDEN, }, + [script_cmd_purge_cache] = { + .short_name = 0, + .long_name = "purge-cache", + .args_count = 0, + .arg = NULL, + .priv = (1 << script_opt_cache_id), + .flags = CLI_COMMAND_HIDDEN, + }, [script_opt_cache_device] = { .short_name = 0, .long_name = "cache-device", @@ -1491,7 +1500,8 @@ static cli_option script_params_options[] = { .args_count = 1, .arg = "ID", .priv = (1 << script_cmd_remove_core) - | (1 << script_cmd_add_core), + | (1 << script_cmd_add_core) + | (1 << script_cmd_purge_cache), .flags = (CLI_OPTION_RANGE_INT | CLI_OPTION_HIDDEN), .min_value = OCF_CACHE_ID_MIN, .max_value = OCF_CACHE_ID_MAX, @@ -1658,6 +1668,8 @@ int script_handle() { command_args_values.detach, command_args_values.no_flush ); + case script_cmd_purge_cache: + return purge_cache(command_args_values.cache_id); } return FAILURE; diff --git a/modules/cas_cache/layer_cache_management.c b/modules/cas_cache/layer_cache_management.c index f6a724e..fd1e1c1 100644 --- a/modules/cas_cache/layer_cache_management.c +++ b/modules/cas_cache/layer_cache_management.c @@ -230,6 +230,56 @@ static int _cache_mngt_cache_flush_uninterruptible(ocf_cache_t cache) return result; } +static void _cache_mngt_cache_purge_complete(ocf_cache_t cache, void *priv, + int error) +{ + struct _cache_mngt_async_context *context = priv; + int result; + + if (context->compl_func) + context->compl_func(cache); + + result = _cache_mngt_async_callee_set_result(context, error); + + if (result == -KCAS_ERR_WAITING_INTERRUPTED) + kfree(context); +} + +/* + * Possible return values: + * 0 - completion was called and operation succeded + * -KCAS_ERR_WAITING_INTERRUPTED - operation was canceled, caller must + * propagate error + * other values - completion was called and operation failed + */ +static int _cache_mngt_cache_purge_sync(ocf_cache_t cache, + void (*compl)(ocf_cache_t cache)) +{ + int result; + struct _cache_mngt_async_context *context; + + context = kmalloc(sizeof(*context), GFP_KERNEL); + if (!context) { + if (compl) + compl(cache); + return -ENOMEM; + } + + _cache_mngt_async_context_init(context); + context->compl_func = compl; + + ocf_mngt_cache_purge(cache, _cache_mngt_cache_purge_complete, context); + result = wait_for_completion_interruptible(&context->cmpl); + + result = _cache_mngt_async_caller_set_result(context, result); + + if (result != -KCAS_ERR_WAITING_INTERRUPTED) + kfree(context); + + return result; +} + + static void _cache_mngt_cache_flush_complete(ocf_cache_t cache, void *priv, int error) { @@ -640,6 +690,27 @@ int cache_mngt_flush_object(const char *cache_name, size_t cache_name_len, return result; } +int cache_mngt_purge_device(const char *cache_name, size_t name_len) +{ + int result; + ocf_cache_t cache; + + result = ocf_mngt_cache_get_by_name(cas_ctx, cache_name, + name_len, &cache); + if (result) + return result; + + result = _cache_mngt_read_lock_sync(cache); + if (result) { + ocf_mngt_cache_put(cache); + return result; + } + + result = _cache_mngt_cache_purge_sync(cache, _cache_read_unlock_put_cmpl); + + return result; +} + int cache_mngt_flush_device(const char *cache_name, size_t name_len) { int result; diff --git a/modules/cas_cache/layer_cache_management.h b/modules/cas_cache/layer_cache_management.h index 5857a39..2c9d176 100644 --- a/modules/cas_cache/layer_cache_management.h +++ b/modules/cas_cache/layer_cache_management.h @@ -82,6 +82,8 @@ int cache_mngt_flush_object(const char *cache_name, size_t cache_name_len, int cache_mngt_flush_device(const char *cache_name, size_t name_len); +int cache_mngt_purge_device(const char *cache_name, size_t name_len); + int cache_mngt_list_caches(struct kcas_cache_list *list); int cache_mngt_interrupt_flushing(const char *cache_name, size_t name_len); diff --git a/modules/cas_cache/service_ui_ioctl.c b/modules/cas_cache/service_ui_ioctl.c index a0cfc6e..53c7823 100644 --- a/modules/cas_cache/service_ui_ioctl.c +++ b/modules/cas_cache/service_ui_ioctl.c @@ -154,6 +154,19 @@ long cas_service_ioctl_ctrl(struct file *filp, unsigned int cmd, RETURN_CMD_RESULT(cmd_info, arg, retval); } + case KCAS_IOCTL_PURGE_CACHE: { + struct kcas_flush_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_purge_device(cache_name, OCF_CACHE_NAME_SIZE); + + RETURN_CMD_RESULT(cmd_info, arg, retval); + } + case KCAS_IOCTL_FLUSH_CACHE: { struct kcas_flush_cache *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 d424d9a..26d591d 100644 --- a/modules/include/cas_ioctl_codes.h +++ b/modules/include/cas_ioctl_codes.h @@ -410,6 +410,7 @@ struct kcas_get_cache_param { * 32 * KCAS_IOCTL_SET_CACHE_PARAM * OK * * 33 * KCAS_IOCTL_GET_CACHE_PARAM * OK * * 34 * KCAS_IOCTL_GET_STATS * OK * + * 35 * KCAS_IOCTL_PURGE_CACHE * OK * ******************************************************************************* */ @@ -500,6 +501,10 @@ struct kcas_get_cache_param { /** Get stats of particular OCF object */ #define KCAS_IOCTL_GET_STATS _IOR(KCAS_IOCTL_MAGIC, 34, struct kcas_get_stats) +/* Flush dirty data from running cache + * and invalidate all valid cache lines */ +#define KCAS_IOCTL_PURGE_CACHE _IOWR(KCAS_IOCTL_MAGIC, 35, struct kcas_flush_cache) + /** * Extended kernel CAS error codes */