[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20120329190252.3895.38390934@jp.panasonic.com>
Date: Thu, 29 Mar 2012 19:02:52 +0900
From: Akira Takeuchi <takeuchi.akr@...panasonic.com>
To: Russell King <linux@....linux.org.uk>
Cc: linux-kernel@...r.kernel.org
Subject: [PATCH 2/2] linux: ARM: memmap: Revise freeing unused memmap entries for SPARSEMEM
The SPARSEMEM code allocates memmap entries for each present section.
Though free_unused_memmap() try to free unused memmap entries,
there remains some unused memmap entries which can be freed potentially,
since free_unused_memmap() does not take it into account that
there might exist unused memory regions on the top of each section.
Let's consider the following memory configuration:
|<------section0------->|<---------hole-------->|<------section1------>|
+---+-----+---+-----+---+-----------------------+---+--------------+---+
| |bank0| |bank1| | | | bank2 | |
+---+-----+---+-----+---+-----------------------+---+--------------+---+
|<->| |<->| |<->| |<->| |<->|
F0 F1 F2 F3 F4
F0-F4 is the unused memory regions and their corresponding memmap entries
can be freed. However, free_unused_memmap() only frees the entries for
F1/F2/F4, and does not free the entries for F0/F3.
This patch revises free_unused_memmap() so that all unused memmap entries
are freed. I divide free_unused_memmap() into FLATMEM version and
SPARSEMEM version, and introduce a for loop by section for SPARSEMEM version.
Also, this patch fixes "start_pg = pfn_to_page(start_pfn - 1) + 1" line
in free_memmap(). This line was changed by the past commit
"3257f43d9296ed7adcc84e48f6ddf5313cf29266".
But this change should be reverted now, because I think it was a workaround
for the present free_unused_memmap() code.
Let's consider again the memory configuration above. Without reverted the line,
pfn_to_page() returns a wrong value when freeing F0/F3.
Signed-off-by: Akira Takeuchi <takeuchi.akr@...panasonic.com>
Signed-off-by: Kiyoshi Owada <owada.kiyoshi@...panasonic.com>
---
arch/arm/mm/init.c | 81 +++++++++++++++++++++++++++++++++++++++++----------
1 files changed, 65 insertions(+), 16 deletions(-)
diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c
index 245a55a..634486b 100644
--- a/arch/arm/mm/init.c
+++ b/arch/arm/mm/init.c
@@ -444,10 +444,15 @@ free_memmap(unsigned long start_pfn, unsigned long end_pfn)
struct page *start_pg, *end_pg;
unsigned long pg, pgend;
+ printk(KERN_INFO
+ "Freeing memmap entries: %4ld KB (PFN 0x%05lx-0x%05lx)\n",
+ ((end_pfn - start_pfn) * sizeof(struct page) / 1024),
+ start_pfn, end_pfn);
+
/*
* 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);
end_pg = pfn_to_page(end_pfn - 1) + 1;
/*
@@ -468,6 +473,63 @@ free_memmap(unsigned long start_pfn, unsigned long end_pfn)
/*
* The mem_map array can get very big. Free the unused area of the memory map.
*/
+#ifdef CONFIG_SPARSEMEM
+static void __init free_unused_memmap(struct meminfo *mi)
+{
+ unsigned long pnum;
+
+ for (pnum = 0; pnum < NR_MEM_SECTIONS; pnum++) {
+ unsigned long sec_start = section_nr_to_pfn(pnum);
+ unsigned long sec_end = sec_start + (1UL << PFN_SECTION_SHIFT);
+ unsigned long free_start, free_end;
+ unsigned int i;
+
+ if (!valid_section_nr(pnum))
+ continue;
+
+ free_start = sec_start;
+
+ /*
+ * This relies on each bank being in address order.
+ * The banks are sorted previously in bootmem_init().
+ */
+ for_each_bank(i, mi) {
+ struct membank *bank = &mi->bank[i];
+ unsigned long bank_start = bank_pfn_start(bank);
+ unsigned long bank_end = bank_pfn_end(bank);
+
+ /*
+ * If this bank is out of range for this section,
+ * skip it.
+ */
+ if (sec_end <= bank_start || bank_end <= sec_start)
+ continue;
+
+ /*
+ * Align down here since the VM subsystem insists that
+ * the memmap entries are valid from the bank start
+ * aligned to MAX_ORDER_NR_PAGES.
+ */
+ free_end = round_down(bank_start, MAX_ORDER_NR_PAGES);
+
+ if (free_start < free_end)
+ free_memmap(free_start, free_end);
+
+ /*
+ * Align up here since the VM subsystem insists that
+ * the memmap entries are valid from the bank end
+ * aligned to MAX_ORDER_NR_PAGES.
+ */
+ free_start = ALIGN(bank_end, MAX_ORDER_NR_PAGES);
+ }
+
+ free_end = sec_end;
+
+ if (free_start < free_end)
+ free_memmap(free_start, free_end);
+ }
+}
+#else /* CONFIG_SPARSEMEM */
static void __init free_unused_memmap(struct meminfo *mi)
{
unsigned long bank_start, prev_bank_end = 0;
@@ -482,21 +544,13 @@ static void __init free_unused_memmap(struct meminfo *mi)
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));
-#else
/*
* Align down here since the VM subsystem insists that the
* memmap entries are valid from the bank start aligned to
* MAX_ORDER_NR_PAGES.
*/
bank_start = round_down(bank_start, MAX_ORDER_NR_PAGES);
-#endif
+
/*
* If we had a previous bank, and there is a space
* between the current bank and the previous, free it.
@@ -511,13 +565,8 @@ static void __init free_unused_memmap(struct meminfo *mi)
*/
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
}
+#endif /* CONFIG_SPARSEMEM */
static void __init free_highpages(void)
{
--
1.7.4.1
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
Powered by blists - more mailing lists