Merge tag 's390-6.10-1' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux
[linux-2.6-block.git] / mm / userfaultfd.c
index 3c3539c573e7fec47b2ac883e18d7644d40197c3..829f7b1089fc6f64b86ea05852ec0fa229d3fa7e 100644 (file)
@@ -316,6 +316,38 @@ out_release:
        goto out;
 }
 
+static int mfill_atomic_pte_zeroed_folio(pmd_t *dst_pmd,
+                                        struct vm_area_struct *dst_vma,
+                                        unsigned long dst_addr)
+{
+       struct folio *folio;
+       int ret = -ENOMEM;
+
+       folio = vma_alloc_zeroed_movable_folio(dst_vma, dst_addr);
+       if (!folio)
+               return ret;
+
+       if (mem_cgroup_charge(folio, dst_vma->vm_mm, GFP_KERNEL))
+               goto out_put;
+
+       /*
+        * The memory barrier inside __folio_mark_uptodate makes sure that
+        * zeroing out the folio become visible before mapping the page
+        * using set_pte_at(). See do_anonymous_page().
+        */
+       __folio_mark_uptodate(folio);
+
+       ret = mfill_atomic_install_pte(dst_pmd, dst_vma, dst_addr,
+                                      &folio->page, true, 0);
+       if (ret)
+               goto out_put;
+
+       return 0;
+out_put:
+       folio_put(folio);
+       return ret;
+}
+
 static int mfill_atomic_pte_zeropage(pmd_t *dst_pmd,
                                     struct vm_area_struct *dst_vma,
                                     unsigned long dst_addr)
@@ -324,6 +356,9 @@ static int mfill_atomic_pte_zeropage(pmd_t *dst_pmd,
        spinlock_t *ptl;
        int ret;
 
+       if (mm_forbids_zeropage(dst_vma->vm_mm))
+               return mfill_atomic_pte_zeroed_folio(dst_pmd, dst_vma, dst_addr);
+
        _dst_pte = pte_mkspecial(pfn_pte(my_zero_pfn(dst_addr),
                                         dst_vma->vm_page_prot));
        ret = -EAGAIN;