1 /* SPDX-License-Identifier: GPL-2.0 */ 2 #ifndef _FLEX_ARRAY_H 3 #define _FLEX_ARRAY_H 4 5 #include <linux/types.h> 6 #include <linux/reciprocal_div.h> 7 #include <asm/page.h> 8 9 #define FLEX_ARRAY_PART_SIZE PAGE_SIZE 10 #define FLEX_ARRAY_BASE_SIZE PAGE_SIZE 11 12 struct flex_array_part; 13 14 /* 15 * This is meant to replace cases where an array-like 16 * structure has gotten too big to fit into kmalloc() 17 * and the developer is getting tempted to use 18 * vmalloc(). 19 */ 20 21 struct flex_array { 22 union { 23 struct { 24 int element_size; 25 int total_nr_elements; 26 int elems_per_part; 27 struct reciprocal_value reciprocal_elems; 28 struct flex_array_part *parts[]; 29 }; 30 /* 31 * This little trick makes sure that 32 * sizeof(flex_array) == PAGE_SIZE 33 */ 34 char padding[FLEX_ARRAY_BASE_SIZE]; 35 }; 36 }; 37 38 /* Number of bytes left in base struct flex_array, excluding metadata */ 39 #define FLEX_ARRAY_BASE_BYTES_LEFT \ 40 (FLEX_ARRAY_BASE_SIZE - offsetof(struct flex_array, parts)) 41 42 /* Number of pointers in base to struct flex_array_part pages */ 43 #define FLEX_ARRAY_NR_BASE_PTRS \ 44 (FLEX_ARRAY_BASE_BYTES_LEFT / sizeof(struct flex_array_part *)) 45 46 /* Number of elements of size that fit in struct flex_array_part */ 47 #define FLEX_ARRAY_ELEMENTS_PER_PART(size) \ 48 (FLEX_ARRAY_PART_SIZE / size) 49 50 /* 51 * Defines a statically allocated flex array and ensures its parameters are 52 * valid. 53 */ 54 #define DEFINE_FLEX_ARRAY(__arrayname, __element_size, __total) \ 55 struct flex_array __arrayname = { { { \ 56 .element_size = (__element_size), \ 57 .total_nr_elements = (__total), \ 58 } } }; \ 59 static inline void __arrayname##_invalid_parameter(void) \ 60 { \ 61 BUILD_BUG_ON((__total) > FLEX_ARRAY_NR_BASE_PTRS * \ 62 FLEX_ARRAY_ELEMENTS_PER_PART(__element_size)); \ 63 } 64 65 /** 66 * flex_array_alloc() - Creates a flexible array. 67 * @element_size: individual object size. 68 * @total: maximum number of objects which can be stored. 69 * @flags: GFP flags 70 * 71 * Return: Returns an object of structure flex_array. 72 */ 73 struct flex_array *flex_array_alloc(int element_size, unsigned int total, 74 gfp_t flags); 75 76 /** 77 * flex_array_prealloc() - Ensures that memory for the elements indexed in the 78 * range defined by start and nr_elements has been allocated. 79 * @fa: array to allocate memory to. 80 * @start: start address 81 * @nr_elements: number of elements to be allocated. 82 * @flags: GFP flags 83 * 84 */ 85 int flex_array_prealloc(struct flex_array *fa, unsigned int start, 86 unsigned int nr_elements, gfp_t flags); 87 88 /** 89 * flex_array_free() - Removes all elements of a flexible array. 90 * @fa: array to be freed. 91 */ 92 void flex_array_free(struct flex_array *fa); 93 94 /** 95 * flex_array_free_parts() - Removes all elements of a flexible array, but 96 * leaves the array itself in place. 97 * @fa: array to be emptied. 98 */ 99 void flex_array_free_parts(struct flex_array *fa); 100 101 /** 102 * flex_array_put() - Stores data into a flexible array. 103 * @fa: array where element is to be stored. 104 * @element_nr: position to copy, must be less than the maximum specified when 105 * the array was created. 106 * @src: data source to be copied into the array. 107 * @flags: GFP flags 108 * 109 * Return: Returns zero on success, a negative error code otherwise. 110 */ 111 int flex_array_put(struct flex_array *fa, unsigned int element_nr, void *src, 112 gfp_t flags); 113 114 /** 115 * flex_array_clear() - Clears an individual element in the array, sets the 116 * given element to FLEX_ARRAY_FREE. 117 * @element_nr: element position to clear. 118 * @fa: array to which element to be cleared belongs. 119 * 120 * Return: Returns zero on success, -EINVAL otherwise. 121 */ 122 int flex_array_clear(struct flex_array *fa, unsigned int element_nr); 123 124 /** 125 * flex_array_get() - Retrieves data into a flexible array. 126 * 127 * @element_nr: Element position to retrieve data from. 128 * @fa: array from which data is to be retrieved. 129 * 130 * Return: Returns a pointer to the data element, or NULL if that 131 * particular element has never been allocated. 132 */ 133 void *flex_array_get(struct flex_array *fa, unsigned int element_nr); 134 135 /** 136 * flex_array_shrink() - Reduces the allocated size of an array. 137 * @fa: array to shrink. 138 * 139 * Return: Returns number of pages of memory actually freed. 140 * 141 */ 142 int flex_array_shrink(struct flex_array *fa); 143 144 #define flex_array_put_ptr(fa, nr, src, gfp) \ 145 flex_array_put(fa, nr, (void *)&(src), gfp) 146 147 void *flex_array_get_ptr(struct flex_array *fa, unsigned int element_nr); 148 149 #endif /* _FLEX_ARRAY_H */ 150