
With this patch, mlocked pages can be migrated.
It works the following steps:
  1. Unmap a target page from process spaces.
  2. Replace the page with new one.
  3. Map the new page to the process spaces where the old one
     have been mapped.

Signed-off-by: Hirokazu Takahashi <taka@valinux.co.jp>
Signed-off-by: Dave Hansen <haveblue@us.ibm.com>
---

 memhotplug-dave/include/linux/mmigrate.h |    8 +++++---
 memhotplug-dave/mm/mmigrate.c            |   31 ++++++++++++++++++++++++-------
 2 files changed, 29 insertions(+), 10 deletions(-)

diff -puN include/linux/mmigrate.h~page_migration17-mlock-migrated-pages include/linux/mmigrate.h
--- memhotplug/include/linux/mmigrate.h~page_migration17-mlock-migrated-pages	2005-01-04 13:49:16.000000000 -0800
+++ memhotplug-dave/include/linux/mmigrate.h	2005-01-04 13:49:16.000000000 -0800
@@ -7,9 +7,11 @@
 
 #ifdef CONFIG_MEMORY_MIGRATE
 extern int generic_migrate_page(struct page *, struct page *,
-		int (*)(struct page *, struct page *));
-extern int migrate_page_common(struct page *, struct page *);
-extern int page_migratable(struct page *, struct page *, int);
+		int (*)(struct page *, struct page *, struct list_head *));
+extern int migrate_page_common(struct page *, struct page *,
+					struct list_head *);
+extern int page_migratable(struct page *, struct page *, int,
+					struct list_head *);
 extern struct page * migrate_onepage(struct page *);
 extern int try_to_migrate_pages(struct list_head *);
 
diff -puN mm/mmigrate.c~page_migration17-mlock-migrated-pages mm/mmigrate.c
--- memhotplug/mm/mmigrate.c~page_migration17-mlock-migrated-pages	2005-01-04 13:49:16.000000000 -0800
+++ memhotplug-dave/mm/mmigrate.c	2005-01-04 13:49:16.000000000 -0800
@@ -106,12 +106,12 @@ replace_pages(struct page *page, struct 
  */
 int
 page_migratable(struct page *page, struct page *newpage,
-			int freeable_page_count)
+			int freeable_page_count, struct list_head *vlist)
 {
 	int truncated;
 
 	if (page_mapped(page)) {
-		switch (try_to_unmap(page, NULL)) {
+		switch (try_to_unmap(page, vlist)) {
 		case SWAP_FAIL:
 			return -EBUSY;
 		case SWAP_AGAIN:
@@ -132,14 +132,15 @@ page_migratable(struct page *page, struc
  * against the page, and copy it.
  */
 int
-migrate_page_common(struct page *page, struct page *newpage)
+migrate_page_common(struct page *page, struct page *newpage,
+					struct list_head *vlist)
 {
 	long timeout = 5000;	/* XXXX */
 	int ret;
 
 	while (timeout > 0) {
 		BUG_ON(page_count(page) == 0);
-		ret = page_migratable(page, newpage, 2);
+		ret = page_migratable(page, newpage, 2, vlist);
 		switch (ret) {
 		case 0:
 		case -ENOENT:
@@ -236,8 +237,9 @@ out:
  */
 int
 generic_migrate_page(struct page *page, struct page *newpage,
-			int (*migrate_fn)(struct page *, struct page *))
+	int (*migrate_fn)(struct page *, struct page *, struct list_head *))
 {
+	LIST_HEAD(vlist);
 	int ret;
 
 	/*
@@ -257,7 +259,7 @@ generic_migrate_page(struct page *page, 
 	 * can be caught and blocked in a pagefault handler.
 	 */
 	if (page_mapped(page)) {
-		while ((ret = try_to_unmap(page, NULL)) == SWAP_AGAIN)
+		while ((ret = try_to_unmap(page, &vlist)) == SWAP_AGAIN)
 			msleep(1);
 		if (ret != SWAP_SUCCESS) {
 			ret = -EBUSY;
@@ -277,7 +279,7 @@ generic_migrate_page(struct page *page, 
 	}
 
 	/* Wait for all operations against the page to finish. */
-	ret = migrate_fn(page, newpage);
+	ret = migrate_fn(page, newpage, &vlist);
 	switch (ret) {
 	default:
 		/* The page is busy. Try it later. */
@@ -320,6 +322,14 @@ generic_migrate_page(struct page *page, 
 		end_page_writeback(newpage);
 	unlock_page(newpage);
 
+	/* map the newpage where the old page have been mapped. */
+	touch_unmapped_address(&vlist);
+	if (PageSwapCache(newpage)) {
+		lock_page(newpage);
+		__remove_exclusive_swap_page(newpage, 1);
+		unlock_page(newpage);
+	}
+
 	page->mapping = NULL;
 	unlock_page(page);
 	page_cache_release(page);
@@ -329,6 +339,13 @@ generic_migrate_page(struct page *page, 
 out_busy:
 	/* Roll back all operations. */
 	unwind_page(page, newpage);
+	touch_unmapped_address(&vlist);
+	if (PageSwapCache(page)) {
+		lock_page(page);
+		__remove_exclusive_swap_page(page, 1);
+		unlock_page(page);
+	}
+
 	return ret;
 
 out_removing:
_
