]> err.no Git - linux-2.6/commitdiff
fix rcu_read_lock() in page migraton
authorKAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com>
Fri, 31 Aug 2007 06:56:21 +0000 (23:56 -0700)
committerLinus Torvalds <torvalds@woody.linux-foundation.org>
Fri, 31 Aug 2007 08:42:22 +0000 (01:42 -0700)
In migration fallback path, write_page() or lock_page() will be called.
This causes sleep with holding rcu_read_lock().
For avoding that, just do rcu_lock if the page is Anon.(this is enough.)

Signed-off-by: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com>
Acked-by: Christoph Lameter <clameter@sgi.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
mm/migrate.c

index 37c73b902008e1dd2083f71995f2ce67975f6512..e2fdbce1874b4ff7a481621b6c5a3285d8d75260 100644 (file)
@@ -611,6 +611,7 @@ static int unmap_and_move(new_page_t get_new_page, unsigned long private,
        int rc = 0;
        int *result = NULL;
        struct page *newpage = get_new_page(page, private, &result);
+       int rcu_locked = 0;
 
        if (!newpage)
                return -ENOMEM;
@@ -636,8 +637,13 @@ static int unmap_and_move(new_page_t get_new_page, unsigned long private,
         * we cannot notice that anon_vma is freed while we migrates a page.
         * This rcu_read_lock() delays freeing anon_vma pointer until the end
         * of migration. File cache pages are no problem because of page_lock()
+        * File Caches may use write_page() or lock_page() in migration, then,
+        * just care Anon page here.
         */
-       rcu_read_lock();
+       if (PageAnon(page)) {
+               rcu_read_lock();
+               rcu_locked = 1;
+       }
        /*
         * This is a corner case handling.
         * When a new swap-cache is read into, it is linked to LRU
@@ -656,7 +662,8 @@ static int unmap_and_move(new_page_t get_new_page, unsigned long private,
        if (rc)
                remove_migration_ptes(page, page);
 rcu_unlock:
-       rcu_read_unlock();
+       if (rcu_locked)
+               rcu_read_unlock();
 
 unlock: