Commit 9af386c8 authored by Will Deacon's avatar Will Deacon Committed by Russell King

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: default avatarCatalin Marinas <catalin.marinas@arm.com>
Signed-off-by: default avatarWill Deacon <will.deacon@arm.com>
Signed-off-by: default avatarRussell King <rmk+kernel@arm.linux.org.uk>
parent 362607df
...@@ -392,7 +392,7 @@ free_memmap(unsigned long start_pfn, unsigned long end_pfn) ...@@ -392,7 +392,7 @@ free_memmap(unsigned long start_pfn, unsigned long end_pfn)
* Convert start_pfn/end_pfn to a struct page pointer. * Convert start_pfn/end_pfn to a struct page pointer.
*/ */
start_pg = pfn_to_page(start_pfn - 1) + 1; start_pg = pfn_to_page(start_pfn - 1) + 1;
end_pg = pfn_to_page(end_pfn); end_pg = pfn_to_page(end_pfn - 1) + 1;
/* /*
* Convert to physical addresses, and * Convert to physical addresses, and
...@@ -426,6 +426,14 @@ static void __init free_unused_memmap(struct meminfo *mi) ...@@ -426,6 +426,14 @@ static void __init free_unused_memmap(struct meminfo *mi)
bank_start = bank_pfn_start(bank); bank_start = bank_pfn_start(bank);
#ifdef CONFIG_SPARSEMEM
/*
* Take care not to free memmap entries that don't exist
* due to SPARSEMEM sections which aren't present.
*/
bank_start = min(bank_start,
ALIGN(prev_bank_end, PAGES_PER_SECTION));
#endif
/* /*
* If we had a previous bank, and there is a space * If we had a previous bank, and there is a space
* between the current bank and the previous, free it. * between the current bank and the previous, free it.
...@@ -440,6 +448,12 @@ static void __init free_unused_memmap(struct meminfo *mi) ...@@ -440,6 +448,12 @@ static void __init free_unused_memmap(struct meminfo *mi)
*/ */
prev_bank_end = ALIGN(bank_pfn_end(bank), MAX_ORDER_NR_PAGES); prev_bank_end = ALIGN(bank_pfn_end(bank), MAX_ORDER_NR_PAGES);
} }
#ifdef CONFIG_SPARSEMEM
if (!IS_ALIGNED(prev_bank_end, PAGES_PER_SECTION))
free_memmap(prev_bank_end,
ALIGN(prev_bank_end, PAGES_PER_SECTION));
#endif
} }
static void __init free_highpages(void) static void __init free_highpages(void)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment