
This patch moves active pages that are under capture from the zone->active_list
to the zone->inactive_list and then prevents any pages that are under capture
from being put back on the active_list.  It also initiates swapping of pages
when there are pages marked for removal and in use.

In limited testing this patch is almost always able to swap all pages in the
remove area in highmem on a 2G i386 machine.

Signed-off by: Bradley Christiansen <bradc1@us.ibm.com>

Index: linux-2.6.10-rc2-mm4-mhp3-reorder/mm/page_alloc.c
===================================================================

---

 memhotplug-dave/mm/page_alloc.c |   20 ++++++++++++++++++++
 memhotplug-dave/mm/swap.c       |    3 ++-
 memhotplug-dave/mm/vmscan.c     |   13 ++++++++-----
 3 files changed, 30 insertions(+), 6 deletions(-)

diff -puN mm/page_alloc.c~K2-swap_changes_mem_remove mm/page_alloc.c
--- memhotplug/mm/page_alloc.c~K2-swap_changes_mem_remove	2005-01-04 13:49:50.000000000 -0800
+++ memhotplug-dave/mm/page_alloc.c	2005-01-04 13:49:50.000000000 -0800
@@ -18,6 +18,7 @@
 #include <linux/stddef.h>
 #include <linux/mm.h>
 #include <linux/swap.h>
+#include <linux/mm_inline.h>
 #include <linux/interrupt.h>
 #include <linux/pagemap.h>
 #include <linux/bootmem.h>
@@ -683,6 +684,24 @@ rmb_and_drain_cpu_pages(void * __unused)
 	drain_local_pages();
 }
 
+/*
+ * This function forces pages that are under capture off the zone->active_list
+ * and onto the zone->inactive_list
+ */
+static inline void force_captured_to_inactive_list(struct page *base)
+{
+	struct zone *zone = page_zone(base);
+	struct list_head *p, *n;
+
+	list_for_each_safe(p, n, &zone->active_list) {
+		struct page *page = list_entry(p, struct page, lru);
+		if (page_under_capture(page)) {
+			ClearPageActive(page);
+			del_page_from_active_list(zone, page);
+			add_page_to_inactive_list(zone, page);
+		}
+	}
+}
 
 /*
  * Flags a given order of pages to be removed from memory, then removes any
@@ -719,6 +738,7 @@ int capture_page_range(unsigned long sta
 
 	page = pfn_to_page(start_pfn);
 	remove_page_freearea(page, order);
+	force_captured_to_inactive_list(page);
 	nr_pages = 1<<order;
 	/*
 	 * storing the last result (fp) keeps up from having
diff -puN mm/swap.c~K2-swap_changes_mem_remove mm/swap.c
--- memhotplug/mm/swap.c~K2-swap_changes_mem_remove	2005-01-04 13:49:50.000000000 -0800
+++ memhotplug-dave/mm/swap.c	2005-01-04 13:49:50.000000000 -0800
@@ -122,7 +122,8 @@ void fastcall activate_page(struct page 
  */
 void fastcall mark_page_accessed(struct page *page)
 {
-	if (!PageActive(page) && PageReferenced(page) && PageLRU(page)) {
+	if (!PageActive(page) && PageReferenced(page) && PageLRU(page) &&
+			!page_under_capture(page)) {
 		activate_page(page);
 		ClearPageReferenced(page);
 	} else if (!PageReferenced(page)) {
diff -puN mm/vmscan.c~K2-swap_changes_mem_remove mm/vmscan.c
--- memhotplug/mm/vmscan.c~K2-swap_changes_mem_remove	2005-01-04 13:49:50.000000000 -0800
+++ memhotplug-dave/mm/vmscan.c	2005-01-04 13:49:50.000000000 -0800
@@ -380,7 +380,7 @@ int shrink_list(struct list_head *page_l
 		}
 
 		if (PageDirty(page)) {
-			if (referenced)
+			if (referenced && !page_under_capture(page))
 				goto keep_locked;
 			if (!may_enter_fs)
 				goto keep_locked;
@@ -475,14 +475,17 @@ int shrink_list(struct list_head *page_l
 
 free_it:
 		unlock_page(page);
-		reclaimed++;
+		if (!page_under_capture(page))
+			reclaimed++;
 		if (!pagevec_add(&freed_pvec, page))
 			__pagevec_release_nonlru(&freed_pvec);
 		continue;
 
 activate_locked:
-		SetPageActive(page);
-		pgactivate++;
+		if (!page_under_capture(page)) {
+			SetPageActive(page);
+			pgactivate++;
+		}
 keep_locked:
 		unlock_page(page);
 keep:
@@ -1164,7 +1167,7 @@ void wakeup_kswapd(struct zone *zone, in
 	wake_up_interruptible(&zone->zone_pgdat->kswapd_wait);
 }
 
-#ifdef CONFIG_PM
+#if defined(CONFIG_PM) || defined(CONFIG_MEMORY_HOTPLUG)
 /*
  * Try to free `nr_pages' of memory, system-wide.  Returns the number of freed
  * pages.
_
