diff options
-rw-r--r-- | arch/powerpc/include/asm/book3s/64/pgtable.h | 4 | ||||
-rw-r--r-- | arch/powerpc/mm/pgtable_64.c | 32 | ||||
-rw-r--r-- | include/asm-generic/pgtable.h | 8 | ||||
-rw-r--r-- | mm/huge_memory.c | 1 |
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); | |||
281 | extern void pmdp_invalidate(struct vm_area_struct *vma, unsigned long address, | 281 | extern 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 | ||
285 | extern 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 |
285 | struct spinlock; | 289 | struct spinlock; |
286 | static inline int pmd_move_must_withdraw(struct spinlock *new_pmd_ptl, | 290 | static 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 | ||
649 | void 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 | */ | ||
666 | void pmdp_invalidate(struct vm_area_struct *vma, unsigned long address, | 692 | void 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 | ||
243 | static 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 |
243 | static inline int pte_same(pte_t pte_a, pte_t pte_b) | 251 | static 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 | ||