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 | |
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>
-rw-r--r-- | include/linux/flex_array.h | 30 | ||||
-rw-r--r-- | lib/flex_array.c | 36 |
2 files changed, 36 insertions, 30 deletions
diff --git a/include/linux/flex_array.h b/include/linux/flex_array.h index f12401e485fe..1d747f72298b 100644 --- a/include/linux/flex_array.h +++ b/include/linux/flex_array.h | |||
@@ -31,10 +31,32 @@ struct flex_array { | |||
31 | }; | 31 | }; |
32 | }; | 32 | }; |
33 | 33 | ||
34 | #define FLEX_ARRAY_INIT(size, total) { { {\ | 34 | /* Number of bytes left in base struct flex_array, excluding metadata */ |
35 | .element_size = (size), \ | 35 | #define FLEX_ARRAY_BASE_BYTES_LEFT \ |
36 | .total_nr_elements = (total), \ | 36 | (FLEX_ARRAY_BASE_SIZE - offsetof(struct flex_array, parts)) |
37 | } } } | 37 | |
38 | /* Number of pointers in base to struct flex_array_part pages */ | ||
39 | #define FLEX_ARRAY_NR_BASE_PTRS \ | ||
40 | (FLEX_ARRAY_BASE_BYTES_LEFT / sizeof(struct flex_array_part *)) | ||
41 | |||
42 | /* Number of elements of size that fit in struct flex_array_part */ | ||
43 | #define FLEX_ARRAY_ELEMENTS_PER_PART(size) \ | ||
44 | (FLEX_ARRAY_PART_SIZE / size) | ||
45 | |||
46 | /* | ||
47 | * Defines a statically allocated flex array and ensures its parameters are | ||
48 | * valid. | ||
49 | */ | ||
50 | #define DEFINE_FLEX_ARRAY(__arrayname, __element_size, __total) \ | ||
51 | struct flex_array __arrayname = { { { \ | ||
52 | .element_size = (__element_size), \ | ||
53 | .total_nr_elements = (__total), \ | ||
54 | } } }; \ | ||
55 | static inline void __arrayname##_invalid_parameter(void) \ | ||
56 | { \ | ||
57 | BUILD_BUG_ON((__total) > FLEX_ARRAY_NR_BASE_PTRS * \ | ||
58 | FLEX_ARRAY_ELEMENTS_PER_PART(__element_size)); \ | ||
59 | } | ||
38 | 60 | ||
39 | struct flex_array *flex_array_alloc(int element_size, unsigned int total, | 61 | struct flex_array *flex_array_alloc(int element_size, unsigned int total, |
40 | gfp_t flags); | 62 | gfp_t flags); |
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; |