memory controller BUG_ON()
[safe/jmp/linux-2.6] / mm / migrate.c
index 37c73b9..7637941 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/pagemap.h>
 #include <linux/buffer_head.h>
 #include <linux/mm_inline.h>
+#include <linux/nsproxy.h>
 #include <linux/pagevec.h>
 #include <linux/rmap.h>
 #include <linux/topology.h>
@@ -28,6 +29,7 @@
 #include <linux/mempolicy.h>
 #include <linux/vmalloc.h>
 #include <linux/security.h>
+#include <linux/memcontrol.h>
 
 #include "internal.h"
 
@@ -114,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
  */
@@ -156,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;
@@ -171,6 +173,7 @@ static void remove_migration_pte(struct vm_area_struct *vma,
        pte = pte_mkold(mk_pte(new, vma->vm_page_prot));
        if (is_write_migration_entry(entry))
                pte = pte_mkwrite(pte);
+       flush_cache_page(vma, addr, pte_pfn(pte));
        set_pte_at(mm, addr, ptep, pte);
 
        if (PageAnon(new))
@@ -180,7 +183,6 @@ static void remove_migration_pte(struct vm_area_struct *vma,
 
        /* No need to invalidate - it was non-present before */
        update_mmu_cache(vma, addr, pte);
-       lazy_mmu_prot_update(pte);
 
 out:
        pte_unmap_unlock(ptep, ptl);
@@ -611,6 +613,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,17 +639,40 @@ 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
-        * 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;
+       }
+
        /* Establish migration ptes or remove ptes */
        try_to_unmap(page, 1);
 
@@ -656,7 +682,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:
 
@@ -698,7 +725,7 @@ move_newpage:
  * The function returns after 10 attempts or if no pages
  * are movable anymore because to has become empty
  * or no retryable pages exist anymore. All pages will be
- * retruned to the LRU or freed.
+ * returned to the LRU or freed.
  *
  * Return: Number of pages not migrated or error code.
  */
@@ -917,7 +944,7 @@ asmlinkage long sys_move_pages(pid_t pid, unsigned long nr_pages,
 
        /* Find the mm_struct */
        read_lock(&tasklist_lock);
-       task = pid ? find_task_by_pid(pid) : current;
+       task = pid ? find_task_by_vpid(pid) : current;
        if (!task) {
                read_unlock(&tasklist_lock);
                return -ESRCH;
@@ -965,7 +992,7 @@ asmlinkage long sys_move_pages(pid_t pid, unsigned long nr_pages,
         * array. Return various errors if the user did something wrong.
         */
        for (i = 0; i < nr_pages; i++) {
-               const void *p;
+               const void __user *p;
 
                err = -EFAULT;
                if (get_user(p, pages + i))
@@ -979,7 +1006,7 @@ asmlinkage long sys_move_pages(pid_t pid, unsigned long nr_pages,
                                goto out;
 
                        err = -ENODEV;
-                       if (!node_online(node))
+                       if (!node_state(node, N_HIGH_MEMORY))
                                goto out;
 
                        err = -EACCES;