<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;">
From: Dave Hansen &lt;haveblue@us.ibm.com&gt;
This patch adds a new type of addressing: logical pfns.  These are necessary
so that a very sparse physical layout can be accounted for in the page
allocator's structures.

This patch allows arbitrary mapping between logical and physical pfn's, which
should allow a sparse free_areas bitmap to be consolidated.  The only lpfn
that is actually stored should be zone-&gt;zone_start_pfn, so any references
to it need to be translated to regular pfns, but no others.

Consider a memory layout that looks like the following, with 6 sections of
active memory.

/-----------------------\
| A | B | C | D | E | F |
\-----------------------/

Now, sections B through E are removed, leaving the free_areas bitmap looking
like this, with 2/3 of its sections being unused:

/-----------------------\
| A |   |   |   |   | F |
\-----------------------/

Using the logical pfn scheme, the pfns may be remapped so that A and F are now
logically adjacent:

/-----------------------\
| A | F |   |   |   |   |
\-----------------------/

... and the structure can now be resized to only use as much space as
it needs:

/-------\
| A | F |
\-------/

Signed-off-by: Dave Hansen &lt;haveblue@us.ibm.com&gt;


---

 memhotplug-dave/include/linux/nonlinear.h |   15 +++++++++++++
 memhotplug-dave/mm/nonlinear.c            |   33 +++++++++++++++++++++++++++++-
 memhotplug-dave/mm/page_alloc.c           |   14 ++++++------
 3 files changed, 54 insertions(+), 8 deletions(-)

diff -puN arch/i386/mm/discontig.c~C1-nonlinear-lpfn arch/i386/mm/discontig.c
diff -puN include/linux/nonlinear.h~C1-nonlinear-lpfn include/linux/nonlinear.h
--- memhotplug/include/linux/nonlinear.h~C1-nonlinear-lpfn	2004-08-13 12:38:29.000000000 -0700
+++ memhotplug-dave/include/linux/nonlinear.h	2004-08-13 12:38:29.000000000 -0700
@@ -18,6 +18,9 @@ static inline void setup_memsections(voi
 static inline void alloc_memsections(unsigned long start_pfn, unsigned long start_phys_pfn, unsigned long size) {}
 static inline void alloc_memmap(struct page *page, unsigned long start_pfn, unsigned long size) {}
 
+#define lpfn_to_page(pfn)	pfn_to_page(pfn)
+#define page_to_lpfn(page)	page_to_pfn(page)
+
 #else
 #include &lt;asm/nonlinear.h&gt;
 
@@ -99,6 +102,7 @@ __va(unsigned long addr)
 }
 
 extern struct page *pfn_to_page(unsigned long pfn);
+extern struct page *lpfn_to_page(unsigned long lpfn);
 unsigned long page_to_pfn(struct page *page);
 
 static inline int
@@ -110,13 +114,24 @@ pfn_valid(unsigned long pfn)
 		return 1;
 }
 
+static inline int
+lpfn_valid(unsigned long lpfn)
+{
+	if (mem_section[pfn_to_section(lpfn)].phys_section == INVALID_SECTION)
+		return 0;
+	else
+		return 1;
+}
+
 extern void setup_memsections(void);
 extern void alloc_memsections(unsigned long start_pfn, unsigned long start_phys_pfn, unsigned long size);
 extern void alloc_memmap(struct page *page, unsigned long start_pfn, unsigned long size);
 extern void memmap_init(unsigned long size, int nid, unsigned long zone, unsigned long start_pfn);
 
 extern struct page *pfn_to_page(unsigned long pfn);
+extern struct page *lpfn_to_page(unsigned long pfn);
 extern unsigned long page_to_pfn(struct page *page);
+extern unsigned long page_to_lpfn(struct page *page);
 
 #endif /* CONFIG_NONLINEAR */
 #endif /* __LINUX_NONLINEAR_H_ */
