Index: linux-2.6.17-rc1-mm3/mm/migrate.c =================================================================== --- linux-2.6.17-rc1-mm3.orig/mm/migrate.c 2006-04-18 10:58:33.878684000 -0700 +++ linux-2.6.17-rc1-mm3/mm/migrate.c 2006-04-26 23:40:13.044190896 -0700 @@ -256,23 +256,10 @@ /* * Remove or replace all references to a page so that future accesses to - * the page can be blocked. Establish the new page - * with the basic settings to be able to stop accesses to the page. + * the page can be blocked. */ -int migrate_page_remove_references(struct page *newpage, - struct page *page, int nr_refs) +static int migrate_page_remove_references(struct page *newpage, struct page *page) { - struct address_space *mapping = page_mapping(page); - struct page **radix_pointer; - - /* - * Avoid doing any of the following work if the page count - * indicates that the page is in use or truncate has removed - * the page. - */ - if (!page->mapping || - page_mapcount(page) + nr_refs != page_count(page)) - return -EAGAIN; /* * Establish migration ptes for anonymous pages or destroy pte @@ -296,32 +283,45 @@ if (page_mapcount(page)) return -EAGAIN; - if (!mapping) { - /* - * Anonymous page without swap mapping. - * User space cannot access the page anymore since we - * removed the ptes. Now check if the kernel still has - * pending references. - */ - if (page_count(page) != nr_refs) - return -EAGAIN; - - /* We are holding the only remaining reference */ - newpage->index = page->index; - newpage->mapping = page->mapping; - return 0; - } + return 0; +} +/* + * Check page count and move key anonymous page information + */ +static int migrate_page_move_anon(struct page *newpage, struct page *page) +{ /* - * The page has a mapping that we need to change + * Anonymous page without swap mapping. + * User space cannot access the page anymore since we + * removed the ptes. Now check if we hold the sole remaining + * reference. */ - write_lock_irq(&mapping->tree_lock); + if (page_count(page) != 1) + return -EAGAIN; + newpage->index = page->index; + newpage->mapping = page->mapping; + return 0; +} + + +/* + * Update the mapping to point to the new page if + * all conditions are met. + */ +int migrate_page_move_mapping(struct page *newpage, struct page *page, + struct address_space *mapping) +{ + struct page **radix_pointer; + + write_lock_irq(&mapping->tree_lock); radix_pointer = (struct page **)radix_tree_lookup_slot( &mapping->page_tree, page_index(page)); - if (!page_mapping(page) || page_count(page) != nr_refs || + if (!page_mapping(page) || + page_count(page) != 2 + !!PagePrivate(page) || *radix_pointer != page) { write_unlock_irq(&mapping->tree_lock); return -EAGAIN; @@ -352,7 +352,6 @@ return 0; } -EXPORT_SYMBOL(migrate_page_remove_references); /* * Copy the page to its new location @@ -394,7 +393,6 @@ if (PageWriteback(newpage)) end_page_writeback(newpage); } -EXPORT_SYMBOL(migrate_page_copy); /* * Common logic to directly migrate a single page suitable for @@ -404,12 +402,21 @@ */ int migrate_page(struct page *newpage, struct page *page) { + struct address_space *mapping = page_mapping(page); int rc; BUG_ON(PageWriteback(page)); /* Writeback must be complete */ - rc = migrate_page_remove_references(newpage, page, - page_mapping(page) ? 2 : 1); + rc = migrate_page_remove_references(newpage, page); + if (rc) { + remove_migration_ptes(page, page); + return rc; + } + + if (mapping) + rc = migrate_page_move_mapping(newpage, page, mapping); + else + rc = migrate_page_move_anon(newpage, page); if (rc) { remove_migration_ptes(page, page); @@ -595,8 +602,11 @@ head = page_buffers(page); - rc = migrate_page_remove_references(newpage, page, 3); + rc = migrate_page_remove_references(newpage, page); + if (rc) + return rc; + rc = migrate_page_move_mapping(newpage, page, mapping); if (rc) return rc; @@ -637,6 +647,7 @@ } EXPORT_SYMBOL(buffer_migrate_page); + /* * Migrate the list 'pagelist' of pages to a certain destination. * Index: linux-2.6.17-rc1-mm3/include/linux/migrate.h =================================================================== --- linux-2.6.17-rc1-mm3.orig/include/linux/migrate.h 2006-04-02 20:22:10.000000000 -0700 +++ linux-2.6.17-rc1-mm3/include/linux/migrate.h 2006-04-26 23:38:02.099198175 -0700 @@ -9,7 +9,6 @@ extern int putback_lru_pages(struct list_head *l); extern int migrate_page(struct page *, struct page *); extern void migrate_page_copy(struct page *, struct page *); -extern int migrate_page_remove_references(struct page *, struct page *, int); extern int migrate_pages(struct list_head *l, struct list_head *t, struct list_head *moved, struct list_head *failed); extern int migrate_pages_to(struct list_head *pagelist,