Line data Source code
1 : /*
2 : * Flexible array managed in PAGE_SIZE parts
3 : *
4 : * This program is free software; you can redistribute it and/or modify
5 : * it under the terms of the GNU General Public License as published by
6 : * the Free Software Foundation; either version 2 of the License, or
7 : * (at your option) any later version.
8 : *
9 : * This program is distributed in the hope that it will be useful,
10 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 : * GNU General Public License for more details.
13 : *
14 : * You should have received a copy of the GNU General Public License
15 : * along with this program; if not, write to the Free Software
16 : * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 : *
18 : * Copyright IBM Corporation, 2009
19 : *
20 : * Author: Dave Hansen <dave@linux.vnet.ibm.com>
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 :
29 : struct flex_array_part {
30 : char elements[FLEX_ARRAY_PART_SIZE];
31 : };
32 :
33 : /*
34 : * If a user requests an allocation which is small
35 : * enough, we may simply use the space in the
36 : * flex_array->parts[] array to store the user
37 : * data.
38 : */
39 : static inline int elements_fit_in_base(struct flex_array *fa)
40 : {
41 0 : int data_size = fa->element_size * fa->total_nr_elements;
42 0 : if (data_size <= FLEX_ARRAY_BASE_BYTES_LEFT)
43 : return 1;
44 : return 0;
45 : }
46 :
47 : /**
48 : * flex_array_alloc - allocate a new flexible array
49 : * @element_size: the size of individual elements in the array
50 : * @total: total number of elements that this should hold
51 : * @flags: page allocation flags to use for base array
52 : *
53 : * Note: all locking must be provided by the caller.
54 : *
55 : * @total is used to size internal structures. If the user ever
56 : * accesses any array indexes >=@total, it will produce errors.
57 : *
58 : * The maximum number of elements is defined as: the number of
59 : * elements that can be stored in a page times the number of
60 : * page pointers that we can fit in the base structure or (using
61 : * integer math):
62 : *
63 : * (PAGE_SIZE/element_size) * (PAGE_SIZE-8)/sizeof(void *)
64 : *
65 : * Here's a table showing example capacities. Note that the maximum
66 : * index that the get/put() functions is just nr_objects-1. This
67 : * basically means that you get 4MB of storage on 32-bit and 2MB on
68 : * 64-bit.
69 : *
70 : *
71 : * Element size | Objects | Objects |
72 : * PAGE_SIZE=4k | 32-bit | 64-bit |
73 : * ---------------------------------|
74 : * 1 bytes | 4177920 | 2088960 |
75 : * 2 bytes | 2088960 | 1044480 |
76 : * 3 bytes | 1392300 | 696150 |
77 : * 4 bytes | 1044480 | 522240 |
78 : * 32 bytes | 130560 | 65408 |
79 : * 33 bytes | 126480 | 63240 |
80 : * 2048 bytes | 2040 | 1020 |
81 : * 2049 bytes | 1020 | 510 |
82 : * void * | 1044480 | 261120 |
83 : *
84 : * Since 64-bit pointers are twice the size, we lose half the
85 : * capacity in the base structure. Also note that no effort is made
86 : * to efficiently pack objects across page boundaries.
87 : */
88 0 : struct 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 0 : struct reciprocal_value reciprocal_elems = { 0 };
95 :
96 0 : if (element_size) {
97 0 : elems_per_part = FLEX_ARRAY_ELEMENTS_PER_PART(element_size);
98 0 : reciprocal_elems = reciprocal_value(elems_per_part);
99 0 : max_size = FLEX_ARRAY_NR_BASE_PTRS * elems_per_part;
100 : }
101 :
102 : /* max_size will end up 0 if element_size > PAGE_SIZE */
103 0 : if (total > max_size)
104 : return NULL;
105 : ret = kzalloc(sizeof(struct flex_array), flags);
106 0 : if (!ret)
107 : return NULL;
108 0 : ret->element_size = element_size;
109 0 : ret->total_nr_elements = total;
110 0 : ret->elems_per_part = elems_per_part;
111 0 : ret->reciprocal_elems = reciprocal_elems;
112 0 : if (elements_fit_in_base(ret) && !(flags & __GFP_ZERO))
113 0 : memset(&ret->parts[0], FLEX_ARRAY_FREE,
114 : FLEX_ARRAY_BASE_BYTES_LEFT);
115 0 : return ret;
116 : }
117 : EXPORT_SYMBOL(flex_array_alloc);
118 :
119 : static int fa_element_to_part_nr(struct flex_array *fa,
120 : unsigned int element_nr)
121 : {
122 : /*
123 : * if element_size == 0 we don't get here, so we never touch
124 : * the zeroed fa->reciprocal_elems, which would yield invalid
125 : * results
126 : */
127 0 : return reciprocal_divide(element_nr, fa->reciprocal_elems);
128 : }
129 :
130 : /**
131 : * flex_array_free_parts - just free the second-level pages
132 : * @fa: the flex array from which to free parts
133 : *
134 : * This is to be used in cases where the base 'struct flex_array'
135 : * has been statically allocated and should not be free.
136 : */
137 0 : void flex_array_free_parts(struct flex_array *fa)
138 : {
139 : int part_nr;
140 :
141 0 : if (elements_fit_in_base(fa))
142 0 : return;
143 0 : for (part_nr = 0; part_nr < FLEX_ARRAY_NR_BASE_PTRS; part_nr++)
144 0 : kfree(fa->parts[part_nr]);
145 : }
146 : EXPORT_SYMBOL(flex_array_free_parts);
147 :
148 0 : void flex_array_free(struct flex_array *fa)
149 : {
150 0 : flex_array_free_parts(fa);
151 0 : kfree(fa);
152 0 : }
153 : EXPORT_SYMBOL(flex_array_free);
154 :
155 : static 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 0 : part_offset = element_nr - part_nr * fa->elems_per_part;
162 0 : return part_offset * fa->element_size;
163 : }
164 :
165 : static struct flex_array_part *
166 0 : __fa_get_part(struct flex_array *fa, int part_nr, gfp_t flags)
167 : {
168 0 : struct flex_array_part *part = fa->parts[part_nr];
169 0 : if (!part) {
170 : part = kmalloc(sizeof(struct flex_array_part), flags);
171 0 : if (!part)
172 : return NULL;
173 0 : if (!(flags & __GFP_ZERO))
174 0 : memset(part, FLEX_ARRAY_FREE,
175 : sizeof(struct flex_array_part));
176 0 : fa->parts[part_nr] = part;
177 : }
178 0 : return part;
179 : }
180 :
181 : /**
182 : * flex_array_put - copy data into the array at @element_nr
183 : * @fa: the flex array to copy data into
184 : * @element_nr: index of the position in which to insert
185 : * the new element.
186 : * @src: address of data to copy into the array
187 : * @flags: page allocation flags to use for array expansion
188 : *
189 : *
190 : * Note that this *copies* the contents of @src into
191 : * the array. If you are trying to store an array of
192 : * pointers, make sure to pass in &ptr instead of ptr.
193 : * You may instead wish to use the flex_array_put_ptr()
194 : * helper function.
195 : *
196 : * Locking must be provided by the caller.
197 : */
198 0 : int 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 0 : if (element_nr >= fa->total_nr_elements)
206 : return -ENOSPC;
207 0 : if (!fa->element_size)
208 : return 0;
209 0 : if (elements_fit_in_base(fa))
210 0 : part = (struct flex_array_part *)&fa->parts[0];
211 : else {
212 : part_nr = fa_element_to_part_nr(fa, element_nr);
213 0 : part = __fa_get_part(fa, part_nr, flags);
214 0 : if (!part)
215 : return -ENOMEM;
216 : }
217 0 : dst = &part->elements[index_inside_part(fa, element_nr, part_nr)];
218 0 : memcpy(dst, src, fa->element_size);
219 0 : return 0;
220 : }
221 : EXPORT_SYMBOL(flex_array_put);
222 :
223 : /**
224 : * flex_array_clear - clear element in array at @element_nr
225 : * @fa: the flex array of the element.
226 : * @element_nr: index of the position to clear.
227 : *
228 : * Locking must be provided by the caller.
229 : */
230 0 : int 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 0 : if (element_nr >= fa->total_nr_elements)
237 : return -ENOSPC;
238 0 : if (!fa->element_size)
239 : return 0;
240 0 : if (elements_fit_in_base(fa))
241 0 : part = (struct flex_array_part *)&fa->parts[0];
242 : else {
243 : part_nr = fa_element_to_part_nr(fa, element_nr);
244 0 : part = fa->parts[part_nr];
245 0 : if (!part)
246 : return -EINVAL;
247 : }
248 0 : dst = &part->elements[index_inside_part(fa, element_nr, part_nr)];
249 0 : memset(dst, FLEX_ARRAY_FREE, fa->element_size);
250 : return 0;
251 : }
252 : EXPORT_SYMBOL(flex_array_clear);
253 :
254 : /**
255 : * flex_array_prealloc - guarantee that array space exists
256 : * @fa: the flex array for which to preallocate parts
257 : * @start: index of first array element for which space is allocated
258 : * @nr_elements: number of elements for which space is allocated
259 : * @flags: page allocation flags
260 : *
261 : * This will guarantee that no future calls to flex_array_put()
262 : * will allocate memory. It can be used if you are expecting to
263 : * be holding a lock or in some atomic context while writing
264 : * data into the array.
265 : *
266 : * Locking must be provided by the caller.
267 : */
268 0 : int 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 0 : if (!start && !nr_elements)
278 : return 0;
279 0 : if (start >= fa->total_nr_elements)
280 : return -ENOSPC;
281 0 : if (!nr_elements)
282 : return 0;
283 :
284 0 : end = start + nr_elements - 1;
285 :
286 0 : if (end >= fa->total_nr_elements)
287 : return -ENOSPC;
288 0 : if (!fa->element_size)
289 : return 0;
290 0 : 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 0 : for (part_nr = start_part; part_nr <= end_part; part_nr++) {
295 0 : part = __fa_get_part(fa, part_nr, flags);
296 0 : if (!part)
297 : return -ENOMEM;
298 : }
299 : return 0;
300 : }
301 : EXPORT_SYMBOL(flex_array_prealloc);
302 :
303 : /**
304 : * flex_array_get - pull data back out of the array
305 : * @fa: the flex array from which to extract data
306 : * @element_nr: index of the element to fetch from the array
307 : *
308 : * Returns a pointer to the data at index @element_nr. Note
309 : * that this is a copy of the data that was passed in. If you
310 : * are using this to store pointers, you'll get back &ptr. You
311 : * may instead wish to use the flex_array_get_ptr helper.
312 : *
313 : * Locking must be provided by the caller.
314 : */
315 0 : void *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 0 : if (!fa->element_size)
321 : return NULL;
322 0 : if (element_nr >= fa->total_nr_elements)
323 : return NULL;
324 0 : if (elements_fit_in_base(fa))
325 0 : part = (struct flex_array_part *)&fa->parts[0];
326 : else {
327 : part_nr = fa_element_to_part_nr(fa, element_nr);
328 0 : part = fa->parts[part_nr];
329 0 : if (!part)
330 : return NULL;
331 : }
332 0 : return &part->elements[index_inside_part(fa, element_nr, part_nr)];
333 : }
334 : EXPORT_SYMBOL(flex_array_get);
335 :
336 : /**
337 : * flex_array_get_ptr - pull a ptr back out of the array
338 : * @fa: the flex array from which to extract data
339 : * @element_nr: index of the element to fetch from the array
340 : *
341 : * Returns the pointer placed in the flex array at element_nr using
342 : * flex_array_put_ptr(). This function should not be called if the
343 : * element in question was not set using the _put_ptr() helper.
344 : */
345 0 : void *flex_array_get_ptr(struct flex_array *fa, unsigned int element_nr)
346 : {
347 : void **tmp;
348 :
349 0 : tmp = flex_array_get(fa, element_nr);
350 0 : if (!tmp)
351 : return NULL;
352 :
353 0 : return *tmp;
354 : }
355 : EXPORT_SYMBOL(flex_array_get_ptr);
356 :
357 : static int part_is_free(struct flex_array_part *part)
358 : {
359 : int i;
360 :
361 0 : for (i = 0; i < sizeof(struct flex_array_part); i++)
362 0 : if (part->elements[i] != FLEX_ARRAY_FREE)
363 : return 0;
364 : return 1;
365 : }
366 :
367 : /**
368 : * flex_array_shrink - free unused second-level pages
369 : * @fa: the flex array to shrink
370 : *
371 : * Frees all second-level pages that consist solely of unused
372 : * elements. Returns the number of pages freed.
373 : *
374 : * Locking must be provided by the caller.
375 : */
376 0 : int flex_array_shrink(struct flex_array *fa)
377 : {
378 : struct flex_array_part *part;
379 : int part_nr;
380 : int ret = 0;
381 :
382 0 : if (!fa->total_nr_elements || !fa->element_size)
383 : return 0;
384 0 : if (elements_fit_in_base(fa))
385 : return ret;
386 0 : for (part_nr = 0; part_nr < FLEX_ARRAY_NR_BASE_PTRS; part_nr++) {
387 0 : part = fa->parts[part_nr];
388 0 : if (!part)
389 0 : continue;
390 0 : if (part_is_free(part)) {
391 0 : fa->parts[part_nr] = NULL;
392 0 : kfree(part);
393 0 : ret++;
394 : }
395 : }
396 : return ret;
397 : }
398 : EXPORT_SYMBOL(flex_array_shrink);
|