aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWill Deacon <will.deacon@arm.com>2011-04-28 13:44:31 -0400
committerRussell King <rmk+kernel@arm.linux.org.uk>2011-05-12 05:52:00 -0400
commit9af386c8dc5a9dce56f36b484647ad6401758c85 (patch)
treeb884faac285aeb76c07f73e118ef29ce94cd7156
parent362607df9faa01fea6ae437b1a50645f33f393c0 (diff)
ARM: 6890/1: memmap: only free allocated memmap entries when using SPARSEMEM
The SPARSEMEM code allocates memmap entries only for sections which are present (i.e. those which contain some valid memory). The membank checks in free_unused_memmap do not take this into account and can incorrectly attempt to free memory which is not allocated, resulting in a BUG() in the bootmem code. However, if memory is configured as follows: |<----section---->|<----hole---->|<----section---->| +--------+--------+--------------+--------+--------+ | bank 0 | unused | | bank 1 | unused | +--------+--------+--------------+--------+--------+ where a bank only occupies part of a section, the memmap allocated for the remainder of the section *can* be freed. This patch modifies the checks in free_unused_memmap so that only valid memmap entries are considered for removal. Acked-by: Catalin Marinas <catalin.marinas@arm.com> Signed-off-by: Will Deacon <will.deacon@arm.com> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
-rw-r--r--arch/arm/mm/init.c16
1 files changed, 15 insertions, 1 deletions
diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c
index e5f6fc42834..e591513bb53 100644
--- a/arch/arm/mm/init.c
+++ b/arch/arm/mm/init.c
@@ -392,7 +392,7 @@ free_memmap(unsigned long start_pfn, unsigned long end_pfn)
392 * Convert start_pfn/end_pfn to a struct page pointer. 392 * Convert start_pfn/end_pfn to a struct page pointer.
393 */ 393 */
394 start_pg = pfn_to_page(start_pfn - 1) + 1; 394 start_pg = pfn_to_page(start_pfn - 1) + 1;
395 end_pg = pfn_to_page(end_pfn); 395 end_pg = pfn_to_page(end_pfn - 1) + 1;
396 396
397 /* 397 /*
398 * Convert to physical addresses, and 398 * Convert to physical addresses, and
@@ -426,6 +426,14 @@ static void __init free_unused_memmap(struct meminfo *mi)
426 426
427 bank_start = bank_pfn_start(bank); 427 bank_start = bank_pfn_start(bank);
428 428
429#ifdef CONFIG_SPARSEMEM
430 /*
431 * Take care not to free memmap entries that don't exist
432 * due to SPARSEMEM sections which aren't present.
433 */
434 bank_start = min(bank_start,
435 ALIGN(prev_bank_end, PAGES_PER_SECTION));
436#endif
429 /* 437 /*
430 * If we had a previous bank, and there is a space 438 * If we had a previous bank, and there is a space
431 * between the current bank and the previous, free it. 439 * between the current bank and the previous, free it.
@@ -440,6 +448,12 @@ static void __init free_unused_memmap(struct meminfo *mi)
440 */ 448 */
441 prev_bank_end = ALIGN(bank_pfn_end(bank), MAX_ORDER_NR_PAGES); 449 prev_bank_end = ALIGN(bank_pfn_end(bank), MAX_ORDER_NR_PAGES);
442 } 450 }
451
452#ifdef CONFIG_SPARSEMEM
453 if (!IS_ALIGNED(prev_bank_end, PAGES_PER_SECTION))
454 free_memmap(prev_bank_end,
455 ALIGN(prev_bank_end, PAGES_PER_SECTION));
456#endif
443} 457}
444 458
445static void __init free_highpages(void) 459static void __init free_highpages(void)