1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23#include <linux/flex_array.h>
24#include <linux/slab.h>
25#include <linux/stddef.h>
26#include <linux/export.h>
27#include <linux/reciprocal_div.h>
28
29struct flex_array_part {
30 char elements[FLEX_ARRAY_PART_SIZE];
31};
32
33
34
35
36
37
38
39static inline int elements_fit_in_base(struct flex_array *fa)
40{
41 int data_size = fa->element_size * fa->total_nr_elements;
42 if (data_size <= FLEX_ARRAY_BASE_BYTES_LEFT)
43 return 1;
44 return 0;
45}
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88struct flex_array *flex_array_alloc(int element_size, unsigned int total,
89 gfp_t flags)
90{
91 struct flex_array *ret;
92 int elems_per_part = 0;
93 int max_size = 0;
94 struct reciprocal_value reciprocal_elems = { 0 };
95
96 if (element_size) {
97 elems_per_part = FLEX_ARRAY_ELEMENTS_PER_PART(element_size);
98 reciprocal_elems = reciprocal_value(elems_per_part);
99 max_size = FLEX_ARRAY_NR_BASE_PTRS * elems_per_part;
100 }
101
102
103 if (total > max_size)
104 return NULL;
105 ret = kzalloc(sizeof(struct flex_array), flags);
106 if (!ret)
107 return NULL;
108 ret->element_size = element_size;
109 ret->total_nr_elements = total;
110 ret->elems_per_part = elems_per_part;
111 ret->reciprocal_elems = reciprocal_elems;
112 if (elements_fit_in_base(ret) && !(flags & __GFP_ZERO))
113 memset(&ret->parts[0], FLEX_ARRAY_FREE,
114 FLEX_ARRAY_BASE_BYTES_LEFT);
115 return ret;
116}
117EXPORT_SYMBOL(flex_array_alloc);
118
119static int fa_element_to_part_nr(struct flex_array *fa,
120 unsigned int element_nr)
121{
122
123
124
125
126
127 return reciprocal_divide(element_nr, fa->reciprocal_elems);
128}
129
130
131
132
133
134
135
136
137void flex_array_free_parts(struct flex_array *fa)
138{
139 int part_nr;
140
141 if (elements_fit_in_base(fa))
142 return;
143 for (part_nr = 0; part_nr < FLEX_ARRAY_NR_BASE_PTRS; part_nr++)
144 kfree(fa->parts[part_nr]);
145}
146EXPORT_SYMBOL(flex_array_free_parts);
147
148void flex_array_free(struct flex_array *fa)
149{
150 flex_array_free_parts(fa);
151 kfree(fa);
152}
153EXPORT_SYMBOL(flex_array_free);
154
155static unsigned int index_inside_part(struct flex_array *fa,
156 unsigned int element_nr,
157 unsigned int part_nr)
158{
159 unsigned int part_offset;
160
161 part_offset = element_nr - part_nr * fa->elems_per_part;
162 return part_offset * fa->element_size;
163}
164
165static struct flex_array_part *
166__fa_get_part(struct flex_array *fa, int part_nr, gfp_t flags)
167{
168 struct flex_array_part *part = fa->parts[part_nr];
169 if (!part) {
170 part = kmalloc(sizeof(struct flex_array_part), flags);
171 if (!part)
172 return NULL;
173 if (!(flags & __GFP_ZERO))
174 memset(part, FLEX_ARRAY_FREE,
175 sizeof(struct flex_array_part));
176 fa->parts[part_nr] = part;
177 }
178 return part;
179}
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198int flex_array_put(struct flex_array *fa, unsigned int element_nr, void *src,
199 gfp_t flags)
200{
201 int part_nr = 0;
202 struct flex_array_part *part;
203 void *dst;
204
205 if (element_nr >= fa->total_nr_elements)
206 return -ENOSPC;
207 if (!fa->element_size)
208 return 0;
209 if (elements_fit_in_base(fa))
210 part = (struct flex_array_part *)&fa->parts[0];
211 else {
212 part_nr = fa_element_to_part_nr(fa, element_nr);
213 part = __fa_get_part(fa, part_nr, flags);
214 if (!part)
215 return -ENOMEM;
216 }
217 dst = &part->elements[index_inside_part(fa, element_nr, part_nr)];
218 memcpy(dst, src, fa->element_size);
219 return 0;
220}
221EXPORT_SYMBOL(flex_array_put);
222
223
224
225
226
227
228
229
230int flex_array_clear(struct flex_array *fa, unsigned int element_nr)
231{
232 int part_nr = 0;
233 struct flex_array_part *part;
234 void *dst;
235
236 if (element_nr >= fa->total_nr_elements)
237 return -ENOSPC;
238 if (!fa->element_size)
239 return 0;
240 if (elements_fit_in_base(fa))
241 part = (struct flex_array_part *)&fa->parts[0];
242 else {
243 part_nr = fa_element_to_part_nr(fa, element_nr);
244 part = fa->parts[part_nr];
245 if (!part)
246 return -EINVAL;
247 }
248 dst = &part->elements[index_inside_part(fa, element_nr, part_nr)];
249 memset(dst, FLEX_ARRAY_FREE, fa->element_size);
250 return 0;
251}
252EXPORT_SYMBOL(flex_array_clear);
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268int flex_array_prealloc(struct flex_array *fa, unsigned int start,
269 unsigned int nr_elements, gfp_t flags)
270{
271 int start_part;
272 int end_part;
273 int part_nr;
274 unsigned int end;
275 struct flex_array_part *part;
276
277 if (!start && !nr_elements)
278 return 0;
279 if (start >= fa->total_nr_elements)
280 return -ENOSPC;
281 if (!nr_elements)
282 return 0;
283
284 end = start + nr_elements - 1;
285
286 if (end >= fa->total_nr_elements)
287 return -ENOSPC;
288 if (!fa->element_size)
289 return 0;
290 if (elements_fit_in_base(fa))
291 return 0;
292 start_part = fa_element_to_part_nr(fa, start);
293 end_part = fa_element_to_part_nr(fa, end);
294 for (part_nr = start_part; part_nr <= end_part; part_nr++) {
295 part = __fa_get_part(fa, part_nr, flags);
296 if (!part)
297 return -ENOMEM;
298 }
299 return 0;
300}
301EXPORT_SYMBOL(flex_array_prealloc);
302
303
304
305
306
307
308
309
310
311
312
313
314
315void *flex_array_get(struct flex_array *fa, unsigned int element_nr)
316{
317 int part_nr = 0;
318 struct flex_array_part *part;
319
320 if (!fa->element_size)
321 return NULL;
322 if (element_nr >= fa->total_nr_elements)
323 return NULL;
324 if (elements_fit_in_base(fa))
325 part = (struct flex_array_part *)&fa->parts[0];
326 else {
327 part_nr = fa_element_to_part_nr(fa, element_nr);
328 part = fa->parts[part_nr];
329 if (!part)
330 return NULL;
331 }
332 return &part->elements[index_inside_part(fa, element_nr, part_nr)];
333}
334EXPORT_SYMBOL(flex_array_get);
335
336
337
338
339
340
341
342
343
344
345void *flex_array_get_ptr(struct flex_array *fa, unsigned int element_nr)
346{
347 void **tmp;
348
349 tmp = flex_array_get(fa, element_nr);
350 if (!tmp)
351 return NULL;
352
353 return *tmp;
354}
355EXPORT_SYMBOL(flex_array_get_ptr);
356
357static int part_is_free(struct flex_array_part *part)
358{
359 int i;
360
361 for (i = 0; i < sizeof(struct flex_array_part); i++)
362 if (part->elements[i] != FLEX_ARRAY_FREE)
363 return 0;
364 return 1;
365}
366
367
368
369
370
371
372
373
374
375
376int flex_array_shrink(struct flex_array *fa)
377{
378 struct flex_array_part *part;
379 int part_nr;
380 int ret = 0;
381
382 if (!fa->total_nr_elements || !fa->element_size)
383 return 0;
384 if (elements_fit_in_base(fa))
385 return ret;
386 for (part_nr = 0; part_nr < FLEX_ARRAY_NR_BASE_PTRS; part_nr++) {
387 part = fa->parts[part_nr];
388 if (!part)
389 continue;
390 if (part_is_free(part)) {
391 fa->parts[part_nr] = NULL;
392 kfree(part);
393 ret++;
394 }
395 }
396 return ret;
397}
398EXPORT_SYMBOL(flex_array_shrink);
399