diff --git a/inc/ocf_io_class.h b/inc/ocf_io_class.h index e3e7b56..caab0db 100644 --- a/inc/ocf_io_class.h +++ b/inc/ocf_io_class.h @@ -57,15 +57,15 @@ struct ocf_io_class_info { * function meant to retrieve information pertaining to particular IO class, * specifically to fill ocf_io_class_info structure based on input parameters. * - * @param[in] cache cache id, to which specified request pertains. + * @param[in] cache cache handle, to which specified request pertains. * @param[in] io_class id of an io class which shall be retreived. - * @param[out] info io class info structure to be filled as a + * @param[out] info io class info structures to be filled as a * result of this function call. * * @return function returns 0 upon successful completion; appropriate error * code is returned otherwise */ -int ocf_io_class_get_info(ocf_cache_t cache, uint32_t io_class, +int ocf_cache_io_class_get_info(ocf_cache_t cache, uint32_t io_class, struct ocf_io_class_info *info); /** diff --git a/inc/ocf_mngt.h b/inc/ocf_mngt.h index 3d1fd55..96de006 100644 --- a/inc/ocf_mngt.h +++ b/inc/ocf_mngt.h @@ -543,8 +543,12 @@ struct ocf_mngt_io_class_config { uint32_t max_size; }; +struct ocf_mngt_io_classes_config { + struct ocf_mngt_io_class_config config[OCF_IO_CLASS_MAX]; +}; + /** - * @brief Configure IO class in given cache + * @brief Configure IO classes in given cache * * @param[in] cache Cache handle * @param[in] cfg IO class configuration @@ -552,8 +556,8 @@ struct ocf_mngt_io_class_config { * @retval 0 Configuration have been set successfully * @retval Non-zero Error occurred and configuration not been set */ -int ocf_mngt_io_class_configure(ocf_cache_t cache, - const struct ocf_mngt_io_class_config *cfg); +int ocf_mngt_cache_io_classes_configure(ocf_cache_t cache, + const struct ocf_mngt_io_classes_config *cfg); /** * @brief Set core sequential cutoff threshold diff --git a/inc/ocf_stats.h b/inc/ocf_stats.h index 379af13..aeb03e4 100644 --- a/inc/ocf_stats.h +++ b/inc/ocf_stats.h @@ -173,18 +173,19 @@ void ocf_core_stats_initialize(ocf_core_t core); void ocf_core_stats_initialize_all(ocf_cache_t cache); /** - * @brief ocf_io_class_get_stats retrieve cache statistics + * @brief ocf_core_io_class_get_stats retrieve io class statistics + * for given core * * Retrieve buffer of cache statistics for given cache instance. * - * @param[in] core core ID to which request pertains - * @param[in] io_class IO class, stats of which are requested - * @param[out] stats statistics structure that shall be filled as + * @param[in] core core handle to which request pertains + * @param[in] part_id IO class, stats of which are requested + * @param[out] stats statistic structure that shall be filled as * a result of this function invocation. * * @result zero upon successful completion; error code otherwise */ -int ocf_io_class_get_stats(ocf_core_t core, uint32_t io_class, +int ocf_core_io_class_get_stats(ocf_core_t core, ocf_part_id_t part_id, struct ocf_stats_io_class *stats); /** diff --git a/src/cleaning/acp.c b/src/cleaning/acp.c index 87497bc..7a44cb3 100644 --- a/src/cleaning/acp.c +++ b/src/cleaning/acp.c @@ -14,6 +14,7 @@ #include "../engine/engine_common.h" #include "../concurrency/ocf_cache_concurrency.h" #include "cleaning_priv.h" +#include "../utils/utils_core.h" #define OCF_ACP_DEBUG 0 @@ -184,10 +185,6 @@ static struct acp_chunk_info *_acp_get_chunk(struct ocf_cache *cache, return &acp->chunk_info[core_line.core_id][chunk_id]; } -#define for_each_core(cache, iter) \ - for (iter = 0; iter < OCF_CORE_MAX; iter++) \ - if (cache->core_conf_meta[iter].added) - static void _acp_remove_cores(struct ocf_cache *cache) { int i; diff --git a/src/engine/cache_engine.c b/src/engine/cache_engine.c index 320833d..cbfe539 100644 --- a/src/engine/cache_engine.c +++ b/src/engine/cache_engine.c @@ -233,7 +233,7 @@ ocf_cache_mode_t ocf_get_effective_cache_mode(ocf_cache_t cache, mode = ocf_cache_mode_pt; if (mode == ocf_cache_mode_wb && - env_atomic_read(&cache->dirty_rq_barrier)) + env_atomic_read(&cache->flush_started)) mode = ocf_cache_mode_wt; return mode; diff --git a/src/mngt/ocf_mngt_cache.c b/src/mngt/ocf_mngt_cache.c index b937368..7691d25 100644 --- a/src/mngt/ocf_mngt_cache.c +++ b/src/mngt/ocf_mngt_cache.c @@ -1856,7 +1856,7 @@ int ocf_mngt_cache_detach(ocf_cache_t cache) return -EINVAL; /* prevent dirty io */ - env_atomic_inc(&cache->dirty_rq_barrier); + env_atomic_inc(&cache->flush_started); result = ocf_mngt_cache_flush(cache, true); if (result) @@ -1867,7 +1867,7 @@ int ocf_mngt_cache_detach(ocf_cache_t cache) env_waitqueue_wait(cache->pending_cache_wq, !env_atomic_read(&cache->pending_cache_requests)); - ENV_BUG_ON(env_atomic_dec_return(&cache->dirty_rq_barrier) < 0); + ENV_BUG_ON(env_atomic_dec_return(&cache->flush_started) < 0); /* remove cacheline metadata and cleaning policy meta for all cores */ for (i = 0, j = 0; j < no && i < OCF_CORE_MAX; i++) { diff --git a/src/mngt/ocf_mngt_flush.c b/src/mngt/ocf_mngt_flush.c index 0263933..4bfef22 100644 --- a/src/mngt/ocf_mngt_flush.c +++ b/src/mngt/ocf_mngt_flush.c @@ -18,7 +18,7 @@ static inline void _ocf_mngt_begin_flush(struct ocf_cache *cache) { env_mutex_lock(&cache->flush_mutex); - env_atomic_inc(&cache->dirty_rq_barrier); + env_atomic_inc(&cache->flush_started); env_waitqueue_wait(cache->pending_dirty_wq, !env_atomic_read(&cache->pending_dirty_requests)); @@ -26,7 +26,7 @@ static inline void _ocf_mngt_begin_flush(struct ocf_cache *cache) static inline void _ocf_mngt_end_flush(struct ocf_cache *cache) { - ENV_BUG_ON(env_atomic_dec_return(&cache->dirty_rq_barrier) < 0); + ENV_BUG_ON(env_atomic_dec_return(&cache->flush_started) < 0); env_mutex_unlock(&cache->flush_mutex); } diff --git a/src/mngt/ocf_mngt_io_class.c b/src/mngt/ocf_mngt_io_class.c index 259630b..777bfe9 100644 --- a/src/mngt/ocf_mngt_io_class.c +++ b/src/mngt/ocf_mngt_io_class.c @@ -109,113 +109,118 @@ static int _ocf_mngt_io_class_configure(ocf_cache_t cache, OCF_CHECK_NULL(cache->device); - OCF_METADATA_LOCK_WR(); - dest_part = &cache->user_parts[part_id]; if (!ocf_part_is_added(dest_part)) { ocf_cache_log(cache, log_info, "Setting IO class, id: %u, " "name: '%s' [ ERROR ]\n", part_id, dest_part->config->name); - OCF_METADATA_UNLOCK_WR(); return -OCF_ERR_INVAL; } + if (!name || !name[0]) + return -OCF_ERR_IO_CLASS_NOT_EXIST; + if (part_id == PARTITION_DEFAULT) { /* Special behavior for default partition */ - if (!name[0]) { - /* Removing of default partition is not allowed */ - ocf_cache_log(cache, log_info, - "Cannot remove unclassified IO class, " - "id: %u [ ERROR ]\n", part_id); - - OCF_METADATA_UNLOCK_WR(); - - return 0; - } - /* Try set partition size */ if (_ocf_mngt_set_partition_size(cache, part_id, min, max)) { ocf_cache_log(cache, log_info, "Setting IO class size, id: %u, name: '%s' " "[ ERROR ]\n", part_id, dest_part->config->name); - OCF_METADATA_UNLOCK_WR(); return -OCF_ERR_INVAL; } ocf_part_set_prio(cache, dest_part, prio); - ocf_part_sort(cache); dest_part->config->cache_mode = cache_mode; ocf_cache_log(cache, log_info, "Updating Unclassified IO class, id: " "%u [ OK ]\n", part_id); - OCF_METADATA_UNLOCK_WR(); - return 0; } - if (name[0]) { - /* Setting */ - result = env_strncpy(dest_part->config->name, sizeof(dest_part->config->name), name, - sizeof(dest_part->config->name)); - if (result) { - OCF_METADATA_UNLOCK_WR(); - return result; - } + /* Setting */ + result = env_strncpy(dest_part->config->name, + sizeof(dest_part->config->name), name, + sizeof(dest_part->config->name)); + if (result) + return result; - /* Try set partition size */ - if (_ocf_mngt_set_partition_size(cache, part_id, min, max)) { - ocf_cache_log(cache, log_info, - "Setting IO class size, id: %u, name: '%s' " - "[ ERROR ]\n", part_id, dest_part->config->name); - OCF_METADATA_UNLOCK_WR(); - return -OCF_ERR_INVAL; - } + /* Try set partition size */ + if (_ocf_mngt_set_partition_size(cache, part_id, min, max)) { + ocf_cache_log(cache, log_info, + "Setting IO class size, id: %u, name: '%s' " + "[ ERROR ]\n", part_id, dest_part->config->name); + return -OCF_ERR_INVAL; + } - if (ocf_part_is_valid(dest_part)) { - /* Updating existing */ - ocf_cache_log(cache, log_info, "Updating existing IO " - "class, id: %u, name: '%s' [ OK ]\n", - part_id, dest_part->config->name); + if (ocf_part_is_valid(dest_part)) { + /* Updating existing */ + ocf_cache_log(cache, log_info, "Updating existing IO " + "class, id: %u, name: '%s' [ OK ]\n", + part_id, dest_part->config->name); + } else { + /* Adding new */ + ocf_part_set_valid(cache, part_id, true); - } else { - /* Adding new */ - ocf_part_set_valid(cache, part_id, true); + ocf_cache_log(cache, log_info, "Adding new IO class, " + "id: %u, name: '%s' [ OK ]\n", part_id, + dest_part->config->name); + } - ocf_cache_log(cache, log_info, "Adding new IO class, " - "id: %u, name: '%s' [ OK ]\n", part_id, - dest_part->config->name); - } + ocf_part_set_prio(cache, dest_part, prio); + dest_part->config->cache_mode = cache_mode; - ocf_part_set_prio(cache, dest_part, prio); - dest_part->config->cache_mode = cache_mode; + return result; +} + +static int _ocf_mngt_io_class_remove(ocf_cache_t cache, + const struct ocf_mngt_io_class_config *cfg) +{ + struct ocf_user_part *dest_part; + ocf_part_id_t part_id = cfg->class_id; + int result; + + dest_part = &cache->user_parts[part_id]; + + OCF_CHECK_NULL(cache->device); + + if (part_id == PARTITION_DEFAULT) { + ocf_cache_log(cache, log_info, + "Cannot remove unclassified IO class, " + "id: %u [ ERROR ]\n", part_id); + return 0; + } + + if (ocf_part_is_valid(dest_part)) { result = 0; + ocf_part_set_valid(cache, part_id, false); + + ocf_cache_log(cache, log_info, + "Removing IO class, id: %u [ %s ]\n", + part_id, result ? "ERROR" : "OK"); + } else { - /* Clearing */ - - if (ocf_part_is_valid(dest_part)) { - /* Removing */ - - result = 0; - - ocf_part_set_valid(cache, part_id, false); - - ocf_cache_log(cache, log_info, - "Removing IO class, id: %u [ %s ]\n", - part_id, result ? "ERROR" : "OK"); - - } else { - /* Does not exist */ - result = -OCF_ERR_IO_CLASS_NOT_EXIST; - } + /* Does not exist */ + result = -OCF_ERR_IO_CLASS_NOT_EXIST; } - ocf_part_sort(cache); + return result; +} - OCF_METADATA_UNLOCK_WR(); +static int _ocf_mngt_io_class_edit(ocf_cache_t cache, + const struct ocf_mngt_io_class_config *cfg) +{ + int result; + + if (cfg->name) { + result = _ocf_mngt_io_class_configure(cache, cfg); + } else { + result = _ocf_mngt_io_class_remove(cache, cfg); + } return result; } @@ -226,6 +231,10 @@ static int _ocf_mngt_io_class_validate_cfg(ocf_cache_t cache, if (cfg->class_id >= OCF_IO_CLASS_MAX) return -OCF_ERR_INVAL; + /* Name set to null means particular io_class should be removed */ + if (!cfg->name) + return 0; + /* TODO(r.baldyga): ocf_cache_mode_max is allowed for compatibility * with OCF 3.1 kernel adapter (upgrade in flight) and casadm. * Forbid ocf_cache_mode_max after fixing these problems. @@ -250,17 +259,60 @@ static int _ocf_mngt_io_class_validate_cfg(ocf_cache_t cache, return 0; } -int ocf_mngt_io_class_configure(ocf_cache_t cache, - const struct ocf_mngt_io_class_config *cfg) +int ocf_mngt_cache_io_classes_configure(ocf_cache_t cache, + const struct ocf_mngt_io_classes_config *cfg) { + struct ocf_user_part *old_config; int result; + int i; OCF_CHECK_NULL(cache); + OCF_CHECK_NULL(cfg); - result = _ocf_mngt_io_class_validate_cfg(cache, cfg); - if (result) + for (i = 0; i < OCF_IO_CLASS_MAX; i++) { + result = _ocf_mngt_io_class_validate_cfg(cache, &cfg->config[i]); + if (result) + return result; + } + + old_config = env_malloc(sizeof(cache->user_parts), ENV_MEM_NORMAL); + if (!old_config) + return -OCF_ERR_NO_MEM; + + OCF_METADATA_LOCK_WR(); + + result = env_memcpy(old_config, sizeof(&cache->user_parts), + cache->user_parts, sizeof(&cache->user_parts)); + if (result) { + env_free(old_config); return result; + } - return _ocf_mngt_io_class_configure(cache, cfg); + for (i = 0; i < OCF_IO_CLASS_MAX; i++) { + result = _ocf_mngt_io_class_edit(cache, &cfg->config[i]); + if (result && result != -OCF_ERR_IO_CLASS_NOT_EXIST) { + ocf_cache_log(cache, log_err, + "Failed to set new io class config\n"); + goto err; + } + + result = 0; + } + + ocf_part_sort(cache); + + if (ocf_metadata_flush_superblock(cache)) { + ocf_cache_log(cache, log_err, "Failed to store new io class config\n"); + result = -OCF_ERR_WRITE_CACHE; + } + +err: + if (result) { + ENV_BUG_ON(env_memcpy(cache->user_parts, sizeof(&cache->user_parts), + old_config, sizeof(&cache->user_parts))); + } + + OCF_METADATA_UNLOCK_WR(); + + return result; } - diff --git a/src/ocf_cache_priv.h b/src/ocf_cache_priv.h index 7422042..626cda2 100644 --- a/src/ocf_cache_priv.h +++ b/src/ocf_cache_priv.h @@ -195,8 +195,8 @@ struct ocf_cache { env_atomic flush_in_progress; - /* Interpreted as a counter rather than a flag */ - env_atomic dirty_rq_barrier; + /* Prevent dirty requests. May be incremented recursively */ + env_atomic flush_started; /* 1 if cache device attached, 0 otherwise */ env_atomic attached; diff --git a/src/ocf_core.c b/src/ocf_core.c index 45e1b98..663d850 100644 --- a/src/ocf_core.c +++ b/src/ocf_core.c @@ -653,14 +653,14 @@ static ctx_data_t *ocf_core_io_get_data(struct ocf_io *io) return core_io->data; } -const struct ocf_data_obj_properties ocf_core_data_obj_properties = { +const struct ocf_data_obj_properties ocf_core_data_obj_properties = { .name = "OCF Core", .io_priv_size = sizeof(struct ocf_core_io), .dobj_priv_size = sizeof(struct ocf_core_dobj), - .caps = { + .caps = { .atomic_writes = 0, }, - .ops = { + .ops = { .submit_io = ocf_core_data_obj_submit_io, .submit_flush = ocf_core_data_obj_submit_flush, .submit_discard = ocf_core_data_obj_submit_discard, diff --git a/src/ocf_io_class.c b/src/ocf_io_class.c index b3677ef..6ded6d1 100644 --- a/src/ocf_io_class.c +++ b/src/ocf_io_class.c @@ -9,7 +9,7 @@ #include "engine/cache_engine.h" #include "utils/utils_part.h" -int ocf_io_class_get_info(ocf_cache_t cache, uint32_t io_class, +int ocf_cache_io_class_get_info(ocf_cache_t cache, uint32_t io_class, struct ocf_io_class_info *info) { ocf_part_id_t part_id = io_class; diff --git a/src/ocf_stats.c b/src/ocf_stats.c index 2627a3f..5c8f6f2 100644 --- a/src/ocf_stats.c +++ b/src/ocf_stats.c @@ -9,6 +9,7 @@ #include "engine/cache_engine.h" #include "utils/utils_part.h" #include "utils/utils_cache_line.h" +#include "utils/utils_core.h" #ifdef OCF_DEBUG_STATS static void ocf_stats_debug_init(struct ocf_counters_debug *stats) @@ -160,39 +161,30 @@ static void copy_debug_stats(struct ocf_stats_core_debug *dest, } #endif -int ocf_io_class_get_stats(ocf_core_t core, uint32_t io_class, +int ocf_core_io_class_get_stats(ocf_core_t core, ocf_part_id_t part_id, struct ocf_stats_io_class *stats) { - ocf_part_id_t part_id = io_class; + ocf_cache_t cache; uint32_t i; uint32_t cache_occupancy_total = 0; struct ocf_counters_part *part_stat; ocf_core_id_t core_id; - ocf_cache_t cache; OCF_CHECK_NULL(core); + OCF_CHECK_NULL(stats); + + if (part_id < OCF_IO_CLASS_ID_MIN || part_id > OCF_IO_CLASS_ID_MAX) + return -OCF_ERR_INVAL; core_id = ocf_core_get_id(core); cache = ocf_core_get_cache(core); - if (!stats) - return -OCF_ERR_INVAL; - - if (io_class >= OCF_IO_CLASS_MAX) - return -OCF_ERR_INVAL; - - if (!ocf_part_is_valid(&cache->user_parts[part_id])) { - /* Partition does not exist */ + if (!ocf_part_is_valid(&cache->user_parts[part_id])) return -OCF_ERR_IO_CLASS_NOT_EXIST; - } - for (i = 0; i != OCF_CORE_MAX; ++i) { - if (!env_bit_test(i, cache->conf_meta-> - valid_object_bitmap)) { - continue; - } - cache_occupancy_total += env_atomic_read(&cache-> - core_runtime_meta[i].cached_clines); + for_each_core(cache, i) { + cache_occupancy_total += env_atomic_read( + &cache->core_runtime_meta[i].cached_clines); } part_stat = &core->counters->part_counters[part_id]; diff --git a/src/utils/utils_core.h b/src/utils/utils_core.h new file mode 100644 index 0000000..32ef195 --- /dev/null +++ b/src/utils/utils_core.h @@ -0,0 +1,13 @@ +/* + * Copyright(c) 2012-2018 Intel Corporation + * SPDX-License-Identifier: BSD-3-Clause-Clear + */ + +#ifndef __UTILS_CORE_H__ +#define __UTILS_CORE_H__ + +#define for_each_core(cache, iter) \ + for (iter = 0; iter < OCF_CORE_MAX; iter++) \ + if (cache->core_conf_meta[iter].added) + +#endif /* __UTILS_CORE_H__ */ diff --git a/tests/unit/tests/mngt/ocf_mngt_io_class.c/ocf_mngt_io_class.c b/tests/unit/tests/mngt/ocf_mngt_io_class.c/ocf_mngt_io_class.c new file mode 100644 index 0000000..ea27a0b --- /dev/null +++ b/tests/unit/tests/mngt/ocf_mngt_io_class.c/ocf_mngt_io_class.c @@ -0,0 +1,274 @@ +/* + * Copyright(c) 2012-2018 Intel Corporation + * SPDX-License-Identifier: BSD-3-Clause-Clear + */ + +/* + * src/mngt/ocf_mngt_io_class.c + * ocf_mngt_cache_io_classes_configure + * + * INSERT HERE LIST OF FUNCTIONS YOU WANT TO LEAVE + * ONE FUNCTION PER LINE + * _ocf_mngt_io_class_edit + * _ocf_mngt_io_class_configure + * _ocf_mngt_io_class_remove + * + */ + +#undef static + +#undef inline + + +#include +#include +#include +#include +#include "print_desc.h" + +#include "ocf/ocf.h" +#include "ocf_mngt_common.h" +#include "../ocf_priv.h" +#include "../metadata/metadata.h" +#include "../engine/cache_engine.h" +#include "../utils/utils_part.h" +#include "../eviction/ops.h" +#include "ocf_env.h" + +/* Mocks reqired for compilation */ +int __wrap_ocf_log_raw(const struct ocf_logger *logger, ocf_logger_lvl_t lvl, + const char *fmt, ...) +{ +} + +ocf_ctx_t __wrap_ocf_cache_get_ctx(ocf_cache_t cache) +{ +} + +char *__wrap_ocf_cache_get_name(ocf_cache_t cache) +{ +} + +int __wrap_ocf_mngt_cache_lock(ocf_cache_t cache) +{ + return 0; +} + +void __wrap_ocf_mngt_cache_unlock(ocf_cache_t cache) +{ +} + +void __wrap_ocf_metadata_lock(struct ocf_cache *cache, int rw) +{ +} + +void __wrap_ocf_metadata_unlock(struct ocf_cache *cache, int rw) +{ +} + +/* Functions mocked for testing purposes */ +bool __wrap_ocf_part_is_added(struct ocf_user_part *part) +{ + function_called(); + return mock(); +} + +int __wrap__ocf_mngt_set_partition_size(struct ocf_cache *cache, + ocf_part_id_t part_id, uint32_t min, uint32_t max) +{ + function_called(); + return mock(); +} + +void __wrap_ocf_part_set_prio(struct ocf_cache *cache, + struct ocf_user_part *part, int16_t prio) +{ + function_called(); +} + +bool __wrap_ocf_part_is_valid(struct ocf_user_part *part) +{ + function_called(); + return mock(); +} + + +void __wrap_ocf_part_set_valid(struct ocf_cache *cache, ocf_part_id_t id, + bool valid) +{ + function_called(); + check_expected(valid); + check_expected(id); +} + +int __wrap__ocf_mngt_io_class_validate_cfg(ocf_cache_t cache, + const struct ocf_mngt_io_class_config *cfg) +{ + function_called(); + return mock(); +} + +void __wrap_ocf_part_sort(struct ocf_cache *cache) +{ + function_called(); +} + +int __wrap_ocf_metadata_flush_superblock(struct ocf_cache *cache) +{ + function_called(); + return mock(); +} + +/* Helper function for test prepration */ +static inline void setup_valid_config(struct ocf_mngt_io_class_config *cfg, + bool remove) +{ + int i; + for (i = 0; i < OCF_IO_CLASS_MAX; i++) { + cfg[i].class_id = i; + cfg[i].name = remove ? NULL : "test_io_class_name" ; + cfg[i].prio = i; + cfg[i].cache_mode = ocf_cache_mode_pt; + cfg[i].min_size = 2*i; + cfg[i].max_size = 20*i; + } +} + +static void ocf_mngt_io_classes_configure_test03(void **state) +{ + struct ocf_cache cache = {0}; + struct ocf_mngt_io_classes_config cfg = {0}; + int result, i; + + for (i = 0; i < OCF_IO_CLASS_MAX; i++) { + cache.user_parts[i].config = + test_malloc(sizeof(struct ocf_user_part_config)); + } + cache.device = 1; + + setup_valid_config(cfg.config, true); + + print_test_description("Remove all io classes"); + + for (i = 0; i < OCF_IO_CLASS_MAX; i++) { + expect_function_call(__wrap__ocf_mngt_io_class_validate_cfg); + will_return(__wrap__ocf_mngt_io_class_validate_cfg, 0); + } + + /* Removing default io_class is not allowed */ + for (i = 1; i < OCF_IO_CLASS_MAX; i++) { + expect_function_call(__wrap_ocf_part_is_valid); + will_return(__wrap_ocf_part_is_valid, 1); + + expect_function_call(__wrap_ocf_part_set_valid); + /* Test assumes default partition has id equal 0 */ + expect_in_range(__wrap_ocf_part_set_valid, id, OCF_IO_CLASS_ID_MIN + 1, + OCF_IO_CLASS_ID_MAX); + expect_value(__wrap_ocf_part_set_valid, valid, false); + } + + expect_function_call(__wrap_ocf_part_sort); + + expect_function_call(__wrap_ocf_metadata_flush_superblock); + will_return(__wrap_ocf_metadata_flush_superblock, 0); + + result = ocf_mngt_cache_io_classes_configure(&cache, &cfg); + + assert_int_equal(result, 0); + + for (i = 0; i < OCF_IO_CLASS_MAX; i++) + test_free(cache.user_parts[i].config); +} + +static void ocf_mngt_io_classes_configure_test02(void **state) +{ + struct ocf_cache cache = {0}; + struct ocf_mngt_io_classes_config cfg = {0}; + int result, i; + + for (i = 0; i < OCF_IO_CLASS_MAX; i++) { + cache.user_parts[i].config = + test_malloc(sizeof(struct ocf_user_part_config)); + } + cache.device = 1; + + setup_valid_config(cfg.config, false); + + print_test_description("Configure all possible io classes"); + + for (i = 0; i < OCF_IO_CLASS_MAX; i++) { + expect_function_call(__wrap__ocf_mngt_io_class_validate_cfg); + will_return(__wrap__ocf_mngt_io_class_validate_cfg, 0); + } + + /* Configure default io_class */ + expect_function_call(__wrap_ocf_part_is_added); + will_return(__wrap_ocf_part_is_added, 1); + + expect_function_call(__wrap__ocf_mngt_set_partition_size); + will_return(__wrap__ocf_mngt_set_partition_size, 0); + + expect_function_call(__wrap_ocf_part_set_prio); + + /* Configure custom io_classes */ + for (i = 1; i < OCF_IO_CLASS_MAX; i++) { + expect_function_call(__wrap_ocf_part_is_added); + will_return(__wrap_ocf_part_is_added, 1); + + expect_function_call(__wrap__ocf_mngt_set_partition_size); + will_return(__wrap__ocf_mngt_set_partition_size, 0); + + expect_function_call(__wrap_ocf_part_is_valid); + will_return(__wrap_ocf_part_is_valid, 0); + + expect_function_call(__wrap_ocf_part_set_valid); + expect_in_range(__wrap_ocf_part_set_valid, id, OCF_IO_CLASS_ID_MIN, + OCF_IO_CLASS_ID_MAX); + expect_value(__wrap_ocf_part_set_valid, valid, true); + + expect_function_call(__wrap_ocf_part_set_prio); + } + + expect_function_call(__wrap_ocf_part_sort); + + expect_function_call(__wrap_ocf_metadata_flush_superblock); + will_return(__wrap_ocf_metadata_flush_superblock, 0); + + result = ocf_mngt_cache_io_classes_configure(&cache, &cfg); + + assert_int_equal(result, 0); + + for (i = 0; i < OCF_IO_CLASS_MAX; i++) + test_free(cache.user_parts[i].config); +} + +static void ocf_mngt_io_classes_configure_test01(void **state) +{ + struct ocf_cache cache; + struct ocf_mngt_io_classes_config cfg[OCF_IO_CLASS_MAX]; + int error_code = -OCF_ERR_INVAL; + int result; + + print_test_description("Invalid config - " + "termination with error"); + + expect_function_call(__wrap__ocf_mngt_io_class_validate_cfg); + will_return(__wrap__ocf_mngt_io_class_validate_cfg, error_code); + + result = ocf_mngt_cache_io_classes_configure(&cache, &cfg); + + assert_int_equal(result, error_code); +} + +int main(void) +{ + const struct CMUnitTest tests[] = { + cmocka_unit_test(ocf_mngt_io_classes_configure_test01), + cmocka_unit_test(ocf_mngt_io_classes_configure_test02), + cmocka_unit_test(ocf_mngt_io_classes_configure_test03) + }; + + print_message("Unit test of src/mngt/ocf_mngt_io_class.c"); + + return cmocka_run_group_tests(tests, NULL, NULL); +}