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/

Reply via email to