1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright (C) 2021 Intel Corporation.
3 * All rights reserved.
4 */
5
6 #include "spdk/env.h"
7 #include "ocf_env.h"
8
9 #include "mpool.h"
10
11 struct env_mpool {
12 env_allocator *allocator[env_mpool_max];
13 /* Handles to memory pools */
14
15 uint32_t hdr_size;
16 /* Data header size (constant allocation part) */
17
18 uint32_t elem_size;
19 /* Per element size increment (variable allocation part) */
20
21 uint32_t mpool_max;
22 /* Max mpool allocation order */
23
24 bool fallback;
25 /* Fallback to vmalloc */
26 };
27
env_mpool_create(uint32_t hdr_size,uint32_t elem_size,int flags,int mpool_max,bool fallback,const uint32_t limits[env_mpool_max],const char * name_prefix,bool zero)28 struct env_mpool *env_mpool_create(uint32_t hdr_size, uint32_t elem_size,
29 int flags, int mpool_max, bool fallback,
30 const uint32_t limits[env_mpool_max],
31 const char *name_prefix, bool zero)
32 {
33 int i;
34 char name[OCF_ALLOCATOR_NAME_MAX] = {};
35 int ret;
36 int size;
37
38 struct env_mpool *mpool = env_zalloc(sizeof(struct env_mpool), ENV_MEM_NOIO);
39 if (!mpool) {
40 return NULL;
41 }
42
43 mpool->hdr_size = hdr_size;
44 mpool->elem_size = elem_size;
45 mpool->mpool_max = mpool_max;
46 mpool->fallback = fallback;
47
48 for (i = 0; i < min(env_mpool_max, mpool_max + 1); i++) {
49 ret = snprintf(name, sizeof(name), "%s_%u", name_prefix, (1 << i));
50 if (ret < 0 || ret >= (int)sizeof(name)) {
51 goto err;
52 }
53
54 size = hdr_size + (elem_size * (1 << i));
55
56 mpool->allocator[i] = env_allocator_create_extended(size, name,
57 limits ? limits[i] : -1, zero);
58
59 if (!mpool->allocator[i]) {
60 goto err;
61 }
62 }
63
64 return mpool;
65
66 err:
67 env_mpool_destroy(mpool);
68 return NULL;
69 }
70
71 void
env_mpool_destroy(struct env_mpool * mpool)72 env_mpool_destroy(struct env_mpool *mpool)
73 {
74 if (mpool) {
75 int i;
76
77 for (i = 0; i < env_mpool_max; i++) {
78 if (mpool->allocator[i]) {
79 env_allocator_destroy(mpool->allocator[i]);
80 }
81 }
82
83 env_free(mpool);
84 }
85 }
86
87 static env_allocator *
env_mpool_get_allocator(struct env_mpool * mpool,uint32_t count)88 env_mpool_get_allocator(struct env_mpool *mpool,
89 uint32_t count)
90 {
91 unsigned int idx;
92
93 if (unlikely(count == 0)) {
94 return mpool->allocator[env_mpool_1];
95 }
96
97 idx = 31 - __builtin_clz(count);
98
99 if (__builtin_ffs(count) <= idx) {
100 idx++;
101 }
102
103 if (idx >= env_mpool_max || idx > mpool->mpool_max) {
104 return NULL;
105 }
106
107 return mpool->allocator[idx];
108 }
109
110 void *
env_mpool_new(struct env_mpool * mpool,uint32_t count)111 env_mpool_new(struct env_mpool *mpool, uint32_t count)
112 {
113 void *items = NULL;
114 env_allocator *allocator;
115 size_t size = mpool->hdr_size + (mpool->elem_size * count);
116
117 allocator = env_mpool_get_allocator(mpool, count);
118
119 if (allocator) {
120 items = env_allocator_new(allocator);
121 } else if (mpool->fallback) {
122 items = env_vmalloc(size);
123 }
124
125 return items;
126 }
127
128 bool
env_mpool_del(struct env_mpool * mpool,void * items,uint32_t count)129 env_mpool_del(struct env_mpool *mpool,
130 void *items, uint32_t count)
131 {
132 env_allocator *allocator;
133
134 allocator = env_mpool_get_allocator(mpool, count);
135
136 if (allocator) {
137 env_allocator_del(allocator, items);
138 } else if (mpool->fallback) {
139 env_vfree(items);
140 } else {
141 return false;
142 }
143
144 return true;
145 }
146