Merge tag 'sh-for-4.9' of git://git.libc.org/linux-sh
[cascardo/linux.git] / mm / memory.c
index 793fe0f..e18c57b 100644 (file)
@@ -1649,10 +1649,14 @@ EXPORT_SYMBOL(vm_insert_pfn_prot);
 int vm_insert_mixed(struct vm_area_struct *vma, unsigned long addr,
                        pfn_t pfn)
 {
+       pgprot_t pgprot = vma->vm_page_prot;
+
        BUG_ON(!(vma->vm_flags & VM_MIXEDMAP));
 
        if (addr < vma->vm_start || addr >= vma->vm_end)
                return -EFAULT;
+       if (track_pfn_insert(vma, &pgprot, pfn))
+               return -EINVAL;
 
        /*
         * If we don't have pte special, then we have to use the pfn_valid()
@@ -1670,9 +1674,9 @@ int vm_insert_mixed(struct vm_area_struct *vma, unsigned long addr,
                 * result in pfn_t_has_page() == false.
                 */
                page = pfn_to_page(pfn_t_to_pfn(pfn));
-               return insert_page(vma, addr, page, vma->vm_page_prot);
+               return insert_page(vma, addr, page, pgprot);
        }
-       return insert_pfn(vma, addr, pfn, vma->vm_page_prot);
+       return insert_pfn(vma, addr, pfn, pgprot);
 }
 EXPORT_SYMBOL(vm_insert_mixed);
 
@@ -3395,7 +3399,7 @@ static int do_numa_page(struct fault_env *fe, pte_t pte)
         * pte_dirty has unpredictable behaviour between PTE scan updates,
         * background writeback, dirty balancing and application behaviour.
         */
-       if (!(vma->vm_flags & VM_WRITE))
+       if (!pte_write(pte))
                flags |= TNF_NO_GROUP;
 
        /*
@@ -3658,6 +3662,19 @@ int handle_mm_fault(struct vm_area_struct *vma, unsigned long address,
                         mem_cgroup_oom_synchronize(false);
        }
 
+       /*
+        * This mm has been already reaped by the oom reaper and so the
+        * refault cannot be trusted in general. Anonymous refaults would
+        * lose data and give a zero page instead e.g. This is especially
+        * problem for use_mm() because regular tasks will just die and
+        * the corrupted data will not be visible anywhere while kthread
+        * will outlive the oom victim and potentially propagate the date
+        * further.
+        */
+       if (unlikely((current->flags & PF_KTHREAD) && !(ret & VM_FAULT_ERROR)
+                               && test_bit(MMF_UNSTABLE, &vma->vm_mm->flags)))
+               ret = VM_FAULT_SIGBUS;
+
        return ret;
 }
 EXPORT_SYMBOL_GPL(handle_mm_fault);
@@ -3852,10 +3869,11 @@ EXPORT_SYMBOL_GPL(generic_access_phys);
  * given task for page fault accounting.
  */
 static int __access_remote_vm(struct task_struct *tsk, struct mm_struct *mm,
-               unsigned long addr, void *buf, int len, int write)
+               unsigned long addr, void *buf, int len, unsigned int gup_flags)
 {
        struct vm_area_struct *vma;
        void *old_buf = buf;
+       int write = gup_flags & FOLL_WRITE;
 
        down_read(&mm->mmap_sem);
        /* ignore errors, just check how much was successfully transferred */
@@ -3865,7 +3883,7 @@ static int __access_remote_vm(struct task_struct *tsk, struct mm_struct *mm,
                struct page *page = NULL;
 
                ret = get_user_pages_remote(tsk, mm, addr, 1,
-                               write, 1, &page, &vma);
+                               gup_flags, &page, &vma);
                if (ret <= 0) {
 #ifndef CONFIG_HAVE_IOREMAP_PROT
                        break;
@@ -3917,14 +3935,14 @@ static int __access_remote_vm(struct task_struct *tsk, struct mm_struct *mm,
  * @addr:      start address to access
  * @buf:       source or destination buffer
  * @len:       number of bytes to transfer
- * @write:     whether the access is a write
+ * @gup_flags: flags modifying lookup behaviour
  *
  * The caller must hold a reference on @mm.
  */
 int access_remote_vm(struct mm_struct *mm, unsigned long addr,
-               void *buf, int len, int write)
+               void *buf, int len, unsigned int gup_flags)
 {
-       return __access_remote_vm(NULL, mm, addr, buf, len, write);
+       return __access_remote_vm(NULL, mm, addr, buf, len, gup_flags);
 }
 
 /*
@@ -3933,7 +3951,7 @@ int access_remote_vm(struct mm_struct *mm, unsigned long addr,
  * Do not walk the page table directly, use get_user_pages
  */
 int access_process_vm(struct task_struct *tsk, unsigned long addr,
-               void *buf, int len, int write)
+               void *buf, int len, unsigned int gup_flags)
 {
        struct mm_struct *mm;
        int ret;
@@ -3942,7 +3960,8 @@ int access_process_vm(struct task_struct *tsk, unsigned long addr,
        if (!mm)
                return 0;
 
-       ret = __access_remote_vm(tsk, mm, addr, buf, len, write);
+       ret = __access_remote_vm(tsk, mm, addr, buf, len, gup_flags);
+
        mmput(mm);
 
        return ret;