Merge pull request #702 from robertbaldyga/v22.6-composite-volume

Introduce composite volume
This commit is contained in:
Adam Rutkowski 2022-06-02 13:36:21 +02:00 committed by GitHub
commit b053f7925a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 1079 additions and 148 deletions

View File

@ -0,0 +1,172 @@
---
group: composite_volume
---
The OCF composite volume provides functionality of composing mutiple OCF volume
instances into one bigger volume. The component volumes are linearly mapped into
address space of the composite volume (unlike RAID0, which uses interleaved
mapping a.k.a. striping).
+-----------------------+---------------+-----------------------------+
| volume A | volume B | volume C |
*-----------------------|---------------|-----------------------------+
LBA | 0 | 1 | 2 | 3 | 4 | 5 | 0 | 1 | 2 | 3 | 0 | 1 | 2 | 3 | 4 | 5 |
+---------------------------------------------------------------------+
| composite volume |
+---------------------------------------------------------------------+
LBA | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
+---------------------------------------------------------------------+
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
title: Creation of composite volume instance
id: creation
---
It shall be possible to create an instance of a composite volume using a
constructor function.
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
title: Destruction of composite volume instance
id: destruction
---
It shall be possible to destroy an instance of a composite volume using
standard ocf_volume API.
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
title: Adding new component volume
id: adding_component_volume
---
If shall be possible to add new component volume to the composite volume using
dedicated function.
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
title: Instatiation of component volumes
id: instatiation_component_volumes
---
Adding component volume to composite volume shall automatically instatiate
component volume based on type, uuid and volume_params parameters.
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
title: Destrution of component volumes
id: destruction_component_volumes
---
Component volume instances shall be destroyed on composite volume destruction.
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
title: Adding component volumes of different types
id: component_volume_types
---
It shall be possible to add component volumes of different volume types to
single composite volume. The only requirement is that those types shall be
registered within the same ocf_ctx.
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
title: Maximum number of composite volumes
id: max_composite_volumes
---
It shall be possible to add up to 16 component volumes to a single composite
volume.
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
title: Volume API
id: volume_api
---
Composite volume shall conform to regular ocf_volume API. I.e. it shall be
possible to perform on it following volume operations: open, close,
get_max_io_size, get_length, submit_io, submit_flush and submit_discard.
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
title: Volume open
id: volume_open
---
Composite volume shall open all component volumes when it's being opened.
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
title: Volume close
id: volume_close
---
Composite volume shall close all component volumes when it's being closed.
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
title: Getting maximum io size
id: get_max_io_size
---
Composite volume shall report a maximum io size being the lowest maximum io
size among all the component volumes.
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
title: Getting volume length
id: get_length
---
Composite volume shall report a lenght being a sum of lenghs of all component
volumes.
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
title: Request passing
id: request_passing
---
Composite volume shall pass io, flush and discard request or its fragments to
component volumes based on their mapping.
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
title: IO Flags passing
id: io_flags_passing
---
Composite volume shall pass all IO flags associated with request to all requests
issued to component volumes as part of fulfilling the master request.
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
title: I/O request completion
id: io_request_completion
---
The I/O request shall be completed only when all sub-I/Os submitted to component
volumes are completed.
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
title: I/O error handling
id: io_error_handling
---
If I/O error occures on any I/O request submitted to composite volume, that
error shall be passed to the completion of the original I/O request. If multiple
sub-I/Os reported errors, the first error that occured shall be passed to the
completion of the original I/O request.
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
title: Attaching/loading the cache
id: cache_attach_load
---
It shall be possible to attach/load the cache using instance of a composite
volume.

View File

