Introduce composite volume
Signed-off-by: Robert Baldyga <robert.baldyga@intel.com>
This commit is contained in:
parent
5012dcd7d5
commit
b847fa9a61
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright(c) 2012-2021 Intel Corporation
|
||||
* Copyright(c) 2012-2022 Intel Corporation
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
@ -18,6 +18,7 @@
|
||||
#include "ocf_types.h"
|
||||
#include "ocf_io.h"
|
||||
#include "ocf_volume.h"
|
||||
#include "ocf_composite_volume.h"
|
||||
#include "ocf_cache.h"
|
||||
#include "ocf_core.h"
|
||||
#include "ocf_queue.h"
|
||||
|
55
inc/ocf_composite_volume.h
Normal file
55
inc/ocf_composite_volume.h
Normal file
@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright(c) 2022 Intel Corporation
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#ifndef __OCF_COMPOSITE_VOLUME_H__
|
||||
#define __OCF_COMPOSITE_VOLUME_H__
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief OCF composite volume API
|
||||
*/
|
||||
|
||||
#include "ocf_types.h"
|
||||
#include "ocf_env_headers.h"
|
||||
#include "ocf_err.h"
|
||||
#include "ocf_volume.h"
|
||||
|
||||
/**
|
||||
* @brief handle to object designating composite volume
|
||||
*/
|
||||
typedef ocf_volume_t ocf_composite_volume_t;
|
||||
|
||||
/**
|
||||
* @brief Allocate and initialize composite volume
|
||||
*
|
||||
* @param[out] cvolume pointer to volume handle
|
||||
* @param[in] ctx OCF context
|
||||
*
|
||||
* @return Zero when success, othewise an error
|
||||
*/
|
||||
int ocf_composite_volume_create(ocf_composite_volume_t *cvolume, ocf_ctx_t ctx);
|
||||
|
||||
/**
|
||||
* @brief Deinitialize and free composite volume
|
||||
*
|
||||
* @param[in] volume volume handle
|
||||
*/
|
||||
void ocf_composite_volume_destroy(ocf_composite_volume_t cvolume);
|
||||
|
||||
/**
|
||||
* @brief Add subvolume to composite volume
|
||||
*
|
||||
* @param[in] cvolume composite volume handle
|
||||
* @param[in] type type of added subvolume
|
||||
* @param[in] uuid UUID of added subvolume
|
||||
* @param[in] volume_params params to be passed to subvolume open
|
||||
*
|
||||
* @return Zero when success, othewise an error
|
||||
*/
|
||||
int ocf_composite_volume_add(ocf_composite_volume_t cvolume,
|
||||
ocf_volume_type_t type, struct ocf_volume_uuid *uuid,
|
||||
void *volume_params);
|
||||
|
||||
#endif /* __OCF_COMPOSITE_VOLUME_H__ */
|
387
src/ocf_composite_volume.c
Normal file
387
src/ocf_composite_volume.c
Normal file
@ -0,0 +1,387 @@
|
||||
/*
|
||||
* Copyright(c) 2022 Intel Corporation
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include "ocf/ocf.h"
|
||||
#include "ocf_priv.h"
|
||||
#include "ocf_core_priv.h"
|
||||
#include "ocf_io_priv.h"
|
||||
#include "metadata/metadata.h"
|
||||
#include "engine/cache_engine.h"
|
||||
#include "utils/utils_user_part.h"
|
||||
#include "ocf_request.h"
|
||||
#include "ocf_composite_volume_priv.h"
|
||||
|
||||
#define OCF_COMPOSITE_VOLUME_MEMBERS_MAX 16
|
||||
|
||||
struct ocf_composite_volume {
|
||||
uint8_t members_cnt;
|
||||
struct {
|
||||
struct ocf_volume volume;
|
||||
void *volume_params;
|
||||
} member[OCF_COMPOSITE_VOLUME_MEMBERS_MAX];
|
||||
uint64_t end_addr[OCF_COMPOSITE_VOLUME_MEMBERS_MAX];
|
||||
uint64_t length;
|
||||
unsigned max_io_size;
|
||||
};
|
||||
|
||||
struct ocf_composite_volume_io {
|
||||
struct ocf_io *member_io[OCF_COMPOSITE_VOLUME_MEMBERS_MAX];
|
||||
ctx_data_t *data;
|
||||
uint8_t begin_member;
|
||||
uint8_t end_member;
|
||||
env_atomic remaining;
|
||||
env_atomic error;
|
||||
};
|
||||
|
||||
static void ocf_composite_volume_master_cmpl(struct ocf_io *master_io,
|
||||
int error)
|
||||
{
|
||||
struct ocf_composite_volume_io *cio = ocf_io_get_priv(master_io);
|
||||
|
||||
env_atomic_cmpxchg(&cio->error, 0, error);
|
||||
|
||||
if (env_atomic_dec_return(&cio->remaining))
|
||||
return;
|
||||
|
||||
ocf_io_end(master_io, env_atomic_read(&cio->error));
|
||||
}
|
||||
|
||||
static void ocf_composite_volume_io_cmpl(struct ocf_io *io, int error)
|
||||
{
|
||||
struct ocf_io *master_io = io->priv1;
|
||||
|
||||
ocf_composite_volume_master_cmpl(master_io, error);
|
||||
}
|
||||
|
||||
static void ocf_composite_volume_handle_io(struct ocf_io *master_io,
|
||||
void (*hndl)(struct ocf_io *io))
|
||||
{
|
||||
struct ocf_composite_volume_io *cio = ocf_io_get_priv(master_io);
|
||||
int i;
|
||||
|
||||
env_atomic_set(&cio->remaining,
|
||||
cio->end_member - cio->begin_member + 1);
|
||||
env_atomic_set(&cio->error, 0);
|
||||
|
||||
for (i = cio->begin_member; i < cio->end_member; i++) {
|
||||
ocf_io_set_cmpl(cio->member_io[i], master_io, NULL,
|
||||
ocf_composite_volume_io_cmpl);
|
||||
|
||||
cio->member_io[i]->io_class = master_io->io_class;
|
||||
cio->member_io[i]->flags = master_io->flags;
|
||||
|
||||
hndl(cio->member_io[i]);
|
||||
}
|
||||
|
||||
ocf_composite_volume_master_cmpl(master_io, 0);
|
||||
}
|
||||
|
||||
static void ocf_composite_volume_submit_io(struct ocf_io *master_io)
|
||||
{
|
||||
ocf_composite_volume_handle_io(master_io, ocf_volume_submit_io);
|
||||
}
|
||||
|
||||
static void ocf_composite_volume_submit_flush(struct ocf_io *master_io)
|
||||
{
|
||||
ocf_composite_volume_handle_io(master_io, ocf_volume_submit_flush);
|
||||
}
|
||||
|
||||
static void ocf_composite_volume_submit_discard(struct ocf_io *master_io)
|
||||
{
|
||||
ocf_composite_volume_handle_io(master_io, ocf_volume_submit_discard);
|
||||
}
|
||||
|
||||
/* *** VOLUME OPS *** */
|
||||
|
||||
static int ocf_composite_volume_open(ocf_volume_t cvolume, void *volume_params)
|
||||
{
|
||||
struct ocf_composite_volume *composite = ocf_volume_get_priv(cvolume);
|
||||
int result, i;
|
||||
|
||||
composite->length = 0;
|
||||
composite->max_io_size = UINT_MAX;
|
||||
for (i = 0; i < composite->members_cnt; i++) {
|
||||
ocf_volume_t volume = &composite->member[i].volume;
|
||||
result = ocf_volume_open(volume,
|
||||
composite->member[i].volume_params);
|
||||
if (result)
|
||||
goto err;
|
||||
|
||||
composite->length += ocf_volume_get_length(volume);
|
||||
composite->end_addr[i] = composite->length;
|
||||
composite->max_io_size = OCF_MIN(composite->max_io_size,
|
||||
ocf_volume_get_max_io_size(volume));
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
while (i--)
|
||||
ocf_volume_close(&composite->member[i].volume);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void ocf_composite_volume_close(ocf_volume_t cvolume)
|
||||
{
|
||||
struct ocf_composite_volume *composite = ocf_volume_get_priv(cvolume);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < composite->members_cnt; i++)
|
||||
ocf_volume_close(&composite->member[i].volume);
|
||||
}
|
||||
|
||||
static unsigned int ocf_composite_volume_get_max_io_size(ocf_volume_t cvolume)
|
||||
{
|
||||
struct ocf_composite_volume *composite = ocf_volume_get_priv(cvolume);
|
||||
|
||||
return composite->max_io_size;
|
||||
}
|
||||
|
||||
static uint64_t ocf_composite_volume_get_byte_length(ocf_volume_t cvolume)
|
||||
{
|
||||
struct ocf_composite_volume *composite = ocf_volume_get_priv(cvolume);
|
||||
|
||||
return composite->length;
|
||||
}
|
||||
|
||||
static void ocf_composite_volume_on_deinit(ocf_volume_t cvolume)
|
||||
{
|
||||
struct ocf_composite_volume *composite = ocf_volume_get_priv(cvolume);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < composite->members_cnt; i++)
|
||||
ocf_volume_deinit(&composite->member[i].volume);
|
||||
}
|
||||
|
||||
/* *** IO OPS *** */
|
||||
|
||||
static int ocf_composite_io_set_data(struct ocf_io *io,
|
||||
ctx_data_t *data, uint32_t offset)
|
||||
{
|
||||
ocf_volume_t cvolume = ocf_io_get_volume(io);
|
||||
struct ocf_composite_volume *composite = ocf_volume_get_priv(cvolume);
|
||||
struct ocf_composite_volume_io *cio = ocf_io_get_priv(io);
|
||||
uint64_t member_volume_start, member_data_offset;
|
||||
int i, ret = 0;
|
||||
|
||||
cio->data = data;
|
||||
|
||||
for (i = cio->begin_member; i < cio->end_member; i++) {
|
||||
/* Each member IO will have the same data set, but with
|
||||
* different offset. First member will use bare offset set from
|
||||
* caller, each subsequent member IO has to skip over parts
|
||||
* "belonging" to previous members. */
|
||||
|
||||
if (i == cio->begin_member) {
|
||||
member_data_offset = offset;
|
||||
} else {
|
||||
member_volume_start = composite->end_addr[i - 1];
|
||||
member_data_offset = member_volume_start - io->addr;
|
||||
member_data_offset += offset;
|
||||
}
|
||||
|
||||
ret = ocf_io_set_data(cio->member_io[i], data,
|
||||
member_data_offset);
|
||||
if (ret)
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ctx_data_t *ocf_composite_io_get_data(struct ocf_io *io)
|
||||
{
|
||||
struct ocf_composite_volume_io *cio = ocf_io_get_priv(io);
|
||||
|
||||
return cio->data;
|
||||
}
|
||||
|
||||
const struct ocf_volume_properties ocf_composite_volume_properties = {
|
||||
.name = "OCF Composite",
|
||||
.io_priv_size = sizeof(struct ocf_composite_volume_io),
|
||||
.volume_priv_size = sizeof(struct ocf_composite_volume),
|
||||
.caps = {
|
||||
.atomic_writes = 0,
|
||||
},
|
||||
.ops = {
|
||||
.submit_io = ocf_composite_volume_submit_io,
|
||||
.submit_flush = ocf_composite_volume_submit_flush,
|
||||
.submit_discard = ocf_composite_volume_submit_discard,
|
||||
.submit_metadata = NULL,
|
||||
|
||||
.open = ocf_composite_volume_open,
|
||||
.close = ocf_composite_volume_close,
|
||||
.get_max_io_size = ocf_composite_volume_get_max_io_size,
|
||||
.get_length = ocf_composite_volume_get_byte_length,
|
||||
|
||||
.on_deinit = ocf_composite_volume_on_deinit,
|
||||
},
|
||||
.io_ops = {
|
||||
.set_data = ocf_composite_io_set_data,
|
||||
.get_data = ocf_composite_io_get_data,
|
||||
},
|
||||
.deinit = NULL,
|
||||
};
|
||||
|
||||
static int ocf_composite_io_allocator_init(ocf_io_allocator_t allocator,
|
||||
uint32_t priv_size, const char *name)
|
||||
{
|
||||
return ocf_io_allocator_default_init(allocator, priv_size, name);
|
||||
}
|
||||
|
||||
static void ocf_composite_io_allocator_deinit(ocf_io_allocator_t allocator)
|
||||
{
|
||||
ocf_io_allocator_default_deinit(allocator);
|
||||
}
|
||||
|
||||
static void *ocf_composite_io_allocator_new(ocf_io_allocator_t allocator,
|
||||
ocf_volume_t cvolume, ocf_queue_t queue,
|
||||
uint64_t addr, uint32_t bytes, uint32_t dir)
|
||||
{
|
||||
struct ocf_composite_volume *composite = ocf_volume_get_priv(cvolume);
|
||||
struct ocf_composite_volume_io *cio;
|
||||
struct ocf_io_internal *ioi;
|
||||
uint64_t member_addr, member_bytes, cur_addr, cur_bytes;
|
||||
int i;
|
||||
|
||||
ioi = ocf_io_allocator_default_new(allocator, cvolume, queue,
|
||||
addr, bytes, dir);
|
||||
if (!ioi)
|
||||
return NULL;
|
||||
|
||||
cio = ocf_io_get_priv(&ioi->io);
|
||||
|
||||
if (bytes == 0) {
|
||||
/* Flush io - allocate io for each volume */
|
||||
for (i = 0; i < composite->members_cnt; i++) {
|
||||
cio->member_io[i] = ocf_io_new(&composite->member[i].volume,
|
||||
queue, 0, 0, dir, 0, 0);
|
||||
if (!cio->member_io[i])
|
||||
goto err;
|
||||
}
|
||||
cio->begin_member = 0;
|
||||
cio->end_member = composite->members_cnt;
|
||||
|
||||
return ioi;
|
||||
}
|
||||
|
||||
for (i = 0; i < composite->members_cnt; i++) {
|
||||
if (addr < composite->end_addr[i]) {
|
||||
cio->begin_member = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
cur_addr = addr;
|
||||
cur_bytes = bytes;
|
||||
|
||||
for (; i < composite->members_cnt; i++) {
|
||||
member_addr = cur_addr - (i > 0 ? composite->end_addr[i-1] : 0);
|
||||
member_bytes =
|
||||
OCF_MIN(cur_addr + cur_bytes, composite->end_addr[i])
|
||||
- member_addr;
|
||||
|
||||
cio->member_io[i] = ocf_io_new(&composite->member[i].volume, queue,
|
||||
member_addr, member_bytes, dir, 0, 0);
|
||||
if (!cio->member_io[i])
|
||||
goto err;
|
||||
|
||||
cur_addr += member_bytes;
|
||||
cur_bytes -= member_bytes;
|
||||
|
||||
if (!cur_bytes) {
|
||||
cio->end_member = i + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ENV_BUG_ON(cur_bytes != 0);
|
||||
|
||||
return ioi;
|
||||
|
||||
err:
|
||||
for (i = 0; i < composite->members_cnt; i++) {
|
||||
if (cio->member_io[i])
|
||||
ocf_io_put(cio->member_io[i]);
|
||||
}
|
||||
|
||||
ocf_io_allocator_default_del(allocator, ioi);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void ocf_composite_io_allocator_del(ocf_io_allocator_t allocator, void *obj)
|
||||
{
|
||||
struct ocf_io_internal *ioi = obj;
|
||||
struct ocf_composite_volume_io *cio = ocf_io_get_priv(&ioi->io);
|
||||
int i;
|
||||
|
||||
for (i = cio->begin_member; i < cio->end_member; i++) {
|
||||
if (cio->member_io[i])
|
||||
ocf_io_put(cio->member_io[i]);
|
||||
}
|
||||
|
||||
ocf_io_allocator_default_del(allocator, ioi);
|
||||
}
|
||||
|
||||
const struct ocf_io_allocator_type ocf_composite_io_allocator_type = {
|
||||
.ops = {
|
||||
.allocator_init = ocf_composite_io_allocator_init,
|
||||
.allocator_deinit = ocf_composite_io_allocator_deinit,
|
||||
.allocator_new = ocf_composite_io_allocator_new,
|
||||
.allocator_del = ocf_composite_io_allocator_del,
|
||||
},
|
||||
};
|
||||
|
||||
const struct ocf_volume_extended ocf_composite_volume_extended = {
|
||||
.allocator_type = &ocf_composite_io_allocator_type,
|
||||
};
|
||||
|
||||
int ocf_composite_volume_type_init(ocf_ctx_t ctx)
|
||||
{
|
||||
return ocf_ctx_register_volume_type_internal(ctx,
|
||||
OCF_VOLUME_TYPE_COMPOSITE,
|
||||
&ocf_composite_volume_properties,
|
||||
&ocf_composite_volume_extended);
|
||||
}
|
||||
|
||||
int ocf_composite_volume_create(ocf_composite_volume_t *volume, ocf_ctx_t ctx)
|
||||
{
|
||||
ocf_volume_type_t type;
|
||||
|
||||
type = ocf_ctx_get_volume_type_internal(ctx, OCF_VOLUME_TYPE_COMPOSITE);
|
||||
if (!type)
|
||||
return -OCF_ERR_INVAL;
|
||||
|
||||
return ocf_volume_create(volume, type, NULL);
|
||||
}
|
||||
|
||||
void ocf_composite_volume_destroy(ocf_composite_volume_t cvolume)
|
||||
{
|
||||
ocf_volume_destroy(cvolume);
|
||||
}
|
||||
|
||||
int ocf_composite_volume_add(ocf_composite_volume_t cvolume,
|
||||
ocf_volume_type_t type, struct ocf_volume_uuid *uuid,
|
||||
void *volume_params)
|
||||
{
|
||||
struct ocf_composite_volume *composite = ocf_volume_get_priv(cvolume);
|
||||
ocf_volume_t volume;
|
||||
int result;
|
||||
|
||||
if (composite->members_cnt >= OCF_COMPOSITE_VOLUME_MEMBERS_MAX)
|
||||
return -OCF_ERR_INVAL;
|
||||
|
||||
volume = &composite->member[composite->members_cnt].volume;
|
||||
result = ocf_volume_init(volume, type, uuid, true);
|
||||
if (result)
|
||||
return result;
|
||||
|
||||
composite->member[composite->members_cnt].volume_params = volume_params;
|
||||
composite->members_cnt++;
|
||||
|
||||
return 0;
|
||||
}
|
13
src/ocf_composite_volume_priv.h
Normal file
13
src/ocf_composite_volume_priv.h
Normal file
@ -0,0 +1,13 @@
|
||||
/*
|
||||
* Copyright(c) 2022 Intel Corporation
|
||||
* SPDX-License-Identifier: BSD-3-Clause-Clear
|
||||
*/
|
||||
|
||||
#ifndef __OCF_COMPOSITE_VOLUME_PRIV_H__
|
||||
#define __OCF_COMPOSITE_VOLUME_PRIV_H__
|
||||
|
||||
#include "ocf/ocf.h"
|
||||
|
||||
int ocf_composite_volume_type_init(ocf_ctx_t ctx);
|
||||
|
||||
#endif /* __OCF_COMPOSITE_VOLUME_H__ */
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright(c) 2012-2021 Intel Corporation
|
||||
* Copyright(c) 2012-2022 Intel Corporation
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
@ -11,6 +11,7 @@
|
||||
#include "ocf_logger_priv.h"
|
||||
#include "ocf_core_priv.h"
|
||||
#include "ocf_cache_priv.h"
|
||||
#include "ocf_composite_volume_priv.h"
|
||||
#include "mngt/ocf_mngt_core_pool_priv.h"
|
||||
#include "metadata/metadata_io.h"
|
||||
|
||||
@ -220,12 +221,18 @@ int ocf_ctx_create(ocf_ctx_t *ctx, const struct ocf_ctx_config *cfg)
|
||||
if (ret)
|
||||
goto err_utils;
|
||||
|
||||
ret = ocf_composite_volume_type_init(ocf_ctx);
|
||||
if (ret)
|
||||
goto err_core_volume;
|
||||
|
||||
ocf_mngt_core_pool_init(ocf_ctx);
|
||||
|
||||
*ctx = ocf_ctx;
|
||||
|
||||
return 0;
|
||||
|
||||
err_core_volume:
|
||||
ocf_ctx_unregister_volume_type(ocf_ctx, OCF_VOLUME_TYPE_CORE);
|
||||
err_utils:
|
||||
ocf_metadata_io_ctx_deinit(ocf_ctx);
|
||||
err_mio:
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright(c) 2012-2021 Intel Corporation
|
||||
* Copyright(c) 2012-2022 Intel Corporation
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
@ -12,13 +12,14 @@
|
||||
#include "ocf_volume_priv.h"
|
||||
|
||||
#define OCF_VOLUME_TYPE_CNT_USER 8
|
||||
#define OCF_VOLUME_TYPE_CNT_PRIV 2
|
||||
#define OCF_VOLUME_TYPE_CNT_PRIV 3
|
||||
#define OCF_VOLUME_TYPE_MAX_USER OCF_VOLUME_TYPE_CNT_USER
|
||||
#define OCF_VOLUME_TYPE_MAX \
|
||||
(OCF_VOLUME_TYPE_CNT_USER + OCF_VOLUME_TYPE_CNT_PRIV)
|
||||
|
||||
#define OCF_VOLUME_TYPE_CORE (OCF_VOLUME_TYPE_MAX_USER + 0)
|
||||
#define OCF_VOLUME_TYPE_CACHE (OCF_VOLUME_TYPE_MAX_USER + 1)
|
||||
#define OCF_VOLUME_TYPE_COMPOSITE (OCF_VOLUME_TYPE_MAX_USER + 2)
|
||||
|
||||
/**
|
||||
* @brief OCF main control structure
|
||||
|
Loading…
Reference in New Issue
Block a user