OSDN Git Service

mm/page_alloc.c: pull out init code from build_all_zonelists
[sagit-ice-cold/kernel_xiaomi_msm8998.git] / mm / memory.c
index 43a5374..f7886ab 100644 (file)
@@ -428,6 +428,7 @@ static inline void free_pmd_range(struct mmu_gather *tlb, pud_t *pud,
        pmd = pmd_offset(pud, start);
        pud_clear(pud);
        pmd_free_tlb(tlb, pmd, start);
+       mm_dec_nr_pmds(tlb->mm);
 }
 
 static inline void free_pud_range(struct mmu_gather *tlb, pgd_t *pgd,
@@ -754,6 +755,8 @@ struct page *vm_normal_page(struct vm_area_struct *vma, unsigned long addr,
        if (HAVE_PTE_SPECIAL) {
                if (likely(!pte_special(pte)))
                        goto check_pfn;
+               if (vma->vm_ops && vma->vm_ops->find_special_page)
+                       return vma->vm_ops->find_special_page(vma, addr);
                if (vma->vm_flags & (VM_PFNMAP | VM_MIXEDMAP))
                        return NULL;
                if (!is_zero_pfn(pfn))
@@ -811,42 +814,40 @@ copy_one_pte(struct mm_struct *dst_mm, struct mm_struct *src_mm,
 
        /* pte contains position in swap or file, so copy. */
        if (unlikely(!pte_present(pte))) {
-               if (!pte_file(pte)) {
-                       swp_entry_t entry = pte_to_swp_entry(pte);
-
-                       if (likely(!non_swap_entry(entry))) {
-                               if (swap_duplicate(entry) < 0)
-                                       return entry.val;
-
-                               /* make sure dst_mm is on swapoff's mmlist. */
-                               if (unlikely(list_empty(&dst_mm->mmlist))) {
-                                       spin_lock(&mmlist_lock);
-                                       if (list_empty(&dst_mm->mmlist))
-                                               list_add(&dst_mm->mmlist,
-                                                        &src_mm->mmlist);
-                                       spin_unlock(&mmlist_lock);
-                               }
-                               rss[MM_SWAPENTS]++;
-                       } else if (is_migration_entry(entry)) {
-                               page = migration_entry_to_page(entry);
-
-                               if (PageAnon(page))
-                                       rss[MM_ANONPAGES]++;
-                               else
-                                       rss[MM_FILEPAGES]++;
-
-                               if (is_write_migration_entry(entry) &&
-                                   is_cow_mapping(vm_flags)) {
-                                       /*
-                                        * COW mappings require pages in both
-                                        * parent and child to be set to read.
-                                        */
-                                       make_migration_entry_read(&entry);
-                                       pte = swp_entry_to_pte(entry);
-                                       if (pte_swp_soft_dirty(*src_pte))
-                                               pte = pte_swp_mksoft_dirty(pte);
-                                       set_pte_at(src_mm, addr, src_pte, pte);
-                               }
+               swp_entry_t entry = pte_to_swp_entry(pte);
+
+               if (likely(!non_swap_entry(entry))) {
+                       if (swap_duplicate(entry) < 0)
+                               return entry.val;
+
+                       /* make sure dst_mm is on swapoff's mmlist. */
+                       if (unlikely(list_empty(&dst_mm->mmlist))) {
+                               spin_lock(&mmlist_lock);
+                               if (list_empty(&dst_mm->mmlist))
+                                       list_add(&dst_mm->mmlist,
+                                                       &src_mm->mmlist);
+                               spin_unlock(&mmlist_lock);
+                       }
+                       rss[MM_SWAPENTS]++;
+               } else if (is_migration_entry(entry)) {
+                       page = migration_entry_to_page(entry);
+
+                       if (PageAnon(page))
+                               rss[MM_ANONPAGES]++;
+                       else
+                               rss[MM_FILEPAGES]++;
+
+                       if (is_write_migration_entry(entry) &&
+                                       is_cow_mapping(vm_flags)) {
+                               /*
+                                * COW mappings require pages in both
+                                * parent and child to be set to read.
+                                */
+                               make_migration_entry_read(&entry);
+                               pte = swp_entry_to_pte(entry);
+                               if (pte_swp_soft_dirty(*src_pte))
+                                       pte = pte_swp_mksoft_dirty(pte);
+                               set_pte_at(src_mm, addr, src_pte, pte);
                        }
                }
                goto out_set_pte;
@@ -1020,11 +1021,9 @@ int copy_page_range(struct mm_struct *dst_mm, struct mm_struct *src_mm,
         * readonly mappings. The tradeoff is that copy_page_range is more
         * efficient than faulting.
         */
-       if (!(vma->vm_flags & (VM_HUGETLB | VM_NONLINEAR |
-                              VM_PFNMAP | VM_MIXEDMAP))) {
-               if (!vma->anon_vma)
-                       return 0;
-       }
+       if (!(vma->vm_flags & (VM_HUGETLB | VM_PFNMAP | VM_MIXEDMAP)) &&
+                       !vma->anon_vma)
+               return 0;
 
        if (is_vm_hugetlb_page(vma))
                return copy_hugetlb_page_range(dst_mm, src_mm, vma);
@@ -2009,7 +2008,7 @@ static int do_wp_page(struct mm_struct *mm, struct vm_area_struct *vma,
        pte_t entry;
        int ret = 0;
        int page_mkwrite = 0;
-       struct page *dirty_page = NULL;
+       bool dirty_shared = false;
        unsigned long mmun_start = 0;   /* For mmu_notifiers */
        unsigned long mmun_end = 0;     /* For mmu_notifiers */
        struct mem_cgroup *memcg;
@@ -2060,6 +2059,7 @@ static int do_wp_page(struct mm_struct *mm, struct vm_area_struct *vma,
                unlock_page(old_page);
        } else if (unlikely((vma->vm_flags & (VM_WRITE|VM_SHARED)) ==
                                        (VM_WRITE|VM_SHARED))) {
+               page_cache_get(old_page);
                /*
                 * Only catch write-faults on shared writable pages,
                 * read-only shared pages can get COWed by
@@ -2067,7 +2067,7 @@ static int do_wp_page(struct mm_struct *mm, struct vm_area_struct *vma,
                 */
                if (vma->vm_ops && vma->vm_ops->page_mkwrite) {
                        int tmp;
-                       page_cache_get(old_page);
+
                        pte_unmap_unlock(page_table, ptl);
                        tmp = do_page_mkwrite(vma, old_page, address);
                        if (unlikely(!tmp || (tmp &
@@ -2087,11 +2087,10 @@ static int do_wp_page(struct mm_struct *mm, struct vm_area_struct *vma,
                                unlock_page(old_page);
                                goto unlock;
                        }
-
                        page_mkwrite = 1;
                }
-               dirty_page = old_page;
-               get_page(dirty_page);
+
+               dirty_shared = true;
 
 reuse:
                /*
@@ -2110,20 +2109,20 @@ reuse:
                pte_unmap_unlock(page_table, ptl);
                ret |= VM_FAULT_WRITE;
 
-               if (!dirty_page)
-                       return ret;
-
-               if (!page_mkwrite) {
+               if (dirty_shared) {
                        struct address_space *mapping;
                        int dirtied;
 
-                       lock_page(dirty_page);
-                       dirtied = set_page_dirty(dirty_page);
-                       VM_BUG_ON_PAGE(PageAnon(dirty_page), dirty_page);
-                       mapping = dirty_page->mapping;
-                       unlock_page(dirty_page);
+                       if (!page_mkwrite)
+                               lock_page(old_page);
 
-                       if (dirtied && mapping) {
+                       dirtied = set_page_dirty(old_page);
+                       VM_BUG_ON_PAGE(PageAnon(old_page), old_page);
+                       mapping = old_page->mapping;
+                       unlock_page(old_page);
+                       page_cache_release(old_page);
+
+                       if ((dirtied || page_mkwrite) && mapping) {
                                /*
                                 * Some device drivers do not set page.mapping
                                 * but still dirty their pages
@@ -2131,25 +2130,9 @@ reuse:
                                balance_dirty_pages_ratelimited(mapping);
                        }
 
-                       /* file_update_time outside page_lock */
-                       if (vma->vm_file)
+                       if (!page_mkwrite)
                                file_update_time(vma->vm_file);
                }
-               put_page(dirty_page);
-               if (page_mkwrite) {
-                       struct address_space *mapping = dirty_page->mapping;
-
-                       set_page_dirty(dirty_page);
-                       unlock_page(dirty_page);
-                       page_cache_release(dirty_page);
-                       if (mapping)    {
-                               /*
-                                * Some device drivers do not set page.mapping
-                                * but still dirty their pages
-                                */
-                               balance_dirty_pages_ratelimited(mapping);
-                       }
-               }
 
                return ret;
        }
@@ -2975,8 +2958,7 @@ static int do_shared_fault(struct mm_struct *mm, struct vm_area_struct *vma,
                balance_dirty_pages_ratelimited(mapping);
        }
 
-       /* file_update_time outside page_lock */
-       if (vma->vm_file && !vma->vm_ops->page_mkwrite)
+       if (!vma->vm_ops->page_mkwrite)
                file_update_time(vma->vm_file);
 
        return ret;
@@ -3031,14 +3013,17 @@ static int do_numa_page(struct mm_struct *mm, struct vm_area_struct *vma,
        bool migrated = false;
        int flags = 0;
 
+       /* A PROT_NONE fault should not end up here */
+       BUG_ON(!(vma->vm_flags & (VM_READ | VM_EXEC | VM_WRITE)));
+
        /*
        * The "pte" at this point cannot be used safely without
        * validation through pte_unmap_same(). It's of NUMA type but
        * the pfn may be screwed if the read is non atomic.
        *
-       * ptep_modify_prot_start is not called as this is clearing
-       * the _PAGE_NUMA bit and it is not really expected that there
-       * would be concurrent hardware modifications to the PTE.
+       * We can safely just do a "set_pte_at()", because the old
+       * page table entry is not accessible, so there would be no
+       * concurrent hardware modifications to the PTE.
        */
        ptl = pte_lockptr(mm, pmd);
        spin_lock(ptl);
@@ -3047,7 +3032,9 @@ static int do_numa_page(struct mm_struct *mm, struct vm_area_struct *vma,
                goto out;
        }
 
-       pte = pte_mknonnuma(pte);
+       /* Make it present again */
+       pte = pte_modify(pte, vma->vm_page_prot);
+       pte = pte_mkyoung(pte);
        set_pte_at(mm, addr, ptep, pte);
        update_mmu_cache(vma, addr, ptep);
 
@@ -3056,7 +3043,6 @@ static int do_numa_page(struct mm_struct *mm, struct vm_area_struct *vma,
                pte_unmap_unlock(ptep, ptl);
                return 0;
        }
-       BUG_ON(is_zero_pfn(page_to_pfn(page)));
 
        /*
         * Avoid grouping on DSO/COW pages in specific and RO pages
@@ -3142,7 +3128,7 @@ static int handle_pte_fault(struct mm_struct *mm,
                                        pte, pmd, flags, entry);
        }
 
-       if (pte_numa(entry))
+       if (pte_protnone(entry))
                return do_numa_page(mm, vma, address, entry, pte, pmd);
 
        ptl = pte_lockptr(mm, pmd);
@@ -3220,7 +3206,7 @@ static int __handle_mm_fault(struct mm_struct *mm, struct vm_area_struct *vma,
                        if (pmd_trans_splitting(orig_pmd))
                                return 0;
 
-                       if (pmd_numa(orig_pmd))
+                       if (pmd_protnone(orig_pmd))
                                return do_huge_pmd_numa_page(mm, vma, address,
                                                             orig_pmd, pmd);
 
@@ -3341,15 +3327,17 @@ int __pmd_alloc(struct mm_struct *mm, pud_t *pud, unsigned long address)
 
        spin_lock(&mm->page_table_lock);
 #ifndef __ARCH_HAS_4LEVEL_HACK
-       if (pud_present(*pud))          /* Another has populated it */
-               pmd_free(mm, new);
-       else
+       if (!pud_present(*pud)) {
+               mm_inc_nr_pmds(mm);
                pud_populate(mm, pud, new);
-#else
-       if (pgd_present(*pud))          /* Another has populated it */
+       } else  /* Another has populated it */
                pmd_free(mm, new);
-       else
+#else
+       if (!pgd_present(*pud)) {
+               mm_inc_nr_pmds(mm);
                pgd_populate(mm, pud, new);
+       } else /* Another has populated it */
+               pmd_free(mm, new);
 #endif /* __ARCH_HAS_4LEVEL_HACK */
        spin_unlock(&mm->page_table_lock);
        return 0;