Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions inc/ocf_mngt.h
Original file line number Diff line number Diff line change
Expand Up @@ -1127,6 +1127,16 @@ struct ocf_mngt_io_class_config {
* @brief IO class eviction priority
*/
int16_t prio;

/**
* @brief Move cache lines currently assigned to this IO class
* to the unclassified IO class
*
* Applies both to an IO class being updated and to one being removed
* (name set to NULL). Lines will be reclassified on next access.
* Ignored for the unclassified and prefetch IO classes.
*/
bool repart;
};

struct ocf_mngt_io_classes_config {
Expand Down
23 changes: 23 additions & 0 deletions src/mngt/ocf_mngt_io_class.c
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,7 @@ 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;
ocf_part_id_t part_id;
int result;
int i;

Expand Down Expand Up @@ -318,6 +319,28 @@ int ocf_mngt_cache_io_classes_configure(ocf_cache_t cache,
}
}

/* Repartitioning can't be rolled back, so do it only once the whole
* configuration has been applied successfully.
*/
for (i = 0; i < OCF_USER_IO_CLASS_MAX; i++) {
part_id = cfg->config[i].class_id;

/* Classification rules of the default IO classes can't change,
* so their cache lines can't become misclassified.
*/
if (!cfg->config[i].repart ||
part_id == OCF_IO_CLASS_UNCLASSIFIED ||
part_id == OCF_IO_CLASS_PREFETCH) {
continue;
}

ocf_user_part_move_all(cache, part_id,
OCF_IO_CLASS_UNCLASSIFIED);
ocf_cache_log(cache, log_info, "Moved cache lines of IO class, "
"id: %u to the unclassified IO class\n",
part_id);
}

ocf_user_part_sort(cache);

out_edit:
Expand Down
47 changes: 47 additions & 0 deletions src/ocf_lru.c
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,34 @@ static void add_lru_head(ocf_cache_t cache, struct ocf_lru_list *list,
balance_lru_list(cache, list);
}

/* Adds the given collision_index to the _tail_ of the LRU list as cold */
static void add_lru_tail(ocf_cache_t cache, struct ocf_lru_list *list,
ocf_cache_line_t collision_index)
{
struct ocf_lru_meta *node;

ENV_BUG_ON(collision_index == end_marker);

node = ocf_metadata_get_lru(cache, collision_index);
node->hot = false;
node->next = end_marker;

if (!list->num_nodes) {
list->head = collision_index;
node->prev = end_marker;
} else {
ENV_BUG_ON(list->tail == end_marker);

node->prev = list->tail;
ocf_metadata_get_lru(cache, list->tail)->next = collision_index;
}

list->tail = collision_index;
++list->num_nodes;

balance_lru_list(cache, list);
}

