[RFC PATCH] ARM: Consider memblocks in mem_init and show_mem.

Steve Capper steve.capper at arm.com
Wed Dec 12 12:40:00 EST 2012


This is based on Michael Spang's patch [1]; and is my attempt at
applying the feedback from Russell [2].

With discontiguous memory (a requirement for running NUMA on some
systems), membanks may not necessarily be representable as
contiguous blocks of struct page *s. This patch updates the page
scanning code in mem_init and show_mem to consider pages in the
intersection of membanks and memblocks instead.

We can't consider memblocks solely as under sparse memory
configurations, contiguous physical membanks won't necessarily have
a contiguous memory map (but may be merged into the same memblock).

Only memory blocks in the "memory" region were considered as the
"reserved" region was found to always overlap "memory"; all the
memory banks are added with memblock_add (which adds to "memory")
and no instances were found where memory was added to "reserved"
then removed from "memory".

In mem_init we are running on one CPU, and I can't see the
memblocks changing whilst being enumerated.

In show_mem, we can be running on multiple CPUs; whilst the
memblock manipulation functions are annotated as __init, this
doesn't stop memblocks being manipulated during bootup. I can't
see any place where memblocks are removed or merged other than
driver initialisation (memblock_steal) or boot memory
initialisation.

One consequence of using memblocks in show_mem, is that we are
unable to define ARCH_DISCARD_MEMBLOCK.

Any feedback would be welcome.

Thanks,
-- 
Steve

[1] http://lists.infradead.org/pipermail/linux-arm-kernel/2012-October/127104.html
[2] http://lists.infradead.org/pipermail/linux-arm-kernel/2012-November/135455.html

Signed-off-by: Steve Capper <steve.capper at arm.com>
---
 arch/arm/mm/init.c |  119 ++++++++++++++++++++++++++++++++++------------------
 1 file changed, 79 insertions(+), 40 deletions(-)

diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c
index ad722f1..abe4eae 100644
--- a/arch/arm/mm/init.c
+++ b/arch/arm/mm/init.c
@@ -94,36 +94,56 @@ void show_mem(unsigned int filter)
 {
 	int free = 0, total = 0, reserved = 0;
 	int shared = 0, cached = 0, slab = 0, i;
-	struct meminfo * mi = &meminfo;
+	struct meminfo *mi = &meminfo;
+	struct memblock_region *reg;
 
 	printk("Mem-info:\n");
 	show_free_areas(filter);
 
 	for_each_bank (i, mi) {
 		struct membank *bank = &mi->bank[i];
-		unsigned int pfn1, pfn2;
-		struct page *page, *end;
-
-		pfn1 = bank_pfn_start(bank);
-		pfn2 = bank_pfn_end(bank);
-
-		page = pfn_to_page(pfn1);
-		end  = pfn_to_page(pfn2 - 1) + 1;
-
-		do {
-			total++;
-			if (PageReserved(page))
-				reserved++;
-			else if (PageSwapCache(page))
-				cached++;
-			else if (PageSlab(page))
-				slab++;
-			else if (!page_count(page))
-				free++;
-			else
-				shared += page_count(page) - 1;
-			page++;
-		} while (page < end);
+		unsigned int sbank, ebank;
+
+		sbank = bank_pfn_start(bank);
+		ebank = bank_pfn_end(bank);
+
+		/* consider every memory block that intersects our memory bank */
+		for_each_memblock(memory, reg) {
+			struct page *page, *end;
+			unsigned int pfn1, pfn2;
+			unsigned int sblock = memblock_region_memory_base_pfn(reg);
+			unsigned int eblock = memblock_region_memory_end_pfn(reg);
+
+			/* we're beyond the membank */
+			if (sblock >= ebank)
+				break;
+
+			/* we're not yet at the membank */
+			if (eblock <= sbank)
+				continue;
+
+			/* take the intersection between bank and block */
+			pfn1 = max(sblock, sbank);
+			pfn2 = min(eblock, ebank);
+
+			page = pfn_to_page(pfn1);
+			end = pfn_to_page(pfn2 - 1) + 1;
+
+			do {
+				total++;
+				if (PageReserved(page))
+					reserved++;
+				else if (PageSwapCache(page))
+					cached++;
+				else if (PageSlab(page))
+					slab++;
+				else if (!page_count(page))
+					free++;
+				else
+					shared += page_count(page) - 1;
+				page++;
+			} while (page < end);
+		}
 	}
 
 	printk("%d pages of RAM\n", total);
@@ -619,22 +639,41 @@ void __init mem_init(void)
 
 	for_each_bank(i, &meminfo) {
 		struct membank *bank = &meminfo.bank[i];
-		unsigned int pfn1, pfn2;
-		struct page *page, *end;
-
-		pfn1 = bank_pfn_start(bank);
-		pfn2 = bank_pfn_end(bank);
-
-		page = pfn_to_page(pfn1);
-		end  = pfn_to_page(pfn2 - 1) + 1;
-
-		do {
-			if (PageReserved(page))
-				reserved_pages++;
-			else if (!page_count(page))
-				free_pages++;
-			page++;
-		} while (page < end);
+		unsigned int sbank, ebank;
+
+		sbank = bank_pfn_start(bank);
+		ebank = bank_pfn_end(bank);
+
+		/* consider every memory block that intersects our memory bank */
+		for_each_memblock(memory, reg) {
+			struct page *page, *end;
+			unsigned int pfn1, pfn2;
+			unsigned int sblock = memblock_region_memory_base_pfn(reg);
+			unsigned int eblock = memblock_region_memory_end_pfn(reg);
+
+			/* we're beyond the membank */
+			if (sblock >= ebank)
+				break;
+
+			/* we're not yet at the membank */
+			if (eblock <= sbank)
+				continue;
+
+			/* take the intersection between bank and block */
+			pfn1 = max(sblock, sbank);
+			pfn2 = min(eblock, ebank);
+
+			page = pfn_to_page(pfn1);
+			end = pfn_to_page(pfn2 - 1) + 1;
+
+			do {
+				if (PageReserved(page))
+					reserved_pages++;
+				else if (!page_count(page))
+					free_pages++;
+				page++;
+			} while (page < end);
+		}
 	}
 
 	/*
-- 
1.7.9.5





More information about the linux-arm-kernel mailing list