lib/reduce: add functions to get pm and backing sizes
A compressed volume will require both a persistent memory region/file for per-chunk metadata and a backing device to store the compressed blocks. Add functions here to calculate the sizes of these based on the desired size of the compressed volume, its chunk size and the size of each backing block. Signed-off-by: Jim Harris <james.r.harris@intel.com> Change-Id: I9203479e2a268c3ab0e2b0e06e348285e9d1cd13 Reviewed-on: https://review.gerrithub.io/430387 Tested-by: SPDK CI Jenkins <sys_sgci@intel.com> Chandler-Test-Pool: SPDK Automated Test System <sys_sgsw@intel.com> Reviewed-by: Shuhei Matsumoto <shuhei.matsumoto.xt@hitachi.com> Reviewed-by: Ben Walker <benjamin.walker@intel.com>
This commit is contained in:
parent
6bf35070c6
commit
dd42c80857
@ -38,4 +38,50 @@
|
||||
#ifndef SPDK_REDUCE_H_
|
||||
#define SPDK_REDUCE_H_
|
||||
|
||||
#include "spdk/uuid.h"
|
||||
|
||||
/**
|
||||
* Describes the parameters of an spdk_reduce_vol.
|
||||
*/
|
||||
struct spdk_reduce_vol_params {
|
||||
/**
|
||||
* Size in bytes of the IO unit for the backing device. This
|
||||
* is the unit in which space is allocated from the backing
|
||||
* device, and the unit in which data is read from of written
|
||||
* to the backing device. Must be greater than 0.
|
||||
*/
|
||||
uint32_t backing_io_unit_size;
|
||||
|
||||
/**
|
||||
* Size in bytes of a chunk on the compressed volume. This
|
||||
* is the unit in which data is compressed. Must be an even
|
||||
* multiple of backing_io_unit_size. Must be greater than 0.
|
||||
*/
|
||||
uint32_t chunk_size;
|
||||
|
||||
/**
|
||||
* Total size in bytes of the compressed volume. Must be
|
||||
* an even multiple of chunk_size. Must be greater than 0.
|
||||
*/
|
||||
uint64_t vol_size;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the required size for the pm file for a compressed volume.
|
||||
*
|
||||
* \param params Parameters for the compressed volume
|
||||
* \return Size of the required pm file (in bytes) needed to create the
|
||||
* compressed volume. Returns -EINVAL if params is invalid.
|
||||
*/
|
||||
int64_t spdk_reduce_get_pm_file_size(struct spdk_reduce_vol_params *params);
|
||||
|
||||
/**
|
||||
* Get the required size for the backing device for a compressed volume.
|
||||
*
|
||||
* \param params Parameters for the compressed volume
|
||||
* \return Size of the required backing device (in bytes) needed to create
|
||||
* the compressed volume. Returns -EINVAL if params is invalid.
|
||||
*/
|
||||
int64_t spdk_reduce_get_backing_device_size(struct spdk_reduce_vol_params *params);
|
||||
|
||||
#endif /* SPDK_REDUCE_H_ */
|
||||
|
@ -36,4 +36,122 @@
|
||||
#include "spdk/reduce.h"
|
||||
#include "spdk_internal/log.h"
|
||||
|
||||
/* Always round up the size of the PM region to the nearest cacheline. */
|
||||
#define REDUCE_PM_SIZE_ALIGNMENT 64
|
||||
|
||||
/* Structure written to offset 0 of both the pm file and the backing device. */
|
||||
struct spdk_reduce_vol_superblock {
|
||||
struct spdk_reduce_vol_params params;
|
||||
uint8_t reserved[4080];
|
||||
};
|
||||
SPDK_STATIC_ASSERT(sizeof(struct spdk_reduce_vol_superblock) == 4096, "size incorrect");
|
||||
|
||||
struct spdk_reduce_vol {
|
||||
};
|
||||
|
||||
/*
|
||||
* Allocate extra metadata chunks and corresponding backing io units to account for
|
||||
* outstanding IO in worst case scenario where logical map is completely allocated
|
||||
* and no data can be compressed. We need extra chunks in this case to handle
|
||||
* in-flight writes since reduce never writes data in place.
|
||||
*/
|
||||
#define REDUCE_NUM_EXTRA_CHUNKS 128
|
||||
|
||||
static inline uint64_t
|
||||
divide_round_up(uint64_t num, uint64_t divisor)
|
||||
{
|
||||
return (num + divisor - 1) / divisor;
|
||||
}
|
||||
|
||||
static uint64_t
|
||||
_get_pm_logical_map_size(uint64_t vol_size, uint64_t chunk_size)
|
||||
{
|
||||
uint64_t chunks_in_logical_map, logical_map_size;
|
||||
|
||||
chunks_in_logical_map = vol_size / chunk_size;
|
||||
logical_map_size = chunks_in_logical_map * sizeof(uint64_t);
|
||||
|
||||
/* Round up to next cacheline. */
|
||||
return divide_round_up(logical_map_size, 64) * 64;
|
||||
}
|
||||
|
||||
static uint64_t
|
||||
_get_total_chunks(uint64_t vol_size, uint64_t chunk_size)
|
||||
{
|
||||
uint64_t num_chunks;
|
||||
|
||||
num_chunks = vol_size / chunk_size;
|
||||
num_chunks += REDUCE_NUM_EXTRA_CHUNKS;
|
||||
|
||||
return num_chunks;
|
||||
}
|
||||
|
||||
static uint64_t
|
||||
_get_pm_total_chunks_size(uint64_t vol_size, uint64_t chunk_size, uint64_t backing_io_unit_size)
|
||||
{
|
||||
uint64_t io_units_per_chunk, num_chunks, total_chunks_size;
|
||||
|
||||
num_chunks = _get_total_chunks(vol_size, chunk_size);
|
||||
io_units_per_chunk = chunk_size / backing_io_unit_size;
|
||||
total_chunks_size = num_chunks * io_units_per_chunk * sizeof(uint64_t);
|
||||
|
||||
return divide_round_up(total_chunks_size, REDUCE_PM_SIZE_ALIGNMENT) * REDUCE_PM_SIZE_ALIGNMENT;
|
||||
}
|
||||
|
||||
static int
|
||||
_validate_vol_params(struct spdk_reduce_vol_params *params)
|
||||
{
|
||||
if (params->vol_size == 0 || params->chunk_size == 0 || params->backing_io_unit_size == 0) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Chunk size must be an even multiple of the backing io unit size. */
|
||||
if ((params->chunk_size % params->backing_io_unit_size) != 0) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Volume size must be an even multiple of the chunk size. */
|
||||
if ((params->vol_size % params->chunk_size) != 0) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int64_t
|
||||
spdk_reduce_get_pm_file_size(struct spdk_reduce_vol_params *params)
|
||||
{
|
||||
uint64_t total_pm_size;
|
||||
int rc;
|
||||
|
||||
rc = _validate_vol_params(params);
|
||||
if (rc != 0) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
total_pm_size = sizeof(struct spdk_reduce_vol_superblock);
|
||||
total_pm_size += _get_pm_logical_map_size(params->vol_size, params->chunk_size);
|
||||
total_pm_size += _get_pm_total_chunks_size(params->vol_size, params->chunk_size,
|
||||
params->backing_io_unit_size);
|
||||
return total_pm_size;
|
||||
}
|
||||
|
||||
int64_t
|
||||
spdk_reduce_get_backing_device_size(struct spdk_reduce_vol_params *params)
|
||||
{
|
||||
uint64_t total_backing_size, num_chunks;
|
||||
int rc;
|
||||
|
||||
rc = _validate_vol_params(params);
|
||||
if (rc != 0) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
num_chunks = _get_total_chunks(params->vol_size, params->chunk_size);
|
||||
total_backing_size = num_chunks * params->chunk_size;
|
||||
total_backing_size += sizeof(struct spdk_reduce_vol_superblock);
|
||||
|
||||
return total_backing_size;
|
||||
}
|
||||
|
||||
SPDK_LOG_REGISTER_COMPONENT("reduce", SPDK_LOG_REDUCE)
|
||||
|
@ -39,9 +39,85 @@
|
||||
#include "common/lib/test_env.c"
|
||||
|
||||
static void
|
||||
empty_test(void)
|
||||
get_pm_file_size(void)
|
||||
{
|
||||
CU_ASSERT(true);
|
||||
struct spdk_reduce_vol_params params;
|
||||
int64_t pm_size, expected_pm_size;
|
||||
|
||||
params.vol_size = 0;
|
||||
params.chunk_size = 0;
|
||||
params.backing_io_unit_size = 0;
|
||||
CU_ASSERT(spdk_reduce_get_pm_file_size(¶ms) == -EINVAL);
|
||||
|
||||
/*
|
||||
* Select a valid backing_io_unit_size. This should still fail since
|
||||
* vol_size and chunk_size are still 0.
|
||||
*/
|
||||
params.backing_io_unit_size = 4096;
|
||||
CU_ASSERT(spdk_reduce_get_pm_file_size(¶ms) == -EINVAL);
|
||||
|
||||
/*
|
||||
* Select a valid chunk_size. This should still fail since val_size
|
||||
* is still 0.
|
||||
*/
|
||||
params.chunk_size = 4096 * 4;
|
||||
CU_ASSERT(spdk_reduce_get_pm_file_size(¶ms) == -EINVAL);
|
||||
|
||||
/* Select a valid vol_size. This should return a proper pm_size. */
|
||||
params.vol_size = 4096 * 4 * 100;
|
||||
pm_size = spdk_reduce_get_pm_file_size(¶ms);
|
||||
expected_pm_size = sizeof(struct spdk_reduce_vol_superblock);
|
||||
/* 100 chunks in logical map * 8 bytes per chunk */
|
||||
expected_pm_size += 100 * sizeof(uint64_t);
|
||||
/* 100 chunks * 4 backing io units per chunk * 8 bytes per backing io unit */
|
||||
expected_pm_size += 100 * 4 * sizeof(uint64_t);
|
||||
/* reduce allocates some extra chunks too for in-flight writes when logical map
|
||||
* is full. REDUCE_EXTRA_CHUNKS is a private #ifdef in reduce.c.
|
||||
*/
|
||||
expected_pm_size += REDUCE_NUM_EXTRA_CHUNKS * 4 * sizeof(uint64_t);
|
||||
/* reduce will add some padding so numbers may not match exactly. Make sure
|
||||
* they are close though.
|
||||
*/
|
||||
CU_ASSERT((pm_size - expected_pm_size) < REDUCE_PM_SIZE_ALIGNMENT);
|
||||
}
|
||||
|
||||
static void
|
||||
get_backing_device_size(void)
|
||||
{
|
||||
struct spdk_reduce_vol_params params;
|
||||
int64_t backing_size, expected_backing_size;
|
||||
|
||||
params.vol_size = 0;
|
||||
params.chunk_size = 0;
|
||||
params.backing_io_unit_size = 0;
|
||||
CU_ASSERT(spdk_reduce_get_backing_device_size(¶ms) == -EINVAL);
|
||||
|
||||
/*
|
||||
* Select a valid backing_io_unit_size. This should still fail since
|
||||
* vol_size and chunk_size are still 0.
|
||||
*/
|
||||
params.backing_io_unit_size = 4096;
|
||||
CU_ASSERT(spdk_reduce_get_backing_device_size(¶ms) == -EINVAL);
|
||||
|
||||
/*
|
||||
* Select a valid chunk_size. This should still fail since val_size
|
||||
* is still 0.
|
||||
*/
|
||||
params.chunk_size = 4096 * 4;
|
||||
CU_ASSERT(spdk_reduce_get_backing_device_size(¶ms) == -EINVAL);
|
||||
|
||||
/* Select a valid vol_size. This should return a proper backing device size. */
|
||||
params.vol_size = 4096 * 4 * 100;
|
||||
backing_size = spdk_reduce_get_backing_device_size(¶ms);
|
||||
expected_backing_size = params.vol_size;
|
||||
/* reduce allocates some extra chunks too for in-flight writes when logical map
|
||||
* is full. REDUCE_EXTRA_CHUNKS is a private #ifdef in reduce.c. Backing device
|
||||
* must have space allocated for these extra chunks.
|
||||
*/
|
||||
expected_backing_size += REDUCE_NUM_EXTRA_CHUNKS * params.chunk_size;
|
||||
/* Account for superblock as well. */
|
||||
expected_backing_size += sizeof(struct spdk_reduce_vol_superblock);
|
||||
CU_ASSERT(backing_size == expected_backing_size);
|
||||
}
|
||||
|
||||
int
|
||||
@ -61,7 +137,8 @@ main(int argc, char **argv)
|
||||
}
|
||||
|
||||
if (
|
||||
CU_add_test(suite, "empty", empty_test) == NULL
|
||||
CU_add_test(suite, "get_pm_file_size", get_pm_file_size) == NULL ||
|
||||
CU_add_test(suite, "get_backing_device_size", get_backing_device_size) == NULL
|
||||
) {
|
||||
CU_cleanup_registry();
|
||||
return CU_get_error();
|
||||
|
Loading…
Reference in New Issue
Block a user