From: Martin Hicks <mort@sgi.com>

The patches introduce two different ways to free up page cache from a node:
manually through a syscall and automatically through flag modifiers to a
mempolicy.

Currently if a job is started and there is page cache lying around on a
particular node then allocations will spill onto remote nodes and page cache
won't be reclaimed until the whole system is short on memory.  This can result
in a signficiant performance hit for HPC applications that planned on that
memory being allocated locally.

Just a refactoring patch that sticks a list of pages back onto the appropriate
LRU lists.  This is used to return pages to the LRU lists after processing
them outside the LRU lock.

Signed-off-by:  Martin Hicks <mort@sgi.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
---

 mm/vmscan.c |   62 ++++++++++++++++++++++++++++++++++++------------------------
 1 files changed, 38 insertions(+), 24 deletions(-)

diff -puN mm/vmscan.c~vm-merge_lru_pages mm/vmscan.c
--- 25/mm/vmscan.c~vm-merge_lru_pages	Wed Apr 27 16:37:37 2005
+++ 25-akpm/mm/vmscan.c	Wed Apr 27 16:37:37 2005
@@ -605,20 +605,50 @@ static int isolate_lru_pages(int nr_to_s
 }
 
 /*
+ * This is the opposite of isolate_lru_pages().  It puts the
+ * pages in @list back onto the lru lists in @zone.
+ */
+void merge_lru_pages(struct zone *zone, struct list_head *list)
+{
+	struct page *page;
+	struct pagevec pvec;
+
+	BUG_ON(zone == NULL);
+	BUG_ON(list == NULL);
+
+	pagevec_init(&pvec, 1);
+
+	while (!list_empty(list)) {
+		page = lru_to_page(list);
+		if (TestSetPageLRU(page))
+			BUG();
+		list_del(&page->lru);
+		if (PageActive(page))
+			add_page_to_active_list(zone, page);
+		else
+			add_page_to_inactive_list(zone, page);
+		if (!pagevec_add(&pvec, page)) {
+			spin_unlock_irq(&zone->lru_lock);
+			__pagevec_release(&pvec);
+			spin_lock_irq(&zone->lru_lock);
+		}
+	}
+	spin_unlock_irq(&zone->lru_lock);
+	pagevec_release(&pvec);
+	spin_lock_irq(&zone->lru_lock);
+}
+
+/*
  * shrink_cache() adds the number of pages reclaimed to sc->nr_reclaimed
  */
 static void shrink_cache(struct zone *zone, struct scan_control *sc)
 {
 	LIST_HEAD(page_list);
-	struct pagevec pvec;
 	int max_scan = sc->nr_to_scan;
 
-	pagevec_init(&pvec, 1);
-
 	lru_add_drain();
 	spin_lock_irq(&zone->lru_lock);
 	while (max_scan > 0) {
-		struct page *page;
 		int nr_taken;
 		int nr_scan;
 		int nr_freed;
@@ -631,7 +661,7 @@ static void shrink_cache(struct zone *zo
 		spin_unlock_irq(&zone->lru_lock);
 
 		if (nr_taken == 0)
-			goto done;
+			return;
 
 		max_scan -= nr_scan;
 		if (current_is_kswapd())
@@ -644,29 +674,13 @@ static void shrink_cache(struct zone *zo
 		mod_page_state_zone(zone, pgsteal, nr_freed);
 		sc->nr_to_reclaim -= nr_freed;
 
-		spin_lock_irq(&zone->lru_lock);
 		/*
 		 * Put back any unfreeable pages.
 		 */
-		while (!list_empty(&page_list)) {
-			page = lru_to_page(&page_list);
-			if (TestSetPageLRU(page))
-				BUG();
-			list_del(&page->lru);
-			if (PageActive(page))
-				add_page_to_active_list(zone, page);
-			else
-				add_page_to_inactive_list(zone, page);
-			if (!pagevec_add(&pvec, page)) {
-				spin_unlock_irq(&zone->lru_lock);
-				__pagevec_release(&pvec);
-				spin_lock_irq(&zone->lru_lock);
-			}
-		}
-  	}
+		spin_lock_irq(&zone->lru_lock);
+		merge_lru_pages(zone, &page_list);
+	}
 	spin_unlock_irq(&zone->lru_lock);
-done:
-	pagevec_release(&pvec);
 }
 
 /*
_