 atomic_copy.c |  102 +++++++++++++++++++++++++++++++++++++++++++++++++++-------
 pagedir.c     |   35 ++++++++++---------
 2 files changed, 108 insertions(+), 29 deletions(-)
diff -ruNp 940-use-bitmap-for-conflicting-pages-list.patch-old/kernel/power/atomic_copy.c 940-use-bitmap-for-conflicting-pages-list.patch-new/kernel/power/atomic_copy.c
--- 940-use-bitmap-for-conflicting-pages-list.patch-old/kernel/power/atomic_copy.c	2005-07-23 05:14:15.000000000 +1000
+++ 940-use-bitmap-for-conflicting-pages-list.patch-new/kernel/power/atomic_copy.c	2005-07-23 05:07:42.000000000 +1000
@@ -41,6 +41,7 @@
 #include "suspend2.h"
 #include "suspend2-smp.h"
 #include "checksum.h"
+#include "pageflags.h"
 
 volatile static int state1 __nosavedata = 0;
 volatile static int state2 __nosavedata = 0;
@@ -56,6 +57,10 @@ static int __nosavedata loop;
 __nosavedata char resume_commandline[COMMAND_LINE_SIZE];
 
 static atomic_t atomic_copy_hold;
+static atomic_t restore_thread_ready;
+
+static dyn_pageflags_t non_conflicting_pages_map;
+static dyn_pageflags_t conflicting_pages_map;
 
 /**
  * copyback_prepare
@@ -221,7 +226,6 @@ static inline void copyback_low(void)
 {
 	unsigned long * origpage;
 	unsigned long * copypage;
-	//int loop;
 
 	origmap = pageset1_map;
 	copymap = pageset1_copy_map;
@@ -408,8 +412,39 @@ void suspend2_unmap_atomic_copy_pages(vo
 }
 #endif
 
+atomic_t number_started;
+atomic_t number_ok;
+int have_thread = 0;
+
 int __suspend_atomic_restore(void *data)
 {
+	if (PagePageset1(virt_to_page(current->thread_info))) {
+
+		atomic_inc(&number_started);
+		current->flags &= ~PF_NOFREEZE;
+
+		while (1) {
+			if (!have_thread) {
+				BUG_ON((kernel_thread(__suspend_atomic_restore, 0,
+					CLONE_KERNEL) < 0));
+			}
+			try_to_freeze();
+			mdelay(50);
+		}
+	}
+
+	if (!atomic_dec_and_test(&number_ok)) {
+		current->flags &= ~PF_NOFREEZE;
+		while (1) {
+			try_to_freeze();
+			mdelay(50);
+		}
+	}
+
+	have_thread = 1;
+
+	atomic_set(&restore_thread_ready, 1);
+
 	while atomic_read(&atomic_copy_hold)
 		schedule();
 
@@ -434,33 +469,76 @@ int __suspend_atomic_restore(void *data)
 	return 0;
 }
 
+static inline void SetPageNonConflicting(struct page * page)
+{
+	set_bit(PAGEBIT(page), PAGE_UL_PTR(non_conflicting_pages_map, page));
+}
+
+static inline void SetPageConflicting(struct page * page)
+{
+	set_bit(PAGEBIT(page), PAGE_UL_PTR(conflicting_pages_map, page));
+}
+
+static inline void get_all_pages(void)
+{
+	int order;
+	unsigned long address;
+
+	order = MAX_ORDER;
+
+	while (order-- >= 0) {
+		while ((address = __get_free_pages(GFP_ATOMIC | __GFP_NOWARN, order))) {
+			struct page * page = virt_to_page(address);
+			int i;
+
+			for (i = 0; i < (1UL << order); i++)
+				if (PagePageset1(page + i))
+					SetPageConflicting(page + i);
+				else
+					SetPageNonConflicting(page + i);
+		}
+	}
+}
+
+int num_non_conflicting = 0;
 
 void suspend_atomic_restore(void)
 {
-	LIST_HEAD(non_conflicting_pages);
-	unsigned long next;
-	struct page * this_page, * next_page;
+	int pfn;
 	
+	atomic_set(&number_started, 1);
+
 	/* Allocate all memory available, then free only those pages
 	 * that don't conflict. This ensures that the stack for our
 	 * copy-back thread is non-conflicting */
