2022-06-15 09:55:53 +00:00
|
|
|
/* 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"
|
2022-06-09 14:05:50 +00:00
|
|
|
#include "ftl_bitmap.h"
|
2022-06-15 09:55:53 +00:00
|
|
|
|
|
|
|
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;
|
2022-06-09 14:05:50 +00:00
|
|
|
struct ftl_bitmap *inuse_bmp;
|
|
|
|
void *inuse_buf;
|
2022-06-15 09:55:53 +00:00
|
|
|
};
|
|
|
|
|
2022-08-03 11:05:20 +00:00
|
|
|
static inline bool is_element_valid(struct ftl_mempool *mpool,
|
|
|
|
void *element) __attribute__((unused));
|
2022-06-15 09:55:53 +00:00
|
|
|
|
2022-08-31 13:04:24 +00:00
|
|
|
static inline bool ftl_mempool_is_initialized(struct ftl_mempool *mpool) __attribute__((unused));
|
|
|
|
|
2022-06-15 09:55:53 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2022-06-09 14:05:50 +00:00
|
|
|
static inline bool
|
|
|
|
ftl_mempool_is_initialized(struct ftl_mempool *mpool)
|
|
|
|
{
|
|
|
|
return mpool->inuse_buf == NULL;
|
|
|
|
}
|
|
|
|
|
2022-06-15 09:55:53 +00:00
|
|
|
void *
|
|
|
|
ftl_mempool_get(struct ftl_mempool *mpool)
|
|
|
|
{
|
|
|
|
struct ftl_mempool_element *el;
|
|
|
|
|
2022-06-09 14:05:50 +00:00
|
|
|
assert(ftl_mempool_is_initialized(mpool));
|
2022-06-15 09:55:53 +00:00
|
|
|
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;
|
|
|
|
|
2022-06-09 14:05:50 +00:00
|
|
|
assert(ftl_mempool_is_initialized(mpool));
|
2022-06-15 09:55:53 +00:00
|
|
|
assert(is_element_valid(mpool, element));
|
|
|
|
SLIST_INSERT_HEAD(&mpool->list, el, entry);
|
|
|
|
}
|
2022-06-09 14:05:50 +00:00
|
|
|
|
|
|
|
struct ftl_mempool *
|
|
|
|
ftl_mempool_create_ext(void *buffer, size_t count, size_t size, size_t alignment)
|
|
|
|
{
|
|
|
|
struct ftl_mempool *mp;
|
|
|
|
size_t inuse_buf_sz;
|
|
|
|
|
|
|
|
assert(buffer);
|
|
|
|
assert(count > 0);
|
|
|
|
assert(size > 0);
|
|
|
|
|
|
|
|
mp = calloc(1, sizeof(*mp));
|
|
|
|
if (!mp) {
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
size = spdk_max(size, sizeof(struct ftl_mempool_element));
|
|
|
|
|
|
|
|
mp->count = count;
|
|
|
|
mp->element_size = element_size_aligned(size, alignment);
|
|
|
|
mp->alignment = alignment;
|
|
|
|
SLIST_INIT(&mp->list);
|
|
|
|
|
|
|
|
/* Calculate underlying inuse_bmp's buf size */
|
|
|
|
inuse_buf_sz = spdk_divide_round_up(mp->count, 8);
|
|
|
|
/* The bitmap size must be a multiple of word size (8b) - round up */
|
|
|
|
if (inuse_buf_sz & 7UL) {
|
|
|
|
inuse_buf_sz &= ~7UL;
|
|
|
|
inuse_buf_sz += 8;
|
|
|
|
}
|
|
|
|
|
|
|
|
mp->inuse_buf = calloc(1, inuse_buf_sz);
|
|
|
|
if (!mp->inuse_buf) {
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
mp->inuse_bmp = ftl_bitmap_create(mp->inuse_buf, inuse_buf_sz);
|
|
|
|
if (!mp->inuse_bmp) {
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Map the buffer */
|
|
|
|
mp->buffer_size = mp->element_size * mp->count;
|
|
|
|
mp->buffer = buffer;
|
|
|
|
|
|
|
|
return mp;
|
|
|
|
|
|
|
|
error:
|
|
|
|
ftl_mempool_destroy_ext(mp);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
ftl_mempool_destroy_ext(struct ftl_mempool *mpool)
|
|
|
|
{
|
|
|
|
if (!mpool) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mpool->inuse_bmp) {
|
|
|
|
ftl_bitmap_destroy(mpool->inuse_bmp);
|
|
|
|
}
|
|
|
|
free(mpool->inuse_buf);
|
|
|
|
free(mpool);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
ftl_mempool_initialize_ext(struct ftl_mempool *mpool)
|
|
|
|
{
|
|
|
|
struct ftl_mempool_element *el;
|
|
|
|
void *buffer = mpool->buffer;
|
|
|
|
size_t i;
|
|
|
|
|
|
|
|
assert(!ftl_mempool_is_initialized(mpool));
|
|
|
|
|
|
|
|
for (i = 0; i < mpool->count; i++, buffer += mpool->element_size) {
|
|
|
|
if (ftl_bitmap_get(mpool->inuse_bmp, i)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
el = buffer;
|
|
|
|
assert(is_element_valid(mpool, el));
|
|
|
|
SLIST_INSERT_HEAD(&mpool->list, el, entry);
|
|
|
|
}
|
|
|
|
|
|
|
|
ftl_bitmap_destroy(mpool->inuse_bmp);
|
|
|
|
mpool->inuse_bmp = NULL;
|
|
|
|
|
|
|
|
free(mpool->inuse_buf);
|
|
|
|
mpool->inuse_buf = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
ftl_df_obj_id
|
|
|
|
ftl_mempool_get_df_obj_id(struct ftl_mempool *mpool, void *df_obj_ptr)
|
|
|
|
{
|
|
|
|
return ftl_df_get_obj_id(mpool->buffer, df_obj_ptr);
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t
|
|
|
|
ftl_mempool_get_df_obj_index(struct ftl_mempool *mpool, void *df_obj_ptr)
|
|
|
|
{
|
|
|
|
return ftl_mempool_get_df_obj_id(mpool, df_obj_ptr) / mpool->element_size;
|
|
|
|
}
|
|
|
|
|
|
|
|
void *
|
|
|
|
ftl_mempool_get_df_ptr(struct ftl_mempool *mpool, ftl_df_obj_id df_obj_id)
|
|
|
|
{
|
|
|
|
return ftl_df_get_obj_ptr(mpool->buffer, df_obj_id);
|
|
|
|
}
|
|
|
|
|
|
|
|
void *
|
|
|
|
ftl_mempool_claim_df(struct ftl_mempool *mpool, ftl_df_obj_id df_obj_id)
|
|
|
|
{
|
|
|
|
struct ftl_mempool_element *el = ftl_df_get_obj_ptr(mpool->buffer, df_obj_id);
|
|
|
|
|
|
|
|
assert(!ftl_mempool_is_initialized(mpool));
|
|
|
|
assert(df_obj_id % mpool->element_size == 0);
|
|
|
|
assert(df_obj_id / mpool->element_size < mpool->count);
|
|
|
|
|
|
|
|
ftl_bitmap_set(mpool->inuse_bmp, df_obj_id / mpool->element_size);
|
|
|
|
return el;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
ftl_mempool_release_df(struct ftl_mempool *mpool, ftl_df_obj_id df_obj_id)
|
|
|
|
{
|
|
|
|
assert(!ftl_mempool_is_initialized(mpool));
|
|
|
|
assert(df_obj_id % mpool->element_size == 0);
|
|
|
|
assert(df_obj_id / mpool->element_size < mpool->count);
|
|
|
|
|
|
|
|
ftl_bitmap_clear(mpool->inuse_bmp, df_obj_id / mpool->element_size);
|
|
|
|
}
|