diff options
Diffstat (limited to 'mm/memblock.c')
-rw-r--r-- | mm/memblock.c | 42 |
1 files changed, 27 insertions, 15 deletions
diff --git a/mm/memblock.c b/mm/memblock.c index a44eab3157f8..952123eba433 100644 --- a/mm/memblock.c +++ b/mm/memblock.c | |||
@@ -37,6 +37,8 @@ struct memblock memblock __initdata_memblock = { | |||
37 | 37 | ||
38 | int memblock_debug __initdata_memblock; | 38 | int memblock_debug __initdata_memblock; |
39 | static int memblock_can_resize __initdata_memblock; | 39 | static int memblock_can_resize __initdata_memblock; |
40 | static int memblock_memory_in_slab __initdata_memblock = 0; | ||
41 | static int memblock_reserved_in_slab __initdata_memblock = 0; | ||
40 | 42 | ||
41 | /* inline so we don't get a warning when pr_debug is compiled out */ | 43 | /* inline so we don't get a warning when pr_debug is compiled out */ |
42 | static inline const char *memblock_type_name(struct memblock_type *type) | 44 | static inline const char *memblock_type_name(struct memblock_type *type) |
@@ -187,6 +189,7 @@ static int __init_memblock memblock_double_array(struct memblock_type *type) | |||
187 | struct memblock_region *new_array, *old_array; | 189 | struct memblock_region *new_array, *old_array; |
188 | phys_addr_t old_size, new_size, addr; | 190 | phys_addr_t old_size, new_size, addr; |
189 | int use_slab = slab_is_available(); | 191 | int use_slab = slab_is_available(); |
192 | int *in_slab; | ||
190 | 193 | ||
191 | /* We don't allow resizing until we know about the reserved regions | 194 | /* We don't allow resizing until we know about the reserved regions |
192 | * of memory that aren't suitable for allocation | 195 | * of memory that aren't suitable for allocation |
@@ -198,6 +201,12 @@ static int __init_memblock memblock_double_array(struct memblock_type *type) | |||
198 | old_size = type->max * sizeof(struct memblock_region); | 201 | old_size = type->max * sizeof(struct memblock_region); |
199 | new_size = old_size << 1; | 202 | new_size = old_size << 1; |
200 | 203 | ||
204 | /* Retrieve the slab flag */ | ||
205 | if (type == &memblock.memory) | ||
206 | in_slab = &memblock_memory_in_slab; | ||
207 | else | ||
208 | in_slab = &memblock_reserved_in_slab; | ||
209 | |||
201 | /* Try to find some space for it. | 210 | /* Try to find some space for it. |
202 | * | 211 | * |
203 | * WARNING: We assume that either slab_is_available() and we use it or | 212 | * WARNING: We assume that either slab_is_available() and we use it or |
@@ -212,14 +221,15 @@ static int __init_memblock memblock_double_array(struct memblock_type *type) | |||
212 | if (use_slab) { | 221 | if (use_slab) { |
213 | new_array = kmalloc(new_size, GFP_KERNEL); | 222 | new_array = kmalloc(new_size, GFP_KERNEL); |
214 | addr = new_array ? __pa(new_array) : 0; | 223 | addr = new_array ? __pa(new_array) : 0; |
215 | } else | 224 | } else { |
216 | addr = memblock_find_in_range(0, MEMBLOCK_ALLOC_ACCESSIBLE, new_size, sizeof(phys_addr_t)); | 225 | addr = memblock_find_in_range(0, MEMBLOCK_ALLOC_ACCESSIBLE, new_size, sizeof(phys_addr_t)); |
226 | new_array = addr ? __va(addr) : 0; | ||
227 | } | ||
217 | if (!addr) { | 228 | if (!addr) { |
218 | pr_err("memblock: Failed to double %s array from %ld to %ld entries !\n", | 229 | pr_err("memblock: Failed to double %s array from %ld to %ld entries !\n", |
219 | memblock_type_name(type), type->max, type->max * 2); | 230 | memblock_type_name(type), type->max, type->max * 2); |
220 | return -1; | 231 | return -1; |
221 | } | 232 | } |
222 | new_array = __va(addr); | ||
223 | 233 | ||
224 | memblock_dbg("memblock: %s array is doubled to %ld at [%#010llx-%#010llx]", | 234 | memblock_dbg("memblock: %s array is doubled to %ld at [%#010llx-%#010llx]", |
225 | memblock_type_name(type), type->max * 2, (u64)addr, (u64)addr + new_size - 1); | 235 | memblock_type_name(type), type->max * 2, (u64)addr, (u64)addr + new_size - 1); |
@@ -234,22 +244,24 @@ static int __init_memblock memblock_double_array(struct memblock_type *type) | |||
234 | type->regions = new_array; | 244 | type->regions = new_array; |
235 | type->max <<= 1; | 245 | type->max <<= 1; |
236 | 246 | ||
237 | /* If we use SLAB that's it, we are done */ | 247 | /* Free old array. We needn't free it if the array is the |
238 | if (use_slab) | 248 | * static one |
239 | return 0; | ||
240 | |||
241 | /* Add the new reserved region now. Should not fail ! */ | ||
242 | BUG_ON(memblock_reserve(addr, new_size)); | ||
243 | |||
244 | /* If the array wasn't our static init one, then free it. We only do | ||
245 | * that before SLAB is available as later on, we don't know whether | ||
246 | * to use kfree or free_bootmem_pages(). Shouldn't be a big deal | ||
247 | * anyways | ||
248 | */ | 249 | */ |
249 | if (old_array != memblock_memory_init_regions && | 250 | if (*in_slab) |
250 | old_array != memblock_reserved_init_regions) | 251 | kfree(old_array); |
252 | else if (old_array != memblock_memory_init_regions && | ||
253 | old_array != memblock_reserved_init_regions) | ||
251 | memblock_free(__pa(old_array), old_size); | 254 | memblock_free(__pa(old_array), old_size); |
252 | 255 | ||
256 | /* Reserve the new array if that comes from the memblock. | ||
257 | * Otherwise, we needn't do it | ||
258 | */ | ||
259 | if (!use_slab) | ||
260 | BUG_ON(memblock_reserve(addr, new_size)); | ||
261 | |||
262 | /* Update slab flag */ | ||
263 | *in_slab = use_slab; | ||
264 | |||
253 | return 0; | 265 | return 0; |
254 | } | 266 | } |
255 | 267 | ||