Spdk/lib/ftl/utils/ftl_mempool.c
Artur Paszkiewicz 71a1762821 ftl: mempool support for durable format objects
Allows for using shared memory in memory pools. Adds API for
accessing such pools after dirty shutdown (claiming them, ie.
marking an entry as actively used; calling the
ftl_mempool_initialize_ext will reclaim all unused entries back
to the pool). Also introduces API for accessing objects, since
using direct pointers is not possible (as addresses may change
inbetween application startups).

Signed-off-by: Artur Paszkiewicz <artur.paszkiewicz@intel.com>
Signed-off-by: Kozlowski Mateusz <mateusz.kozlowski@intel.com>
Change-Id: I5325b39d68aef7e231945cee9d92c925cab2fb2a
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/13346
Community-CI: Mellanox Build Bot
Tested-by: SPDK CI Jenkins <sys_sgci@intel.com>
Reviewed-by: Jim Harris <james.r.harris@intel.com>
Reviewed-by: Ben Walker <benjamin.walker@intel.com>
2022-08-30 14:48:50 +00:00

292 lines
5.9 KiB
C

/* 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"
#include "ftl_bitmap.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;
struct ftl_bitmap *inuse_bmp;
void *inuse_buf;
};
static inline bool is_element_valid(struct ftl_mempool *mpool,
void *element) __attribute__((unused));
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);
}
static inline bool
ftl_mempool_is_initialized(struct ftl_mempool *mpool)
{
return mpool->inuse_buf == NULL;
}
void *
ftl_mempool_get(struct ftl_mempool *mpool)
{
struct ftl_mempool_element *el;
assert(ftl_mempool_is_initialized(mpool));
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(ftl_mempool_is_initialized(mpool));
assert(is_element_valid(mpool, element));
SLIST_INSERT_HEAD(&mpool->list, el, entry);
}
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);
}