diff -puN kernel/power/swsusp.c~C1-nonlinear-lpfn kernel/power/swsusp.c
diff -puN mm/nonlinear.c~C1-nonlinear-lpfn mm/nonlinear.c
--- memhotplug/mm/nonlinear.c~C1-nonlinear-lpfn	2004-08-13 12:38:29.000000000 -0700
+++ memhotplug-dave/mm/nonlinear.c	2004-08-13 12:38:29.000000000 -0700
@@ -118,12 +118,43 @@ memmap_init(unsigned long num_pages, int
 struct page *
 pfn_to_page(unsigned long pfn)
 {
-	return &amp;mem_section[phys_section[pfn_to_section(pfn)]].mem_map[section_offset_pfn(pfn)];
+	struct page *page = &amp;mem_section[phys_section[pfn_to_section(pfn)]].mem_map[section_offset_pfn(pfn)];
+	if (!page) {
+		printk("%s()\n", __func__);
+		printk("pfn_to_section(%ld): %d\n", pfn, pfn_to_section(pfn));
+		printk("phys_section[%d]: %d\n", pfn_to_section(pfn),
+				phys_section[pfn_to_section(pfn)]);
+		BUG();
+	}
+	return page;
+}
+
+struct page *
+lpfn_to_page(unsigned long lpfn)
+{
+	struct page *page = &amp;mem_section[pfn_to_section(lpfn)].mem_map[section_offset_pfn(lpfn)];
+	if (!page) {
+		printk("%s()\n", __func__);
+		printk("pfn_to_section(%ld): %d\n", lpfn, pfn_to_section(lpfn));
+		printk("phys_section[%d]: %d\n", pfn_to_section(lpfn),
+				phys_section[pfn_to_section(lpfn)]);
+		BUG();
+	}
+	return page;
+}
+
+unsigned long
+page_to_lpfn(struct page *page)
+{
+	BUG_ON(mem_section[page-&gt;section].phys_section == INVALID_SECTION);
+	return section_to_pfn(page-&gt;section) +
+		(page - mem_section[page-&gt;section].mem_map);
 }
 
 unsigned long
 page_to_pfn(struct page *page)
 {
+	BUG_ON(mem_section[page-&gt;section].phys_section == INVALID_SECTION);
 	return section_to_pfn(mem_section[page-&gt;section].phys_section) +
 		(page - mem_section[page-&gt;section].mem_map);
 }
diff -puN mm/page_alloc.c~C1-nonlinear-lpfn mm/page_alloc.c
--- memhotplug/mm/page_alloc.c~C1-nonlinear-lpfn	2004-08-13 12:38:29.000000000 -0700
+++ memhotplug-dave/mm/page_alloc.c	2004-08-13 12:38:29.000000000 -0700
@@ -65,9 +65,9 @@ static unsigned long __initdata nr_all_p
  */
 static int bad_range(struct zone *zone, struct page *page)
 {
-	if (page_to_pfn(page) &gt;= zone-&gt;zone_start_pfn + zone-&gt;spanned_pages)
+	if (page_to_lpfn(page) &gt;= zone-&gt;zone_start_pfn + zone-&gt;spanned_pages)
 		return 1;
-	if (page_to_pfn(page) &lt; zone-&gt;zone_start_pfn)
+	if (page_to_lpfn(page) &lt; zone-&gt;zone_start_pfn)
 		return 1;
 	if (zone != page_zone(page))
 		return 1;
@@ -186,7 +186,7 @@ static inline void __free_pages_bulk (st
 	if (order)
 		destroy_compound_page(page, order);
 	mask = (~0UL) &lt;&lt; order;
-	page_idx = page_to_pfn(page) - base;
+	page_idx = page_to_lpfn(page) - base;
 	if (page_idx &amp; ~mask)
 		BUG();
 	index = page_idx &gt;&gt; (1 + order);
@@ -203,8 +203,8 @@ static inline void __free_pages_bulk (st
 			break;
 
 		/* Move the buddy up one level. */
-		buddy1 = pfn_to_page(base + (page_idx ^ (1 &lt;&lt; order)));
-		buddy2 = pfn_to_page(base + page_idx);
+		buddy1 = lpfn_to_page(base + (page_idx ^ (1 &lt;&lt; order)));
+		buddy2 = lpfn_to_page(base + page_idx);
 		BUG_ON(bad_range(zone, buddy1));
 		BUG_ON(bad_range(zone, buddy2));
 		list_del(&amp;buddy1-&gt;lru);
@@ -214,7 +214,7 @@ static inline void __free_pages_bulk (st
 		index &gt;&gt;= 1;
 		page_idx &amp;= mask;
 	}
-	list_add(&amp;(pfn_to_page(base + page_idx))-&gt;lru, &amp;area-&gt;free_list);
+	list_add(&amp;(lpfn_to_page(base + page_idx))-&gt;lru, &amp;area-&gt;free_list);
 }
 
 static inline void free_pages_check(const char *function, struct page *page)
@@ -379,7 +379,7 @@ static struct page *__rmqueue(struct zon
 
 		page = list_entry(area-&gt;free_list.next, struct page, lru);
 		list_del(&amp;page-&gt;lru);
-		index = page_to_pfn(page) - zone-&gt;zone_start_pfn;
+		index = page_to_lpfn(page) - zone-&gt;zone_start_pfn;
 		if (current_order != MAX_ORDER-1)
 			MARK_USED(index, current_order, area);
 		zone-&gt;free_pages -= 1UL &lt;&lt; order;

_
</pre></body></html>