--- /usr/src/linux-vanilla/mm/migrate.c 2006-12-02 15:08:23.000000000 +0100 +++ /usr/src/linux/mm/migrate.c 2007-03-12 18:44:16.000000000 +0100 @@ -587,7 +595,7 @@ static int move_to_new_page(struct page * to the newly allocated page in newpage. */ static int unmap_and_move(new_page_t get_new_page, unsigned long private, - struct page *page, int force) + struct page *page, int force, int put_lru) { int rc = 0; int *result = NULL; @@ -631,10 +639,11 @@ unlock: * A page that has been migrated has all references * removed and will be freed. A page that has not been * migrated will have kepts its references and be - * restored. + * restored. Don't push page to LRU unless wanted. */ list_del(&page->lru); - move_to_lru(page); + if(put_lru) + move_to_lru(page); } move_newpage: @@ -687,7 +696,7 @@ int migrate_pages(struct list_head *from cond_resched(); rc = unmap_and_move(get_new_page, private, - page, pass > 2); + page, pass > 2, 1); switch(rc) { case -ENOMEM: @@ -717,6 +726,111 @@ out: return nr_failed + retry; } +/* target page is stored in private parameter when used from + * migrate_pfn_page + */ +static struct page * return_target(struct page * page, unsigned long private, + int ** result) +{ + return (struct page *)private; +} + +int __migrate_pfn_page(struct page * page, new_page_t get_new_page, unsigned long private) +{ + int rc = 0; + int pass; + int retry = 1; + + for(pass = 0; pass < 10 && retry; pass++) + { + retry = 0; + cond_resched(); + rc = unmap_and_move(get_new_page, private, page, pass > 2, 0); + switch(rc) + { + case -ENOMEM: + goto out; + case -EAGAIN: + retry = 1; + break; + case 0: + break; + default: + return 1; + } + } + if(rc) + move_to_lru(page); +out: + return rc; +} + +int migrate_pfn_page(struct page * original, struct page * target) +{ + LIST_HEAD(pagelist); + int ret; + int swapwrite = current->flags & PF_SWAPWRITE; + + if (!swapwrite) + current->flags |= PF_SWAPWRITE; + + /* this will fail if migration is not supported */ + if((ret = migrate_prep())) + goto done; + get_page(original); + ret = isolate_lru_page(original, &pagelist); + put_page(original); + if(ret) + goto done; + ret = __migrate_pfn_page(original, return_target, (unsigned long)target); + if(!ret) + page_cache_release(original); +done: + if (!swapwrite) + current->flags &= ~PF_SWAPWRITE; + return ret; +}