
When setting ioclass, print info about it's max size Signed-off-by: Michal Mielewczyk <michal.mielewczyk@intel.com>
310 lines
7.5 KiB
C
310 lines
7.5 KiB
C
/*
|
|
* Copyright(c) 2012-2020 Intel Corporation
|
|
* SPDX-License-Identifier: BSD-3-Clause-Clear
|
|
*/
|
|
|
|
#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"
|
|
|
|
static uint64_t _ocf_mngt_count_parts_min_size(struct ocf_cache *cache)
|
|
{
|
|
struct ocf_user_part *part;
|
|
ocf_part_id_t part_id;
|
|
uint64_t count = 0;
|
|
|
|
for_each_part(cache, part, part_id) {
|
|
if (ocf_part_is_valid(part))
|
|
count += part->config->min_size;
|
|
}
|
|
|
|
return count;
|
|
}
|
|
|
|
int ocf_mngt_add_partition_to_cache(struct ocf_cache *cache,
|
|
ocf_part_id_t part_id, const char *name, uint32_t min_size,
|
|
uint32_t max_size, uint8_t priority, bool valid)
|
|
{
|
|
uint32_t size;
|
|
struct ocf_lst_entry *iter;
|
|
uint32_t iter_id;
|
|
|
|
if (!name)
|
|
return -OCF_ERR_INVAL;
|
|
|
|
if (part_id >= OCF_IO_CLASS_MAX)
|
|
return -OCF_ERR_INVAL;
|
|
|
|
if (cache->user_parts[part_id].config->flags.valid)
|
|
return -OCF_ERR_INVAL;
|
|
|
|
if (max_size > PARTITION_SIZE_MAX)
|
|
return -OCF_ERR_INVAL;
|
|
|
|
if (env_strnlen(name, OCF_IO_CLASS_NAME_MAX) >=
|
|
OCF_IO_CLASS_NAME_MAX) {
|
|
ocf_cache_log(cache, log_info,
|
|
"Name of the partition is too long\n");
|
|
return -OCF_ERR_INVAL;
|
|
}
|
|
|
|
for_each_lst(&cache->lst_part, iter, iter_id) {
|
|
if (iter_id == part_id) {
|
|
ocf_cache_log(cache, log_err,
|
|
"Part with id %hu already exists\n", part_id);
|
|
return -OCF_ERR_INVAL;
|
|
}
|
|
}
|
|
|
|
size = sizeof(cache->user_parts[part_id].config->name);
|
|
if (env_strncpy(cache->user_parts[part_id].config->name, size, name, size))
|
|
return -OCF_ERR_INVAL;
|
|
|
|
cache->user_parts[part_id].config->min_size = min_size;
|
|
cache->user_parts[part_id].config->max_size = max_size;
|
|
cache->user_parts[part_id].config->priority = priority;
|
|
cache->user_parts[part_id].config->cache_mode = ocf_cache_mode_max;
|
|
|
|
ocf_part_set_valid(cache, part_id, valid);
|
|
ocf_lst_add(&cache->lst_part, part_id);
|
|
ocf_part_sort(cache);
|
|
|
|
cache->user_parts[part_id].config->flags.added = 1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int _ocf_mngt_set_partition_size(struct ocf_cache *cache,
|
|
ocf_part_id_t part_id, uint32_t min, uint32_t max)
|
|
{
|
|
struct ocf_user_part *part = &cache->user_parts[part_id];
|
|
|
|
if (min > max)
|
|
return -OCF_ERR_INVAL;
|
|
|
|
if (_ocf_mngt_count_parts_min_size(cache) + min
|
|
>= cache->device->collision_table_entries) {
|
|
/* Illegal configuration in which sum of all min_sizes exceeds
|
|
* cache size.
|
|
*/
|
|
return -OCF_ERR_INVAL;
|
|
}
|
|
|
|
if (max > PARTITION_SIZE_MAX)
|
|
max = PARTITION_SIZE_MAX;
|
|
|
|
part->config->min_size = min;
|
|
part->config->max_size = max;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int _ocf_mngt_io_class_configure(ocf_cache_t cache,
|
|
const struct ocf_mngt_io_class_config *cfg)
|
|
{
|
|
int result = -1;
|
|
struct ocf_user_part *dest_part;
|
|
|
|
ocf_part_id_t part_id = cfg->class_id;
|
|
const char *name = cfg->name;
|
|
int16_t prio = cfg->prio;
|
|
ocf_cache_mode_t cache_mode = cfg->cache_mode;
|
|
uint32_t min = cfg->min_size;
|
|
uint32_t max = cfg->max_size;
|
|
|
|
OCF_CHECK_NULL(cache->device);
|
|
|
|
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);
|
|
return -OCF_ERR_INVAL;
|
|
}
|
|
|
|
if (!name[0])
|
|
return -OCF_ERR_INVAL;
|
|
|
|
if (part_id == PARTITION_DEFAULT) {
|
|
/* Special behavior for default partition */
|
|
|
|
/* 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', max size: %u"
|
|
" [ ERROR ]\n", part_id, dest_part->config->name, max);
|
|
return -OCF_ERR_INVAL;
|
|
}
|
|
ocf_part_set_prio(cache, dest_part, prio);
|
|
dest_part->config->cache_mode = cache_mode;
|
|
|
|
ocf_cache_log(cache, log_info,
|
|
"Updating unclassified IO class, id: %u, name :'%s',"
|
|
"max size: %u [ OK ]\n",
|
|
part_id, dest_part->config->name, max);
|
|
return 0;
|
|
}
|
|
|
|
/* 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', max size %u"
|
|
"[ ERROR ]\n", part_id, dest_part->config->name, max);
|
|
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', max size %u [ OK ]\n",
|
|
part_id, dest_part->config->name, max);
|
|
} 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', max size %u [ OK ]\n", part_id,
|
|
dest_part->config->name, max);
|
|
}
|
|
|
|
ocf_part_set_prio(cache, dest_part, prio);
|
|
dest_part->config->cache_mode = cache_mode;
|
|
|
|
return result;
|
|
}
|
|
|
|
static void _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;
|
|
|
|
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;
|
|
}
|
|
|
|
if (!ocf_part_is_valid(dest_part)) {
|
|
/* Does not exist */
|
|
return;
|
|
}
|
|
|
|
|
|
ocf_part_set_valid(cache, part_id, false);
|
|
|
|
ocf_cache_log(cache, log_info,
|
|
"Removing IO class, id: %u [ OK ]\n", part_id);
|
|
}
|
|
|
|
static int _ocf_mngt_io_class_edit(ocf_cache_t cache,
|
|
const struct ocf_mngt_io_class_config *cfg)
|
|
{
|
|
int result = 0;
|
|
|
|
if (cfg->name)
|
|
result = _ocf_mngt_io_class_configure(cache, cfg);
|
|
else
|
|
_ocf_mngt_io_class_remove(cache, cfg);
|
|
|
|
return result;
|
|
}
|
|
|
|
static int _ocf_mngt_io_class_validate_cfg(ocf_cache_t cache,
|
|
const struct ocf_mngt_io_class_config *cfg)
|
|
{
|
|
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;
|
|
|
|
if (cfg->cache_mode < ocf_cache_mode_none ||
|
|
cfg->cache_mode > ocf_cache_mode_max) {
|
|
return -OCF_ERR_INVAL;
|
|
}
|
|
|
|
if (!ocf_part_is_name_valid(cfg->name)) {
|
|
ocf_cache_log(cache, log_info,
|
|
"The name of the partition is not valid\n");
|
|
return -OCF_ERR_INVAL;
|
|
}
|
|
|
|
if (!ocf_part_is_prio_valid(cfg->prio)) {
|
|
ocf_cache_log(cache, log_info,
|
|
"Invalid value of the partition priority\n");
|
|
return -OCF_ERR_INVAL;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
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);
|
|
|
|
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_start_exclusive_access(&cache->metadata.lock);
|
|
|
|
result = env_memcpy(old_config, sizeof(cache->user_parts),
|
|
cache->user_parts, sizeof(cache->user_parts));
|
|
if (result)
|
|
goto out_cpy;
|
|
|
|
for (i = 0; i < OCF_IO_CLASS_MAX; i++) {
|
|
result = _ocf_mngt_io_class_edit(cache, &cfg->config[i]);
|
|
if (result) {
|
|
ocf_cache_log(cache, log_err,
|
|
"Failed to set new io class config\n");
|
|
goto out_edit;
|
|
}
|
|
}
|
|
|
|
ocf_part_sort(cache);
|
|
|
|
out_edit:
|
|
if (result) {
|
|
ENV_BUG_ON(env_memcpy(cache->user_parts, sizeof(cache->user_parts),
|
|
old_config, sizeof(cache->user_parts)));
|
|
}
|
|
|
|
out_cpy:
|
|
ocf_metadata_end_exclusive_access(&cache->metadata.lock);
|
|
env_free(old_config);
|
|
|
|
return result;
|
|
}
|