ocf/src/mngt/ocf_mngt_io_class.c
Robert Baldyga a8e1ce8cc5 Initial commit
Signed-off-by: Robert Baldyga <robert.baldyga@intel.com>
2018-11-29 15:14:21 +01:00

274 lines
6.5 KiB
C

/*
* Copyright(c) 2012-2018 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;
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;
}
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);
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 (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;
}
/* 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;
}
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);
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;
result = 0;
} 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;
}
}
ocf_part_sort(cache);
OCF_METADATA_UNLOCK_WR();
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;
/* 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.
*/
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_io_class_configure(ocf_cache_t cache,
const struct ocf_mngt_io_class_config *cfg)
{
int result;
OCF_CHECK_NULL(cache);
result = _ocf_mngt_io_class_validate_cfg(cache, cfg);
if (result)
return result;
result = ocf_mngt_cache_lock(cache);
if (result)
return result;
result = _ocf_mngt_io_class_configure(cache, cfg);
ocf_mngt_cache_unlock(cache);
return 0;
}