diff options
Diffstat (limited to 'mm/migrate.c')
-rw-r--r-- | mm/migrate.c | 12 |
1 files changed, 12 insertions, 0 deletions
diff --git a/mm/migrate.c b/mm/migrate.c index 5938db54e1d7..b768a1d4fa43 100644 --- a/mm/migrate.c +++ b/mm/migrate.c | |||
@@ -543,6 +543,7 @@ static int unmap_and_move(new_page_t get_new_page, unsigned long private, | |||
543 | int rcu_locked = 0; | 543 | int rcu_locked = 0; |
544 | int charge = 0; | 544 | int charge = 0; |
545 | struct mem_cgroup *mem = NULL; | 545 | struct mem_cgroup *mem = NULL; |
546 | struct anon_vma *anon_vma = NULL; | ||
546 | 547 | ||
547 | if (!newpage) | 548 | if (!newpage) |
548 | return -ENOMEM; | 549 | return -ENOMEM; |
@@ -599,6 +600,8 @@ static int unmap_and_move(new_page_t get_new_page, unsigned long private, | |||
599 | if (PageAnon(page)) { | 600 | if (PageAnon(page)) { |
600 | rcu_read_lock(); | 601 | rcu_read_lock(); |
601 | rcu_locked = 1; | 602 | rcu_locked = 1; |
603 | anon_vma = page_anon_vma(page); | ||
604 | atomic_inc(&anon_vma->migrate_refcount); | ||
602 | } | 605 | } |
603 | 606 | ||
604 | /* | 607 | /* |
@@ -638,6 +641,15 @@ skip_unmap: | |||
638 | if (rc) | 641 | if (rc) |
639 | remove_migration_ptes(page, page); | 642 | remove_migration_ptes(page, page); |
640 | rcu_unlock: | 643 | rcu_unlock: |
644 | |||
645 | /* Drop an anon_vma reference if we took one */ | ||
646 | if (anon_vma && atomic_dec_and_lock(&anon_vma->migrate_refcount, &anon_vma->lock)) { | ||
647 | int empty = list_empty(&anon_vma->head); | ||
648 | spin_unlock(&anon_vma->lock); | ||
649 | if (empty) | ||
650 | anon_vma_free(anon_vma); | ||
651 | } | ||
652 | |||
641 | if (rcu_locked) | 653 | if (rcu_locked) |
642 | rcu_read_unlock(); | 654 | rcu_read_unlock(); |
643 | uncharge: | 655 | uncharge: |