ftl: support for metadata on shared memory
Signed-off-by: Artur Paszkiewicz <artur.paszkiewicz@intel.com> Signed-off-by: Kozlowski Mateusz <mateusz.kozlowski@intel.com> Change-Id: Ibc259f61f0ef2aeadb0e5ac7230969e29d77f184 Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/13340 Reviewed-by: Jim Harris <james.r.harris@intel.com> Reviewed-by: Ben Walker <benjamin.walker@intel.com> Tested-by: SPDK CI Jenkins <sys_sgci@intel.com>
This commit is contained in:
parent
aaa1ddc3b0
commit
818b9c053b
@ -50,6 +50,7 @@ ftl_mngt_init_md(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
|
||||
struct ftl_layout *layout = &dev->layout;
|
||||
struct ftl_layout_region *region = layout->region;
|
||||
uint64_t i;
|
||||
int md_flags;
|
||||
|
||||
for (i = 0; i < FTL_LAYOUT_REGION_TYPE_MAX; i++, region++) {
|
||||
if (layout->md[i]) {
|
||||
@ -61,8 +62,11 @@ ftl_mngt_init_md(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
|
||||
*/
|
||||
continue;
|
||||
}
|
||||
md_flags = is_buffer_needed(i) ?
|
||||
FTL_MD_CREATE_SHM | FTL_MD_CREATE_SHM_NEW :
|
||||
FTL_MD_CREATE_NO_MEM;
|
||||
layout->md[i] = ftl_md_create(dev, region->current.blocks, region->vss_blksz, region->name,
|
||||
!is_buffer_needed(i), region);
|
||||
md_flags, region);
|
||||
if (NULL == layout->md[i]) {
|
||||
ftl_mngt_fail_step(mngt);
|
||||
return;
|
||||
@ -245,6 +249,7 @@ ftl_mngt_superblock_init(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt
|
||||
struct ftl_layout *layout = &dev->layout;
|
||||
struct ftl_layout_region *region = &layout->region[FTL_LAYOUT_REGION_TYPE_SB];
|
||||
char uuid[SPDK_UUID_STRING_LEN];
|
||||
int md_create_flags = FTL_MD_CREATE_SHM | FTL_MD_CREATE_SHM_NEW;
|
||||
|
||||
/* Must generate UUID before MD create on SHM for the SB */
|
||||
if (dev->conf.mode & SPDK_FTL_MODE_CREATE) {
|
||||
@ -261,7 +266,8 @@ ftl_mngt_superblock_init(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt
|
||||
|
||||
/* Allocate md buf */
|
||||
layout->md[FTL_LAYOUT_REGION_TYPE_SB] = ftl_md_create(dev, region->current.blocks,
|
||||
region->vss_blksz, region->name, false, region);
|
||||
region->vss_blksz, region->name,
|
||||
md_create_flags, region);
|
||||
if (NULL == layout->md[FTL_LAYOUT_REGION_TYPE_SB]) {
|
||||
ftl_mngt_fail_step(mngt);
|
||||
return;
|
||||
@ -273,7 +279,7 @@ ftl_mngt_superblock_init(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt
|
||||
/* Setup superblock mirror to QLC */
|
||||
region = &layout->region[FTL_LAYOUT_REGION_TYPE_SB_BASE];
|
||||
layout->md[FTL_LAYOUT_REGION_TYPE_SB_BASE] = ftl_md_create(dev, region->current.blocks,
|
||||
region->vss_blksz, NULL, false, region);
|
||||
region->vss_blksz, NULL, FTL_MD_CREATE_HEAP, region);
|
||||
if (NULL == layout->md[FTL_LAYOUT_REGION_TYPE_SB_BASE]) {
|
||||
ftl_mngt_fail_step(mngt);
|
||||
return;
|
||||
|
@ -61,8 +61,194 @@ xfer_size(struct ftl_md *md)
|
||||
return ftl_md_xfer_blocks(md->dev) * FTL_BLOCK_SIZE;
|
||||
}
|
||||
|
||||
static void
|
||||
ftl_md_create_heap(struct ftl_md *md, uint64_t vss_blksz)
|
||||
{
|
||||
md->shm_fd = -1;
|
||||
md->vss_data = NULL;
|
||||
md->data = calloc(md->data_blocks, FTL_BLOCK_SIZE + vss_blksz);
|
||||
|
||||
if (md->data && vss_blksz) {
|
||||
md->vss_data = ((char *)md->data) + md->data_blocks * FTL_BLOCK_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
ftl_md_destroy_heap(struct ftl_md *md)
|
||||
{
|
||||
if (md->data) {
|
||||
free(md->data);
|
||||
md->data = NULL;
|
||||
md->vss_data = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
ftl_wrapper_open(const char *name, int of, mode_t m)
|
||||
{
|
||||
return open(name, of, m);
|
||||
}
|
||||
|
||||
static void
|
||||
ftl_md_setup_obj(struct ftl_md *md, int flags,
|
||||
const char *name)
|
||||
{
|
||||
char uuid_str[SPDK_UUID_STRING_LEN];
|
||||
const char *fmt;
|
||||
|
||||
if (!(flags & FTL_MD_CREATE_SHM)) {
|
||||
assert(false);
|
||||
return;
|
||||
}
|
||||
|
||||
/* TODO: temporary, define a proper hugetlbfs mountpoint */
|
||||
fmt = "/dev/hugepages/ftl_%s_%s";
|
||||
md->shm_mmap_flags = MAP_SHARED;
|
||||
md->shm_open = ftl_wrapper_open;
|
||||
md->shm_unlink = unlink;
|
||||
|
||||
if (name == NULL ||
|
||||
spdk_uuid_fmt_lower(uuid_str, SPDK_UUID_STRING_LEN, &md->dev->conf.uuid) ||
|
||||
snprintf(md->name, sizeof(md->name) / sizeof(md->name[0]),
|
||||
fmt, uuid_str, name) <= 0) {
|
||||
md->name[0] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
ftl_md_create_shm(struct ftl_md *md, uint64_t vss_blksz, int flags)
|
||||
{
|
||||
struct stat shm_stat;
|
||||
size_t vss_blk_offs;
|
||||
void *shm_ptr;
|
||||
int open_flags = O_RDWR;
|
||||
mode_t open_mode = S_IRUSR | S_IWUSR;
|
||||
|
||||
assert(md->shm_open && md->shm_unlink);
|
||||
md->data = NULL;
|
||||
md->vss_data = NULL;
|
||||
md->shm_sz = 0;
|
||||
|
||||
/* Must have an object name */
|
||||
if (md->name[0] == 0) {
|
||||
assert(false);
|
||||
return;
|
||||
}
|
||||
|
||||
/* If specified, unlink before create a new SHM object */
|
||||
if (flags & FTL_MD_CREATE_SHM_NEW) {
|
||||
if (md->shm_unlink(md->name) < 0 && errno != ENOENT) {
|
||||
return;
|
||||
}
|
||||
open_flags += O_CREAT | O_TRUNC;
|
||||
}
|
||||
|
||||
/* Open existing or create a new SHM object, then query its props */
|
||||
md->shm_fd = md->shm_open(md->name, open_flags, open_mode);
|
||||
if (md->shm_fd < 0 || fstat(md->shm_fd, &shm_stat) < 0) {
|
||||
goto err_shm;
|
||||
}
|
||||
|
||||
/* Verify open mode hasn't changed */
|
||||
if ((shm_stat.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO)) != open_mode) {
|
||||
goto err_shm;
|
||||
}
|
||||
|
||||
/* Round up the SHM obj size to the nearest blk size (i.e. page size) */
|
||||
md->shm_sz = spdk_divide_round_up(md->data_blocks * FTL_BLOCK_SIZE, shm_stat.st_blksize);
|
||||
|
||||
/* Add some blks for VSS metadata */
|
||||
vss_blk_offs = md->shm_sz;
|
||||
|
||||
if (vss_blksz) {
|
||||
md->shm_sz += spdk_divide_round_up(md->data_blocks * vss_blksz,
|
||||
shm_stat.st_blksize);
|
||||
}
|
||||
|
||||
/* Total SHM obj size */
|
||||
md->shm_sz *= shm_stat.st_blksize;
|
||||
|
||||
/* Set or check the object size - zero init`d in case of set (FTL_MD_CREATE_SHM_NEW) */
|
||||
if ((shm_stat.st_size == 0 && (ftruncate(md->shm_fd, md->shm_sz) < 0 ||
|
||||
(flags & FTL_MD_CREATE_SHM_NEW) == 0))
|
||||
|| (shm_stat.st_size > 0 && (size_t)shm_stat.st_size != md->shm_sz)) {
|
||||
goto err_shm;
|
||||
}
|
||||
|
||||
/* Create a virtual memory mapping for the object */
|
||||
shm_ptr = mmap(NULL, md->shm_sz, PROT_READ | PROT_WRITE, md->shm_mmap_flags,
|
||||
md->shm_fd, 0);
|
||||
if (shm_ptr == MAP_FAILED) {
|
||||
goto err_shm;
|
||||
}
|
||||
|
||||
md->data = shm_ptr;
|
||||
if (vss_blksz) {
|
||||
md->vss_data = ((char *)shm_ptr) + vss_blk_offs * shm_stat.st_blksize;
|
||||
}
|
||||
|
||||
/* Lock the pages in memory (i.e. prevent the pages to be paged out) */
|
||||
if (mlock(md->data, md->shm_sz) < 0) {
|
||||
goto err_map;
|
||||
}
|
||||
|
||||
if (spdk_mem_register(md->data, md->shm_sz)) {
|
||||
goto err_mlock;
|
||||
}
|
||||
md->mem_reg = true;
|
||||
|
||||
return;
|
||||
|
||||
/* Cleanup upon fault */
|
||||
err_mlock:
|
||||
munlock(md->data, md->shm_sz);
|
||||
|
||||
err_map:
|
||||
munmap(md->data, md->shm_sz);
|
||||
md->data = NULL;
|
||||
md->vss_data = NULL;
|
||||
md->shm_sz = 0;
|
||||
|
||||
err_shm:
|
||||
if (md->shm_fd >= 0) {
|
||||
close(md->shm_fd);
|
||||
md->shm_unlink(md->name);
|
||||
md->shm_fd = -1;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
ftl_md_destroy_shm(struct ftl_md *md)
|
||||
{
|
||||
if (!md->data) {
|
||||
return;
|
||||
}
|
||||
|
||||
assert(md->shm_sz > 0);
|
||||
if (md->mem_reg) {
|
||||
spdk_mem_unregister(md->data, md->shm_sz);
|
||||
md->mem_reg = false;
|
||||
}
|
||||
|
||||
/* Unlock the pages in memory */
|
||||
munlock(md->data, md->shm_sz);
|
||||
|
||||
/* Remove the virtual memory mapping for the object */
|
||||
munmap(md->data, md->shm_sz);
|
||||
|
||||
/* Close SHM object fd */
|
||||
close(md->shm_fd);
|
||||
|
||||
md->data = NULL;
|
||||
md->vss_data = NULL;
|
||||
|
||||
/* Otherwise destroy/unlink the object */
|
||||
assert(md->name[0] != 0 && md->shm_unlink != NULL);
|
||||
md->shm_unlink(md->name);
|
||||
}
|
||||
|
||||
struct ftl_md *ftl_md_create(struct spdk_ftl_dev *dev, uint64_t blocks,
|
||||
uint64_t vss_blksz, const char *name, bool no_mem,
|
||||
uint64_t vss_blksz, const char *name, int flags,
|
||||
const struct ftl_layout_region *region)
|
||||
{
|
||||
struct ftl_md *md;
|
||||
@ -75,20 +261,19 @@ struct ftl_md *ftl_md_create(struct spdk_ftl_dev *dev, uint64_t blocks,
|
||||
md->data_blocks = blocks;
|
||||
md->mirror_enabled = true;
|
||||
|
||||
if (!no_mem) {
|
||||
size_t buf_size = md->data_blocks * (FTL_BLOCK_SIZE + vss_blksz);
|
||||
int ret;
|
||||
if (flags != FTL_MD_CREATE_NO_MEM) {
|
||||
if (flags & FTL_MD_CREATE_SHM) {
|
||||
ftl_md_setup_obj(md, flags, name);
|
||||
ftl_md_create_shm(md, vss_blksz, flags);
|
||||
} else {
|
||||
assert((flags & FTL_MD_CREATE_HEAP) == FTL_MD_CREATE_HEAP);
|
||||
ftl_md_create_heap(md, vss_blksz);
|
||||
}
|
||||
|
||||
ret = posix_memalign((void **)&md->data, FTL_BLOCK_SIZE, buf_size);
|
||||
if (ret) {
|
||||
if (!md->data) {
|
||||
free(md);
|
||||
return NULL;
|
||||
}
|
||||
memset(md->data, 0, buf_size);
|
||||
|
||||
if (vss_blksz) {
|
||||
md->vss_data = ((char *)md->data) + md->data_blocks * FTL_BLOCK_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
if (region) {
|
||||
@ -114,6 +299,22 @@ err:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int
|
||||
ftl_md_unlink(struct spdk_ftl_dev *dev, const char *name, int flags)
|
||||
{
|
||||
struct ftl_md md = { 0 };
|
||||
|
||||
if (0 == (flags & FTL_MD_CREATE_SHM)) {
|
||||
/* Unlink can be called for shared memory only */
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
md.dev = dev;
|
||||
ftl_md_setup_obj(&md, flags, name);
|
||||
|
||||
return md.shm_unlink(md.name);
|
||||
}
|
||||
|
||||
void
|
||||
ftl_md_destroy(struct ftl_md *md)
|
||||
{
|
||||
@ -136,10 +337,10 @@ ftl_md_free_buf(struct ftl_md *md)
|
||||
return;
|
||||
}
|
||||
|
||||
if (md->data) {
|
||||
free(md->data);
|
||||
md->data = NULL;
|
||||
md->vss_data = NULL;
|
||||
if (md->shm_fd < 0) {
|
||||
ftl_md_destroy_heap(md);
|
||||
} else {
|
||||
ftl_md_destroy_shm(md);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -20,6 +20,9 @@ enum ftl_md_ops {
|
||||
FTL_MD_OP_CLEAR,
|
||||
};
|
||||
|
||||
typedef int (*shm_open_t)(const char *, int, mode_t);
|
||||
typedef int (*shm_unlink_t)(const char *);
|
||||
|
||||
/* FTL metadata container which allows to store/restore/recover */
|
||||
struct ftl_md {
|
||||
/* Context of owner (Caller of restore/persist/clear operation) */
|
||||
@ -64,6 +67,27 @@ struct ftl_md {
|
||||
struct spdk_bdev_io_wait_entry bdev_io_wait;
|
||||
} io;
|
||||
|
||||
/* SHM object file descriptor or -1 if heap alloc */
|
||||
int shm_fd;
|
||||
|
||||
/* Object name */
|
||||
char name[NAME_MAX + 1];
|
||||
|
||||
/* mmap flags for the SHM object */
|
||||
int shm_mmap_flags;
|
||||
|
||||
/* Total size of SHM object (data + md) */
|
||||
size_t shm_sz;
|
||||
|
||||
/* open() for the SHM object */
|
||||
shm_open_t shm_open;
|
||||
|
||||
/* unlink() for the SHM object */
|
||||
shm_unlink_t shm_unlink;
|
||||
|
||||
/* Memory was registered to SPDK */
|
||||
bool mem_reg;
|
||||
|
||||
/* Metadata primary object */
|
||||
struct ftl_md *mirror;
|
||||
|
||||
@ -104,6 +128,23 @@ union ftl_md_vss {
|
||||
|
||||
SPDK_STATIC_ASSERT(sizeof(union ftl_md_vss) == FTL_MD_VSS_SZ, "Invalid md vss size");
|
||||
|
||||
/**
|
||||
* FTL metadata creation flags
|
||||
*/
|
||||
enum ftl_md_create_flags {
|
||||
/** FTL metadata will be created without memory allocation */
|
||||
FTL_MD_CREATE_NO_MEM = 0x0,
|
||||
|
||||
/** FTL metadata data buf will be allocated in SHM */
|
||||
FTL_MD_CREATE_SHM = 0x1,
|
||||
|
||||
/** Always create a new SHM obj, i.e. issue shm_unlink() before shm_open(), only valid with FTL_MD_CREATE_SHM */
|
||||
FTL_MD_CREATE_SHM_NEW = 0x2,
|
||||
|
||||
/** FTL metadata will be created on heap */
|
||||
FTL_MD_CREATE_HEAP = 0x4,
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Creates FTL metadata
|
||||
*
|
||||
@ -111,7 +152,7 @@ SPDK_STATIC_ASSERT(sizeof(union ftl_md_vss) == FTL_MD_VSS_SZ, "Invalid md vss si
|
||||
* @param blocks Size of buffer in FTL block size unit
|
||||
* @param vss_blksz Size of VSS MD
|
||||
* @param name Name of the object being created
|
||||
* @param no_mem If true metadata will be created without memory allocation
|
||||
* @param flags Bit flags of ftl_md_create_flags type
|
||||
* @param region Region associated with FTL metadata
|
||||
*
|
||||
* @note if buffer is NULL, the buffer will be allocated internally by the object
|
||||
@ -119,9 +160,21 @@ SPDK_STATIC_ASSERT(sizeof(union ftl_md_vss) == FTL_MD_VSS_SZ, "Invalid md vss si
|
||||
* @return FTL metadata
|
||||
*/
|
||||
struct ftl_md *ftl_md_create(struct spdk_ftl_dev *dev, uint64_t blocks,
|
||||
uint64_t vss_blksz, const char *name, bool no_mem,
|
||||
uint64_t vss_blksz, const char *name, int flags,
|
||||
const struct ftl_layout_region *region);
|
||||
|
||||
/**
|
||||
* @brief Unlinks metadata object from FS
|
||||
* @param dev The FTL device
|
||||
* @param name Name of the object being unlinked
|
||||
* @param flags Bit flag describing the MD object
|
||||
*
|
||||
* @note Unlink is possible only for objects created with FTL_MD_CREATE_SHM flag
|
||||
*
|
||||
* @return Operation result
|
||||
*/
|
||||
int ftl_md_unlink(struct spdk_ftl_dev *dev, const char *name, int flags);
|
||||
|
||||
/**
|
||||
* @brief Destroys metadata
|
||||
*
|
||||
|
@ -32,3 +32,5 @@ for ((i = 0; i < ${#tests[@]}; i++)); do
|
||||
trap - SIGINT SIGTERM EXIT
|
||||
timing_exit "${tests[$i]}"
|
||||
done
|
||||
|
||||
remove_shm
|
||||
|
@ -46,3 +46,13 @@ function create_base_bdev() {
|
||||
$rootdir/scripts/rpc.py bdev_lvol_create ${base_bdev}p0 $size -t -u $lvs
|
||||
fi
|
||||
}
|
||||
|
||||
# Remove not needed files from shared memory
|
||||
function remove_shm() {
|
||||
echo Remove shared memory files
|
||||
rm -f rm -f /dev/shm/ftl*
|
||||
rm -f rm -f /dev/hugepages/ftl*
|
||||
rm -f rm -f /dev/shm/spdk*
|
||||
rm -f rm -f /dev/shm/iscsi
|
||||
rm -f rm -f /dev/hugepages/spdk*
|
||||
}
|
||||
|
@ -66,3 +66,4 @@ for test in ${tests}; do
|
||||
done
|
||||
|
||||
rm -f $FTL_JSON_CONF
|
||||
remove_shm
|
||||
|
@ -22,6 +22,7 @@ function at_ftl_exit() {
|
||||
|
||||
# restore original driver
|
||||
$rootdir/scripts/setup.sh reset
|
||||
remove_shm
|
||||
}
|
||||
|
||||
trap 'at_ftl_exit' SIGINT SIGTERM EXIT
|
||||
|
Loading…
Reference in New Issue
Block a user