diff options
Diffstat (limited to 'mm/huge_memory.c')
-rw-r--r-- | mm/huge_memory.c | 30 |
1 files changed, 22 insertions, 8 deletions
diff --git a/mm/huge_memory.c b/mm/huge_memory.c index 08f6c1993832..3644ff918434 100644 --- a/mm/huge_memory.c +++ b/mm/huge_memory.c | |||
@@ -32,6 +32,7 @@ | |||
32 | #include <linux/userfaultfd_k.h> | 32 | #include <linux/userfaultfd_k.h> |
33 | #include <linux/page_idle.h> | 33 | #include <linux/page_idle.h> |
34 | #include <linux/shmem_fs.h> | 34 | #include <linux/shmem_fs.h> |
35 | #include <linux/oom.h> | ||
35 | 36 | ||
36 | #include <asm/tlb.h> | 37 | #include <asm/tlb.h> |
37 | #include <asm/pgalloc.h> | 38 | #include <asm/pgalloc.h> |
@@ -550,6 +551,7 @@ static int __do_huge_pmd_anonymous_page(struct vm_fault *vmf, struct page *page, | |||
550 | struct mem_cgroup *memcg; | 551 | struct mem_cgroup *memcg; |
551 | pgtable_t pgtable; | 552 | pgtable_t pgtable; |
552 | unsigned long haddr = vmf->address & HPAGE_PMD_MASK; | 553 | unsigned long haddr = vmf->address & HPAGE_PMD_MASK; |
554 | int ret = 0; | ||
553 | 555 | ||
554 | VM_BUG_ON_PAGE(!PageCompound(page), page); | 556 | VM_BUG_ON_PAGE(!PageCompound(page), page); |
555 | 557 | ||
@@ -561,9 +563,8 @@ static int __do_huge_pmd_anonymous_page(struct vm_fault *vmf, struct page *page, | |||
561 | 563 | ||
562 | pgtable = pte_alloc_one(vma->vm_mm, haddr); | 564 | pgtable = pte_alloc_one(vma->vm_mm, haddr); |
563 | if (unlikely(!pgtable)) { | 565 | if (unlikely(!pgtable)) { |
564 | mem_cgroup_cancel_charge(page, memcg, true); | 566 | ret = VM_FAULT_OOM; |
565 | put_page(page); | 567 | goto release; |
566 | return VM_FAULT_OOM; | ||
567 | } | 568 | } |
568 | 569 | ||
569 | clear_huge_page(page, haddr, HPAGE_PMD_NR); | 570 | clear_huge_page(page, haddr, HPAGE_PMD_NR); |
@@ -576,13 +577,14 @@ static int __do_huge_pmd_anonymous_page(struct vm_fault *vmf, struct page *page, | |||
576 | 577 | ||
577 | vmf->ptl = pmd_lock(vma->vm_mm, vmf->pmd); | 578 | vmf->ptl = pmd_lock(vma->vm_mm, vmf->pmd); |
578 | if (unlikely(!pmd_none(*vmf->pmd))) { | 579 | if (unlikely(!pmd_none(*vmf->pmd))) { |
579 | spin_unlock(vmf->ptl); | 580 | goto unlock_release; |
580 | mem_cgroup_cancel_charge(page, memcg, true); | ||
581 | put_page(page); | ||
582 | pte_free(vma->vm_mm, pgtable); | ||
583 | } else { | 581 | } else { |
584 | pmd_t entry; | 582 | pmd_t entry; |
585 | 583 | ||
584 | ret = check_stable_address_space(vma->vm_mm); | ||
585 | if (ret) | ||
586 | goto unlock_release; | ||
587 | |||
586 | /* Deliver the page fault to userland */ | 588 | /* Deliver the page fault to userland */ |
587 | if (userfaultfd_missing(vma)) { | 589 | if (userfaultfd_missing(vma)) { |
588 | int ret; | 590 | int ret; |
@@ -610,6 +612,15 @@ static int __do_huge_pmd_anonymous_page(struct vm_fault *vmf, struct page *page, | |||
610 | } | 612 | } |
611 | 613 | ||
612 | return 0; | 614 | return 0; |
615 | unlock_release: | ||
616 | spin_unlock(vmf->ptl); | ||
617 | release: | ||
618 | if (pgtable) | ||
619 | pte_free(vma->vm_mm, pgtable); | ||
620 | mem_cgroup_cancel_charge(page, memcg, true); | ||
621 | put_page(page); | ||
622 | return ret; | ||
623 | |||
613 | } | 624 | } |
614 | 625 | ||
615 | /* | 626 | /* |
@@ -688,7 +699,10 @@ int do_huge_pmd_anonymous_page(struct vm_fault *vmf) | |||
688 | ret = 0; | 699 | ret = 0; |
689 | set = false; | 700 | set = false; |
690 | if (pmd_none(*vmf->pmd)) { | 701 | if (pmd_none(*vmf->pmd)) { |
691 | if (userfaultfd_missing(vma)) { | 702 | ret = check_stable_address_space(vma->vm_mm); |
703 | if (ret) { | ||
704 | spin_unlock(vmf->ptl); | ||
705 | } else if (userfaultfd_missing(vma)) { | ||
692 | spin_unlock(vmf->ptl); | 706 | spin_unlock(vmf->ptl); |
693 | ret = handle_userfault(vmf, VM_UFFD_MISSING); | 707 | ret = handle_userfault(vmf, VM_UFFD_MISSING); |
694 | VM_BUG_ON(ret & VM_FAULT_FALLBACK); | 708 | VM_BUG_ON(ret & VM_FAULT_FALLBACK); |