ksm: make KSM page migration possible
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / mm / memory.c
index e0a9b0ce4f102f8cfef2d6d7c6581d71f7595ff4..7bd22a621817b24e65bd606d2c63950c07828857 100644 (file)
 
 #include "internal.h"
 
+#ifdef LAST_NID_NOT_IN_PAGE_FLAGS
+#warning Unfortunate NUMA and NUMA Balancing config, growing page-frame for last_nid.
+#endif
+
 #ifndef CONFIG_NEED_MULTIPLE_NODES
 /* use the per-pgdat data instead for discontigmem - mbligh */
 unsigned long max_mapnr;
@@ -184,10 +188,14 @@ static int tlb_next_batch(struct mmu_gather *tlb)
                return 1;
        }
 
+       if (tlb->batch_count == MAX_GATHER_BATCH_COUNT)
+               return 0;
+
        batch = (void *)__get_free_pages(GFP_NOWAIT | __GFP_NOWARN, 0);
        if (!batch)
                return 0;
 
+       tlb->batch_count++;
        batch->next = NULL;
        batch->nr   = 0;
        batch->max  = MAX_GATHER_BATCH;
@@ -216,6 +224,7 @@ void tlb_gather_mmu(struct mmu_gather *tlb, struct mm_struct *mm, bool fullmm)
        tlb->local.nr   = 0;
        tlb->local.max  = ARRAY_SIZE(tlb->__pages);
        tlb->active     = &tlb->local;
+       tlb->batch_count = 0;
 
 #ifdef CONFIG_HAVE_RCU_TABLE_FREE
        tlb->batch = NULL;
@@ -2985,17 +2994,16 @@ static int do_swap_page(struct mm_struct *mm, struct vm_area_struct *vma,
        if (unlikely(!PageSwapCache(page) || page_private(page) != entry.val))
                goto out_page;
 
-       if (ksm_might_need_to_copy(page, vma, address)) {
-               swapcache = page;
-               page = ksm_does_need_to_copy(page, vma, address);
-
-               if (unlikely(!page)) {
-                       ret = VM_FAULT_OOM;
-                       page = swapcache;
-                       swapcache = NULL;
-                       goto out_page;
-               }
+       swapcache = page;
+       page = ksm_might_need_to_copy(page, vma, address);
+       if (unlikely(!page)) {
+               ret = VM_FAULT_OOM;
+               page = swapcache;
+               swapcache = NULL;
+               goto out_page;
        }
+       if (page == swapcache)
+               swapcache = NULL;
 
        if (mem_cgroup_try_charge_swapin(mm, page, GFP_KERNEL, &ptr)) {
                ret = VM_FAULT_OOM;
@@ -3039,7 +3047,10 @@ static int do_swap_page(struct mm_struct *mm, struct vm_area_struct *vma,
        }
        flush_icache_page(vma, page);
        set_pte_at(mm, address, page_table, pte);
-       do_page_add_anon_rmap(page, vma, address, exclusive);
+       if (swapcache) /* ksm created a completely new copy */
+               page_add_new_anon_rmap(page, vma, address);
+       else
+               do_page_add_anon_rmap(page, vma, address, exclusive);
        /* It's better to call commit-charge after rmap is established */
        mem_cgroup_commit_charge_swapin(page, ptr);
 
@@ -3706,6 +3717,14 @@ retry:
                if (pmd_trans_huge(orig_pmd)) {
                        unsigned int dirty = flags & FAULT_FLAG_WRITE;
 
+                       /*
+                        * If the pmd is splitting, return and retry the
+                        * the fault.  Alternative: wait until the split
+                        * is done, and goto retry.
+                        */
+                       if (pmd_trans_splitting(orig_pmd))
+                               return 0;
+
                        if (pmd_numa(orig_pmd))
                                return do_huge_pmd_numa_page(mm, vma, address,
                                                             orig_pmd, pmd);
@@ -3808,30 +3827,6 @@ int __pmd_alloc(struct mm_struct *mm, pud_t *pud, unsigned long address)
 }
 #endif /* __PAGETABLE_PMD_FOLDED */
 
-int make_pages_present(unsigned long addr, unsigned long end)
-{
-       int ret, len, write;
-       struct vm_area_struct * vma;
-
-       vma = find_vma(current->mm, addr);
-       if (!vma)
-               return -ENOMEM;
-       /*
-        * We want to touch writable mappings with a write fault in order
-        * to break COW, except for shared mappings because these don't COW
-        * and we would not want to dirty them for nothing.
-        */
-       write = (vma->vm_flags & (VM_WRITE | VM_SHARED)) == VM_WRITE;
-       BUG_ON(addr >= end);
-       BUG_ON(end > vma->vm_end);
-       len = DIV_ROUND_UP(end, PAGE_SIZE) - addr/PAGE_SIZE;
-       ret = get_user_pages(current, current->mm, addr,
-                       len, write, 0, NULL, NULL);
-       if (ret < 0)
-               return ret;
-       return ret == len ? 0 : -EFAULT;
-}
-
 #if !defined(__HAVE_ARCH_GATE_AREA)
 
 #if defined(AT_SYSINFO_EHDR)