diff options
Diffstat (limited to 'mm/migrate.c')
-rw-r--r-- | mm/migrate.c | 54 |
1 files changed, 40 insertions, 14 deletions
diff --git a/mm/migrate.c b/mm/migrate.c index 6a207e8d17ea..a73504ff5ab9 100644 --- a/mm/migrate.c +++ b/mm/migrate.c | |||
@@ -29,6 +29,7 @@ | |||
29 | #include <linux/mempolicy.h> | 29 | #include <linux/mempolicy.h> |
30 | #include <linux/vmalloc.h> | 30 | #include <linux/vmalloc.h> |
31 | #include <linux/security.h> | 31 | #include <linux/security.h> |
32 | #include <linux/memcontrol.h> | ||
32 | 33 | ||
33 | #include "internal.h" | 34 | #include "internal.h" |
34 | 35 | ||
@@ -115,11 +116,6 @@ int putback_lru_pages(struct list_head *l) | |||
115 | return count; | 116 | return count; |
116 | } | 117 | } |
117 | 118 | ||
118 | static inline int is_swap_pte(pte_t pte) | ||
119 | { | ||
120 | return !pte_none(pte) && !pte_present(pte) && !pte_file(pte); | ||
121 | } | ||
122 | |||
123 | /* | 119 | /* |
124 | * Restore a potential migration pte to a working pte entry | 120 | * Restore a potential migration pte to a working pte entry |
125 | */ | 121 | */ |
@@ -157,6 +153,11 @@ static void remove_migration_pte(struct vm_area_struct *vma, | |||
157 | return; | 153 | return; |
158 | } | 154 | } |
159 | 155 | ||
156 | if (mem_cgroup_charge(new, mm, GFP_KERNEL)) { | ||
157 | pte_unmap(ptep); | ||
158 | return; | ||
159 | } | ||
160 | |||
160 | ptl = pte_lockptr(mm, pmd); | 161 | ptl = pte_lockptr(mm, pmd); |
161 | spin_lock(ptl); | 162 | spin_lock(ptl); |
162 | pte = *ptep; | 163 | pte = *ptep; |
@@ -592,9 +593,10 @@ static int move_to_new_page(struct page *newpage, struct page *page) | |||
592 | else | 593 | else |
593 | rc = fallback_migrate_page(mapping, newpage, page); | 594 | rc = fallback_migrate_page(mapping, newpage, page); |
594 | 595 | ||
595 | if (!rc) | 596 | if (!rc) { |
597 | mem_cgroup_page_migration(page, newpage); | ||
596 | remove_migration_ptes(page, newpage); | 598 | remove_migration_ptes(page, newpage); |
597 | else | 599 | } else |
598 | newpage->mapping = NULL; | 600 | newpage->mapping = NULL; |
599 | 601 | ||
600 | unlock_page(newpage); | 602 | unlock_page(newpage); |
@@ -613,6 +615,7 @@ static int unmap_and_move(new_page_t get_new_page, unsigned long private, | |||
613 | int *result = NULL; | 615 | int *result = NULL; |
614 | struct page *newpage = get_new_page(page, private, &result); | 616 | struct page *newpage = get_new_page(page, private, &result); |
615 | int rcu_locked = 0; | 617 | int rcu_locked = 0; |
618 | int charge = 0; | ||
616 | 619 | ||
617 | if (!newpage) | 620 | if (!newpage) |
618 | return -ENOMEM; | 621 | return -ENOMEM; |
@@ -645,23 +648,46 @@ static int unmap_and_move(new_page_t get_new_page, unsigned long private, | |||
645 | rcu_read_lock(); | 648 | rcu_read_lock(); |
646 | rcu_locked = 1; | 649 | rcu_locked = 1; |
647 | } | 650 | } |
651 | |||
648 | /* | 652 | /* |
649 | * This is a corner case handling. | 653 | * Corner case handling: |
650 | * When a new swap-cache is read into, it is linked to LRU | 654 | * 1. When a new swap-cache page is read into, it is added to the LRU |
651 | * and treated as swapcache but has no rmap yet. | 655 | * and treated as swapcache but it has no rmap yet. |
652 | * Calling try_to_unmap() against a page->mapping==NULL page is | 656 | * Calling try_to_unmap() against a page->mapping==NULL page will |
653 | * BUG. So handle it here. | 657 | * trigger a BUG. So handle it here. |
658 | * 2. An orphaned page (see truncate_complete_page) might have | ||
659 | * fs-private metadata. The page can be picked up due to memory | ||
660 | * offlining. Everywhere else except page reclaim, the page is | ||
661 | * invisible to the vm, so the page can not be migrated. So try to | ||
662 | * free the metadata, so the page can be freed. | ||
654 | */ | 663 | */ |
655 | if (!page->mapping) | 664 | if (!page->mapping) { |
665 | if (!PageAnon(page) && PagePrivate(page)) { | ||
666 | /* | ||
667 | * Go direct to try_to_free_buffers() here because | ||
668 | * a) that's what try_to_release_page() would do anyway | ||
669 | * b) we may be under rcu_read_lock() here, so we can't | ||
670 | * use GFP_KERNEL which is what try_to_release_page() | ||
671 | * needs to be effective. | ||
672 | */ | ||
673 | try_to_free_buffers(page); | ||
674 | } | ||
656 | goto rcu_unlock; | 675 | goto rcu_unlock; |
676 | } | ||
677 | |||
678 | charge = mem_cgroup_prepare_migration(page); | ||
657 | /* Establish migration ptes or remove ptes */ | 679 | /* Establish migration ptes or remove ptes */ |
658 | try_to_unmap(page, 1); | 680 | try_to_unmap(page, 1); |
659 | 681 | ||
660 | if (!page_mapped(page)) | 682 | if (!page_mapped(page)) |
661 | rc = move_to_new_page(newpage, page); | 683 | rc = move_to_new_page(newpage, page); |
662 | 684 | ||
663 | if (rc) | 685 | if (rc) { |
664 | remove_migration_ptes(page, page); | 686 | remove_migration_ptes(page, page); |
687 | if (charge) | ||
688 | mem_cgroup_end_migration(page); | ||
689 | } else if (charge) | ||
690 | mem_cgroup_end_migration(newpage); | ||
665 | rcu_unlock: | 691 | rcu_unlock: |
666 | if (rcu_locked) | 692 | if (rcu_locked) |
667 | rcu_read_unlock(); | 693 | rcu_read_unlock(); |