linux/lib/flex_array.c
<<
>>
Prefs
   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/module.h>
  27
  28struct flex_array_part {
  29        char elements[FLEX_ARRAY_PART_SIZE];
  30};
  31
  32/*
  33 * If a user requests an allocation which is small
  34 * enough, we may simply use the space in the
  35 * flex_array->parts[] array to store the user
  36 * data.
  37 */
  38static inline int elements_fit_in_base(struct flex_array *fa)
  39{
  40        int data_size = fa->element_size * fa->total_nr_elements;
  41        if (data_size <= FLEX_ARRAY_BASE_BYTES_LEFT)
  42                return 1;
  43        return 0;
  44}
  45
  46/**
  47 * flex_array_alloc - allocate a new flexible array
  48 * @element_size:       the size of individual elements in the array
  49 * @total:              total number of elements that this should hold
  50 * @flags:              page allocation flags to use for base array
  51 *
  52 * Note: all locking must be provided by the caller.
  53 *
  54 * @total is used to size internal structures.  If the user ever
  55 * accesses any array indexes >=@total, it will produce errors.
  56 *
  57 * The maximum number of elements is defined as: the number of
  58 * elements that can be stored in a page times the number of
  59 * page pointers that we can fit in the base structure or (using
  60 * integer math):
  61 *
  62 *      (PAGE_SIZE/element_size) * (PAGE_SIZE-8)/sizeof(void *)
  63 *
  64 * Here's a table showing example capacities.  Note that the maximum
  65 * index that the get/put() functions is just nr_objects-1.   This
  66 * basically means that you get 4MB of storage on 32-bit and 2MB on
  67 * 64-bit.
  68 *
  69 *
  70 * Element size | Objects | Objects |
  71 * PAGE_SIZE=4k |  32-bit |  64-bit |
  72 * ---------------------------------|
  73 *      1 bytes | 4186112 | 2093056 |
  74 *      2 bytes | 2093056 | 1046528 |
  75 *      3 bytes | 1395030 |  697515 |
  76 *      4 bytes | 1046528 |  523264 |
  77 *     32 bytes |  130816 |   65408 |
  78 *     33 bytes |  126728 |   63364 |
  79 *   2048 bytes |    2044 |    1022 |
  80 *   2049 bytes |    1022 |     511 |
  81 *       void * | 1046528 |  261632 |
  82 *
  83 * Since 64-bit pointers are twice the size, we lose half the
  84 * capacity in the base structure.  Also note that no effort is made
  85 * to efficiently pack objects across page boundaries.
  86 */
  87struct flex_array *flex_array_alloc(int element_size, unsigned int total,
  88                                        gfp_t flags)
  89{
  90        struct flex_array *ret;
  91        int max_size = FLEX_ARRAY_NR_BASE_PTRS *
  92                                FLEX_ARRAY_ELEMENTS_PER_PART(element_size);
  93
  94        /* max_size will end up 0 if element_size > PAGE_SIZE */
  95        if (total > max_size)
  96                return NULL;
  97        ret = kzalloc(sizeof(struct flex_array), flags);
  98        if (!ret)
  99                return NULL;
 100        ret->element_size = element_size;
 101        ret->total_nr_elements = total;
 102        if (elements_fit_in_base(ret) && !(flags & __GFP_ZERO))
 103                memset(&ret->parts[0], FLEX_ARRAY_FREE,
 104                                                FLEX_ARRAY_BASE_BYTES_LEFT);
 105        return ret;
 106}
 107EXPORT_SYMBOL(flex_array_alloc);
 108
 109static int fa_element_to_part_nr(struct flex_array *fa,
 110                                        unsigned int element_nr)
 111{
 112        return element_nr / FLEX_ARRAY_ELEMENTS_PER_PART(fa->element_size);
 113}
 114
 115/**
 116 * flex_array_free_parts - just free the second-level pages
 117 * @fa:         the flex array from which to free parts
 118 *
 119 * This is to be used in cases where the base 'struct flex_array'
 120 * has been statically allocated and should not be free.
 121 */
 122void flex_array_free_parts(struct flex_array *fa)
 123{
 124        int part_nr;
 125
 126        if (elements_fit_in_base(fa))
 127                return;
 128        for (part_nr = 0; part_nr < FLEX_ARRAY_NR_BASE_PTRS; part_nr++)
 129                kfree(fa->parts[part_nr]);
 130}
 131EXPORT_SYMBOL(flex_array_free_parts);
 132
 133void flex_array_free(struct flex_array *fa)
 134{
 135        flex_array_free_parts(fa);
 136        kfree(fa);
 137}
 138EXPORT_SYMBOL(flex_array_free);
 139
 140static unsigned int index_inside_part(struct flex_array *fa,
 141                                        unsigned int element_nr)
 142{
 143        unsigned int part_offset;
 144
 145        part_offset = element_nr %
 146                                FLEX_ARRAY_ELEMENTS_PER_PART(fa->element_size);
 147        return part_offset * fa->element_size;
 148}
 149
 150static struct flex_array_part *
 151__fa_get_part(struct flex_array *fa, int part_nr, gfp_t flags)
 152{
 153        struct flex_array_part *part = fa->parts[part_nr];
 154        if (!part) {
 155                part = kmalloc(sizeof(struct flex_array_part), flags);
 156                if (!part)
 157                        return NULL;
 158                if (!(flags & __GFP_ZERO))
 159                        memset(part, FLEX_ARRAY_FREE,
 160                                sizeof(struct flex_array_part));
 161                fa->parts[part_nr] = part;
 162        }
 163        return part;
 164}
 165
 166/**
 167 * flex_array_put - copy data into the array at @element_nr
 168 * @fa:         the flex array to copy data into
 169 * @element_nr: index of the position in which to insert
 170 *              the new element.
 171 * @src:        address of data to copy into the array
 172 * @flags:      page allocation flags to use for array expansion
 173 *
 174 *
 175 * Note that this *copies* the contents of @src into
 176 * the array.  If you are trying to store an array of
 177 * pointers, make sure to pass in &ptr instead of ptr.
 178 * You may instead wish to use the flex_array_put_ptr()
 179 * helper function.
 180 *
 181 * Locking must be provided by the caller.
 182 */
 183int flex_array_put(struct flex_array *fa, unsigned int element_nr, void *src,
 184                        gfp_t flags)
 185{
 186        int part_nr = fa_element_to_part_nr(fa, element_nr);
 187        struct flex_array_part *part;
 188        void *dst;
 189
 190        if (element_nr >= fa->total_nr_elements)
 191                return -ENOSPC;
 192        if (elements_fit_in_base(fa))
 193                part = (struct flex_array_part *)&fa->parts[0];
 194        else {
 195                part = __fa_get_part(fa, part_nr, flags);
 196                if (!part)
 197                        return -ENOMEM;
 198        }
 199        dst = &part->elements[index_inside_part(fa, element_nr)];
 200        memcpy(dst, src, fa->element_size);
 201        return 0;
 202}
 203EXPORT_SYMBOL(flex_array_put);
 204
 205/**
 206 * flex_array_clear - clear element in array at @element_nr
 207 * @fa:         the flex array of the element.
 208 * @element_nr: index of the position to clear.
 209 *
 210 * Locking must be provided by the caller.
 211 */
 212int flex_array_clear(struct flex_array *fa, unsigned int element_nr)
 213{
 214        int part_nr = fa_element_to_part_nr(fa, element_nr);
 215        struct flex_array_part *part;
 216        void *dst;
 217
 218        if (element_nr >= fa->total_nr_elements)
 219                return -ENOSPC;
 220        if (elements_fit_in_base(fa))
 221                part = (struct flex_array_part *)&fa->parts[0];
 222        else {
 223                part = fa->parts[part_nr];
 224                if (!part)
 225                        return -EINVAL;
 226        }
 227        dst = &part->elements[index_inside_part(fa, element_nr)];
 228        memset(dst, FLEX_ARRAY_FREE, fa->element_size);
 229        return 0;
 230}
 231EXPORT_SYMBOL(flex_array_clear);
 232
 233/**
 234 * flex_array_prealloc - guarantee that array space exists
 235 * @fa:         the flex array for which to preallocate parts
 236 * @start:      index of first array element for which space is allocated
 237 * @end:        index of last (inclusive) element for which space is allocated
 238 * @flags:      page allocation flags
 239 *
 240 * This will guarantee that no future calls to flex_array_put()
 241 * will allocate memory.  It can be used if you are expecting to
 242 * be holding a lock or in some atomic context while writing
 243 * data into the array.
 244 *
 245 * Locking must be provided by the caller.
 246 */
 247int flex_array_prealloc(struct flex_array *fa, unsigned int start,
 248                        unsigned int end, gfp_t flags)
 249{
 250        int start_part;
 251        int end_part;
 252        int part_nr;
 253        struct flex_array_part *part;
 254
 255        if (start >= fa->total_nr_elements || end >= fa->total_nr_elements)
 256                return -ENOSPC;
 257        if (elements_fit_in_base(fa))
 258                return 0;
 259        start_part = fa_element_to_part_nr(fa, start);
 260        end_part = fa_element_to_part_nr(fa, end);
 261        for (part_nr = start_part; part_nr <= end_part; part_nr++) {
 262                part = __fa_get_part(fa, part_nr, flags);
 263                if (!part)
 264                        return -ENOMEM;
 265        }
 266        return 0;
 267}
 268EXPORT_SYMBOL(flex_array_prealloc);
 269
 270/**
 271 * flex_array_get - pull data back out of the array
 272 * @fa:         the flex array from which to extract data
 273 * @element_nr: index of the element to fetch from the array
 274 *
 275 * Returns a pointer to the data at index @element_nr.  Note
 276 * that this is a copy of the data that was passed in.  If you
 277 * are using this to store pointers, you'll get back &ptr.  You
 278 * may instead wish to use the flex_array_get_ptr helper.
 279 *
 280 * Locking must be provided by the caller.
 281 */
 282void *flex_array_get(struct flex_array *fa, unsigned int element_nr)
 283{
 284        int part_nr = fa_element_to_part_nr(fa, element_nr);
 285        struct flex_array_part *part;
 286
 287        if (element_nr >= fa->total_nr_elements)
 288                return NULL;
 289        if (elements_fit_in_base(fa))
 290                part = (struct flex_array_part *)&fa->parts[0];
 291        else {
 292                part = fa->parts[part_nr];
 293                if (!part)
 294                        return NULL;
 295        }
 296        return &part->elements[index_inside_part(fa, element_nr)];
 297}
 298EXPORT_SYMBOL(flex_array_get);
 299
 300/**
 301 * flex_array_get_ptr - pull a ptr back out of the array
 302 * @fa:         the flex array from which to extract data
 303 * @element_nr: index of the element to fetch from the array
 304 *
 305 * Returns the pointer placed in the flex array at element_nr using
 306 * flex_array_put_ptr().  This function should not be called if the
 307 * element in question was not set using the _put_ptr() helper.
 308 */
 309void *flex_array_get_ptr(struct flex_array *fa, unsigned int element_nr)
 310{
 311        void **tmp;
 312
 313        tmp = flex_array_get(fa, element_nr);
 314        if (!tmp)
 315                return NULL;
 316
 317        return *tmp;
 318}
 319EXPORT_SYMBOL(flex_array_get_ptr);
 320
 321static int part_is_free(struct flex_array_part *part)
 322{
 323        int i;
 324
 325        for (i = 0; i < sizeof(struct flex_array_part); i++)
 326                if (part->elements[i] != FLEX_ARRAY_FREE)
 327                        return 0;
 328        return 1;
 329}
 330
 331/**
 332 * flex_array_shrink - free unused second-level pages
 333 * @fa:         the flex array to shrink
 334 *
 335 * Frees all second-level pages that consist solely of unused
 336 * elements.  Returns the number of pages freed.
 337 *
 338 * Locking must be provided by the caller.
 339 */
 340int flex_array_shrink(struct flex_array *fa)
 341{
 342        struct flex_array_part *part;
 343        int part_nr;
 344        int ret = 0;
 345
 346        if (elements_fit_in_base(fa))
 347                return ret;
 348        for (part_nr = 0; part_nr < FLEX_ARRAY_NR_BASE_PTRS; part_nr++) {
 349                part = fa->parts[part_nr];
 350                if (!part)
 351                        continue;
 352                if (part_is_free(part)) {
 353                        fa->parts[part_nr] = NULL;
 354                        kfree(part);
 355                        ret++;
 356                }
 357        }
 358        return ret;
 359}
 360EXPORT_SYMBOL(flex_array_shrink);
 361