aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/powerpc/include/asm/book3s/64/pgtable.h4
-rw-r--r--arch/powerpc/mm/pgtable_64.c32
-rw-r--r--include/asm-generic/pgtable.h8
-rw-r--r--mm/huge_memory.c1
4 files changed, 45 insertions, 0 deletions
diff --git a/arch/powerpc/include/asm/book3s/64/pgtable.h b/arch/powerpc/include/asm/book3s/64/pgtable.h
index 8d1c41d28318..ac07a30a7934 100644
--- a/arch/powerpc/include/asm/book3s/64/pgtable.h
+++ b/arch/powerpc/include/asm/book3s/64/pgtable.h
@@ -281,6 +281,10 @@ extern pgtable_t pgtable_trans_huge_withdraw(struct mm_struct *mm, pmd_t *pmdp);
281extern void pmdp_invalidate(struct vm_area_struct *vma, unsigned long address, 281extern void pmdp_invalidate(struct vm_area_struct *vma, unsigned long address,
282 pmd_t *pmdp); 282 pmd_t *pmdp);
283 283
284#define __HAVE_ARCH_PMDP_HUGE_SPLIT_PREPARE
285extern void pmdp_huge_split_prepare(struct vm_area_struct *vma,
286 unsigned long address, pmd_t *pmdp);
287
284#define pmd_move_must_withdraw pmd_move_must_withdraw 288#define pmd_move_must_withdraw pmd_move_must_withdraw
285struct spinlock; 289struct spinlock;
286static inline int pmd_move_must_withdraw(struct spinlock *new_pmd_ptl, 290static inline int pmd_move_must_withdraw(struct spinlock *new_pmd_ptl,
diff --git a/arch/powerpc/mm/pgtable_64.c b/arch/powerpc/mm/pgtable_64.c
index 3124a20d0fab..cdf2123d46db 100644
--- a/arch/powerpc/mm/pgtable_64.c
+++ b/arch/powerpc/mm/pgtable_64.c
@@ -646,6 +646,28 @@ pgtable_t pgtable_trans_huge_withdraw(struct mm_struct *mm, pmd_t *pmdp)
646 return pgtable; 646 return pgtable;
647} 647}
648 648
649void pmdp_huge_split_prepare(struct vm_area_struct *vma,
650 unsigned long address, pmd_t *pmdp)
651{
652 VM_BUG_ON(address & ~HPAGE_PMD_MASK);
653 VM_BUG_ON(REGION_ID(address) != USER_REGION_ID);
654
655 /*
656 * We can't mark the pmd none here, because that will cause a race
657 * against exit_mmap. We need to continue mark pmd TRANS HUGE, while
658 * we spilt, but at the same time we wan't rest of the ppc64 code
659 * not to insert hash pte on this, because we will be modifying
660 * the deposited pgtable in the caller of this function. Hence
661 * clear the _PAGE_USER so that we move the fault handling to
662 * higher level function and that will serialize against ptl.
663 * We need to flush existing hash pte entries here even though,
664 * the translation is still valid, because we will withdraw
665 * pgtable_t after this.
666 */
667 pmd_hugepage_update(vma->vm_mm, address, pmdp, _PAGE_USER, 0);
668}
669
670
649/* 671/*
650 * set a new huge pmd. We should not be called for updating 672 * set a new huge pmd. We should not be called for updating
651 * an existing pmd entry. That should go via pmd_hugepage_update. 673 * an existing pmd entry. That should go via pmd_hugepage_update.
@@ -663,10 +685,20 @@ void set_pmd_at(struct mm_struct *mm, unsigned long addr,
663 return set_pte_at(mm, addr, pmdp_ptep(pmdp), pmd_pte(pmd)); 685 return set_pte_at(mm, addr, pmdp_ptep(pmdp), pmd_pte(pmd));
664} 686}
665 687
688/*
689 * We use this to invalidate a pmdp entry before switching from a
690 * hugepte to regular pmd entry.
691 */
666void pmdp_invalidate(struct vm_area_struct *vma, unsigned long address, 692void pmdp_invalidate(struct vm_area_struct *vma, unsigned long address,
667 pmd_t *pmdp) 693 pmd_t *pmdp)
668{ 694{
669 pmd_hugepage_update(vma->vm_mm, address, pmdp, _PAGE_PRESENT, 0); 695 pmd_hugepage_update(vma->vm_mm, address, pmdp, _PAGE_PRESENT, 0);
696
697 /*
698 * This ensures that generic code that rely on IRQ disabling
699 * to prevent a parallel THP split work as expected.
700 */
701 kick_all_cpus_sync();
670} 702}
671 703
672/* 704/*
diff --git a/include/asm-generic/pgtable.h b/include/asm-generic/pgtable.h
index 0b3c0d39ef75..c370b261c720 100644
--- a/include/asm-generic/pgtable.h
+++ b/include/asm-generic/pgtable.h
@@ -239,6 +239,14 @@ extern void pmdp_invalidate(struct vm_area_struct *vma, unsigned long address,
239 pmd_t *pmdp); 239 pmd_t *pmdp);
240#endif 240#endif
241 241
242#ifndef __HAVE_ARCH_PMDP_HUGE_SPLIT_PREPARE
243static inline void pmdp_huge_split_prepare(struct vm_area_struct *vma,
244 unsigned long address, pmd_t *pmdp)
245{
246
247}
248#endif
249
242#ifndef __HAVE_ARCH_PTE_SAME 250#ifndef __HAVE_ARCH_PTE_SAME
243static inline int pte_same(pte_t pte_a, pte_t pte_b) 251static inline int pte_same(pte_t pte_a, pte_t pte_b)
244{ 252{
diff --git a/mm/huge_memory.c b/mm/huge_memory.c
index b1cf73bc3b12..de3f43cde129 100644
--- a/mm/huge_memory.c
+++ b/mm/huge_memory.c
@@ -2856,6 +2856,7 @@ static void __split_huge_pmd_locked(struct vm_area_struct *vma, pmd_t *pmd,
2856 young = pmd_young(*pmd); 2856 young = pmd_young(*pmd);
2857 dirty = pmd_dirty(*pmd); 2857 dirty = pmd_dirty(*pmd);
2858 2858
2859 pmdp_huge_split_prepare(vma, haddr, pmd);
2859 pgtable = pgtable_trans_huge_withdraw(mm, pmd); 2860 pgtable = pgtable_trans_huge_withdraw(mm, pmd);
2860 pmd_populate(mm, &_pmd, pgtable); 2861 pmd_populate(mm, &_pmd, pgtable);
2861 2862