
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>

---

Signed-off-by: Dave Hansen <haveblue@us.ibm.com>
---

 memhotplug1-dave/mm/page_alloc.c |   20 ++++++++++++++++++++
 memhotplug1-dave/mm/swap.c       |    3 ++-
 memhotplug1-dave/mm/vmscan.c     |   15 +++++++++------
 3 files changed, 31 insertions(+), 7 deletions(-)

diff -puN mm/page_alloc.c~K2-swap_changes_mem_remove mm/page_alloc.c
--- memhotplug1/mm/page_alloc.c~K2-swap_changes_mem_remove	2004-11-04 16:45:51.000000000 -0800
+++ memhotplug1-dave/mm/page_alloc.c	2004-11-04 16:45:51.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>
@@ -637,6 +638,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
@@ -673,6 +692,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
--- memhotplug1/mm/swap.c~K2-swap_changes_mem_remove	2004-11-04 16:45:51.000000000 -0800
+++ memhotplug1-dave/mm/swap.c	2004-11-04 16:45:51.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
--- memhotplug1/mm/vmscan.c~K2-swap_changes_mem_remove	2004-11-04 16:45:51.000000000 -0800
+++ memhotplug1-dave/mm/vmscan.c	2004-11-04 16:45:51.000000000 -0800
@@ -416,7 +416,7 @@ static int shrink_list(struct list_head 
 		}
 
 		if (PageDirty(page)) {
-			if (referenced)
+			if (referenced && !page_under_capture(page))
 				goto keep_locked;
 			if (!may_enter_fs)
 				goto keep_locked;
@@ -511,14 +511,17 @@ static int shrink_list(struct list_head 
 
 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:
@@ -607,7 +610,7 @@ static void shrink_cache(struct zone *zo
 			if (TestSetPageLRU(page))
 				BUG();
 			list_del(&page->lru);
-			if (PageActive(page))
+			if (PageActive(page) && !page_under_capture(page))
 				add_page_to_active_list(zone, page);
 			else
 				add_page_to_inactive_list(zone, page);
@@ -1228,7 +1231,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.
_
