diff options
Diffstat (limited to 'mm/migrate.c')
-rw-r--r-- | mm/migrate.c | 24 |
1 files changed, 20 insertions, 4 deletions
diff --git a/mm/migrate.c b/mm/migrate.c index 34d8ada053e4..37c73b902008 100644 --- a/mm/migrate.c +++ b/mm/migrate.c | |||
@@ -49,9 +49,8 @@ int isolate_lru_page(struct page *page, struct list_head *pagelist) | |||
49 | struct zone *zone = page_zone(page); | 49 | struct zone *zone = page_zone(page); |
50 | 50 | ||
51 | spin_lock_irq(&zone->lru_lock); | 51 | spin_lock_irq(&zone->lru_lock); |
52 | if (PageLRU(page)) { | 52 | if (PageLRU(page) && get_page_unless_zero(page)) { |
53 | ret = 0; | 53 | ret = 0; |
54 | get_page(page); | ||
55 | ClearPageLRU(page); | 54 | ClearPageLRU(page); |
56 | if (PageActive(page)) | 55 | if (PageActive(page)) |
57 | del_page_from_active_list(zone, page); | 56 | del_page_from_active_list(zone, page); |
@@ -632,18 +631,35 @@ static int unmap_and_move(new_page_t get_new_page, unsigned long private, | |||
632 | goto unlock; | 631 | goto unlock; |
633 | wait_on_page_writeback(page); | 632 | wait_on_page_writeback(page); |
634 | } | 633 | } |
635 | |||
636 | /* | 634 | /* |
637 | * Establish migration ptes or remove ptes | 635 | * By try_to_unmap(), page->mapcount goes down to 0 here. In this case, |
636 | * we cannot notice that anon_vma is freed while we migrates a page. | ||
637 | * This rcu_read_lock() delays freeing anon_vma pointer until the end | ||
638 | * of migration. File cache pages are no problem because of page_lock() | ||
639 | */ | ||
640 | rcu_read_lock(); | ||
641 | /* | ||
642 | * This is a corner case handling. | ||
643 | * When a new swap-cache is read into, it is linked to LRU | ||
644 | * and treated as swapcache but has no rmap yet. | ||
645 | * Calling try_to_unmap() against a page->mapping==NULL page is | ||
646 | * BUG. So handle it here. | ||
638 | */ | 647 | */ |
648 | if (!page->mapping) | ||
649 | goto rcu_unlock; | ||
650 | /* Establish migration ptes or remove ptes */ | ||
639 | try_to_unmap(page, 1); | 651 | try_to_unmap(page, 1); |
652 | |||
640 | if (!page_mapped(page)) | 653 | if (!page_mapped(page)) |
641 | rc = move_to_new_page(newpage, page); | 654 | rc = move_to_new_page(newpage, page); |
642 | 655 | ||
643 | if (rc) | 656 | if (rc) |
644 | remove_migration_ptes(page, page); | 657 | remove_migration_ptes(page, page); |
658 | rcu_unlock: | ||
659 | rcu_read_unlock(); | ||
645 | 660 | ||
646 | unlock: | 661 | unlock: |
662 | |||
647 | unlock_page(page); | 663 | unlock_page(page); |
648 | 664 | ||
649 | if (rc != -EAGAIN) { | 665 | if (rc != -EAGAIN) { |