-	while ((next = suspend2_get_nonconflicting_pages(0))) {
-		struct page * page = virt_to_page(next);
-		list_add(&page->lru, &non_conflicting_pages);
-	}
+	allocate_dyn_pageflags(&non_conflicting_pages_map);
+	allocate_dyn_pageflags(&conflicting_pages_map);
+
+	get_all_pages();
 
-	list_for_each_entry_safe(this_page, next_page, &non_conflicting_pages, lru) {
-		list_del(&this_page->lru);
-		__free_page(this_page);
+	BITMAP_FOR_EACH_SET(non_conflicting_pages_map, pfn) {
+		set_page_count(pfn_to_page(pfn), 1);
+		__free_page(pfn_to_page(pfn));
 	}
 
+	free_dyn_pageflags(&non_conflicting_pages_map);
+
 	atomic_set(&atomic_copy_hold, 1);
+	atomic_set(&restore_thread_ready, 0);
+	atomic_set(&number_ok, 1);
+	have_thread = 0;
 
 	/* Now start the new thread */
 	BUG_ON((kernel_thread(__suspend_atomic_restore, 0,
 			CLONE_KERNEL) < 0));
 
-	suspend2_release_conflicting_pages();
+	while (!atomic_read(&restore_thread_ready))
+		schedule();
+
+	BITMAP_FOR_EACH_SET(conflicting_pages_map, pfn) {
+		set_page_count(pfn_to_page(pfn), 1);
+		__free_page(pfn_to_page(pfn));
+	}
 	
 	atomic_set(&atomic_copy_hold, 0);
 	
diff -ruNp 940-use-bitmap-for-conflicting-pages-list.patch-old/kernel/power/pagedir.c 940-use-bitmap-for-conflicting-pages-list.patch-new/kernel/power/pagedir.c
--- 940-use-bitmap-for-conflicting-pages-list.patch-old/kernel/power/pagedir.c	2005-07-23 05:14:15.000000000 +1000
+++ 940-use-bitmap-for-conflicting-pages-list.patch-new/kernel/power/pagedir.c	2005-07-23 04:15:21.000000000 +1000
@@ -22,7 +22,8 @@
 #include "pagedir.h"
 
 int extra_pagedir_pages_allocated = 0;
-static LIST_HEAD(conflicting_pages);
+
+dyn_pageflags_t conflicting_pages_map;
 
 /* suspend2_free_pagedir_data
  *
@@ -203,6 +204,11 @@ void suspend2_mark_pages_for_pageset2(vo
 	}
 }
 
+static inline void SetPageConflicting(struct page * page)
+{
+	set_bit(PAGEBIT(page), PAGE_UL_PTR(conflicting_pages_map, page));
+}
+
 /* suspend2_get_nonconflicting_pages
  *
  * Description: Gets higher-order pages that won't be overwritten
@@ -218,9 +224,12 @@ unsigned long suspend2_get_nonconflictin
 {
 	struct page * page;
 	unsigned long new_page;
-	int more = 0;
+	int more = 0, i;
 	unsigned long pgcount;
 
+	if (!conflicting_pages_map && allocate_dyn_pageflags(&conflicting_pages_map))
+		return -ENOMEM;
+
 	do {
 		new_page = __get_free_pages(GFP_ATOMIC | __GFP_NOWARN, order);
 		if (!new_page)
@@ -235,13 +244,8 @@ unsigned long suspend2_get_nonconflictin
 		}
 		if (more) {
 			page = virt_to_page(new_page);
-			list_add(&page->lru, &conflicting_pages);
-
-			/* since this page is technically free, we can abuse it to
-			 * store the order. When we resume it'll just be overwritten,
-			 * but we need this value when freeing it in
-			 * suspend2_release_conflicting_pages. */
-			*((int*)new_page) = order;
+			for (i = 0; i < (1UL << order); i++)
+				SetPageConflicting(page + i);
 		}
 	}
 	while (more);
@@ -259,15 +263,12 @@ unsigned long suspend2_get_nonconflictin
 
 void suspend2_release_conflicting_pages(void)
 {
-	struct page *this_page, *next;
-	int order;
+	int pfn;
 
-	list_for_each_entry_safe(this_page, next, &conflicting_pages, lru)
-	{
-		order = *((int*)(page_address(this_page)));
-		list_del(&this_page->lru);
-		__free_pages(virt_to_page(this_page), order);
-	}
+	BITMAP_FOR_EACH_SET(conflicting_pages_map, pfn)
+		__free_page(pfn_to_page(pfn));
+
+	free_dyn_pageflags(&conflicting_pages_map);
 }
 
 /* relocate_page_if_required

