xref: /spdk/lib/ftl/utils/ftl_mempool.c (revision a6dbe3721eb3b5990707fc3e378c95e505dd8ab5)
1b4316404SKozlowski Mateusz /*   SPDX-License-Identifier: BSD-3-Clause
2*a6dbe372Spaul luse  *   Copyright (C) 2022 Intel Corporation.
3b4316404SKozlowski Mateusz  *   All rights reserved.
4b4316404SKozlowski Mateusz  */
5b4316404SKozlowski Mateusz 
6b4316404SKozlowski Mateusz #include "spdk/stdinc.h"
7b4316404SKozlowski Mateusz #include "spdk/queue.h"
8b4316404SKozlowski Mateusz #include "spdk/util.h"
9b4316404SKozlowski Mateusz #include "spdk/env.h"
10b4316404SKozlowski Mateusz #include "spdk/likely.h"
11b4316404SKozlowski Mateusz 
12b4316404SKozlowski Mateusz #include "ftl_mempool.h"
1371a17628SArtur Paszkiewicz #include "ftl_bitmap.h"
14b4316404SKozlowski Mateusz 
15b4316404SKozlowski Mateusz struct ftl_mempool_element {
16b4316404SKozlowski Mateusz 	SLIST_ENTRY(ftl_mempool_element) entry;
17b4316404SKozlowski Mateusz };
18b4316404SKozlowski Mateusz 
19b4316404SKozlowski Mateusz struct ftl_mempool {
20b4316404SKozlowski Mateusz 	SLIST_HEAD(, ftl_mempool_element) list;
21b4316404SKozlowski Mateusz 	size_t element_size;
22b4316404SKozlowski Mateusz 	void *buffer;
23b4316404SKozlowski Mateusz 	size_t buffer_size;
24b4316404SKozlowski Mateusz 	size_t count;
25b4316404SKozlowski Mateusz 	size_t alignment;
26b4316404SKozlowski Mateusz 	int socket_id;
2771a17628SArtur Paszkiewicz 	struct ftl_bitmap *inuse_bmp;
2871a17628SArtur Paszkiewicz 	void *inuse_buf;
29b4316404SKozlowski Mateusz };
30b4316404SKozlowski Mateusz 
31be1883d9SMichal Berger static inline bool is_element_valid(struct ftl_mempool *mpool,
32be1883d9SMichal Berger 				    void *element)  __attribute__((unused));
33b4316404SKozlowski Mateusz 
3459c10a2fSMichal Berger static inline bool ftl_mempool_is_initialized(struct ftl_mempool *mpool) __attribute__((unused));
3559c10a2fSMichal Berger 
36b4316404SKozlowski Mateusz static size_t
element_size_aligned(size_t size,size_t alignment)37b4316404SKozlowski Mateusz element_size_aligned(size_t size, size_t alignment)
38b4316404SKozlowski Mateusz {
39b4316404SKozlowski Mateusz 	if (!alignment) {
40b4316404SKozlowski Mateusz 		return size;
41b4316404SKozlowski Mateusz 	}
42b4316404SKozlowski Mateusz 
43b4316404SKozlowski Mateusz 	if (size % alignment) {
44b4316404SKozlowski Mateusz 		return (size / alignment + 1) * alignment;
45b4316404SKozlowski Mateusz 	}
46b4316404SKozlowski Mateusz 
47b4316404SKozlowski Mateusz 	return size;
48b4316404SKozlowski Mateusz }
49b4316404SKozlowski Mateusz 
50b4316404SKozlowski Mateusz static inline bool
is_element_valid(struct ftl_mempool * mpool,void * element)51b4316404SKozlowski Mateusz is_element_valid(struct ftl_mempool *mpool, void *element)
52b4316404SKozlowski Mateusz {
53b4316404SKozlowski Mateusz 	if (element < mpool->buffer) {
54b4316404SKozlowski Mateusz 		return false;
55b4316404SKozlowski Mateusz 	}
56b4316404SKozlowski Mateusz 
57b4316404SKozlowski Mateusz 	if (element + mpool->element_size > mpool->buffer + mpool->buffer_size) {
58b4316404SKozlowski Mateusz 		return false;
59b4316404SKozlowski Mateusz 	}
60b4316404SKozlowski Mateusz 
61b4316404SKozlowski Mateusz 	if (!mpool->alignment) {
62b4316404SKozlowski Mateusz 		return true;
63b4316404SKozlowski Mateusz 	}
64b4316404SKozlowski Mateusz 
65b4316404SKozlowski Mateusz 	if ((size_t)element % mpool->alignment) {
66b4316404SKozlowski Mateusz 		return false;
67b4316404SKozlowski Mateusz 	}
68b4316404SKozlowski Mateusz 
69b4316404SKozlowski Mateusz 	if ((element - mpool->buffer) % mpool->element_size != 0) {
70b4316404SKozlowski Mateusz 		return false;
71b4316404SKozlowski Mateusz 	}
72b4316404SKozlowski Mateusz 
73b4316404SKozlowski Mateusz 	return true;
74b4316404SKozlowski Mateusz }
75b4316404SKozlowski Mateusz 
ftl_mempool_create(size_t count,size_t size,size_t alignment,int socket_id)76b4316404SKozlowski Mateusz struct ftl_mempool *ftl_mempool_create(size_t count, size_t size,
77b4316404SKozlowski Mateusz 				       size_t alignment, int socket_id)
78b4316404SKozlowski Mateusz {
79b4316404SKozlowski Mateusz 	struct ftl_mempool *mp;
80b4316404SKozlowski Mateusz 	void *buffer;
81b4316404SKozlowski Mateusz 	size_t i;
82b4316404SKozlowski Mateusz 
83b4316404SKozlowski Mateusz 	assert(count > 0);
84b4316404SKozlowski Mateusz 	assert(size > 0);
85b4316404SKozlowski Mateusz 
86b4316404SKozlowski Mateusz 	if (!spdk_u64_is_pow2(alignment)) {
87b4316404SKozlowski Mateusz 		return NULL;
88b4316404SKozlowski Mateusz 	}
89b4316404SKozlowski Mateusz 
90b4316404SKozlowski Mateusz 	mp = calloc(1, sizeof(*mp));
91b4316404SKozlowski Mateusz 	if (!mp) {
92b4316404SKozlowski Mateusz 		return NULL;
93b4316404SKozlowski Mateusz 	}
94b4316404SKozlowski Mateusz 
95b4316404SKozlowski Mateusz 	size = spdk_max(size, sizeof(struct ftl_mempool_element));
96b4316404SKozlowski Mateusz 
97b4316404SKozlowski Mateusz 	mp->count = count;
98b4316404SKozlowski Mateusz 	mp->element_size = element_size_aligned(size, alignment);
99b4316404SKozlowski Mateusz 	mp->alignment = alignment;
100b4316404SKozlowski Mateusz 	mp->socket_id = socket_id;
101b4316404SKozlowski Mateusz 	SLIST_INIT(&mp->list);
102b4316404SKozlowski Mateusz 
103b4316404SKozlowski Mateusz 	mp->buffer_size = mp->element_size * mp->count;
104b4316404SKozlowski Mateusz 	mp->buffer = spdk_dma_malloc_socket(mp->buffer_size, mp->alignment,
105b4316404SKozlowski Mateusz 					    NULL, socket_id);
106b4316404SKozlowski Mateusz 	if (!mp->buffer) {
107b4316404SKozlowski Mateusz 		free(mp);
108b4316404SKozlowski Mateusz 		return NULL;
109b4316404SKozlowski Mateusz 	}
110b4316404SKozlowski Mateusz 
111b4316404SKozlowski Mateusz 	buffer = mp->buffer;
112b4316404SKozlowski Mateusz 	for (i = 0; i < count; i++, buffer += mp->element_size) {
113b4316404SKozlowski Mateusz 		struct ftl_mempool_element *el = buffer;
114b4316404SKozlowski Mateusz 		assert(is_element_valid(mp, el));
115b4316404SKozlowski Mateusz 		SLIST_INSERT_HEAD(&mp->list, el, entry);
116b4316404SKozlowski Mateusz 	}
117b4316404SKozlowski Mateusz 
118b4316404SKozlowski Mateusz 	return mp;
119b4316404SKozlowski Mateusz }
120b4316404SKozlowski Mateusz 
121b4316404SKozlowski Mateusz void
ftl_mempool_destroy(struct ftl_mempool * mpool)122b4316404SKozlowski Mateusz ftl_mempool_destroy(struct ftl_mempool *mpool)
123b4316404SKozlowski Mateusz {
124b4316404SKozlowski Mateusz 	if (!mpool) {
125b4316404SKozlowski Mateusz 		return;
126b4316404SKozlowski Mateusz 	}
127b4316404SKozlowski Mateusz 
128b4316404SKozlowski Mateusz 	spdk_dma_free(mpool->buffer);
129b4316404SKozlowski Mateusz 	free(mpool);
130b4316404SKozlowski Mateusz }
131b4316404SKozlowski Mateusz 
13271a17628SArtur Paszkiewicz static inline bool
ftl_mempool_is_initialized(struct ftl_mempool * mpool)13371a17628SArtur Paszkiewicz ftl_mempool_is_initialized(struct ftl_mempool *mpool)
13471a17628SArtur Paszkiewicz {
13571a17628SArtur Paszkiewicz 	return mpool->inuse_buf == NULL;
13671a17628SArtur Paszkiewicz }
13771a17628SArtur Paszkiewicz 
138b4316404SKozlowski Mateusz void *
ftl_mempool_get(struct ftl_mempool * mpool)139b4316404SKozlowski Mateusz ftl_mempool_get(struct ftl_mempool *mpool)
140b4316404SKozlowski Mateusz {
141b4316404SKozlowski Mateusz 	struct ftl_mempool_element *el;
142b4316404SKozlowski Mateusz 
14371a17628SArtur Paszkiewicz 	assert(ftl_mempool_is_initialized(mpool));
144b4316404SKozlowski Mateusz 	if (spdk_unlikely(SLIST_EMPTY(&mpool->list))) {
145b4316404SKozlowski Mateusz 		return NULL;
146b4316404SKozlowski Mateusz 	}
147b4316404SKozlowski Mateusz 
148b4316404SKozlowski Mateusz 	el = SLIST_FIRST(&mpool->list);
149b4316404SKozlowski Mateusz 	SLIST_REMOVE_HEAD(&mpool->list, entry);
150b4316404SKozlowski Mateusz 
151b4316404SKozlowski Mateusz 	return el;
152b4316404SKozlowski Mateusz }
153b4316404SKozlowski Mateusz 
154b4316404SKozlowski Mateusz void
ftl_mempool_put(struct ftl_mempool * mpool,void * element)155b4316404SKozlowski Mateusz ftl_mempool_put(struct ftl_mempool *mpool, void *element)
156b4316404SKozlowski Mateusz {
157b4316404SKozlowski Mateusz 	struct ftl_mempool_element *el = element;
158b4316404SKozlowski Mateusz 
15971a17628SArtur Paszkiewicz 	assert(ftl_mempool_is_initialized(mpool));
160b4316404SKozlowski Mateusz 	assert(is_element_valid(mpool, element));
161b4316404SKozlowski Mateusz 	SLIST_INSERT_HEAD(&mpool->list, el, entry);
162b4316404SKozlowski Mateusz }
16371a17628SArtur Paszkiewicz 
16471a17628SArtur Paszkiewicz struct ftl_mempool *
ftl_mempool_create_ext(void * buffer,size_t count,size_t size,size_t alignment)16571a17628SArtur Paszkiewicz ftl_mempool_create_ext(void *buffer, size_t count, size_t size, size_t alignment)
16671a17628SArtur Paszkiewicz {
16771a17628SArtur Paszkiewicz 	struct ftl_mempool *mp;
16871a17628SArtur Paszkiewicz 	size_t inuse_buf_sz;
16971a17628SArtur Paszkiewicz 
17071a17628SArtur Paszkiewicz 	assert(buffer);
17171a17628SArtur Paszkiewicz 	assert(count > 0);
17271a17628SArtur Paszkiewicz 	assert(size > 0);
17371a17628SArtur Paszkiewicz 
17471a17628SArtur Paszkiewicz 	mp = calloc(1, sizeof(*mp));
17571a17628SArtur Paszkiewicz 	if (!mp) {
17671a17628SArtur Paszkiewicz 		goto error;
17771a17628SArtur Paszkiewicz 	}
17871a17628SArtur Paszkiewicz 
17971a17628SArtur Paszkiewicz 	size = spdk_max(size, sizeof(struct ftl_mempool_element));
18071a17628SArtur Paszkiewicz 
18171a17628SArtur Paszkiewicz 	mp->count = count;
18271a17628SArtur Paszkiewicz 	mp->element_size = element_size_aligned(size, alignment);
18371a17628SArtur Paszkiewicz 	mp->alignment = alignment;
18471a17628SArtur Paszkiewicz 	SLIST_INIT(&mp->list);
18571a17628SArtur Paszkiewicz 
18671a17628SArtur Paszkiewicz 	/* Calculate underlying inuse_bmp's buf size */
18771a17628SArtur Paszkiewicz 	inuse_buf_sz = spdk_divide_round_up(mp->count, 8);
18871a17628SArtur Paszkiewicz 	/* The bitmap size must be a multiple of word size (8b) - round up */
18971a17628SArtur Paszkiewicz 	if (inuse_buf_sz & 7UL) {
19071a17628SArtur Paszkiewicz 		inuse_buf_sz &= ~7UL;
19171a17628SArtur Paszkiewicz 		inuse_buf_sz += 8;
19271a17628SArtur Paszkiewicz 	}
19371a17628SArtur Paszkiewicz 
19471a17628SArtur Paszkiewicz 	mp->inuse_buf = calloc(1, inuse_buf_sz);
19571a17628SArtur Paszkiewicz 	if (!mp->inuse_buf) {
19671a17628SArtur Paszkiewicz 		goto error;
19771a17628SArtur Paszkiewicz 	}
19871a17628SArtur Paszkiewicz 
19971a17628SArtur Paszkiewicz 	mp->inuse_bmp = ftl_bitmap_create(mp->inuse_buf, inuse_buf_sz);
20071a17628SArtur Paszkiewicz 	if (!mp->inuse_bmp) {
20171a17628SArtur Paszkiewicz 		goto error;
20271a17628SArtur Paszkiewicz 	}
20371a17628SArtur Paszkiewicz 
20471a17628SArtur Paszkiewicz 	/* Map the buffer */
20571a17628SArtur Paszkiewicz 	mp->buffer_size = mp->element_size * mp->count;
20671a17628SArtur Paszkiewicz 	mp->buffer = buffer;
20771a17628SArtur Paszkiewicz 
20871a17628SArtur Paszkiewicz 	return mp;
20971a17628SArtur Paszkiewicz 
21071a17628SArtur Paszkiewicz error:
21171a17628SArtur Paszkiewicz 	ftl_mempool_destroy_ext(mp);
21271a17628SArtur Paszkiewicz 	return NULL;
21371a17628SArtur Paszkiewicz }
21471a17628SArtur Paszkiewicz 
21571a17628SArtur Paszkiewicz void
ftl_mempool_destroy_ext(struct ftl_mempool * mpool)21671a17628SArtur Paszkiewicz ftl_mempool_destroy_ext(struct ftl_mempool *mpool)
21771a17628SArtur Paszkiewicz {
21871a17628SArtur Paszkiewicz 	if (!mpool) {
21971a17628SArtur Paszkiewicz 		return;
22071a17628SArtur Paszkiewicz 	}
22171a17628SArtur Paszkiewicz 
22271a17628SArtur Paszkiewicz 	if (mpool->inuse_bmp) {
22371a17628SArtur Paszkiewicz 		ftl_bitmap_destroy(mpool->inuse_bmp);
22471a17628SArtur Paszkiewicz 	}
22571a17628SArtur Paszkiewicz 	free(mpool->inuse_buf);
22671a17628SArtur Paszkiewicz 	free(mpool);
22771a17628SArtur Paszkiewicz }
22871a17628SArtur Paszkiewicz 
22971a17628SArtur Paszkiewicz void
ftl_mempool_initialize_ext(struct ftl_mempool * mpool)23071a17628SArtur Paszkiewicz ftl_mempool_initialize_ext(struct ftl_mempool *mpool)
23171a17628SArtur Paszkiewicz {
23271a17628SArtur Paszkiewicz 	struct ftl_mempool_element *el;
23371a17628SArtur Paszkiewicz 	void *buffer = mpool->buffer;
23471a17628SArtur Paszkiewicz 	size_t i;
23571a17628SArtur Paszkiewicz 
23671a17628SArtur Paszkiewicz 	assert(!ftl_mempool_is_initialized(mpool));
23771a17628SArtur Paszkiewicz 
23871a17628SArtur Paszkiewicz 	for (i = 0; i < mpool->count; i++, buffer += mpool->element_size) {
23971a17628SArtur Paszkiewicz 		if (ftl_bitmap_get(mpool->inuse_bmp, i)) {
24071a17628SArtur Paszkiewicz 			continue;
24171a17628SArtur Paszkiewicz 		}
24271a17628SArtur Paszkiewicz 		el = buffer;
24371a17628SArtur Paszkiewicz 		assert(is_element_valid(mpool, el));
24471a17628SArtur Paszkiewicz 		SLIST_INSERT_HEAD(&mpool->list, el, entry);
24571a17628SArtur Paszkiewicz 	}
24671a17628SArtur Paszkiewicz 
24771a17628SArtur Paszkiewicz 	ftl_bitmap_destroy(mpool->inuse_bmp);
24871a17628SArtur Paszkiewicz 	mpool->inuse_bmp = NULL;
24971a17628SArtur Paszkiewicz 
25071a17628SArtur Paszkiewicz 	free(mpool->inuse_buf);
25171a17628SArtur Paszkiewicz 	mpool->inuse_buf = NULL;
25271a17628SArtur Paszkiewicz }
25371a17628SArtur Paszkiewicz 
25471a17628SArtur Paszkiewicz ftl_df_obj_id
ftl_mempool_get_df_obj_id(struct ftl_mempool * mpool,void * df_obj_ptr)25571a17628SArtur Paszkiewicz ftl_mempool_get_df_obj_id(struct ftl_mempool *mpool, void *df_obj_ptr)
25671a17628SArtur Paszkiewicz {
25771a17628SArtur Paszkiewicz 	return ftl_df_get_obj_id(mpool->buffer, df_obj_ptr);
25871a17628SArtur Paszkiewicz }
25971a17628SArtur Paszkiewicz 
26071a17628SArtur Paszkiewicz size_t
ftl_mempool_get_df_obj_index(struct ftl_mempool * mpool,void * df_obj_ptr)26171a17628SArtur Paszkiewicz ftl_mempool_get_df_obj_index(struct ftl_mempool *mpool, void *df_obj_ptr)
26271a17628SArtur Paszkiewicz {
26371a17628SArtur Paszkiewicz 	return ftl_mempool_get_df_obj_id(mpool, df_obj_ptr) / mpool->element_size;
26471a17628SArtur Paszkiewicz }
26571a17628SArtur Paszkiewicz 
26671a17628SArtur Paszkiewicz void *
ftl_mempool_get_df_ptr(struct ftl_mempool * mpool,ftl_df_obj_id df_obj_id)26771a17628SArtur Paszkiewicz ftl_mempool_get_df_ptr(struct ftl_mempool *mpool, ftl_df_obj_id df_obj_id)
26871a17628SArtur Paszkiewicz {
26971a17628SArtur Paszkiewicz 	return ftl_df_get_obj_ptr(mpool->buffer, df_obj_id);
27071a17628SArtur Paszkiewicz }
27171a17628SArtur Paszkiewicz 
27271a17628SArtur Paszkiewicz void *
ftl_mempool_claim_df(struct ftl_mempool * mpool,ftl_df_obj_id df_obj_id)27371a17628SArtur Paszkiewicz ftl_mempool_claim_df(struct ftl_mempool *mpool, ftl_df_obj_id df_obj_id)
27471a17628SArtur Paszkiewicz {
27571a17628SArtur Paszkiewicz 	struct ftl_mempool_element *el = ftl_df_get_obj_ptr(mpool->buffer, df_obj_id);
27671a17628SArtur Paszkiewicz 
27771a17628SArtur Paszkiewicz 	assert(!ftl_mempool_is_initialized(mpool));
27871a17628SArtur Paszkiewicz 	assert(df_obj_id % mpool->element_size == 0);
27971a17628SArtur Paszkiewicz 	assert(df_obj_id / mpool->element_size < mpool->count);
28071a17628SArtur Paszkiewicz 
28171a17628SArtur Paszkiewicz 	ftl_bitmap_set(mpool->inuse_bmp, df_obj_id / mpool->element_size);
28271a17628SArtur Paszkiewicz 	return el;
28371a17628SArtur Paszkiewicz }
28471a17628SArtur Paszkiewicz 
28571a17628SArtur Paszkiewicz void
ftl_mempool_release_df(struct ftl_mempool * mpool,ftl_df_obj_id df_obj_id)28671a17628SArtur Paszkiewicz ftl_mempool_release_df(struct ftl_mempool *mpool, ftl_df_obj_id df_obj_id)
28771a17628SArtur Paszkiewicz {
28871a17628SArtur Paszkiewicz 	assert(!ftl_mempool_is_initialized(mpool));
28971a17628SArtur Paszkiewicz 	assert(df_obj_id % mpool->element_size == 0);
29071a17628SArtur Paszkiewicz 	assert(df_obj_id / mpool->element_size < mpool->count);
29171a17628SArtur Paszkiewicz 
29271a17628SArtur Paszkiewicz 	ftl_bitmap_clear(mpool->inuse_bmp, df_obj_id / mpool->element_size);
29371a17628SArtur Paszkiewicz }
294