From d24288a9b11160290cb567d073a1a1b58ca66686 Mon Sep 17 00:00:00 2001 From: Michal Mielewczyk Date: Fri, 8 May 2020 11:12:31 -0400 Subject: [PATCH 1/4] Purge cache command Purge invalidates all cache lines. It is very usefull feature for tests. Calling purge is possbile with casadm `--script` swtich. Signed-off-by: Michal Mielewczyk --- casadm/cas_lib.c | 23 +++++++ casadm/cas_lib.h | 2 + casadm/cas_main.c | 14 ++++- modules/cas_cache/layer_cache_management.c | 71 ++++++++++++++++++++++ modules/cas_cache/layer_cache_management.h | 2 + modules/cas_cache/service_ui_ioctl.c | 13 ++++ modules/include/cas_ioctl_codes.h | 5 ++ 7 files changed, 129 insertions(+), 1 deletion(-) 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 */ From 3b62e40a2ea6414ac508a42400a3431a8960abfd Mon Sep 17 00:00:00 2001 From: Michal Mielewczyk Date: Mon, 11 May 2020 04:49:03 -0400 Subject: [PATCH 2/4] Purge core command Purge invalidates all cache lines which belongs to given core. It is very usefull feature for tests. Calling purge is possbile with casadm `--script` swtich. Signed-off-by: Michal Mielewczyk --- casadm/cas_lib.c | 23 ++++++ casadm/cas_lib.h | 1 + casadm/cas_main.c | 21 +++++- modules/cas_cache/layer_cache_management.c | 81 ++++++++++++++++++++++ modules/cas_cache/layer_cache_management.h | 3 + modules/cas_cache/service_ui_ioctl.c | 17 +++++ modules/include/cas_ioctl_codes.h | 5 ++ 7 files changed, 149 insertions(+), 2 deletions(-) diff --git a/casadm/cas_lib.c b/casadm/cas_lib.c index f673824..f4089e1 100644 --- a/casadm/cas_lib.c +++ b/casadm/cas_lib.c @@ -1967,6 +1967,29 @@ int flush_cache(unsigned int cache_id) return SUCCESS; } +int purge_core(unsigned int cache_id, unsigned int core_id) +{ + int fd = 0; + struct kcas_flush_core cmd; + + memset(&cmd, 0, sizeof(cmd)); + cmd.cache_id = cache_id; + cmd.core_id = core_id; + + fd = open_ctrl_device(); + if (fd == -1) + return FAILURE; + + /* synchronous flag */ + if (run_ioctl_interruptible(fd, KCAS_IOCTL_PURGE_CORE, &cmd, "Purging core", cache_id, core_id) < 0) { + close(fd); + print_err(cmd.ext_err_code); + return FAILURE; + } + close(fd); + return SUCCESS; +} + int flush_core(unsigned int cache_id, unsigned int core_id) { int fd = 0; diff --git a/casadm/cas_lib.h b/casadm/cas_lib.h index 9dafcdc..e5adefc 100644 --- a/casadm/cas_lib.h +++ b/casadm/cas_lib.h @@ -221,6 +221,7 @@ 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 purge_core(unsigned int cache_id, unsigned int core_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 3b8bcef..d4039a6 100644 --- a/casadm/cas_main.c +++ b/casadm/cas_main.c @@ -1420,6 +1420,7 @@ enum { script_cmd_add_core, script_cmd_remove_core, script_cmd_purge_cache, + script_cmd_purge_core, script_cmd_max_id, @@ -1486,6 +1487,15 @@ static cli_option script_params_options[] = { .priv = (1 << script_opt_cache_id), .flags = CLI_COMMAND_HIDDEN, }, + [script_cmd_purge_core] = { + .short_name = 0, + .long_name = "purge-core", + .args_count = 0, + .arg = NULL, + .priv = (1 << script_opt_cache_id) + | (1 << script_opt_core_id), + .flags = CLI_COMMAND_HIDDEN, + }, [script_opt_cache_device] = { .short_name = 0, .long_name = "cache-device", @@ -1501,7 +1511,8 @@ static cli_option script_params_options[] = { .arg = "ID", .priv = (1 << script_cmd_remove_core) | (1 << script_cmd_add_core) - | (1 << script_cmd_purge_cache), + | (1 << script_cmd_purge_cache) + | (1 << script_cmd_purge_core), .flags = (CLI_OPTION_RANGE_INT | CLI_OPTION_HIDDEN), .min_value = OCF_CACHE_ID_MIN, .max_value = OCF_CACHE_ID_MAX, @@ -1512,7 +1523,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_core), .flags = (CLI_OPTION_RANGE_INT | CLI_OPTION_HIDDEN), .min_value = OCF_CORE_ID_MIN, .max_value = OCF_CORE_ID_MAX, @@ -1670,6 +1682,11 @@ int script_handle() { ); case script_cmd_purge_cache: return purge_cache(command_args_values.cache_id); + case script_cmd_purge_core: + return purge_core( + command_args_values.cache_id, + command_args_values.core_id + ); } return FAILURE; diff --git a/modules/cas_cache/layer_cache_management.c b/modules/cas_cache/layer_cache_management.c index fd1e1c1..841f9b8 100644 --- a/modules/cas_cache/layer_cache_management.c +++ b/modules/cas_cache/layer_cache_management.c @@ -279,6 +279,56 @@ static int _cache_mngt_cache_purge_sync(ocf_cache_t cache, return result; } +static void _cache_mngt_core_purge_complete(ocf_core_t core, void *priv, + int error) +{ + struct _cache_mngt_async_context *context = priv; + int result; + ocf_cache_t cache = ocf_core_get_cache(core); + + 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_core_purge_sync(ocf_core_t core, bool interruption, + void (*compl)(ocf_cache_t cache)) +{ + int result; + struct _cache_mngt_async_context *context; + ocf_cache_t cache = ocf_core_get_cache(core); + + 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_core_purge(core, _cache_mngt_core_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) @@ -659,6 +709,37 @@ static void _cache_read_unlock_put_cmpl(ocf_cache_t cache) ocf_mngt_cache_put(cache); } +int cache_mngt_purge_object(const char *cache_name, size_t cache_name_len, + const char *core_name, size_t core_name_len) +{ + ocf_cache_t cache; + ocf_core_t core; + int result; + + result = ocf_mngt_cache_get_by_name(cas_ctx, cache_name, + cache_name_len, &cache); + if (result) + return result; + + result = _cache_mngt_read_lock_sync(cache); + if (result) { + ocf_mngt_cache_put(cache); + return result; + } + + result = ocf_core_get_by_name(cache, core_name, core_name_len, &core); + if (result) { + ocf_mngt_cache_read_unlock(cache); + ocf_mngt_cache_put(cache); + return result; + } + + result = _cache_mngt_core_purge_sync(core, true, + _cache_read_unlock_put_cmpl); + + return result; +} + int cache_mngt_flush_object(const char *cache_name, size_t cache_name_len, const char *core_name, size_t core_name_len) { diff --git a/modules/cas_cache/layer_cache_management.h b/modules/cas_cache/layer_cache_management.h index 2c9d176..8f24f19 100644 --- a/modules/cas_cache/layer_cache_management.h +++ b/modules/cas_cache/layer_cache_management.h @@ -77,6 +77,9 @@ int cache_mngt_get_seq_cutoff_policy(ocf_core_t core, int cache_mngt_set_cache_mode(const char *cache_name, size_t name_len, ocf_cache_mode_t mode, uint8_t flush); +int cache_mngt_purge_object(const char *cache_name, size_t cache_name_len, + const char *core_name, size_t core_name_len); + int cache_mngt_flush_object(const char *cache_name, size_t cache_name_len, const char *core_name, size_t core_name_len); diff --git a/modules/cas_cache/service_ui_ioctl.c b/modules/cas_cache/service_ui_ioctl.c index 53c7823..f3788fa 100644 --- a/modules/cas_cache/service_ui_ioctl.c +++ b/modules/cas_cache/service_ui_ioctl.c @@ -194,6 +194,23 @@ long cas_service_ioctl_ctrl(struct file *filp, unsigned int cmd, RETURN_CMD_RESULT(cmd_info, arg, retval); } + case KCAS_IOCTL_PURGE_CORE: { + struct kcas_flush_core *cmd_info; + char cache_name[OCF_CACHE_NAME_SIZE]; + char core_name[OCF_CORE_NAME_SIZE]; + + GET_CMD_INFO(cmd_info, arg); + + cache_name_from_id(cache_name, cmd_info->cache_id); + + core_name_from_id(core_name, cmd_info->core_id); + + retval = cache_mngt_purge_object(cache_name, OCF_CACHE_NAME_SIZE, + core_name, OCF_CORE_NAME_SIZE); + + RETURN_CMD_RESULT(cmd_info, arg, retval); + } + case KCAS_IOCTL_FLUSH_CORE: { struct kcas_flush_core *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 26d591d..5f660e8 100644 --- a/modules/include/cas_ioctl_codes.h +++ b/modules/include/cas_ioctl_codes.h @@ -411,6 +411,7 @@ struct kcas_get_cache_param { * 33 * KCAS_IOCTL_GET_CACHE_PARAM * OK * * 34 * KCAS_IOCTL_GET_STATS * OK * * 35 * KCAS_IOCTL_PURGE_CACHE * OK * + * 36 * KCAS_IOCTL_PURGE_CORE * OK * ******************************************************************************* */ @@ -505,6 +506,10 @@ struct kcas_get_cache_param { * and invalidate all valid cache lines */ #define KCAS_IOCTL_PURGE_CACHE _IOWR(KCAS_IOCTL_MAGIC, 35, struct kcas_flush_cache) +/* Flush dirty data from running core object + * and invalidate all valid cache lines associated with given core. */ +#define KCAS_IOCTL_PURGE_CORE _IOWR(KCAS_IOCTL_MAGIC, 36, struct kcas_flush_core) + /** * Extended kernel CAS error codes */ From c28babde8ba5db32314d9e0023e781d21a02187a Mon Sep 17 00:00:00 2001 From: Michal Mielewczyk Date: Mon, 11 May 2020 06:24:40 -0400 Subject: [PATCH 3/4] tests: Wrappers for purge commands Signed-off-by: Michal Mielewczyk --- test/functional/api/cas/cache.py | 4 ++++ test/functional/api/cas/casadm.py | 14 ++++++++++++++ test/functional/api/cas/cli.py | 8 ++++++++ test/functional/api/cas/core.py | 4 ++++ 4 files changed, 30 insertions(+) diff --git a/test/functional/api/cas/cache.py b/test/functional/api/cas/cache.py index a876848..a31db71 100644 --- a/test/functional/api/cas/cache.py +++ b/test/functional/api/cas/cache.py @@ -117,6 +117,10 @@ class Cache: sync() assert self.get_dirty_blocks().get_value(Unit.Blocks4096) == 0 + def purge_cache(self): + casadm.purge_cache(cache_id=self.cache_id) + sync() + def stop(self, no_data_flush: bool = False): return casadm.stop_cache(self.cache_id, no_data_flush) diff --git a/test/functional/api/cas/casadm.py b/test/functional/api/cas/casadm.py index 35759ad..9f81579 100644 --- a/test/functional/api/cas/casadm.py +++ b/test/functional/api/cas/casadm.py @@ -79,6 +79,20 @@ def try_add(core_device: Device, cache_id: int): return Core(core_device.system_path, cache_id) +def purge_cache(cache_id: int): + output = TestRun.executor.run(script_purge_cache(str(cache_id))) + if output.exit_code != 0: + raise CmdException("Purge cache failed.", output) + return output + + +def purge_core(cache_id: int, core_id: int): + output = TestRun.executor.run(script_purge_core(str(cache_id), str(core_id))) + if output.exit_code != 0: + raise CmdException("Purge core failed.", output) + return output + + def reset_counters(cache_id: int, core_id: int = None, shortcut: bool = False): _core_id = None if core_id is None else str(core_id) output = TestRun.executor.run( diff --git a/test/functional/api/cas/cli.py b/test/functional/api/cas/cli.py index 3a43178..be66f8d 100644 --- a/test/functional/api/cas/cli.py +++ b/test/functional/api/cas/cli.py @@ -24,6 +24,14 @@ def script_try_add_cmd(cache_id: str, core_dev: str): f"--core-device {core_dev}" +def script_purge_cache_cmd(cache_id: str): + return f"{casadm_bin} --script --purge-cache --cache-id {cache_id}" + + +def script_purge_core_cmd(cache_id: str, core_id: str): + return f"{casadm_bin} --script --purge-core --cache-id {cache_id} --core-id {core_id}" + + def remove_core_cmd(cache_id: str, core_id: str, force: bool = False, shortcut: bool = False): command = f" -R -i {cache_id} -j {core_id}" if shortcut \ else f" --remove-core --cache-id {cache_id} --core-id {core_id}" diff --git a/test/functional/api/cas/core.py b/test/functional/api/cas/core.py index a54e6b3..c9bc65e 100644 --- a/test/functional/api/cas/core.py +++ b/test/functional/api/cas/core.py @@ -111,6 +111,10 @@ class Core(Device): sync() assert self.get_dirty_blocks().get_value(Unit.Blocks4096) == 0 + def purge_core(self): + casadm.purge_core(self.cache_id, self.core_id) + sync() + def set_seq_cutoff_parameters(self, seq_cutoff_param: SeqCutOffParameters): return casadm.set_param_cutoff(self.cache_id, self.core_id, seq_cutoff_param.threshold, seq_cutoff_param.policy) From 84f2dc3c077f9fa9ea94563233bb04738a6497ad Mon Sep 17 00:00:00 2001 From: Michal Mielewczyk Date: Mon, 11 May 2020 08:24:54 -0400 Subject: [PATCH 4/4] CLI test for purge commands Signed-off-by: Michal Mielewczyk --- test/functional/tests/cli/test_cli_script.py | 85 ++++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 test/functional/tests/cli/test_cli_script.py diff --git a/test/functional/tests/cli/test_cli_script.py b/test/functional/tests/cli/test_cli_script.py new file mode 100644 index 0000000..ece85db --- /dev/null +++ b/test/functional/tests/cli/test_cli_script.py @@ -0,0 +1,85 @@ +# +# Copyright(c) 2020 Intel Corporation +# SPDX-License-Identifier: BSD-3-Clause-Clear +# + + +import pytest + +from api.cas import casadm, casadm_parser +from core.test_run import TestRun +from test_utils.os_utils import sync +from storage_devices.disk import DiskType, DiskTypeSet, DiskTypeLowerThan +from test_utils.size import Unit, Size +from test_tools.dd import Dd + + +@pytest.mark.require_disk("cache", DiskTypeSet([DiskType.nand, DiskType.optane])) +@pytest.mark.require_disk("core", DiskTypeLowerThan("cache")) +@pytest.mark.parametrize("purge_target", ["cache", "core"]) +def test_purge(purge_target): + """ + title: Call purge without and with `--script` switch + description: | + Check if purge is called only when `--script` switch is used. + pass_criteria: + - casadm returns an error when `--script` is missing + - cache is wiped when purge command is used properly + """ + with TestRun.step("Prepare devices"): + cache_device = TestRun.disks["cache"] + core_device = TestRun.disks["core"] + + cache_device.create_partitions([Size(500, Unit.MebiByte)]) + core_device.create_partitions([Size(500, Unit.MebiByte)]) + + cache_device = cache_device.partitions[0] + core_device = core_device.partitions[0] + + with TestRun.step("Prepare cache instance"): + cache = casadm.start_cache(cache_device, force=True) + core = casadm.add_core(cache, core_device) + + with TestRun.step("Trigger IO to prepared cache instance"): + dd = ( + Dd() + .input("/dev/zero") + .output(core.system_path) + .count(100) + .block_size(Size(1, Unit.Blocks512)) + .oflag("direct") + ) + dd.run() + sync() + + with TestRun.step( + f"Try to call purge-{purge_target} without `--script` switch" + ): + original_occupancy = cache.get_statistics().usage_stats.occupancy + purge_params = f"--cache-id {cache.cache_id} " + if purge_target == "core": + purge_params += f"--core-id {core.core_id}" + TestRun.executor.run_expect_fail( + f"casadm --purge-{purge_target} {purge_params}" + ) + + if cache.get_statistics().usage_stats.occupancy != original_occupancy: + TestRun.fail( + f"Purge {purge_target} should not be possible to use without `--script` switch!" + ) + + with TestRun.step( + f"Try to call purge-{purge_target} with `--script` switch" + ): + TestRun.executor.run_expect_success( + f"casadm --script --purge-{purge_target} {purge_params}" + ) + + if cache.get_statistics().usage_stats.occupancy.get_value() != 0: + TestRun.fail(f"{cache.get_statistics().usage_stats.occupancy.get_value()}") + TestRun.fail(f"Purge {purge_target} should invalidate all cache lines!") + + with TestRun.step( + f"Stop cache" + ): + casadm.stop_all_caches()