<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;">
From: Nick Piggin &lt;piggin@cyberone.com.au&gt;

Nikita's patch to keep more page ordering info in the active list.  Also
should improve system time due to less useless scanning Helps swapping
loads significantly.



---

 25-akpm/include/linux/mmzone.h |    6 +
 25-akpm/mm/page_alloc.c        |   20 +++++
 25-akpm/mm/vmscan.c            |  144 ++++++++++++++++++++++++++---------------
 3 files changed, 119 insertions(+), 51 deletions(-)

diff -puN include/linux/mmzone.h~vm-dont-rotate-active-list include/linux/mmzone.h
--- 25/include/linux/mmzone.h~vm-dont-rotate-active-list	Wed Feb  4 12:32:20 2004
+++ 25-akpm/include/linux/mmzone.h	Wed Feb  4 12:32:20 2004
@@ -149,6 +149,12 @@ struct zone {
 	unsigned long		zone_start_pfn;
 
 	/*
+	 * dummy page used as place holder during scanning of
+	 * active_list in refill_inactive_zone()
+	 */
+	struct page *scan_page;
+
+	/*
 	 * rarely used fields:
 	 */
 	char			*name;
diff -puN mm/page_alloc.c~vm-dont-rotate-active-list mm/page_alloc.c
--- 25/mm/page_alloc.c~vm-dont-rotate-active-list	Wed Feb  4 12:32:20 2004
+++ 25-akpm/mm/page_alloc.c	Wed Feb  4 12:32:20 2004
@@ -1211,6 +1211,9 @@ void __init memmap_init_zone(struct page
 	memmap_init_zone((start), (size), (nid), (zone), (start_pfn))
 #endif
 
+/* dummy pages used to scan active lists */
+static struct page scan_pages[MAX_NUMNODES][MAX_NR_ZONES];
+
 /*
  * Set up the zone data structures:
  *   - mark all pages reserved
@@ -1233,6 +1236,7 @@ static void __init free_area_init_core(s
 		struct zone *zone = pgdat-&gt;node_zones + j;
 		unsigned long size, realsize;
 		unsigned long batch;
+		struct page *scan_page;
 
 		zone_table[NODEZONE(nid, j)] = zone;
 		realsize = size = zones_size[j];
@@ -1287,6 +1291,22 @@ static void __init free_area_init_core(s
 		atomic_set(&amp;zone-&gt;refill_counter, 0);
 		zone-&gt;nr_active = 0;
 		zone-&gt;nr_inactive = 0;
+
+		/* initialize dummy page used for scanning */
+		scan_page = &amp;scan_pages[nid][j];
+		zone-&gt;scan_page = scan_page;
+		memset(scan_page, 0, sizeof *scan_page);
+		scan_page-&gt;flags =
+			(1 &lt;&lt; PG_locked) |
+			(1 &lt;&lt; PG_error) |
+			(1 &lt;&lt; PG_lru) |
+			(1 &lt;&lt; PG_active) |
+			(1 &lt;&lt; PG_reserved);
+		set_page_zone(scan_page, j);
+		page_cache_get(scan_page);
+		INIT_LIST_HEAD(&amp;scan_page-&gt;list);
+		list_add(&amp;scan_page-&gt;lru, &amp;zone-&gt;active_list);
+
 		if (!size)
 			continue;
 
diff -puN mm/vmscan.c~vm-dont-rotate-active-list mm/vmscan.c
--- 25/mm/vmscan.c~vm-dont-rotate-active-list	Wed Feb  4 12:32:20 2004
+++ 25-akpm/mm/vmscan.c	Wed Feb  4 12:32:20 2004
@@ -43,14 +43,15 @@
 int vm_swappiness = 60;
 static long total_memory;
 
+#define lru_to_page(_head) (list_entry((_head)-&gt;prev, struct page, lru))
+
 #ifdef ARCH_HAS_PREFETCH
 #define prefetch_prev_lru_page(_page, _base, _field)			\
 	do {								\
 		if ((_page)-&gt;lru.prev != _base) {			\
 			struct page *prev;				\
 									\
-			prev = list_entry(_page-&gt;lru.prev,		\
-					struct page, lru);		\
+			prev = lru_to_page(&amp;(_page)-&gt;lru);		\
 			prefetch(&amp;prev-&gt;_field);			\
 		}							\
 	} while (0)
@@ -64,8 +65,7 @@ static long total_memory;
 		if ((_page)-&gt;lru.prev != _base) {			\
 			struct page *prev;				\
 									\
-			prev = list_entry(_page-&gt;lru.prev,		\
-					struct page, lru);		\
+			prev = lru_to_page(&amp;(_page)-&gt;lru);		\
 			prefetchw(&amp;prev-&gt;_field);			\
 		}							\
 	} while (0)
@@ -260,7 +260,7 @@ shrink_list(struct list_head *page_list,
 		int may_enter_fs;
 		int referenced;
 
-		page = list_entry(page_list-&gt;prev, struct page, lru);
+		page = lru_to_page(page_list);
 		list_del(&amp;page-&gt;lru);
 
 		if (TestSetPageLocked(page))
@@ -505,8 +505,7 @@ shrink_cache(const int nr_pages, struct 
 
 		while (nr_scan++ &lt; nr_to_process &amp;&amp;
 				!list_empty(&amp;zone-&gt;inactive_list)) {
-			page = list_entry(zone-&gt;inactive_list.prev,
-						struct page, lru);
+			page = lru_to_page(&amp;zone-&gt;inactive_list);
 
 			prefetchw_prev_lru_page(page,
 						&amp;zone-&gt;inactive_list, flags);
@@ -544,7 +543,7 @@ shrink_cache(const int nr_pages, struct 
 		 * Put back any unfreeable pages.
 		 */
 		while (!list_empty(&amp;page_list)) {
-			page = list_entry(page_list.prev, struct page, lru);
+			page = lru_to_page(&amp;page_list);
 			if (TestSetPageLRU(page))
 				BUG();
 			list_del(&amp;page-&gt;lru);
@@ -565,6 +564,39 @@ done:
 	return ret;
 }
 
+
+/* move pages from @page_list to the @spot, that should be somewhere on the
+ * @zone-&gt;active_list */
+static int
+spill_on_spot(struct zone *zone,
+	      struct list_head *page_list, struct list_head *spot,
+	      struct pagevec *pvec)
+{
+	struct page *page;
+	int          moved;
+
+	moved = 0;
+	while (!list_empty(page_list)) {
+		page = lru_to_page(page_list);
+		prefetchw_prev_lru_page(page, page_list, flags);
+		if (TestSetPageLRU(page))
+			BUG();
+		BUG_ON(!PageActive(page));
+		list_move(&amp;page-&gt;lru, spot);
+		moved++;
+		if (!pagevec_add(pvec, page)) {
+			zone-&gt;nr_active += moved;
+			moved = 0;
+			spin_unlock_irq(&amp;zone-&gt;lru_lock);
+			__pagevec_release(pvec);
+			spin_lock_irq(&amp;zone-&gt;lru_lock);
+		}
+	}
+	return moved;
+}
+
+
+
 /*
  * This moves pages from the active list to the inactive list.
  *
@@ -591,37 +623,18 @@ refill_inactive_zone(struct zone *zone, 
 	int nr_pages = nr_pages_in;
 	LIST_HEAD(l_hold);	/* The pages which were snipped off */
 	LIST_HEAD(l_inactive);	/* Pages to go onto the inactive_list */
-	LIST_HEAD(l_active);	/* Pages to go onto the active_list */
+	LIST_HEAD(l_ignore);	/* Pages to be returned to the active_list */
+	LIST_HEAD(l_active);	/* Pages to go onto the head of the
+				 * active_list */
+
 	struct page *page;
+	struct page *scan;
 	struct pagevec pvec;
 	int reclaim_mapped = 0;
 	long mapped_ratio;
 	long distress;
 	long swap_tendency;
 
-	lru_add_drain();
-	pgmoved = 0;
-	spin_lock_irq(&amp;zone-&gt;lru_lock);
-	while (nr_pages &amp;&amp; !list_empty(&amp;zone-&gt;active_list)) {
-		page = list_entry(zone-&gt;active_list.prev, struct page, lru);
-		prefetchw_prev_lru_page(page, &amp;zone-&gt;active_list, flags);
-		if (!TestClearPageLRU(page))
-			BUG();
-		list_del(&amp;page-&gt;lru);
-		if (page_count(page) == 0) {
-			/* It is currently in pagevec_release() */
-			SetPageLRU(page);
-			list_add(&amp;page-&gt;lru, &amp;zone-&gt;active_list);
-		} else {
-			page_cache_get(page);
-			list_add(&amp;page-&gt;lru, &amp;l_hold);
-			pgmoved++;
-		}
-		nr_pages--;
-	}
-	zone-&gt;nr_active -= pgmoved;
-	spin_unlock_irq(&amp;zone-&gt;lru_lock);
-
 	/*
 	 * `distress' is a measure of how much trouble we're having reclaiming
 	 * pages.  0 -&gt; no problems.  100 -&gt; great trouble.
@@ -653,10 +666,53 @@ refill_inactive_zone(struct zone *zone, 
 	if (swap_tendency &gt;= 100)
 		reclaim_mapped = 1;
 
+	scan = zone-&gt;scan_page;
+	lru_add_drain();
+	pgmoved = 0;
+	spin_lock_irq(&amp;zone-&gt;lru_lock);
+	if (reclaim_mapped) {
+		/*
+		 * When scanning active_list with !reclaim_mapped mapped
+		 * inactive pages are left behind zone-&gt;scan_page. If zone is
+		 * switched to reclaim_mapped mode reset zone-&gt;scan_page to
+		 * the end of inactive list so that inactive mapped pages are
+		 * re-scanned.
+		 */
+		list_move_tail(&amp;scan-&gt;lru, &amp;zone-&gt;active_list);
+	}
+	while (nr_pages &amp;&amp; zone-&gt;active_list.prev != zone-&gt;active_list.next) {
+		/*
+		 * if head of active list reached---wrap to the tail
+		 */
+		if (scan-&gt;lru.prev == &amp;zone-&gt;active_list)
+			list_move_tail(&amp;scan-&gt;lru, &amp;zone-&gt;active_list);
+		page = lru_to_page(&amp;scan-&gt;lru);
+		prefetchw_prev_lru_page(page, &amp;zone-&gt;active_list, flags);
+		if (!TestClearPageLRU(page))
+			BUG();
+		list_del(&amp;page-&gt;lru);
+		if (page_count(page) == 0) {
+			/* It is currently in pagevec_release() */
+			SetPageLRU(page);
+			list_add(&amp;page-&gt;lru, &amp;zone-&gt;active_list);
+		} else {
+			page_cache_get(page);
+			list_add(&amp;page-&gt;lru, &amp;l_hold);
+			pgmoved++;
+		}
+		nr_pages--;
+	}
+	zone-&gt;nr_active -= pgmoved;
+	spin_unlock_irq(&amp;zone-&gt;lru_lock);
+
 	while (!list_empty(&amp;l_hold)) {
-		page = list_entry(l_hold.prev, struct page, lru);
+		page = lru_to_page(&amp;l_hold);
 		list_del(&amp;page-&gt;lru);
 		if (page_mapped(page)) {
+			/*
+			 * probably it would be useful to transfer dirty bit
+			 * from pte to the @page here.
+			 */
 			pte_chain_lock(page);
 			if (page_mapped(page) &amp;&amp; page_referenced(page)) {
 				pte_chain_unlock(page);
@@ -665,7 +721,7 @@ refill_inactive_zone(struct zone *zone, 
 			}
 			pte_chain_unlock(page);
 			if (!reclaim_mapped) {
-				list_add(&amp;page-&gt;lru, &amp;l_active);
+				list_add(&amp;page-&gt;lru, &amp;l_ignore);
 				continue;
 			}
 		}
@@ -685,7 +741,7 @@ refill_inactive_zone(struct zone *zone, 
 	pgmoved = 0;
 	spin_lock_irq(&amp;zone-&gt;lru_lock);
 	while (!list_empty(&amp;l_inactive)) {
-		page = list_entry(l_inactive.prev, struct page, lru);
+		page = lru_to_page(&amp;l_inactive);
 		prefetchw_prev_lru_page(page, &amp;l_inactive, flags);
 		if (TestSetPageLRU(page))
 			BUG();
@@ -712,23 +768,9 @@ refill_inactive_zone(struct zone *zone, 
 		spin_lock_irq(&amp;zone-&gt;lru_lock);
 	}
 
-	pgmoved = 0;
-	while (!list_empty(&amp;l_active)) {
-		page = list_entry(l_active.prev, struct page, lru);
-		prefetchw_prev_lru_page(page, &amp;l_active, flags);
-		if (TestSetPageLRU(page))
-			BUG();
-		BUG_ON(!PageActive(page));
-		list_move(&amp;page-&gt;lru, &amp;zone-&gt;active_list);
-		pgmoved++;
-		if (!pagevec_add(&amp;pvec, page)) {
+	pgmoved = spill_on_spot(zone, &amp;l_active, &amp;zone-&gt;active_list, &amp;pvec);
 			zone-&gt;nr_active += pgmoved;
-			pgmoved = 0;
-			spin_unlock_irq(&amp;zone-&gt;lru_lock);
-			__pagevec_release(&amp;pvec);
-			spin_lock_irq(&amp;zone-&gt;lru_lock);
-		}
-	}
+	pgmoved = spill_on_spot(zone, &amp;l_ignore, &amp;scan-&gt;lru, &amp;pvec);
 	zone-&gt;nr_active += pgmoved;
 	spin_unlock_irq(&amp;zone-&gt;lru_lock);
 	pagevec_release(&amp;pvec);

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