@ -72,6 +72,9 @@ int initialize_cache(ocf_ctx_t ctx, ocf_cache_t *cache)
{
struct ocf_mngt_cache_config cache_cfg = { .name = "cache1" };
struct ocf_mngt_cache_attach_config attach_cfg = { };
ocf_volume_t volume;
ocf_volume_type_t type;
struct ocf_volume_uuid uuid;
struct cache_priv *cache_priv;
struct simple_context context;
int ret;
@ -92,20 +95,28 @@ int initialize_cache(ocf_ctx_t ctx, ocf_cache_t *cache)
cache_cfg.metadata_volatile = true;
/* Cache deivce (volume) configuration */
ocf_mngt_cache_attach_config_set_default(&attach_cfg);
attach_cfg.device.volume_type = VOL_TYPE;
ret = ocf_uuid_set_str(&attach_cfg.device.uuid, "cache");
type = ocf_ctx_get_volume_type(ctx, VOL_TYPE);
ret = ocf_uuid_set_str(&uuid, "cache");
if (ret)
goto err_sem;
ret = ocf_volume_create(&volume, type, &uuid);
if (ret)
goto err_sem;
ocf_mngt_cache_attach_config_set_default(&attach_cfg);
attach_cfg.device.volume = volume;
/*
* Allocate cache private structure. We can not initialize it
* on stack, as it may be used in various async contexts
* throughout the entire live span of cache object.
*/
cache_priv = malloc(sizeof(*cache_priv));
if (!cache_priv)
return -ENOMEM;
if (!cache_priv) {
ret = -ENOMEM;
goto err_vol;
}
/* Start cache */
ret = ocf_mngt_cache_start(ctx, cache, &cache_cfg, NULL);
@ -157,6 +168,8 @@ err_cache:
ocf_queue_put(cache_priv->mngt_queue);
err_priv:
free(cache_priv);
err_vol:
ocf_volume_destroy(&volume);
err_sem:
sem_destroy(&context.sem);
return ret;

View File

@ -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"

View 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__ */

View File

@ -361,14 +361,17 @@ void ocf_mngt_cache_stop(ocf_cache_t cache,
*/
struct ocf_mngt_cache_device_config {
/**
* @brief Cache volume UUID
* @brief Cache volume
*
* The volume ownership is moved to the context of operation that takes
* this config. Thus the volume is being effectively moved using
* ocf_volume_move(), leaving the original volume uninitialized.
*
* Note that if the original volume was instantiated using *_create
* function, it still needs to be destroyed using ocf_volume_destroy()
* to deallocate the memory.
*/
struct ocf_volume_uuid uuid;
/**
* @brief Cache volume type
*/
uint8_t volume_type;
ocf_volume_t volume;
/**
* @brief If set, cache features (like discard) are tested

View File

@ -1,5 +1,5 @@
/*
* Copyright(c) 2012-2021 Intel Corporation
* Copyright(c) 2012-2022 Intel Corporation
* SPDX-License-Identifier: BSD-3-Clause
*/
@ -82,6 +82,24 @@ struct ocf_volume_ops {
*/
void (*submit_write_zeroes)(struct ocf_io *io);
/**
* @brief Volume initialization callback, called when volume object
* is being initialized
*
* @param[in] volume Volume
*
* @return Zero on success, otherwise error code
*/
int (*on_init)(ocf_volume_t volume);
/**
* @brief Volume deinitialization callback, called when volume object
* is being deinitialized
*
* @param[in] volume Volume
*/
void (*on_deinit)(ocf_volume_t volume);
/**
* @brief Open volume
*

View File

@ -135,10 +135,6 @@ struct ocf_cache_attach_context {
* load or recovery
*/
bool uuid_copied : 1;
/*!< copied uuid data to context.
*/
bool metadata_frozen : 1;
/*!< metadata reference counter frozen
*/
@ -790,7 +786,6 @@ static void _ocf_mngt_attach_cache_device(ocf_pipeline_t pipeline,
struct ocf_cache_attach_context *context = priv;
struct ocf_mngt_cache_device_config *device_cfg = &context->cfg.device;
ocf_cache_t cache = context->cache;
ocf_volume_type_t type;
int ret;
cache->device = env_vzalloc(sizeof(*cache->device));
@ -799,20 +794,9 @@ static void _ocf_mngt_attach_cache_device(ocf_pipeline_t pipeline,
context->flags.device_alloc = true;
/* Prepare UUID of cache volume */
type = ocf_ctx_get_volume_type(cache->owner, device_cfg->volume_type);
if (!type) {
OCF_PL_FINISH_RET(pipeline,
-OCF_ERR_INVAL_VOLUME_TYPE);
}
ret = ocf_volume_init(&cache->device->volume, type,
&device_cfg->uuid, true);
if (ret)
OCF_PL_FINISH_RET(pipeline, ret);
cache->device->volume.cache = cache;
ocf_volume_move(&cache->device->volume, device_cfg->volume);
context->flags.volume_inited = true;
cache->device->volume.cache = cache;
/*
* Open cache device, It has to be done first because metadata service
@ -1279,8 +1263,6 @@ uint64_t _ocf_mngt_calculate_ram_needed(ocf_cache_line_size_t line_size,
int ocf_mngt_get_ram_needed(ocf_cache_t cache,
struct ocf_mngt_cache_device_config *cfg, uint64_t *ram_needed)
{
ocf_volume_t volume;
ocf_volume_type_t type;
ocf_cache_line_size_t line_size;
uint64_t volume_size;
int result;
@ -1289,26 +1271,15 @@ int ocf_mngt_get_ram_needed(ocf_cache_t cache,
OCF_CHECK_NULL(cfg);
OCF_CHECK_NULL(ram_needed);
type = ocf_ctx_get_volume_type(cache->owner, cfg->volume_type);
if (!type)
return -OCF_ERR_INVAL_VOLUME_TYPE;
result = ocf_volume_create(&volume, type, &cfg->uuid);
result = ocf_volume_open(cfg->volume, cfg->volume_params);
if (result)
return result;
result = ocf_volume_open(volume, cfg->volume_params);
if (result) {
ocf_volume_destroy(volume);
return result;
}
line_size = ocf_line_size(cache);
volume_size = ocf_volume_get_length(volume);
volume_size = ocf_volume_get_length(cfg->volume);
*ram_needed = _ocf_mngt_calculate_ram_needed(line_size, volume_size);
ocf_volume_close(volume);
ocf_volume_destroy(volume);
ocf_volume_close(cfg->volume);
return 0;
}
@ -1479,34 +1450,6 @@ static void _ocf_mngt_init_attached_nonpersistent(ocf_pipeline_t pipeline,
ocf_pipeline_next(pipeline);
}
static void _ocf_mngt_copy_uuid_data(ocf_pipeline_t pipeline,
void *priv, ocf_pipeline_arg_t arg)
{
struct ocf_cache_attach_context *context = priv;
struct ocf_mngt_cache_device_config *device_cfg = &context->cfg.device;
void *data;
int result;
if (device_cfg->uuid.size == 0)
OCF_PL_NEXT_RET(pipeline);
data = env_vmalloc(device_cfg->uuid.size);
if (!data)
OCF_PL_FINISH_RET(pipeline, -OCF_ERR_NO_MEM);
result = env_memcpy(data, device_cfg->uuid.size, device_cfg->uuid.data,
device_cfg->uuid.size);
if (result) {
env_vfree(data);
OCF_PL_FINISH_RET(pipeline, -OCF_ERR_INVAL);
}
device_cfg->uuid.data = data;
context->flags.uuid_copied = true;
ocf_pipeline_next(pipeline);
}
static void _ocf_mngt_attach_check_ram(ocf_pipeline_t pipeline,
void *priv, ocf_pipeline_arg_t arg)
{
@ -1799,6 +1742,8 @@ static void _ocf_mngt_attach_handle_error(
if (context->flags.volume_inited)
ocf_volume_deinit(&cache->device->volume);
else
ocf_volume_deinit(context->cfg.device.volume);
if (context->flags.front_volume_opened)
ocf_volume_close(&cache->device->front_volume);
@ -1824,16 +1769,12 @@ static void _ocf_mngt_cache_attach_finish(ocf_pipeline_t pipeline,
void *priv, int error)
{
struct ocf_cache_attach_context *context = priv;
struct ocf_mngt_cache_device_config *device_cfg = &context->cfg.device;
if (error)
_ocf_mngt_attach_handle_error(context);
context->cmpl(context->cache, context->priv1, context->priv2, error);
if (context->flags.uuid_copied)
env_vfree(device_cfg->uuid.data);
ocf_pipeline_destroy(context->pipeline);
}
@ -1841,7 +1782,6 @@ struct ocf_pipeline_properties _ocf_mngt_cache_attach_pipeline_properties = {
.priv_size = sizeof(struct ocf_cache_attach_context),
.finish = _ocf_mngt_cache_attach_finish,
.steps = {
OCF_PL_STEP(_ocf_mngt_copy_uuid_data),
OCF_PL_STEP(_ocf_mngt_init_attached_nonpersistent),
OCF_PL_STEP(_ocf_mngt_attach_cache_device),
OCF_PL_STEP(_ocf_mngt_init_properties),
@ -1868,7 +1808,6 @@ struct ocf_pipeline_properties _ocf_mngt_cache_load_pipeline_properties = {
.priv_size = sizeof(struct ocf_cache_attach_context),
.finish = _ocf_mngt_cache_attach_finish,
.steps = {
OCF_PL_STEP(_ocf_mngt_copy_uuid_data),
OCF_PL_STEP(_ocf_mngt_init_attached_nonpersistent),
OCF_PL_STEP(_ocf_mngt_attach_cache_device),
OCF_PL_STEP(_ocf_mngt_init_properties),
@ -2265,7 +2204,6 @@ struct ocf_pipeline_properties _ocf_mngt_cache_standby_attach_pipeline_propertie
.priv_size = sizeof(struct ocf_cache_attach_context),
.finish = _ocf_mngt_cache_attach_finish,
.steps = {
OCF_PL_STEP(_ocf_mngt_copy_uuid_data),
OCF_PL_STEP(_ocf_mngt_init_attached_nonpersistent),
OCF_PL_STEP(_ocf_mngt_attach_cache_device),
OCF_PL_STEP(_ocf_mngt_attach_read_properties),
@ -2292,7 +2230,6 @@ struct ocf_pipeline_properties _ocf_mngt_cache_standby_load_pipeline_properties
.priv_size = sizeof(struct ocf_cache_attach_context),
.finish = _ocf_mngt_cache_attach_finish,
.steps = {
OCF_PL_STEP(_ocf_mngt_copy_uuid_data),
OCF_PL_STEP(_ocf_mngt_init_attached_nonpersistent),
OCF_PL_STEP(_ocf_mngt_attach_cache_device),
OCF_PL_STEP(_ocf_mngt_init_cache_front_volume),
@ -2342,20 +2279,9 @@ static void _ocf_mngt_activate_set_cache_device(ocf_pipeline_t pipeline,
struct ocf_cache_attach_context *context = priv;
struct ocf_mngt_cache_device_config *device_cfg = &context->cfg.device;
ocf_cache_t cache = context->cache;
ocf_volume_type_t type;
int ret;
type = ocf_ctx_get_volume_type(cache->owner, device_cfg->volume_type);
if (!type) {
OCF_PL_FINISH_RET(pipeline,
-OCF_ERR_INVAL_VOLUME_TYPE);
}
ret = ocf_volume_init(&cache->device->volume, type,
&device_cfg->uuid, true);
if (ret)
OCF_PL_FINISH_RET(pipeline, ret);
ocf_volume_move(&cache->device->volume, device_cfg->volume);
cache->device->volume.cache = cache;
context->flags.volume_inited = true;
@ -2473,6 +2399,8 @@ static void _ocf_mngt_activate_handle_error(
if (context->flags.volume_inited)
ocf_volume_deinit(&cache->device->volume);
else
ocf_volume_deinit(context->cfg.device.volume);
if (context->flags.volume_stored)
ocf_volume_move(&cache->device->volume, &context->cache_volume);
@ -2485,7 +2413,6 @@ static void _ocf_mngt_cache_activate_finish(ocf_pipeline_t pipeline,
void *priv, int error)
{
struct ocf_cache_attach_context *context = priv;
struct ocf_mngt_cache_device_config *device_cfg = &context->cfg.device;
ocf_cache_t cache = context->cache;
ocf_pipeline_t stop_pipeline;
@ -2510,12 +2437,9 @@ static void _ocf_mngt_cache_activate_finish(ocf_pipeline_t pipeline,
ocf_volume_deinit(&context->cache_volume);
}
out:
context->cmpl(context->cache, context->priv1, context->priv2, error);
if (context->flags.uuid_copied)
env_vfree(device_cfg->uuid.data);
ocf_pipeline_destroy(context->pipeline);
}
@ -2523,7 +2447,6 @@ struct ocf_pipeline_properties _ocf_mngt_cache_activate_pipeline_properties = {
.priv_size = sizeof(struct ocf_cache_attach_context),
.finish = _ocf_mngt_cache_activate_finish,
.steps = {
OCF_PL_STEP(_ocf_mngt_copy_uuid_data),
OCF_PL_STEP(_ocf_mngt_activate_set_cache_device),
OCF_PL_STEP(_ocf_mngt_activate_init_properties),
OCF_PL_STEP(_ocf_mngt_activate_compare_superblock),
@ -2870,10 +2793,7 @@ static int _ocf_mngt_cache_validate_cfg(struct ocf_mngt_cache_config *cfg)
static int _ocf_mngt_cache_validate_device_cfg(
struct ocf_mngt_cache_device_config *device_cfg)
{
if (!device_cfg->uuid.data)
return -OCF_ERR_INVAL;
if (device_cfg->uuid.size > OCF_VOLUME_UUID_MAX_SIZE)
if (!device_cfg->volume)
return -OCF_ERR_INVAL;
return 0;

387
src/ocf_composite_volume.c Normal file
View 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;
}

View 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__ */

View File

@ -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:

View File

@ -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

View File

@ -1,5 +1,5 @@
/*
* Copyright(c) 2012-2021 Intel Corporation
* Copyright(c) 2012-2022 Intel Corporation
* SPDX-License-Identifier: BSD-3-Clause
*/
@ -31,7 +31,7 @@
#define OCF_IO_TOTAL(priv_size) \
(sizeof(struct ocf_io_internal) + priv_size)
static int ocf_io_allocator_default_init(ocf_io_allocator_t allocator,
int ocf_io_allocator_default_init(ocf_io_allocator_t allocator,
uint32_t priv_size, const char *name)
{
allocator->priv = env_allocator_create(OCF_IO_TOTAL(priv_size), name,
@ -42,20 +42,20 @@ static int ocf_io_allocator_default_init(ocf_io_allocator_t allocator,
return 0;
}
static void ocf_io_allocator_default_deinit(ocf_io_allocator_t allocator)
void ocf_io_allocator_default_deinit(ocf_io_allocator_t allocator)
{
env_allocator_destroy(allocator->priv);
allocator->priv = NULL;
}
static void *ocf_io_allocator_default_new(ocf_io_allocator_t allocator,
void *ocf_io_allocator_default_new(ocf_io_allocator_t allocator,
ocf_volume_t volume, ocf_queue_t queue,
uint64_t addr, uint32_t bytes, uint32_t dir)
{
return env_allocator_new(allocator->priv);
}
static void ocf_io_allocator_default_del(ocf_io_allocator_t allocator, void *obj)
void ocf_io_allocator_default_del(ocf_io_allocator_t allocator, void *obj)
{
env_allocator_del(allocator->priv, obj);
}

View File

@ -1,5 +1,5 @@
/*
* Copyright(c) 2012-2021 Intel Corporation
* Copyright(c) 2012-2022 Intel Corporation
* SPDX-License-Identifier: BSD-3-Clause
*/
@ -27,6 +27,17 @@ static inline struct ocf_io_internal *ocf_io_get_internal(struct ocf_io* io)
return container_of(io, struct ocf_io_internal, io);
}
int ocf_io_allocator_default_init(ocf_io_allocator_t allocator,
uint32_t priv_size, const char *name);
void ocf_io_allocator_default_deinit(ocf_io_allocator_t allocator);
void *ocf_io_allocator_default_new(ocf_io_allocator_t allocator,
ocf_volume_t volume, ocf_queue_t queue,
uint64_t addr, uint32_t bytes, uint32_t dir);
void ocf_io_allocator_default_del(ocf_io_allocator_t allocator, void *obj);
int ocf_io_allocator_init(ocf_io_allocator_t allocator, ocf_io_allocator_type_t type,
uint32_t priv_size, const char *name);

View File

@ -1,5 +1,5 @@
/*
* Copyright(c) 2012-2021 Intel Corporation
* Copyright(c) 2012-2022 Intel Corporation
* SPDX-License-Identifier: BSD-3-Clause
*/
@ -94,57 +94,73 @@ int ocf_volume_init(ocf_volume_t volume, ocf_volume_type_t type,
return -OCF_ERR_INVAL;
priv_size = type->properties->volume_priv_size;
volume->opened = false;
volume->type = type;
volume->priv = env_zalloc(priv_size, ENV_MEM_NORMAL);
if (!volume->priv)
return -OCF_ERR_NO_MEM;
ocf_refcnt_init(&volume->refcnt);
ocf_refcnt_freeze(&volume->refcnt);
volume->opened = false;
volume->type = type;
if (!uuid) {
volume->uuid.size = 0;
volume->uuid.data = NULL;
volume->uuid_copy = false;
ocf_refcnt_init(&volume->refcnt);
ocf_refcnt_freeze(&volume->refcnt);
if (!uuid)
return 0;
}
volume->uuid_copy = uuid_copy;
if (uuid_copy) {
data = env_vmalloc(uuid->size);
if (!data)
goto err;
ret = env_memcpy(data, uuid->size, uuid->data, uuid->size);
if (ret) {
env_vfree(data);
if (!data) {
ret = -OCF_ERR_NO_MEM;
goto err;
}
volume->uuid.data = data;
ret = env_memcpy(data, uuid->size, uuid->data, uuid->size);
if (ret) {
ret = -OCF_ERR_INVAL;
goto err;
}
} else {
volume->uuid.data = uuid->data;
}
volume->uuid.size = uuid->size;
if (volume->type->properties->ops.on_init) {
ret = volume->type->properties->ops.on_init(volume);
if (ret)
goto err;
}
return 0;
err:
ocf_refcnt_unfreeze(&volume->refcnt);
env_free(volume->priv);
return -OCF_ERR_NO_MEM;
volume->priv = NULL;
if (volume->uuid_copy && volume->uuid.data)
env_vfree(volume->uuid.data);
volume->uuid.data = NULL;
volume->uuid.size = 0;
return ret;
}
void ocf_volume_deinit(ocf_volume_t volume)
{
OCF_CHECK_NULL(volume);
if (volume->type && volume->type->properties->ops.on_deinit)
volume->type->properties->ops.on_deinit(volume);
env_free(volume->priv);
volume->priv = NULL;
if (volume->uuid_copy && volume->uuid.data) {
env_vfree(volume->uuid.data);

View File

@ -63,8 +63,7 @@ class CacheConfig(Structure):
class CacheDeviceConfig(Structure):
_fields_ = [
("_uuid", Uuid),
("_volume_type", c_uint8),
("_volume", c_void_p),
("_perform_test", c_bool),
("_volume_params", c_void_p),
]
@ -257,7 +256,7 @@ class Cache:
raise OcfError("Failed to detach failover cache device", c.results["error"])
def standby_activate(self, device, open_cores=True):
device_cfg = Cache.generate_device_config(device)
device_cfg = self.generate_device_config(device)
activate_cfg = CacheStandbyActivateConfig(_device=device_cfg, _open_cores=open_cores,)
@ -457,14 +456,24 @@ class Cache:
if status:
raise OcfError("Error adding partition to cache", status)
@staticmethod
def generate_device_config(device, perform_test=True):
device_config = CacheDeviceConfig(
_uuid=Uuid(
def generate_device_config(self, device, perform_test=True):
uuid = Uuid(
_data=cast(create_string_buffer(device.uuid.encode("ascii")), c_char_p),
_size=len(device.uuid) + 1,
),
_volume_type=device.type_id,
)
volume = c_void_p()
lib = OcfLib.getInstance()
result = lib.ocf_volume_create(
byref(volume),
self.owner.ocf_volume_type[type(device)],
byref(uuid)
)
if result != 0:
raise OcfError("Cache volume initialization failed", result)
device_config = CacheDeviceConfig(
_volume=volume,
_perform_test=perform_test,
_volume_params=None,
)
@ -477,7 +486,7 @@ class Cache:
self.device = device
self.device_name = device.uuid
device_config = Cache.generate_device_config(device, perform_test=perform_test)
device_config = self.generate_device_config(device, perform_test=perform_test)
attach_cfg = CacheAttachConfig(
_device=device_config,
@ -505,7 +514,7 @@ class Cache:
self.device = device
self.device_name = device.uuid
device_config = Cache.generate_device_config(device, perform_test=False)
device_config = self.generate_device_config(device, perform_test=False)
attach_cfg = CacheAttachConfig(
_device=device_config,
@ -533,7 +542,7 @@ class Cache:
self.device = device
self.device_name = device.uuid
device_config = Cache.generate_device_config(device, perform_test=perform_test)
device_config = self.generate_device_config(device, perform_test=perform_test)
attach_cfg = CacheAttachConfig(
_device=device_config,
@ -570,7 +579,7 @@ class Cache:
self.device = device
self.device_name = device.uuid
device_config = Cache.generate_device_config(device)
device_config = self.generate_device_config(device)
attach_cfg = CacheAttachConfig(
_device=device_config,
@ -917,3 +926,5 @@ lib.ocf_mngt_add_partition_to_cache.argtypes = [
]
lib.ocf_mngt_cache_io_classes_configure.restype = c_int
lib.ocf_mngt_cache_io_classes_configure.argtypes = [c_void_p, c_void_p]
lib.ocf_volume_create.restype = c_int
lib.ocf_volume_create.argtypes = [c_void_p, c_void_p, c_void_p]

View File

@ -3,7 +3,7 @@
# SPDX-License-Identifier: BSD-3-Clause
#
from ctypes import c_void_p, Structure, c_char_p, cast, pointer, byref, c_int
from ctypes import c_void_p, Structure, c_char_p, cast, pointer, byref, c_int, c_uint8
import weakref
from .logger import LoggerOps, Logger
@ -37,6 +37,7 @@ class OcfCtx:
self.lib = lib
self.volume_types_count = 1
self.volume_types = {}
self.ocf_volume_type = {}
self.caches = []
self.cfg = OcfCtxCfg(
@ -77,6 +78,11 @@ class OcfCtx:
if result != 0:
raise OcfError("Volume type registration failed", result)
self.ocf_volume_type[volume_type] = self.lib.ocf_ctx_get_volume_type(
self.ctx_handle,
volume_type.type_id
)
self.volume_types_count += 1
def unregister_volume_type(self, vol_type):
@ -86,6 +92,7 @@ class OcfCtx:
self.lib.ocf_ctx_unregister_volume_type(self.ctx_handle, vol_type.type_id)
del self.volume_types[vol_type.type_id]
del self.ocf_volume_type[vol_type]
def cleanup_volume_types(self):
for k, vol_type in list(self.volume_types.items()):
@ -108,3 +115,5 @@ class OcfCtx:
lib = OcfLib.getInstance()
lib.ocf_mngt_cache_get_by_name.argtypes = [c_void_p, c_void_p, c_void_p]
lib.ocf_mngt_cache_get_by_name.restype = c_int
lib.ocf_ctx_get_volume_type.argtypes = [c_void_p, c_uint8]
lib.ocf_ctx_get_volume_type.restype = c_void_p

View File

@ -47,7 +47,9 @@ class VolumeOps(Structure):
SUBMIT_METADATA = CFUNCTYPE(None, c_void_p)
SUBMIT_DISCARD = CFUNCTYPE(None, c_void_p)
SUBMIT_WRITE_ZEROES = CFUNCTYPE(None, c_void_p)
OPEN = CFUNCTYPE(c_int, c_void_p)
ON_INIT = CFUNCTYPE(c_int, c_void_p)
ON_DEINIT = CFUNCTYPE(None, c_void_p)
OPEN = CFUNCTYPE(c_int, c_void_p, c_void_p)
CLOSE = CFUNCTYPE(None, c_void_p)
GET_MAX_IO_SIZE = CFUNCTYPE(c_uint, c_void_p)
GET_LENGTH = CFUNCTYPE(c_uint64, c_void_p)
@ -58,6 +60,8 @@ class VolumeOps(Structure):
("_submit_metadata", SUBMIT_METADATA),
("_submit_discard", SUBMIT_DISCARD),
("_submit_write_zeroes", SUBMIT_WRITE_ZEROES),
("_on_init", ON_INIT),
("_on_deinit", ON_DEINIT),
("_open", OPEN),
("_close", CLOSE),
("_get_length", GET_LENGTH),
@ -124,8 +128,16 @@ class Volume:
def _submit_write_zeroes(write_zeroes):
raise NotImplementedError
@VolumeOps.ON_INIT
def _on_init(ref):
return 0
@VolumeOps.ON_DEINIT
def _on_deinit(ref):
return
@VolumeOps.OPEN
def _open(ref):
def _open(ref, params):
uuid_ptr = cast(OcfLib.getInstance().ocf_volume_get_uuid(ref), POINTER(Uuid))
uuid = str(uuid_ptr.contents._data, encoding="ascii")
try:
@ -161,6 +173,8 @@ class Volume:
_close=_close,
_get_max_io_size=_get_max_io_size,
_get_length=_get_length,
_on_init=_on_init,
_on_deinit=_on_deinit,
)
return Volume._ops_[cls]

View File

@ -74,6 +74,8 @@ def test_io_flags(pyocf_ctx, cache_mode):
data = bytes(block_size)
pyocf_ctx.register_volume_type(FlagsValVolume)
cache_device = FlagsValVolume(Size.from_MiB(50), flags)
core_device = FlagsValVolume(Size.from_MiB(50), flags)

View File

@ -63,6 +63,8 @@ def test_flush_after_mngmt(pyocf_ctx):
data = bytes(block_size)
pyocf_ctx.register_volume_type(FlushValVolume)
cache_device = FlushValVolume(Size.from_MiB(50))
core_device = FlushValVolume(Size.from_MiB(50))

View File

@ -0,0 +1,276 @@
#
# Copyright(c) 2022 Intel Corporation
# SPDX-License-Identifier: BSD-3-Clause
#
import pytest
@pytest.mark.skip(reason="not implemented")
def test_create_composite_volume(pyocf_ctx):
"""
title: Create composite volume.
description: |
Check that it is possible to create and destroy composite volume
object.
pass_criteria:
- Composite volume is created without an error.
- Subvolume is added without an error.
steps:
- Create composite volume
- Verify that no error occured
- Add RamVolume as a subvolume
- Verify that no error occured
- Destroy composite volume
requirements:
- composite_volume::creation
- composite_volume::adding_component_volume
"""
pass
@pytest.mark.skip(reason="not implemented")
def test_add_subvolumes_of_different_types(pyocf_ctx):
"""
title: Add subvolumes of different types.
description: |
Check that it is possible to add two subvolumes of different types to
composite volume.
pass_criteria:
- Composite volume is created without an error.
- Subvolumes are added without an error.
steps:
- Create composite volume
- Add RamVolume as a subvolume
- Verify that no error occured
- Add ErrorDevice as a subvolume
- Verify that no error occured
- Destroy composite volume
requirements:
- composite_volume::component_volume_types
"""
pass
@pytest.mark.skip(reason="not implemented")
def test_add_max_subvolumes(pyocf_ctx):
"""
title: Add maximum number of subvolumes.
description: |
Check that it is possible to add 16 subvolumes to composite volume.
pass_criteria:
- Composite volume is created without an error.
- Subvolumes are added without an error.
steps:
- Create composite volume
- Add 16 RamVolume instances as subvolumes
- Verify that no error occured
- Destroy composite volume
requirements:
- composite_volume::max_composite_volumes
"""
pass
@pytest.mark.skip(reason="not implemented")
def test_basic_volume_operations(pyocf_ctx):
"""
title: Perform basic volume operations.
description: |
Check that basic volume operations work on composite volume.
pass_criteria:
- Composite volume is created without an error.
- Subvolume is added without an error.
- Submit io, submit flush and submit discard operations work properly.
steps:
- Create composite volume
- Add mock volume as a subvolume
- Submit io to composite volume and check if it was propagated
- Submit flush to composite volume and check if it was propagated
- Submit discard to composite volume and check if it was propagated
- Destroy composite volume
requirements:
- composite_volume::volume_api
- composite_volume::io_request_passing
"""
pass
@pytest.mark.skip(reason="not implemented")
def test_io_propagation_basic(pyocf_ctx):
"""
title: Perform volume operations with multiple subvolumes.
description: |
Check that io operations are propagated properly to subvolumes.
pass_criteria:
- Composite volume is created without an error.
- Subvolumes are added without an error.
- Operations are propagated properly.
steps:
- Create composite volume
- Add 16 mock volumes as subvolumes
- Submit io to each subvolume address range
- Check if requests were propagated properly
- Submit flush to each subvolume address range
- Check if requests were propagated properly
- Submit discard to each subvolume address range
- Check if requests were propagated properly
- Destroy composite volume
requirements:
- composite_volume::volume_api
- composite_volume::io_request_passing
"""
pass
@pytest.mark.skip(reason="not implemented")
def test_io_propagation_cross_boundary(pyocf_ctx):
"""
title: Perform cross-subvolume operations.
description: |
Check that cross-subvolume operations are propagated properly.
pass_criteria:
- Composite volume is created without an error.
- Subvolumes are added without an error.
- Operations are propagated properly.
steps:
- Create composite volume
- Add 16 mock volumes as subvolumes
- Submit io that cross address range boundary between each subvolume
- Check if requests were propagated properly
- Submit flush that cross address range boundary between each subvolume
- Check if requests were propagated properly
- Submit discard that cross address range boundary between each subvolume
- Check if requests were propagated properly
- Destroy composite volume
requirements:
- composite_volume::io_request_passing
"""
pass
@pytest.mark.skip(reason="not implemented")
def test_io_propagation_multiple_subvolumes(pyocf_ctx):
"""
title: Perform multi-subvolume operations.
description: |
Check that multi-subvolume operations are propagated properly.
pass_criteria:
- Composite volume is created without an error.
- Subvolumes are added without an error.
- Operations are propagated properly.
steps:
- Create composite volume
- Add 16 mock volumes as subvolumes
- Submit series of ios that touch from 2 to 16 subvolumes
- Check if requests were propated properly
- Submit series of flushes that touch from 2 to 16 subvolumes
- Check if requests were propagated properly
- Submit series of discardss that touch from 2 to 16 subvolumes
- Check if requests were propagated properly
- Destroy composite volume
requirements:
- composite_volume::io_request_passing
"""
pass
@pytest.mark.skip(reason="not implemented")
def test_io_completion(pyocf_ctx):
"""
title: Composite volume completion order.
description: |
Check that composite volume waits for completions from all subvolumes.
pass_criteria:
- Composite volume is created without an error.
- Subvolumes are added without an error.
- Operations are completed only after all subvolumes operations complete.
steps:
- Create composite volume
- Add 16 mock volumes as subvolumes
- Submit series of ios that touch from 2 to 16 subvolumes
- Check if completions are called only after all subvolumes completed
- Submit series of flushes that touch from 2 to 16 subvolumes
- Check if completions are called only after all subvolumes completed
- Submit series of discardss that touch from 2 to 16 subvolumes
- Check if completions are called only after all subvolumes completed
- Destroy composite volume
requirements:
- composite_volume::io_request_completion
"""
pass
@pytest.mark.skip(reason="not implemented")
def test_io_completion(pyocf_ctx):
"""
title: Composite volume error propagation.
description: |
Check that composite volume propagates errors from subvolumes.
pass_criteria:
- Composite volume is created without an error.
- Subvolumes are added without an error.
- Errors from subvolumes are propagated to composite volume.
steps:
- Create composite volume
- Add 16 ErrorDevice instances as subvolumes
- Before each request arm one of ErrorDevices touched by this request
- Submit series of ios that touch from 2 to 16 subvolumes
- Check if errors were propagated properly
- Submit series of flushes that touch from 2 to 16 subvolumes
- Check if errors were propagated properly
- Submit series of discardss that touch from 2 to 16 subvolumes
- Check if errors were propagated properly
- Destroy composite volume
requirements:
- composite_volume::io_error_handling
"""
pass
@pytest.mark.skip(reason="not implemented")
def test_attach(pyocf_ctx):
"""
title: Attach composite volume.
description: |
Check that it is possible to attach composite volume
pass_criteria:
- Composite volume is created without an error.
- Subvolumes are added without an error.
- Cache attach succeeds.
steps:
- Create composite volume
- Add 16 RamVolume instances as subvolumes.
- Start cache and attach it using composite volume instance.
- Verify that cache was attached properly.
- Stop the cache.
- Verify that cache was stopped.
requirements:
- composite_volume::cache_attach_load
"""
pass
@pytest.mark.skip(reason="not implemented")
def test_load(pyocf_ctx):
"""
title: Load composite volume.
description: |
Check that it is possible to attach composite volume
pass_criteria:
- Composite volume is created without an error.
- Subvolumes are added without an error.
- Cache load succeeds.
steps:
- Create composite volume
- Add 16 RamVolume instances as subvolumes.
- Start cache and attach it using composite volume instance.
- Stop the cache.
- Start cache and load it using composite volume instance.
- Verify that cache was loaded properly.
- Stop the cache.
- Verify that cache was stopped.
requirements:
- composite_volume::cache_attach_load
"""
pass