diff options
| author | David Rientjes <rientjes@google.com> | 2009-09-21 20:04:33 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-09-22 10:17:47 -0400 |
| commit | 45b588d6e5cc172704bac0c998ce54873b149b22 (patch) | |
| tree | 57a9d3478af60fcf6932c1f61b083b9203ef1ee8 /lib | |
| parent | 4af5a2f770cc8575840ccb1514ec76ecb592985c (diff) | |
flex_array: introduce DEFINE_FLEX_ARRAY
FLEX_ARRAY_INIT(element_size, total_nr_elements) cannot determine if
either parameter is valid, so flex arrays which are statically allocated
with this interface can easily become corrupted or reference beyond its
allocated memory.
This removes FLEX_ARRAY_INIT() as a struct flex_array initializer since no
initializer may perform the required checking. Instead, the array is now
defined with a new interface:
DEFINE_FLEX_ARRAY(name, element_size, total_nr_elements)
This may be prefixed with `static' for file scope.
This interface includes compile-time checking of the parameters to ensure
they are valid. Since the validity of both element_size and
total_nr_elements depend on FLEX_ARRAY_BASE_SIZE and FLEX_ARRAY_PART_SIZE,
the kernel build will fail if either of these predefined values changes
such that the array parameters are no longer valid.
Since BUILD_BUG_ON() requires compile time constants, several of the
static inline functions that were once local to lib/flex_array.c had to be
moved to include/linux/flex_array.h.
Signed-off-by: David Rientjes <rientjes@google.com>
Acked-by: Dave Hansen <dave@linux.vnet.ibm.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/flex_array.c | 36 |
1 files changed, 10 insertions, 26 deletions
diff --git a/lib/flex_array.c b/lib/flex_array.c index 1b03bb553410..b62ce6cffd0a 100644 --- a/lib/flex_array.c +++ b/lib/flex_array.c | |||
| @@ -28,23 +28,6 @@ struct flex_array_part { | |||
| 28 | char elements[FLEX_ARRAY_PART_SIZE]; | 28 | char elements[FLEX_ARRAY_PART_SIZE]; |
| 29 | }; | 29 | }; |
| 30 | 30 | ||
| 31 | static inline int __elements_per_part(int element_size) | ||
| 32 | { | ||
| 33 | return FLEX_ARRAY_PART_SIZE / element_size; | ||
| 34 | } | ||
| 35 | |||
| 36 | static inline int bytes_left_in_base(void) | ||
| 37 | { | ||
| 38 | int element_offset = offsetof(struct flex_array, parts); | ||
| 39 | int bytes_left = FLEX_ARRAY_BASE_SIZE - element_offset; | ||
| 40 | return bytes_left; | ||
| 41 | } | ||
| 42 | |||
| 43 | static inline int nr_base_part_ptrs(void) | ||
| 44 | { | ||
| 45 | return bytes_left_in_base() / sizeof(struct flex_array_part *); | ||
| 46 | } | ||
| 47 | |||
| 48 | /* | 31 | /* |
| 49 | * If a user requests an allocation which is small | 32 | * If a user requests an allocation which is small |
| 50 | * enough, we may simply use the space in the | 33 | * enough, we may simply use the space in the |
| @@ -54,7 +37,7 @@ static inline int nr_base_part_ptrs(void) | |||
| 54 | static inline int elements_fit_in_base(struct flex_array *fa) | 37 | static inline int elements_fit_in_base(struct flex_array *fa) |
| 55 | { | 38 | { |
| 56 | int data_size = fa->element_size * fa->total_nr_elements; | 39 | int data_size = fa->element_size * fa->total_nr_elements; |
| 57 | if (data_size <= bytes_left_in_base()) | 40 | if (data_size <= FLEX_ARRAY_BASE_BYTES_LEFT) |
| 58 | return 1; | 41 | return 1; |
| 59 | return 0; | 42 | return 0; |
| 60 | } | 43 | } |
| @@ -103,7 +86,8 @@ struct flex_array *flex_array_alloc(int element_size, unsigned int total, | |||
| 103 | gfp_t flags) | 86 | gfp_t flags) |
| 104 | { | 87 | { |
| 105 | struct flex_array *ret; | 88 | struct flex_array *ret; |
| 106 | int max_size = nr_base_part_ptrs() * __elements_per_part(element_size); | 89 | int max_size = FLEX_ARRAY_NR_BASE_PTRS * |
| 90 | FLEX_ARRAY_ELEMENTS_PER_PART(element_size); | ||
| 107 | 91 | ||
| 108 | /* max_size will end up 0 if element_size > PAGE_SIZE */ | 92 | /* max_size will end up 0 if element_size > PAGE_SIZE */ |
| 109 | if (total > max_size) | 93 | if (total > max_size) |
| @@ -114,14 +98,15 @@ struct flex_array *flex_array_alloc(int element_size, unsigned int total, | |||
| 114 | ret->element_size = element_size; | 98 | ret->element_size = element_size; |
| 115 | ret->total_nr_elements = total; | 99 | ret->total_nr_elements = total; |
| 116 | if (elements_fit_in_base(ret) && !(flags & __GFP_ZERO)) | 100 | if (elements_fit_in_base(ret) && !(flags & __GFP_ZERO)) |
| 117 | memset(ret->parts[0], FLEX_ARRAY_FREE, bytes_left_in_base()); | 101 | memset(ret->parts[0], FLEX_ARRAY_FREE, |
| 102 | FLEX_ARRAY_BASE_BYTES_LEFT); | ||
| 118 | return ret; | 103 | return ret; |
| 119 | } | 104 | } |
| 120 | 105 | ||
| 121 | static int fa_element_to_part_nr(struct flex_array *fa, | 106 | static int fa_element_to_part_nr(struct flex_array *fa, |
| 122 | unsigned int element_nr) | 107 | unsigned int element_nr) |
| 123 | { | 108 | { |
| 124 | return element_nr / __elements_per_part(fa->element_size); | 109 | return element_nr / FLEX_ARRAY_ELEMENTS_PER_PART(fa->element_size); |
| 125 | } | 110 | } |
| 126 | 111 | ||
| 127 | /** | 112 | /** |
| @@ -133,11 +118,10 @@ static int fa_element_to_part_nr(struct flex_array *fa, | |||
| 133 | void flex_array_free_parts(struct flex_array *fa) | 118 | void flex_array_free_parts(struct flex_array *fa) |
| 134 | { | 119 | { |
| 135 | int part_nr; | 120 | int part_nr; |
| 136 | int max_part = nr_base_part_ptrs(); | ||
| 137 | 121 | ||
| 138 | if (elements_fit_in_base(fa)) | 122 | if (elements_fit_in_base(fa)) |
| 139 | return; | 123 | return; |
| 140 | for (part_nr = 0; part_nr < max_part; part_nr++) | 124 | for (part_nr = 0; part_nr < FLEX_ARRAY_NR_BASE_PTRS; part_nr++) |
| 141 | kfree(fa->parts[part_nr]); | 125 | kfree(fa->parts[part_nr]); |
| 142 | } | 126 | } |
| 143 | 127 | ||
| @@ -152,7 +136,8 @@ static unsigned int index_inside_part(struct flex_array *fa, | |||
| 152 | { | 136 | { |
| 153 | unsigned int part_offset; | 137 | unsigned int part_offset; |
| 154 | 138 | ||
| 155 | part_offset = element_nr % __elements_per_part(fa->element_size); | 139 | part_offset = element_nr % |
| 140 | FLEX_ARRAY_ELEMENTS_PER_PART(fa->element_size); | ||
| 156 | return part_offset * fa->element_size; | 141 | return part_offset * fa->element_size; |
| 157 | } | 142 | } |
| 158 | 143 | ||
| @@ -313,13 +298,12 @@ static int part_is_free(struct flex_array_part *part) | |||
| 313 | int flex_array_shrink(struct flex_array *fa) | 298 | int flex_array_shrink(struct flex_array *fa) |
| 314 | { | 299 | { |
| 315 | struct flex_array_part *part; | 300 | struct flex_array_part *part; |
| 316 | int max_part = nr_base_part_ptrs(); | ||
| 317 | int part_nr; | 301 | int part_nr; |
| 318 | int ret = 0; | 302 | int ret = 0; |
| 319 | 303 | ||
| 320 | if (elements_fit_in_base(fa)) | 304 | if (elements_fit_in_base(fa)) |
| 321 | return ret; | 305 | return ret; |
| 322 | for (part_nr = 0; part_nr < max_part; part_nr++) { | 306 | for (part_nr = 0; part_nr < FLEX_ARRAY_NR_BASE_PTRS; part_nr++) { |
| 323 | part = fa->parts[part_nr]; | 307 | part = fa->parts[part_nr]; |
| 324 | if (!part) | 308 | if (!part) |
| 325 | continue; | 309 | continue; |
