Nuke duplicate header from sysctl.c
[cascardo/linux.git] / mm / migrate.c
index 6a207e8..a73504f 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/mempolicy.h>
 #include <linux/vmalloc.h>
 #include <linux/security.h>
+#include <linux/memcontrol.h>
 
 #include "internal.h"
 
@@ -115,11 +116,6 @@ int putback_lru_pages(struct list_head *l)
        return count;
 }
 
-static inline int is_swap_pte(pte_t pte)
-{
-       return !pte_none(pte) && !pte_present(pte) && !pte_file(pte);
-}
-
 /*
  * Restore a potential migration pte to a working pte entry
  */
@@ -157,6 +153,11 @@ static void remove_migration_pte(struct vm_area_struct *vma,
                return;
        }
 
+       if (mem_cgroup_charge(new, mm, GFP_KERNEL)) {
+               pte_unmap(ptep);
+               return;
+       }
+
        ptl = pte_lockptr(mm, pmd);
        spin_lock(ptl);
        pte = *ptep;
@@ -592,9 +593,10 @@ static int move_to_new_page(struct page *newpage, struct page *page)
        else
                rc = fallback_migrate_page(mapping, newpage, page);
 
-       if (!rc)
+       if (!rc) {
+               mem_cgroup_page_migration(page, newpage);
                remove_migration_ptes(page, newpage);
-       else
+       else
                newpage->mapping = NULL;
 
        unlock_page(newpage);
@@ -613,6 +615,7 @@ static int unmap_and_move(new_page_t get_new_page, unsigned long private,
        int *result = NULL;
        struct page *newpage = get_new_page(page, private, &result);
        int rcu_locked = 0;
+       int charge = 0;
 
        if (!newpage)
                return -ENOMEM;
@@ -645,23 +648,46 @@ static int unmap_and_move(new_page_t get_new_page, unsigned long private,
                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
-        * and treated as swapcache but has no rmap yet.
-        * Calling try_to_unmap() against a page->mapping==NULL page is
-        * BUG. So handle it here.
+        * Corner case handling:
+        * 1. When a new swap-cache page is read into, it is added to the LRU
+        * and treated as swapcache but it has no rmap yet.
+        * Calling try_to_unmap() against a page->mapping==NULL page will
+        * trigger a BUG.  So handle it here.
+        * 2. An orphaned page (see truncate_complete_page) might have
+        * fs-private metadata. The page can be picked up due to memory
+        * offlining.  Everywhere else except page reclaim, the page is
+        * invisible to the vm, so the page can not be migrated.  So try to
+        * free the metadata, so the page can be freed.
         */
-       if (!page->mapping)
+       if (!page->mapping) {
+               if (!PageAnon(page) && PagePrivate(page)) {
+                       /*
+                        * Go direct to try_to_free_buffers() here because
+                        * a) that's what try_to_release_page() would do anyway
+                        * b) we may be under rcu_read_lock() here, so we can't
+                        *    use GFP_KERNEL which is what try_to_release_page()
+                        *    needs to be effective.
+                        */
+                       try_to_free_buffers(page);
+               }
                goto rcu_unlock;
+       }
+
+       charge = mem_cgroup_prepare_migration(page);
        /* Establish migration ptes or remove ptes */
        try_to_unmap(page, 1);
 
        if (!page_mapped(page))
                rc = move_to_new_page(newpage, page);
 
-       if (rc)
+       if (rc) {
                remove_migration_ptes(page, page);
+               if (charge)
+                       mem_cgroup_end_migration(page);
+       } else if (charge)
+               mem_cgroup_end_migration(newpage);
 rcu_unlock:
        if (rcu_locked)
                rcu_read_unlock();