
Management path does not benefit much from mpools, as number of requests allocated is very small. It's less restrictive (mngt_queue does not have single-CPU affinity) thus avoiding mpool usage in management path allows to introduce additional restrictions on mpool, leading to I/O performance improvement. Signed-off-by: Robert Baldyga <robert.baldyga@huawei.com> Signed-off-by: Michal Mielewczyk <michal.mielewczyk@huawei.com>
161 lines
3.7 KiB
C
161 lines
3.7 KiB
C
/*
|
|
* Copyright(c) 2012-2022 Intel Corporation
|
|
* Copyright(c) 2023-2024 Huawei Technologies
|
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
*/
|
|
|
|
#include "ocf/ocf.h"
|
|
#include "../engine/cache_engine.h"
|
|
#include "../engine/engine_common.h"
|
|
#include "../ocf_request.h"
|
|
#include "utils_parallelize.h"
|
|
|
|
#define OCF_PARALLELIZE_ALIGNMENT 64
|
|
|
|
struct ocf_parallelize {
|
|
ocf_cache_t cache;
|
|
ocf_parallelize_handle_t handle;
|
|
ocf_parallelize_finish_t finish;
|
|
void *priv;
|
|
|
|
unsigned shards_cnt;
|
|
env_atomic remaining;
|
|
env_atomic error;
|
|
|
|
struct ocf_request *reqs[];
|
|
};
|
|
|
|
static void _ocf_parallelize_finish(ocf_parallelize_t parallelize)
|
|
{
|
|
ocf_parallelize_finish_t finish;
|
|
void *priv;
|
|
int error;
|
|
|
|
if (env_atomic_dec_return(¶llelize->remaining))
|
|
return;
|
|
|
|
finish = parallelize->finish;
|
|
priv = parallelize->priv;
|
|
error = env_atomic_read(¶llelize->error);
|
|
|
|
finish(parallelize, priv, error);
|
|
}
|
|
|
|
static int _ocf_parallelize_hndl(struct ocf_request *req)
|
|
{
|
|
ocf_parallelize_t parallelize = req->priv;
|
|
int error;
|
|
|
|
error = parallelize->handle(parallelize, parallelize->priv,
|
|
req->byte_position, parallelize->shards_cnt);
|
|
|
|
env_atomic_cmpxchg(¶llelize->error, 0, error);
|
|
|
|
_ocf_parallelize_finish(parallelize);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int ocf_parallelize_create(ocf_parallelize_t *parallelize,
|
|
ocf_cache_t cache, unsigned shards_cnt, uint32_t priv_size,
|
|
ocf_parallelize_handle_t handle,
|
|
ocf_parallelize_finish_t finish)
|
|
{
|
|
ocf_parallelize_t tmp_parallelize;
|
|
struct list_head *iter;
|
|
ocf_queue_t queue;
|
|
size_t prl_size;
|
|
unsigned queue_count = 0;
|
|
int result, i;
|
|
|
|
queue_count = ocf_cache_get_queue_count(cache);
|
|
|
|
if (shards_cnt == 0)
|
|
shards_cnt = queue_count ?: 1;
|
|
|
|
prl_size = sizeof(*tmp_parallelize) +
|
|
shards_cnt * sizeof(*tmp_parallelize->reqs);
|
|
|
|
tmp_parallelize = env_vzalloc(prl_size + priv_size + OCF_PARALLELIZE_ALIGNMENT);
|
|
if (!tmp_parallelize)
|
|
return -OCF_ERR_NO_MEM;
|
|
|
|
if (priv_size > 0) {
|
|
uintptr_t priv = (uintptr_t)tmp_parallelize + prl_size;
|
|
priv = OCF_DIV_ROUND_UP(priv, OCF_PARALLELIZE_ALIGNMENT) * OCF_PARALLELIZE_ALIGNMENT;
|
|
tmp_parallelize->priv = (void*)priv;
|
|
}
|
|
|
|
tmp_parallelize->cache = cache;
|
|
tmp_parallelize->handle = handle;
|
|
tmp_parallelize->finish = finish;
|
|
|
|
tmp_parallelize->shards_cnt = shards_cnt;
|
|
env_atomic_set(&tmp_parallelize->remaining, shards_cnt + 1);
|
|
env_atomic_set(&tmp_parallelize->error, 0);
|
|
|
|
|
|
iter = cache->io_queues.next;
|
|
for (i = 0; i < shards_cnt; i++) {
|
|
if (queue_count > 0) {
|
|
queue = list_entry(iter, struct ocf_queue, list);
|
|
iter = iter->next;
|
|
if (iter == &cache->io_queues)
|
|
iter = iter->next;
|
|
} else {
|
|
queue = cache->mngt_queue;
|
|
}
|
|
tmp_parallelize->reqs[i] = ocf_req_new_mngt(queue);
|
|
if (!tmp_parallelize->reqs[i]) {
|
|
result = -OCF_ERR_NO_MEM;
|
|
goto err_reqs;
|
|
}
|
|
tmp_parallelize->reqs[i]->info.internal = true;
|
|
tmp_parallelize->reqs[i]->engine_handler =
|
|
_ocf_parallelize_hndl;
|
|
tmp_parallelize->reqs[i]->byte_position = i;
|
|
tmp_parallelize->reqs[i]->priv = tmp_parallelize;
|
|
}
|
|
|
|
*parallelize = tmp_parallelize;
|
|
|
|
return 0;
|
|
|
|
err_reqs:
|
|
while (i--)
|
|
ocf_req_put(tmp_parallelize->reqs[i]);
|
|
env_vfree(tmp_parallelize);
|
|
|
|
return result;
|
|
}
|
|
|
|
void ocf_parallelize_destroy(ocf_parallelize_t parallelize)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < parallelize->shards_cnt; i++)
|
|
ocf_req_put(parallelize->reqs[i]);
|
|
|
|
env_vfree(parallelize);
|
|
}
|
|
|
|
void *ocf_parallelize_get_priv(ocf_parallelize_t parallelize)
|
|
{
|
|
return parallelize->priv;
|
|
}
|
|
|
|
void ocf_parallelize_set_priv(ocf_parallelize_t parallelize, void *priv)
|
|
{
|
|
parallelize->priv = priv;
|
|
}
|
|
|
|
void ocf_parallelize_run(ocf_parallelize_t parallelize)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < parallelize->shards_cnt; i++)
|
|
ocf_queue_push_req(parallelize->reqs[i], OCF_QUEUE_PRIO_HIGH);
|
|
|
|
_ocf_parallelize_finish(parallelize);
|
|
}
|