|
@@ -708,6 +708,18 @@ static inline struct page *alloc_hugepage(int defrag)
|
|
|
}
|
|
|
#endif
|
|
|
|
|
|
+static void set_huge_zero_page(pgtable_t pgtable, struct mm_struct *mm,
|
|
|
+ struct vm_area_struct *vma, unsigned long haddr, pmd_t *pmd)
|
|
|
+{
|
|
|
+ pmd_t entry;
|
|
|
+ entry = pfn_pmd(huge_zero_pfn, vma->vm_page_prot);
|
|
|
+ entry = pmd_wrprotect(entry);
|
|
|
+ entry = pmd_mkhuge(entry);
|
|
|
+ set_pmd_at(mm, haddr, pmd, entry);
|
|
|
+ pgtable_trans_huge_deposit(mm, pgtable);
|
|
|
+ mm->nr_ptes++;
|
|
|
+}
|
|
|
+
|
|
|
int do_huge_pmd_anonymous_page(struct mm_struct *mm, struct vm_area_struct *vma,
|
|
|
unsigned long address, pmd_t *pmd,
|
|
|
unsigned int flags)
|
|
@@ -785,6 +797,16 @@ int copy_huge_pmd(struct mm_struct *dst_mm, struct mm_struct *src_mm,
|
|
|
pte_free(dst_mm, pgtable);
|
|
|
goto out_unlock;
|
|
|
}
|
|
|
+ /*
|
|
|
+ * mm->page_table_lock is enough to be sure that huge zero pmd is not
|
|
|
+ * under splitting since we don't split the page itself, only pmd to
|
|
|
+ * a page table.
|
|
|
+ */
|
|
|
+ if (is_huge_zero_pmd(pmd)) {
|
|
|
+ set_huge_zero_page(pgtable, dst_mm, vma, addr, dst_pmd);
|
|
|
+ ret = 0;
|
|
|
+ goto out_unlock;
|
|
|
+ }
|
|
|
if (unlikely(pmd_trans_splitting(pmd))) {
|
|
|
/* split huge page running from under us */
|
|
|
spin_unlock(&src_mm->page_table_lock);
|