/**
 * flex_array_alloc - allocate a new flexible array
 * @element_size:	the size of individual elements in the array
 * @total:		total number of elements that this should hold
 * @flags:		page allocation flags to use for base array
 *
 * Note: all locking must be provided by the caller.
 *
 * @total is used to size internal structures.  If the user ever
 * accesses any array indexes >=@total, it will produce errors.
 *
 * The maximum number of elements is defined as: the number of
 * elements that can be stored in a page times the number of
 * page pointers that we can fit in the base structure or (using
 * integer math):
 *
 * 	(PAGE_SIZE/element_size) * (PAGE_SIZE-8)/sizeof(void *)
 *
 * Here's a table showing example capacities.  Note that the maximum
 * index that the get/put() functions is just nr_objects-1.   This
 * basically means that you get 4MB of storage on 32-bit and 2MB on
 * 64-bit.
 *
 *
 * Element size | Objects | Objects |
 * PAGE_SIZE=4k |  32-bit |  64-bit |
 * ---------------------------------|
 *      1 bytes | 4177920 | 2088960 |
 *      2 bytes | 2088960 | 1044480 |
 *      3 bytes | 1392300 |  696150 |
 *      4 bytes | 1044480 |  522240 |
 *     32 bytes |  130560 |   65408 |
 *     33 bytes |  126480 |   63240 |
 *   2048 bytes |    2040 |    1020 |
 *   2049 bytes |    1020 |     510 |
 *       void * | 1044480 |  261120 |
 *
 * Since 64-bit pointers are twice the size, we lose half the
 * capacity in the base structure.  Also note that no effort is made
 * to efficiently pack objects across page boundaries.
 */
struct flex_array *flex_array_alloc(int element_size, unsigned int total,
					gfp_t flags)
{
	struct flex_array *ret;
	int elems_per_part = 0;
	int reciprocal_elems = 0;
	int max_size = 0;

	if (element_size) {
		elems_per_part = FLEX_ARRAY_ELEMENTS_PER_PART(element_size);
		reciprocal_elems = reciprocal_value(elems_per_part);
		max_size = FLEX_ARRAY_NR_BASE_PTRS * elems_per_part;
	}

	/* max_size will end up 0 if element_size > PAGE_SIZE */
	if (total > max_size)
		return NULL;
	ret = kzalloc(sizeof(struct flex_array), flags);
	if (!ret)
		return NULL;
	ret->element_size = element_size;
	ret->total_nr_elements = total;
	ret->elems_per_part = elems_per_part;
	ret->reciprocal_elems = reciprocal_elems;
	if (elements_fit_in_base(ret) && !(flags & __GFP_ZERO))
		memset(&ret->parts[0], FLEX_ARRAY_FREE,
						FLEX_ARRAY_BASE_BYTES_LEFT);
	return ret;
}
Exemple #2
0
static unsigned int index_inside_part(struct flex_array *fa,
					unsigned int element_nr)
{
	unsigned int part_offset;

	part_offset = element_nr %
				FLEX_ARRAY_ELEMENTS_PER_PART(fa->element_size);
	return part_offset * fa->element_size;
}
Exemple #3
0
static int fa_element_to_part_nr(struct flex_array *fa,
					unsigned int element_nr)
{
	return element_nr / FLEX_ARRAY_ELEMENTS_PER_PART(fa->element_size);
}