xref: /spdk/lib/ftl/utils/ftl_mempool.c (revision 081f080a49a3dbe31acb2a8557db90b08bbeaf9c)
1 /*   SPDX-License-Identifier: BSD-3-Clause
2  *   Copyright (c) Intel Corporation.
3  *   All rights reserved.
4  */
5 
6 #include "spdk/stdinc.h"
7 #include "spdk/queue.h"
8 #include "spdk/util.h"
9 #include "spdk/env.h"
10 #include "spdk/likely.h"
11 
12 #include "ftl_mempool.h"
13 
14 struct ftl_mempool_element {
15 	SLIST_ENTRY(ftl_mempool_element) entry;
16 };
17 
18 struct ftl_mempool {
19 	SLIST_HEAD(, ftl_mempool_element) list;
20 	size_t element_size;
21 	void *buffer;
22 	size_t buffer_size;
23 	size_t count;
24 	size_t alignment;
25 	int socket_id;
26 };
27 
28 static inline bool is_element_valid(struct ftl_mempool *mpool,
29 				    void *element)  __attribute__((unused));
30 
31 static size_t
32 element_size_aligned(size_t size, size_t alignment)
33 {
34 	if (!alignment) {
35 		return size;
36 	}
37 
38 	if (size % alignment) {
39 		return (size / alignment + 1) * alignment;
40 	}
41 
42 	return size;
43 }
44 
45 static inline bool
46 is_element_valid(struct ftl_mempool *mpool, void *element)
47 {
48 	if (element < mpool->buffer) {
49 		return false;
50 	}
51 
52 	if (element + mpool->element_size > mpool->buffer + mpool->buffer_size) {
53 		return false;
54 	}
55 
56 	if (!mpool->alignment) {
57 		return true;
58 	}
59 
60 	if ((size_t)element % mpool->alignment) {
61 		return false;
62 	}
63 
64 	if ((element - mpool->buffer) % mpool->element_size != 0) {
65 		return false;
66 	}
67 
68 	return true;
69 }
70 
71 struct ftl_mempool *ftl_mempool_create(size_t count, size_t size,
72 				       size_t alignment, int socket_id)
73 {
74 	struct ftl_mempool *mp;
75 	void *buffer;
76 	size_t i;
77 
78 	assert(count > 0);
79 	assert(size > 0);
80 
81 	if (!spdk_u64_is_pow2(alignment)) {
82 		return NULL;
83 	}
84 
85 	mp = calloc(1, sizeof(*mp));
86 	if (!mp) {
87 		return NULL;
88 	}
89 
90 	size = spdk_max(size, sizeof(struct ftl_mempool_element));
91 
92 	mp->count = count;
93 	mp->element_size = element_size_aligned(size, alignment);
94 	mp->alignment = alignment;
95 	mp->socket_id = socket_id;
96 	SLIST_INIT(&mp->list);
97 
98 	mp->buffer_size = mp->element_size * mp->count;
99 	mp->buffer = spdk_dma_malloc_socket(mp->buffer_size, mp->alignment,
100 					    NULL, socket_id);
101 	if (!mp->buffer) {
102 		free(mp);
103 		return NULL;
104 	}
105 
106 	buffer = mp->buffer;
107 	for (i = 0; i < count; i++, buffer += mp->element_size) {
108 		struct ftl_mempool_element *el = buffer;
109 		assert(is_element_valid(mp, el));
110 		SLIST_INSERT_HEAD(&mp->list, el, entry);
111 	}
112 
113 	return mp;
114 }
115 
116 void
117 ftl_mempool_destroy(struct ftl_mempool *mpool)
118 {
119 	if (!mpool) {
120 		return;
121 	}
122 
123 	spdk_dma_free(mpool->buffer);
124 	free(mpool);
125 }
126 
127 void *
128 ftl_mempool_get(struct ftl_mempool *mpool)
129 {
130 	struct ftl_mempool_element *el;
131 
132 	if (spdk_unlikely(SLIST_EMPTY(&mpool->list))) {
133 		return NULL;
134 	}
135 
136 	el = SLIST_FIRST(&mpool->list);
137 	SLIST_REMOVE_HEAD(&mpool->list, entry);
138 
139 	return el;
140 }
141 
142 void
143 ftl_mempool_put(struct ftl_mempool *mpool, void *element)
144 {
145 	struct ftl_mempool_element *el = element;
146 
147 	assert(is_element_valid(mpool, element));
148 	SLIST_INSERT_HEAD(&mpool->list, el, entry);
149 }
150