diff --git a/lib/ftl/Makefile b/lib/ftl/Makefile index 6e914317c..31b001f61 100644 --- a/lib/ftl/Makefile +++ b/lib/ftl/Makefile @@ -20,7 +20,7 @@ FTL_SUBDIRS := mngt utils C_SRCS = ftl_core.c ftl_init.c ftl_layout.c ftl_debug.c C_SRCS += mngt/ftl_mngt.c mngt/ftl_mngt_bdev.c mngt/ftl_mngt_shutdown.c mngt/ftl_mngt_startup.c C_SRCS += mngt/ftl_mngt_md.c mngt/ftl_mngt_misc.c -C_SRCS += utils/ftl_conf.c utils/ftl_md.c +C_SRCS += utils/ftl_conf.c utils/ftl_md.c utils/ftl_mempool.c SPDK_MAP_FILE = $(abspath $(CURDIR)/spdk_ftl.map) diff --git a/lib/ftl/ftl_core.c b/lib/ftl/ftl_core.c index 4ec1e3868..72da507c5 100644 --- a/lib/ftl/ftl_core.c +++ b/lib/ftl/ftl_core.c @@ -16,6 +16,7 @@ #include "ftl_debug.h" #include "ftl_internal.h" #include "mngt/ftl_mngt.h" +#include "utils/ftl_mempool.h" static int ftl_shutdown_complete(struct spdk_ftl_dev *dev) diff --git a/lib/ftl/ftl_utils.h b/lib/ftl/ftl_utils.h index c00c2b879..89720060c 100644 --- a/lib/ftl/ftl_utils.h +++ b/lib/ftl/ftl_utils.h @@ -7,6 +7,7 @@ #define FTL_FTL_UTILS_H #include "utils/ftl_defs.h" +#include "utils/ftl_mempool.h" #include "utils/ftl_conf.h" #include "utils/ftl_md.h" diff --git a/lib/ftl/utils/ftl_mempool.c b/lib/ftl/utils/ftl_mempool.c new file mode 100644 index 000000000..e1ccb6b58 --- /dev/null +++ b/lib/ftl/utils/ftl_mempool.c @@ -0,0 +1,147 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright (c) Intel Corporation. + * All rights reserved. + */ + +#include "spdk/stdinc.h" +#include "spdk/queue.h" +#include "spdk/util.h" +#include "spdk/env.h" +#include "spdk/likely.h" + +#include "ftl_mempool.h" + +struct ftl_mempool_element { + SLIST_ENTRY(ftl_mempool_element) entry; +}; + +struct ftl_mempool { + SLIST_HEAD(, ftl_mempool_element) list; + size_t element_size; + void *buffer; + size_t buffer_size; + size_t count; + size_t alignment; + int socket_id; +}; + + +static size_t +element_size_aligned(size_t size, size_t alignment) +{ + if (!alignment) { + return size; + } + + if (size % alignment) { + return (size / alignment + 1) * alignment; + } + + return size; +} + +static inline bool +is_element_valid(struct ftl_mempool *mpool, void *element) +{ + if (element < mpool->buffer) { + return false; + } + + if (element + mpool->element_size > mpool->buffer + mpool->buffer_size) { + return false; + } + + if (!mpool->alignment) { + return true; + } + + if ((size_t)element % mpool->alignment) { + return false; + } + + if ((element - mpool->buffer) % mpool->element_size != 0) { + return false; + } + + return true; +} + +struct ftl_mempool *ftl_mempool_create(size_t count, size_t size, + size_t alignment, int socket_id) +{ + struct ftl_mempool *mp; + void *buffer; + size_t i; + + assert(count > 0); + assert(size > 0); + + if (!spdk_u64_is_pow2(alignment)) { + return NULL; + } + + mp = calloc(1, sizeof(*mp)); + if (!mp) { + return NULL; + } + + size = spdk_max(size, sizeof(struct ftl_mempool_element)); + + mp->count = count; + mp->element_size = element_size_aligned(size, alignment); + mp->alignment = alignment; + mp->socket_id = socket_id; + SLIST_INIT(&mp->list); + + mp->buffer_size = mp->element_size * mp->count; + mp->buffer = spdk_dma_malloc_socket(mp->buffer_size, mp->alignment, + NULL, socket_id); + if (!mp->buffer) { + free(mp); + return NULL; + } + + buffer = mp->buffer; + for (i = 0; i < count; i++, buffer += mp->element_size) { + struct ftl_mempool_element *el = buffer; + assert(is_element_valid(mp, el)); + SLIST_INSERT_HEAD(&mp->list, el, entry); + } + + return mp; +} + +void +ftl_mempool_destroy(struct ftl_mempool *mpool) +{ + if (!mpool) { + return; + } + + spdk_dma_free(mpool->buffer); + free(mpool); +} + +void * +ftl_mempool_get(struct ftl_mempool *mpool) +{ + struct ftl_mempool_element *el; + + if (spdk_unlikely(SLIST_EMPTY(&mpool->list))) { + return NULL; + } + + el = SLIST_FIRST(&mpool->list); + SLIST_REMOVE_HEAD(&mpool->list, entry); + + return el; +} + +void +ftl_mempool_put(struct ftl_mempool *mpool, void *element) +{ + struct ftl_mempool_element *el = element; + + assert(is_element_valid(mpool, element)); + SLIST_INSERT_HEAD(&mpool->list, el, entry); +} diff --git a/lib/ftl/utils/ftl_mempool.h b/lib/ftl/utils/ftl_mempool.h new file mode 100644 index 000000000..2387a4267 --- /dev/null +++ b/lib/ftl/utils/ftl_mempool.h @@ -0,0 +1,53 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright (c) Intel Corporation. + * All rights reserved. + */ + +#ifndef FTL_MEMPOOL_H +#define FTL_MEMPOOL_H + +#include "spdk/stdinc.h" + +/* TODO: Consider porting this mempool to general SPDK utils */ + +/** + * @brief Creates custom FTL memory pool using DMA kind memory + * + * The pool is being initialized. + * + * @param count Count of element in the memory pool + * @param size Size of elements in the memory pool + * @param alignment Memory alignment of element in the memory pool + * @param socket_id It is the socket identifier in the case of NUMA. The value + * can be *SOCKET_ID_ANY* if there is no NUMA constraint for the reserved zone. + * + * @return Pointer to the memory pool + */ +struct ftl_mempool *ftl_mempool_create(size_t count, size_t size, + size_t alignment, int socket_id); + +/** + * @brief Destroys the FTL memory pool + + * @param mpool The memory pool to be destroyed + */ +void ftl_mempool_destroy(struct ftl_mempool *mpool); + +/** + * @brief Gets (allocates) an element from the memory pool + * + * @param mpool The memory pool + * + * @return Element from memory pool. If memory pool empty it returns NULL. + */ +void *ftl_mempool_get(struct ftl_mempool *mpool); + +/** + * @brief Puts (releases) the element to the memory pool + * + * @param mpool The memory pool + * @param element The element to be released + */ +void ftl_mempool_put(struct ftl_mempool *mpool, void *element); + +#endif /* FTL_MEMPOOL_H */