

Each filesystem can define its own page-migrating method.
If a filesystem have the method, the method is invoked instead of
generic page-migrating function.

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

 memhotplug-dave/include/linux/fs.h       |    1 +
 memhotplug-dave/include/linux/mmigrate.h |    9 +++++++++
 memhotplug-dave/mm/mmigrate.c            |   18 ++++++++++++------
 3 files changed, 22 insertions(+), 6 deletions(-)

diff -puN include/linux/fs.h~P13-migrate_page-operation include/linux/fs.h
--- memhotplug/include/linux/fs.h~P13-migrate_page-operation	2004-10-12 10:11:16.000000000 -0700
+++ memhotplug-dave/include/linux/fs.h	2004-10-12 10:11:16.000000000 -0700
@@ -331,6 +331,7 @@ struct address_space_operations {
 
 	/* notification that a page is about to become writable */
 	int (*page_mkwrite)(struct page *page);
+	int (*migrate_page)(struct page *, struct page *);
 };
 
 struct backing_dev_info;
diff -puN include/linux/mmigrate.h~P13-migrate_page-operation include/linux/mmigrate.h
--- memhotplug/include/linux/mmigrate.h~P13-migrate_page-operation	2004-10-12 10:11:16.000000000 -0700
+++ memhotplug-dave/include/linux/mmigrate.h	2004-10-12 10:11:16.000000000 -0700
@@ -5,9 +5,18 @@
 #include <linux/mm.h>
 
 
+#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);
 extern struct page * migrate_onepage(struct page *);
 extern int try_to_migrate_pages(struct list_head *);
 
+#else
+#define generic_migrate_page(p1, p2, fn)	(-ENOSYS)
+#endif
+
 #ifdef ARCH_HAS_PAGEMIGRATION
 extern void arch_migrate_page(struct page *, struct page *);
 #else
diff -puN mm/mmigrate.c~P13-migrate_page-operation mm/mmigrate.c
--- memhotplug/mm/mmigrate.c~P13-migrate_page-operation	2004-10-12 10:11:16.000000000 -0700
+++ memhotplug-dave/mm/mmigrate.c	2004-10-12 10:11:16.000000000 -0700
@@ -104,7 +104,7 @@ replace_pages(struct page *page, struct 
 /*
  * Check whether the page can be migrated or not.
  */
-static inline int
+int
 page_migratable(struct page *page, struct page *newpage,
 			int freeable_page_count)
 {
@@ -234,8 +234,9 @@ out:
  *   - Lock for the page must be held when invoked.
  *   - The page must be attached to an address_space.
  */
-static int
-generic_migrate_page(struct page *page, struct page *newpage)
+int
+generic_migrate_page(struct page *page, struct page *newpage,
+			int (*migrate_fn)(struct page *, struct page *))
 {
 	int ret;
 
@@ -276,7 +277,7 @@ generic_migrate_page(struct page *page, 
 	}
 
 	/* Wait for all operations against the page to finish. */
-	ret = migrate_page_common(page, newpage);
+	ret = migrate_fn(page, newpage);
 	switch (ret) {
 	default:
 		/* The page is busy. Try it later. */
@@ -376,7 +377,10 @@ migrate_onepage(struct page *page)
 		return ERR_PTR(-ENOMEM);
 	}
 
-	ret = generic_migrate_page(page, newpage);
+	if (mapping->a_ops->migrate_page)
+		ret = mapping->a_ops->migrate_page(page, newpage);
+	else
+		ret = generic_migrate_page(page, newpage, migrate_page_common);
 	if (ret) {
 		BUG_ON(page_count(newpage) != 1);
 		page_cache_release(newpage);
@@ -405,11 +409,13 @@ int try_to_migrate_pages(struct list_hea
 	list_for_each_entry_safe(page, page2, page_list, lru) {
 		/*
 		 * Start writeback I/O if it's a dirty page with buffers
+		 * and it doesn't have migrate_page method.
 		 */
 		if (PageDirty(page) && PagePrivate(page)) {
 			if (!TestSetPageLocked(page)) {
 				mapping = page_mapping(page);
-				if (!mapping || pageout(page, mapping) != PAGE_SUCCESS)
+				if (!mapping || mapping->a_ops->migrate_page ||
+				    pageout(page, mapping) != PAGE_SUCCESS)
 					unlock_page(page);
 			}
 		}
_
