aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Rientjes <rientjes@google.com>2009-09-21 20:04:33 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2009-09-22 10:17:47 -0400
commit45b588d6e5cc172704bac0c998ce54873b149b22 (patch)
tree57a9d3478af60fcf6932c1f61b083b9203ef1ee8
parent4af5a2f770cc8575840ccb1514ec76ecb592985c (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.h30
-rw-r--r--lib/flex_array.c36
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
39struct flex_array *flex_array_alloc(int element_size, unsigned int total, 61struct 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
31static inline int __elements_per_part(int element_size)
32{
33 return FLEX_ARRAY_PART_SIZE / element_size;
34}
35
36static 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
43static 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)
54static inline int elements_fit_in_base(struct flex_array *fa) 37static 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
121static int fa_element_to_part_nr(struct flex_array *fa, 106static 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,
133void flex_array_free_parts(struct flex_array *fa) 118void 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)
313int flex_array_shrink(struct flex_array *fa) 298int 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;