/* update list global pointers and node neighbours to reflect removal */
static inline void remove_update_ptrs(ocf_cache_t cache,
struct ocf_lru_list *list, ocf_cache_line_t collision_index,
Expand Down Expand Up @@ -308,6 +336,25 @@ void ocf_lru_repart(ocf_cache_t cache, ocf_cache_line_t cline,
OCF_METADATA_LRU_UNLOCK(lru_list);
}

/* the caller must hold exclusive metadata access */
void ocf_lru_repart_cold(ocf_cache_t cache, ocf_cache_line_t cline,
struct ocf_part *src_part, struct ocf_part *dst_part)
{
uint32_t lru_list = OCF_LRU_GET_LIST_INDEX(cline);
struct ocf_lru_list *src_list, *dst_list;
bool clean;

clean = !metadata_test_dirty(cache, cline);
src_list = ocf_lru_get_list(src_part, lru_list, clean);
dst_list = ocf_lru_get_list(dst_part, lru_list, clean);

ocf_lru_remove_locked(cache, src_list, cline);
add_lru_tail(cache, dst_list, cline);
ocf_metadata_set_partition_id(cache, cline, dst_part->id);
env_atomic_dec(&src_part->runtime->curr_size);
env_atomic_inc(&dst_part->runtime->curr_size);
}

/* the caller must hold the metadata lock */
void ocf_lru_rm_cline(ocf_cache_t cache, ocf_cache_line_t cline)
{
Expand Down
2 changes: 2 additions & 0 deletions src/ocf_lru.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ void ocf_lru_clean(ocf_cache_t cache, struct ocf_user_part *user_part,
ocf_queue_t io_queue, uint32_t count);
void ocf_lru_repart(ocf_cache_t cache, ocf_cache_line_t cline,
struct ocf_part *src_upart, struct ocf_part *dst_upart);
void ocf_lru_repart_cold(ocf_cache_t cache, ocf_cache_line_t cline,
struct ocf_part *src_part, struct ocf_part *dst_part);
void ocf_lru_add_free(ocf_cache_t cache, ocf_cache_line_t cline);
uint32_t ocf_lru_num_free(ocf_cache_t cache);
struct ocf_lru_list *ocf_lru_get_list(struct ocf_part *part,
Expand Down
124 changes: 87 additions & 37 deletions src/utils/utils_user_part.c
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,54 @@ void ocf_user_part_init(struct ocf_cache *cache)
cache->user_parts[i].part.id = i;
}

static void _ocf_user_part_move_line(struct ocf_cache *cache,
struct ocf_core *core, ocf_cache_line_t line,
ocf_part_id_t id_old, ocf_part_id_t id_new, bool cold)
{
struct ocf_part *src_part = &cache->user_parts[id_old].part;
struct ocf_part *dst_part = &cache->user_parts[id_new].part;

if (metadata_test_dirty(cache, line)) {
/*
* Remove cline from cleaning - this if for ioclass
* oriented cleaning policy (e.g. ALRU).
* TODO: Consider adding update_cache_line() ops
* to cleaning policy to let policies handle this.
*/
ocf_cleaning_purge_cache_block(cache, line);
}

if (cold)
ocf_lru_repart_cold(cache, line, src_part, dst_part);
else
ocf_lru_repart(cache, line, src_part, dst_part);

/* Check if cache line is dirty. If yes then need to change
* cleaning policy and update partition dirty clines
* statistics.
*/
if (metadata_test_dirty(cache, line)) {
/* Add cline back to cleaning policy */
ocf_cleaning_set_hot_cache_line(cache, line);

env_atomic_inc(&core->runtime_meta->
part_counters[id_new].dirty_clines);
env_atomic_dec(&core->runtime_meta->
part_counters[id_old].dirty_clines);
}

/* Only valid cache lines are accounted. A line that is mapped,
* but not valid yet, gets accounted to its current partition
* once it becomes valid.
*/
if (metadata_test_valid_any(cache, line)) {
env_atomic_inc(&core->runtime_meta->
part_counters[id_new].cached_clines);
env_atomic_dec(&core->runtime_meta->
part_counters[id_old].cached_clines);
}
}

void ocf_user_part_move(struct ocf_request *req)
{
struct ocf_cache *cache = req->cache;
Expand Down Expand Up @@ -130,45 +178,47 @@ void ocf_user_part_move(struct ocf_request *req)
continue;
}

if (metadata_test_dirty(cache, line)) {
/*
* Remove cline from cleaning - this if for ioclass
* oriented cleaning policy (e.g. ALRU).
* TODO: Consider adding update_cache_line() ops
* to cleaning policy to let policies handle this.
*/
ocf_cleaning_purge_cache_block(cache, line);
}

ocf_lru_repart(cache, line, &cache->user_parts[id_old].part,
&cache->user_parts[id_new].part);

/* Check if cache line is dirty. If yes then need to change
* cleaning policy and update partition dirty clines
* statistics.
*/
if (metadata_test_dirty(cache, line)) {
/* Add cline back to cleaning policy */
ocf_cleaning_set_hot_cache_line(cache, line);

env_atomic_inc(&req->core->runtime_meta->
part_counters[id_new].dirty_clines);
env_atomic_dec(&req->core->runtime_meta->
part_counters[id_old].dirty_clines);
}
_ocf_user_part_move_line(cache, req->core, line,
id_old, id_new, false);
}
}

