lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<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

Powered by Openwall GNU/*/Linux Powered by OpenVZ