mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Akira Takeuchi <takeuchi.akr@jp.panasonic.com>
To: Russell King <linux@arm.linux.org.uk>
Cc: linux-kernel@vger.kernel.org
Subject: [PATCH 2/2] linux: ARM: memmap: Revise freeing unused memmap entries for SPARSEMEM
Date: Thu, 29 Mar 2012 19:02:52 +0900	[thread overview]
Message-ID: <20120329190252.3895.38390934@jp.panasonic.com> (raw)
In-Reply-To: <20120329190113.3891.38390934@jp.panasonic.com>

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@jp.panasonic.com>
Signed-off-by: Kiyoshi Owada <owada.kiyoshi@jp.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



  reply	other threads:[~2012-03-29 10:02 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-03-29 10:01 [PATCH 1/2] linux: sparsemem: Initialize all memmap entries within sections Akira Takeuchi
2012-03-29 10:02 ` Akira Takeuchi [this message]
2012-03-29 12:13   ` [PATCH 2/2] linux: ARM: memmap: Revise freeing unused memmap entries for SPARSEMEM Russell King - ARM Linux
2012-03-30  1:27     ` Akira Takeuchi

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20120329190252.3895.38390934@jp.panasonic.com \
    --to=takeuchi.akr@jp.panasonic.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux@arm.linux.org.uk \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®