Merge tag 'v3.10.76' into update
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / mm / memory.c
index e6b1da3a8924c54ee547cac496c78e2e6f93d0e4..9feed4bfb32366d3356ba6dcc6390c748655ca75 100644 (file)
 
 #include "internal.h"
 
+#ifdef CONFIG_MTK_EXTMEM
+extern bool extmem_in_mspace(struct vm_area_struct *vma);
+extern unsigned long get_virt_from_mspace(unsigned long pa);
+#endif
+
 #ifdef LAST_NID_NOT_IN_PAGE_FLAGS
 #warning Unfortunate NUMA and NUMA Balancing config, growing page-frame for last_nid.
 #endif
@@ -1462,6 +1467,16 @@ int zap_vma_ptes(struct vm_area_struct *vma, unsigned long address,
 }
 EXPORT_SYMBOL_GPL(zap_vma_ptes);
 
+/*
+ * FOLL_FORCE can write to even unwritable pte's, but only
+ * after we've gone through a COW cycle and they are dirty.
+ */
+static inline bool can_follow_write_pte(pte_t pte, unsigned int flags)
+{
+       return pte_write(pte) ||
+               ((flags & FOLL_FORCE) && (flags & FOLL_COW) && pte_dirty(pte));
+}
+
 /**
  * follow_page_mask - look up a page descriptor from a user-virtual address
  * @vma: vm_area_struct mapping @address
@@ -1569,7 +1584,7 @@ split_fallthrough:
        }
        if ((flags & FOLL_NUMA) && pte_numa(pte))
                goto no_page;
-       if ((flags & FOLL_WRITE) && !pte_write(pte))
+       if ((flags & FOLL_WRITE) && !can_follow_write_pte(pte, flags))
                goto unlock;
 
        page = vm_normal_page(vma, address, pte);
@@ -1643,6 +1658,7 @@ no_page_table:
                return ERR_PTR(-EFAULT);
        return page;
 }
+EXPORT_SYMBOL_GPL(follow_page_mask);
 
 static inline int stack_guard_page(struct vm_area_struct *vma, unsigned long addr)
 {
@@ -1787,11 +1803,24 @@ long __get_user_pages(struct task_struct *tsk, struct mm_struct *mm,
                        page_mask = 0;
                        goto next_page;
                }
-
+    #ifdef CONFIG_MTK_EXTMEM
+        if (!vma || !(vm_flags & vma->vm_flags))
+               {
+                   return i ? : -EFAULT;
+        }
+
+               if (vma->vm_flags & (VM_IO | VM_PFNMAP))
+               {
+                   /*Would pass VM_IO | VM_RESERVED | VM_PFNMAP. (for Reserved Physical Memory PFN Mapping Usage)*/
+                   if(!((vma->vm_flags&VM_IO)&&(vma->vm_flags&VM_RESERVED)&&(vma->vm_flags&VM_PFNMAP)))
+                           return i ? : -EFAULT;
+        }
+    #else
                if (!vma ||
                    (vma->vm_flags & (VM_IO | VM_PFNMAP)) ||
                    !(vm_flags & vma->vm_flags))
                        return i ? : -EFAULT;
+    #endif
 
                if (is_vm_hugetlb_page(vma)) {
                        i = follow_hugetlb_page(mm, vma, pages, vmas,
@@ -1877,7 +1906,7 @@ long __get_user_pages(struct task_struct *tsk, struct mm_struct *mm,
                                 */
                                if ((ret & VM_FAULT_WRITE) &&
                                    !(vma->vm_flags & VM_WRITE))
-                                       foll_flags &= ~FOLL_WRITE;
+                                       foll_flags |= FOLL_COW;
 
                                cond_resched();
                        }
@@ -2368,12 +2397,18 @@ int remap_pfn_range(struct vm_area_struct *vma, unsigned long addr,
         * un-COW'ed pages by matching them up with "vma->vm_pgoff".
         * See vm_normal_page() for details.
         */
+#ifdef CONFIG_MTK_EXTMEM
+       if (addr == vma->vm_start && end == vma->vm_end) {
+               vma->vm_pgoff = pfn;
+       } else if (is_cow_mapping(vma->vm_flags))
+               return -EINVAL;
+#else
        if (is_cow_mapping(vma->vm_flags)) {
                if (addr != vma->vm_start || end != vma->vm_end)
                        return -EINVAL;
                vma->vm_pgoff = pfn;
        }
-
+#endif
        err = track_pfn_remap(vma, &prot, pfn, addr, PAGE_ALIGN(size));
        if (err)
                return -EINVAL;
@@ -3230,6 +3265,10 @@ static int do_anonymous_page(struct mm_struct *mm, struct vm_area_struct *vma,
 
        pte_unmap(page_table);
 
+       /* File mapping without ->vm_ops ? */
+       if (vma->vm_flags & VM_SHARED)
+               return VM_FAULT_SIGBUS;
+
        /* Check if we need to add a guard page to the stack */
        if (check_stack_guard_page(vma, address) < 0)
                return VM_FAULT_SIGSEGV;
@@ -3494,6 +3533,10 @@ static int do_linear_fault(struct mm_struct *mm, struct vm_area_struct *vma,
        pgoff_t pgoff = (((address & PAGE_MASK)
                        - vma->vm_start) >> PAGE_SHIFT) + vma->vm_pgoff;
 
+       /* The VMA was not fully populated on mmap() or missing VM_DONTEXPAND */
+       if (!vma->vm_ops->fault)
+               return VM_FAULT_SIGBUS;
+
        pte_unmap(page_table);
        return __do_fault(mm, vma, address, pmd, pgoff, flags, orig_pte);
 }
@@ -3707,9 +3750,8 @@ int handle_pte_fault(struct mm_struct *mm,
        if (!pte_present(entry)) {
                if (pte_none(entry)) {
                        if (vma->vm_ops) {
-                               if (likely(vma->vm_ops->fault))
-                                       return do_linear_fault(mm, vma, address,
-                                               pte, pmd, flags, entry);
+                               return do_linear_fault(mm, vma, address,
+                                       pte, pmd, flags, entry);
                        }
                        return do_anonymous_page(mm, vma, address,
                                                 pte, pmd, flags);
@@ -4121,6 +4163,21 @@ static int __access_remote_vm(struct task_struct *tsk, struct mm_struct *mm,
                ret = get_user_pages(tsk, mm, addr, 1,
                                write, 1, &page, &vma);
                if (ret <= 0) {
+#ifdef CONFIG_MTK_EXTMEM
+                       if (!write) {
+                               vma = find_vma(mm, addr);
+                               if (!vma || vma->vm_start > addr)
+                                       break;
+                               if (vma->vm_end < addr + len)
+                                       len = vma->vm_end - addr;
+                               if (extmem_in_mspace(vma)) {
+                                       void *extmem_va = (void *)get_virt_from_mspace(vma->vm_pgoff << PAGE_SHIFT) + (addr - vma->vm_start);
+                                       memcpy(buf, extmem_va, len);
+                                       buf += len;
+                                       break;
+                               }
+                       }
+#endif
                        /*
                         * Check if this is a VM_IO | VM_PFNMAP VMA, which
                         * we can access using slightly different code.