

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

Each filesystem have to move its own data when migrating a page
because private member of struct page may point filesystem specific
data or some cluster filesystems might increment the count of
the page to pin it for its performance or somthing else.


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            |   15 ++++++++++-----
 3 files changed, 20 insertions(+), 5 deletions(-)

diff -puN include/linux/fs.h~P13.1-migrate_page-operation include/linux/fs.h
--- memhotplug/include/linux/fs.h~P13.1-migrate_page-operation	2004-12-10 13:53:11.000000000 -0800
+++ memhotplug-dave/include/linux/fs.h	2004-12-10 13:53:11.000000000 -0800
@@ -334,6 +334,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.1-migrate_page-operation include/linux/mmigrate.h
--- memhotplug/include/linux/mmigrate.h~P13.1-migrate_page-operation	2004-12-10 13:53:11.000000000 -0800
+++ memhotplug-dave/include/linux/mmigrate.h	2004-12-10 13:53:11.000000000 -0800
@@ -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.1-migrate_page-operation mm/mmigrate.c
--- memhotplug/mm/mmigrate.c~P13.1-migrate_page-operation	2004-12-10 13:53:11.000000000 -0800
+++ memhotplug-dave/mm/mmigrate.c	2004-12-10 13:53:11.000000000 -0800
@@ -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. */
@@ -377,7 +378,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);
@@ -396,6 +400,7 @@ need_writeback(struct page *page)
 
 /*
  * Start writeback I/O if it's a dirty page with buffers
+ * and it doesn't have migrate_page method.
  */
 static inline void page_start_writeback(struct page *page)
 {
_
