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);
+}