diff options
author | Marcel Ziswiler <marcel.ziswiler@toradex.com> | 2019-03-28 16:27:49 +0100 |
---|---|---|
committer | Marcel Ziswiler <marcel.ziswiler@toradex.com> | 2019-03-28 16:27:49 +0100 |
commit | d899927728beca8357a5b4120b690cb3c1d80844 (patch) | |
tree | ccb170439cc8638d71f6120ae08a6faded46db98 /mm/memory.c | |
parent | 8d60367808c45e33c0a9127621f4e5fc34914f6b (diff) | |
parent | 0a8ab17689e628c84a666195bfc6ab85d11cf057 (diff) |
Merge remote-tracking branch 'remotes/fslc/4.9-2.3.x-imx' into toradex_4.9-2.3.x-imx-nextColibri-iMX7_LXDE-Image_2.8b6.184-20190401Colibri-iMX6_LXDE-Image_2.8b6.184-20190401Colibri-iMX6ULL_LXDE-Image_2.8b6.184-20190401Apalis-iMX6_LXDE-Image_2.8b6.184-20190401
Diffstat (limited to 'mm/memory.c')
-rw-r--r-- | mm/memory.c | 43 |
1 files changed, 37 insertions, 6 deletions
diff --git a/mm/memory.c b/mm/memory.c index f3fef1df7402..47248dc0b9e1 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -2823,6 +2823,28 @@ static int __do_fault(struct fault_env *fe, pgoff_t pgoff, struct vm_fault vmf; int ret; + /* + * Preallocate pte before we take page_lock because this might lead to + * deadlocks for memcg reclaim which waits for pages under writeback: + * lock_page(A) + * SetPageWriteback(A) + * unlock_page(A) + * lock_page(B) + * lock_page(B) + * pte_alloc_pne + * shrink_page_list + * wait_on_page_writeback(A) + * SetPageWriteback(B) + * unlock_page(B) + * # flush A, B to clear the writeback + */ + if (pmd_none(*fe->pmd) && !fe->prealloc_pte) { + fe->prealloc_pte = pte_alloc_one(vma->vm_mm, fe->address); + if (!fe->prealloc_pte) + return VM_FAULT_OOM; + smp_wmb(); /* See comment in __pte_alloc() */ + } + vmf.virtual_address = (void __user *)(fe->address & PAGE_MASK); vmf.pgoff = pgoff; vmf.flags = fe->flags; @@ -3307,15 +3329,24 @@ static int do_fault(struct fault_env *fe) { struct vm_area_struct *vma = fe->vma; pgoff_t pgoff = linear_page_index(vma, fe->address); + int ret; /* The VMA was not fully populated on mmap() or missing VM_DONTEXPAND */ if (!vma->vm_ops->fault) - return VM_FAULT_SIGBUS; - if (!(fe->flags & FAULT_FLAG_WRITE)) - return do_read_fault(fe, pgoff); - if (!(vma->vm_flags & VM_SHARED)) - return do_cow_fault(fe, pgoff); - return do_shared_fault(fe, pgoff); + ret = VM_FAULT_SIGBUS; + else if (!(fe->flags & FAULT_FLAG_WRITE)) + ret = do_read_fault(fe, pgoff); + else if (!(vma->vm_flags & VM_SHARED)) + ret = do_cow_fault(fe, pgoff); + else + ret = do_shared_fault(fe, pgoff); + + /* preallocated pagetable is unused: free it */ + if (fe->prealloc_pte) { + pte_free(vma->vm_mm, fe->prealloc_pte); + fe->prealloc_pte = 0; + } + return ret; } static int numa_migrate_prep(struct page *page, struct vm_area_struct *vma, |