/* Only valid cache lines are accounted. A line that is mapped,
* but not valid yet, gets accounted to its current partition
* once it becomes valid.
*/
if (metadata_test_valid_any(cache, line)) {
env_atomic_inc(&req->core->runtime_meta->
part_counters[id_new].cached_clines);
env_atomic_dec(&req->core->runtime_meta->
part_counters[id_old].cached_clines);
/*
* Move all cache lines of user partition id_old to user partition id_new.
* Lines are inserted at the cold end of destination LRU lists, preserving
* their relative order. Cache line locks are not taken, so the caller must
* hold exclusive metadata access to keep out any concurrent metadata update.
*/
void ocf_user_part_move_all(struct ocf_cache *cache, ocf_part_id_t id_old,
ocf_part_id_t id_new)
{
struct ocf_part *src_part = &cache->user_parts[id_old].part;
struct ocf_lru_list *list;
struct ocf_core *core;
ocf_cache_line_t line;
ocf_core_id_t core_id;
uint32_t lru_idx;
uint32_t step = 0;
int clean;

ENV_BUG_ON(id_old >= OCF_USER_IO_CLASS_MAX ||
id_new >= OCF_USER_IO_CLASS_MAX);

if (id_old == id_new)
return;

for (lru_idx = 0; lru_idx < OCF_NUM_LRU_LISTS; lru_idx++) {
for (clean = 0; clean <= 1; clean++) {
list = ocf_lru_get_list(src_part, lru_idx, clean);
while (list->num_nodes) {
line = list->head;
core_id = ocf_metadata_get_core_id(cache, line);
core = ocf_cache_get_core(cache, core_id);
_ocf_user_part_move_line(cache, core, line,
id_old, id_new, true);
OCF_COND_RESCHED_DEFAULT(step);
}
}

/* DONE */
}
}

Expand Down
3 changes: 3 additions & 0 deletions src/utils/utils_user_part.h
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,9 @@ static inline uint32_t ocf_user_part_get_max_size(ocf_cache_t cache,

void ocf_user_part_move(struct ocf_request *req);

void ocf_user_part_move_all(struct ocf_cache *cache, ocf_part_id_t id_old,
ocf_part_id_t id_new);

#define for_each_user_part(cache, user_part, id) \
for_each_lst_entry(&cache->user_part_list, user_part, id, \
struct ocf_user_part, lst_valid)
Expand Down
9 changes: 8 additions & 1 deletion tests/functional/pyocf/rio.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#
# Copyright(c) 2022 Intel Corporation
# Copyright(c) 2024 Huawei Technologies
# Copyright(c) 2026 Unvertical
# SPDX-License-Identifier: BSD-3-Clause
#

Expand Down Expand Up @@ -72,6 +73,7 @@ class JobSpec:
time_based: bool = False
time: timedelta = None
continue_on_error: bool = False
io_class: int = 0

def merge(self, other):
# TODO implement
Expand Down Expand Up @@ -155,7 +157,8 @@ def run(self):

data = Data(self.jobspec.bs) # TODO pattern and verify
io = self.jobspec.target.new_io(
self.queue, next(iogen), self.jobspec.bs, iodir, 0, 0,
self.queue, next(iogen), self.jobspec.bs, iodir,
self.jobspec.io_class, 0,
)
io.set_data(data)
io.callback = self.get_io_cb()
Expand Down Expand Up @@ -248,6 +251,10 @@ def time(self, time: timedelta):
self.global_jobspec.time = time
return self

def io_class(self, io_class: int):
self.global_jobspec.io_class = io_class
return self

def continue_on_error(self):
self.global_jobspec.continue_on_error = True
return self
Expand Down
42 changes: 30 additions & 12 deletions tests/functional/pyocf/types/cache.py
Original file line number Diff line number Diff line change
Expand Up @@ -612,14 +612,7 @@ def add_partition(
if status:
raise OcfError("Error adding partition to cache", status)

def configure_partition(
self,
part_id: int,
name: str,
max_size: int,
priority: int,
cache_mode=CACHE_MODE_NONE,
):
def _get_ioclasses_config(self):
ioclasses_info = IoClassesInfo()

self.read_lock()
Expand All @@ -641,11 +634,9 @@ def configure_partition(

self.read_unlock()

ioclasses_info._config[part_id]._name = name.encode("utf-8")
ioclasses_info._config[part_id]._cache_mode = int(cache_mode)
ioclasses_info._config[part_id]._priority = priority
ioclasses_info._config[part_id]._max_size = max_size
return ioclasses_info

def _set_ioclasses_config(self, ioclasses_info):
self.write_lock()

status = self.owner.lib.ocf_mngt_cache_io_classes_configure(
Expand All @@ -657,6 +648,33 @@ def configure_partition(
if status:
raise OcfError("Error adding partition to cache", status)

def configure_partition(
self,
part_id: int,
name: str,
max_size: int,
priority: int,
cache_mode=CACHE_MODE_NONE,
repart: bool = False,
):
ioclasses_info = self._get_ioclasses_config()

ioclasses_info._config[part_id]._name = name.encode("utf-8")
ioclasses_info._config[part_id]._cache_mode = int(cache_mode)
ioclasses_info._config[part_id]._priority = priority
ioclasses_info._config[part_id]._max_size = max_size
ioclasses_info._config[part_id]._repart = repart

self._set_ioclasses_config(ioclasses_info)

def remove_partition(self, part_id: int, repart: bool = False):
ioclasses_info = self._get_ioclasses_config()

ioclasses_info._config[part_id]._name = None
ioclasses_info._config[part_id]._repart = repart

self._set_ioclasses_config(ioclasses_info)

def alloc_device_config(self, device, perform_test=True):
if not device.handle:
uuid = Uuid(
Expand Down
Loading
Loading