This is a rollup of two patches from KAMEZAWA Hiroyuki. A slightly later version exists but this is the one I tested with and it checks page_mapped() with the RCU lock held.
Patch 1 is "page migration by kernel v5." Patch 2 is "isolate lru page race fix." Changelog V5->V6 - removed dummy_vma and uses rcu_read_lock(). In usual, migrate_pages(page,,) is called with holoding mm->sem by systemcall. (mm here is a mm_struct which maps the migration target page.) This semaphore helps avoiding some race conditions. But, if we want to migrate a page by some kernel codes, we have to avoid some races. This patch adds check code for following race condition. 1. A page which is not mapped can be target of migration. Then, we have to check page_mapped() before calling try_to_unmap(). 2. anon_vma can be freed while page is unmapped, but page->mapping remains as it was. We drop page->mapcount to be 0. Then we cannot trust page->mapping. So, use rcu_read_lock() to prevent anon_vma pointed by page->mapping will not be freed during migration. release_pages() in mm/swap.c changes page_count() to be 0 without removing PageLRU flag... This means isolate_lru_page() can see a page, PageLRU() && page_count(page)==0.. This is BUG. (get_page() will be called against count=0 page.) Signed-off-by: KAMEZAWA Hiroyuki <[EMAIL PROTECTED]> Signed-off-by: Mel Gorman <[EMAIL PROTECTED]> --- migrate.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff -rup -X /usr/src/patchset-0.6/bin//dontdiff linux-2.6.22-rc4-mm2-clean/mm/migrate.c linux-2.6.22-rc4-mm2-005_migrationkernel/mm/migrate.c --- linux-2.6.22-rc4-mm2-clean/mm/migrate.c 2007-06-13 23:43:12.000000000 +0100 +++ linux-2.6.22-rc4-mm2-005_migrationkernel/mm/migrate.c 2007-06-15 16:25:31.000000000 +0100 @@ -49,9 +49,8 @@ int isolate_lru_page(struct page *page, struct zone *zone = page_zone(page); spin_lock_irq(&zone->lru_lock); - if (PageLRU(page)) { + if (PageLRU(page) && get_page_unless_zero(page)) { ret = 0; - get_page(page); ClearPageLRU(page); if (PageActive(page)) del_page_from_active_list(zone, page); @@ -612,6 +611,7 @@ static int unmap_and_move(new_page_t get int rc = 0; int *result = NULL; struct page *newpage = get_new_page(page, private, &result); + int rcu_locked = 0; if (!newpage) return -ENOMEM; @@ -632,18 +632,27 @@ static int unmap_and_move(new_page_t get goto unlock; wait_on_page_writeback(page); } - + /* anon_vma should not be freed while migration. */ + if (PageAnon(page)) { + rcu_read_lock(); + rcu_locked = 1; + } /* * Establish migration ptes or remove ptes */ - try_to_unmap(page, 1); if (!page_mapped(page)) - rc = move_to_new_page(newpage, page); + goto unlock; + + try_to_unmap(page, 1); + rc = move_to_new_page(newpage, page); if (rc) remove_migration_ptes(page, page); unlock: + if (rcu_locked) + rcu_read_unlock(); + unlock_page(page); if (rc != -EAGAIN) { - To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to [EMAIL PROTECTED] More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/